图层修改

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-14 16:02:20 +08:00
parent ff1542c24f
commit ae75fce80b
5121 changed files with 17930 additions and 16467861 deletions

View File

@@ -1,12 +1,32 @@
#!/usr/bin/env python3
"""从 Unity Level{N}.prefab 解析 TilemapGround / Border格子数据。"""
"""从 Unity Level{N}.prefab 解析 TilemapGround / Border格子数据。
层级锁定:
- Baseblock / JumpBlock → ground地砖属性
- WallBlock / 墙饰 → border墙砖属性
不再用死板的 tileIndex==1 → JumpBlock。
"""
from __future__ import annotations
import re
from functools import lru_cache
from pathlib import Path
GROUND_TILES = frozenset({"Baseblock", "JumpBlock"})
BORDER_DECOR = frozenset(
{
"WallBlock",
"kuai11",
"Decor23",
"素材切图-23",
"素材切图2-23",
"小游戏素材红色_03",
}
)
def parse_tilemap_layer(text: str, layer_name: str) -> dict[str, int]:
"""返回格子 → 该 Tilemap 本地 m_TileIndex。"""
parts = re.split(r"(?=--- !u!1 &)", text)
for part in parts:
if f"m_Name: {layer_name}" not in part or "Tilemap:" not in part:
@@ -22,7 +42,84 @@ def parse_tilemap_layer(text: str, layer_name: str) -> dict[str, int]:
return {}
def parse_level_prefab(prefab_path: Path) -> dict:
def _tilemap_part(text: str, layer_name: str) -> str | None:
parts = re.split(r"(?=--- !u!1 &)", text)
for part in parts:
if f"m_Name: {layer_name}" not in part or "Tilemap:" not in part:
continue
return part
return None
def _tile_asset_guids(tilemap_part: str) -> list[str | None]:
"""按 m_TileAssetArray 顺序解析 guid空槽为 None"""
assets: list[str | None] = []
in_arr = False
for line in tilemap_part.splitlines():
if "m_TileAssetArray:" in line:
in_arr = True
continue
if in_arr and ("m_TileSpriteArray" in line or "m_AnimationFrameRate" in line):
break
if not in_arr:
continue
if "guid:" in line:
m = re.search(r"guid: ([a-f0-9]+)", line)
assets.append(m.group(1) if m else None)
elif "m_Data: {fileID: 0}" in line:
assets.append(None)
return assets
@lru_cache(maxsize=1)
def _guid_to_tile_name(unity_texture_root: str) -> dict[str, str]:
root = Path(unity_texture_root)
out: dict[str, str] = {}
if not root.is_dir():
return out
for meta in root.rglob("*.asset.meta"):
try:
text = meta.read_text(encoding="utf-8", errors="ignore")
except OSError:
continue
m = re.search(r"^guid: ([a-f0-9]+)", text, re.M)
if m:
out[m.group(1)] = meta.name.replace(".asset.meta", "")
return out
def tile_asset_names(text: str, layer_name: str, unity_texture_root: Path | None = None) -> list[str | None]:
part = _tilemap_part(text, layer_name)
if not part:
return []
guids = _tile_asset_guids(part)
if unity_texture_root is None:
# 默认prefab 所在工程 Assets/Texture
return [None] * len(guids)
mapping = _guid_to_tile_name(str(unity_texture_root))
return [mapping.get(g) if g else None for g in guids]
def normalize_ground_tile(name: str | None) -> str:
return "JumpBlock" if name == "JumpBlock" else "Baseblock"
def normalize_border_tile(name: str | None) -> str:
if not name or name in GROUND_TILES:
return "WallBlock"
if name in BORDER_DECOR:
return name
# 其它墙饰保留文件名,禁止地砖名漏到墙层
return name
def _resolve_name(assets: list[str | None], tile_index: int) -> str | None:
if 0 <= tile_index < len(assets):
return assets[tile_index]
return None
def parse_level_prefab(prefab_path: Path, unity_texture_root: Path | None = None) -> dict:
if not prefab_path.is_file():
return {}
text = prefab_path.read_text(encoding="utf-8")
@@ -30,8 +127,35 @@ def parse_level_prefab(prefab_path: Path) -> dict:
b_raw = parse_tilemap_layer(text, "Border")
if not g_raw and not b_raw:
return {}
ground = {
k: ("JumpBlock" if ti == 1 else "Baseblock") for k, ti in g_raw.items()
}
border = {k: True for k in b_raw}
if unity_texture_root is None:
# Level91601.prefab → …/Assets/Prefabs/Level → …/Assets/Texture
unity_texture_root = prefab_path.resolve().parents[2] / "Texture"
g_assets = tile_asset_names(text, "Ground", unity_texture_root)
b_assets = tile_asset_names(text, "Border", unity_texture_root)
ground: dict[str, str] = {}
border: dict[str, str] = {}
# 按瓦片类型归层层级固定地砖→Ground墙/饰→Border
for key, ti in g_raw.items():
name = _resolve_name(g_assets, ti)
if name in GROUND_TILES:
ground[key] = normalize_ground_tile(name)
else:
border[key] = normalize_border_tile(name)
for key, ti in b_raw.items():
name = _resolve_name(b_assets, ti)
if name in GROUND_TILES:
ground[key] = normalize_ground_tile(name)
else:
border[key] = normalize_border_tile(name)
# 同格冲突:墙优先(不可走)
for key in list(ground.keys()):
if key in border:
del ground[key]
return {"ground": ground, "border": border}