Trading card city builder game?

update client side to match latest websocket updates

eldridge.cam 0dcc0a35 008a37ce

verified
Waiting for spindle ...
+49 -31
+21 -7
app/src/lib/appserver/socket/SocketV1.svelte.ts
··· 5 5 import Value from "typebox/value"; 6 6 import { 7 7 Account, 8 - GameState, 8 + DeckState, 9 + FieldState, 9 10 Request, 10 11 RequestMessage, 11 12 ResponseMessage, ··· 100 101 }); 101 102 } 102 103 103 - $watchField(data: { id: number }, subscriber: (gameState: GameState | undefined) => void) { 104 - let gameState: GameState | undefined = undefined; 104 + $watchField(data: { id: number }, subscriber: (fieldState: FieldState | undefined) => void) { 105 + let fieldState: FieldState | undefined = undefined; 105 106 this.#sendMessage({ type: "WatchField", data: data.id }).$subscribe((response) => { 106 107 if (response.type === "PutFieldState") { 107 - gameState = response.data; 108 - } else if (response.type === "PatchFieldState") { 108 + fieldState = response.data; 109 + } else if (response.type === "PatchState") { 110 + const patches = response.data; 111 + fieldState = jsonpatch.apply(fieldState, patches); 112 + } 113 + subscriber(fieldState); 114 + }); 115 + } 116 + 117 + $watchDeck(subscriber: (deckState: DeckState | undefined) => void) { 118 + let deckState: DeckState | undefined = undefined; 119 + this.#sendMessage({ type: "WatchDeck" }).$subscribe((response) => { 120 + if (response.type === "PutDeckState") { 121 + deckState = response.data; 122 + } else if (response.type === "PatchState") { 109 123 const patches = response.data; 110 - gameState = jsonpatch.apply(gameState, patches); 124 + deckState = jsonpatch.apply(deckState, patches); 111 125 } 112 - subscriber(gameState); 126 + subscriber(deckState); 113 127 }); 114 128 } 115 129
+20 -16
app/src/lib/appserver/socket/SocketV1Protocol.ts
··· 94 94 export const FieldCitizen = Type.Object({ id: CitizenId, x: Type.Integer(), y: Type.Integer() }); 95 95 export type FieldCitizen = StaticDecode<typeof FieldCitizen>; 96 96 97 - export const GameStateField = Type.Object({ 97 + export const FieldState = Type.Object({ 98 98 tiles: Type.Array(FieldTile), 99 99 citizens: Type.Array(FieldCitizen), 100 100 }); 101 - export type GameStateField = StaticDecode<typeof GameStateField>; 101 + export type FieldState = StaticDecode<typeof FieldState>; 102 102 103 - export const GameState = Type.Object({ 104 - deck: Type.Object({ 105 - tiles: Type.Array(Tile), 106 - citizens: Type.Array(Citizen), 107 - }), 108 - field: GameStateField, 103 + export const DeckState = Type.Object({ 104 + tiles: Type.Array(Tile), 105 + citizens: Type.Array(Citizen), 109 106 }); 110 - export type GameState = StaticDecode<typeof GameState>; 107 + export type DeckState = StaticDecode<typeof DeckState>; 111 108 112 109 export const Authenticate = Type.Object({ 113 110 type: Type.Literal("Authenticate"), 114 111 data: Type.String(), 115 112 }); 116 113 export type Authenticate = StaticDecode<typeof Authenticate>; 114 + 115 + export const WatchDeck = Type.Object({ type: Type.Literal("WatchDeck") }); 116 + export type WatchDeck = StaticDecode<typeof WatchDeck>; 117 117 118 118 export const WatchField = Type.Object({ type: Type.Literal("WatchField"), data: Type.Integer() }); 119 119 export type WatchField = StaticDecode<typeof WatchField>; ··· 127 127 }); 128 128 export type DebugAddCard = StaticDecode<typeof DebugAddCard>; 129 129 130 - export const Request = Type.Union([Authenticate, WatchField, Unsubscribe, DebugAddCard]); 130 + export const Request = Type.Union([Authenticate, WatchDeck, WatchField, Unsubscribe, DebugAddCard]); 131 131 export type Request = StaticDecode<typeof Request>; 132 132 133 133 export const Authenticated = Type.Object({ type: Type.Literal("Authenticated"), data: Account }); 134 134 export type Authenticated = StaticDecode<typeof Authenticated>; 135 135 136 - export const PutFieldState = Type.Object({ type: Type.Literal("PutFieldState"), data: GameState }); 136 + export const PutFieldState = Type.Object({ type: Type.Literal("PutFieldState"), data: FieldState }); 137 137 export type PutFieldState = StaticDecode<typeof PutFieldState>; 138 138 139 - export const PatchFieldState = Type.Object({ 140 - type: Type.Literal("PatchFieldState"), 139 + export const PutDeckState = Type.Object({ type: Type.Literal("PutDeckState"), data: DeckState }); 140 + export type PutDeckState = StaticDecode<typeof PutDeckState>; 141 + 142 + export const PatchState = Type.Object({ 143 + type: Type.Literal("PatchState"), 141 144 data: Type.Array(JsonPatch), 142 145 }); 143 - export type PatchFieldState = StaticDecode<typeof PatchFieldState>; 146 + export type PatchState = StaticDecode<typeof PatchState>; 144 147 145 - export const Response = Type.Union([Authenticated, PutFieldState, PatchFieldState]); 148 + export const Response = Type.Union([Authenticated, PutFieldState, PutDeckState, PatchState]); 146 149 export type Response = StaticDecode<typeof Response>; 147 150 148 151 export type Once<T> = Branded<"Once", T>; ··· 153 156 154 157 export interface SocketV1Protocol { 155 158 Authenticate: Once<Authenticated>; 156 - WatchField: Stream<PutFieldState | PatchFieldState>; 159 + WatchDeck: Stream<PutDeckState | PatchState>; 160 + WatchField: Stream<PutFieldState | PatchState>; 157 161 Unsubscribe: never; 158 162 } 159 163
+3 -3
app/src/routes/(socket)/play/components/FieldView.svelte
··· 1 1 <script lang="ts"> 2 - import { FieldTile, GameState, TileId } from "$lib/appserver/socket/SocketV1Protocol"; 2 + import { FieldTile, FieldState, TileId } from "$lib/appserver/socket/SocketV1Protocol"; 3 3 import DragTile from "$lib/components/DragTile.svelte"; 4 4 5 5 type RuntimeTile = FieldTile | { id: TileId; x: number | undefined; y: number | undefined }; 6 6 7 - const { gameState }: { gameState: GameState } = $props(); 7 + const { fieldState }: { fieldState: FieldState } = $props(); 8 8 9 9 const uncommittedTiles: { id: TileId; x: number | undefined; y: number | undefined }[] = $state( 10 10 [], 11 11 ); 12 - const fieldTiles = $derived<RuntimeTile[]>([...gameState.field.tiles, ...uncommittedTiles]); 12 + const fieldTiles = $derived<RuntimeTile[]>([...fieldState.tiles, ...uncommittedTiles]); 13 13 </script> 14 14 15 15 {#each fieldTiles as fieldTile (fieldTile.id)}
+5 -5
app/src/routes/(socket)/play/components/PlayPage.svelte
··· 1 1 <script lang="ts"> 2 - import type { GameState } from "$lib/appserver/socket/SocketV1Protocol"; 2 + import type { FieldState } from "$lib/appserver/socket/SocketV1Protocol"; 3 3 import { getSocket } from "$lib/appserver/provideSocket.svelte"; 4 4 import DragTile from "$lib/components/DragTile.svelte"; 5 5 import DragWindow from "$lib/components/DragWindow.svelte"; ··· 12 12 const fields = createListFields(() => "foxfriends"); 13 13 14 14 let fieldId: number | undefined = $state(); 15 - let gameState: GameState | undefined = $state(); 15 + let fieldState: FieldState | undefined = $state(); 16 16 17 17 $effect(() => { 18 18 if (fieldId) { 19 - socket.$watchField({ id: fieldId }, (state) => (gameState = state)); 19 + socket.$watchField({ id: fieldId }, (state) => (fieldState = state)); 20 20 } 21 21 }); 22 22 </script> ··· 45 45 {:else} 46 46 <div>Loading</div> 47 47 {/if} 48 - {:else if gameState} 49 - <FieldView {gameState} /> 48 + {:else if fieldState} 49 + <FieldView {fieldState} /> 50 50 {:else} 51 51 <div>Loading</div> 52 52 {/if}