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
+17 -2
View File
@@ -109,12 +109,27 @@ export class InkEngine {
if (!this.story) {
throw new Error('No active Ink story to save');
}
return this.story.state.toJson();
return JSON.stringify({
inkState: this.story.state.toJson(),
nextTurnId: this.nextTurnId,
});
}
loadGame(savedState: string): TurnResult {
this.story = this.loadStory();
this.story.state.LoadJson(savedState);
let inkState = savedState;
try {
const parsed = JSON.parse(savedState);
if (parsed && typeof parsed.inkState === 'string') {
inkState = parsed.inkState;
if (Number.isInteger(parsed.nextTurnId)) {
this.nextTurnId = Math.max(1, parsed.nextTurnId);
}
}
} catch {
// Backward compatibility with raw Ink state JSON.
}
this.story.state.LoadJson(inkState);
return this.continueStory();
}
+6 -4
View File
@@ -130,11 +130,12 @@ async function handleGameApi(
case 'loadGame':
case 'loadGame()': {
const slot = normalizeSaveSlot(args[0]);
if (!slots.has(slot)) {
const browserSave = typeof args[1] === 'string' ? args[1] : null;
if (!browserSave && !slots.has(slot)) {
return { success: false, error: 'missing_save', result: false };
}
const engine = getOrCreateEngine(socket.id);
socket.emit('narrativeResponse', engine.loadGame(slots.get(slot)!));
socket.emit('narrativeResponse', engine.loadGame(browserSave || slots.get(slot)!));
socket.emit('gameLoaded', { slot });
return { success: true, result: true, running: true, slot };
}
@@ -146,9 +147,10 @@ async function handleGameApi(
return { success: false, error: 'game_not_running', result: false };
}
const slot = normalizeSaveSlot(args[0]);
slots.set(slot, engine.saveGame());
const savedState = engine.saveGame();
slots.set(slot, savedState);
socket.emit('gameSaved', { slot });
return { success: true, result: true, slot };
return { success: true, result: true, slot, savedState };
}
case 'hasSaveGame':