From 1e307fa50c3947a8ca0b8b63f7577692e39ba8ad Mon Sep 17 00:00:00 2001 From: Simon Lemieux <1105380+simlmx@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:54:02 +0000 Subject: [PATCH 1/4] Note default value when normalizing game settings --- games/game1-v2.3.0/game/src/index.ts | 7 ++++-- packages/core/src/types.ts | 12 ++++++++-- packages/dev-server/src/App.tsx | 16 +++++-------- packages/game/src/gameDef.ts | 36 ++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/games/game1-v2.3.0/game/src/index.ts b/games/game1-v2.3.0/game/src/index.ts index b796744..7d7af89 100644 --- a/games/game1-v2.3.0/game/src/index.ts +++ b/games/game1-v2.3.0/game/src/index.ts @@ -133,7 +133,10 @@ const gameSettings: GameSettings = [ key: "setting1", options: [{ value: "a" }, { value: "b" }], }, - { key: "setting2", options: [{ value: "x" }, { value: "y" }] }, + { + key: "setting2", + options: [{ value: "x" }, { value: "y", isDefault: true }], + }, ]; const gamePlayerSettings: GamePlayerSettings = [ @@ -157,7 +160,7 @@ const gamePlayerSettings: GamePlayerSettings = [ { key: "dieNumFaces", type: "string", - options: [{ value: "6" }, { value: "20" }], + options: [{ value: "6", isDefault: true }, { value: "20" }], }, ]; diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index fc1b2a2..448fb3a 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -37,6 +37,7 @@ export type GameSetting = { // * `previousMatchValue` // * The first option `default: true` // * The first option + // This logic si defined where we set `defaultValue`. // // If your implement this function, don't forget to return `previousMatchValue` when // it is defined, if you want to keep that behaviour! @@ -53,7 +54,14 @@ export type GameSettings = GameSetting[]; export type GameSettings_ = { allIds: string[]; - byId: Record; + byId: Record< + string, + GameSetting & { + // We set this from the `isDefault` option if there is one. + // This avoids the need to loop through all the options to find it. + defaultValue: string; + } + >; }; /* @@ -104,7 +112,7 @@ export type GamePlayerSettings = GamePlayerSetting[]; export type GamePlayerSettings_ = { allIds: string[]; - byId: Record; + byId: Record; }; export type GameStatType = diff --git a/packages/dev-server/src/App.tsx b/packages/dev-server/src/App.tsx index 4a5c8bd..1b5584b 100644 --- a/packages/dev-server/src/App.tsx +++ b/packages/dev-server/src/App.tsx @@ -295,9 +295,9 @@ function MatchSetting({ }); }} > - {options.map(({ value }) => ( + {options.map(({ value, isDefault }) => ( ))} @@ -372,9 +372,9 @@ function MatchPlayerSetting({ }); }} > - {options.map(({ value }) => ( + {options.map(({ value, isDefault }) => ( ))} @@ -796,12 +796,8 @@ const initMatch = ({ if (gameSettings) { matchSettings = Object.fromEntries( gameSettings.allIds.map((key) => { - for (const { value, isDefault } of gameSettings.byId[key].options) { - if (isDefault) { - return [key, value]; - } - } - return [key, gameSettings.byId[key].options[0].value]; + const defaultValue = gameSettings.byId[key].defaultValue; + return [key, defaultValue]; }), ); } diff --git a/packages/game/src/gameDef.ts b/packages/game/src/gameDef.ts index 0f01ff5..3fe7da0 100644 --- a/packages/game/src/gameDef.ts +++ b/packages/game/src/gameDef.ts @@ -479,6 +479,36 @@ function normalizeStats(stats: GameStats | undefined): GameStats_ { return stats_; } +function normalizeSettings(settings: GameSettings): GameSettings_; +function normalizeSettings(settings: GamePlayerSettings): GamePlayerSettings_; +function normalizeSettings(settings: GameSettings | GamePlayerSettings) { + const newSettings = normalizeArray(settings, "key"); + + // Find the default values. + for (const key of newSettings.allIds) { + const gameSetting = newSettings.byId[key]; + + let defaultValue: string | null = null; + let numDefault = 0; + + for (const { value, isDefault } of gameSetting.options) { + if (isDefault) { + defaultValue = value; + numDefault++; + } + } + + if (numDefault > 1) { + throw new Error(`multiple default values for game setting ${key}`); + } + + (gameSetting as any).defaultValue = + defaultValue ?? gameSetting.options[0].value; + } + + return newSettings; +} + /* * Parse a @lefun/game game definition into our internal game definition. */ @@ -489,8 +519,10 @@ export function parseGame< >(game: Game): Game_ { const playerStats = normalizeStats(game.playerStats); const matchStats = normalizeStats(game.matchStats); - const gameSettings = normalizeArray(game.gameSettings, "key"); - const gamePlayerSettings = normalizeArray(game.gamePlayerSettings, "key"); + const gameSettings = + game.gameSettings && normalizeSettings(game.gameSettings); + const gamePlayerSettings = + game.gamePlayerSettings && normalizeSettings(game.gamePlayerSettings); return { ...game, playerStats, matchStats, gameSettings, gamePlayerSettings }; } From 1b41567cc68cf3c12c9d4ba04b1c36db155d7830 Mon Sep 17 00:00:00 2001 From: Simon Lemieux <1105380+simlmx@users.noreply.github.com> Date: Thu, 29 Aug 2024 19:20:48 +0000 Subject: [PATCH 2/4] Add test for double `turns.begin` --- packages/game/src/testing.test.ts | 40 ++++++++++++++++++++++++++++++- packages/game/src/testing.ts | 3 ++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/game/src/testing.test.ts b/packages/game/src/testing.test.ts index 448adab..1825441 100644 --- a/packages/game/src/testing.test.ts +++ b/packages/game/src/testing.test.ts @@ -163,6 +163,44 @@ describe("turns", () => { match.makeMove(userId, "go", {}); expect(match.board.expiresAt).toEqual(1000); }); + + test("double begin turn: only the latest counts", () => { + type B = { + x: string; + }; + type GS = GameState; + const game = { + ...gameBase, + initialBoards: () => ({ board: { x: "" } }), + playerMoves: { + add: { + executeNow({ board, payload }) { + board.x += payload.x; + }, + } as PlayerMove, + begin: { + execute({ userId, payload, _ }) { + _.turns.begin(userId, { + expiresIn: 10, + playerMoveOnExpire: ["add", { x: payload.onExpire }], + }); + }, + } as PlayerMove, + }, + } satisfies Game; + + const match = new MatchTester({ game, numPlayers: 1 }); + const userId = match.meta.players.allIds[0]; + match.makeMove(userId, "begin", { onExpire: "a" }); + expect(match.board.x).toBe(""); + match.fastForward(10); + expect(match.board.x).toBe("a"); + + match.makeMove(userId, "begin", { onExpire: "b" }); + match.makeMove(userId, "begin", { onExpire: "c" }); + match.fastForward(20); + expect(match.board.x).toBe("ac"); + }); }); describe("fastForward", () => { @@ -345,7 +383,7 @@ test("end match ends turns", () => { initialBoards: () => ({ board: { x: 0 } }), playerMoves: { go: { - execute({ userId, board, _ }) { + execute({ userId, _ }) { _.turns.begin(userId); _.endMatch(); }, diff --git a/packages/game/src/testing.ts b/packages/game/src/testing.ts index 2861384..5fd61ba 100644 --- a/packages/game/src/testing.ts +++ b/packages/game/src/testing.ts @@ -399,7 +399,8 @@ export class MatchTester> { }) { for (const userId of beginTurnUsers) { this.meta.players.byId[userId].itsYourTurn = true; - // Clear previous turn player moves for that player. + // Clear previous turn player moves for that player: in other words only the + // lastest `turns.begin` counts for a given player. this.delayedMoves = this.delayedMoves.filter( ({ userId: otherUserId }) => otherUserId !== userId, ); From ab9932c290b9248656fc376c27a4bafe3d5a85ca Mon Sep 17 00:00:00 2001 From: Simon Lemieux <1105380+simlmx@users.noreply.github.com> Date: Thu, 29 Aug 2024 19:47:27 +0000 Subject: [PATCH 3/4] Add READMEs to @lefun/* packages --- packages/core/README.md | 1 + packages/core/package.json | 2 +- packages/dev-server/README.md | 1 + packages/game/README.md | 1 + packages/ui-testing/README.md | 1 + packages/ui/README.md | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 packages/core/README.md create mode 100644 packages/dev-server/README.md create mode 100644 packages/game/README.md create mode 100644 packages/ui-testing/README.md create mode 100644 packages/ui/README.md diff --git a/packages/core/README.md b/packages/core/README.md new file mode 100644 index 0000000..9e21ea6 --- /dev/null +++ b/packages/core/README.md @@ -0,0 +1 @@ +Core library to make games at [lefun.fun](https://lefun.fun). diff --git a/packages/core/package.json b/packages/core/package.json index 606a69a..f304aeb 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@lefun/core", "version": "2.5.1", - "description": "Core library to make games for https://lefun.fun", + "description": "Core library to make games at https://lefun.fun", "author": "Simon Lemieux", "repository": { "type": "git", diff --git a/packages/dev-server/README.md b/packages/dev-server/README.md new file mode 100644 index 0000000..20ec880 --- /dev/null +++ b/packages/dev-server/README.md @@ -0,0 +1 @@ +Development server to help while developing games at [lefun.fun](https://lefun.com). diff --git a/packages/game/README.md b/packages/game/README.md new file mode 100644 index 0000000..af9d243 --- /dev/null +++ b/packages/game/README.md @@ -0,0 +1 @@ +Main dependency for writing game logic at [lefun.fun](https://lefun.fun). diff --git a/packages/ui-testing/README.md b/packages/ui-testing/README.md new file mode 100644 index 0000000..899034e --- /dev/null +++ b/packages/ui-testing/README.md @@ -0,0 +1 @@ +Utils for testing the UI of games at [lefun.fun](https://lefun.fun). diff --git a/packages/ui/README.md b/packages/ui/README.md new file mode 100644 index 0000000..e74eed3 --- /dev/null +++ b/packages/ui/README.md @@ -0,0 +1 @@ +Main dependency for writing the UI of games at [lefun.fun](https://lefun.com). From 69c8f3e98cebb0dd91565be2176d0b58d86340df Mon Sep 17 00:00:00 2001 From: Simon Lemieux <1105380+simlmx@users.noreply.github.com> Date: Thu, 29 Aug 2024 19:47:51 +0000 Subject: [PATCH 4/4] Version 2.5.2 --- lerna.json | 2 +- packages/core/package.json | 2 +- packages/dev-server/package.json | 2 +- packages/game/package.json | 2 +- packages/ui-testing/package.json | 2 +- packages/ui/package.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lerna.json b/lerna.json index 4b1aeb4..5a5bcac 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "2.5.1", + "version": "2.5.2", "npmClient": "pnpm" } diff --git a/packages/core/package.json b/packages/core/package.json index f304aeb..a80da35 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@lefun/core", - "version": "2.5.1", + "version": "2.5.2", "description": "Core library to make games at https://lefun.fun", "author": "Simon Lemieux", "repository": { diff --git a/packages/dev-server/package.json b/packages/dev-server/package.json index 6a87a00..2ee666f 100644 --- a/packages/dev-server/package.json +++ b/packages/dev-server/package.json @@ -1,6 +1,6 @@ { "name": "@lefun/dev-server", - "version": "2.5.1", + "version": "2.5.2", "description": "Development server to run games developed for https://lefun.com.", "author": "Simon Lemieux", "repository": { diff --git a/packages/game/package.json b/packages/game/package.json index d7df7de..3967b9e 100644 --- a/packages/game/package.json +++ b/packages/game/package.json @@ -1,6 +1,6 @@ { "name": "@lefun/game", - "version": "2.5.1", + "version": "2.5.2", "description": "Main dependency for writing game logic at https://lefun.fun.", "author": "Simon Lemieux", "repository": { diff --git a/packages/ui-testing/package.json b/packages/ui-testing/package.json index fc9c336..39747d9 100644 --- a/packages/ui-testing/package.json +++ b/packages/ui-testing/package.json @@ -1,6 +1,6 @@ { "name": "@lefun/ui-testing", - "version": "2.5.1", + "version": "2.5.2", "description": "Utils for testing the UI of games at https://lefun.fun.", "author": "Simon Lemieux", "repository": { diff --git a/packages/ui/package.json b/packages/ui/package.json index 94e8611..b3c953e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@lefun/ui", - "version": "2.5.1", + "version": "2.5.2", "description": "Main dependency for writing the UI of games at https://lefun.com.", "author": "Simon Lemieux", "repository": {