Files
cocos/tools/level_id.py
刘宇飞 d393302388 Complete Cocos Creator port with level bundles, themes, and tooling.
Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 15:30:58 +08:00

99 lines
2.8 KiB
Python

"""关卡 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")