feat: 초기 커밋
- Progress Quest 6.4 Flutter 포팅 프로젝트 - 게임 루프, 상태 관리, UI 구현 - 캐릭터 생성, 인벤토리, 장비, 주문 시스템 - 시장/판매/구매 메커니즘
This commit is contained in:
138
lib/src/core/engine/progress_loop.dart
Normal file
138
lib/src/core/engine/progress_loop.dart
Normal file
@@ -0,0 +1,138 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:askiineverdie/src/core/model/game_state.dart';
|
||||
import 'package:askiineverdie/src/core/storage/save_manager.dart';
|
||||
import 'package:askiineverdie/src/core/engine/progress_service.dart';
|
||||
|
||||
class AutoSaveConfig {
|
||||
const AutoSaveConfig({
|
||||
this.onLevelUp = true,
|
||||
this.onQuestComplete = true,
|
||||
this.onActComplete = true,
|
||||
this.onStop = true,
|
||||
});
|
||||
|
||||
final bool onLevelUp;
|
||||
final bool onQuestComplete;
|
||||
final bool onActComplete;
|
||||
final bool onStop;
|
||||
|
||||
bool shouldSave(ProgressTickResult result) {
|
||||
return (onLevelUp && result.leveledUp) ||
|
||||
(onQuestComplete && result.completedQuest) ||
|
||||
(onActComplete && result.completedAct);
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the periodic timer loop that advances tasks/quests/plots.
|
||||
class ProgressLoop {
|
||||
ProgressLoop({
|
||||
required GameState initialState,
|
||||
required this.progressService,
|
||||
this.saveManager,
|
||||
Duration tickInterval = const Duration(milliseconds: 50),
|
||||
AutoSaveConfig autoSaveConfig = const AutoSaveConfig(),
|
||||
DateTime Function()? now,
|
||||
this.cheatsEnabled = false,
|
||||
}) : _state = initialState,
|
||||
_tickInterval = tickInterval,
|
||||
_autoSaveConfig = autoSaveConfig,
|
||||
_now = now ?? DateTime.now,
|
||||
_stateController = StreamController<GameState>.broadcast();
|
||||
|
||||
final ProgressService progressService;
|
||||
final SaveManager? saveManager;
|
||||
final Duration _tickInterval;
|
||||
final AutoSaveConfig _autoSaveConfig;
|
||||
final DateTime Function() _now;
|
||||
final StreamController<GameState> _stateController;
|
||||
bool cheatsEnabled;
|
||||
|
||||
Timer? _timer;
|
||||
int? _lastTickMs;
|
||||
int _speedMultiplier = 1;
|
||||
|
||||
GameState get current => _state;
|
||||
Stream<GameState> get stream => _stateController.stream;
|
||||
GameState _state;
|
||||
|
||||
/// 현재 배속 (1x, 2x, 5x)
|
||||
int get speedMultiplier => _speedMultiplier;
|
||||
|
||||
/// 배속 순환: 1 -> 2 -> 5 -> 1
|
||||
void cycleSpeed() {
|
||||
_speedMultiplier = switch (_speedMultiplier) {
|
||||
1 => 2,
|
||||
2 => 5,
|
||||
_ => 1,
|
||||
};
|
||||
}
|
||||
|
||||
void start() {
|
||||
_lastTickMs = _now().millisecondsSinceEpoch;
|
||||
_timer ??= Timer.periodic(_tickInterval, (_) => tickOnce());
|
||||
}
|
||||
|
||||
Future<void> stop({bool saveOnStop = false}) async {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
if (saveOnStop && _autoSaveConfig.onStop && saveManager != null) {
|
||||
await saveManager!.saveState(_state);
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
_stateController.close();
|
||||
}
|
||||
|
||||
/// Run one iteration of the loop (used by Timer or manual stepping).
|
||||
GameState tickOnce({int? deltaMillis}) {
|
||||
final baseDelta = deltaMillis ?? _computeDelta();
|
||||
final delta = baseDelta * _speedMultiplier;
|
||||
final result = progressService.tick(_state, delta);
|
||||
_state = result.state;
|
||||
_stateController.add(_state);
|
||||
|
||||
if (saveManager != null && _autoSaveConfig.shouldSave(result)) {
|
||||
saveManager!.saveState(_state);
|
||||
}
|
||||
return _state;
|
||||
}
|
||||
|
||||
/// Replace state (e.g., after loading) and reset timing.
|
||||
void replaceState(GameState newState) {
|
||||
_state = newState;
|
||||
_stateController.add(newState);
|
||||
_lastTickMs = _now().millisecondsSinceEpoch;
|
||||
}
|
||||
|
||||
// Developer-only helpers mirroring original cheat panel actions.
|
||||
void cheatCompleteTask() {
|
||||
if (!cheatsEnabled) return;
|
||||
_state = progressService.forceTaskComplete(_state);
|
||||
_stateController.add(_state);
|
||||
}
|
||||
|
||||
void cheatCompleteQuest() {
|
||||
if (!cheatsEnabled) return;
|
||||
_state = progressService.forceQuestComplete(_state);
|
||||
_stateController.add(_state);
|
||||
}
|
||||
|
||||
void cheatCompletePlot() {
|
||||
if (!cheatsEnabled) return;
|
||||
_state = progressService.forcePlotComplete(_state);
|
||||
_stateController.add(_state);
|
||||
}
|
||||
|
||||
int _computeDelta() {
|
||||
final nowMs = _now().millisecondsSinceEpoch;
|
||||
final last = _lastTickMs;
|
||||
_lastTickMs = nowMs;
|
||||
if (last == null) return 0;
|
||||
final delta = nowMs - last;
|
||||
if (delta < 0) return 0;
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user