diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..5dceb1c --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,239 @@ +# 아키텍처 + +Ascii Never Die의 시스템 설계 문서. + +## 계층 구조 + +``` +┌─────────────────────────────────────────────────┐ +│ Presentation │ +│ features/ (화면, 위젯, 컨트롤러) │ +│ front / new_character / game / arena / settings │ +├─────────────────────────────────────────────────┤ +│ Domain │ +│ core/engine/ (게임 로직 서비스) │ +│ core/model/ (데이터 모델) │ +├─────────────────────────────────────────────────┤ +│ Data │ +│ data/ (정적 게임 데이터) │ +│ core/storage/ (세이브/설정 저장소) │ +│ core/infrastructure/ (광고, IAP) │ +└─────────────────────────────────────────────────┘ + +의존 방향: Presentation → Domain → Data (역방향 금지) +``` + +## 핵심 데이터 흐름 + +``` +ProgressLoop (타이머) + │ + ▼ tickOnce() +ProgressService.tick() + │ + ├─→ CombatTickService (전투 틱 처리) + ├─→ LootHandler (전리품 처리) + ├─→ ExpHandler (경험치/레벨업) + ├─→ SkillService (스킬 진행) + ├─→ QuestCompletionHandler(퀘스트 완료) + ├─→ StoryService (스토리 진행) + └─→ GameMutations (상태 변경 적용) + │ + ▼ + GameState (Stream) + │ + ├─→ UI 갱신 (StreamBuilder) + └─→ SaveManager 자동 저장 +``` + +### 전투 사이클 + +``` +TaskGenerator.생성() → 몬스터 조우 + │ + ▼ +CombatTickService.처리() + ├─→ PlayerAttackProcessor (플레이어 공격) + ├─→ CombatCalculator (데미지 계산) + └─→ 결과 판정 + ├─ 승리 → LootHandler → ExpHandler → 다음 태스크 + └─ 패배 → DeathHandler → ResurrectionService +``` + +## 디렉토리별 책임 + +### `data/` -- 정적 게임 데이터 + +Config.dfm에서 추출한 종족, 직업, 스킬, 포션, 스토리 데이터. Dart const로 관리하며 런타임 변경 없음. + +| 파일 | 역할 | +|------|------| +| `pq_config_data.dart` | PQ 원본 데이터 (몬스터, 아이템, 주문 등) | +| `class_data.dart` | 직업 정의 + 특성 | +| `race_data.dart` | 종족 정의 + 특성 | +| `skill_data.dart` | 68개 스킬 정의 | +| `potion_data.dart` | 포션 데이터 | +| `story_data.dart` | 스토리/액트 데이터 | +| `game_text_l10n.dart` | 게임 텍스트 다국어 매핑 | + +### `core/engine/` -- 게임 로직 (30개 서비스) + +타이머 기반 메인 루프에서 호출되는 순수 게임 로직. UI 의존 없음. + +| 서비스 | 역할 | +|--------|------| +| `progress_loop.dart` | 타이머 기반 메인 루프 (틱 발행) | +| `progress_service.dart` | 틱 수신 → 서비스 오케스트레이션 | +| `combat_tick_service.dart` | 전투 틱 처리 | +| `combat_calculator.dart` | 데미지/방어/크리티컬 계산 | +| `player_attack_processor.dart` | 플레이어 공격 처리 | +| `death_handler.dart` | 사망 처리 | +| `resurrection_service.dart` | 부활 처리 | +| `loot_handler.dart` | 전리품 드롭 | +| `exp_handler.dart` | 경험치/레벨업 | +| `item_service.dart` | 아이템 생성/비교 | +| `shop_service.dart` | 상점 매매 | +| `market_service.dart` | 시장 거래 | +| `skill_service.dart` | 스킬 진행/레벨업 | +| `skill_auto_selector.dart` | 스킬 자동 선택 | +| `potion_service.dart` | 포션 수집/사용 | +| `quest_completion_handler.dart` | 퀘스트 완료 처리 | +| `story_service.dart` | 스토리/액트 진행 | +| `act_progression_service.dart` | 액트 전환 | +| `arena_service.dart` | 아레나 랭킹/매칭 | +| `arena_combat_simulator.dart` | 아레나 전투 시뮬레이션 | +| `chest_service.dart` | 보물상자 처리 | +| `reward_service.dart` | 보상 분배 | +| `return_rewards_service.dart` | 복귀 보상 계산 | +| `stat_calculator.dart` | 스탯 총합 계산 | +| `task_generator.dart` | 태스크(전투/이동/상점) 생성 | +| `game_mutations.dart` | GameState 변경 함수 | +| `character_roll_service.dart` | 캐릭터 스탯 롤 (3d6) | + +### `core/model/` -- 데이터 모델 + +freezed + json_serializable로 불변(immutable) 모델 생성. 직렬화/역직렬화 자동 처리. + +주요 모델: `GameState`, `SaveData`, `CombatStats`, `EquipmentItem`, `ItemStats`, `MonetizationState`, `SkillSystemState`, `ProgressState`, `HallOfFame` + +### `core/storage/` -- 저장 시스템 + +| 파일 | 역할 | +|------|------| +| `save_manager.dart` | 자동/수동 저장 관리 | +| `save_service.dart` | 세이브 슬롯 CRUD | +| `save_repository.dart` | 파일시스템 I/O | +| `save_integrity.dart` | HMAC-SHA256 무결성 검증 | +| `settings_repository.dart` | SharedPreferences 설정 | +| `hall_of_fame_storage.dart` | 명예의 전당 저장 | +| `statistics_storage.dart` | 통계 저장 | + +### `core/infrastructure/` -- 외부 서비스 + +| 파일 | 역할 | +|------|------| +| `ad_service.dart` | Google AdMob 래퍼 (IAdService 구현) | +| `iap_service.dart` | in_app_purchase 래퍼 (IIAPService 구현) | + +### `features/` -- 화면 (Presentation) + +각 화면은 독립된 디렉토리. controllers/managers/pages/widgets로 세분화. + +| 디렉토리 | 화면 | 구성 | +|----------|------|------| +| `front/` | 타이틀/세이브 선택 | 프론트 스크린, 세이브 피커 | +| `new_character/` | 캐릭터 생성 | 종족/직업 선택, 스탯 롤, 이름 입력 | +| `game/` | 메인 게임 | 7개 탭 페이지, 모바일/데스크톱 레이아웃 | +| `arena/` | 아레나 PvP | 셋업, 전투, 결과 | +| `hall_of_fame/` | 명예의 전당 | 영웅 목록, 상세 정보 | +| `settings/` | 설정 | 사운드, 언어, 계정 | + +### `shared/` -- 공용 컴포넌트 + +- `animation/` -- ASCII 아트 애니메이션 시스템 (Canvas 기반 렌더링, 캐릭터/몬스터/무기 프레임) +- `widgets/` -- 레트로 UI 위젯 (RetroButton, RetroPanel, RetroProgressBar, RetroDialog 등) +- `theme/` -- ASCII 컬러 팔레트, 레트로 테마 상수 + +## DI 구조 + +GetIt 서비스 로케이터 패턴으로 인터페이스 기반 의존성 주입. + +``` +core/di/ +├── service_locator.dart # GetIt 인스턴스 + 등록 +├── i_ad_service.dart # 광고 서비스 인터페이스 +└── i_iap_service.dart # IAP 서비스 인터페이스 +``` + +```dart +// 등록 (main.dart에서 1회 호출) +sl.registerLazySingleton(() => IAPService.createInstance()); +sl.registerLazySingleton(() => AdService.createInstance()); + +// 사용 +final iap = sl(); +``` + +인터페이스를 통해 테스트 시 목(mock) 교체 가능. + +## 수익화 시스템 + +### IAP (인앱결제) + +- 상품: `remove_ads_and` (광고 제거 + 프리미엄) +- 구매 상태: `flutter_secure_storage`에 암호화 저장 +- 영수증 검증: Google Play RSA 서명 로컬 검증 (`pointycastle`) +- 앱 재설치 시 자동 복원 지원 +- `MonetizationState` (freezed 모델)로 구매/광고 상태 통합 관리 + +### AdMob (광고) + +- 리워드 광고: 속도 부스트, 복귀 보상 2배 +- 인터스티셜 광고: 부활 시 +- IAP 구매자는 모든 광고 자동 비활성화 +- 릴리즈 빌드에서 치트 메뉴 완전 차단 (`kDebugMode` 가드) + +## 저장 시스템 + +### 세이브 파일 + +- JSON 직렬화 (`SaveData` → `json_serializable`) +- HMAC-SHA256 체크섬으로 무결성 검증 (`save_integrity.dart`) +- 파일시스템 기반 저장 (`path_provider`) +- 자동 저장: 레벨업, 퀘스트 완료, 주기적 타이머 + +### 설정 + +- `SharedPreferences`로 경량 설정 저장 (사운드, 언어 등) + +### 보안 저장 + +- IAP 구매 상태: `flutter_secure_storage` (플랫폼 키체인/키스토어) + +## 테스트 전략 + +``` +test/ +├── core/ +│ ├── engine/ # 게임 엔진 서비스 단위 테스트 (12개) +│ ├── model/ # 모델 직렬화/상태 테스트 (2개) +│ ├── storage/ # 저장소 테스트 (1개) +│ └── util/ # 유틸리티/밸런스 테스트 (3개) +├── features/ # 위젯/컨트롤러 테스트 (3개) +├── regression/ # 결정적 게임 시뮬레이션 회귀 테스트 (1개) +└── helpers/ # 목 팩토리, 테스트 셋업 +``` + +### 테스트 원칙 + +- **엔진 로직 우선**: 게임 엔진 서비스에 집중 (전투, 아이템, 스킬, 상점, 아레나, 포션, 복귀보상) +- **결정적 시뮬레이션**: `DeterministicRandom`으로 동일 시드 → 동일 결과 보장 +- **목 팩토리**: `test/helpers/mock_factories.dart`로 GameState, CombatStats 등 재사용 가능한 테스트 데이터 제공 +- **회귀 테스트**: 전체 게임 루프를 N틱 시뮬레이션하여 밸런스 변경 감지 + +### 실행 + +```bash +flutter test # 전체 실행 +flutter test test/core/engine/ # 엔진 테스트만 +``` diff --git a/README.md b/README.md index b2282da..8828683 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,103 @@ # Ascii Never Die -Offline Flutter rebuild of **Progress Quest 6.4** (single-player only). Network features are stripped; all game data and saves live locally. +Progress Quest 6.4의 핵심 메커니즘을 기반으로, "디지털 판타지" 세계관과 확장된 시스템으로 재구성한 오프라인 싱글플레이어 방치형 RPG. -## Layout -- `lib/src/features/front/` – temporary front screen shell to hang the upcoming flow on. -- `doc/progress-quest-flutter-plan.md` – working plan/notes for the port. -- `example/pq/` – original Delphi source/assets (reference only, not built). +## 스크린샷 + + +| 타이틀 | 캐릭터 생성 | 게임 진행 | +|--------|-------------|-----------| +| ![타이틀](docs/screenshots/front.png) | ![생성](docs/screenshots/new_character.png) | ![게임](docs/screenshots/game.png) | + +| 아레나 | 명예의 전당 | 설정 | +|--------|-------------|------| +| ![아레나](docs/screenshots/arena.png) | ![명예의 전당](docs/screenshots/hall_of_fame.png) | ![설정](docs/screenshots/settings.png) | + +## 주요 기능 + +- **6개 화면** -- 타이틀/세이브 선택, 캐릭터 생성(3d6 스탯 롤), 게임 진행(장비/인벤토리/퀘스트/스킬/전투로그/스토리), 아레나 PvP, 명예의 전당, 설정 +- **완전 오프라인** -- 네트워크 불필요. 모든 게임 데이터와 세이브가 로컬에 저장 +- **수익화** -- AdMob 리워드/인터스티셜 광고 + IAP 광고 제거/프리미엄 +- **다국어 지원** -- 한국어, 영어, 일본어 (앱 UI + 게임 데이터) +- **ASCII 아트 애니메이션** -- Canvas 기반 전투/탐험/마을 씬, 종족별 캐릭터 프레임 +- **보안** -- 세이브 파일 HMAC-SHA256 무결성 검증, IAP 영수증 RSA 서명 검증 + +## 기술 스택 + +| 구분 | 기술 | +|------|------| +| 프레임워크 | Flutter 3.x / Dart ^3.9.2 | +| 상태 관리 | Stream + 직접 관리 | +| 코드 생성 | freezed + json_serializable | +| DI | GetIt (서비스 로케이터) | +| 광고 | google_mobile_ads 7.x | +| 인앱결제 | in_app_purchase 3.x | +| 보안 저장 | flutter_secure_storage, crypto (HMAC), pointycastle (RSA) | +| 오디오 | just_audio | +| 폰트 | JetBrainsMono (ASCII), PressStart2P (레트로 UI) | + +## 빌드 및 실행 -## Run ```bash +# 의존성 설치 flutter pub get + +# 코드 생성 (freezed/json_serializable) +dart run build_runner build --delete-conflicting-outputs + +# 실행 (-d macos, -d chrome, -d android 등) flutter run -``` -Use any supported platform (`-d macos`, `-d chrome`, etc.); multi-platform scaffolding is enabled. - -## Checks -Run from repo root before handoff: - -```bash +# 검증 dart format --set-exit-if-changed . flutter analyze flutter test ``` + +## 프로젝트 구조 + +``` +lib/ +├── main.dart # 앱 진입점 +├── data/ # 정적 게임 데이터 (종족, 직업, 스킬, 포션, 스토리) +├── l10n/ # 앱 UI 다국어 리소스 (arb) +└── src/ + ├── app.dart # MaterialApp 설정 + ├── core/ + │ ├── engine/ # 게임 루프, 전투, 보상, 스킬 등 30개 서비스 + │ ├── model/ # GameState, 장비, 스킬, 전투 등 데이터 모델 + │ ├── infrastructure/ # AdMob, IAP 외부 서비스 구현 + │ ├── di/ # GetIt 서비스 로케이터 + 인터페이스 + │ ├── audio/ # BGM/SFX 오디오 서비스 + │ ├── storage/ # 세이브/설정/통계 저장소 + │ └── util/ # RNG, 밸런스 상수, PQ 로직 헬퍼 + ├── features/ + │ ├── front/ # 타이틀/세이브 선택 + │ ├── new_character/ # 캐릭터 생성 + │ ├── game/ # 메인 게임 (탭별 페이지 + 위젯) + │ ├── arena/ # 아레나 PvP + │ ├── hall_of_fame/ # 명예의 전당 + │ └── settings/ # 설정 + └── shared/ # 테마, 레트로 위젯, ASCII 애니메이션 + +example/pq/ # Delphi 원본 소스 (참조용) +test/ # 단위/위젯/회귀 테스트 (25개 파일) +``` + +아키텍처 상세는 [ARCHITECTURE.md](ARCHITECTURE.md) 참조. + +## 릴리즈 이력 + +| 버전 | 날짜 | 주요 내용 | +|------|------|-----------| +| 1.1.0 | 2026-03-30 | IAP RSA 검증, HMAC 세이브, CI, 테스트 105개 추가 | +| 1.0.1 | 2026-03-19 | 초기 릴리즈 (Google Play 내부 테스트) | + +전체 변경 이력은 [CHANGELOG.md](CHANGELOG.md) 참조. + +## 라이선스 + +비공개 프로젝트. 무단 배포 금지. + +Progress Quest 원본 소스(`example/pq/`)는 참조용으로만 포함되어 있습니다. +폰트 라이선스: JetBrains Mono (SIL OFL 1.1), Press Start 2P (SIL OFL 1.1).