diff --git a/src/client/LocalServer.ts b/src/client/LocalServer.ts index 4d7be1a1c..9910ce909 100644 --- a/src/client/LocalServer.ts +++ b/src/client/LocalServer.ts @@ -21,7 +21,7 @@ export class LocalServer { private turns: Turn[] = []; - private intents: Intent[] = []; + private intents: { intent: Intent; isServerSide: boolean }[] = []; private startedAt: number; private paused = false; @@ -96,11 +96,11 @@ export class LocalServer { if (clientMsg.intent.type === "troop_ratio") { // Store troop change events because otherwise they are // not registered when game is paused. - this.intents.push(clientMsg.intent); + this.intents.push({ intent: clientMsg.intent, isServerSide: false }); } return; } - this.intents.push(clientMsg.intent); + this.intents.push({ intent: clientMsg.intent, isServerSide: false }); } if (clientMsg.type === "hash") { if (!this.lobbyConfig.gameRecord) { @@ -154,7 +154,12 @@ export class LocalServer { this.endGame(); return; } - this.intents = this.replayTurns[this.turns.length].intents; + this.intents = this.replayTurns[this.turns.length].intents.map((i) => { + return { + intent: i.intent, + isServerSide: false, + }; + }); } const pastTurn: Turn = { turnNumber: this.turns.length, diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index fdb6b3f9c..7654b181a 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -323,7 +323,12 @@ const IntentSchema = z.union([ export const TurnSchema = z.object({ turnNumber: z.number(), - intents: z.array(IntentSchema), + intents: z.array( + z.object({ + intent: IntentSchema, + isServerSide: z.boolean(), + }), + ), // The hash of the game state at the end of the turn. hash: z.number().nullable().optional(), }); diff --git a/src/core/execution/ExecutionManager.ts b/src/core/execution/ExecutionManager.ts index db094ca3e..22032c68b 100644 --- a/src/core/execution/ExecutionManager.ts +++ b/src/core/execution/ExecutionManager.ts @@ -39,10 +39,10 @@ export class Executor { } createExecs(turn: Turn): Execution[] { - return turn.intents.map((i) => this.createExec(i)); + return turn.intents.map((i) => this.createExec(i.intent, i.isServerSide)); } - createExec(intent: Intent): Execution { + createExec(intent: Intent, isServerSide: boolean): Execution { const player = this.mg.playerByClientID(intent.clientID); if (!player) { console.warn(`player with clientID ${intent.clientID} not found`); @@ -122,7 +122,11 @@ export class Executor { intent.variables ?? {}, ); case "mark_disconnected": - return new MarkDisconnectedExecution(player, intent.isDisconnected); + if (isServerSide) { + return new MarkDisconnectedExecution(player, intent.isDisconnected); + } else { + return new NoOpExecution(); + } default: throw new Error(`intent type ${intent} not found`); } diff --git a/src/server/GameServer.ts b/src/server/GameServer.ts index 3bcf80ba7..8612c001e 100644 --- a/src/server/GameServer.ts +++ b/src/server/GameServer.ts @@ -38,7 +38,7 @@ export class GameServer { private disconnectedTimeout = 1 * 30 * 1000; // 30 seconds private turns: Turn[] = []; - private intents: Intent[] = []; + private intents: { intent: Intent; isServerSide: boolean }[] = []; public activeClients: Client[] = []; // Used for record record keeping private allClients: Map = new Map(); @@ -325,8 +325,8 @@ export class GameServer { }); } - private addIntent(intent: Intent) { - this.intents.push(intent); + private addIntent(intent: Intent, isServerSide: boolean = false) { + this.intents.push({ intent, isServerSide }); } private sendStartGameMsg(ws: WebSocket, lastTurn: number) { @@ -353,7 +353,12 @@ export class GameServer { private endTurn() { const pastTurn: Turn = { turnNumber: this.turns.length, - intents: this.intents, + intents: this.intents.map((i) => { + return { + intent: i.intent, + isServerSide: i.isServerSide, + }; + }), }; this.turns.push(pastTurn); this.intents = []; @@ -563,11 +568,14 @@ export class GameServer { private markClientDisconnected(client: Client, isDisconnected: boolean) { client.isDisconnected = isDisconnected; - this.addIntent({ - type: "mark_disconnected", - clientID: client.clientID, - isDisconnected: isDisconnected, - }); + this.addIntent( + { + type: "mark_disconnected", + clientID: client.clientID, + isDisconnected: isDisconnected, + }, + true, + ); } private archiveGame() {