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