Project_WL/CLAUDE.md

13 KiB
Raw Blame History

WL 프로젝트 (What's your level?) — Unity 에디터 제어 가이드

Unity 6000.3.23f1 · URP 17.3 · 3D RPG. 조직 규칙·세션 절차의 SOT 는 NerdNavisAi 레포의 profile-wl 스킬이고, 이 파일은 이 프로젝트에서 에이전트가 Unity 에디터를 다루는 방법만 다룬다.

1. 에디터 제어 = Unity 공식 CLI + Pipeline 패키지 (커뮤니티 unity-mcp 사용 금지)

  • 2026-09-03 부로 WL 은 CoplayDev unity-mcp 브릿지(Assets/unity-mcp/)를 제거하고 Unity CLI(unity) + com.unity.pipeline 로 전환했다. mcp__unity-mcp__* 도구는 이 프로젝트에서 호출하지 않는다 (.claude/settings.json deny).
  • 에디터가 켜져 있으면 Pipeline 서버가 자동 기동한다 (포트 7800~7849 · 설정 에셋 Assets/Settings/Pipeline/EditorPipelineManager.asset).
  • 호출 방식 2가지 — ①이 기본 (공식 권장 · MCP 왕복보다 빠르고 토큰이 적다):
    1. unity command <이름> [--인자 값] 을 Bash/PowerShell 도구로 직접 실행 (unity cmd 동일)
    2. MCP 서버 unity (= unity mcp, Claude 데스크톱 전역 등록) — 셸을 못 쓰는 클라이언트용 보조 경로. 🔴 claude_desktop_config.json앱이 켜진 채 외부 편집하면 앱의 환경설정 저장 시 덮어써져 유실된다 (2026-09-03 실증 · 등록 후 사라짐). 앱 재시작 후 unity mcp configure --listclaude ✓ configured 를 확인하고, 없으면 unity mcp configure claude --yes 를 다시 실행한다. 앱 실행 중에는 그 파일을 손대지 않는다.
  • unity 를 찾지 못하면(PATH 갱신 전에 켜진 앱) 전체 경로 %LOCALAPPDATA%\Unity\bin\unity.exe 로 호출한다.
  • Windows 경로 인자가 들어가는 명령은 PowerShell 로 실행한다 (Git Bash 는 D:\… 를 현재 폴더와 섞어 버린다). 인자 없는 짧은 명령은 Bash 도 무방.
  • 명령 목록·인자 스키마 = unity command (이름 없이) 또는 unity command --query wl_. 정확한 문법은 unity <명령> --help 로 재확인 (CLI 는 베타).
  • 인자 안에 큰따옴표가 들어가는 C# (eval --code "new GameObject(\"X\")" 류)은 PowerShell 5.1 이 따옴표를 벗겨 깨진다 → .cs 파일로 두고 unity command eval_file --file <경로> 를 쓰거나, python Tools/Pipeline/pipeline_client.py eval "<코드>" (구조화 JSON 전송 · 따옴표 안전) 를 쓴다.

1-1. 사용 규칙·함정 (2026-09-04 #738 — 타 조직 문서 검토 후 채택분 + 이 프로젝트 실측분 · 첫 CLI 조작 전 1회 Read)

  • "Unity CLI" = 켜져 있는 에디터에 붙는 unity command …(com.unity.pipeline) 이다. -batchmode/-quit/unity run 으로 새 Unity 프로세스를 띄우는 것이 아니다 — 그쪽은 CI 빌드 전용.
  • eval/eval_file 코드에는 using 을 쓸 수 없다(메서드 본문처럼 감싸여 실행) → 네임스페이스를 전부 풀어 쓴다(UnityEngine.·UnityEditor.·System.Collections.Generic. 은 이미 들어와 있어 생략 가능하나, 안전하게 풀어 쓴다). 여러 줄 C# 도 eval_file 로 충분하다(이 프로젝트 실측 수십 회) · run_script 는 진입점(정적 메서드)이 있는 파일용.
  • 첫 Roslyn 컴파일은 느리다 → 기본 5초를 넘기면 --timeout 60 을 준다(격자 스캔 등 무거운 eval 도 동일).
  • PowerShell → CLI 인자: 공백·따옴표가 든 문자열(경로·JSON)은 깨질 수 있다. 오브젝트 지정은 경로 문자열 대신 find_gameobjects 로 얻은 숫자 instanceId 를 쓴다. .ps1 안에 한글 정규식·문자열을 두면 PowerShell 5.1 이 ANSI 로 읽어 깨진다 → 스크립트 안 문자열은 ASCII 로(한글은 .cs eval 파일에만).
  • PowerShell 함수 이름 R 금지(Invoke-History 별칭 충돌) · 리컴파일 직후 Connection reset by server 는 도메인 리로드 중 정상 → 폴링에서 ERR 문자열을 종료 조건으로 쓰지 말 것.
  • Play 중 recompile 은 멈춘 것처럼 보인다(수 분간 triggered) → editor_statusplaying 이면 editor_stop(PD 승인) 후 실행. 새 .cs 파일 복사도 Play 중엔 하지 않는다(포커스 시 자동 리컴파일이 PD 테스트를 끊는다) — 스크래치에 스테이징 후 정지 뒤 복사.
  • 구조화 명령 한계: remove_component/add_component 가 "Could not resolve component type" 을 내면 재시도 대신 eval_file 로 우회 · save_prefab_contents 는 이름·활성 토글만(계층 구성은 eval_file) · apply_prefab_overrides --instance 가 "not part of a prefab instance" 를 내면 PrefabUtility.ApplyPrefabInstance(root, InteractionMode.AutomatedAction) 로.
  • 프리팹 편집 정석 = PrefabUtility.LoadPrefabContents → 수정 → SaveAsPrefabAssetUnloadPrefabContents(예외 시 저장 안 됨 = 반쯤 망가지지 않음). 씬 인스턴스를 프리팹에 반영 = IsPartOfPrefabInstance 확인 후 ApplyPrefabInstance. 씬 오브젝트를 새 프리팹으로 = SaveAsPrefabAssetAndConnect.
  • 리플렉션으로 [SerializeField] List<T> 채우기 = 필드의 정확한 제네릭 타입(typeof(List<>).MakeGenericType(concrete) + Activator.CreateInstance)으로 만든다 — List<Component> 같은 부정확한 타입은 런타임 에러.
  • 캡처: capture_game_view --source screen 은 Play 중만(오버레이 UI 포함) · save_path 는 항상 Assets/ 아래에 저장되므로 캡처 후 프로젝트 루트 Screenshots_WL/ 로 옮기고 Assets/Screenshots_WL+.meta 를 지운다(에셋 오염 방지).
  • 디바이스 시뮬레이터(게임 뷰 1080×2280 등)에서는 Pointer.current 가 시뮬레이터 터치스크린이라 런타임 simulate_pointer(마우스)가 무시된다 → 터치는 InputSystem.QueueStateEvent(Touchscreen.current, new TouchState{…}) 로 주입(단, Began 만 보내면 곧 사라지므로 Moved 를 이어서).
  • SerializeField 이름 변경: FormerlySerializedAs 를 그대로 쓴다(씬·프리팹·브랜치 전반에 안전). CLI set_serialized_field 재배선은 소수 오브젝트를 즉석에서 고칠 때의 보조 수단.

2. 세션 시작 체크 (순서대로)

unity status                                   # WL 에디터가 ready 로 보이는지 (포트·PID)
unity command editor_status                    # playing / compiling / blocked_by_dialog 확인
unity command set_autotick --enable true       # 포커스 없어도 컴파일·테스트가 진행되게 (필수)
  • editor_statusplaying 이면 PD 가 직접 테스트 중일 수 있다 → 리컴파일·Play 전환·씬 저장을 하지 말고 먼저 PD 에게 확인한다.
  • blocked_by_dialog 면 모달 다이얼로그가 메인 스레드를 막고 있다 → CLI 로는 못 닫는다. 제목·메시지를 PD 에게 보고.
  • 에디터가 여러 개면 --project-path D:\NerdNavis\IdleRPG\WLevelRPG 로 대상을 고정한다.
  • 동시에 두 자동화 채널(다른 세션·사람)이 같은 에디터를 조작하지 않는다.

3. 코드 수정 → 검증 루프

unity command recompile
unity command recompile_status                 # completed | up_to_date 까지 반복 (failed 면 errors 배열 확인)
unity command get_console_logs --severity error --limit 20
unity command run_tests --mode editor --filter <TestClass>
  • 컴파일 판정 = recompile_status 가 completed/up_to_date 이고 콘솔 error 0 (조직 C39 정합).
  • 도메인 리로드 중 연결 오류는 정상 — 잠시 후 재시도. 종료 코드 2 = 인자 오류(명령줄 수정), 6 = 에디터 쪽 실패(같은 명령 재시도 무의미).

4. 에디터 재실행 없이 런타임 변경 (PD 요구 핵심)

방법 언제 명령
eval 한 줄짜리 즉석 조작 (Play 중 값 확인·변경) unity command eval --code "return UnityEngine.Time.timeScale;"
run_script 여러 줄 · 대량 생성 · 반복 실행 — 도메인 리로드 없이 인메모리 컴파일(~2s) AgentScripts/Build.cspublic static class Build { public static object Run() { … } }unity command run_script --file AgentScripts/Build.cs --entry Build.Run
Hot Reload (파일) Play 중 메서드 본문을 고쳐 즉시 반영 대상 메서드에 [HotReload] (public · 반환 void/IEnumerator) → 본문 수정 → unity command reload_file --filename Assets/WL/Scripts/….cs
Hot Reload (감시) 저장만 하면 자동 반영 에디터 Window ▸ Pipeline ▸ Settings… ▸ Hot Reload Interpreter Watch ▸ Start Watching (감시 중엔 자동 리프레시가 꺼진다 · 끝나면 Stop)
WL 커스텀 명령 프로젝트 전용 동작 unity command wl_info 등 (§6)
  • [HotReload] = using Unity.Pipeline.HotReload; · public 메서드 · void/IEnumerator 만 · 본문이 만지는 멤버도 public 만 (private setter 프로퍼티·private 필드를 쓰면 리로드 컴파일 실패 — 2026-09-03 실측). 상태 재초기화는 [OnHotReload] 콜백. 예시 = Assets/WL/Scripts/Debug/WLHotReloadProbe.cs (실검증 2026-09-03: Play 중 본문 수정 → reload_file → 다음 틱부터 새 문구, 도메인 리로드 0회).
  • Play 중에는 create_gameobject·add_component 가 거부된다("cannot be used during play mode") → 임시 오브젝트는 eval 로 만든다: unity command eval --code "new UnityEngine.GameObject(\"Probe\").AddComponent<WL.Diagnostics.WLHotReloadProbe>(); return 1;" (Play 종료 시 사라짐).
  • 코드는 파일에 두고 eval_file(즉석 실행) 또는 run_script(정적 진입점) 로 실행한다. 여러 줄 C# 을 eval --code 문자열로 밀어 넣지 않는다(§1-1).
  • 런타임 서버 (Play 모드·개발 빌드 · 포트 7900~7949 · 2026-09-03 실검증: 에디터 Play 진입 시 7900 자동 기동, set_timescale·console·runtime_status 동작) = Project Settings ▸ Pipeline ▸ Runtime ▸ Enable In Builds ON (ProjectSettings/Packages/com.unity.pipeline/RuntimePipelineConfig.json). 에디터 Play 진입 시 프로젝트 루트에 .unity-pipeline-runtime-port 가 생기며 unity command --runtime-path D:\NerdNavis\IdleRPG\WLevelRPG runtime_status 처럼 런타임 명령(set_timescale·simulate_key·simulate_pointer·log·console…)을 보낸다.
  • Android/IL2CPP 빌드에는 런타임 HTTP 서버가 컴파일되지 않는다 (Standalone 개발 빌드 만). 디바이스 핫리로드는 reload_file_player_interpreter (프로파일러 연결 경유).

5. Play 제어·관찰

unity command editor_play      # / editor_pause / editor_stop
unity command capture_game_view --save_path Screenshots_WL/<이름>.png --source screen   # Play 중 오버레이 UI 포함
unity command get_scene_hierarchy
unity command find_gameobjects --type WL.Player.PlayerController
unity command get_serialized_fields --target <핸들> --format value

6. WL 커스텀 명령 (Assets/WL/Scripts/Debug/WLPipelineCommands.cs)

명령 설명
wl_info 씬 · Play 상태 · timeScale · FPS · 플레이어(이름/위치/HP/상태) · 적 수(생존/전체)
wl_timescale --scale 0.2 에디터 서버에서 Time.timeScale 즉시 변경 (런타임 서버 없이도 Play 중 동작)
wl_teleport_player --x 0 --y 1 --z 0 현재 플레이어를 월드 좌표로 이동 (CharacterController 안전 처리 · Play 중만)
  • 새 명령 = static 메서드에 [CliCommand("wl_이름", "설명")] + 인자에 [CliArg("이름", "설명")]. 리컴파일 후 unity command 목록에 자동 등장 (등록 코드 없음).
  • 파괴적 명령은 confirm/dry_run 인자를 두고 게이트한다. 데이터 값은 코드에 상수로 두지 말고 설정 에셋을 읽는다 (C45).

7. 커스텀 인터페이스 (HTTP + JSON)

  • 서버 API = http://127.0.0.1:<port>/api/{status, commands, exec, progress, dialog, job} · 헤더 Authorization: Bearer <evalToken>. 포트·토큰 = Library/Pipeline/.unity-pipeline-port (런타임 = .unity-pipeline-runtime-port). 로컬 전용 · Origin 헤더가 있는 브라우저 직접 요청은 거부.
  • POST /api/exec 본문 = {"commandLine": "wl_timescale --scale 0.5"} 또는 {"command": "eval", "parameters": {"code": "…"}} → 응답 {"success": true, "result": …}.
  • 준비된 클라이언트 = Tools/Pipeline/pipeline_client.py (표준 라이브러리만 · import 가능한 PipelineClient + CLI). python Tools/Pipeline/pipeline_client.py servehttp://127.0.0.1:7700 브라우저 제어판(control_panel.html) — 프록시가 토큰을 주입하므로 CORS·토큰 입력이 없다.
  • 브라우저 페이지가 서버에 직접 붙어야 한다면 EditorPipelineManager.asset 의 Allow Browser Clients 를 켜야 한다 (프록시 방식이면 불필요).

8. 커밋·기록

  • 커밋은 PD 확인 후 파일 지정으로만 (조직 규칙). Library/·Tools/Pipeline/__pycache__/·.unity-pipeline-runtime-port 는 미추적.
  • 작업 결과·교훈은 NerdNavisAi 레포 공유/대화로그/WL프로젝트/profile-wl 교훈 인덱스에 남긴다.