docs: add rendered developer and player handbook
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { defineConfig } from 'vitepress';
|
||||
|
||||
export default defineConfig({
|
||||
lang: 'ko-KR',
|
||||
title: 'core2026 핸드북',
|
||||
description: 'SAM core2026 개발자 내부 문서와 플레이어 이용 가이드',
|
||||
cleanUrls: true,
|
||||
lastUpdated: true,
|
||||
head: [['meta', { name: 'theme-color', content: '#6b3f22' }]],
|
||||
themeConfig: {
|
||||
siteTitle: 'core2026 핸드북',
|
||||
nav: [
|
||||
{ text: '개발자', link: '/developer/' },
|
||||
{ text: '플레이어', link: '/user/' },
|
||||
{ text: '기준 커밋', link: '/reference-baseline' },
|
||||
],
|
||||
sidebar: {
|
||||
'/developer/': [
|
||||
{
|
||||
text: '개발자 핸드북',
|
||||
items: [
|
||||
{ text: '시작하기', link: '/developer/' },
|
||||
{ text: '시스템 아키텍처', link: '/developer/system-architecture' },
|
||||
{ text: '요청·턴·저장 흐름', link: '/developer/request-turn-persistence' },
|
||||
{ text: '도메인 로직과 핵심 클래스', link: '/developer/domain-and-classes' },
|
||||
{ text: '파일 지도와 변경 절차', link: '/developer/code-map' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/user/': [
|
||||
{
|
||||
text: '플레이어 가이드',
|
||||
items: [
|
||||
{ text: '시작하기', link: '/user/' },
|
||||
{ text: '시간과 턴', link: '/user/time-and-turns' },
|
||||
{ text: '커맨드와 실행 시기', link: '/user/commands-and-timing' },
|
||||
{ text: '커맨드 전체 목록', link: '/user/command-catalog.generated' },
|
||||
{ text: '국가 운영과 주요 기능', link: '/user/nation-and-features' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
search: {
|
||||
provider: 'local',
|
||||
},
|
||||
outline: {
|
||||
level: [2, 3],
|
||||
label: '이 페이지에서',
|
||||
},
|
||||
docFooter: {
|
||||
prev: '이전',
|
||||
next: '다음',
|
||||
},
|
||||
lastUpdated: {
|
||||
text: '마지막 변경',
|
||||
},
|
||||
footer: {
|
||||
message: '현재 구현을 설명하는 문서입니다. 기준 커밋과 검증 범위를 함께 확인해 주세요.',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
# 파일 지도와 변경 절차
|
||||
|
||||
## 최상위 지도
|
||||
|
||||
```text
|
||||
core2026/
|
||||
├─ app/
|
||||
│ ├─ gateway-frontend/ 계정·로비·관리 UI
|
||||
│ ├─ gateway-api/ 인증·profile·operation·orchestrator
|
||||
│ ├─ game-frontend/ profile 게임 SPA
|
||||
│ ├─ game-api/ tRPC/SSE와 mutation 수신
|
||||
│ └─ game-engine/ turn daemon과 persistence orchestration
|
||||
├─ packages/
|
||||
│ ├─ common/ 공통 타입·직렬화·RNG
|
||||
│ ├─ logic/ 명령·constraint·전투·trigger·scenario
|
||||
│ ├─ infra/ Prisma·PostgreSQL·Redis
|
||||
│ └─ tools-scripts/ resource schema 도구
|
||||
├─ resources/ scenario·map·unitset·명령 profile
|
||||
├─ tools/
|
||||
│ ├─ integration-tests/ DB/Redis 및 ref 차등
|
||||
│ ├─ frontend-legacy-parity/ 실제 Chromium 비교
|
||||
│ ├─ legacy-db-migration/ 장기보존 데이터 CLI
|
||||
│ ├─ build-scripts/ profile resource 복사 기반 build 도구
|
||||
│ └─ docs/ 문서 생성 도구
|
||||
└─ docs/ VitePress 소스와 상세 설계 문서
|
||||
```
|
||||
|
||||
## 기능에서 파일로
|
||||
|
||||
| 기능 | 시작점 | 핵심 하위 경계 |
|
||||
| -------------- | --------------------------------------------- | ------------------------------------- |
|
||||
| 로그인·session | `gateway-api/src/router.ts` | `auth/*`, `account/router.ts`, Redis |
|
||||
| profile 운영 | `gateway-api/src/adminRouter.ts` | `orchestrator/*`, gateway Prisma |
|
||||
| 게임 인증 | `game-api/src/context.ts`, `router/auth` | session actor, profile·sanction |
|
||||
| 메인 턴 입력 | `game-frontend/src/stores/mainDashboard.ts` | `router/turns`, `turns/*` |
|
||||
| command 실행 | `game-engine/src/turn/reservedTurnHandler.ts` | `packages/logic/src/actions/turn` |
|
||||
| 월간 lifecycle | `game-engine/src/turn/turnDaemon.ts` | `monthly*Handler.ts`, scenario events |
|
||||
| 전투 | `actions/turn/general/che_출병.ts` | `packages/logic/src/war` |
|
||||
| DB load/flush | `game-engine/src/turn/worldLoader.ts` | `databaseHooks.ts`, `packages/infra` |
|
||||
| 공개/국가 정보 | `game-api/src/router/public`, `router/nation` | DTO와 redaction |
|
||||
| 화면 parity | `game-frontend/src/views`, `styles` | `tools/frontend-legacy-parity` |
|
||||
|
||||
## 변경 절차
|
||||
|
||||
### API나 화면
|
||||
|
||||
router의 input, auth procedure, transaction과 response를 먼저 정한 뒤 frontend 호출부와 오류·loading 상태를
|
||||
연결합니다. public prefix에서 direct navigation, asset, tRPC와 SSE URL을 확인합니다. UI를 바꾸면 실제
|
||||
Chromium에서 ref와 geometry·computed style·interaction을 비교합니다.
|
||||
|
||||
### 도메인 로직
|
||||
|
||||
ref entry point부터 SQL·로그까지 호출 순서를 찾고, `packages/logic` 계산과 engine context/persistence를 함께
|
||||
수정합니다. unit test만으로 끝내지 않고 fixed seed, 전체 state, RNG trace, 실패 side effect와 가능한
|
||||
ref 차등을 확인합니다.
|
||||
|
||||
### DB
|
||||
|
||||
기존 migration을 고치지 않고 새 migration을 만듭니다. 빈 DB 전체 적용, 기존 DB 증분 적용, 재실행 no-op,
|
||||
constraint/index와 runtime query, backup/restore 또는 rollback 경로를 확인합니다.
|
||||
|
||||
## 문서 사이트
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
pnpm docs:generate
|
||||
pnpm docs:dev
|
||||
pnpm docs:build
|
||||
pnpm docs:preview
|
||||
```
|
||||
|
||||
`docs:dev`와 `docs:build`는 먼저 커맨드 목록을 생성합니다. 정적 결과는 `docs/.vitepress/dist`에 생기며
|
||||
Git에 포함하지 않습니다. 문서만 바꿔도 Prettier, 생성 결과의 clean diff, VitePress build와 내부 링크를
|
||||
검증해 주세요.
|
||||
|
||||
## 리팩터링 체크포인트
|
||||
|
||||
- [문서 기준선](../reference-baseline.md)과 현재 commit의 diff를 먼저 봅니다.
|
||||
- 파일 이동만 했는지 소유권·transaction·호출 순서까지 바뀌었는지 구분합니다.
|
||||
- public API, DB schema, action key와 resource format은 내부 파일명보다 강한 계약입니다.
|
||||
- `rg`로 이 페이지의 이전 경로가 남았는지 확인합니다.
|
||||
- command key를 바꿨다면 저장된 예약 턴과 profile resource의 migration/호환 경로가 필요합니다.
|
||||
- 문서의 광범위한 “완료” 표현은 관련 integration·ref 차등·Chromium 증거가 있을 때만 사용합니다.
|
||||
@@ -0,0 +1,106 @@
|
||||
# 도메인 로직과 핵심 클래스
|
||||
|
||||
## 핵심 entity
|
||||
|
||||
`packages/logic/src/domain/entities.ts`가 HTTP나 Prisma row에 종속되지 않은 `General`, `City`, `Nation`,
|
||||
`Troop`, diplomacy와 trigger 상태를 정의합니다. engine 전용 `TurnGeneral`, `TurnWorldState`,
|
||||
`TurnEvent`는 `app/game-engine/src/turn/types.ts`에서 실행 시간·예약 턴·월간 상태를 더합니다.
|
||||
|
||||
| entity | 핵심 책임 |
|
||||
| ------- | -------------------------------------------------------------------------- |
|
||||
| General | 능력치, 경험·공헌, 소속·도시·부대, 병력·훈련·사기, 자원, 특기·아이템, meta |
|
||||
| City | 소유 국가, 규모, 인구·농업·상업·치안, 수비·성벽, 보급·전선 상태 |
|
||||
| Nation | 수도, 국고·군량, 등급·국가 타입, 기술과 국가 meta |
|
||||
| Troop | 부대장·구성원과 부대 상태 |
|
||||
| World | 현재 연·월, 최근 턴 시각, scenario config/meta와 전체 entity collection |
|
||||
|
||||
Prisma row를 곧바로 게임 규칙에 넘기지 않습니다. `worldLoader.ts`와 API의 row mapper가 DB 표현을 domain
|
||||
표현으로 바꾸고, flush 계층이 반대 변환을 담당합니다.
|
||||
|
||||
## 명령 정의
|
||||
|
||||
`GeneralActionDefinition`은 장수·국가 예약 명령이 공유하는 계약입니다.
|
||||
|
||||
- `key`, `name`: 저장 key와 화면 표시명
|
||||
- `parseArgs`: 외부 입력을 실행 인자로 변환
|
||||
- `buildPermissionConstraints`: 예약 입력 자체를 허용할지 판단
|
||||
- `buildMinConstraints`: command table에서 현재 가능한지 사전 판단
|
||||
- `buildConstraints`: 실행 시점의 전체 조건
|
||||
- `getPreReqTurn`, `getPostReqTurn`: 연속 실행과 재사용 대기
|
||||
- `resolve`: domain state와 effect를 계산
|
||||
|
||||
각 파일의 `commandSpec`은 category, 인자 필요 여부, schema와 definition factory를 등록합니다.
|
||||
`GENERAL_TURN_COMMAND_KEYS`, `NATION_TURN_COMMAND_KEYS`가 전체 key 집합이며, `TurnCommandProfile`이
|
||||
profile별 subset을 선택합니다.
|
||||
|
||||
## Constraint 시스템
|
||||
|
||||
`packages/logic/src/constraints`는 “무엇이 필요한가”와 “현재 view가 무엇을 알고 있는가”를 분리합니다.
|
||||
`ConstraintContext`에는 actor, city, nation, args, env와 평가 mode가 있고 `StateView`가 entity와 대상
|
||||
정보를 제공합니다.
|
||||
|
||||
평가 결과는 다음 셋입니다.
|
||||
|
||||
- `allow`: 현재 정보로 조건을 만족합니다.
|
||||
- `deny`: 이유가 확정된 실패입니다.
|
||||
- `unknown`: 대상 입력이나 추가 state가 없어 아직 판정할 수 없습니다.
|
||||
|
||||
API command table은 `unknown`의 missing requirement가 대상 입력뿐이면 `needsInput`, 그 밖이면
|
||||
`unknown`으로 보여 줍니다. 예약 뒤 실제 실행에서는 전체 context로 다시 판단합니다.
|
||||
|
||||
## 핵심 클래스와 조립 지점
|
||||
|
||||
### TurnDaemonLifecycle
|
||||
|
||||
`app/game-engine/src/lifecycle/turnDaemonLifecycle.ts`에 있습니다. clock, control queue, hook과 run budget을
|
||||
조정하며 pause/resume/manual/scheduled run의 상태 전이를 소유합니다.
|
||||
|
||||
### DatabaseTurnDaemonLease
|
||||
|
||||
`app/game-engine/src/lifecycle/databaseTurnDaemonLease.ts`에 있습니다. profile별 단일 active owner와 fencing을
|
||||
관리합니다. daemon 계산이 맞아도 lease를 잃었다면 결과를 저장하면 안 됩니다.
|
||||
|
||||
### InMemoryTurnWorld
|
||||
|
||||
`app/game-engine/src/turn/inMemoryWorld.ts`에 있습니다. entity map, dirty/create/delete set, log, message,
|
||||
event, checkpoint와 월 변경을 소유합니다. `peekDirtyState()`는 저장할 변경을 보여 주고 성공한 flush 뒤
|
||||
정리됩니다.
|
||||
|
||||
### EngineStateManager
|
||||
|
||||
`app/game-engine/src/turn/engineStateManager.ts`에 있습니다. world와 예약 턴 store 같은 mutable participant를
|
||||
등록하고 계산 단위의 capture/restore/transaction을 제공합니다. PostgreSQL transaction을 대신하지 않고
|
||||
실패한 계산의 메모리 rollback을 담당합니다.
|
||||
|
||||
### InMemoryReservedTurnStore와 ReservedTurnHandler
|
||||
|
||||
`reservedTurnStore.ts`는 장수 30칸·국가 12칸 예약 queue를 메모리에 유지합니다.
|
||||
`reservedTurnHandler.ts`는 명령 loading, constraint, action context, AI fallback, progress/cooldown,
|
||||
효과·로그와 queue rotation을 연결합니다.
|
||||
|
||||
### GeneralActionPipeline과 trigger module
|
||||
|
||||
`packages/logic/src/actions/engine.ts`, `triggers/*`는 명령 본체 전후의 특기·아이템·국가 특성 효과를
|
||||
일정한 우선순위로 적용합니다. 같은 module 목록이라도 실행 순서가 결과와 RNG 소비를 바꿀 수 있습니다.
|
||||
|
||||
### WarEngine
|
||||
|
||||
`packages/logic/src/war/engine.ts`가 전투 resolution을, `war/actions.ts`와 trigger module이 확장 효과를,
|
||||
`war/aftermath.ts`가 피해·점령·외교·후속 state를 계산합니다. `che_출병.ts`가 map, unit set, diplomacy,
|
||||
time, seed와 aftermath를 조립하는 실제 장수 명령 entry입니다.
|
||||
|
||||
### GatewayOrchestrator
|
||||
|
||||
`app/gateway-api/src/orchestrator/gatewayOrchestrator.ts`가 DB의 profile desired state를 process state에
|
||||
맞춥니다. `workspaceManager.ts`, `buildRunner.ts`, `seedProfileDatabase.ts`, `pm2ProcessManager.ts`가
|
||||
commit worktree 준비부터 build, seed, start/stop을 나눕니다.
|
||||
|
||||
## 새 명령을 추가할 때
|
||||
|
||||
1. 가장 가까운 ref command의 constraint, 실행 순서, RNG, 로그와 DB side effect를 조사합니다.
|
||||
2. `packages/logic/src/actions/turn/{general,nation}`에 definition과 `commandSpec`을 작성합니다.
|
||||
3. 해당 `*_TURN_COMMAND_KEYS`와 필요한 `resources/turn-commands` profile에 key를 등록합니다.
|
||||
4. 인자가 있으면 Zod schema와 `app/game-api/src/turns/commandInput.ts`의 화면 입력 field를 연결합니다.
|
||||
5. engine action context가 대상 entity·map·unit set·시간·seed를 완전하게 공급하는지 확인합니다.
|
||||
6. permission/min/full 실패, 성공, 연속 턴, cooldown과 persistence를 테스트합니다.
|
||||
7. `pnpm docs:generate`로 플레이어 커맨드 목록을 갱신하고 ref 매핑 문서를 함께 수정합니다.
|
||||
@@ -0,0 +1,29 @@
|
||||
# 개발자 핸드북
|
||||
|
||||
이 핸드북은 새 기능을 어디에 넣을지뿐 아니라 요청이 어떤 경계를 지나 상태로 남는지 설명합니다. 먼저
|
||||
[문서 기준선](../reference-baseline.md)을 확인하고, 변경 성격에 따라 다음 순서로 읽어 주세요.
|
||||
|
||||
| 변경하려는 것 | 먼저 읽을 문서 | 주로 확인할 코드 |
|
||||
| -------------------------- | ---------------------------------------------------- | -------------------------------------------- |
|
||||
| 화면·라우팅·조회 API | [시스템 아키텍처](./system-architecture.md) | `app/*-frontend`, `app/*-api` |
|
||||
| 턴 입력·게임 상태 mutation | [요청·턴·저장 흐름](./request-turn-persistence.md) | `app/game-api`, `app/game-engine` |
|
||||
| 명령·전투·월간 로직 | [도메인 로직과 핵심 클래스](./domain-and-classes.md) | `packages/logic`, `app/game-engine/src/turn` |
|
||||
| 새 파일 위치·검증 범위 | [파일 지도와 변경 절차](./code-map.md) | package manifest, test, docs |
|
||||
|
||||
## 읽을 때 지켜야 할 경계
|
||||
|
||||
- `packages/logic`의 순수 계산과 `app/game-engine`의 scheduling·persistence orchestration을 구분합니다.
|
||||
- game API가 mutation을 받는 것과 engine이 world mutation을 확정하는 것은 다른 단계입니다.
|
||||
- PostgreSQL `input_event`가 내구성 있는 작업 경계이며 Redis는 realtime fan-out과 일부 보조 worker
|
||||
통신에 사용됩니다.
|
||||
- 로그인한 사용자, 게임 장수, 국가 직책은 같은 개념이 아닙니다. actor와 소유권은 session에서
|
||||
서버가 결정합니다.
|
||||
- `resources/`의 scenario·map·unit set·turn-command profile이 런타임 구성을 바꿉니다. 기본 TypeScript
|
||||
목록만 보고 실제 profile을 단정하지 않습니다.
|
||||
- ref 호환 변경은 결과뿐 아니라 판정·정렬·반올림·RNG 소비·로그·저장 순서를 비교합니다.
|
||||
|
||||
## 기존 상세 문서와의 관계
|
||||
|
||||
이 핸드북은 탐색용 상위 지도입니다. 상세한 호환 근거와 테스트 절차는 `docs/architecture/*`,
|
||||
`docs/integration-tests.md`, `docs/frontend-legacy-parity.md`에 유지합니다. 상위 작업공간의
|
||||
`../docs/ref-core2026-mapping.md`는 ref entry point와 core 구현의 end-to-end 대응 인덱스입니다.
|
||||
@@ -0,0 +1,99 @@
|
||||
# 요청·턴·저장 흐름
|
||||
|
||||
## 조회 요청
|
||||
|
||||
일반 query는 다음 경로를 따릅니다.
|
||||
|
||||
```text
|
||||
Vue view/store
|
||||
-> tRPC client
|
||||
-> game-api router
|
||||
-> session actor + 입력 validation
|
||||
-> Prisma query
|
||||
-> 권한에 맞춘 DTO/redaction
|
||||
-> 화면 상태
|
||||
```
|
||||
|
||||
조회는 engine의 in-memory object를 직접 공유하지 않습니다. 따라서 daemon이 transaction을 commit하기 전의
|
||||
중간 계산은 API query에 노출되지 않습니다.
|
||||
|
||||
## API가 직접 끝내는 mutation
|
||||
|
||||
예약 턴, 메시지처럼 API가 DB에서 완결할 수 있는 변경도 `input_event`를 사용합니다.
|
||||
|
||||
1. `Idempotency-Key`와 tRPC path로 요청 identity를 만듭니다.
|
||||
2. `app/game-api/src/inputEventBoundary.ts`가 중복·처리 상태를 확인합니다.
|
||||
3. 같은 PostgreSQL transaction에서 대상 row와 input event 결과를 저장합니다.
|
||||
4. commit 뒤 응답하고 필요한 realtime 갱신을 알립니다.
|
||||
|
||||
동일 revision을 전제로 한 예약 턴 수정은 다른 탭이나 요청이 먼저 갱신했으면 충돌합니다. frontend는 최신
|
||||
목록을 다시 불러와 사용자의 변경을 덮어쓰지 않게 해야 합니다.
|
||||
|
||||
## engine이 처리하는 mutation
|
||||
|
||||
```text
|
||||
game-api mutation
|
||||
-> input_event PENDING
|
||||
-> daemon claim (FOR UPDATE SKIP LOCKED)
|
||||
-> lease/fencing 확인
|
||||
-> EngineStateManager savepoint
|
||||
-> command/turn/monthly handler가 InMemoryTurnWorld 변경
|
||||
-> world + 예약 턴 + log + message + event 결과 flush
|
||||
-> input_event COMPLETED를 같은 DB transaction으로 commit
|
||||
-> commit 이후 realtime 신호
|
||||
```
|
||||
|
||||
계산이나 DB 쓰기가 실패하면 `EngineStateManager`가 등록된 in-memory participant를 savepoint로 되돌립니다.
|
||||
DB transaction도 commit되지 않아 메모리와 DB의 부분 진행을 피합니다. lease를 잃은 worker는 stale 결과를
|
||||
commit할 수 없어야 합니다.
|
||||
|
||||
## 한 tick의 처리
|
||||
|
||||
`TurnDaemonLifecycle`은 clock과 schedule에서 다음 실행 시점을 구합니다. 턴을 시작하면
|
||||
`InMemoryTurnProcessor`와 `InMemoryTurnWorld`가 `turnTime`, 그다음 `general.id` 순서로 실행 대상을
|
||||
결정합니다. checkpoint는 재시작 시 이미 처리한 동일 시점의 장수를 건너뛰는 기준입니다.
|
||||
|
||||
장수 한 명의 예약 명령은 대략 다음 순서입니다.
|
||||
|
||||
1. `InMemoryReservedTurnStore`에서 첫 예약 명령을 읽습니다.
|
||||
2. 명령 key를 `GeneralTurnCommandLoader` 또는 `NationTurnCommandLoader`로 불러옵니다.
|
||||
3. `actionContextBuilder`가 대상 도시·국가·장수, map, unit set, 외교, 시간과 RNG를 구성합니다.
|
||||
4. permission/min/full constraint를 목적에 맞게 평가합니다.
|
||||
5. 선행 턴이 있으면 진행 상태를 쌓고, 완성된 시점에 `resolve()`를 실행합니다.
|
||||
6. effect와 직접 변경을 world에 반영하고 로그·메시지·후속 턴 시간을 기록합니다.
|
||||
7. 실행된 queue를 당기고 끝에 기본 `휴식`을 채웁니다.
|
||||
|
||||
예약 시 통과와 실행 시 성공은 같지 않습니다. 그 사이 자원, 도시 소유, 외교, 직책이 바뀔 수 있으므로 full
|
||||
constraint는 실행 순간 다시 평가됩니다.
|
||||
|
||||
## 월 변경 경계
|
||||
|
||||
`InMemoryTurnWorld.advanceMonth()`는 다음 순서를 보존합니다.
|
||||
|
||||
1. 다음 연·월을 계산합니다.
|
||||
2. `beforeMonthChanged` handler를 등록 순서대로 실행합니다.
|
||||
3. world의 현재 연·월을 바꿉니다.
|
||||
4. `onMonthChanged` handler를 등록 순서대로 실행합니다.
|
||||
5. 연도가 바뀌었으면 `onYearChanged`를 실행합니다.
|
||||
|
||||
`turnDaemon.ts`의 `composeCalendarHandlers()` 순서에는 월간 event, 수입, 연감, PRE_MONTH 상태 정리,
|
||||
국가 명령, 국가 통계, 외교, 전쟁 설정, 방랑, 국가 수, 통일, 토너먼트, 경매, 전선 상태가 포함됩니다.
|
||||
이 순서는 ref의 관찰 가능한 결과와 RNG·persistence에 영향을 주므로 리팩터링 시 단순 정렬하지 않습니다.
|
||||
|
||||
## RNG 경계
|
||||
|
||||
게임 결과에 영향을 주는 난수는 `LiteHashDRBG`와 `RandUtil`을 사용합니다. seed에는 hidden seed와
|
||||
action/month/general 같은 context가 직렬화됩니다. main RNG의 소비 순서를 유지해야 하는 로직과 독립된
|
||||
재현 가능 substream을 써야 하는 fallback을 구분합니다. authoritative path에 `Math.random()`을 넣지
|
||||
않습니다.
|
||||
|
||||
## 장애를 추적할 위치
|
||||
|
||||
| 증상 | 우선 확인 |
|
||||
| ----------------------------- | --------------------------------------------------------------------- |
|
||||
| 같은 mutation이 두 번 보임 | idempotency key, `input_event` 상태·attempt |
|
||||
| 요청은 성공했지만 화면이 늦음 | DB commit 결과, Redis/SSE fan-out |
|
||||
| daemon이 처리하지 않음 | profile gate, pause 상태, lease owner, PENDING claim |
|
||||
| 재시작 뒤 일부 턴 반복 | checkpoint와 general turn ordering |
|
||||
| DB와 메모리가 다름 | `EngineStateManager`, `databaseHooks`, flush 대상 누락 |
|
||||
| ref와 결과가 다름 | constraint 순서, action context, RNG trace, rounding, log/effect 순서 |
|
||||
@@ -0,0 +1,99 @@
|
||||
# 시스템 아키텍처
|
||||
|
||||
## 런타임 구성
|
||||
|
||||
```text
|
||||
브라우저
|
||||
├─ /gateway/ ─ gateway-frontend ─ tRPC ─ gateway-api
|
||||
│ ├─ PostgreSQL public schema
|
||||
│ ├─ Redis session
|
||||
│ └─ orchestrator ─ Git worktree / build / PM2
|
||||
│
|
||||
└─ /{profile}/ ─ game-frontend ─ tRPC/SSE ─ game-api
|
||||
├─ profile별 PostgreSQL schema
|
||||
├─ Redis realtime/battle worker
|
||||
└─ input_event ─ game-engine
|
||||
├─ in-memory world
|
||||
└─ transactional flush
|
||||
```
|
||||
|
||||
Gateway는 계정·session·profile lifecycle을, game 계층은 한 profile의 플레이와 턴 진행을 소유합니다.
|
||||
`/gateway`, `/che`, `/hwe` 같은 외부 prefix와 `/image/*`의 Caddy 소유권은 애플리케이션 밖의 배포
|
||||
계약입니다.
|
||||
|
||||
## 애플리케이션
|
||||
|
||||
### gateway-frontend
|
||||
|
||||
`app/gateway-frontend/src/main.ts`가 Vue 앱과 router를 시작합니다. 가입·로그인·계정·로비·관리자 화면은
|
||||
`src/views`에 있고, profile 선택 뒤 game frontend로 이동합니다. 브라우저에 보이는 `VITE_*` 값은
|
||||
공개 설정이며 secret이 아닙니다.
|
||||
|
||||
### gateway-api
|
||||
|
||||
`app/gateway-api/src/server.ts`와 `router.ts`가 HTTP/tRPC 경계입니다.
|
||||
|
||||
- `auth/*`, `account/router.ts`: Kakao·로컬 계정, session 발급·폐기, 사용자 저장소
|
||||
- `lobby/profileStatusService.ts`: 사용자에게 보여 줄 profile 상태
|
||||
- `adminRouter.ts`, `adminAuth.ts`: 관리자 권한과 operation 입력
|
||||
- `orchestrator/*`: 원하는 profile 상태를 Git worktree, build, seed, PM2 프로세스에 반영
|
||||
|
||||
Gateway DB는 기본 `public` schema를 사용합니다. game profile DB를 직접 게임 로직의 source of truth로
|
||||
대체하지 않습니다.
|
||||
|
||||
### game-frontend
|
||||
|
||||
`app/game-frontend/src/main.ts`가 profile base path 아래 Vue SPA를 시작합니다. `src/views`가 공개 정보,
|
||||
메인 턴 입력, 국가 운영, 경매·토너먼트·기록 화면을 나누고 `src/stores/mainDashboard.ts`가 메인 화면의
|
||||
query, 예약 턴 revision, mutation과 realtime refresh를 조정합니다.
|
||||
|
||||
UI는 서버가 반환한 command table의 `available`, `blocked`, `needsInput`, `unknown` 상태를 사용합니다.
|
||||
클라이언트가 장수 ID나 직책을 보냈다는 이유만으로 권한이 생기지 않습니다.
|
||||
|
||||
### game-api
|
||||
|
||||
`app/game-api/src/server.ts`와 `router.ts`가 query/mutation을 공개합니다. router는 기능 단위로
|
||||
`src/router/*`에 나뉩니다.
|
||||
|
||||
- 읽기: world, public, directory, ranking, yearbook, dynasty 등은 권한·redaction을 거쳐 DB에서 조회합니다.
|
||||
- 플레이: turns, join, nation, troop, diplomacy, messages, auction, betting, tournament 등이 있습니다.
|
||||
- mutation: `inputEventBoundary.ts`가 idempotency와 PostgreSQL 작업 경계를 만듭니다.
|
||||
- realtime: SSE와 Redis 알림은 commit 이후 화면 갱신 신호입니다.
|
||||
|
||||
### game-engine
|
||||
|
||||
`app/game-engine/src/index.ts`가 daemon entry point이고 `src/turn/turnDaemon.ts`가 profile resource,
|
||||
world snapshot, command registry, calendar handler, persistence hook과 lease를 조립합니다.
|
||||
|
||||
한 daemon owner가 `TurnDaemonLifecycle`을 통해 정해진 tick과 durable inbox를 처리합니다. 실제 장수·도시·국가
|
||||
상태는 `InMemoryTurnWorld`에서 계산하고, 성공한 작업만 `databaseHooks.ts`를 통해 PostgreSQL에 flush합니다.
|
||||
lease/fencing은 오래된 daemon owner의 commit을 막습니다.
|
||||
|
||||
## 공유 package
|
||||
|
||||
| package | 책임 | 넣지 말아야 할 것 |
|
||||
| ------------------------ | ------------------------------------------------------------------------------- | ---------------------------------- |
|
||||
| `packages/common` | 공통 type, 직렬화, `LiteHashDRBG`, `RandUtil`, session/sanction 유틸리티 | profile DB orchestration |
|
||||
| `packages/logic` | entity, constraint, command, battle, trigger, scenario parsing 같은 도메인 계산 | HTTP·Vue·Prisma transaction 소유권 |
|
||||
| `packages/infra` | Prisma client, PostgreSQL·Redis connector, log와 turn-engine DB adapter | 게임 규칙 결정 |
|
||||
| `packages/tools-scripts` | resource schema 생성·검증 | 런타임 요청 처리 |
|
||||
|
||||
## 데이터와 구성
|
||||
|
||||
- `packages/infra/prisma/schema.gateway.prisma`: 계정·profile·operation 같은 gateway 모델
|
||||
- `packages/infra/prisma/schema.game.prisma`: profile별 world·general·city·nation·turn·event·log 모델
|
||||
- `resources/scenario`: 시작 연도, 상수, 월간 event 등 scenario 정의
|
||||
- `resources/map`, `resources/unitset`: 지형과 병종 정의
|
||||
- `resources/turn-commands`: profile별 허용 명령 목록
|
||||
|
||||
새 persistence field는 schema와 새 migration만으로 끝나지 않습니다. domain type, loader, in-memory dirty
|
||||
tracking, transaction flush, reload 검증까지 연결해야 합니다.
|
||||
|
||||
## 인증·권한 모델
|
||||
|
||||
Gateway session은 사용자 identity를, game token은 profile과 게임 역할을 전달합니다. game API는 session으로
|
||||
내 장수를 조회한 뒤 그 장수의 국가·직책·sanction과 대상 resource의 관계를 판단합니다. 공개 endpoint도
|
||||
비공개 국가 정보, 타 사용자 archive, 비밀 명령을 DTO에서 제거해야 합니다.
|
||||
|
||||
권한 변경을 검증할 때는 무인증, 일반 사용자, 본인, 같은 국가, 다른 국가, NPC, 직책 보유자, sanction
|
||||
적용자를 필요한 범위에서 나눕니다. 거부된 mutation은 world와 queue에 side effect를 남기지 않아야 합니다.
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: core2026 핸드북
|
||||
text: 구현과 플레이를 한곳에서 설명합니다
|
||||
tagline: 현재 코드의 아키텍처·실행 흐름·핵심 클래스와 커맨드·시기별 이용 방법을 연결한 문서입니다.
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 개발자 핸드북
|
||||
link: /developer/
|
||||
- theme: alt
|
||||
text: 플레이어 가이드
|
||||
link: /user/
|
||||
|
||||
features:
|
||||
- title: 코드에서 실행까지
|
||||
details: frontend, tRPC, input_event, daemon, in-memory world와 PostgreSQL flush의 실제 경계를 따라갑니다.
|
||||
- title: 커맨드와 시기
|
||||
details: 장수·국가 커맨드 전체 목록을 소스에서 생성하고, 언제 왜 실행 가능하거나 막히는지 설명합니다.
|
||||
- title: 고정된 기준선
|
||||
details: 문서가 조사한 Git 기준 커밋과 재검증 지점을 밝혀 이후 리팩터링의 출발점을 남깁니다.
|
||||
---
|
||||
|
||||
## 문서 성격
|
||||
|
||||
이 사이트는 `report/`의 작업 일지가 아니라 제품 저장소 안에서 계속 갱신하는 핸드북입니다.
|
||||
개발자는 [시스템 아키텍처](./developer/system-architecture.md)부터, 플레이어는
|
||||
[시간과 턴](./user/time-and-turns.md)부터 읽으면 됩니다.
|
||||
|
||||
문서의 사실관계는 [기준 커밋](./reference-baseline.md)의 코드에서 확인했습니다. 기능을 변경했다면 같은
|
||||
작업에서 관련 페이지와 자동 생성 커맨드 목록을 함께 갱신해 주세요.
|
||||
@@ -0,0 +1,39 @@
|
||||
# 문서 기준선
|
||||
|
||||
## 코드 기준 커밋
|
||||
|
||||
이 핸드북의 최초 전면 갱신은 다음 상태를 기준으로 조사했습니다.
|
||||
|
||||
| 항목 | 값 |
|
||||
| ----------- | ------------------------------------------ |
|
||||
| 저장소 | `devsam/core2026.git` |
|
||||
| 브랜치 | `main` |
|
||||
| 기준 커밋 | `1181f6f4e03cbed77b1c40b6b572585f6e395a2c` |
|
||||
| 기준 일자 | 2026-07-28 |
|
||||
| 레거시 위치 | 형제 저장소 `../ref/sam`의 `devel` |
|
||||
|
||||
기준 커밋은 “이 버전이 완성됐다”는 선언이 아니라 문장과 소스 경로를 다시 대조할 출발점입니다. 이후
|
||||
리팩터링에서 설명과 코드가 어긋나면 다음 순서로 갱신해 주세요.
|
||||
|
||||
1. 이 페이지의 기준 커밋과 현재 `main` 사이의 변경 파일을 확인합니다.
|
||||
2. 해당 문서가 가리키는 entry point, 호출 순서, transaction과 오류 경로를 다시 추적합니다.
|
||||
3. 커맨드 등록부를 바꿨다면 `pnpm docs:generate`로 생성 페이지의 차이를 확인합니다.
|
||||
4. `pnpm docs:build`로 링크와 정적 HTML 생성을 검증합니다.
|
||||
5. 기준 커밋과 기준 일자를 현재 조사한 commit으로 바꾸고, 검증하지 못한 범위를 명시합니다.
|
||||
|
||||
## 사실 수준
|
||||
|
||||
- 이 핸드북의 아키텍처·파일·클래스 설명은 기준 커밋의 정적 코드와 기존 검증 문서를 교차 확인한
|
||||
결과입니다.
|
||||
- `input_event` transaction, daemon lease, ref 차등, 실제 Chromium 같은 동작 증명은 각 테스트와
|
||||
기존 상세 문서가 담당합니다. 이 핸드북 자체의 HTML 빌드가 제품 동작을 다시 증명하지는 않습니다.
|
||||
- profile과 scenario가 명령 목록·상수·맵·병종을 바꿀 수 있으므로 플레이어 화면의 현재 가능 여부가
|
||||
정적 표보다 우선입니다.
|
||||
|
||||
## 상세 근거 문서
|
||||
|
||||
- [레거시 이관 제약](./architecture/rewrite-constraints.md)
|
||||
- [턴 daemon lifecycle](./architecture/turn-daemon-lifecycle.md)
|
||||
- [PostgreSQL schema](./architecture/postgres-schema.md)
|
||||
- [프론트엔드 CSS 구조](./frontend-css-architecture.md)
|
||||
- [레거시 화면 비교](./frontend-legacy-parity.md)
|
||||
@@ -0,0 +1,188 @@
|
||||
---
|
||||
title: 커맨드 전체 목록
|
||||
outline: deep
|
||||
---
|
||||
|
||||
<!-- 이 파일은 tools/docs/generate-command-reference.mjs가 생성합니다. 직접 수정하지 말아 주세요. -->
|
||||
|
||||
# 커맨드 전체 목록
|
||||
|
||||
이 페이지는 현재 소스의 명령 등록부와 각 `commandSpec`에서 자동 생성됩니다.
|
||||
총 90개이며, profile의 `resources/turn-commands/*.json` 설정에 따라 실제 서버에서 일부가 제외될 수
|
||||
있습니다. “기본 실행 단위”는 정의에 고정된 선행 턴만 표시합니다. 자원, 신분, 도시, 외교, 시나리오 시점처럼
|
||||
실행 순간에 달라지는 조건은 [커맨드와 실행 시기](./commands-and-timing.md)를 확인해 주세요.
|
||||
|
||||
## 장수 커맨드
|
||||
|
||||
등록된 명령은 55개입니다.
|
||||
|
||||
### 전략
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| -------------- | ------------------ | -------------- | -------------- |
|
||||
| `che_거병` | 거병 | 없음 | 1턴 |
|
||||
| `che_임관` | 임관 | 필요 | 1턴 |
|
||||
| `che_랜덤임관` | 무작위 국가로 임관 | 없음 | 1턴 |
|
||||
| `che_건국` | 건국 | 필요 | 1턴 |
|
||||
|
||||
### 군사
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| -------------- | --------- | -------------- | -------------- |
|
||||
| `che_귀환` | 귀환 | 없음 | 1턴 |
|
||||
| `che_훈련` | 훈련 | 없음 | 1턴 |
|
||||
| `cr_맹훈련` | 맹훈련 | 없음 | 1턴 |
|
||||
| `che_전투태세` | 전투태세 | 없음 | 1턴 |
|
||||
| `che_단련` | 단련 | 없음 | 1턴 |
|
||||
| `che_숙련전환` | 숙련전환 | 필요 | 1턴 |
|
||||
| `che_사기진작` | 사기진작 | 없음 | 1턴 |
|
||||
| `che_출병` | 출병 | 필요 | 1턴 |
|
||||
| `che_집합` | 집합 | 없음 | 1턴 |
|
||||
| `che_모병` | 모병 | 필요 | 1턴 |
|
||||
| `che_소집해제` | 소집해제 | 없음 | 1턴 |
|
||||
| `che_이동` | 이동 | 필요 | 1턴 |
|
||||
| `che_방랑` | 방랑 | 없음 | 1턴 |
|
||||
| `che_첩보` | 첩보 | 필요 | 1턴 |
|
||||
| `che_파괴` | 파괴 | 필요 | 1턴 |
|
||||
| `che_선동` | 선동 | 필요 | 1턴 |
|
||||
| `che_탈취` | 탈취 | 필요 | 1턴 |
|
||||
| `che_강행` | 강행 | 필요 | 1턴 |
|
||||
|
||||
### 인사
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| ------------------ | ---------------- | -------------- | -------------- |
|
||||
| `che_등용수락` | 등용수락 | 필요 | 1턴 |
|
||||
| `che_장수대상임관` | 장수를 따라 임관 | 필요 | 1턴 |
|
||||
| `che_인재탐색` | 인재탐색 | 없음 | 1턴 |
|
||||
| `che_접경귀환` | 접경귀환 | 없음 | 1턴 |
|
||||
| `che_하야` | 하야 | 없음 | 1턴 |
|
||||
| `che_등용` | 등용 | 필요 | 1턴 |
|
||||
|
||||
### 국가
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| ---------------- | ---------------- | -------------- | -------------- |
|
||||
| `cr_건국` | 건국 | 필요 | 1턴 |
|
||||
| `che_무작위건국` | 무작위 도시 건국 | 필요 | 1턴 |
|
||||
| `che_선양` | 선양 | 필요 | 1턴 |
|
||||
| `che_모반시도` | 모반시도 | 없음 | 1턴 |
|
||||
| `che_증여` | 증여 | 필요 | 1턴 |
|
||||
| `che_해산` | 해산 | 없음 | 1턴 |
|
||||
|
||||
### 개인
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| -------------------- | ---------------- | -------------- | -------------- |
|
||||
| `che_요양` | 요양 | 없음 | 1턴 |
|
||||
| `che_견문` | 견문 | 없음 | 1턴 |
|
||||
| `che_장비매매` | 장비매매 | 필요 | 1턴 |
|
||||
| `che_내정특기초기화` | 내정 특기 초기화 | 없음 | 1턴 |
|
||||
| `che_전투특기초기화` | 전투 특기 초기화 | 없음 | 1턴 |
|
||||
| `che_군량매매` | 군량매매 | 필요 | 1턴 |
|
||||
| `che_은퇴` | 은퇴 | 없음 | 1턴 |
|
||||
| `휴식` | 휴식 | 없음 | 1턴 |
|
||||
|
||||
### 내정
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| -------------- | --------- | -------------- | -------------- |
|
||||
| `che_주민선정` | 주민 선정 | 없음 | 1턴 |
|
||||
| `che_정착장려` | 정착 장려 | 없음 | 1턴 |
|
||||
| `che_농지개간` | 농지 개간 | 없음 | 1턴 |
|
||||
| `che_상업투자` | 상업 투자 | 없음 | 1턴 |
|
||||
| `che_기술연구` | 기술 연구 | 없음 | 1턴 |
|
||||
| `che_치안강화` | 치안 강화 | 없음 | 1턴 |
|
||||
| `che_수비강화` | 수비 강화 | 없음 | 1턴 |
|
||||
| `che_성벽보수` | 성벽 보수 | 없음 | 1턴 |
|
||||
| `che_징병` | 징병 | 필요 | 1턴 |
|
||||
| `che_물자조달` | 물자조달 | 없음 | 1턴 |
|
||||
| `che_헌납` | 헌납 | 필요 | 1턴 |
|
||||
|
||||
### 계략
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| ---------- | --------- | -------------- | -------------- |
|
||||
| `che_화계` | 화계 | 필요 | 1턴 |
|
||||
|
||||
### 특수
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| ------------- | --------- | -------------- | -------------- |
|
||||
| `che_NPC능동` | NPC능동 | 필요 | 1턴 |
|
||||
|
||||
## 국가 커맨드
|
||||
|
||||
등록된 명령은 35개입니다.
|
||||
|
||||
### 휴식
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| ------- | --------- | -------------- | -------------- |
|
||||
| `휴식` | 휴식 | 없음 | 1턴 |
|
||||
|
||||
### 인사
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| ------------------ | -------------- | -------------- | -------------- |
|
||||
| `che_포상` | 포상 | 필요 | 1턴 |
|
||||
| `che_부대탈퇴지시` | 부대 탈퇴 지시 | 필요 | 1턴 |
|
||||
| `che_발령` | 발령 | 필요 | 1턴 |
|
||||
| `che_몰수` | 몰수 | 필요 | 1턴 |
|
||||
|
||||
### 외교
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| -------------------- | ---------------- | -------------- | -------------- |
|
||||
| `che_선전포고` | 선전포고 | 필요 | 1턴 |
|
||||
| `che_종전제의` | 종전 제의 | 필요 | 1턴 |
|
||||
| `che_불가침제의` | 불가침 제의 | 필요 | 1턴 |
|
||||
| `che_불가침파기제의` | 불가침 파기 제의 | 필요 | 1턴 |
|
||||
| `che_이호경식` | 이호경식 | 필요 | 1턴 |
|
||||
| `che_급습` | 급습 | 필요 | 1턴 |
|
||||
| `che_물자원조` | 원조 | 필요 | 1턴 |
|
||||
|
||||
### 전략
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| -------------- | --------- | -------------- | -------------- |
|
||||
| `che_의병모집` | 의병모집 | 없음 | 1턴 |
|
||||
| `che_허보` | 허보 | 필요 | 1턴 |
|
||||
| `che_필사즉생` | 필사즉생 | 없음 | 1턴 |
|
||||
| `che_백성동원` | 백성동원 | 필요 | 1턴 |
|
||||
| `che_수몰` | 수몰 | 필요 | 1턴 |
|
||||
| `che_피장파장` | 피장파장 | 필요 | 1턴 |
|
||||
|
||||
### 특수
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| -------------------- | ------------- | -------------- | -------------- |
|
||||
| `che_초토화` | 초토화 | 필요 | 1턴 |
|
||||
| `cr_인구이동` | 인구이동 | 필요 | 1턴 |
|
||||
| `event_원융노병연구` | 원융노병 연구 | 없음 | 24턴 연속 실행 |
|
||||
| `event_화시병연구` | 화시병 연구 | 없음 | 12턴 연속 실행 |
|
||||
| `event_음귀병연구` | 음귀병 연구 | 없음 | 12턴 연속 실행 |
|
||||
| `event_대검병연구` | 대검병 연구 | 없음 | 12턴 연속 실행 |
|
||||
| `event_화륜차연구` | 화륜차 연구 | 없음 | 24턴 연속 실행 |
|
||||
| `event_산저병연구` | 산저병 연구 | 없음 | 12턴 연속 실행 |
|
||||
| `event_극병연구` | 극병 연구 | 없음 | 24턴 연속 실행 |
|
||||
| `event_상병연구` | 상병 연구 | 없음 | 24턴 연속 실행 |
|
||||
| `event_무희연구` | 무희 연구 | 없음 | 24턴 연속 실행 |
|
||||
|
||||
### 국가
|
||||
|
||||
| 내부 키 | 화면 이름 | 대상·수량 입력 | 기본 실행 단위 |
|
||||
| -------------------- | ---------------- | -------------- | -------------- |
|
||||
| `che_천도` | 천도 | 필요 | 1턴 |
|
||||
| `che_국호변경` | 국호변경 | 필요 | 1턴 |
|
||||
| `che_무작위수도이전` | 무작위 수도 이전 | 없음 | 1턴 |
|
||||
| `che_국기변경` | 국기변경 | 필요 | 1턴 |
|
||||
| `che_증축` | 증축 | 없음 | 1턴 |
|
||||
| `che_감축` | 감축 | 없음 | 1턴 |
|
||||
|
||||
## 생성 근거
|
||||
|
||||
- 등록 순서: `packages/logic/src/actions/turn/general/index.ts`,
|
||||
`packages/logic/src/actions/turn/nation/index.ts`
|
||||
- 표시명·분류·입력 여부·다중 턴: 각 명령 모듈의 `commandSpec`과 `ActionDefinition`
|
||||
- 생성 명령: `pnpm docs:generate`
|
||||
@@ -0,0 +1,98 @@
|
||||
# 커맨드와 실행 시기
|
||||
|
||||
## 화면의 상태 표시
|
||||
|
||||
서버는 내 장수, 도시, 국가와 현재 시점으로 각 커맨드를 사전 평가합니다.
|
||||
|
||||
| 표시 | 의미 |
|
||||
| -------------- | ----------------------------------------------------------------------------- |
|
||||
| 사용 가능 | 현재 알려진 조건을 만족합니다. 실행 시 다시 검사합니다. |
|
||||
| 대상 선택 필요 | 도시·장수·국가·수량 같은 입력을 고르면 판정할 수 있습니다. |
|
||||
| 사용 불가 | 현재 확정된 조건을 만족하지 않으며 이유가 함께 표시됩니다. |
|
||||
| 정보 부족 | 사전 화면에 없는 실행 context가 필요합니다. 실제 실행 성공을 뜻하지 않습니다. |
|
||||
|
||||
전체 key와 화면 이름은 [자동 생성 커맨드 목록](./command-catalog.generated.md)에 있습니다.
|
||||
|
||||
## 시기별로 보는 장수 커맨드
|
||||
|
||||
### 재야·방랑 상태
|
||||
|
||||
임관, 무작위 임관, 장수를 따라 임관, 거병, 건국 계열이 중심입니다. 서버의 가입 방식이 “무작위 임관만”
|
||||
이면 직접 국가를 고르는 임관·등용장 수락은 막힙니다. 초반에는 국가별 인원 제한과 건국 가능 도시·시점도
|
||||
적용될 수 있습니다.
|
||||
|
||||
### 국가 소속·도시 주둔
|
||||
|
||||
농지 개간, 상업 투자, 치안 강화, 수비 강화, 성벽 보수, 정착 장려, 기술 연구, 헌납처럼 도시·국가를
|
||||
전제로 한 내정 커맨드를 사용할 수 있습니다. 대부분은 다음을 함께 검사합니다.
|
||||
|
||||
- 재야나 방랑 국가가 아닌지
|
||||
- 내 장수가 실제 소속 도시를 점유하고 있는지
|
||||
- 해당 도시가 보급 상태인지
|
||||
- 목표 내정치가 이미 최대인지
|
||||
- 필요한 금·쌀과 능력·병력이 있는지
|
||||
|
||||
### 병력이 있을 때
|
||||
|
||||
훈련, 사기 진작, 단련, 전투 태세, 숙련 전환, 이동·집합·귀환, 출병을 검토할 수 있습니다. 출병은 병력과
|
||||
군량뿐 아니라 인접·경로, 대상 도시, 외교 관계, 보호 기간과 병종 조건을 실행 시점에 다시 확인합니다.
|
||||
|
||||
### 대상이 필요한 행동
|
||||
|
||||
등용, 증여, 첩보, 화계, 파괴, 선동, 탈취, 이동·출병 등은 대상이나 수량을 선택해야 합니다. 목록에 대상을
|
||||
고를 수 없으면 이미 사라졌거나 현재 권한·공개 범위에서 선택할 수 없는 경우일 수 있습니다.
|
||||
|
||||
### 국가 이탈·신분 변경
|
||||
|
||||
하야, 은퇴, 방랑, 선양, 모반 시도, 해산은 장수 또는 국가의 소속과 생애 상태를 크게 바꿉니다. 군주인지,
|
||||
국가가 방랑 상태인지, 건국 직후인지, 후계 대상이 유효한지 같은 추가 조건이 있습니다. 로그와 확인 문구를
|
||||
읽고 가까운 후속 예턴도 함께 점검해 주세요.
|
||||
|
||||
## 시기별로 보는 국가 커맨드
|
||||
|
||||
국가 예턴은 국가 운영 권한이 있을 때 보입니다. 많은 국가 명령은 군주만 실행할 수 있고, 일부 화면 운영
|
||||
기능은 직책별 권한을 따릅니다.
|
||||
|
||||
### 상시 국가 운영
|
||||
|
||||
포상, 발령, 부대 탈퇴 지시, 몰수, 물자 원조, 국호·국기 변경, 천도, 증축·감축, 인구 이동 등이 있습니다.
|
||||
국고·군량, 수도와 대상 도시, 장수·직책, 보급과 도시 규모 조건을 확인합니다.
|
||||
|
||||
### 외교 상태에 따른 명령
|
||||
|
||||
선전포고는 기본 구현에서 scenario 시작 연도보다 적어도 1년 지난 뒤에 허용되며, 대상 국가와의 상태도
|
||||
맞아야 합니다. 종전·불가침·불가침 파기 제안은 현재 외교 관계와 최소 기간을 검사합니다. 상대가 제안을
|
||||
수락하는 즉시 행동은 일반 예약 국가 턴과 별도의 승인 흐름으로 처리됩니다.
|
||||
|
||||
### 전략 커맨드
|
||||
|
||||
의병 모집, 허보, 필사즉생, 백성 동원, 이호경식, 수몰, 급습, 피장파장, 초토화는 군주 여부와 전략 커맨드
|
||||
재사용 가능 상태를 검사합니다. 명령마다 대상 도시·국가, 교전, 수도, 자원과 추가 상태가 다릅니다.
|
||||
초반 보호 기간에는 의병 모집·몰수 등 일부 행동이 제한됩니다.
|
||||
|
||||
### 특수 병종 연구
|
||||
|
||||
`event_*연구` 명령은 scenario가 해당 명령을 profile에 넣고 필요한 연구 flag가 아직 없을 때 사용할 수
|
||||
있습니다. 군주와 국고 조건을 검사하며 11턴 또는 23턴을 연속으로 쌓은 뒤 비용을 지불하고 병종 사용
|
||||
권한을 얻습니다. 소스의 선행 턴 값 11·23은 완료 턴을 포함하지 않으므로 화면에서 필요한 전체 실행은
|
||||
각각 12턴·24턴입니다.
|
||||
|
||||
## 보호 기간과 연도
|
||||
|
||||
scenario의 `startYear`와 `openingPartYear`가 초반 제한의 기준입니다. 다음은 대표적인 동작이며 서버별
|
||||
상수에 따라 실제 연도가 달라집니다.
|
||||
|
||||
- 출병은 예약 사전 판단과 실제 실행 모두 보호 기간을 고려합니다.
|
||||
- 방랑, 의병 모집, 몰수 같은 일부 국가 변화도 초반에는 제한됩니다.
|
||||
- 기술 연구의 허용 기술 단계와 임관 인원 제한은 경과 연도에 따라 넓어질 수 있습니다.
|
||||
- 선전포고는 시작 직후가 아니라 상대 연도 1 이상에서 가능합니다.
|
||||
|
||||
“몇 년 몇 월부터”를 고정 문구로 외우기보다 현재 서버의 시작 연도와 화면의 불가 이유를 확인해 주세요.
|
||||
|
||||
## 실패했을 때
|
||||
|
||||
1. 메인 로그에서 실패 이유를 확인합니다.
|
||||
2. 자원·병력, 소속 도시와 보급, 직책, 대상과 외교 상태를 다시 확인합니다.
|
||||
3. 여러 턴 뒤 실행될 명령이면 앞선 예턴이 상태를 바꾸는지 살펴봅니다.
|
||||
4. command table을 새로 불러와 대상 목록과 가능 상태를 갱신합니다.
|
||||
5. 동일 요청을 반복 전송하지 말고 화면이 최신 revision을 받은 뒤 다시 저장해 주세요.
|
||||
@@ -0,0 +1,37 @@
|
||||
# 플레이어 가이드
|
||||
|
||||
core2026에서는 지금 누르는 버튼이 즉시 모든 결과를 만드는 것이 아니라, 많은 행동을 **예턴**에 넣고 내
|
||||
장수의 다음 턴에 실행합니다. 국가 커맨드도 같은 방식이지만 군주·직책과 국가 상태에 따라 이용 범위가
|
||||
달라집니다.
|
||||
|
||||
## 처음 접속했을 때
|
||||
|
||||
1. Gateway에서 로그인하고 열려 있는 서버 profile을 선택합니다.
|
||||
2. 게임에 장수가 없다면 장수 생성·참가 화면에서 이름, 능력치 등 필요한 정보를 정합니다.
|
||||
3. 메인 화면에서 현재 도시·국가·자원·다음 턴 시각을 확인합니다.
|
||||
4. 예턴 목록의 가까운 순서부터 실행할 커맨드를 지정합니다.
|
||||
5. 국가에 소속됐다면 국가 정보·도시·장수·외교 화면에서 상황을 확인합니다.
|
||||
|
||||
서버마다 scenario, 시작 연도, 턴 간격, 가입 방식, map, 병종과 허용 커맨드가 다를 수 있습니다. 이 문서는
|
||||
기본 구현을 설명하며 현재 화면의 가능/불가 표시와 운영 공지를 우선해 주세요.
|
||||
|
||||
## 어디서 무엇을 하나요?
|
||||
|
||||
| 메뉴 | 용도 |
|
||||
| -------------------------- | ---------------------------------------------- |
|
||||
| 메인 | 장수·국가 예턴, 현재 상태, 최근 기록 |
|
||||
| 현재 도시·국가 정보 | 도시 내정치·보급·전선, 국가 자원·기술 |
|
||||
| 국가 장수·인사 | 소속 장수와 직책, 권한이 있으면 인사·방침 설정 |
|
||||
| 외교 | 국가 관계와 제안·교전 상태 확인 |
|
||||
| 부대 | 부대 생성·가입·관리 |
|
||||
| 경매·토너먼트·베팅 | 해당 기간에 열린 참가·입찰·예측 기능 |
|
||||
| 게시판·메시지 | 공개/국가 소통과 개인 메시지 |
|
||||
| 연감·명장·왕조·과거 플레이 | 현재·과거 기록 열람 |
|
||||
| 내 정보·설정 | 표시·알림 등 개인 설정 |
|
||||
|
||||
## 다음에 읽을 문서
|
||||
|
||||
- 예턴이 언제 실행되는지: [시간과 턴](./time-and-turns.md)
|
||||
- 어떤 조건에서 커맨드를 쓸 수 있는지: [커맨드와 실행 시기](./commands-and-timing.md)
|
||||
- 현재 소스에 등록된 전체 목록: [커맨드 전체 목록](./command-catalog.generated.md)
|
||||
- 국가 직책과 부가 기능: [국가 운영과 주요 기능](./nation-and-features.md)
|
||||
@@ -0,0 +1,64 @@
|
||||
# 국가 운영과 주요 기능
|
||||
|
||||
## 국가 직책과 정보 공개
|
||||
|
||||
국가에 소속됐다고 모든 국가 기능을 바꿀 수 있는 것은 아닙니다. 군주와 직책별 권한이 국가 예턴, 인사,
|
||||
전략·재정 설정, 비밀 장수 정보와 정찰 차단 같은 기능에 적용됩니다. 같은 국가 장수에게만 보이는 정보도
|
||||
있고, 공개 목록에는 일부 값이 가려질 수 있습니다.
|
||||
|
||||
내가 직접 URL이나 장수 번호를 입력해도 권한은 늘어나지 않습니다. 서버가 로그인 session에서 내 장수를
|
||||
찾아 국가·직책·대상 관계를 판단합니다.
|
||||
|
||||
## 국가 운영 화면
|
||||
|
||||
| 화면 | 할 수 있는 일 |
|
||||
| ----------- | --------------------------------------------- |
|
||||
| 국가 정보 | 국호·국기, 수도, 국고·군량, 기술과 공지 확인 |
|
||||
| 국가 도시 | 소유 도시의 내정·인구·방어·보급 상태 비교 |
|
||||
| 국가 장수 | 소속 장수의 공개 정보와 직책 확인 |
|
||||
| 인사 | 권한이 있으면 임명·해임, 추방, 봉록·권한 설정 |
|
||||
| 전략·재정 | 세율·전쟁 차단·비밀 제한 등 허용된 국가 설정 |
|
||||
| 비밀 장수 | 같은 국가 및 직책 권한에 맞춘 상세 정보 |
|
||||
| 전투 본부 | 전선·출병 판단에 필요한 국가 전투 정보 |
|
||||
| 정찰 메시지 | 정찰 관련 기록과 차단 상태 |
|
||||
|
||||
변경 버튼이 보이더라도 실행 전에 직책과 대상이 다시 검사됩니다. 권한이 바뀐 직후에는 화면을 새로 불러와
|
||||
주세요.
|
||||
|
||||
## 외교와 즉시 승인
|
||||
|
||||
선전포고 같은 일부 외교 행동은 국가 예턴으로 실행합니다. 종전·불가침·파기 제안은 제안 생성과 상대의
|
||||
수락이 나뉘며, 수락은 현재 관계와 권한을 다시 확인하는 즉시 action입니다. 제안 뒤 국가가 멸망하거나
|
||||
관계·직책이 바뀌면 수락할 수 없을 수 있습니다.
|
||||
|
||||
## 부대
|
||||
|
||||
부대 화면에서는 생성, 가입, 탈퇴와 권한이 있는 관리 기능을 사용합니다. 부대 상태는 장수 예턴과 국가
|
||||
발령·탈퇴 지시에도 영향을 받을 수 있습니다. 출병 전에 부대장·소속과 예약된 명령을 함께 확인해 주세요.
|
||||
|
||||
## 경매
|
||||
|
||||
경매는 열림·입찰·마감 단계가 있습니다. 입찰은 로그인한 내 장수와 자원을 기준으로 저장되고, 마감은 daemon
|
||||
worker가 낙찰과 정산을 확정합니다. 이미 마감됐거나 자원이 바뀌면 이전에 보던 화면의 입찰 가능 상태가
|
||||
유효하지 않을 수 있습니다.
|
||||
|
||||
## 토너먼트와 베팅
|
||||
|
||||
토너먼트는 등록·진행·종료와 보상 정산 lifecycle을 가집니다. 국가 베팅도 열림과 마감·정산 event가
|
||||
scenario 달력에 의해 발생합니다. 각 화면의 현재 상태와 마감 시각을 확인해 주세요. profile에서 event가
|
||||
열리지 않았다면 메뉴가 있어도 참여할 수 없습니다.
|
||||
|
||||
## 게시판·메시지
|
||||
|
||||
공개 글, 국가 범위 글, 개인 메시지는 서로 공개 범위가 다릅니다. 작성자·수신자·국가 관계와 운영 권한에
|
||||
따라 조회·수정 범위가 결정됩니다. 민감한 외교나 국가 정보를 공개 게시판에 적지 말아 주세요.
|
||||
|
||||
## 기록
|
||||
|
||||
- 연감은 월 경계의 world 상태를 보존합니다.
|
||||
- 명장·순위·왕조 화면은 현재 또는 종료된 시즌의 집계 데이터를 보여 줍니다.
|
||||
- 과거 플레이는 로그인한 사용자 소유 archive만 볼 수 있습니다.
|
||||
- 다른 사용자의 archive나 국가 비밀 정보는 URL을 바꿔도 공개되지 않습니다.
|
||||
|
||||
기록 화면의 값은 실시간 메인 상태와 갱신 시점이 다를 수 있습니다. 월 정산이나 시즌 종료 직후에는 해당
|
||||
기능의 최신 상태 표시를 함께 확인해 주세요.
|
||||
@@ -0,0 +1,52 @@
|
||||
# 시간과 턴
|
||||
|
||||
## 현실 시간과 게임 달력
|
||||
|
||||
서버는 profile의 턴 schedule에 따라 tick을 진행합니다. 한 tick마다 실행 시각이 된 장수의 명령을 처리하고,
|
||||
게임 달력이 다음 달로 넘어갈 경계에서는 월간 정산과 event도 처리합니다. 실제 턴 간격은 서버 설정에 따라
|
||||
달라지므로 메인 화면의 다음 턴 시각을 확인해 주세요.
|
||||
|
||||
게임 달력은 1월부터 12월까지 진행하고 12월 다음은 다음 해 1월입니다. 월이 바뀔 때 수입, 외교·전쟁 상태,
|
||||
도시·국가 상태, 연감, scenario event 같은 여러 처리가 정해진 순서로 일어납니다. 그러므로 같은 커맨드도
|
||||
월 변경 직전과 직후에 자원이나 조건이 달라질 수 있습니다.
|
||||
|
||||
## 예턴
|
||||
|
||||
- 장수 예턴은 최대 30칸입니다.
|
||||
- 국가 예턴은 최대 12칸입니다.
|
||||
- 위쪽에 가까운 명령부터 차례로 소비됩니다.
|
||||
- 대상 도시·장수·국가, 병종, 수량 등이 필요한 커맨드는 입력값까지 저장됩니다.
|
||||
- 비어 있는 칸과 실행 뒤 밀려난 끝 칸은 기본적으로 `휴식`으로 채워집니다.
|
||||
|
||||
여러 칸에 한꺼번에 같은 명령을 넣거나 예턴을 앞뒤로 이동할 수 있습니다. 다른 탭에서 먼저 수정하면 revision
|
||||
충돌이 날 수 있으므로 새 목록을 불러온 뒤 다시 적용해 주세요.
|
||||
|
||||
## 예약할 수 있어도 실행에 실패할 수 있습니다
|
||||
|
||||
예턴을 넣는 시점과 실제 실행 시점 사이에 다음 상태가 바뀔 수 있습니다.
|
||||
|
||||
- 가진 금·쌀과 병력
|
||||
- 도시의 소유 국가, 보급과 전선 상태
|
||||
- 내 소속 국가와 직책
|
||||
- 대상 장수·도시·국가의 존재와 외교 관계
|
||||
- 전쟁·불가침 기간과 전략 커맨드 재사용 상태
|
||||
- scenario 연도, 가입 방식, 기술 수준과 병종 개방
|
||||
|
||||
입력 화면은 현재 정보로 사전 판단하지만, 실제 턴에서는 전체 조건을 다시 확인합니다. 실패 이유는 명령
|
||||
로그에서 확인하고 다음 예턴을 조정해 주세요.
|
||||
|
||||
## 여러 턴이 필요한 행동
|
||||
|
||||
일부 커맨드는 한 칸에서 즉시 끝나지 않고 선행 턴을 쌓습니다. 진행 중 조건이 깨지거나 명령이 바뀌면 결과가
|
||||
달라질 수 있습니다. 현재 기본 목록에서는 국가의 특수 병종 연구가 12턴 또는 24턴의 연속 실행을 요구합니다.
|
||||
정확한 값은 [커맨드 전체 목록](./command-catalog.generated.md)의 “기본 실행 단위”에 표시됩니다.
|
||||
|
||||
## 월 변경 전 확인할 것
|
||||
|
||||
- 금·쌀이 필요한 예턴을 계속 감당할 수 있는지 확인해 주세요.
|
||||
- 공격·외교·전략 명령은 보호 기간, 교전 상태와 대상 도시가 그대로인지 확인해 주세요.
|
||||
- 국가 운영자는 국고·군량, 직책과 외교 제안의 만료·수락 상태를 확인해 주세요.
|
||||
- 경매·토너먼트·국가 베팅은 각 화면에 열린 기간과 마감 상태가 표시될 때만 입력해 주세요.
|
||||
|
||||
월간 event는 scenario resource가 결정하므로 모든 서버가 같은 월에 같은 event를 실행한다고 가정하지
|
||||
말아 주세요.
|
||||
Reference in New Issue
Block a user