Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration. Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
2.8 KiB
Python
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")
|