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>
This commit is contained in:
98
tools/level_id.py
Normal file
98
tools/level_id.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""关卡 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")
|
||||
Reference in New Issue
Block a user