This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
AgrarianGameArchive/Scripts/verify_ground_zero_water_source_visual_pass.py
T

133 lines
5.0 KiB
Python

import math
from pathlib import Path
import unreal
MAP_PATH = "/Game/Agrarian/Maps/L_GroundZeroTerrain_Test"
WATER_SOURCE_LABEL = "AGR_GZ_FreshWaterSource_01"
EXPECTED_WATER_LOCATION = unreal.Vector(-7200.0, 10400.0, 0.0)
MAX_WATER_LOCATION_DISTANCE_CM = 500.0
MAX_DRESSING_DISTANCE_CM = 3500.0
FRESH_WATER_MATERIAL = "/Game/Agrarian/Materials/M_AGR_GZ_FreshWater"
STONE_MATERIAL = "/Game/Agrarian/Materials/M_AGR_GZ_Stone_Sandstone"
REQUIRED_COMPONENTS = {
"Mesh",
"WaterSurfaceProxy",
"StoneBankProxy",
"CollectMarkerProxy",
}
REQUIRED_NEARBY_DRESSING = {
"AGR_GZ_EnvVar_Water_Surface_01",
"AGR_GZ_EnvVar_Water_Bank_01",
"AGR_GZ_EnvVar_Water_Reed_01",
"AGR_GZ_EnvVar_Water_Reed_02",
}
def get_actor_label(actor):
try:
return actor.get_actor_label()
except Exception:
return actor.get_name()
def material_path(material):
if not material:
return ""
return material.get_path_name().split(".", 1)[0]
def distance_2d(a, b):
return math.hypot(a.x - b.x, a.y - b.y)
def component_by_name(actor, component_name):
for component in actor.get_components_by_class(unreal.StaticMeshComponent):
if component.get_name() == component_name:
return component
return None
def main():
if not unreal.EditorLevelLibrary.load_level(MAP_PATH):
raise RuntimeError(f"Could not load map: {MAP_PATH}")
actors = unreal.EditorLevelLibrary.get_all_level_actors()
failures = []
water_sources = [actor for actor in actors if get_actor_label(actor) == WATER_SOURCE_LABEL]
if len(water_sources) != 1:
raise RuntimeError(f"Expected exactly one {WATER_SOURCE_LABEL}, found {len(water_sources)}")
water_source = water_sources[0]
if not isinstance(water_source, unreal.AgrarianWaterSource):
failures.append(f"{WATER_SOURCE_LABEL} is not an AgrarianWaterSource")
components = {
component_name: component_by_name(water_source, component_name)
for component_name in REQUIRED_COMPONENTS
}
for component_name, component in components.items():
if component is None:
failures.append(f"{WATER_SOURCE_LABEL} missing {component_name}")
water_surface = components.get("WaterSurfaceProxy")
if water_surface:
if material_path(water_surface.get_material(0)) != FRESH_WATER_MATERIAL:
failures.append("WaterSurfaceProxy does not use the freshwater material")
scale = water_surface.get_editor_property("relative_scale3d")
if scale.x < 2.0 or scale.y < 1.3:
failures.append(f"WaterSurfaceProxy scale is too small: {scale}")
collect_marker = components.get("CollectMarkerProxy")
if collect_marker and material_path(collect_marker.get_material(0)) != FRESH_WATER_MATERIAL:
failures.append("CollectMarkerProxy does not use the freshwater material")
for component_name in ("Mesh", "StoneBankProxy"):
component = components.get(component_name)
if component and material_path(component.get_material(0)) != STONE_MATERIAL:
failures.append(f"{component_name} does not use the sandstone material")
water_location = water_source.get_actor_location()
if distance_2d(water_location, EXPECTED_WATER_LOCATION) > MAX_WATER_LOCATION_DISTANCE_CM:
failures.append(f"{WATER_SOURCE_LABEL} moved too far from drainage-candidate placement: {water_location}")
nearby_labels = {}
for actor in actors:
label = get_actor_label(actor)
if label in REQUIRED_NEARBY_DRESSING:
nearby_labels[label] = actor
missing_dressing = REQUIRED_NEARBY_DRESSING.difference(nearby_labels)
if missing_dressing:
failures.append("missing water dressing actors: " + ", ".join(sorted(missing_dressing)))
for label, actor in nearby_labels.items():
if distance_2d(water_location, actor.get_actor_location()) > MAX_DRESSING_DISTANCE_CM:
failures.append(f"{label} is too far from the freshwater source")
project_root = Path(unreal.Paths.convert_relative_path_to_full(unreal.Paths.project_dir()))
docs = project_root / "Docs" / "Terrain" / "GroundZeroWaterSourceVisualPass.md"
roadmap = project_root / "AGRARIAN_DEVELOPMENT_ROADMAP.md"
for path, snippets in {
docs: ["Ground Zero Water Source Visual Pass", "WaterSurfaceProxy", "stone bank/edge treatment"],
roadmap: ["[x] Add a real water-source visual pass", "surface material, edge treatment, scale, and placement"],
}.items():
text = path.read_text(encoding="utf-8")
for snippet in snippets:
if snippet not in text:
failures.append(f"{path} missing {snippet!r}")
if failures:
raise RuntimeError("Ground Zero water-source visual verification failed: " + "; ".join(failures))
unreal.log(
"Ground Zero water-source visual verification complete: "
f"{WATER_SOURCE_LABEL}, {len(REQUIRED_COMPONENTS)} native visual components, "
f"{len(REQUIRED_NEARBY_DRESSING)} nearby dressing actors."
)
main()