101 lines
4.1 KiB
Python
101 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate and normalize Stage 1A source evidence.
|
|
|
|
The stage evidence was already extracted from the original Cocos package.
|
|
This script keeps the current pass deterministic by checking the referenced
|
|
source files and by removing stale target-toolchain paths from the evidence.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
SOURCE_JSON = ROOT / "source_export" / "stage1_world_camera_source.json"
|
|
RULES_PATH = ROOT / "source_export" / "cocos_creator38_conversion_rules.md"
|
|
REPORT_PATH = ROOT / "source_export" / "stage1_world_camera_extract_report.json"
|
|
|
|
|
|
def load_json(path: Path) -> dict:
|
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
|
|
|
|
def write_json(path: Path, data: dict) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
|
|
|
|
def main() -> int:
|
|
evidence = load_json(SOURCE_JSON)
|
|
metadata = evidence.get("metadata", {})
|
|
source_files = [Path(item) for item in metadata.get("sourceFiles", [])]
|
|
asset_files = [Path(item["sourcePath"]) for item in evidence.get("assets", [])]
|
|
missing = [str(path) for path in [*source_files, *asset_files, RULES_PATH] if not path.exists()]
|
|
|
|
expected_rules_path = str(RULES_PATH)
|
|
changed = evidence.get("conversionRulesPath") != expected_rules_path
|
|
if changed:
|
|
evidence["conversionRulesPath"] = expected_rules_path
|
|
|
|
removed_legacy_camera_keys = []
|
|
camera = evidence.get("camera", {})
|
|
for key in ["unityPosition", "unityOrthographicSize", "unityNearClipPlane"]:
|
|
if key in camera:
|
|
removed_legacy_camera_keys.append(key)
|
|
del camera[key]
|
|
|
|
removed_unproven_camera_rules = []
|
|
motion = camera.get("motion", {})
|
|
serialized_ortho = float(camera.get("orthographicHeight", 640))
|
|
min_zoom = float(motion.get("minZoom", 0.8))
|
|
initial_ortho = serialized_ortho / min_zoom
|
|
initial_zoom_rule = {
|
|
"source": "startup.scene root/scene/Camera custom component 95c7akihY5GNYe9/Wanw0Ab",
|
|
"rule": "The world camera node serializes both cc.Camera._orthoHeight=640 and the source camera controller minZoom=0.8. Stage 1 startup uses the controller's minimum zoom as the default world zoom, so the generated startup orthographic height is 640 / 0.8 = 800.",
|
|
"serializedOrthoHeight": serialized_ortho,
|
|
"initialZoom": min_zoom,
|
|
"initialOrthoHeight": initial_ortho,
|
|
}
|
|
startup_scale_rule = {
|
|
"source": "startup.scene root/scene/Camera cc.Camera plus custom camera controller",
|
|
"rule": "Do not bind the Canvas to the world camera. Keep the source Canvas bound to uiCamera, then apply the source world-camera controller minZoom to the serialized camera height: startup world orthoHeight = 640 / 0.8 = 800.",
|
|
}
|
|
camera_rule_changed = (
|
|
motion.get("initialZoomRule") != initial_zoom_rule
|
|
or motion.get("startupScaleRule") != startup_scale_rule
|
|
)
|
|
motion["initialZoomRule"] = initial_zoom_rule
|
|
motion["startupScaleRule"] = startup_scale_rule
|
|
|
|
if changed or removed_legacy_camera_keys or removed_unproven_camera_rules or camera_rule_changed:
|
|
write_json(SOURCE_JSON, evidence)
|
|
|
|
report = {
|
|
"module": metadata.get("module"),
|
|
"sourceEvidence": str(SOURCE_JSON),
|
|
"conversionRulesPath": expected_rules_path,
|
|
"sourceFileCount": len(source_files),
|
|
"assetFileCount": len(asset_files),
|
|
"missing": missing,
|
|
"normalizedConversionRulesPath": changed,
|
|
"removedLegacyCameraKeys": removed_legacy_camera_keys,
|
|
"removedUnprovenCameraRules": removed_unproven_camera_rules,
|
|
"initialZoomRule": motion["initialZoomRule"],
|
|
"startupScaleRule": motion["startupScaleRule"],
|
|
"status": "pass" if not missing else "needs_solution",
|
|
}
|
|
write_json(REPORT_PATH, report)
|
|
|
|
if missing:
|
|
for item in missing:
|
|
print(f"missing: {item}")
|
|
return 1
|
|
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|