"""关卡 ID 约定:与 Unity 首关 91601、主站 config.js BEGINNING_REAL_LVID 一致。""" from __future__ import annotations import json from datetime import datetime, timezone from pathlib import Path LEVEL_ID_BASE = 91601 # Unity 首关 / 主站 BEGINNING_REAL_LVID PREFAB_DIR = "level-prefabs" LEVEL_DB_REL = "assets/level-data/levels-database.json" def level_db_path(project: Path) -> Path: return project / LEVEL_DB_REL def is_game_level_id(level_id: int) -> bool: return level_id >= LEVEL_ID_BASE def normalize_level_id(raw_id: int) -> int: """Unity Levels*.cs 中的 ID 原样使用,不做 Cocos 侧二次编号。""" return raw_id def internal_level_index(level_id: int) -> int: if is_game_level_id(level_id): return level_id - LEVEL_ID_BASE return level_id def is_external_level_id(level_id: int) -> bool: return is_game_level_id(level_id) def prefab_resource_path(level_id: int) -> str: return f"{PREFAB_DIR}/Level{level_id}" def normalize_db(data: dict) -> dict: data.setdefault("levels", {}) data["levelIdBase"] = LEVEL_ID_BASE return data def next_available_level_id(data: dict) -> int: levels = data.get("levels") or {} ids: list[int] = [] for key in levels: try: ids.append(int(key)) except ValueError: continue if not ids: return LEVEL_ID_BASE return max(ids) + 1 def sync_level_entry(cfg: dict, level_id: int) -> dict: out = dict(cfg) out["levelID"] = level_id out["cocosPrefab"] = prefab_resource_path(level_id) unity = out.get("unityPrefab") if isinstance(unity, str) and unity: import re out["unityPrefab"] = re.sub( r"Level\d+\.prefab$", f"Level{level_id}.prefab", unity.replace("\\", "/"), flags=re.I, ) return out def update_db_stats(data: dict) -> None: levels = data.get("levels") or {} total = len(levels) data["stats"] = { **(data.get("stats") or {}), "total": total, "withPrefabTilemap": total, } def touch_database(db_path: Path, level_ids: list[int] | None = None) -> None: """保存/烘焙后刷新数据库元数据与关卡条目。""" if not db_path.is_file(): return data = normalize_db(json.loads(db_path.read_text(encoding="utf-8"))) ids = level_ids if level_ids is not None else [int(k) for k in data["levels"]] for lid in ids: key = str(lid) if key not in data["levels"]: continue data["levels"][key] = sync_level_entry(data["levels"][key], lid) update_db_stats(data) data["generatedAt"] = datetime.now(timezone.utc).isoformat() db_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")