feat(#37): Q-P2 정밀 2차 응답 + Unity MCP 시뮬 인프라 4종 (독립 어셈블리)

- Q-P2 3서브 질의 실측 확정:
  - 피해 감소율: 실측 30% (GlobalValue.PCDefence_Mul=0.3, 기획 가정 50% 불일치)
  - 쿨다운: 없음 (UITouchHandler.cs 전수 확인)
  - 형식: 지속형 (터치 Down→Up), 방어 중 공격 불가
- 시뮬 인프라 설계문서 4종 (프로젝트/수상한잡화점/시뮬레이터/)
  - 01 아키텍처(독립 어셈블리 격리) / 02 시나리오 JSON 스키마
  - 03 결과 JSON 포맷 / 04 Unity MCP 호출 스니펫 3종
- PD 지시 로그 #37 진행중→완료 아카이브 이동
- 대화로그 엔트리 추가 (기각안 8종 포함, P24)
- Unity 프로젝트 독립 Sim 어셈블리는 별도 커밋 (DeckBuilding 레포)

PD 제약: 기존 수상한잡화점 코드·구조 불변 (Assets/Script/ 변경 0건 증명)
Editor-only 어셈블리(NerdNavis.Sim)로 빌드 산출물 제외
This commit is contained in:
깃 관리자 2026-04-17 20:58:10 +09:00
parent 775aa908d4
commit cd036eca1c
7 changed files with 958 additions and 1 deletions

View File

@ -32,7 +32,6 @@ C3·C13 위반에 해당. **즉시 자진 보고 후 소급 등록**.
| # | 일시 | 지시 요지 | 처리 상태 | 산출물 경로 | 중단 사유 | 사후 조치 | | # | 일시 | 지시 요지 | 처리 상태 | 산출물 경로 | 중단 사유 | 사후 조치 |
|---|------|----------|----------|-----------|----------|----------| |---|------|----------|----------|-----------|----------|----------|
| 2 | 2026-04-14 | 서버 Critical 보안 3건 보류 | 보류 | `프로젝트/수상한잡화점/개발/05_서버연동_현황_v1.md` | 서버 파트 정비 미완료 (PD님 지시) | 서버팀 가동 시점에 블로커급 재개. 담당: 서버팀장. 재개 트리거: 서버 파트 정비 완료 통보 | | 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 동시 재개 | | 38 | 2026-04-17 | (#28 후속 분리) Phase 3 재개 로드맵 결정 — Unity MCP 단일축 기반 밸런스 작업 재개 범위·선후관계·검증 축 확정 | 보류 | (로드맵 확정 시 기입) | PD님 별도 논의 예정 | 재개 트리거: PD님 Phase 3 재개 지시 수령. 기획팀 #3 동시 재개 |
> **2026-04-15 오후 추가 갱신 (C4·C13 위반 자진 정정 2차)**: > **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 준수) | | 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로 분리 (보류) | | 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로 분리** (대기) | | 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로 분리** (대기) |

View File

@ -119,3 +119,29 @@
- **상태**: 완료 (Q-P2 2차 정밀 응답은 후속) - **상태**: 완료 (Q-P2 2차 정밀 응답은 후속)
- **기각안**: (1) Q-P1에 "의도된 설계로 추정" 단정 응답 — 개발팀 의사결정 권한 외, C23 위반. 의도 선언은 기획팀으로 환송. (2) Q-P2 3항 전수 리버스 엔지니어링을 본 응답서에 포함 — 작업량 막대 + 범위 초과. 2차 응답서로 분리. (3) Python 시뮬레이터 복구 시도 — PD님 #28 "폐기 사안" 정면 위반. (4) Unity 외 3rd-party 시뮬레이터 검토 — PD님 Unity MCP 단일 방향 확정, 검토 대상 아님. - **기각안**: (1) Q-P1에 "의도된 설계로 추정" 단정 응답 — 개발팀 의사결정 권한 외, C23 위반. 의도 선언은 기획팀으로 환송. (2) Q-P2 3항 전수 리버스 엔지니어링을 본 응답서에 포함 — 작업량 막대 + 범위 초과. 2차 응답서로 분리. (3) Python 시뮬레이터 복구 시도 — PD님 #28 "폐기 사안" 정면 위반. (4) Unity 외 3rd-party 시뮬레이터 검토 — PD님 Unity MCP 단일 방향 확정, 검토 대상 아님.
<!-- #PD지시 #개발 #완료 #결정 #시뮬레이터 -->
## [작업완료] #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` 즉시 실행 채택

View File

@ -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` 기준 실측.

View File

@ -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` 경로 접근 제약·기획팀 셋업 복잡도 증가. 동일 레포 격리가 최선

View File

@ -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`·테이블 구조 그대로 입력 → 시뮬 독립성 훼손. 최소 스키마로 재정의

View File

@ -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<id, float> | 몬스터별 가한 피해 (감소 후) |
| `damage_blocked_by_monster` | map<id, float> | 몬스터별 감소시킨 피해량 |
| `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 로그 항상 포함 → 토큰·디스크 낭비. 플래그 제어가 효율

View File

@ -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` 즉시 실행이 기획팀 피드백 루프 최적