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.
AdLike2048/tools/patch_maplayer1_grid_sprite...

164 lines
5.3 KiB

3 weeks ago
#!/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())