# -*- coding: utf-8 -*- # FR 맵 폴더의 '쓰이지 않는 에셋' 목록 문서를 만든다 — 2026-09-28 PD 지시 # "남겨두되, 어떤 에셋이 안쓰이는지 기록해서 추후 삭제 유무를 결정할 수 있도록 정리해둘 것. (내가 나중에 물어보면 바로 알 수 있게 정리 필요)" # 순서: ① 유니티(편집 모드)에서 tools/unity_eval/unused_scan.cs 실행 → FR/Logs/bt_unused_maps_assets.json # ② python unused_report.py → 공유/기획/FirstRising/맵/미사용_에셋_목록.md # 묶음 · 까닭은 아래 RULES 에 적는다(새 묶음이 생기면 여기에 더한다). 어느 묶음에도 안 맞는 것은 '분류 안 됨'으로 나온다. import io, json, os, re, subprocess, sys, time FR = r"C:\BurningTimes\FirstRising" SRC = os.path.join(FR, "Logs", "bt_unused_maps_assets.json") OUT = r"E:\BurningTimes\공유\기획\FirstRising\맵\미사용_에셋_목록.md" # (묶음 열쇠, 묶음 이름, 경로 정규식, 안 쓰이게 된 까닭, 지워도 되는가(PM 의견), 되살리는 법) RULES = [ ("A", "던전 — 옛 지형 층", r"PlagueCatacomb/Terrain/Catacomb_(Rock|Paver|Floor|Slime)\.terrainlayer$", "BT38(2026-09-28)에서 던전 바닥 층을 던전 타일로 바꿨다. 옛 층 넷은 지형 데이터가 더는 가리키지 않는다", "지워도 된다", "git 에 있다(bt/work `159f17f6c0` 부터) — `git checkout <커밋> -- <경로>`"), ("B", "던전 — 옛 바닥 텍스처", r"PlagueCatacomb/Textures/FRMap_dun_(paver|slime)(_N)?\.png$", "옛 지형 층(A)만 쓰던 텍스처다 — 그려 만든 포석 · 점액 포석과 그 노멀맵", "지워도 된다(A 와 함께)", "git 에 있다(bt/work `159f17f6c0` 부터). 만든 도구는 준비 폴더 `texderive.py`"), ("C", "던전 — 1차 시도(깨진 타일)", r"PlagueCatacomb/(Terrain/Catacomb_TileBroken\.terrainlayer|Textures/FRMap_dun_tile_broken(_N)?\.png)$", "BT38 1차 시도에서 만든 깨진 타일 층. 화면 확인 뒤 흙 층으로 바꿔 쓰지 않게 됐다", "지워도 된다", "git 에 있다(bt/work `5f9c8dd297`). 팩의 `CatacombsFloorA2` 에서 다시 만들 수도 있다"), ("D", "큰 바닥돌의 재질 사본", r"_Shared/Materials/Lit/CATA_Floor[AB]_[0-9a-f]+_Lit\.mat$", "팩의 10 m 바닥 판(GroundTileCATAM)에 끼우던 재질 사본. BT38 에서 바닥돌 띠를 걷어내고 다리 판을 바꿔 쓰는 곳이 없다", "지워도 된다", "git 에 있다. 그 바닥 판을 다시 쓰면 빌더가 다시 만든다"), ("E", "옛 이름의 가림 반투명 재질 사본", r"/Materials/Fade/(?!.*_(Tuned|Lit)_Fade)(?!FRProp_).*_Fade\.mat$", "재질 사본의 이름 규칙이 바뀌기 전(BT31 초기 빌드)에 만든 것. 지금 씬은 `<이름>_<번호>_Tuned_Fade` 를 쓴다", "지워도 된다", "git 에 있다. 쓸 일은 없다"), ("F", "빌더의 중간 산출물(밝기 맞춘 재질 사본)", r"_Shared/Materials/Lit/.*_Tuned\.mat$", "씬은 이 사본에서 다시 만든 가림 반투명 사본(`_Tuned_Fade`)을 쓴다. 이 사본 자체는 씬이 가리키지 않지만 빌더가 맵을 지을 때 재료로 쓴다", "지울 실익이 없다(다음 빌드 때 다시 생긴다)", "맵을 다시 지으면 생긴다"), ] def tracked(paths): out = subprocess.run(["git", "-c", "core.quotepath=false", "ls-files", "--"] + paths, cwd=FR, capture_output=True).stdout.decode("utf-8", "replace") return set(l.strip() for l in out.splitlines() if l.strip()) def addressable(items): """쓰이지 않는 에셋이 어드레서블 설정에 등록돼 있는지 본다(등록돼 있으면 씬이 가리키지 않아도 빌드에 들어간다). (설정 파일 수, 걸린 에셋 수)""" import glob files = glob.glob(os.path.join(FR, "Assets", "AddressableAssetsData", "**", "*.asset"), recursive=True) hit = set() for f in files: text = io.open(f, encoding="utf-8", errors="replace").read() for i in items: if i["guid"] in text: hit.add(i["path"]) return len(files), len(hit) def kb(n): return "%.1f MB" % (n / 1048576.0) if n >= 1048576 else "%.1f KB" % (n / 1024.0) def main(): d = json.loads(io.open(SRC, encoding="utf-8").read()) items = d["unused"] paths = [i["path"] for i in items] tr = tracked(paths) stamp = time.strftime("%Y-%m-%d %H:%M", time.localtime(os.path.getmtime(SRC))) groups = {} for i in items: i["group"] = "?" for key, name, rx, why, ok, back in RULES: if re.search(rx, i["path"]): i["group"] = key break groups.setdefault(i["group"], []).append(i) L = [] L.append("# FR 맵 폴더 — 쓰이지 않는 에셋 목록") L.append("") L.append("> PD 지시(2026-09-28): \"남겨두되, 어떤 에셋이 안쓰이는지 기록해서 추후 삭제 유무를 결정할 수 있도록 정리해둘 것. (내가 나중에 물어보면 바로 알 수 있게 정리 필요)\"") L.append("> **지운 것은 없다.** 아래 에셋은 모두 프로젝트에 그대로 있다. 지울지는 PD 결정.") L.append("") L.append("## 한눈에") L.append("") L.append("| 항목 | 값 |") L.append("|---|---|") L.append("| 조사한 때 | %s [실측] |" % stamp) L.append("| 조사 범위 | FR `%s` (맵 작업으로 만든 에셋) — 에셋 %d개 |" % (d["scope"], d["total"])) L.append("| **쓰이지 않는 에셋** | **%d개 · %s** |" % (d["unusedCount"], kb(d["unusedBytes"]))) L.append("| 그 가운데 지워도 되는 것(PM 의견) | %d개 · %s |" % (sum(len(v) for k, v in groups.items() if k in "ABCDE"), kb(sum(i["bytes"] for k, v in groups.items() if k in "ABCDE" for i in v)))) addr_files, addr_hits = addressable(items) L.append("| 게임에 주는 영향 | 없다 — 씬 · 프리팹 어디에서도 가리키지 않는다. 어드레서블 설정 파일 %d개에 등록된 것 %d개 [실측]. 기기 빌드에 들어가는지는 빌드로 확인하지 않았다 |" % (addr_files, addr_hits)) L.append("") L.append("## 묶음별") L.append("") L.append("| 묶음 | 개수 | 용량 | 왜 안 쓰이게 됐나 | 지워도 되는가(PM 의견) | 되살리는 법 |") L.append("|---|---|---|---|---|---|") for key, name, rx, why, ok, back in RULES: v = groups.get(key, []) if not v: continue L.append("| **%s. %s** | %d | %s | %s | %s | %s |" % (key, name, len(v), kb(sum(i["bytes"] for i in v)), why, ok, back)) if "?" in groups: v = groups["?"] L.append("| **?. 분류 안 됨** | %d | %s | 까닭을 아직 적지 못했다 — 확인 필요 | 판단 보류 | — |" % (len(v), kb(sum(i["bytes"] for i in v)))) L.append("") L.append("## 전체 목록") L.append("") L.append("경로는 `%s/` 아래. 'git' = FR 저장소가 추적하는가." % d["scope"]) L.append("") L.append("| 묶음 | 경로 | 종류 | 크기 | git |") L.append("|---|---|---|---|---|") for i in sorted(items, key=lambda x: (x["group"], x["path"])): rel = i["path"][len(d["scope"]) + 1:] L.append("| %s | `%s` | %s | %s | %s |" % (i["group"], rel, i["type"], kb(i["bytes"]), "추적" if i["path"] in tr else "미추적")) L.append("") L.append("## '쓰이지 않는다'의 기준") L.append("") L.append("- **쓰인다**: ① 씬(`Assets/Scenes` 아래 전부) · 로비 프리팹(`LobbyPlayScene`) · 보스전 전용 필드 프리팹 · `Resources` 폴더의 에셋이 직접 또는 건너 건너 가리키는 것 " "② 맵 정의(`<맵>.map.json`) · 소품 목록(`props.json`)에 경로가 적힌 것과 그것이 가리키는 것 — 지금 맵에 놓이지 않았어도 빌더의 재료이므로 쓰이는 것으로 본다.") L.append("- **쓰이지 않는다**: 위 어디에도 걸리지 않는 것. 유니티의 의존 관계 조회(`AssetDatabase.GetDependencies`)로 판정했다 [실측].") L.append("- 기준이 된 에셋 %d개(정의 파일에서 %d개). 정의 파일(.json)과 폴더는 후보에서 뺐다." % (d["roots"], d["rootsFromJson"])) L.append("- **조사하지 않은 곳**: 맵 폴더 밖(`Assets/BurningTimes/Boss` · `Visual` 등)과 게임 원본 에셋. 코드가 경로 글자로 불러오는 에셋은 이 방법으로 잡히지 않는다 — 맵 폴더 안에는 그런 것이 없음을 확인했다(빌더는 정의 파일의 경로만 읽는다).") L.append("") L.append("## 지우기로 정하면") L.append("") L.append("1. 유니티 에디터의 Project 창에서 지운다(메타 파일이 함께 지워진다). 탐색기에서 지우면 메타 파일이 남는다.") L.append("2. 지운 뒤 확인: 컴파일 오류 0 → 해당 맵 다시 짓기(`BurningTimes/Maps/<맵>/Build`) RESULT OK → Play 에서 그 맵으로 이동해 에디터 로그 오류 0.") L.append("3. 묶음 A · B 는 함께 지운다(A 가 B 를 가리킨다 — A 만 남기면 빈 텍스처를 가리키는 층이 된다).") L.append("4. 묶음 F 는 지워도 다음 빌드 때 다시 생긴다.") L.append("") L.append("## 목록을 다시 만드는 법") L.append("") L.append("1. 유니티 편집 모드에서 `공유/기획/FirstRising/맵/tools/unity_eval/unused_scan.cs` 실행 → FR `Logs/bt_unused_maps_assets.json`") L.append("2. `python 공유/기획/FirstRising/맵/tools/unused_report.py` → 이 문서를 다시 쓴다(묶음 · 까닭은 스크립트의 RULES)") L.append("") L.append("## 그 밖의 정리 후보(에셋이 아닌 것)") L.append("") L.append("| 대상 | 크기 | 상태 | 비고 |") L.append("|---|---|---|---|") L.append("| 조직 레포 `공유/개발팀_백업/FirstRising/` | 약 1.2 GB | 미추적(레포에 올리지 않음) | FR 에셋을 바꾸기 전에 떠 둔 안전 사본. 91 MB 짜리 지형 데이터 10개 포함. 무시 목록(.gitignore)에 넣을지 PD 판단 |") L.append("| 조직 레포 `공유/기획/FirstRising/리뉴얼/~$…기획서_v1.pptx` | 165 B | 미추적 | 오피스 잠금 파일(파워포인트가 열어 둔 흔적) |") L.append("| 준비 폴더 `C:\\BurningTimes\\FR_maps_staging\\_work\\` | — | 저장소 밖 | 블렌더 굽기 · 텍스처 파생의 중간 결과. 다시 만들 수 있다 |") L.append("") io.open(OUT, "w", encoding="utf-8", newline="\n").write("\n".join(L)) print("쓴 곳", OUT) print("묶음", {k: len(v) for k, v in sorted(groups.items())}, "· 추적", len(tr), "· 미추적", len(items) - len(tr)) main()