From 85d94e484a2a3ceed481ecb13dac3b548cae77a7 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Wed, 18 Jun 2025 03:29:49 -0400 Subject: [PATCH] Schema cleanup (#1219) ## Description: Cleanup schemas that are using `z.discriminatedUnion()`. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors --------- Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com> --- src/core/Schemas.ts | 97 ++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 41 deletions(-) diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index bb0ca9550..dcc5d7699 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -122,6 +122,10 @@ export enum LogSeverity { Fatal = "FATAL", } +// +// Utility types +// + export const GameConfigSchema = z.object({ gameMap: z.nativeEnum(GameMapType), difficulty: z.nativeEnum(Difficulty), @@ -170,7 +174,19 @@ export const ID = z export const AllPlayersStatsSchema = z.record(ID, PlayerStatsSchema); -// Zod schemas +export const UsernameSchema = SafeString; +export const FlagSchema = z.string().max(128).optional(); + +export const QuickChatKeySchema = z.enum( + Object.entries(quickChatData).flatMap(([category, entries]) => + entries.map((entry) => `${category}.${entry.key}`), + ) as [string, ...string[]], +); + +// +// Intents +// + const BaseIntentSchema = z.object({ clientID: ID, }); @@ -181,9 +197,6 @@ export const AttackIntentSchema = BaseIntentSchema.extend({ troops: z.number().nullable(), }); -export const UsernameSchema = SafeString; -export const FlagSchema = z.string().max(128).optional(); - export const SpawnIntentSchema = BaseIntentSchema.extend({ type: z.literal("spawn"), name: UsernameSchema, @@ -282,12 +295,6 @@ export const MoveWarshipIntentSchema = BaseIntentSchema.extend({ tile: z.number(), }); -export const QuickChatKeySchema = z.enum( - Object.entries(quickChatData).flatMap(([category, entries]) => - entries.map((entry) => `${category}.${entry.key}`), - ) as [string, ...string[]], -); - export const QuickChatIntentSchema = BaseIntentSchema.extend({ type: z.literal("quick_chat"), recipient: ID, @@ -322,6 +329,10 @@ const IntentSchema = z.discriminatedUnion("type", [ QuickChatIntentSchema, ]); +// +// Server utility types +// + export const TurnSchema = z.object({ turnNumber: z.number(), intents: IntentSchema.array(), @@ -329,26 +340,6 @@ export const TurnSchema = z.object({ hash: z.number().nullable().optional(), }); -// Server - -const ServerBaseMessageSchema = z.object({ - type: z.enum(["turn", "ping", "prestart", "start", "desync", "error"]), -}); - -export const ServerTurnMessageSchema = ServerBaseMessageSchema.extend({ - type: z.literal("turn"), - turn: TurnSchema, -}); - -export const ServerPingMessageSchema = ServerBaseMessageSchema.extend({ - type: z.literal("ping"), -}); - -export const ServerPrestartMessageSchema = ServerBaseMessageSchema.extend({ - type: z.literal("prestart"), - gameMap: z.nativeEnum(GameMapType), -}); - export const PlayerSchema = z.object({ clientID: ID, username: UsernameSchema, @@ -361,14 +352,40 @@ export const GameStartInfoSchema = z.object({ players: PlayerSchema.array(), }); -export const ServerStartGameMessageSchema = ServerBaseMessageSchema.extend({ +export const WinnerSchema = z + .union([ + z.tuple([z.literal("player"), ID]), + z.tuple([z.literal("team"), SafeString]), + ]) + .optional(); +export type Winner = z.infer; + +// +// Server +// + +export const ServerTurnMessageSchema = z.object({ + type: z.literal("turn"), + turn: TurnSchema, +}); + +export const ServerPingMessageSchema = z.object({ + type: z.literal("ping"), +}); + +export const ServerPrestartMessageSchema = z.object({ + type: z.literal("prestart"), + gameMap: z.nativeEnum(GameMapType), +}); + +export const ServerStartGameMessageSchema = z.object({ type: z.literal("start"), // Turns the client missed if they are late to the game. turns: TurnSchema.array(), gameStartInfo: GameStartInfoSchema, }); -export const ServerDesyncSchema = ServerBaseMessageSchema.extend({ +export const ServerDesyncSchema = z.object({ type: z.literal("desync"), turn: z.number(), correctHash: z.number().nullable(), @@ -377,7 +394,7 @@ export const ServerDesyncSchema = ServerBaseMessageSchema.extend({ yourHash: z.number().optional(), }); -export const ServerErrorSchema = ServerBaseMessageSchema.extend({ +export const ServerErrorSchema = z.object({ type: z.literal("error"), error: z.string(), }); @@ -391,15 +408,9 @@ export const ServerMessageSchema = z.discriminatedUnion("type", [ ServerErrorSchema, ]); +// // Client - -export const WinnerSchema = z - .union([ - z.tuple([z.literal("player"), ID]), - z.tuple([z.literal("team"), SafeString]), - ]) - .optional(); -export type Winner = z.infer; +// export const ClientSendWinnerSchema = z.object({ type: z.literal("winner"), @@ -448,6 +459,10 @@ export const ClientMessageSchema = z.discriminatedUnion("type", [ ClientHashSchema, ]); +// +// Records +// + export const PlayerRecordSchema = PlayerSchema.extend({ persistentID: PersistentIdSchema, // WARNING: PII stats: PlayerStatsSchema,