Add storage-backed story history

This commit is contained in:
2026-05-15 21:58:30 +02:00
parent f2e786d5bc
commit 42582352d6
16 changed files with 1048 additions and 113 deletions
+36 -4
View File
@@ -9,7 +9,7 @@ class GameLoopModule extends BaseModule {
super('game-loop', 'Game Loop');
// Dependencies
this.dependencies = ['ui-controller', 'socket-client', 'text-buffer', 'sentence-queue', 'playback-coordinator', 'animation-queue', 'audio-manager', 'tts-factory', 'ui-input-handler'];
this.dependencies = ['ui-controller', 'socket-client', 'text-buffer', 'sentence-queue', 'playback-coordinator', 'animation-queue', 'audio-manager', 'tts-factory', 'ui-input-handler', 'story-history'];
// Game state
this.gameState = {
@@ -30,6 +30,7 @@ class GameLoopModule extends BaseModule {
'updateGameState',
'updateUIState',
'refreshGameApiState',
'hasSaveGame',
'requestStartGame',
'requestSaveGame',
'requestLoadGame',
@@ -136,7 +137,7 @@ class GameLoopModule extends BaseModule {
const [running, hasSave] = await Promise.all([
socketClient.isGameRunning(),
socketClient.hasSaveGame(1)
this.hasSaveGame(1)
]);
this.gameState.started = Boolean(running?.result);
@@ -191,6 +192,10 @@ class GameLoopModule extends BaseModule {
if (!socketClient) return;
await this.resetClientPlaybackAndDisplay();
const storyHistory = this.getModule('story-history');
if (storyHistory && typeof storyHistory.startNewGame === 'function') {
await storyHistory.startNewGame();
}
const response = await socketClient.newGame();
if (!response?.success) {
console.error('GameLoop: newGame failed', response);
@@ -211,6 +216,12 @@ class GameLoopModule extends BaseModule {
const response = await socketClient.saveGame(1);
if (response?.success) {
const storyHistory = this.getModule('story-history');
if (storyHistory && typeof storyHistory.saveSlot === 'function') {
await storyHistory.saveSlot(1, {
inkState: response.savedState || null
});
}
this.gameState.canLoad = true;
this.updateUIState();
}
@@ -223,7 +234,11 @@ class GameLoopModule extends BaseModule {
const socketClient = this.getModule('socket-client');
if (!socketClient) return;
const hasSave = await socketClient.hasSaveGame(1);
const storyHistory = this.getModule('story-history');
const browserSave = storyHistory && typeof storyHistory.loadSlot === 'function'
? await storyHistory.loadSlot(1)
: null;
const hasSave = browserSave ? { result: true } : await socketClient.hasSaveGame(1);
if (!hasSave?.result) {
this.gameState.canLoad = false;
this.updateUIState();
@@ -231,7 +246,14 @@ class GameLoopModule extends BaseModule {
}
await this.resetClientPlaybackAndDisplay();
const response = await socketClient.loadGame(1);
if (browserSave?.gameId && storyHistory?.setCurrentGame) {
storyHistory.setCurrentGame(browserSave.gameId, browserSave.latestBlockId || 0);
}
const uiController = this.getModule('ui-controller');
if (browserSave && uiController?.displayHandler?.restoreFromHistory) {
await uiController.displayHandler.restoreFromHistory(browserSave);
}
const response = await socketClient.loadGame(1, browserSave?.inkState || null);
if (response?.success) {
this.gameState.started = true;
this.gameState.canSave = true;
@@ -240,6 +262,16 @@ class GameLoopModule extends BaseModule {
}
}
async hasSaveGame(slot = 1) {
const storyHistory = this.getModule('story-history');
if (storyHistory && typeof storyHistory.hasSaveSlot === 'function') {
const hasBrowserSave = await storyHistory.hasSaveSlot(slot);
if (hasBrowserSave) return { success: true, result: true, slot };
}
const socketClient = this.getModule('socket-client');
return socketClient?.hasSaveGame ? socketClient.hasSaveGame(slot) : { success: false, result: false };
}
async resetClientPlaybackAndDisplay() {
const playbackCoordinator = this.getModule('playback-coordinator');
if (playbackCoordinator && typeof playbackCoordinator.stop === 'function') {