Some checks failed
CI / analyze-and-test (push) Has been cancelled
- README: 프로젝트 설명, 게임 시스템, 스탯 표 포함 재작성 - CLAUDE.md, ARCHITECTURE.md: PQ 참조 제거 - skill_data, pq_logic, game_state, game_mutations: 주석에서 PQ 언급 제거 - analysis/market-analysis: PQ 언급 제거
9.3 KiB
9.3 KiB
아키텍처
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 |
게임 원본 정적 데이터 (몬스터, 아이템, 주문 등) |
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 서비스 인터페이스
// 등록 (main.dart에서 1회 호출)
sl.registerLazySingleton<IIAPService>(() => IAPService.createInstance());
sl.registerLazySingleton<IAdService>(() => AdService.createInstance());
// 사용
final iap = sl<IIAPService>();
인터페이스를 통해 테스트 시 목(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틱 시뮬레이션하여 밸런스 변경 감지
실행
flutter test # 전체 실행
flutter test test/core/engine/ # 엔진 테스트만