Fix stale restore after game restart
This commit is contained in:
+16
-5
@@ -97,10 +97,18 @@ function getOrCreateEngine(socketId: string): InkEngine {
|
||||
return engine;
|
||||
}
|
||||
|
||||
function withClientRequestId<T extends object>(turn: T, requestId?: number): T {
|
||||
const id = Number(requestId || 0);
|
||||
return Number.isInteger(id) && id > 0
|
||||
? { ...turn, clientRequestId: id }
|
||||
: turn;
|
||||
}
|
||||
|
||||
async function handleGameApi(
|
||||
socket: ReturnType<SocketIOServer['sockets']['sockets']['get']> & { id: string },
|
||||
method: string,
|
||||
args: unknown[],
|
||||
requestId?: number,
|
||||
): Promise<object> {
|
||||
const slots = getSlots(socket.id);
|
||||
|
||||
@@ -109,7 +117,7 @@ async function handleGameApi(
|
||||
case 'newGame()': {
|
||||
const engine = new InkEngine(getStoryPath());
|
||||
sessions.set(socket.id, engine);
|
||||
socket.emit('narrativeResponse', engine.newGame());
|
||||
socket.emit('narrativeResponse', withClientRequestId(engine.newGame(), requestId));
|
||||
return {
|
||||
success: true,
|
||||
result: true,
|
||||
@@ -129,7 +137,7 @@ async function handleGameApi(
|
||||
if (!Number.isInteger(choiceIndex)) {
|
||||
return { success: false, error: 'invalid_choice', result: false };
|
||||
}
|
||||
socket.emit('narrativeResponse', engine.chooseChoice(choiceIndex));
|
||||
socket.emit('narrativeResponse', withClientRequestId(engine.chooseChoice(choiceIndex), requestId));
|
||||
return { success: true, result: true };
|
||||
}
|
||||
|
||||
@@ -141,8 +149,8 @@ async function handleGameApi(
|
||||
return { success: false, error: 'missing_save', result: false };
|
||||
}
|
||||
const engine = getOrCreateEngine(socket.id);
|
||||
socket.emit('narrativeResponse', engine.loadGame(browserSave || slots.get(slot)!));
|
||||
socket.emit('gameLoaded', { slot });
|
||||
socket.emit('narrativeResponse', withClientRequestId(engine.loadGame(browserSave || slots.get(slot)!), requestId));
|
||||
socket.emit('gameLoaded', { slot, clientRequestId: requestId });
|
||||
return { success: true, result: true, running: true, slot };
|
||||
}
|
||||
|
||||
@@ -206,7 +214,7 @@ io.on('connection', (socket) => {
|
||||
socket.on(
|
||||
'gameApi',
|
||||
async (
|
||||
request: { method?: string; args?: unknown[] },
|
||||
request: { method?: string; args?: unknown[]; requestId?: number },
|
||||
respond: (result: object) => void,
|
||||
) => {
|
||||
try {
|
||||
@@ -214,6 +222,9 @@ io.on('connection', (socket) => {
|
||||
socket as Parameters<typeof handleGameApi>[0],
|
||||
String(request?.method ?? ''),
|
||||
Array.isArray(request?.args) ? request.args : [],
|
||||
Number.isInteger(Number(request?.requestId)) && Number(request?.requestId) > 0
|
||||
? Number(request?.requestId)
|
||||
: undefined,
|
||||
);
|
||||
if (typeof respond === 'function') respond(result);
|
||||
} catch (error) {
|
||||
|
||||
+21
-8
@@ -87,7 +87,14 @@ function normalizeSaveSlot(slot: unknown): number {
|
||||
return Number.isInteger(value) && value > 0 ? value : 1;
|
||||
}
|
||||
|
||||
async function startDemoGameForSocket(socket: any): Promise<GameRunner> {
|
||||
function withClientRequestId<T extends object>(turn: T, requestId?: number): T {
|
||||
const id = Number(requestId || 0);
|
||||
return Number.isInteger(id) && id > 0
|
||||
? { ...turn, clientRequestId: id }
|
||||
: turn;
|
||||
}
|
||||
|
||||
async function startDemoGameForSocket(socket: any, requestId?: number): Promise<GameRunner> {
|
||||
nextTurnIds.set(socket.id, 1);
|
||||
const gameRunner = new GameRunner();
|
||||
const worldFile = projectPath(process.env.DEFAULT_WORLD_FILE || engineConfig.paths.mainGameFile);
|
||||
@@ -100,7 +107,7 @@ async function startDemoGameForSocket(socket: any): Promise<GameRunner> {
|
||||
...textToParagraphs(gameState.world.introduction),
|
||||
...textToParagraphs(gameRunner.getCurrentRoomDescription()),
|
||||
];
|
||||
socket.emit('narrativeResponse', {
|
||||
socket.emit('narrativeResponse', withClientRequestId({
|
||||
turnId: nextTurnId(socket.id),
|
||||
paragraphs,
|
||||
choices: [],
|
||||
@@ -108,19 +115,19 @@ async function startDemoGameForSocket(socket: any): Promise<GameRunner> {
|
||||
gameState: {
|
||||
currentRoomId: gameState.currentRoomId,
|
||||
},
|
||||
});
|
||||
}, requestId));
|
||||
|
||||
return gameRunner;
|
||||
}
|
||||
|
||||
async function handleGameApi(socket: any, method: string, args: unknown[] = []) {
|
||||
async function handleGameApi(socket: any, method: string, args: unknown[] = [], requestId?: number) {
|
||||
const saveGames: Map<number, any> = socket.data.saveGames || new Map<number, any>();
|
||||
socket.data.saveGames = saveGames;
|
||||
|
||||
switch (method) {
|
||||
case 'newGame':
|
||||
case 'newGame()':
|
||||
await startDemoGameForSocket(socket);
|
||||
await startDemoGameForSocket(socket, requestId);
|
||||
return { success: true, result: true, running: true, canLoad: saveGames.size > 0 };
|
||||
|
||||
case 'loadGame':
|
||||
@@ -129,8 +136,8 @@ async function handleGameApi(socket: any, method: string, args: unknown[] = [])
|
||||
if (!saveGames.has(slot)) {
|
||||
return { success: false, error: 'missing_save', result: false };
|
||||
}
|
||||
await startDemoGameForSocket(socket);
|
||||
socket.emit('gameLoaded', { slot });
|
||||
await startDemoGameForSocket(socket, requestId);
|
||||
socket.emit('gameLoaded', { slot, clientRequestId: requestId });
|
||||
return { success: true, result: true, running: true, slot };
|
||||
}
|
||||
|
||||
@@ -174,7 +181,13 @@ io.on('connection', (socket) => {
|
||||
|
||||
socket.on('gameApi', async (request, respond) => {
|
||||
try {
|
||||
const response = await handleGameApi(socket, String(request?.method || ''), Array.isArray(request?.args) ? request.args : []);
|
||||
const requestId = Number(request?.requestId || 0);
|
||||
const response = await handleGameApi(
|
||||
socket,
|
||||
String(request?.method || ''),
|
||||
Array.isArray(request?.args) ? request.args : [],
|
||||
Number.isInteger(requestId) && requestId > 0 ? requestId : undefined,
|
||||
);
|
||||
if (typeof respond === 'function') {
|
||||
respond(response);
|
||||
}
|
||||
|
||||
+15
-4
@@ -114,12 +114,20 @@ function getSlots(socketId: string): Map<number, string> {
|
||||
return slots;
|
||||
}
|
||||
|
||||
function withClientRequestId<T extends object>(turn: T, requestId?: number): T {
|
||||
const id = Number(requestId || 0);
|
||||
return Number.isInteger(id) && id > 0
|
||||
? { ...turn, clientRequestId: id }
|
||||
: turn;
|
||||
}
|
||||
|
||||
async function handleGameApi(
|
||||
socket: ReturnType<SocketIOServer['sockets']['sockets']['get']> & {
|
||||
id: string;
|
||||
},
|
||||
method: string,
|
||||
args: unknown[],
|
||||
requestId?: number,
|
||||
): Promise<object> {
|
||||
const slots = getSlots(socket.id);
|
||||
debugLog(`gameApi request from ${socket.id}: ${method}`, { args });
|
||||
@@ -129,7 +137,7 @@ async function handleGameApi(
|
||||
case 'newGame()': {
|
||||
const engine = getOrCreateEngine(socket.id);
|
||||
const turn = await engine.newGame();
|
||||
socket.emit('narrativeResponse', toClientTurn(turn));
|
||||
socket.emit('narrativeResponse', withClientRequestId(toClientTurn(turn), requestId));
|
||||
return {
|
||||
success: true,
|
||||
result: true,
|
||||
@@ -146,8 +154,8 @@ async function handleGameApi(
|
||||
}
|
||||
const engine = getOrCreateEngine(socket.id);
|
||||
const turn = await engine.loadGame(slots.get(slot)!);
|
||||
socket.emit('narrativeResponse', toClientTurn(turn));
|
||||
socket.emit('gameLoaded', { slot });
|
||||
socket.emit('narrativeResponse', withClientRequestId(toClientTurn(turn), requestId));
|
||||
socket.emit('gameLoaded', { slot, clientRequestId: requestId });
|
||||
return { success: true, result: true, running: true, slot };
|
||||
}
|
||||
|
||||
@@ -236,7 +244,7 @@ io.on('connection', (socket) => {
|
||||
socket.on(
|
||||
'gameApi',
|
||||
async (
|
||||
request: { method?: string; args?: unknown[] },
|
||||
request: { method?: string; args?: unknown[]; requestId?: number },
|
||||
respond: (result: object) => void,
|
||||
) => {
|
||||
try {
|
||||
@@ -244,6 +252,9 @@ io.on('connection', (socket) => {
|
||||
socket as Parameters<typeof handleGameApi>[0],
|
||||
String(request?.method ?? ''),
|
||||
Array.isArray(request?.args) ? request.args : [],
|
||||
Number.isInteger(Number(request?.requestId)) && Number(request?.requestId) > 0
|
||||
? Number(request?.requestId)
|
||||
: undefined,
|
||||
);
|
||||
debugLog(`gameApi response to ${socket.id}`, result);
|
||||
if (typeof respond === 'function') respond(result);
|
||||
|
||||
Reference in New Issue
Block a user