feat: 전투 시뮬레이터를 브라우저 Worker로 이관
서버가 권위 환경과 반복 seed를 준비하고 공용 logic 프로세서를 브라우저와 기존 서버 fallback이 함께 사용하도록 변경한다. production Chromium에서 고정 seed와 1000회 Node 결과 동등성을 검증한다.
This commit is contained in:
@@ -61,9 +61,11 @@ scenario parser, resource schema, PostgreSQL world loader와 battle simulator
|
||||
않습니다.
|
||||
|
||||
전투 시뮬레이터의 효과는 공개 request가 아니라 저장된 world config에서
|
||||
서버가 파생합니다. 내부 queue payload의 필드는 optional이므로 배포 전에
|
||||
생성된 payload는 효과 없음으로 처리하며, 신·구 API/worker 혼재 시에는
|
||||
효과 누락을 피하기 위해 queue를 비우거나 API와 worker를 함께 재시작합니다.
|
||||
서버가 파생합니다. `battle.prepareSimulation`은 해당 효과와 전체 병종 정의,
|
||||
전투 상수, 시나리오 시작 연도, 반복별 seed를 권위 payload로 만들고 브라우저
|
||||
Web Worker가 `@sammo-ts/logic`의 공용 프로세서를 실행합니다. 기존
|
||||
`battle.simulate`와 Redis worker도 같은 processor와 payload를 사용하므로
|
||||
검증·호환 fallback 경로에서 결과를 대조할 수 있습니다.
|
||||
|
||||
## 닫힌 의미 이벤트
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# 전투 시뮬레이터 브라우저 실행 경계
|
||||
|
||||
## 요청과 권위 데이터
|
||||
|
||||
`BattleSimulatorView.vue`는 사용자가 편집한 장수·국가·도시 입력을
|
||||
`battle.prepareSimulation`에 보냅니다. 이 API는 로그인만 요구하며 게임 장수
|
||||
보유 여부나 input-event transaction에는 의존하지 않습니다. 서버는 현재
|
||||
`WorldState`에서 다음 값을 읽어 실행 payload에 추가합니다.
|
||||
|
||||
- 전체 `UnitSetDefinition`
|
||||
- 전투 상수와 성벽 병종/병과 ID
|
||||
- 시나리오 시작 연도와 저장된 `scenarioEffect`
|
||||
- 고정 seed가 없는 경우 각 반복에 사용할 UUID seed
|
||||
|
||||
클라이언트가 같은 이름의 `scenarioEffect`를 보내도 입력 schema가 제거하며,
|
||||
저장된 효과가 유일한 기준입니다. 1000회 실행 seed를 서버에서 한 번 확정하므로
|
||||
브라우저와 Node가 동일 payload를 재실행해 전체 결과를 정확히 비교할 수 있습니다.
|
||||
|
||||
## 실행 경로
|
||||
|
||||
준비된 payload는 module Web Worker에 전달됩니다. Worker는 메시지 handler를 먼저
|
||||
등록한 뒤 `@sammo-ts/logic`을 lazy-load하고 `processBattleSimJob()`을 실행합니다.
|
||||
전투 중 UI thread를 점유하지 않으며, 결과만 화면 상태로 돌려줍니다. Worker
|
||||
bundle은 동적 trait/item module을 한 파일에 묶어 첫 실행의 다수 요청을 피합니다.
|
||||
|
||||
공용 processor와 DTO는 `packages/logic/src/battleSimulator/`가 소유합니다.
|
||||
game-api의 processor/type 파일은 기존 import와 Redis worker 호환을 위한 re-export
|
||||
경계입니다. 기존 `battle.simulate` → Redis queue → battle-sim worker 경로는 당장
|
||||
삭제하지 않고 검증 및 호환 fallback으로 유지하지만 기본 화면에서는 호출하지
|
||||
않습니다.
|
||||
|
||||
## RNG와 부작용
|
||||
|
||||
- 고정 seed가 있으면 기존 계약대로 한 번만 실행합니다.
|
||||
- 고정 seed가 없으면 `payload.seeds[index]`를 반복 순서대로 소비합니다.
|
||||
- 구형 Redis payload처럼 seed 배열이 없을 때만 실행 runtime의
|
||||
`crypto.randomUUID()`를 fallback으로 사용합니다.
|
||||
- 계산은 전달받은 plain object에서 새 도메인 객체를 만들며 DB, Redis, 턴 상태를
|
||||
변경하지 않습니다.
|
||||
|
||||
## 검증
|
||||
|
||||
`battleSimulator.spec.ts`는 production bundle의 실제 Chromium module Worker를
|
||||
실행합니다. 고정 seed와 서버 발급 seed 1000개 케이스에서 Node processor 결과와
|
||||
브라우저 Worker의 전체 결과 객체를 비교하고, 기본 UI 경로가
|
||||
`battle.simulate`/`battle.getSimulation`을 호출하지 않는지 확인합니다.
|
||||
@@ -41,10 +41,10 @@ writer reconciliation을 포함한다. rolling deployment가 끝난 뒤에만
|
||||
| Redis projection | 6 | `tournament.patchState`, `tournament.seedParticipants`, `tournament.setBettingEntries`, `tournament.setMatches`, `tournament.setParticipants`, `tournament.setState` |
|
||||
| operational | 3 | `turnDaemon.pause`, `turnDaemon.resume`, `turnDaemon.run` |
|
||||
| external upload | 1 | `board.uploadImage` |
|
||||
| read-only mutation transport | 1 | `battle.simulate` |
|
||||
| read-only mutation transport | 2 | `battle.prepareSimulation`, `battle.simulate` |
|
||||
| session only | 1 | `auth.exchangeGatewayToken` |
|
||||
|
||||
합계는 86개다.
|
||||
합계는 87개다.
|
||||
|
||||
## durable journal dependency 매핑
|
||||
|
||||
@@ -75,7 +75,8 @@ public dashboard event로 내보내지 않는다. browser wake-up은 정밀 enti
|
||||
- nation reserved turn, selection-pool reservation, possession 후보, inheritance owner
|
||||
확인은 각각 전용 화면/request response가 최신 상태를 소유한다.
|
||||
- image upload는 외부 content store write이며 game PostgreSQL read model이 아니다.
|
||||
- battle simulation은 호환상 mutation transport를 쓰지만 read-only 계산이다.
|
||||
- battle simulation 준비와 서버 fallback은 호환상 mutation transport를 쓰지만
|
||||
read-only 계산이며 input event transaction을 열지 않는다.
|
||||
|
||||
## 남은 업무 원자성 gap과 coverage 판정
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ storage, route guards, and image loading.
|
||||
| survey | `hwe/v_vote.php`, `hwe/ts/PageVote.vue` | 1000/500px fixed container, blue title/green table textures, list/detail/results/comments, selection/focus/hover, submit and retained-selection API error |
|
||||
| nation personnel | `hwe/b_myBossInfo.php` | fixed 1000px document at both viewports, chief icon columns, officer/permission/city/kick controls, role redaction |
|
||||
| nation finance | `hwe/v_nationStratFinan.php` | 1000/500px at the legacy 940px breakpoint, exact diplomacy grid, policy controls, role gating and failed-mutation rollback |
|
||||
| battle simulator | `hwe/battle_simulator.php` | centered 1000px desktop document, 500px responsive stacking, independent/current presets, owned-general import gating, fixed-seed result/logs, retained input after API error |
|
||||
| battle simulator | `hwe/battle_simulator.php` | centered 1000px desktop document, 500px responsive stacking, independent/current presets, owned-general import gating, browser Web Worker calculation including 1000 repeats, fixed-seed result/logs, retained input after API error |
|
||||
| NPC policy | `hwe/v_NPCControl.php` | 1000/500px form and priority-list geometry, walnut/green textures, dynamic zero hints, drag/focus/tooltip, successful save and permission failures |
|
||||
| tournament | `hwe/b_tournament.php` | fixed 2000px canvas, 16×125px bracket, eight 250px group tables, walnut texture, 1024px overflow, hover/focus |
|
||||
| tournament betting | `hwe/b_betting.php` | fixed 1120px canvas, 16×70px candidates, four 280px rank tables, exact title/button geometry, retained selection on error |
|
||||
|
||||
Reference in New Issue
Block a user