import unreal MAP_PATH = "/Game/Agrarian/Maps/L_GroundZeroTerrain_Test" EXPECTED_PLAYABLE_ACTORS = { "AGR_DemoPlayerStart": { "class": unreal.PlayerStart, }, "AGR_DemoWoodResource_01": { "class_path": "/Game/Agrarian/Blueprints/Resources/BP_WoodResourceNode", "properties": { "remaining_harvests": 16, "quantity_per_harvest": 2, "persistence_node_id": "AGR_DemoWoodResource_01", }, }, "AGR_DemoFiberResource_01": { "class_path": "/Game/Agrarian/Blueprints/Resources/BP_FiberResourceNode", "properties": { "remaining_harvests": 10, "quantity_per_harvest": 3, "persistence_node_id": "AGR_DemoFiberResource_01", }, }, "AGR_DemoCampfire_01": { "class_path": "/Game/Agrarian/Blueprints/Structures/BP_Campfire", "properties": { "fuel_seconds": 180.0, "warmth_radius": 650.0, }, }, "AGR_DemoPrimitiveShelter_01": { "class_path": "/Game/Agrarian/Blueprints/Structures/BP_PrimitiveShelter", "properties": { "weather_protection": 0.7, }, }, "AGR_DemoRabbitWildlife_01": { "class_path": "/Game/Agrarian/Blueprints/Wildlife/BP_RabbitWildlife", "properties": { "wildlife_id": "rabbit", "max_health": 12.0, }, }, "AGR_GZ_FreshWaterSource_01": { "class_path": "/Game/Agrarian/Blueprints/World/BP_FreshWaterSource", }, "AGR_GroundZeroMapBoundary": { "class": unreal.AgrarianMapBoundaryVolume, "properties": { "boundary_id": "ground_zero_mvp_tile", "clamp_players_at_boundary": True, }, }, "AGR_DemoSkyLightingController": { "class": unreal.AgrarianSkyLightingController, }, "AGR_DemoWeatherAudioController": { "class": unreal.AgrarianWeatherAudioController, }, "AGR_DemoNoticeActor": { "class": unreal.AgrarianDemoNoticeActor, }, } LEGACY_FLAT_TEST_LABELS = { "AGR_WoodResourceNode_01", "AGR_FiberResourceNode_01", "AGR_Campfire_01", "AGR_PrimitiveShelter_01", "AGR_RabbitWildlife_01", } NEAR_SPAWN_ACTORS = { "AGR_DemoWoodResource_01": 12000.0, "AGR_DemoFiberResource_01": 12000.0, "AGR_DemoCampfire_01": 12000.0, "AGR_DemoPrimitiveShelter_01": 12000.0, "AGR_DemoRabbitWildlife_01": 12000.0, "AGR_GZ_FreshWaterSource_01": 25000.0, } def nearly_equal(left, right): return abs(float(left) - float(right)) < 0.001 def distance_2d(left, right): return ((left.x - right.x) ** 2.0 + (left.y - right.y) ** 2.0) ** 0.5 def class_path(actor): return actor.get_class().get_path_name() def get_actor_label(actor): try: return actor.get_actor_label() except Exception: return actor.get_name() def verify_class(label, actor, expected, failures): expected_class = expected.get("class") if expected_class and not isinstance(actor, expected_class): failures.append(f"{label} expected class {expected_class.__name__}, got {actor.get_class().get_name()}") expected_class_path = expected.get("class_path") if expected_class_path: actual_class_path = class_path(actor) if not actual_class_path.startswith(expected_class_path + "."): failures.append(f"{label} expected class under {expected_class_path}, got {actual_class_path}") def main(): if not unreal.EditorLevelLibrary.load_level(MAP_PATH): raise RuntimeError(f"Could not load map: {MAP_PATH}") failures = [] actors_by_label = {get_actor_label(actor): actor for actor in unreal.EditorLevelLibrary.get_all_level_actors()} for legacy_label in LEGACY_FLAT_TEST_LABELS: if legacy_label in actors_by_label: failures.append(f"legacy flat-test actor should not remain in Ground Zero map: {legacy_label}") for label, expected in EXPECTED_PLAYABLE_ACTORS.items(): actor = actors_by_label.get(label) if not actor: failures.append(f"{label} missing") continue verify_class(label, actor, expected, failures) for property_name, expected_value in expected.get("properties", {}).items(): actual_value = actor.get_editor_property(property_name) if isinstance(expected_value, (int, float)): if not nearly_equal(actual_value, expected_value): failures.append(f"{label} {property_name} expected {expected_value}, got {actual_value}") elif isinstance(expected_value, bool): if bool(actual_value) != expected_value: failures.append(f"{label} {property_name} expected {expected_value}, got {actual_value}") elif str(actual_value) != expected_value: failures.append(f"{label} {property_name} expected {expected_value}, got {actual_value}") player_start = actors_by_label.get("AGR_DemoPlayerStart") if player_start: spawn_location = player_start.get_actor_location() if spawn_location.z < 150.0: failures.append(f"AGR_DemoPlayerStart expected safe above-terrain offset, got z {spawn_location.z}") for label, max_distance in NEAR_SPAWN_ACTORS.items(): actor = actors_by_label.get(label) if not actor: continue actual_distance = distance_2d(spawn_location, actor.get_actor_location()) if actual_distance > max_distance: failures.append(f"{label} is {actual_distance:.0f}cm from spawn, above {max_distance:.0f}cm playable radius") if failures: raise RuntimeError("Test map placement verification failed: " + "; ".join(failures)) unreal.log( "Agrarian Ground Zero playable test map verification complete: " f"{len(EXPECTED_PLAYABLE_ACTORS)} critical actors checked." ) main()