import 'dart:async'; import 'package:askiineverdie/src/core/engine/progress_loop.dart'; import 'package:askiineverdie/src/core/engine/progress_service.dart'; import 'package:askiineverdie/src/core/engine/resurrection_service.dart'; import 'package:askiineverdie/src/core/engine/shop_service.dart'; import 'package:askiineverdie/src/core/model/game_state.dart'; import 'package:askiineverdie/src/core/storage/save_manager.dart'; import 'package:flutter/foundation.dart'; enum GameSessionStatus { idle, loading, running, error, dead } /// Presentation-friendly wrapper that owns ProgressLoop and SaveManager. class GameSessionController extends ChangeNotifier { GameSessionController({ required this.progressService, required this.saveManager, this.autoSaveConfig = const AutoSaveConfig(), Duration tickInterval = const Duration(milliseconds: 50), DateTime Function()? now, }) : _tickInterval = tickInterval, _now = now ?? DateTime.now; final ProgressService progressService; final SaveManager saveManager; final AutoSaveConfig autoSaveConfig; final Duration _tickInterval; final DateTime Function() _now; ProgressLoop? _loop; StreamSubscription? _subscription; bool _cheatsEnabled = false; GameSessionStatus _status = GameSessionStatus.idle; GameState? _state; String? _error; GameSessionStatus get status => _status; GameState? get state => _state; String? get error => _error; bool get isRunning => _status == GameSessionStatus.running; bool get cheatsEnabled => _cheatsEnabled; /// 현재 ProgressLoop 인스턴스 (치트 기능용) ProgressLoop? get loop => _loop; Future startNew( GameState initialState, { bool cheatsEnabled = false, bool isNewGame = true, }) async { await _stopLoop(saveOnStop: false); // 새 게임인 경우 초기화 (프롤로그 태스크 설정) final state = isNewGame ? progressService.initializeNewGame(initialState) : initialState; _state = state; _error = null; _status = GameSessionStatus.running; _cheatsEnabled = cheatsEnabled; _loop = ProgressLoop( initialState: state, progressService: progressService, saveManager: saveManager, autoSaveConfig: autoSaveConfig, tickInterval: _tickInterval, now: _now, cheatsEnabled: cheatsEnabled, onPlayerDied: _onPlayerDied, ); _subscription = _loop!.stream.listen((next) { _state = next; notifyListeners(); }); _loop!.start(); notifyListeners(); } Future loadAndStart({ String? fileName, bool cheatsEnabled = false, }) async { _status = GameSessionStatus.loading; _error = null; notifyListeners(); final (outcome, loaded) = await saveManager.loadState(fileName: fileName); if (!outcome.success || loaded == null) { _status = GameSessionStatus.error; _error = outcome.error ?? 'Unknown error'; notifyListeners(); return; } await startNew(loaded, cheatsEnabled: cheatsEnabled, isNewGame: false); } Future pause({bool saveOnStop = false}) async { await _stopLoop(saveOnStop: saveOnStop); _status = GameSessionStatus.idle; notifyListeners(); } /// 일시 정지 상태에서 재개 Future resume() async { if (_state == null || _status != GameSessionStatus.idle) return; await startNew(_state!, cheatsEnabled: _cheatsEnabled, isNewGame: false); } /// 일시 정지/재개 토글 Future togglePause() async { if (isRunning) { await pause(saveOnStop: true); } else if (_state != null && _status == GameSessionStatus.idle) { await resume(); } } @override void dispose() { final stop = _stopLoop(saveOnStop: false); if (stop != null) { unawaited(stop); } super.dispose(); } Future? _stopLoop({required bool saveOnStop}) { final loop = _loop; final sub = _subscription; _loop = null; _subscription = null; sub?.cancel(); if (loop == null) return null; return loop.stop(saveOnStop: saveOnStop); } // ============================================================================ // Phase 4: 사망/부활 처리 // ============================================================================ /// 플레이어 사망 콜백 (ProgressLoop에서 호출) void _onPlayerDied() { _status = GameSessionStatus.dead; notifyListeners(); } /// 플레이어 부활 처리 /// /// HP/MP 회복, 빈 슬롯에 장비 자동 구매, 게임 재개 Future resurrect() async { if (_state == null || !_state!.isDead) return; // ResurrectionService를 사용하여 부활 처리 final shopService = ShopService(rng: _state!.rng); final resurrectionService = ResurrectionService(shopService: shopService); final resurrectedState = resurrectionService.processResurrection(_state!); // 저장 await saveManager.saveState(resurrectedState); // 게임 재개 await startNew(resurrectedState, cheatsEnabled: _cheatsEnabled, isNewGame: false); } /// 사망 상태 여부 bool get isDead => _status == GameSessionStatus.dead || (_state?.isDead ?? false); }