diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 21ff527..4d38b1c 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -458,7 +458,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe - [x] Add water source. - [x] Replace grey-box environment presentation with an MVP natural environment pass: terrain material, grass, shrubs, bushes, trees, water-source visuals, and clearer Ground Zero biome dressing. Added repeatable Ground Zero environment material generation, applied terrain/foliage/resource/water materials in the map setup, regenerated the demo map, documented the pass, and added verification for material assets plus map assignments. - [x] Add first-pass environment asset variation so trees, bushes, grass, resource nodes, and water do not read as repeated placeholders. Added repeatable labeled variation actors for tree canopies/trunks, rounded bushes, grass mats, rock slabs, and a freshwater surface using multiple prototype mesh silhouettes, unique scales, rotations, and Ground Zero material families; extended the natural-environment verifier to require variation coverage. -- [ ] Replace `LevelPrototyping` cube/cylinder mesh dependencies in Agrarian setup scripts and prototype Blueprints with Agrarian-native placeholder environment meshes. +- [x] Replace `LevelPrototyping` cube/cylinder mesh dependencies in Agrarian setup scripts and prototype Blueprints with Agrarian-native placeholder environment meshes. Added repeatable Agrarian-native placeholder mesh assets under `/Game/Agrarian/Environment/PlaceholderMeshes`, updated playable Blueprint and Ground Zero setup scripts to use those native paths, regenerated affected Blueprints/map content, and added verification that Blueprint, foliage, and variation meshes no longer point at template mesh paths. - [ ] Add weather exposure zones if needed. - [ ] Add landmark or ruin placeholder. - [ ] Add spawn area with validation that the player spawns above sea level, above terrain by a safe offset, away from water, away from steep slopes, away from dense resource clusters, and with a known safe fallback coordinate. diff --git a/Content/Agrarian/Blueprints/Resources/BP_FiberResourceNode.uasset b/Content/Agrarian/Blueprints/Resources/BP_FiberResourceNode.uasset index 16a64c8..e835241 100644 --- a/Content/Agrarian/Blueprints/Resources/BP_FiberResourceNode.uasset +++ b/Content/Agrarian/Blueprints/Resources/BP_FiberResourceNode.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b50e3b41ee746b6d7ab6240239400141684ba87b4e27ceeaa6013a92b5a4d357 -size 24611 +oid sha256:8e50d9a974731203e3b47f86ac57da3dbd35ba7917e3f1b2d42ee649f40177d2 +size 24658 diff --git a/Content/Agrarian/Blueprints/Resources/BP_StoneResourceNode.uasset b/Content/Agrarian/Blueprints/Resources/BP_StoneResourceNode.uasset index f3bf3a2..816972b 100644 --- a/Content/Agrarian/Blueprints/Resources/BP_StoneResourceNode.uasset +++ b/Content/Agrarian/Blueprints/Resources/BP_StoneResourceNode.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14b455202260d7af6dc923120ac6e644defc5b11bee2c95e28db104df36d8f44 -size 24603 +oid sha256:f341aff0f1209840088e12c7ea2007ea0822dfabe604504146fd9773cc84dd81 +size 24650 diff --git a/Content/Agrarian/Blueprints/Resources/BP_WoodResourceNode.uasset b/Content/Agrarian/Blueprints/Resources/BP_WoodResourceNode.uasset index 1c4c34b..1ad88ed 100644 --- a/Content/Agrarian/Blueprints/Resources/BP_WoodResourceNode.uasset +++ b/Content/Agrarian/Blueprints/Resources/BP_WoodResourceNode.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c38b59147c528d2d65595ac20de72973d79da528b213c171c2ac295c13c3a5de -size 24587 +oid sha256:130c0664a96b4a645f85581b3f47f84eb052ee8f41152cf1685ae8f0703b97e7 +size 24634 diff --git a/Content/Agrarian/Blueprints/Structures/BP_Campfire.uasset b/Content/Agrarian/Blueprints/Structures/BP_Campfire.uasset index 1eb70d1..43b556a 100644 --- a/Content/Agrarian/Blueprints/Structures/BP_Campfire.uasset +++ b/Content/Agrarian/Blueprints/Structures/BP_Campfire.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74b3622334aad407eb4f5a2450af4399dfabab9f01fae0cafaf73248e6fd1793 -size 24809 +oid sha256:82dfd817ade7b263453f20fdb3e71d6ce5f8c99191e17c0f788aed17761c33a0 +size 24856 diff --git a/Content/Agrarian/Blueprints/Structures/BP_PrimitiveShelter.uasset b/Content/Agrarian/Blueprints/Structures/BP_PrimitiveShelter.uasset index e74be9c..0b207c5 100644 --- a/Content/Agrarian/Blueprints/Structures/BP_PrimitiveShelter.uasset +++ b/Content/Agrarian/Blueprints/Structures/BP_PrimitiveShelter.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d4685ece6830d97af2a9e6aa3a573389185310bb6350a326d0def623d88eae0f -size 25151 +oid sha256:eb3bded2f25be1115d63eb6bb5262f6b27a250ddb6a95dd24b749f6c1f1d1d58 +size 25198 diff --git a/Content/Agrarian/Blueprints/World/BP_FreshWaterSource.uasset b/Content/Agrarian/Blueprints/World/BP_FreshWaterSource.uasset index 986724b..d20e7fc 100644 --- a/Content/Agrarian/Blueprints/World/BP_FreshWaterSource.uasset +++ b/Content/Agrarian/Blueprints/World/BP_FreshWaterSource.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ab551d62337c79fc3fb407cd45f79dbaed34801e33b21cedd8a2d518b6da0be -size 24258 +oid sha256:0dcc249ba2e7ebda965223d697efa4a6959ff0f16697662b519656f70d21486d +size 24305 diff --git a/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube.uasset b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube.uasset new file mode 100644 index 0000000..321547b --- /dev/null +++ b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9bba1435285e0e6dbd3dd0caf4e71b7d89d327190c06ad5bc65853cd5d01b87 +size 125980 diff --git a/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube.uasset b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube.uasset new file mode 100644 index 0000000..2bbe109 --- /dev/null +++ b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:264005527a6ff325b2790031048021f5e899d2e8471ea71bd1e69149ac8fe5d7 +size 13741 diff --git a/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.uasset b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.uasset new file mode 100644 index 0000000..204f122 --- /dev/null +++ b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aec2eb761542acb4c6e036a5322a73786b6d16010b1059691529aaadd9f9f137 +size 147479 diff --git a/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Plane.uasset b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Plane.uasset new file mode 100644 index 0000000..da9e1fd --- /dev/null +++ b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Plane.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0ca642a6792e859a667696d822886b06cc723dbe26f39bd5970fd51090979f7 +size 11789 diff --git a/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_QuarterCylinder.uasset b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_QuarterCylinder.uasset new file mode 100644 index 0000000..30ae7c3 --- /dev/null +++ b/Content/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_QuarterCylinder.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:125ccccef65306c817a9a92d9a4b021441f9b0a39264497d8997cb3aff0eb1bb +size 88771 diff --git a/Content/Agrarian/Maps/L_GroundZeroTerrain_Test.umap b/Content/Agrarian/Maps/L_GroundZeroTerrain_Test.umap index c5f3669..a528137 100644 --- a/Content/Agrarian/Maps/L_GroundZeroTerrain_Test.umap +++ b/Content/Agrarian/Maps/L_GroundZeroTerrain_Test.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26752dbb323c8880ebb9d10037e5fdf972f5744f4141c6678f33daf3d87ae76e -size 7470505 +oid sha256:71bc16dc0b387ea9dc6d6fc9cbff5e1da88d33937345ce3f19a47f425e9e7371 +size 7468900 diff --git a/Docs/TemplateVariantDecision.md b/Docs/TemplateVariantDecision.md index 483d4aa..561b8fb 100644 --- a/Docs/TemplateVariantDecision.md +++ b/Docs/TemplateVariantDecision.md @@ -21,9 +21,9 @@ Keep temporarily: - `ThirdPerson` compatibility assets only while references are audited. The active player, controller, and game mode Blueprint paths now live under `/Game/Agrarian/Blueprints/Characters`. -- `LevelPrototyping` meshes needed by current setup scripts and prototype - Blueprints until the version 0.1 environment pass replaces them with - Agrarian-native placeholder meshes. +- Source `LevelPrototyping` meshes may remain only as copy sources for + repeatable setup scripts. Active setup outputs now use Agrarian-native + placeholder mesh assets under `/Game/Agrarian/Environment/PlaceholderMeshes`. - Shared mannequin/animation content only where current Agrarian assets still reference it. @@ -48,8 +48,8 @@ Cleanup performed: 4. Disabled `StateTree` and `GameplayStateTree` in `AgrarianGame.uproject`. 5. Replaced the current `ThirdPerson` player/game mode paths with Agrarian-owned player, controller, and game mode Blueprint assets. -6. Kept the current `LevelPrototyping` mesh path until the Ground Zero - environment pass replaces the simple cube/cylinder placeholder dependencies. +6. Replaced the active `LevelPrototyping` cube/cylinder placeholder dependencies + with Agrarian-native placeholder mesh assets. ## Current State @@ -60,6 +60,7 @@ version `0.01` project-structure completion: - `ThirdPerson` active player/game mode paths have been replaced. Remaining ThirdPerson compatibility assets should be deleted only after redirector and editor reference checks confirm they are unused. -- `LevelPrototyping` stays because current Agrarian setup scripts and prototype - Blueprints still use its simple cube/cylinder meshes. This is now tracked as - version `0.1` environment replacement work. +- Active setup scripts, prototype Blueprints, and the Ground Zero map now use + Agrarian-native placeholder mesh assets. `LevelPrototyping` can be removed + after later reference audits confirm no editor-only copy-source path is still + needed. diff --git a/Docs/Terrain/GroundZeroNaturalEnvironmentPass.md b/Docs/Terrain/GroundZeroNaturalEnvironmentPass.md index 8acfe56..af624d0 100644 --- a/Docs/Terrain/GroundZeroNaturalEnvironmentPass.md +++ b/Docs/Terrain/GroundZeroNaturalEnvironmentPass.md @@ -14,8 +14,19 @@ space. - First-pass asset variation actors add additional tree canopies/trunks, rounded bushes, grass mats, rock slabs, and a visible freshwater surface with varied meshes, scales, rotations, and material families. +- The foliage and asset variation layers now use Agrarian-native placeholder + mesh assets from `/Game/Agrarian/Environment/PlaceholderMeshes` instead of + direct `LevelPrototyping` mesh references. - The setup remains repeatable through `Scripts/setup_ground_zero_demo_map.py`. +## Placeholder Mesh Assets + +- `/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube` +- `/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube` +- `/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder` +- `/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_QuarterCylinder` +- `/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Plane` + ## Material Assets - `/Game/Agrarian/Materials/M_AGR_GZ_Terrain_CoastalScrub` @@ -35,11 +46,15 @@ the expected instance counts and material assignments, and resource/water actors are visually dressed. It also checks the first-pass asset variation layer: eleven labeled variation actors, at least four mesh silhouettes, unique scale profiles, and coverage across tree, bush, grass, rock, and water visual -families. +families. `Scripts/verify_native_placeholder_meshes.py` checks that playable +resource/structure/water Blueprints, foliage components, and environment +variation actors use Agrarian-native placeholder meshes rather than template +mesh paths. ## Follow-Up This pass deliberately keeps the current prototype geometry so it stays small -and stable. Later environment work should replace these prototype silhouettes -with region-appropriate sourced or custom meshes, then drive density and shape -selection from land-cover, slope, hydrography, and biome data. +and stable. Later environment work should replace the Agrarian-native +placeholder silhouettes with region-appropriate sourced or custom meshes, then +drive density and shape selection from land-cover, slope, hydrography, and biome +data. diff --git a/Scripts/setup_ground_zero_demo_map.py b/Scripts/setup_ground_zero_demo_map.py index dbe7d88..92bbaff 100644 --- a/Scripts/setup_ground_zero_demo_map.py +++ b/Scripts/setup_ground_zero_demo_map.py @@ -17,17 +17,29 @@ LANDSCAPE_MIN_XY = -50000.0 FOLIAGE_LABEL = "AGR_GroundZeroFoliage_FirstPass" FOLIAGE_RANDOM_SEED = 4160544 +PLACEHOLDER_MESH_FOLDER = "/Game/Agrarian/Environment/PlaceholderMeshes" +PLACEHOLDER_MESH_SOURCES = { + "SM_AGR_Placeholder_Cube": "/Game/LevelPrototyping/Meshes/SM_Cube", + "SM_AGR_Placeholder_ChamferCube": "/Game/LevelPrototyping/Meshes/SM_ChamferCube", + "SM_AGR_Placeholder_Cylinder": "/Game/LevelPrototyping/Meshes/SM_Cylinder", + "SM_AGR_Placeholder_QuarterCylinder": "/Game/LevelPrototyping/Meshes/SM_QuarterCylinder", + "SM_AGR_Placeholder_Plane": "/Game/LevelPrototyping/Meshes/SM_Plane", +} +PLACEHOLDER_MESHES = { + name: f"{PLACEHOLDER_MESH_FOLDER}/{name}" + for name in PLACEHOLDER_MESH_SOURCES +} FOLIAGE_MESHES = { - "tree": "/Game/LevelPrototyping/Meshes/SM_Cylinder", - "shrub": "/Game/LevelPrototyping/Meshes/SM_Cube", - "grass": "/Game/LevelPrototyping/Meshes/SM_Cylinder", + "tree": PLACEHOLDER_MESHES["SM_AGR_Placeholder_Cylinder"], + "shrub": PLACEHOLDER_MESHES["SM_AGR_Placeholder_Cube"], + "grass": PLACEHOLDER_MESHES["SM_AGR_Placeholder_Cylinder"], } VARIATION_MESHES = { - "cube": "/Game/LevelPrototyping/Meshes/SM_Cube", - "chamfer_cube": "/Game/LevelPrototyping/Meshes/SM_ChamferCube", - "cylinder": "/Game/LevelPrototyping/Meshes/SM_Cylinder", - "quarter_cylinder": "/Game/LevelPrototyping/Meshes/SM_QuarterCylinder", - "plane": "/Game/LevelPrototyping/Meshes/SM_Plane", + "cube": PLACEHOLDER_MESHES["SM_AGR_Placeholder_Cube"], + "chamfer_cube": PLACEHOLDER_MESHES["SM_AGR_Placeholder_ChamferCube"], + "cylinder": PLACEHOLDER_MESHES["SM_AGR_Placeholder_Cylinder"], + "quarter_cylinder": PLACEHOLDER_MESHES["SM_AGR_Placeholder_QuarterCylinder"], + "plane": PLACEHOLDER_MESHES["SM_AGR_Placeholder_Plane"], } MATERIAL_FOLDER = "/Game/Agrarian/Materials" ENVIRONMENT_MATERIALS = { @@ -405,6 +417,19 @@ def load_required_asset(path): return asset +def ensure_native_placeholder_meshes(): + unreal.EditorAssetLibrary.make_directory(PLACEHOLDER_MESH_FOLDER) + for asset_name, source_path in PLACEHOLDER_MESH_SOURCES.items(): + destination_path = f"{PLACEHOLDER_MESH_FOLDER}/{asset_name}" + if unreal.EditorAssetLibrary.does_asset_exist(destination_path): + continue + + if not unreal.EditorAssetLibrary.duplicate_asset(source_path, destination_path): + raise RuntimeError(f"Could not create native placeholder mesh {destination_path} from {source_path}") + unreal.EditorAssetLibrary.save_asset(destination_path) + unreal.log(f"Created native placeholder mesh: {destination_path}") + + def ensure_environment_materials(): if not unreal.EditorAssetLibrary.does_directory_exist(MATERIAL_FOLDER): unreal.EditorAssetLibrary.make_directory(MATERIAL_FOLDER) @@ -669,6 +694,8 @@ def main(): if not unreal.EditorLevelLibrary.load_level(MAP_PATH): raise RuntimeError(f"Could not load map: {MAP_PATH}") + ensure_native_placeholder_meshes() + labels = {spec["label"] for spec in DEMO_ACTORS} labels.update(LEGACY_DEMO_LIGHTING_LABELS) labels.update(spec["label"] for spec in BIOME_RESOURCE_ACTORS) diff --git a/Scripts/setup_playable_blueprints.py b/Scripts/setup_playable_blueprints.py index bc14df0..d8d42a7 100644 --- a/Scripts/setup_playable_blueprints.py +++ b/Scripts/setup_playable_blueprints.py @@ -11,8 +11,17 @@ WOOD_ITEM_PATH = "/Game/Agrarian/DataAssets/Items/DA_Item_Wood" FIBER_ITEM_PATH = "/Game/Agrarian/DataAssets/Items/DA_Item_Fiber" STONE_ITEM_PATH = "/Game/Agrarian/DataAssets/Items/DA_Item_Stone" -MESH_CUBE_PATH = "/Game/LevelPrototyping/Meshes/SM_Cube" -MESH_CYLINDER_PATH = "/Game/LevelPrototyping/Meshes/SM_Cylinder" +PLACEHOLDER_MESH_FOLDER = "/Game/Agrarian/Environment/PlaceholderMeshes" +PLACEHOLDER_MESH_SOURCES = { + "SM_AGR_Placeholder_Cube": "/Game/LevelPrototyping/Meshes/SM_Cube", + "SM_AGR_Placeholder_Cylinder": "/Game/LevelPrototyping/Meshes/SM_Cylinder", +} +PLACEHOLDER_MESHES = { + name: f"{PLACEHOLDER_MESH_FOLDER}/{name}" + for name in PLACEHOLDER_MESH_SOURCES +} +MESH_CUBE_PATH = PLACEHOLDER_MESHES["SM_AGR_Placeholder_Cube"] +MESH_CYLINDER_PATH = PLACEHOLDER_MESHES["SM_AGR_Placeholder_Cylinder"] BLUEPRINTS = [ { @@ -125,6 +134,19 @@ def load_required_asset(path): return asset +def ensure_native_placeholder_meshes(): + unreal.EditorAssetLibrary.make_directory(PLACEHOLDER_MESH_FOLDER) + for asset_name, source_path in PLACEHOLDER_MESH_SOURCES.items(): + destination_path = f"{PLACEHOLDER_MESH_FOLDER}/{asset_name}" + if unreal.EditorAssetLibrary.does_asset_exist(destination_path): + continue + + if not unreal.EditorAssetLibrary.duplicate_asset(source_path, destination_path): + raise RuntimeError(f"Could not create native placeholder mesh {destination_path} from {source_path}") + unreal.EditorAssetLibrary.save_asset(destination_path) + unreal.log(f"Created native placeholder mesh: {destination_path}") + + def create_or_load_blueprint(asset_name, folder, parent_class): path = f"{folder}/{asset_name}" existing = unreal.EditorAssetLibrary.load_asset(path) @@ -177,6 +199,8 @@ def apply_defaults(blueprint, config): def main(): + ensure_native_placeholder_meshes() + for folder in (RESOURCE_FOLDER, STRUCTURE_FOLDER, WILDLIFE_FOLDER, WORLD_FOLDER): unreal.EditorAssetLibrary.make_directory(folder) diff --git a/Scripts/verify_native_placeholder_meshes.py b/Scripts/verify_native_placeholder_meshes.py new file mode 100644 index 0000000..a6b3e96 --- /dev/null +++ b/Scripts/verify_native_placeholder_meshes.py @@ -0,0 +1,110 @@ +from pathlib import Path + +import unreal + + +MAP_PATH = "/Game/Agrarian/Maps/L_GroundZeroTerrain_Test" +PROJECT_ROOT = Path(unreal.Paths.convert_relative_path_to_full(unreal.Paths.project_dir())) +PLACEHOLDER_MESH_FOLDER = "/Game/Agrarian/Environment/PlaceholderMeshes" +PLACEHOLDER_MESHES = { + "SM_AGR_Placeholder_Cube", + "SM_AGR_Placeholder_ChamferCube", + "SM_AGR_Placeholder_Cylinder", + "SM_AGR_Placeholder_QuarterCylinder", + "SM_AGR_Placeholder_Plane", +} +BLUEPRINT_PATHS = [ + "/Game/Agrarian/Blueprints/Resources/BP_WoodResourceNode", + "/Game/Agrarian/Blueprints/Resources/BP_FiberResourceNode", + "/Game/Agrarian/Blueprints/Resources/BP_StoneResourceNode", + "/Game/Agrarian/Blueprints/Structures/BP_Campfire", + "/Game/Agrarian/Blueprints/Structures/BP_PrimitiveShelter", + "/Game/Agrarian/Blueprints/World/BP_FreshWaterSource", +] +DOC_SNIPPETS = [ + (PROJECT_ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md", "[x] Replace `LevelPrototyping` cube/cylinder mesh dependencies"), + (PROJECT_ROOT / "Docs" / "Terrain" / "GroundZeroNaturalEnvironmentPass.md", "Agrarian-native placeholder"), +] + + +def asset_path(asset): + if not asset: + return "" + return asset.get_path_name().split(".", 1)[0] + + +def get_actor_label(actor): + try: + return actor.get_actor_label() + except Exception: + return actor.get_name() + + +def assert_native_mesh(path, failures): + if not path.startswith(PLACEHOLDER_MESH_FOLDER): + failures.append(f"expected native Agrarian placeholder mesh, got {path}") + if "LevelPrototyping" in path: + failures.append(f"template mesh reference remains: {path}") + + +def main(): + failures = [] + + for mesh_name in PLACEHOLDER_MESHES: + mesh_path = f"{PLACEHOLDER_MESH_FOLDER}/{mesh_name}" + if not unreal.EditorAssetLibrary.does_asset_exist(mesh_path): + failures.append(f"missing native placeholder mesh asset: {mesh_path}") + + for blueprint_path in BLUEPRINT_PATHS: + generated_class = unreal.EditorAssetLibrary.load_blueprint_class(blueprint_path) + if not generated_class: + failures.append(f"could not load Blueprint class: {blueprint_path}") + continue + + cdo = unreal.get_default_object(generated_class) + mesh_component = cdo.get_editor_property("mesh") + assert_native_mesh(asset_path(mesh_component.get_editor_property("static_mesh")), failures) + + if not unreal.EditorLevelLibrary.load_level(MAP_PATH): + failures.append(f"could not load map: {MAP_PATH}") + else: + actors = unreal.EditorLevelLibrary.get_all_level_actors() + foliage_actors = [ + actor + for actor in actors + if get_actor_label(actor) == "AGR_GroundZeroFoliage_FirstPass" + ] + if len(foliage_actors) != 1: + failures.append(f"expected one AGR_GroundZeroFoliage_FirstPass, found {len(foliage_actors)}") + else: + for property_name in ("tree_instances", "shrub_instances", "grass_instances"): + component = foliage_actors[0].get_editor_property(property_name) + assert_native_mesh(asset_path(component.get_editor_property("static_mesh")), failures) + + for actor in actors: + label = get_actor_label(actor) + if not label.startswith("AGR_GZ_EnvVar_"): + continue + + mesh_components = actor.get_components_by_class(unreal.StaticMeshComponent) + if not mesh_components: + failures.append(f"{label} has no static mesh component") + continue + assert_native_mesh(asset_path(mesh_components[0].get_editor_property("static_mesh")), failures) + + for path, snippet in DOC_SNIPPETS: + text = path.read_text(encoding="utf-8") + if snippet not in text: + failures.append(f"{path} missing `{snippet}`") + + if failures: + raise RuntimeError("Native placeholder mesh verification failed: " + "; ".join(failures)) + + unreal.log( + "Native placeholder mesh verification complete: " + f"{len(PLACEHOLDER_MESHES)} Agrarian mesh assets, {len(BLUEPRINT_PATHS)} Blueprint meshes, " + "foliage meshes, and environment variation meshes use native paths." + ) + + +main()