Replace template meshes with native placeholders
This commit is contained in:
@@ -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.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user