104 lines
3.4 KiB
Python
104 lines
3.4 KiB
Python
"""Print per-GUID analysis of the foreground Tilemap to help identify TileIds.
|
|
|
|
For each tile asset GUID, prints:
|
|
- count
|
|
- bounding box (min/max x, y in Unity cell coords)
|
|
- 5 sample positions
|
|
- top neighbor distribution: which GUID most often sits directly ABOVE this one
|
|
- bottom neighbor distribution: which GUID most often sits directly BELOW
|
|
|
|
Run:
|
|
python tools/analyze_foreground.py
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from collections import Counter, defaultdict
|
|
from typing import Dict, Tuple
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import unity_to_level as u2l
|
|
|
|
|
|
def short(guid: str) -> str:
|
|
return guid[:8]
|
|
|
|
|
|
def main() -> int:
|
|
with open(u2l.SCENE_PATH, "r", encoding="utf-8") as f:
|
|
text = f.read()
|
|
docs = u2l.split_documents(text)
|
|
go_names = u2l.parse_gameobjects(docs)
|
|
tms = u2l.parse_tilemaps(docs, go_names)
|
|
|
|
fg = tms.get("foreground")
|
|
if not fg:
|
|
print("no foreground tilemap")
|
|
return 1
|
|
|
|
# Build a (x, y) -> guid map; drop duplicates conservatively.
|
|
cell_guid: Dict[Tuple[int, int], str] = {}
|
|
for x, y, idx in fg.cells:
|
|
if 0 <= idx < len(fg.asset_guids):
|
|
cell_guid[(x, y)] = fg.asset_guids[idx]
|
|
|
|
# Group cells by guid.
|
|
by_guid: Dict[str, list] = defaultdict(list)
|
|
for (x, y), guid in cell_guid.items():
|
|
by_guid[guid].append((x, y))
|
|
|
|
# Order by count desc.
|
|
ordered = sorted(by_guid.items(), key=lambda kv: -len(kv[1]))
|
|
|
|
print(f"foreground tile assets: {len(fg.asset_guids)}, total cells: {len(cell_guid)}")
|
|
print()
|
|
for guid, cells in ordered:
|
|
xs = [c[0] for c in cells]
|
|
ys = [c[1] for c in cells]
|
|
# Neighbors: in Unity Y is up, so "above" = y+1, "below" = y-1.
|
|
above_counter: Counter = Counter()
|
|
below_counter: Counter = Counter()
|
|
left_counter: Counter = Counter()
|
|
for x, y in cells:
|
|
up = cell_guid.get((x, y + 1))
|
|
dn = cell_guid.get((x, y - 1))
|
|
lf = cell_guid.get((x - 1, y))
|
|
above_counter[up] += 1 # None means empty/sky
|
|
below_counter[dn] += 1
|
|
left_counter[lf] += 1
|
|
|
|
# Sample positions: a few spread out cells.
|
|
sample = sorted(cells)[:: max(1, len(cells) // 5)][:5]
|
|
|
|
print(f"{short(guid)} ({guid})")
|
|
print(f" count : {len(cells)}")
|
|
print(f" bbox : x [{min(xs)} .. {max(xs)}] y [{min(ys)} .. {max(ys)}]")
|
|
print(f" samples: {sample}")
|
|
# top 3 of each direction
|
|
def fmt(c: Counter) -> str:
|
|
top = c.most_common(3)
|
|
return ", ".join(
|
|
f"{short(g) if g else '<empty>'}={n}" for g, n in top
|
|
)
|
|
print(f" above (Unity y+1): {fmt(above_counter)}")
|
|
print(f" below (Unity y-1): {fmt(below_counter)}")
|
|
print(f" left : {fmt(left_counter)}")
|
|
# If almost all rows are the same y, it's probably a horizontal-only tile.
|
|
y_hist = Counter(ys)
|
|
top_y = y_hist.most_common(3)
|
|
print(f" y histogram (top 3): {top_y}")
|
|
# Single-row or single-col flag
|
|
if len(set(ys)) <= 2:
|
|
print(f" >>> appears on only {len(set(ys))} distinct row(s) — likely a 'top' or row-specific tile")
|
|
if len(set(xs)) <= 2:
|
|
print(f" >>> appears on only {len(set(xs))} distinct column(s)")
|
|
print()
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|