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:
2026-06-16 15:30:58 +08:00
parent cba5105908
commit d393302388
6248 changed files with 17322729 additions and 11036 deletions

View File

@@ -0,0 +1,356 @@
#!/usr/bin/env python3
"""
从 Unity Assets/Texture 导入 PNG 到 Cocos assets/resources/textures/
用法:
python3 tools/import_unity_textures.py \\
--unity-root "/path/to/主站" \\
[--themes silu,snow,default]
"""
from __future__ import annotations
import argparse
import json
import shutil
import uuid
from pathlib import Path
# 与 GameController UIStyleNames 对应Unity 目录名 → Cocos 子目录)
THEME_MAP = {
"default": ".", # Assets/Texture 根目录单层 png
"silu": "silu",
"chinese": "Chinese",
"redArmy": "redarmy",
"numMan": "numMan",
"snow": "snow",
"sanxing": "sanxing",
}
# 角色 + 砖块核心文件名(各主题有则拷贝,无则跳过)
CORE_NAMES = {
"Baseblock.png",
"JumpBlock.png",
"WallBlock.png",
"player_F.png",
"player_B.png",
"ship_F.png",
"ship_B.png",
"Ship_F.png",
"Prop.png",
"nProp.png",
"kuai11.png",
"素材切图-23.png",
"素材切图2-23.png",
"Prop_kuai1.png",
"Prop_kuai2.png",
"Prop_kuai.png",
"nProp_kuai1.png",
"nProp_kuai2.png",
"nProp_kuai.png",
"Prop_Dumpling.png",
"Prop_Mooncake.png",
"Prop_Ricedumpling.png",
"Prop_Zhongzi.png",
"Prop_star.png",
"nProp_star.png",
"nProp_Dumpling.png",
"nProp_Mooncake.png",
"nProp_Ricedumpling.png",
"nProp_Zhongzi.png",
}
# 丝路:对齐 sanxing/snow 命名skin/待机正面、*Ship_F、Prop_kuai1
SILU_CANONICAL_COPIES: list[tuple[str, str]] = [
("ship_F.png", "siluShip_F.png"),
("ship_B.png", "siluShip_B.png"),
("Prop.png", "Prop_kuai1.png"),
("nProp.png", "nProp_kuai1.png"),
]
def ensure_directory_meta(meta_path: Path) -> None:
if meta_path.is_file():
return
meta_path.write_text(
json.dumps(
{
"ver": "1.2.0",
"importer": "directory",
"imported": True,
"uuid": str(uuid.uuid4()),
"files": [],
"subMetas": {},
"userData": {},
},
indent=2,
),
encoding="utf-8",
)
def ensure_image_meta(meta_path: Path, display_name: str) -> None:
if meta_path.is_file():
return
base_uuid = str(uuid.uuid4())
meta_path.write_text(
json.dumps(
{
"ver": "1.0.27",
"importer": "image",
"imported": False,
"uuid": base_uuid,
"files": [".json", ".png"],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": f"{base_uuid}@6c48a",
"displayName": display_name,
"id": "6c48a",
"name": "texture",
"userData": {
"imageUuidOrDatabaseUri": base_uuid,
"isUuid": True,
"visible": False,
},
"ver": "1.0.22",
"imported": False,
"files": [".json"],
"subMetas": {},
}
},
"userData": {"type": "texture", "redirect": f"{base_uuid}@6c48a"},
},
indent=2,
),
encoding="utf-8",
)
def ensure_png_meta(png_path: Path) -> None:
ensure_image_meta(png_path.with_suffix(".png.meta"), png_path.stem)
def first_existing_file(*candidates: Path) -> Path | None:
for path in candidates:
if path.is_file():
return path
return None
def copy_skin_tree(src_skin: Path, dst_skin: Path) -> None:
"""将 player/skin 整树复制到主题根 skin对齐 sanxing 目录结构)。"""
if not src_skin.is_dir():
return
dst_skin.mkdir(parents=True, exist_ok=True)
ensure_directory_meta(dst_skin.parent / f"{dst_skin.name}.meta")
for src in sorted(src_skin.rglob("*")):
rel = src.relative_to(src_skin)
dst = dst_skin / rel
if src.is_dir():
dst.mkdir(parents=True, exist_ok=True)
ensure_directory_meta(dst.parent / f"{dst.name}.meta")
continue
if src.suffix.lower() != ".png":
continue
dst.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src, dst)
ensure_png_meta(dst)
def normalize_silu_assets(theme_dir: Path) -> None:
"""拷贝丝路实体贴图为标准文件名(保留 Unity 原名,额外写规范别名)。"""
skin_root = theme_dir / "skin"
player_skin = theme_dir / "player" / "skin"
if player_skin.is_dir():
copy_skin_tree(player_skin, skin_root)
skin_front = skin_root / "待机正面"
skin_back = skin_root / "待机背面"
skin_front.mkdir(parents=True, exist_ok=True)
skin_back.mkdir(parents=True, exist_ok=True)
ensure_directory_meta(skin_root.parent / f"{skin_root.name}.meta")
ensure_directory_meta(skin_front.parent / f"{skin_front.name}.meta")
ensure_directory_meta(skin_back.parent / f"{skin_back.name}.meta")
front_src = first_existing_file(
skin_front / "1.png",
player_skin / "待机正面" / "1.png",
theme_dir / "player" / "idel-正" / "1.png",
theme_dir / "player_F.png",
)
if front_src and front_src != skin_front / "1.png":
shutil.copy2(front_src, skin_front / "1.png")
if (skin_front / "1.png").is_file():
ensure_png_meta(skin_front / "1.png")
back_src = first_existing_file(
skin_back / "1.png",
player_skin / "待机背面" / "1.png",
theme_dir / "player" / "idel-反" / "1.png",
theme_dir / "player_B.png",
)
if back_src and back_src != skin_back / "1.png":
shutil.copy2(back_src, skin_back / "1.png")
if (skin_back / "1.png").is_file():
ensure_png_meta(skin_back / "1.png")
for src_name, dst_name in SILU_CANONICAL_COPIES:
src = theme_dir / src_name
dst = theme_dir / dst_name
if src.is_file():
shutil.copy2(src, dst)
ensure_png_meta(dst)
def normalize_nprop_filenames(theme_dir: Path) -> None:
"""Unity numMan 等主题 nProp 文件名可能带尾空格,统一为无空格文件名。"""
for png in theme_dir.rglob("nProp*.png"):
stem = png.stem
if stem != stem.rstrip():
fixed = png.with_name(f"{stem.rstrip()}.png")
if fixed != png:
if fixed.is_file():
png.unlink()
else:
png.rename(fixed)
meta = png.with_suffix(".png.meta")
fixed_meta = fixed.with_suffix(".png.meta")
if meta.is_file() and not fixed_meta.is_file():
meta.rename(fixed_meta)
# HUD 按钮UIMain 右侧,与 themes-database.json hud 字段对应)
HUD_GLOBS = (
"anniu_*.png",
"redarmy*.png",
"素材切图-*.png",
"素材切图2-*.png",
"1倍速.png",
"2倍速.png",
"4倍速.png",
"声音.png",
"声音关闭.png",
"导航图标.png",
"重置.png",
"放大图标.png",
"缩小图标.png",
)
def copy_hud_assets(unity_tex: Path, out_root: Path, style_key: str, rel: str) -> int:
"""拷贝 Unity UI 按钮贴图(原先 rglob 会跳过 anniu_/倍速/声音)"""
src = unity_tex if rel == "." else unity_tex / rel
if not src.is_dir():
return 0
dst = out_root / style_key
dst.mkdir(parents=True, exist_ok=True)
count = 0
seen: set[str] = set()
for pattern in HUD_GLOBS:
for png in src.glob(pattern):
if not png.is_file():
continue
key = str(png.resolve())
if key in seen:
continue
seen.add(key)
target = dst / png.name
shutil.copy2(png, target)
count += 1
return count
def copy_theme(unity_tex: Path, out_root: Path, style_key: str, rel: str) -> int:
src = unity_tex if rel == "." else unity_tex / rel
dst = out_root / style_key
dst.mkdir(parents=True, exist_ok=True)
count = 0
if rel == ".":
for png in src.glob("*.png"):
shutil.copy2(png, dst / png.name)
if png.name == "Ship_F.png":
shutil.copy2(png, dst / "ship_F.png")
count += 1
return count
if not src.is_dir():
print(f" skip missing theme dir: {src}")
return 0
for png in src.rglob("*.png"):
rel_path = png.relative_to(src)
# 跳过 HUD 专用碎图(由 copy_hud_assets 扁平拷贝到主题根目录)
if png.name.startswith("anniu_") or "倍速" in png.name or png.name.startswith("声音"):
continue
if png.name.startswith("素材切图") or png.name.startswith("redarmy"):
continue
target = dst / rel_path
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(png, target)
count += 1
# silu 装饰砖块别名(烘焙脚本用 Decor23
decor = dst / "素材切图-23.png"
if decor.is_file():
shutil.copy2(decor, dst / "Decor23.png")
normalize_nprop_filenames(dst)
if style_key == "silu":
normalize_silu_assets(dst)
return count
def copy_prop(unity_tex: Path, out_root: Path) -> int:
src = unity_tex / "Prop"
if not src.is_dir():
return 0
dst = out_root / "prop"
dst.mkdir(parents=True, exist_ok=True)
n = 0
for png in src.glob("*.png"):
name = png.name.replace("载具 正面", "vehicle_F").replace("载具 背面", "vehicle_B")
shutil.copy2(png, dst / name)
n += 1
return n
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--unity-root", required=True)
ap.add_argument("--out", default="assets/resources/textures")
ap.add_argument("--themes", default=",".join(THEME_MAP.keys()))
args = ap.parse_args()
project = Path(__file__).resolve().parent.parent
unity_tex = Path(args.unity_root) / "Assets" / "Texture"
out_root = project / args.out
if not unity_tex.is_dir():
raise SystemExit(f"Unity Texture 不存在: {unity_tex}")
themes = [t.strip() for t in args.themes.split(",") if t.strip()]
total = 0
for key in themes:
rel = THEME_MAP.get(key)
if rel is None:
print(f"unknown theme: {key}")
continue
n = copy_theme(unity_tex, out_root, key, rel)
hn = copy_hud_assets(unity_tex, out_root, key, rel)
print(f" {key}: {n} png (+ {hn} hud)")
total += n + hn
pn = copy_prop(unity_tex, out_root)
print(f" prop: {pn} png")
total += pn
print(f"Imported {total} files -> {out_root}")
print("请在 Cocos Creator 中刷新 assets/resources/textures然后运行:")
print(" python3 tools/fix_tile_texture_metas.py")
if __name__ == "__main__":
main()