diff --git a/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md b/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md index 9cc16b2..33c63e7 100644 --- a/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md +++ b/공유/PD_지시_트래킹/개발팀_PD_지시_로그.md @@ -32,7 +32,6 @@ C3·C13 위반에 해당. **즉시 자진 보고 후 소급 등록**. | # | 일시 | 지시 요지 | 처리 상태 | 산출물 경로 | 중단 사유 | 사후 조치 | |---|------|----------|----------|-----------|----------|----------| | 2 | 2026-04-14 | 서버 Critical 보안 3건 보류 | 보류 | `프로젝트/수상한잡화점/개발/05_서버연동_현황_v1.md` | 서버 파트 정비 미완료 (PD님 지시) | 서버팀 가동 시점에 블로커급 재개. 담당: 서버팀장. 재개 트리거: 서버 파트 정비 완료 통보 | -| 37 | 2026-04-17 | (#5 후속 분리) Q-P2 정밀 2차 응답 + Unity MCP 시뮬레이션 인프라 4종 구현 (SimulationRunner 프로토타입·파라미터 외부화·결과 JSON 스키마·MCP 호출 스니펫) | 대기 | (후속 산출물 생성 후 기입) | - | 재개 트리거: 개발팀장 재량 착수 또는 PD님 후속 지시. Q-P2 정밀은 PCActor·MobActor·EffectMgr 전수 실측 필요 | | 38 | 2026-04-17 | (#28 후속 분리) Phase 3 재개 로드맵 결정 — Unity MCP 단일축 기반 밸런스 작업 재개 범위·선후관계·검증 축 확정 | 보류 | (로드맵 확정 시 기입) | PD님 별도 논의 예정 | 재개 트리거: PD님 Phase 3 재개 지시 수령. 기획팀 #3 동시 재개 | > **2026-04-15 오후 추가 갱신 (C4·C13 위반 자진 정정 2차)**: @@ -86,6 +85,7 @@ C3·C13 위반에 해당. **즉시 자진 보고 후 소급 등록**. | # | 일시 | 지시 요지 | 처리 상태 | 산출물 경로 | 중단 사유 | 사후 조치 | |---|------|----------|----------|-----------|----------|----------| +| 37 | 2026-04-17 | (#5 후속 분리) Q-P2 정밀 2차 응답 + Unity MCP 시뮬레이션 인프라 4종 구현 (SimulationRunner 프로토타입·파라미터 외부화·결과 JSON 스키마·MCP 호출 스니펫) · **2026-04-17 PD님 재지시 추가 제약**: 기존 수상한잡화점 코드·구조 불변, 독립 어셈블리(`Assets/Sim/` + `NerdNavis.Sim.asmdef`)로 격리, Editor-only, 설계문서는 `프로젝트/수상한잡화점/시뮬레이터/`·실행코드는 Unity 프로젝트 내 | **완료** | `공유/소통/완료/2026-04-17_Phase0-C_QP2_정밀2차_응답서.md` + `프로젝트/수상한잡화점/시뮬레이터/{01_아키텍처,02_시나리오_JSON_스키마,03_결과_JSON_포맷,04_MCP_호출_스니펫}_v1.md` + (Unity) `Assets/Sim/NerdNavis.Sim.asmdef` · `Assets/Sim/Runtime/{SimulationRunner.cs,ScenarioLoader.cs,ResultEmitter.cs}` · `Assets/Sim/Runtime/Models/{ActorModel,DefenceModel,DamageCalc}.cs`. **Q-P2 실측**: PCDefence_Mul=0.3 (30%, 기획 가정 50% 불일치 확인)·쿨다운 없음·지속형·방어 중 공격 불가. **독립성 증명**: `git diff --stat Assets/Script/` = 0건 | - | Unity MCP 실행 검증은 Editor 기동 + MCP 연결 환경에서 기획팀·개발팀 공동 수행 (C23 정직). PM 자동 push 대상 (C20-1-A) | | 36 | 2026-04-17 | (#1 후속 분리) Tier 1 잔여 3종 구현 — Data·Event·Container 모듈. 상호작용 설계 재검증 선행 필요 | **완료** | `프로젝트/코어프레임워크/04_Tier1_3종_상호작용_설계_v1.md` (P18 설계 문서) + `코어코드/NerdNavis.Framework/Runtime/Core/Event/{EventBus.cs,Raw/RawEventBus.cs}` · `Container/{ObservableList,ObservableDictionary,ObservableQueue}.cs` · `Data/{IDataRow,DataTable,DataTableSO,DataTableLoader,DataTableLoadedEvent}.cs` + `Tests/Runtime/Core/{Event,Container,Data}/*Tests.cs` 5종 + `CHANGELOG.md` Unreleased 3블록 추가. **Tier 1 총 16/16종 완료** | - | PD님 "세션 공유" 시점에 일괄 push (C20-1-A 준수) | | 28 | 2026-04-16 | (PD님 직접 지시, 총괄PM 경유) 기획팀 밸런스 작업을 위한 시뮬레이션 대응 — 07 착수계획(시뮬레이터 이원화 해소) 진행 상태 보고 + 기획팀 밸런스 작업용 시뮬레이션 환경 구축. 2026-04-17 PD님 직접 지시로 **Unity MCP 기반 시뮬레이션 방향 전환** 확정 | **완료 (라운드 승인분)** | `공유/소통/완료/2026-04-16_RPT_시뮬레이션_대응_현황보고.md` + `공유/소통/완료/2026-04-17_Unity_MCP_시뮬레이션_기술검토_개발팀.md` (기술검토 완료). 시뮬 방향 Unity MCP 단일축 확정, Python 시뮬 폐기 사안 기록 | - | Phase 3 재개 로드맵은 #38로 분리 (보류) | | 5 | 2026-04-15 | (3대 지시) **A.** Framework Tier 1 기반 Core 모듈 구현 착수 **B.** 수상한 잡화점 Phase 0-B/C 재개 **C.** 총괄PM 보고 | **완료 (라운드 승인분)** | **A 라운드 승인분**: #1 참조 (Attribute 3종 + Util 6종 추가 구현 완료). **B-1/B-2/B-3 완료**: `프로젝트/수상한잡화점/개발/08_전투시스템_SOT_v1.md`·`09_카드시스템_아키텍처_v1.md`·`10_데이터로딩_구조_v1.md`. **B-4/B-5 완료 2026-04-17**: `11_UI아키텍처_v1.md`·`12_메타시스템_v1.md`. **C-Phase0-C 초벌 완료**: `공유/소통/완료/2026-04-17_Phase0-C_QP_응답서_개발팀.md`. **C 일괄 공유 완료** | - | Q-P2 정밀 2차 + Unity MCP 시뮬레이션 인프라 4종 구현은 **#37로 분리** (대기) | diff --git a/공유/대화로그/수상한잡화점/2026-04-17.md b/공유/대화로그/수상한잡화점/2026-04-17.md index dab5128..357d4fb 100644 --- a/공유/대화로그/수상한잡화점/2026-04-17.md +++ b/공유/대화로그/수상한잡화점/2026-04-17.md @@ -119,3 +119,29 @@ - **상태**: 완료 (Q-P2 2차 정밀 응답은 후속) - **기각안**: (1) Q-P1에 "의도된 설계로 추정" 단정 응답 — 개발팀 의사결정 권한 외, C23 위반. 의도 선언은 기획팀으로 환송. (2) Q-P2 3항 전수 리버스 엔지니어링을 본 응답서에 포함 — 작업량 막대 + 범위 초과. 2차 응답서로 분리. (3) Python 시뮬레이터 복구 시도 — PD님 #28 "폐기 사안" 정면 위반. (4) Unity 외 3rd-party 시뮬레이터 검토 — PD님 Unity MCP 단일 방향 확정, 검토 대상 아님. + +## [작업완료] #37 Q-P2 정밀 2차 응답 + Unity MCP 시뮬 인프라 4종 (독립 시뮬 제약 반영) +- **요지**: Q-P2 3서브 질의 실측 확정(30% 감소·지속형·쿨다운 없음) + 시뮬 인프라 4종 설계문서 + 독립 어셈블리 `NerdNavis.Sim` 스켈레톤 구현 +- **이유**: PD님 #37 즉시 수행 지시 + 독립 시뮬 요건 명시(기존 코드 불변, Editor-only 어셈블리, 메커닉 독립 재구현). Q-P2 1차 응답의 미확정 수치 해소가 기획팀 밸런싱 재개 선결 조건 +- **산출물**: + - `공유/소통/개발팀→PM/2026-04-17_Phase0-C_QP2_정밀2차_응답서.md` + - `프로젝트/수상한잡화점/시뮬레이터/01_시뮬레이터_아키텍처_v1.md` + - `프로젝트/수상한잡화점/시뮬레이터/02_시나리오_JSON_스키마_v1.md` + - `프로젝트/수상한잡화점/시뮬레이터/03_결과_JSON_포맷_v1.md` + - `프로젝트/수상한잡화점/시뮬레이터/04_MCP_호출_스니펫_v1.md` + - `(Unity) Assets/Sim/NerdNavis.Sim.asmdef` (Editor-only) + - `(Unity) Assets/Sim/Runtime/SimulationRunner.cs`·`ScenarioLoader.cs`·`ResultEmitter.cs` + - `(Unity) Assets/Sim/Runtime/Models/ActorModel.cs`·`DefenceModel.cs`·`DamageCalc.cs` +- **상태**: 완료 (Unity MCP 실행 검증은 Editor 기동·MCP 연결 환경에서 후속 수행 — C23 정직) +- **실측 주요 결과**: PCDefence_Mul=0.3 (기획 가정 50% 불일치), 쿨다운 전무, 터치 Down→Up 지속형, 방어 중 공격 불가, Melee/Range 공통 적용, Mob 방어 메커닉 부재 +- **독립성 증명**: `git diff --stat Assets/Script/` = 0건. 신규 생성물 `Assets/Sim/` 단독. asmdef `references: []`·`includePlatforms: ["Editor"]`·`defineConstraints: ["UNITY_EDITOR"]`로 3중 격리 +- **기각안**: + - (1) 기존 `Actor.cs` 경로 재사용 실행 — PD 제약(독립 시뮬) 정면 위반 + - (2) Q-P2에 "50% 추정" 유지 — 실측 결과 30% 확정, C23 위반 회피 + - (3) 쿨다운 "있을 것" 추정 — `UITouchHandler.cs` 전수 확인 결과 미존재 + - (4) Mob 방어 메커닉 가정 — `MobActor.cs` 전수 확인 결과 override 부재 + - (5) Scenarios ScriptableObject 입력 — MCP 외부 접근 곤란, JSON 채택 + - (6) PlayMode 기반 시뮬 — 독립성·성능 악화, EditMode + 독립 Runner 채택 + - (7) 별도 레포 서브모듈 — MCP 경로 제약·기획팀 셋업 복잡, 동일 레포 격리 채택 + - (8) Headless 배치 빌드 — 피드백 루프 느림, MCP `execute_code` 즉시 실행 채택 + diff --git a/공유/소통/완료/2026-04-17_Phase0-C_QP2_정밀2차_응답서.md b/공유/소통/완료/2026-04-17_Phase0-C_QP2_정밀2차_응답서.md new file mode 100644 index 0000000..24e5a97 --- /dev/null +++ b/공유/소통/완료/2026-04-17_Phase0-C_QP2_정밀2차_응답서.md @@ -0,0 +1,164 @@ +--- +type: 응답서 +from: 개발팀장 +to: 총괄PM / 기획팀장 +subject: Phase 0-C Q-P2 정밀 2차 응답 (터치 방어 메커닉 실측 확정) +date: 2026-04-17 +status: 완료 +related: + - 공유/소통/완료/2026-04-17_Phase0-C_QP_응답서_개발팀.md # 1차(초벌) 응답서 + - 프로젝트/수상한잡화점/기획/Phase0_1_앵커전투시뮬레이션_v1.md + - 프로젝트/수상한잡화점/개발/08_전투시스템_SOT_v1.md +depends_on: + - PD 지시 #37 (Q-P2 정밀 2차 + Unity MCP 시뮬 인프라 4종) +--- + +# Phase 0-C — Q-P2 정밀 2차 응답 (터치 방어 메커닉 실측 확정) + +## 0. 본 문서 범위 + +1차 응답서(`2026-04-17_Phase0-C_QP_응답서_개발팀.md`)에서 **"미확인 — 정밀 코드 리뷰 필요"**로 분류했던 Q-P2 4개 항목(감소 수치 실위치·고정/변동 여부·쿨다운 존재·지속형 여부)을 **Unity 프로젝트 코드 전수 실측**으로 확정한다. 읽은 파일은 `PCActor.cs`·`MobActor.cs`·`Actor.cs(base)`·`EffectMgr.cs`·`UITouchHandler.cs`·`IngameUIManager.cs`·`GlobalValue.json` (전부 Read only, C23 정직 보고). + +--- + +## 1. Q-P2 3개 서브 질의 — 실측 기반 확정 답변 + +### 1-1. 서브 질의 1: "터치 1회 = 다음 공격 1회 피해 50% 감소?" + +**확정 답변: ✗ 전제 오해 + 수치 불일치** + +- **감소 비율 실측**: **30%** (기획팀 가정 "50%"와 불일치) +- **근거**: `Assets/ResWork/Table/Export/GlobalValue.json` — `{"s_ID": "PCDefence_Mul", "n_Value": "0.3", "exception": "PC 방어 시 피해% (0.3 = 30%)"}` +- **적용 지점**: `Assets/Script/InGame/Actor/Actor.cs:782-783` — `if (ActorStatus == eActorStatus.Defecne) reducedmg_rate += table_GlobalValue.Ins.Get_Float("PCDefence_Mul");` +- **추가 고정 감소**: `PCDefence = 1` (절대값 1 감소) — 소수점·저데미지 구간에서 효과, 고데미지 구간에서는 미미 + +**추가 정정**: "터치 1회 = **다음 공격 1회**" 도 부정확. 실제는 **터치 Down↔Up 구간 동안 지속**되는 상태 효과이며, 단일 공격에 바인딩되지 않는다. 1-2로 연결. + +### 1-2. 서브 질의 2: "터치 유지 중 계속 감소?" + +**확정 답변: ✓ 그렇다 (지속형 상태 효과)** + +- **구조**: `UITouchHandler.cs` (`Assets/Script/UGUI/Util/UITouchHandler.cs`) — `IPointerDownHandler`·`IPointerUpHandler`·`IPointerExitHandler` 인터페이스로 구현 +- **바인딩**: `IngameUIManager.cs:39` — `m_PCDefence.Set(m_PCActor.Play_Defence, m_PCActor.Release_Defence, null)` +- **동작 흐름**: + 1. `OnPointerDown` → `isTouching = true` + `Play_Defence()` 호출 → `ActorStatus = eActorStatus.Defecne` + 2. 터치 유지 동안 매 프레임 `Update()`에서 `m_onHold?.Invoke()` (현재 `null` 바인딩이라 no-op) + 3. `OnPointerUp`·`OnPointerExit`·`OnDisable` → `isTouching = false` + `Release_Defence()` → `ActorStatus = eActorStatus.Idle` +- **지속 중 피격 처리**: `Actor.cs:515-519` — 데미지 계산 완료 후 `ActorStatus == Defecne`면 `huddmg.Set_Block(dmg, ...)` + `PCBlock` 이펙트 재생. 매 피격마다 **PCDefence_Mul(30%) + PCDefence(1) 감소가 반복 적용**됨 +- **상태 중 공격 차단**: `Actor.cs:4500` — `ActorStatus == Defecne` 시 공격 프레임 return. 즉 **방어 중 DPS 0** +- **상태 중 Hit 애니메이션 차단**: `PCActor.cs:133` — `ActorStatus == Defecne` 시 `Play_Hit` 조기 return + +**결론**: 터치 유지 시간 동안 "무한 횟수 30% 감소 + 공격 불가"의 **공격↔방어 트레이드오프** 메커닉. 지속형이며 횟수 제한 없음. + +### 1-3. 서브 질의 3: "쿨다운?" + +**확정 답변: ✗ 없음 (즉시 재사용 가능)** + +- **`UITouchHandler.cs` 전수 확인 결과**: 쿨다운 타이머·재사용 제한·다음 활성화 대기 로직 **일절 없음** +- **`PCActor.Play_Defence`·`Release_Defence`**: 상태 전환만 수행, 쿨 관련 코드 없음 (`PCActor.cs:148-162`) +- **`Actor.cs` 검색 결과**: `Cooltime`·`CoolDown`·`BlockCool`·`DefenceCool` 어떤 키워드로도 방어 쿨 관련 코드 미발견 +- **실행 시나리오**: 유저가 터치 Up 즉시 다시 터치 Down 가능. 시스템상 1프레임 Up/Down 교차도 허용 (단 게임 경험상 연속 탭은 의미 없음 — 상태 유지가 더 유리) + +**유의**: 이는 **2026-04-17 시점 Dev 브랜치**(커밋 `43b6074c4`) 기준. 향후 기획팀이 쿨다운 도입을 결정하면 `UITouchHandler` 래핑·별도 `DefenceCooldownMgr` 추가가 자연스러운 확장점. + +--- + +## 2. 종합 — 터치 방어 메커닉 SOT (실측 확정판) + +| 항목 | 값 | 근거 경로 | +|------|-----|----------| +| 감소 비율 (%) | **30%** | `GlobalValue.json.PCDefence_Mul = 0.3` | +| 고정 감소 (절대) | **1** | `GlobalValue.json.PCDefence = 1` | +| 적용 지점 | `Actor.cs:774-783` (절대+%) | 데미지 계산 pipeline | +| 활성 조건 | `ActorStatus == eActorStatus.Defecne` | PC 한정 (Mob은 `Play_Defence` override 없음) | +| 입력 메커닉 | 터치 Down→Up 지속 | `UITouchHandler.cs` (`IPointerDown/Up/ExitHandler`) | +| 쿨다운 | **없음** | 코드 전수 확인 결과 미존재 | +| 지속형/1회성 | **지속형** (터치 유지 = 방어 유지) | `isTouching` 상태 기반 | +| 방어 중 공격 | **불가** (차단됨) | `Actor.cs:4500`, `PCActor.cs:150` (Defecne 시 Set_Active/조기 return) | +| 방어 중 Hit 애니 | **재생 안함** (무적 아님, 데미지는 감소된 양으로 들어감) | `PCActor.cs:133` | +| 방어 중 회피(Evasion) | **차단** (Defecne 우선) | `PCActor.cs:143` | +| 적용 대상 범위 | Melee·Range 구분 없이 전 피격 | `Actor.cs:774` (`hitterAttacktype` 분기 없음, Defecne 보정은 공통) | +| 몬스터 방어 | **메커닉 부재** (MobActor에 `Play_Defence` override 없음) | `MobActor.cs` 전수 확인 | +| 이펙트 | `PCBlock` 이펙트 재생 + `huddmg.Set_Block` 호출 | `Actor.cs:517-518` | +| 오타 주의 | 원본 enum 표기 `Defecne`(Defence 오타) | 코드 전반 일관 오타, 수정 시 전역 영향 | + +--- + +## 3. 기획팀 가정 vs 실측 불일치 리스트 (충돌 현황) + +| 기획팀 가정 | 실측 결과 | 영향 | +|------------|-----------|------| +| 50% 피해 감소 | **30%** 감소 | 앵커 전투 생존 시뮬 결과가 기획팀 추정보다 낮게 나올 것 | +| 1회 공격 단위 | **지속형** 상태 효과 | "터치 1회 N회 방어" 계산식 전면 재검토 필요 | +| 쿨다운 존재 가능 | **없음** | 밸런싱 상한이 시스템이 아닌 **유저 조작 여유**에 의존 (동시 공격 불가 trade-off가 실질적 상한) | +| 터치=단순 감소 | 터치=**공격 불가 + 감소 + 이펙트** 3효과 묶음 | "공격 기회 손실 비용"을 반영한 밸런스 재계산 필요 | + +본 불일치는 **Phase 0-C Q-P1(4마리 노드 초반 위험도 의도) 해석에도 직접 영향**. 30%+지속형+공격불가 조건이라면 "카드 0장 + 4마리" 시나리오에서 터치 방어 전략이 기획 의도 대비 얼마나 효과적인지를 시뮬레이션으로 재측정해야 함. Unity MCP 시뮬 인프라 4종(본 PD 지시 #37의 축 B)이 이 재측정의 직접 도구. + +--- + +## 4. 개발팀 해석·권고 + +### 4-1. 용어 정리 권고 (기획팀 협의 대상) +- "터치 방어"·"블록"·"가드"·"Defence"·"Block"이 혼용 중 — `eActorStatus.Defecne` 오타 + `PCBlock` 이펙트 + `UITouchHandler.m_PCDefence` 바인딩이 각기 다른 용어 사용. 기획 SOT는 **"터치 방어(Touch Defence)"** 단일 표기 권장. + +### 4-2. 수치 SOT 권고 +- **GlobalValue.json이 단일 SOT**. 밸런스 변경 시 본 파일 수정으로 일원화. 카드·장비·인장에 의한 추가 감소는 **별개 스택**(`ReduceDmg`·`ReduceRangeDmg_Mul` 등)이며 방어 중에도 누산 적용됨 (`Actor.cs:773·781`). + +### 4-3. Q-P1 재평가 안건 +"의도된 설계 여부"는 **기획팀 영역**(1차 응답 유지). 단, 본 정밀 실측으로 "터치 방어 = 30% + 지속형 + 공격불가"가 확정된 이상, 기획팀은 본 메커닉 값을 전제로 의도를 재검토할 수 있음. Unity MCP 시뮬 인프라(§5)로 실측 생존률 측정 가능. + +--- + +## 5. Unity MCP 시뮬 인프라 4종 (별도 산출물로 분리) + +본 응답서와 동시 발신되는 4종 설계 문서: + +1. `프로젝트/수상한잡화점/시뮬레이터/01_시뮬레이터_아키텍처_v1.md` — 독립성 보장 + 어셈블리 분리 설계 +2. `프로젝트/수상한잡화점/시뮬레이터/02_시나리오_JSON_스키마_v1.md` — 입력 포맷 +3. `프로젝트/수상한잡화점/시뮬레이터/03_결과_JSON_포맷_v1.md` — 출력 포맷 +4. `프로젝트/수상한잡화점/시뮬레이터/04_MCP_호출_스니펫_v1.md` — 기획팀장용 복붙 템플릿 3종 + +실행 코드 스켈레톤 (독립 어셈블리, Editor-only): +- `Assets/Sim/NerdNavis.Sim.asmdef` +- `Assets/Sim/Runtime/SimulationRunner.cs` +- `Assets/Sim/Runtime/ScenarioLoader.cs` +- `Assets/Sim/Runtime/ResultEmitter.cs` +- `Assets/Sim/Runtime/Models/ActorModel.cs` + +**핵심 원칙**: 기존 `Assets/Script/` 일체 수정 없음. 메커닉은 독립 모델로 재구현(30% + 지속형 + 공격불가 규칙을 순수 C# 로직으로). 빌드 포함 안 됨(Editor-only define). + +--- + +## 6. 기각안 (P24 기각안 필드 필수) + +- **기각안 A: 실제 `Actor.cs` 경로를 재사용하여 시뮬 실행** — 1) 기존 코드 수정 위험 2) PlayMode 의존성 과도 3) PD님 "독립 시뮬" 제약 위반. 별도 Models/ 독립 재구현으로 우회 +- **기각안 B: Q-P2 답변에 "50% 추정" 유지** — 실측 결과 30% 확정. C23 위반 회피. 기획팀 가정 정정 필요성 명시가 본 2차 응답의 존재 이유 +- **기각안 C: 터치 방어에 쿨다운 있을 것이라 추정** — 코드 전수 확인 결과 미존재. 추정을 단정으로 포장하는 건 C23 위반. "시스템 상한 부재, 유저 조작 상한이 실질 상한"으로 정확히 기재 +- **기각안 D: Mob도 방어 메커닉 있다고 가정** — `MobActor.cs` 전수 확인 결과 `Play_Defence` override 부재. 추정 금지, 실측 기록 + +--- + +## 7. 후속 작업 + +### 7-1. 개발팀 (본 응답서 발신과 동시 완료) +- [x] Q-P2 3서브 질의 실측 확정 +- [x] 시뮬 인프라 4종 설계 문서 +- [x] Sim 어셈블리·스켈레톤 코드 작성 +- [x] PD 지시 로그 #37 진행중→완료 갱신 +- [x] 수상한잡화점 대화로그 엔트리 (기각안 포함) + +### 7-2. 기획팀 필요 액션 +1. 터치 방어 수치 가정 정정 (50% → 30%, 1회 → 지속형, 쿨다운 없음) +2. Q-P1 재평가 (본 실측 기반 의도 재확인) +3. 시나리오 JSON 작성 (§5의 02 스키마 참조) → Unity MCP 실행 요청 +4. 기획팀장이 Q-P2 정책 최종 결정 후 개발팀에 공유 (코드 변경 필요 시 별도 PR) + +### 7-3. PM 조율 필요 +- 본 PD 지시 #37 완료 아카이브 이동 + C20-1-A 자동 push +- 기획팀에 본 응답서 전달 (본 문서 완료 이동 시 자동 공유됨) + +--- + +## 부록. 변경 이력 +- **v1 (2026-04-17)**: 초판. 개발팀장. Unity 프로젝트 Dev 브랜치 `43b6074c4` 기준 실측. diff --git a/프로젝트/수상한잡화점/시뮬레이터/01_시뮬레이터_아키텍처_v1.md b/프로젝트/수상한잡화점/시뮬레이터/01_시뮬레이터_아키텍처_v1.md new file mode 100644 index 0000000..2245d87 --- /dev/null +++ b/프로젝트/수상한잡화점/시뮬레이터/01_시뮬레이터_아키텍처_v1.md @@ -0,0 +1,178 @@ +--- +type: 설계문서 +project: 수상한잡화점 +subject: 독립 시뮬레이터 아키텍처 (Unity MCP 실행 인프라) +version: v1 +date: 2026-04-17 +status: 초판 +author: 개발팀장 +related: + - 공유/소통/개발팀→PM/2026-04-17_Phase0-C_QP2_정밀2차_응답서.md + - 프로젝트/수상한잡화점/시뮬레이터/02_시나리오_JSON_스키마_v1.md + - 프로젝트/수상한잡화점/시뮬레이터/03_결과_JSON_포맷_v1.md + - 프로젝트/수상한잡화점/시뮬레이터/04_MCP_호출_스니펫_v1.md +핵심원칙: + - 기존 수상한잡화점 코드 일체 수정 금지 + - 독립 어셈블리 격리 (`NerdNavis.Sim.asmdef`) + - Editor-only (빌드 산출물 제외) + - 메커닉은 별도 모델로 독립 재구현 (Read-only 참조) +--- + +# 독립 시뮬레이터 아키텍처 v1 + +## 1. 배경 (왜 필요한가) + +### 1-1. PD님 직접 지시 (2026-04-17) +> "기존 수상한잡화점 프로젝트의 코드나 구조에 영향을 주지 않는 독립적인 시뮬레이터로 동작해야 함." + +### 1-2. 요구사항 해석 +1. **기존 코드 불변 원칙**: `Assets/Script/` 하위 파일을 일절 수정 불가. 시뮬 인프라는 **관찰·참조**만 허용, **수정·확장·상속**을 통한 침투 불허 +2. **독립 어셈블리 격리**: 기존 `Assets/Script/*.asmdef`와 별개 어셈블리로 운영하여 빌드 의존성·컴파일 영향 차단 +3. **Editor-only 동작**: 프로덕션 빌드 산출물에 시뮬 코드 포함 방지 (앱 크기·보안·의도치 않은 실행 차단) +4. **메커닉 재현의 독립성**: Actor·Effect 등의 로직을 재사용·복제가 아닌 **동등 결과를 내는 별도 로직**으로 독립 재구현 + +### 1-3. 설계 제약 (대안 고려) +- **대안 A (기각)**: 기존 `Assets/Script/Actor/` 직접 호출하여 시뮬 실행 → 코드 수정 위험·PlayMode 의존·PD 제약 위반 +- **대안 B (기각)**: 별도 레포 구축 → Unity MCP `execute_code`가 현 프로젝트 내부만 접근 가능, 운영 분리 과도 +- **대안 C (채택)**: 같은 Unity 프로젝트 내 `Assets/Sim/` 신규 폴더 + 독립 asmdef + Editor-only define + 모델 독립 재구현 + +--- + +## 2. 폴더·어셈블리 구조 + +``` +D:/NerdNavis/FilGoodBandits/DeckBuilding/Assets/Sim/ ← 신규 (이번에 생성) +├── NerdNavis.Sim.asmdef ← 독립 어셈블리 정의 +├── Runtime/ +│ ├── SimulationRunner.cs ← 진입점 +│ ├── ScenarioLoader.cs ← 시나리오 JSON → ActorModel 로드 +│ ├── ResultEmitter.cs ← 결과 JSON 출력 +│ └── Models/ +│ ├── ActorModel.cs ← Actor 동등 모델 (독립 재구현) +│ ├── DefenceModel.cs ← 터치 방어 30% + 지속형 재현 +│ └── DamageCalc.cs ← 데미지 감소 pipeline 재현 +``` + +### 2-1. 어셈블리 정의 (`NerdNavis.Sim.asmdef`) +- `name`: `NerdNavis.Sim` +- `rootNamespace`: `NerdNavis.Sim` +- `references`: **비움** (기존 어셈블리 참조 안 함 — 독립성 확보) +- `includePlatforms`: `["Editor"]` (Editor-only) +- `excludePlatforms`: `[]` +- `autoReferenced`: `false` +- `defineConstraints`: `["UNITY_EDITOR"]` +- `noEngineReferences`: `false` (UnityEngine은 사용, but 최소) + +### 2-2. 의존성 격리 결과 +- 빌드 시 본 어셈블리 **자동 제외** (Editor 플랫폼만 타겟) +- 기존 게임 어셈블리와 컴파일 단위 분리 → 기존 코드 변경 감지 없음 +- 기존 `Assets/Script/` 전혀 참조하지 않으므로 기존 리팩토링·삭제에도 영향 없음 + +--- + +## 3. 실행 흐름 + +``` +기획팀장 Unity MCP SimulationRunner + │ │ │ + │ 04_MCP_호출_스니펫_v1.md 기반 │ │ + │ execute_code 호출 │ │ + │ {scenario_json_path: "..."} │ │ + │ │ │ + │ ─────────────────────────────► │ │ + │ │ │ + │ │ SimulationRunner.Run(path) + │ │ ─────────────────────────► + │ │ │ + │ │ │ 1. ScenarioLoader.Load(path) + │ │ │ → ActorModel 생성 + │ │ │ 2. 전투 tick 루프 실행 + │ │ │ (DefenceModel·DamageCalc 호출) + │ │ │ 3. ResultEmitter.Emit(result) + │ │ │ → 결과 JSON 파일 또는 stdout + │ │ │ + │ │ ◄───────────────────────── + │ │ {결과 JSON} + │ ◄───────────────────────────── │ + │ │ │ + │ 기획팀 분석·밸런스 튜닝 │ │ +``` + +### 3-1. 실행 환경 2모드 +- **모드 1 (단일 실행)**: Unity Editor 기동 상태 + MCP 연결 + `execute_code` 한 번 → 결과 1건 +- **모드 2 (배치 실행)**: `execute_code`로 스윕 파라미터 배열 전달 → 내부 루프로 N회 실행 + 결과 N건 집계 + +--- + +## 4. 독립 모델 설계 (Models/) + +### 4-1. ActorModel +**기존 `Actor.cs`(4545줄)를 재구현하지 않는다.** 시뮬에 필요한 최소 상태만 추출: + +```csharp +public class ActorModel { + public string id; + public float maxHP, hp; + public float shield; + public float attackDmg; + public float attackCoolTime; + public float accumulatedAttackTime; + public bool isDefencing; // ActorStatus == Defecne 동등 + public bool isDead => hp <= 0f; + // ... 시뮬 범위 내 최소 필드만 +} +``` + +### 4-2. DefenceModel (실측 규칙 재현) +Q-P2 정밀 2차 응답서 §2 실측 기반 독립 구현: +- `PCDefence_Mul = 0.3f` (30% 감소) +- `PCDefence = 1` (절대값 1 감소) +- 터치 Down↔Up 지속 (`isDefencing` 플래그) +- 방어 중 공격 불가 (`accumulatedAttackTime` 갱신 중단) +- 방어 중 데미지: `dmg = (dmg - 1) * (1 - 0.3)` (추가 감소 스택은 포함하지 않음 — 단순화) + +### 4-3. DamageCalc (감소 pipeline 재현) +`Actor.cs:762-809` 실측 기반 간이 재구현. 시뮬 범위 외(카드·인장·각성)는 제외하고 **순수 방어 메커닉 + 기본 스탯** 차원만 재현. 복잡 메커닉 필요 시 scope 확장 v2에서 추가. + +### 4-4. 재구현 원칙 +- **동등 결과 우선, 구조 복사 금지** — 기존 코드를 복붙하지 않고 실측 스펙을 문서로 보고 재작성 +- **최소 기능 원칙** — 밸런싱에 필요한 축(HP·Shield·Dmg·Defence·CoolTime)만 구현, 나머지는 생략 +- **버전 고정 주석** — 각 파일 상단에 `// 실측 기준: Dev 브랜치 43b6074c4 (2026-04-17)` 명시하여 원본 변경 시 재동기화 시점 명확화 + +--- + +## 5. 검증 방법 + +### 5-1. 기존 코드 불변 증명 +- 본 작업 커밋 diff에 `Assets/Script/` 하위 변경이 **0건**이어야 한다 +- `git diff --stat Assets/Script/` 결과가 비어있는지 확인 + +### 5-2. 빌드 제외 증명 +- `manage_build` MCP로 Player 빌드 시도 → 빌드 로그에 `NerdNavis.Sim` 미포함 확인 +- `NerdNavis.Sim.asmdef`의 `includePlatforms: ["Editor"]` 준수 + +### 5-3. 메커닉 등가성 검증 (향후) +- 동일 시나리오에서 실제 게임 PlayMode vs 시뮬 실행 결과를 **기획팀이 비교** → 오차 10% 이내 목표 +- 오차 원인이 시뮬 모델 누락인지 실측 데이터 누락인지 구분하여 보완 + +### 5-4. MCP 연결 필요 환경 +- 본 세션에서 **Unity MCP 접근 가능 여부 미확인** (C23 정직: `mcp__unity-mcp__*` 호출을 실제로 수행하지 않음). 스켈레톤 코드는 작성 완료 상태이며, Unity Editor 구동 + MCP 연결 시점에 기획팀장·개발팀이 실행 검증 + +--- + +## 6. 확장 포인트 (v2 이후) + +1. **카드·인장·각성 효과 모델 추가** — 현재 스코프는 방어 메커닉 중심. 기획팀이 밸런싱 축 확장 요청 시 Models/에 파일 추가 +2. **몬스터 AI 모델** — 현재 단순 공격 tick만. 라인별 공격 조건·특수 효과(자폭·치명타 등) 재현 필요 시 `MonsterAIModel.cs` 추가 +3. **앵커 전투 노드 시퀀스 통합** — 단일 전투가 아닌 스테이지 경로 전체 시뮬 + +--- + +## 7. 변경 이력 +- **v1 (2026-04-17)**: 초판. PD 지시 #37 독립 시뮬 제약에 따른 어셈블리 격리 아키텍처. + +## 8. 기각안 (P24) +- **기각안 A**: `AssemblyDefinitionReferences` 로 기존 `Assets/Script/` 어셈블리 참조 → 독립성 훼손, PD 제약 위반. 0 references 고수 +- **기각안 B**: Runtime 포함(Editor-only 제외) → 빌드 산출물 오염·보안. Editor-only 확정 +- **기각안 C**: `Assets/Editor/Sim/` 아래 배치 → Unity asmdef 자동 Editor 어셈블리와 충돌 위험. `Assets/Sim/Runtime/` + 자체 asmdef의 Editor 플랫폼 제약이 깔끔 +- **기각안 D**: 별도 레포 서브모듈 → Unity MCP `execute_code` 경로 접근 제약·기획팀 셋업 복잡도 증가. 동일 레포 격리가 최선 diff --git a/프로젝트/수상한잡화점/시뮬레이터/02_시나리오_JSON_스키마_v1.md b/프로젝트/수상한잡화점/시뮬레이터/02_시나리오_JSON_스키마_v1.md new file mode 100644 index 0000000..adc3f11 --- /dev/null +++ b/프로젝트/수상한잡화점/시뮬레이터/02_시나리오_JSON_스키마_v1.md @@ -0,0 +1,192 @@ +--- +type: 설계문서 +project: 수상한잡화점 +subject: 시뮬레이션 시나리오 입력 JSON 스키마 +version: v1 +date: 2026-04-17 +status: 초판 +author: 개발팀장 +--- + +# 시나리오 JSON 스키마 v1 + +## 1. 목적 + +`SimulationRunner`가 받는 **입력 포맷**. 기획팀장이 한 번 작성하면 Unity MCP `execute_code`로 반복 실행 가능. 파라미터 스윕·배치 비교도 본 스키마의 배열 버전으로 처리. + +## 2. 최상위 구조 + +```json +{ + "schema_version": "1.0", + "scenario_id": "Anchor_Stage1_NoCard_4Mob", + "description": "앵커 전투 시뮬 — 카드 0장 + 4마리 전열 몬스터 + 터치 방어 전략", + "seed": 12345, + "rng_mode": "deterministic", + "pc": { + "hp": 100, + "max_hp": 100, + "shield": 0, + "attack_dmg": 10, + "attack_cooltime": 1.5, + "defence_strategy": "touch_hold_on_incoming" + }, + "monsters": [ + { + "id": "mob_front_01", + "hp": 20, "max_hp": 20, + "attack_dmg": 5, + "attack_cooltime": 2.0, + "line": "Frontline", + "attack_type": "Melee" + } + ], + "global_value": { + "PCDefence": 1, + "PCDefence_Mul": 0.3 + }, + "simulation": { + "max_turns": 1000, + "tick_interval": 0.1, + "stop_on_death": true, + "record_detail": true + } +} +``` + +## 3. 필드 정의 + +### 3-1. 메타 (필수) +| 필드 | 타입 | 설명 | +|------|------|------| +| `schema_version` | string | 스키마 버전 (`"1.0"`). 하위 호환 체크용 | +| `scenario_id` | string | 고유 식별자. 결과 JSON에 그대로 echo됨 | +| `description` | string | 사람 읽는 설명 (선택) | +| `seed` | int | 난수 시드. 재현성 보장 | +| `rng_mode` | string | `"deterministic"` 또는 `"random"`. 기본값 `"deterministic"` | + +### 3-2. PC (필수) +| 필드 | 타입 | 설명 | 기본값 | +|------|------|------|-------| +| `hp` / `max_hp` | float | 시작 HP, 최대 HP | — | +| `shield` | float | 시작 실드 | 0 | +| `attack_dmg` | float | 공격력 | — | +| `attack_cooltime` | float | 공격 쿨타임 (초) | — | +| `defence_strategy` | string | 방어 전략 — 아래 표 참조 | `"never"` | + +**defence_strategy 값**: +| 값 | 동작 | +|----|------| +| `"never"` | 방어 사용 안 함 (공격만) | +| `"always"` | 매 tick 방어 (공격 0 DPS) | +| `"touch_hold_on_incoming"` | 몬스터 projectile 발사 감지 시 자동 방어 on, 피격 후 off | +| `"auto_low_hp"` | HP <= `{low_hp_threshold}`% 시 자동 방어 | + +### 3-3. Monsters (필수, 배열) +| 필드 | 타입 | 설명 | +|------|------|------| +| `id` | string | 개체 식별자 | +| `hp` / `max_hp` | float | HP | +| `attack_dmg` | float | 공격력 | +| `attack_cooltime` | float | 공격 쿨타임 | +| `line` | string | `"Frontline"` / `"Middleline"` / `"Backline"` | +| `attack_type` | string | `"Melee"` / `"Range"` | + +### 3-4. GlobalValue (선택, 미제공 시 실측 기본값 사용) +| 필드 | 타입 | 실측 기본값 | 설명 | +|------|------|-------------|------| +| `PCDefence` | int | 1 | 방어 중 절대값 감소 | +| `PCDefence_Mul` | float | 0.3 | 방어 중 % 감소 (0.3 = 30%) | + +실측 기본값 근거: `Assets/ResWork/Table/Export/GlobalValue.json` (Dev 브랜치 `43b6074c4` 시점) + +### 3-5. Simulation 제어 (선택) +| 필드 | 타입 | 기본값 | 설명 | +|------|------|-------|------| +| `max_turns` | int | 1000 | 최대 tick 수 (무한루프 방지) | +| `tick_interval` | float | 0.1 | 1 tick당 시간(초) | +| `stop_on_death` | bool | true | PC 또는 몬스터 전멸 시 조기 종료 | +| `record_detail` | bool | false | tick별 상세 로그 생성 여부 (결과 JSON 크기 증가) | + +## 4. 파라미터 스윕 (배열 버전) + +동일 시나리오를 여러 값으로 돌릴 때: + +```json +{ + "schema_version": "1.0", + "sweep_id": "Defence_Mul_Grid", + "base_scenario": { /* 위 §2 구조 */ }, + "sweep_axes": [ + { + "path": "global_value.PCDefence_Mul", + "values": [0.2, 0.3, 0.4, 0.5] + }, + { + "path": "monsters[0].attack_dmg", + "values": [3, 5, 7] + } + ], + "sweep_mode": "cartesian", + "runs_per_cell": 10 +} +``` + +- `sweep_mode`: `"cartesian"` (모든 조합) 또는 `"zip"` (같은 인덱스끼리) +- `runs_per_cell`: 셀당 반복 횟수 (난수 분산 측정) + +## 5. 배치 비교 (시나리오 N개) + +```json +{ + "schema_version": "1.0", + "batch_id": "Anchor_Strategies_Compare", + "scenarios": [ + { "scenario_id": "strategy_never", /* 전체 시나리오 */ }, + { "scenario_id": "strategy_always", /* ... */ }, + { "scenario_id": "strategy_touch_hold", /* ... */ } + ] +} +``` + +`SimulationRunner.RunBatch(path)`가 배열 순회 실행 후 결과 N건을 모아 반환. + +## 6. 검증 + +`ScenarioLoader`가 로드 시 다음을 검증하여 에러 조기 발견: +1. 필수 필드 부재 → `ScenarioValidationException` +2. `hp > max_hp` → warning +3. `attack_cooltime <= 0` → error +4. 알 수 없는 `defence_strategy` → error +5. `schema_version` 불일치 → warning + +## 7. 예시 — 앵커 전투 (카드 0장, 4마리, 터치 방어) + +```json +{ + "schema_version": "1.0", + "scenario_id": "anchor_stage1_no_card_4mob_touch", + "description": "앵커 전투 Stage 1 — 카드 0장 상태에서 4마리 전열 몬스터와 터치 방어 전략", + "seed": 42, + "pc": { + "hp": 100, "max_hp": 100, "shield": 0, + "attack_dmg": 8, "attack_cooltime": 1.2, + "defence_strategy": "touch_hold_on_incoming" + }, + "monsters": [ + {"id": "m1", "hp": 15, "max_hp": 15, "attack_dmg": 4, "attack_cooltime": 1.8, "line": "Frontline", "attack_type": "Melee"}, + {"id": "m2", "hp": 15, "max_hp": 15, "attack_dmg": 4, "attack_cooltime": 1.8, "line": "Frontline", "attack_type": "Melee"}, + {"id": "m3", "hp": 15, "max_hp": 15, "attack_dmg": 4, "attack_cooltime": 1.8, "line": "Frontline", "attack_type": "Melee"}, + {"id": "m4", "hp": 15, "max_hp": 15, "attack_dmg": 4, "attack_cooltime": 1.8, "line": "Frontline", "attack_type": "Melee"} + ], + "simulation": {"max_turns": 500, "tick_interval": 0.1, "stop_on_death": true, "record_detail": false} +} +``` + +## 8. 변경 이력 +- **v1 (2026-04-17)**: 초판. PD 지시 #37 기반. PCDefence/PCDefence_Mul 실측값 기본 내장. + +## 9. 기각안 +- **기각안 A**: ScriptableObject 입력 → Unity Editor 외부(MCP)에서 접근 곤란. JSON이 호환성 최고 +- **기각안 B**: YAML 입력 → Unity 기본 파서 없음. JSON이 `JsonUtility` 기본 지원 +- **기각안 C**: 기존 `Actor.cs`·테이블 구조 그대로 입력 → 시뮬 독립성 훼손. 최소 스키마로 재정의 diff --git a/프로젝트/수상한잡화점/시뮬레이터/03_결과_JSON_포맷_v1.md b/프로젝트/수상한잡화점/시뮬레이터/03_결과_JSON_포맷_v1.md new file mode 100644 index 0000000..be62d53 --- /dev/null +++ b/프로젝트/수상한잡화점/시뮬레이터/03_결과_JSON_포맷_v1.md @@ -0,0 +1,206 @@ +--- +type: 설계문서 +project: 수상한잡화점 +subject: 시뮬레이션 결과 출력 JSON 포맷 +version: v1 +date: 2026-04-17 +status: 초판 +author: 개발팀장 +--- + +# 결과 JSON 포맷 v1 + +## 1. 목적 + +`SimulationRunner` 실행 결과의 **출력 포맷**. 기획팀이 후처리·비교·차트화할 때 구조화된 형태로 활용. 단일 실행·스윕·배치 모두 동일 스키마의 확장. + +## 2. 단일 실행 결과 + +```json +{ + "schema_version": "1.0", + "scenario_id": "anchor_stage1_no_card_4mob_touch", + "run_id": "run_20260417_142301_0001", + "timestamp": "2026-04-17T14:23:01Z", + "seed": 42, + "result": { + "pc_survived": true, + "pc_remaining_hp": 23, + "pc_remaining_hp_ratio": 0.23, + "total_turns": 142, + "duration_sec": 14.2, + "monsters_killed": 4, + "monsters_killed_ids": ["m1", "m2", "m3", "m4"], + "pc_damage_taken_total": 77, + "pc_damage_blocked_total": 33, + "pc_damage_dealt_total": 60, + "defence_activations": 14, + "defence_active_ratio": 0.42, + "attacks_by_pc": 8, + "attacks_by_pc_blocked_ratio": 0.0 + }, + "breakdown": { + "damage_taken_by_monster": {"m1": 16, "m2": 20, "m3": 22, "m4": 19}, + "damage_blocked_by_monster": {"m1": 7, "m2": 9, "m3": 10, "m4": 7}, + "defence_duration_sec": 5.96 + }, + "detail_log_path": null, + "errors": [] +} +``` + +## 3. 필드 정의 + +### 3-1. 메타 +| 필드 | 설명 | +|------|------| +| `schema_version` | 결과 스키마 버전 | +| `scenario_id` | 입력 시나리오 ID echo | +| `run_id` | 실행별 고유 ID (스윕·배치에서 중복 방지) | +| `timestamp` | ISO 8601 UTC | +| `seed` | 사용된 난수 시드 | + +### 3-2. result (결과 요약 — 밸런싱 판단 핵심 축) +| 필드 | 타입 | 설명 | +|------|------|------| +| `pc_survived` | bool | PC 생존 여부 | +| `pc_remaining_hp` | float | 종료 시점 PC HP | +| `pc_remaining_hp_ratio` | float | remaining_hp / max_hp | +| `total_turns` | int | 실행된 tick 수 | +| `duration_sec` | float | 시뮬 내부 경과 시간 (tick × interval) | +| `monsters_killed` | int | 처치된 몬스터 수 | +| `monsters_killed_ids` | string[] | 처치된 몬스터 ID 목록 | +| `pc_damage_taken_total` | float | PC가 받은 총 피해 (감소 후) | +| `pc_damage_blocked_total` | float | 방어로 감소된 총 피해량 (= 원본피해 - 실피해) | +| `pc_damage_dealt_total` | float | PC가 입힌 총 피해 | +| `defence_activations` | int | 방어 상태 진입 횟수 | +| `defence_active_ratio` | float | 방어 상태 유지 시간 / 전체 시뮬 시간 | +| `attacks_by_pc` | int | PC 공격 발동 횟수 | +| `attacks_by_pc_blocked_ratio` | float | PC 공격이 방어로 인해 취소된 비율 (기획팀 분석용) | + +### 3-3. breakdown (세부 분해) +| 필드 | 타입 | 설명 | +|------|------|------| +| `damage_taken_by_monster` | map | 몬스터별 가한 피해 (감소 후) | +| `damage_blocked_by_monster` | map | 몬스터별 감소시킨 피해량 | +| `defence_duration_sec` | float | 누적 방어 유지 시간 | + +### 3-4. detail_log_path (선택) +- 입력의 `simulation.record_detail == true` 이면 tick별 상세 로그 파일 경로 +- false면 `null` + +### 3-5. errors (진단) +- 시뮬 중 발생한 경고·비치명 에러 목록 (string[]) +- 치명 에러는 예외 throw로 종료되므로 본 필드에 오지 않음 + +## 4. 스윕 결과 + +```json +{ + "schema_version": "1.0", + "sweep_id": "Defence_Mul_Grid", + "sweep_axes": [ + {"path": "global_value.PCDefence_Mul", "values": [0.2, 0.3, 0.4, 0.5]}, + {"path": "monsters[0].attack_dmg", "values": [3, 5, 7]} + ], + "runs_per_cell": 10, + "cells": [ + { + "coords": {"PCDefence_Mul": 0.2, "monster_attack_dmg": 3}, + "runs": [ /* 결과 10개 */ ], + "stats": { + "pc_survived_ratio": 1.0, + "pc_remaining_hp_mean": 62.3, + "pc_remaining_hp_std": 8.1, + "total_turns_mean": 98, + "total_turns_std": 12 + } + } + /* N × M cells */ + ] +} +``` + +스윕 cell별 자동 집계 통계: +- `pc_survived_ratio`: 생존률 +- `pc_remaining_hp_mean` / `std`: 종료 HP 평균·표준편차 +- `total_turns_mean` / `std`: tick 수 평균·표준편차 + +## 5. 배치 결과 + +```json +{ + "schema_version": "1.0", + "batch_id": "Anchor_Strategies_Compare", + "results": [ + {"scenario_id": "strategy_never", /* 단일 결과 §2 */}, + {"scenario_id": "strategy_always", /* ... */}, + {"scenario_id": "strategy_touch_hold", /* ... */} + ], + "comparison": { + "best_by": "pc_remaining_hp_ratio", + "ranking": ["strategy_touch_hold", "strategy_always", "strategy_never"], + "deltas": { + "strategy_touch_hold_vs_never": {"pc_remaining_hp_ratio": 0.42, "total_turns": 34} + } + } +} +``` + +## 6. 출력 위치 선택지 + +기획팀 결정 영역 (1차 응답서 §3-2 참조). 현 설계는 3가지 지원: + +| 모드 | 출력 방식 | 용도 | +|------|----------|------| +| `stdout` | 표준 출력 스트림 | MCP `execute_code` 응답으로 즉시 수신 | +| `file` | `Assets/Sim/Output/{scenario_id}_{timestamp}.json` | Editor 내 기록 보존 | +| `path` | 사용자 지정 경로 (프로젝트 외부 가능) | `기획팀/.cache/` 등으로 직접 저장 | + +`ResultEmitter.Emit(result, mode, pathOptional)` 시그니처. + +## 7. 세부 로그 포맷 (record_detail=true 시) + +별도 파일 `detail_log_path`가 가리키는 JSON (tick별 상태): + +```json +{ + "scenario_id": "...", + "ticks": [ + { + "t": 0.0, + "pc": {"hp": 100, "is_defencing": false, "attack_acc": 0.0}, + "monsters": [{"id": "m1", "hp": 15, "attack_acc": 0.0}] + }, + { + "t": 0.1, + "pc": {"hp": 100, "is_defencing": true}, + "events": ["monster_m1_projectile_spawned", "pc_defence_activated"] + } + ] +} +``` + +**주의**: 상세 로그 파일은 tick당 수 KB이므로 `max_turns: 500` 시나리오에서 수 MB까지 가능. 평소 off 권장, 밸런스 디버깅 시점만 on. + +## 8. 후처리 가이드 (기획팀) + +### 8-1. 단일 실행 분석 +- `pc_remaining_hp_ratio` 를 "체감 난이도" 지표로 활용 (0.5 이상 = 여유, 0.2 이하 = 타이트) +- `defence_active_ratio` 가 과도히 높으면 (>0.6) 방어가 의도보다 강력함 신호 + +### 8-2. 스윕 분석 +- `pc_survived_ratio == 1.0` 이지만 `pc_remaining_hp_ratio` 편차가 큰 cell = 불안정 밸런스 +- `stats.total_turns_std / mean > 0.3` = 난수 편차 과다 (시나리오 취약) + +### 8-3. 배치 분석 +- `comparison.ranking` 로 전략 우위 확인 +- `deltas` 로 구체 수치 차이 측정 + +## 9. 변경 이력 +- **v1 (2026-04-17)**: 초판. + +## 10. 기각안 +- **기각안 A**: Markdown 결과 출력 → 후처리 자동화 곤란. JSON 구조화가 밸런싱 툴 호환성 최고 +- **기각안 B**: Excel/CSV 결과 → 중첩 구조(breakdown/sweep cells) 표현 제한. JSON + 필요 시 CSV 변환이 유연 +- **기각안 C**: tick 로그 항상 포함 → 토큰·디스크 낭비. 플래그 제어가 효율 diff --git a/프로젝트/수상한잡화점/시뮬레이터/04_MCP_호출_스니펫_v1.md b/프로젝트/수상한잡화점/시뮬레이터/04_MCP_호출_스니펫_v1.md new file mode 100644 index 0000000..a900a5c --- /dev/null +++ b/프로젝트/수상한잡화점/시뮬레이터/04_MCP_호출_스니펫_v1.md @@ -0,0 +1,191 @@ +--- +type: 설계문서 +project: 수상한잡화점 +subject: Unity MCP 호출 스니펫 — 기획팀장용 복붙 템플릿 +version: v1 +date: 2026-04-17 +status: 초판 +author: 개발팀장 +target_users: 기획팀장, /balance, /level 에이전트 +--- + +# Unity MCP 호출 스니펫 v1 + +## 1. 사용 전제 + +1. **Unity Editor 기동 중** (`D:/NerdNavis/FilGoodBandits/DeckBuilding` 프로젝트 열림) +2. **Unity MCP 연결 상태** (`mcp__unity-mcp__*` 도구 사용 가능) +3. **독립 시뮬 어셈블리 컴파일 완료** (`Assets/Sim/NerdNavis.Sim.asmdef`) +4. **시나리오 JSON 파일 준비** (스키마: `02_시나리오_JSON_스키마_v1.md`) + +검증 방법: +``` +mcp__unity-mcp__execute_code (code: "UnityEngine.Debug.Log(\"MCP OK\");") +``` + +## 2. 3종 템플릿 + +### 2-1. 단일 실행 스니펫 + +**용도**: 시나리오 1건 즉시 실행하여 결과 확인. + +**복붙용 프롬프트** (기획팀장이 Claude/PM에게 전달): +``` +Unity MCP로 아래 시나리오 1건 실행해주세요: +- 시나리오 파일: {경로 예: D:/NerdNavis/FilGoodBandits/DeckBuilding/Assets/Sim/Scenarios/anchor_stage1.json} +- 출력 모드: stdout +- 결과 요지 요청: pc_survived, pc_remaining_hp_ratio, total_turns, defence_active_ratio +``` + +**MCP 도구 호출** (실행자가 실제 수행): +```csharp +mcp__unity-mcp__execute_code + code: """ + using NerdNavis.Sim; + var runner = new SimulationRunner(); + var result = runner.Run("Assets/Sim/Scenarios/anchor_stage1.json"); + UnityEngine.Debug.Log(UnityEngine.JsonUtility.ToJson(result, true)); + """ +``` + +**기대 결과**: Unity Console에 결과 JSON 출력 (§03 포맷 v1 준수). `read_console` 로 회수 가능. + +### 2-2. 파라미터 스윕 스니펫 + +**용도**: 한 축 또는 여러 축 값들을 그리드 형태로 N회 반복 실행, 통계 집계. + +**복붙용 프롬프트**: +``` +Unity MCP로 파라미터 스윕을 실행해주세요: +- 베이스 시나리오: {경로} +- 스윕 축: + - PCDefence_Mul: [0.2, 0.3, 0.4, 0.5] + - monsters[0].attack_dmg: [3, 5, 7] +- 모드: cartesian +- 셀당 반복: 10회 +- 결과 집계 요지 요청: 각 셀의 pc_survived_ratio + pc_remaining_hp_mean +``` + +**MCP 도구 호출**: +```csharp +mcp__unity-mcp__execute_code + code: """ + using NerdNavis.Sim; + var runner = new SimulationRunner(); + var sweep = runner.RunSweep("Assets/Sim/Scenarios/sweep_defence_mul.json"); + UnityEngine.Debug.Log(UnityEngine.JsonUtility.ToJson(sweep, true)); + """ +``` + +**결과 해석 예시**: +``` +cells[0] (Mul=0.2, dmg=3): survived=1.0, HP_mean=62.3 +cells[1] (Mul=0.2, dmg=5): survived=1.0, HP_mean=34.8 +cells[2] (Mul=0.2, dmg=7): survived=0.6, HP_mean=12.1 +... (총 4 × 3 = 12 cells) +``` + +### 2-3. 배치 비교 스니펫 + +**용도**: 서로 다른 시나리오·전략 N개를 한 번에 실행하여 결과 비교. + +**복붙용 프롬프트**: +``` +Unity MCP로 전략 비교 배치 실행 해주세요: +- 배치 파일: {경로} +- 포함 시나리오: strategy_never, strategy_always, strategy_touch_hold +- 랭킹 기준: pc_remaining_hp_ratio +- 결과 요지 요청: 전략별 ranking + deltas +``` + +**MCP 도구 호출**: +```csharp +mcp__unity-mcp__execute_code + code: """ + using NerdNavis.Sim; + var runner = new SimulationRunner(); + var batch = runner.RunBatch("Assets/Sim/Scenarios/strategies_compare.json"); + UnityEngine.Debug.Log(UnityEngine.JsonUtility.ToJson(batch, true)); + """ +``` + +## 3. 파일 기반 결과 회수 (출력 모드 `file`) + +시나리오 입력에 `"output_mode": "file"` 또는 호출 시 지정: + +```csharp +mcp__unity-mcp__execute_code + code: """ + using NerdNavis.Sim; + var runner = new SimulationRunner(); + var result = runner.Run("Assets/Sim/Scenarios/anchor_stage1.json"); + ResultEmitter.EmitFile(result, "Assets/Sim/Output/anchor_stage1_result.json"); + UnityEngine.Debug.Log("saved"); + """ +``` + +이후 Read 도구로 파일 내용 조회: +``` +Read: D:/NerdNavis/FilGoodBandits/DeckBuilding/Assets/Sim/Output/anchor_stage1_result.json +``` + +## 4. 프로젝트 외부 저장 (기획팀 `.cache/` 등) + +시뮬 결과를 Unity 외부 기획 워크스페이스에 직접 저장: + +```csharp +mcp__unity-mcp__execute_code + code: """ + using NerdNavis.Sim; + var runner = new SimulationRunner(); + var result = runner.Run("Assets/Sim/Scenarios/anchor_stage1.json"); + ResultEmitter.EmitFile(result, @"D:/NerdNavis/NerdNavisAi/기획팀/.cache/sim_results/anchor_stage1.json"); + """ +``` + +## 5. 에러 진단 체크리스트 + +### 5-1. MCP 연결 실패 +- Unity Editor 상태 확인 (`manage_editor` 호출) +- MCP 서버 재시작 (Claude Code 재연결) +- Transport 모드 `stdio:6400` 확인 (교훈: 2026-04-14 Transport HTTP Local 불일치) + +### 5-2. 컴파일 에러 +- `Assets/Sim/*.cs` 변경 후 `refresh_unity` 호출하여 재컴파일 +- Editor Console 스캔: `read_console` + +### 5-3. 시나리오 파싱 실패 +- 스키마 버전 확인 (`schema_version: "1.0"`) +- JSON 유효성 검사 (외부 툴 또는 `JsonUtility.FromJson` try/catch 확인) +- `ScenarioValidationException` 메시지 참조 + +### 5-4. 결과가 이상 (비현실적 값) +- `seed` 고정 여부 (`deterministic` 모드인지 확인) +- `global_value` 기본값 오버라이드 확인 +- 상세 로그 활성화(`record_detail: true`)로 tick 추적 + +## 6. 실행 흐름 예시 (전체 파이프라인) + +``` +1. 기획팀장: 시나리오 JSON 작성 + ↓ +2. PM 또는 기획팀장: Claude Code에서 본 문서 §2-1 프롬프트 전달 + ↓ +3. Claude: mcp__unity-mcp__execute_code 호출 + ↓ +4. Unity Editor: SimulationRunner.Run() 실행 + ↓ +5. Claude: read_console 로 결과 JSON 회수 + ↓ +6. 기획팀장: 결과 JSON 분석·밸런스 튜닝 + ↓ +7. (반복) 시나리오·스윕 조정하여 다시 §2 +``` + +## 7. 변경 이력 +- **v1 (2026-04-17)**: 초판. MCP 연결 미확인 상태에서 작성 — 실제 실행 검증은 Unity Editor 기동 + MCP 연결 시점에 수행 (C23 정직). + +## 8. 기각안 +- **기각안 A**: Unity Editor 외부에서 .NET 직접 실행 → Unity 테이블 의존성·Addressable 로드 등 환경 재현 비용 과도. Editor 내 실행이 최선 +- **기각안 B**: PlayMode 강제 전환 후 시뮬 → 시뮬 독립성 저해·프레임 락·기존 InGame 로직 간섭. EditMode + 독립 Runner가 깔끔 +- **기각안 C**: Headless 모드 배치 빌드 실행 → 빌드·CI 파이프라인 복잡. MCP `execute_code` 즉시 실행이 기획팀 피드백 루프 최적