You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
5.3 KiB
163 lines
5.3 KiB
#!/usr/bin/env python3
|
|
"""为 mapLayer 格子层所有 MapGrid 实例统一 digSprite / putSprite(参考 grid0)。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from copy import deepcopy
|
|
from pathlib import Path
|
|
|
|
MAP_GRID_PREFAB_UUID = "5d1d936e-4aad-4dea-a4ed-65596d036a4e"
|
|
MAP_GRID_LOCAL_ID = "a5Czjqnj1DIa/1qXv6uwzF"
|
|
GRID_PARENT_NAME = "格子"
|
|
|
|
|
|
def load_prefab(path: Path) -> list:
|
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
|
|
|
|
def save_prefab(path: Path, data: list) -> None:
|
|
path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
|
|
|
|
def resolve(data: list, ref) -> dict | None:
|
|
if ref is None:
|
|
return None
|
|
if isinstance(ref, dict) and "__id__" in ref:
|
|
return data[ref["__id__"]]
|
|
return None
|
|
|
|
|
|
def find_grid_parent_id(data: list) -> int | None:
|
|
for i, obj in enumerate(data):
|
|
if obj.get("__type__") == "cc.Node" and obj.get("_name") == GRID_PARENT_NAME:
|
|
return i
|
|
return None
|
|
|
|
|
|
def collect_instance_overrides(data: list, instance: dict) -> list[dict]:
|
|
overrides: list[dict] = []
|
|
for ref in instance.get("propertyOverrides", []):
|
|
ov = resolve(data, ref)
|
|
if ov is not None:
|
|
overrides.append(ov)
|
|
return overrides
|
|
|
|
|
|
def get_grid_name(data: list, overrides: list[dict]) -> str | None:
|
|
for ov in overrides:
|
|
if ov.get("propertyPath") == ["_name"]:
|
|
return ov.get("value")
|
|
return None
|
|
|
|
|
|
def find_mapgrid_target_id(data: list, overrides: list[dict]) -> int | None:
|
|
for ov in overrides:
|
|
target = resolve(data, ov.get("targetInfo"))
|
|
if target and target.get("localID") == [MAP_GRID_LOCAL_ID]:
|
|
return ov["targetInfo"]["__id__"]
|
|
return None
|
|
|
|
|
|
def sprite_value(uuid: str) -> dict:
|
|
return {
|
|
"__uuid__": uuid,
|
|
"__expectedType__": "cc.SpriteFrame",
|
|
}
|
|
|
|
|
|
def patch_prefab(data: list) -> tuple[int, int, int]:
|
|
parent_id = find_grid_parent_id(data)
|
|
if parent_id is None:
|
|
raise RuntimeError(f"未找到节点「{GRID_PARENT_NAME}」")
|
|
|
|
parent = data[parent_id]
|
|
dig_ref: dict | None = None
|
|
put_ref: dict | None = None
|
|
added = 0
|
|
updated = 0
|
|
skipped = 0
|
|
|
|
for child_ref in parent.get("_children", []):
|
|
child = resolve(data, child_ref)
|
|
if child is None:
|
|
continue
|
|
prefab_info = resolve(data, child.get("_prefab"))
|
|
if prefab_info is None:
|
|
continue
|
|
asset = prefab_info.get("asset", {})
|
|
if asset.get("__uuid__") != MAP_GRID_PREFAB_UUID:
|
|
continue
|
|
instance = resolve(data, prefab_info.get("instance"))
|
|
if instance is None:
|
|
continue
|
|
|
|
overrides = collect_instance_overrides(data, instance)
|
|
grid_name = get_grid_name(data, overrides)
|
|
mapgrid_target_id = find_mapgrid_target_id(data, overrides)
|
|
if mapgrid_target_id is None:
|
|
print(f"warn: {grid_name or child_ref} 无 MapGrid TargetInfo,跳过", file=sys.stderr)
|
|
skipped += 1
|
|
continue
|
|
|
|
if grid_name == "grid0":
|
|
for ov in overrides:
|
|
path = ov.get("propertyPath", [])
|
|
if path == ["digSprite"]:
|
|
dig_ref = deepcopy(ov.get("value"))
|
|
elif path == ["putSprite"]:
|
|
put_ref = deepcopy(ov.get("value"))
|
|
continue
|
|
|
|
if dig_ref is None or put_ref is None:
|
|
raise RuntimeError("grid0 缺少 digSprite 或 putSprite 引用")
|
|
|
|
existing: dict[str, dict] = {}
|
|
for ov in overrides:
|
|
path = ov.get("propertyPath", [])
|
|
if path in (["digSprite"], ["putSprite"]):
|
|
existing[path[0]] = ov
|
|
|
|
for prop, ref_value in (("digSprite", dig_ref), ("putSprite", put_ref)):
|
|
if prop in existing:
|
|
if existing[prop].get("value") != ref_value:
|
|
existing[prop]["value"] = deepcopy(ref_value)
|
|
updated += 1
|
|
else:
|
|
new_ov = {
|
|
"__type__": "CCPropertyOverrideInfo",
|
|
"targetInfo": {"__id__": mapgrid_target_id},
|
|
"propertyPath": [prop],
|
|
"value": deepcopy(ref_value),
|
|
}
|
|
data.append(new_ov)
|
|
instance.setdefault("propertyOverrides", []).append({"__id__": len(data) - 1})
|
|
added += 1
|
|
|
|
return added, updated, skipped
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="统一 mapLayer 格子 MapGrid 的 digSprite / putSprite")
|
|
parser.add_argument(
|
|
"prefab",
|
|
nargs="?",
|
|
default="mapLayer1.prefab",
|
|
help="预制体文件名,如 mapLayer1.prefab / mapLayer2.prefab",
|
|
)
|
|
args = parser.parse_args()
|
|
prefab_path = Path(__file__).resolve().parents[1] / "assets/bundles/battleMap/prefab/地图" / args.prefab
|
|
if not prefab_path.is_file():
|
|
print(f"错误: 找不到 {prefab_path}", file=sys.stderr)
|
|
return 1
|
|
data = load_prefab(prefab_path)
|
|
added, updated, skipped = patch_prefab(data)
|
|
save_prefab(prefab_path, data)
|
|
print(f"{prefab_path.name}: 新增 {added} 条, 更新 {updated} 条, 跳过 {skipped} 个实例")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|
|
|