@drmxrcy/tcg-core 0.0.0-202602060542

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +882 -0
  2. package/package.json +58 -0
  3. package/src/__tests__/alpha-clash-engine-definition.test.ts +319 -0
  4. package/src/__tests__/createMockAlphaClashGame.ts +462 -0
  5. package/src/__tests__/createMockGrandArchiveGame.ts +373 -0
  6. package/src/__tests__/createMockGundamGame.ts +379 -0
  7. package/src/__tests__/createMockLorcanaGame.ts +328 -0
  8. package/src/__tests__/createMockOnePieceGame.ts +429 -0
  9. package/src/__tests__/createMockRiftboundGame.ts +462 -0
  10. package/src/__tests__/grand-archive-engine-definition.test.ts +118 -0
  11. package/src/__tests__/gundam-engine-definition.test.ts +110 -0
  12. package/src/__tests__/integration-complete-game.test.ts +508 -0
  13. package/src/__tests__/integration-network-sync.test.ts +469 -0
  14. package/src/__tests__/lorcana-engine-definition.test.ts +100 -0
  15. package/src/__tests__/move-enumeration.test.ts +725 -0
  16. package/src/__tests__/multiplayer-engine.test.ts +555 -0
  17. package/src/__tests__/one-piece-engine-definition.test.ts +114 -0
  18. package/src/__tests__/riftbound-engine-definition.test.ts +124 -0
  19. package/src/actions/action-definition.test.ts +201 -0
  20. package/src/actions/action-definition.ts +122 -0
  21. package/src/actions/action-timing.test.ts +490 -0
  22. package/src/actions/action-timing.ts +257 -0
  23. package/src/cards/card-definition.test.ts +268 -0
  24. package/src/cards/card-definition.ts +27 -0
  25. package/src/cards/card-instance.test.ts +422 -0
  26. package/src/cards/card-instance.ts +49 -0
  27. package/src/cards/computed-properties.test.ts +530 -0
  28. package/src/cards/computed-properties.ts +84 -0
  29. package/src/cards/conditional-modifiers.test.ts +390 -0
  30. package/src/cards/modifiers.test.ts +286 -0
  31. package/src/cards/modifiers.ts +51 -0
  32. package/src/engine/MULTIPLAYER.md +425 -0
  33. package/src/engine/__tests__/rule-engine-flow.test.ts +348 -0
  34. package/src/engine/__tests__/rule-engine-history.test.ts +535 -0
  35. package/src/engine/__tests__/rule-engine-moves.test.ts +488 -0
  36. package/src/engine/__tests__/rule-engine.test.ts +366 -0
  37. package/src/engine/index.ts +14 -0
  38. package/src/engine/multiplayer-engine.example.ts +571 -0
  39. package/src/engine/multiplayer-engine.ts +409 -0
  40. package/src/engine/rule-engine.test.ts +286 -0
  41. package/src/engine/rule-engine.ts +1539 -0
  42. package/src/engine/tracker-system.ts +172 -0
  43. package/src/examples/__tests__/coin-flip-game.test.ts +641 -0
  44. package/src/filtering/card-filter.test.ts +230 -0
  45. package/src/filtering/card-filter.ts +91 -0
  46. package/src/filtering/card-query.test.ts +901 -0
  47. package/src/filtering/card-query.ts +273 -0
  48. package/src/filtering/filter-matching.test.ts +944 -0
  49. package/src/filtering/filter-matching.ts +315 -0
  50. package/src/flow/SERIALIZATION.md +428 -0
  51. package/src/flow/__tests__/flow-definition.test.ts +427 -0
  52. package/src/flow/__tests__/flow-manager.test.ts +756 -0
  53. package/src/flow/__tests__/flow-serialization.test.ts +565 -0
  54. package/src/flow/flow-definition.ts +453 -0
  55. package/src/flow/flow-manager.ts +1044 -0
  56. package/src/flow/index.ts +35 -0
  57. package/src/game-definition/__tests__/game-definition-validation.test.ts +359 -0
  58. package/src/game-definition/__tests__/game-definition.test.ts +291 -0
  59. package/src/game-definition/__tests__/move-definitions.test.ts +328 -0
  60. package/src/game-definition/game-definition.ts +261 -0
  61. package/src/game-definition/index.ts +28 -0
  62. package/src/game-definition/move-definitions.ts +188 -0
  63. package/src/game-definition/validation.ts +183 -0
  64. package/src/history/history-manager.test.ts +497 -0
  65. package/src/history/history-manager.ts +312 -0
  66. package/src/history/history-operations.ts +122 -0
  67. package/src/history/index.ts +9 -0
  68. package/src/history/types.ts +255 -0
  69. package/src/index.ts +32 -0
  70. package/src/logging/index.ts +27 -0
  71. package/src/logging/log-formatter.ts +187 -0
  72. package/src/logging/logger.ts +276 -0
  73. package/src/logging/types.ts +148 -0
  74. package/src/moves/create-move.test.ts +331 -0
  75. package/src/moves/create-move.ts +64 -0
  76. package/src/moves/move-enumeration.ts +228 -0
  77. package/src/moves/move-executor.test.ts +431 -0
  78. package/src/moves/move-executor.ts +195 -0
  79. package/src/moves/move-system.test.ts +380 -0
  80. package/src/moves/move-system.ts +463 -0
  81. package/src/moves/standard-moves.ts +231 -0
  82. package/src/operations/card-operations.test.ts +236 -0
  83. package/src/operations/card-operations.ts +116 -0
  84. package/src/operations/card-registry-impl.test.ts +251 -0
  85. package/src/operations/card-registry-impl.ts +70 -0
  86. package/src/operations/card-registry.test.ts +234 -0
  87. package/src/operations/card-registry.ts +106 -0
  88. package/src/operations/counter-operations.ts +152 -0
  89. package/src/operations/game-operations.test.ts +280 -0
  90. package/src/operations/game-operations.ts +140 -0
  91. package/src/operations/index.ts +24 -0
  92. package/src/operations/operations-impl.test.ts +354 -0
  93. package/src/operations/operations-impl.ts +468 -0
  94. package/src/operations/zone-operations.test.ts +295 -0
  95. package/src/operations/zone-operations.ts +223 -0
  96. package/src/rng/seeded-rng.test.ts +339 -0
  97. package/src/rng/seeded-rng.ts +123 -0
  98. package/src/targeting/index.ts +48 -0
  99. package/src/targeting/target-definition.test.ts +273 -0
  100. package/src/targeting/target-definition.ts +37 -0
  101. package/src/targeting/target-dsl.ts +279 -0
  102. package/src/targeting/target-resolver.ts +486 -0
  103. package/src/targeting/target-validation.test.ts +994 -0
  104. package/src/targeting/target-validation.ts +286 -0
  105. package/src/telemetry/events.ts +202 -0
  106. package/src/telemetry/index.ts +21 -0
  107. package/src/telemetry/telemetry-manager.ts +127 -0
  108. package/src/telemetry/types.ts +68 -0
  109. package/src/testing/__tests__/testing-utilities-integration.test.ts +161 -0
  110. package/src/testing/index.ts +88 -0
  111. package/src/testing/test-assertions.test.ts +341 -0
  112. package/src/testing/test-assertions.ts +256 -0
  113. package/src/testing/test-card-factory.test.ts +228 -0
  114. package/src/testing/test-card-factory.ts +111 -0
  115. package/src/testing/test-context-factory.ts +187 -0
  116. package/src/testing/test-end-assertions.test.ts +262 -0
  117. package/src/testing/test-end-assertions.ts +95 -0
  118. package/src/testing/test-engine-builder.test.ts +389 -0
  119. package/src/testing/test-engine-builder.ts +46 -0
  120. package/src/testing/test-flow-assertions.test.ts +284 -0
  121. package/src/testing/test-flow-assertions.ts +115 -0
  122. package/src/testing/test-player-builder.test.ts +132 -0
  123. package/src/testing/test-player-builder.ts +46 -0
  124. package/src/testing/test-replay-assertions.test.ts +356 -0
  125. package/src/testing/test-replay-assertions.ts +164 -0
  126. package/src/testing/test-rng-helpers.test.ts +260 -0
  127. package/src/testing/test-rng-helpers.ts +190 -0
  128. package/src/testing/test-state-builder.test.ts +373 -0
  129. package/src/testing/test-state-builder.ts +99 -0
  130. package/src/testing/test-zone-factory.test.ts +295 -0
  131. package/src/testing/test-zone-factory.ts +224 -0
  132. package/src/types/branded-utils.ts +54 -0
  133. package/src/types/branded.test.ts +175 -0
  134. package/src/types/branded.ts +33 -0
  135. package/src/types/index.ts +8 -0
  136. package/src/types/state.test.ts +198 -0
  137. package/src/types/state.ts +154 -0
  138. package/src/validation/card-type-guards.test.ts +242 -0
  139. package/src/validation/card-type-guards.ts +179 -0
  140. package/src/validation/index.ts +40 -0
  141. package/src/validation/schema-builders.test.ts +403 -0
  142. package/src/validation/schema-builders.ts +345 -0
  143. package/src/validation/type-guard-builder.test.ts +216 -0
  144. package/src/validation/type-guard-builder.ts +109 -0
  145. package/src/validation/validator-builder.test.ts +375 -0
  146. package/src/validation/validator-builder.ts +273 -0
  147. package/src/zones/index.ts +28 -0
  148. package/src/zones/zone-factory.test.ts +183 -0
  149. package/src/zones/zone-factory.ts +44 -0
  150. package/src/zones/zone-operations.test.ts +800 -0
  151. package/src/zones/zone-operations.ts +306 -0
  152. package/src/zones/zone-state-helpers.test.ts +337 -0
  153. package/src/zones/zone-state-helpers.ts +128 -0
  154. package/src/zones/zone-visibility.test.ts +156 -0
  155. package/src/zones/zone-visibility.ts +36 -0
  156. package/src/zones/zone.test.ts +186 -0
  157. package/src/zones/zone.ts +66 -0
@@ -0,0 +1,51 @@
1
+ import type { CardId } from "../types";
2
+
3
+ /**
4
+ * Modifier type definitions
5
+ * - stat: Modifies numerical stats (power, toughness, cost, etc.)
6
+ * - ability: Grants or removes abilities
7
+ * - type: Changes card types or subtypes
8
+ * - keyword: Grants keywords (flying, haste, trample, etc.)
9
+ */
10
+ export type ModifierType = "stat" | "ability" | "type" | "keyword";
11
+
12
+ /**
13
+ * Modifier duration options
14
+ * - permanent: Lasts indefinitely
15
+ * - until-end-of-turn: Expires at end of turn
16
+ * - while-condition: Active only while condition is true
17
+ */
18
+ export type ModifierDuration =
19
+ | "permanent"
20
+ | "until-end-of-turn"
21
+ | "while-condition";
22
+
23
+ /**
24
+ * Modifier represents a temporary or permanent change to a card's properties
25
+ * @template TGameState - Game state type for condition evaluation (defaults to unknown)
26
+ */
27
+ export type Modifier<TGameState = unknown> = {
28
+ /** Unique identifier for this modifier */
29
+ id: string;
30
+
31
+ /** Type of modification */
32
+ type: ModifierType;
33
+
34
+ /** Which property to modify (e.g., 'power', 'toughness', 'flying') */
35
+ property: string;
36
+
37
+ /** The modification value (can be number, string, or boolean) */
38
+ value: number | string | boolean;
39
+
40
+ /** How long this modifier lasts */
41
+ duration: ModifierDuration;
42
+
43
+ /** Optional condition function - modifier only applies when this returns true */
44
+ condition?: (state: TGameState) => boolean;
45
+
46
+ /** Card that created this modifier */
47
+ source: CardId;
48
+
49
+ /** Optional layer for complex modifier interactions (e.g., MTG layer system) */
50
+ layer?: number;
51
+ };
@@ -0,0 +1,425 @@
1
+ # MultiplayerEngine - Network Synchronization Guide
2
+
3
+ ## Overview
4
+
5
+ `MultiplayerEngine` is a reusable wrapper around `RuleEngine` that encapsulates multiplayer patterns for server-authoritative gameplay. It provides a clean abstraction for network synchronization using Immer patches.
6
+
7
+ ## Key Features
8
+
9
+ - **Server-Authoritative Architecture**: Server is the source of truth
10
+ - **Patch-Based Synchronization**: Efficient delta updates using Immer patches
11
+ - **Client Tracking**: Monitor which clients are synchronized
12
+ - **Reconnection Support**: Batch patch application for catching up
13
+ - **Type-Safe**: Full TypeScript support with branded types
14
+ - **Network Agnostic**: Works with any transport layer (WebSocket, HTTP, etc.)
15
+
16
+ ## Architecture
17
+
18
+ ```
19
+ ┌─────────────────────────────────────────────────────────┐
20
+ │ Server │
21
+ │ ┌───────────────────────────────────────────────────┐ │
22
+ │ │ MultiplayerEngine (Server Mode) │ │
23
+ │ │ - Executes moves authoritatively │ │
24
+ │ │ - Generates patches │ │
25
+ │ │ - Broadcasts patches to clients │ │
26
+ │ │ - Tracks client sync state │ │
27
+ │ └───────────────────────────────────────────────────┘ │
28
+ └─────────────────────────────────────────────────────────┘
29
+
30
+ │ Patches
31
+
32
+ ┌──────────────────────────────────────────┐
33
+ │ Network Layer │
34
+ │ (WebSocket, HTTP, Custom Protocol) │
35
+ └──────────────────────────────────────────┘
36
+
37
+ │ Patches
38
+
39
+ ┌─────────────────────────────────────────────────────────┐
40
+ │ Clients │
41
+ │ ┌───────────────────────────────────────────────────┐ │
42
+ │ │ MultiplayerEngine (Client Mode) │ │
43
+ │ │ - Applies patches from server │ │
44
+ │ │ - Maintains synced state │ │
45
+ │ │ - Validates moves locally (optional) │ │
46
+ │ │ - Provides player views │ │
47
+ │ └───────────────────────────────────────────────────┘ │
48
+ └─────────────────────────────────────────────────────────┘
49
+ ```
50
+
51
+ ## Quick Start
52
+
53
+ ### Server Setup
54
+
55
+ ```typescript
56
+ import { MultiplayerEngine } from "@drmxrcy/tcg-core";
57
+
58
+ const server = new MultiplayerEngine(gameDefinition, players, {
59
+ mode: "server",
60
+ seed: "game-123-seed",
61
+
62
+ // Callback when moves generate patches
63
+ onPatchBroadcast: (broadcast) => {
64
+ // Send patches to all connected clients via your network layer
65
+ websocket.broadcast({
66
+ type: "PATCH_UPDATE",
67
+ patches: broadcast.patches,
68
+ historyIndex: broadcast.historyIndex,
69
+ });
70
+ },
71
+
72
+ // Callback when moves are rejected
73
+ onMoveRejected: (moveId, error, errorCode) => {
74
+ console.error(`Move ${moveId} rejected: ${error}`);
75
+ }
76
+ });
77
+
78
+ // Execute moves (server only)
79
+ const result = server.executeMove("playCard", {
80
+ playerId: createPlayerId("p1"),
81
+ data: { cardId: "card-123" }
82
+ });
83
+
84
+ // Patches are automatically broadcast via onPatchBroadcast callback
85
+ ```
86
+
87
+ ### Client Setup
88
+
89
+ ```typescript
90
+ import { MultiplayerEngine } from "@drmxrcy/tcg-core";
91
+
92
+ const client = new MultiplayerEngine(gameDefinition, players, {
93
+ mode: "client",
94
+
95
+ // Callback when patches are applied
96
+ onPatchesApplied: (patches) => {
97
+ console.log(`Applied ${patches.length} patches from server`);
98
+ updateUI(); // Refresh your game UI
99
+ }
100
+ });
101
+
102
+ // Receive and apply patches from server
103
+ websocket.on("message", (data) => {
104
+ if (data.type === "PATCH_UPDATE") {
105
+ client.applyServerPatches(data.patches);
106
+ }
107
+ });
108
+
109
+ // Get current state
110
+ const state = client.getState();
111
+
112
+ // Get player-specific view (hides private information)
113
+ const playerView = client.getPlayerView(playerId);
114
+
115
+ // Check valid moves for UI (enable/disable buttons)
116
+ const validMoves = client.getValidMoves(playerId);
117
+ const canDraw = client.canExecuteMove("drawCard", { playerId });
118
+ ```
119
+
120
+ ## Common Patterns
121
+
122
+ ### Pattern 1: Move Request Flow
123
+
124
+ ```typescript
125
+ // CLIENT SIDE
126
+ // User clicks "Draw Card" button
127
+ function handleDrawCard() {
128
+ // Optional: Check if move is valid (for immediate UI feedback)
129
+ const canDraw = client.canExecuteMove("drawCard", { playerId });
130
+
131
+ if (!canDraw) {
132
+ showError("Cannot draw card right now");
133
+ return;
134
+ }
135
+
136
+ // Send move request to server
137
+ websocket.send({
138
+ type: "MOVE_REQUEST",
139
+ moveId: "drawCard",
140
+ playerId: "p1"
141
+ });
142
+ }
143
+
144
+ // SERVER SIDE
145
+ // Receive move request from client
146
+ websocket.on("message", (msg) => {
147
+ if (msg.type === "MOVE_REQUEST") {
148
+ const result = server.executeMove(msg.moveId, {
149
+ playerId: msg.playerId
150
+ });
151
+
152
+ // On success, patches automatically broadcast to all clients
153
+ // On failure, send error back to requesting client
154
+ if (!result.success) {
155
+ websocket.send({
156
+ type: "MOVE_ERROR",
157
+ error: result.error,
158
+ errorCode: result.errorCode
159
+ });
160
+ }
161
+ }
162
+ });
163
+ ```
164
+
165
+ ### Pattern 2: Client Reconnection
166
+
167
+ ```typescript
168
+ // SERVER SIDE
169
+ function handleReconnection(clientId: string, lastKnownIndex: number) {
170
+ // Get all patches since client's last known state
171
+ const catchupPatches = server.getCatchupPatches(lastKnownIndex + 1);
172
+
173
+ return {
174
+ type: "CATCHUP",
175
+ patches: catchupPatches,
176
+ currentIndex: server.getCurrentHistoryIndex()
177
+ };
178
+ }
179
+
180
+ // CLIENT SIDE
181
+ function reconnect(lastKnownIndex: number) {
182
+ websocket.send({
183
+ type: "RECONNECT",
184
+ lastKnownIndex
185
+ });
186
+ }
187
+
188
+ websocket.on("message", (msg) => {
189
+ if (msg.type === "CATCHUP") {
190
+ // Apply all missed patches at once
191
+ client.applyServerPatches(msg.patches);
192
+ console.log(`Caught up from ${lastKnownIndex} to ${msg.currentIndex}`);
193
+ }
194
+ });
195
+ ```
196
+
197
+ ### Pattern 3: Client State Tracking
198
+
199
+ ```typescript
200
+ // SERVER SIDE
201
+ // Register client when they connect
202
+ server.registerClient("client-123", -1);
203
+
204
+ // Update sync index when client acknowledges patches
205
+ websocket.on("message", (msg) => {
206
+ if (msg.type === "PATCH_ACK") {
207
+ server.updateClientSyncIndex(msg.clientId, msg.historyIndex);
208
+ }
209
+ });
210
+
211
+ // Check client sync state
212
+ const clientState = server.getClientState("client-123");
213
+ if (clientState && !clientState.connected) {
214
+ console.log("Client disconnected, can remove from game");
215
+ }
216
+
217
+ // Get all clients for monitoring
218
+ const allClients = server.getAllClients();
219
+ console.log(`${allClients.filter(c => c.connected).length} clients online`);
220
+ ```
221
+
222
+ ### Pattern 4: Optimistic UI Updates
223
+
224
+ ```typescript
225
+ // CLIENT SIDE
226
+ function handlePlayCard(cardId: string) {
227
+ // Check if move is valid
228
+ if (!client.canExecuteMove("playCard", { playerId, data: { cardId } })) {
229
+ return;
230
+ }
231
+
232
+ // Optimistic UI update (optional)
233
+ showCardPlaying(cardId);
234
+
235
+ // Send to server
236
+ websocket.send({
237
+ type: "MOVE_REQUEST",
238
+ moveId: "playCard",
239
+ data: { cardId }
240
+ });
241
+
242
+ // Server will broadcast patches if successful
243
+ // If rejected, patches won't arrive and server sends error
244
+ }
245
+
246
+ websocket.on("message", (msg) => {
247
+ if (msg.type === "MOVE_ERROR") {
248
+ // Revert optimistic update
249
+ hideCardPlaying(msg.data?.cardId);
250
+ showError(msg.error);
251
+ }
252
+ });
253
+ ```
254
+
255
+ ## API Reference
256
+
257
+ ### Server-Only Methods
258
+
259
+ | Method | Description |
260
+ |--------|-------------|
261
+ | `executeMove(moveId, context)` | Execute a move and generate patches |
262
+ | `getCatchupPatches(sinceIndex)` | Get patches for reconnecting clients |
263
+ | `registerClient(clientId, lastSyncedIndex)` | Track a connected client |
264
+ | `unregisterClient(clientId)` | Mark client as disconnected |
265
+ | `updateClientSyncIndex(clientId, index)` | Update client's sync state |
266
+ | `getClientState(clientId)` | Get a client's sync state |
267
+ | `getAllClients()` | Get all registered clients |
268
+ | `getHistory()` | Get full move history |
269
+ | `getCurrentHistoryIndex()` | Get current history position |
270
+
271
+ ### Client-Only Methods
272
+
273
+ | Method | Description |
274
+ |--------|-------------|
275
+ | `applyServerPatches(patches)` | Apply patches from server |
276
+
277
+ ### Common Methods (Both Server & Client)
278
+
279
+ | Method | Description |
280
+ |--------|-------------|
281
+ | `getState()` | Get current game state |
282
+ | `getPlayerView(playerId)` | Get player-specific view |
283
+ | `canExecuteMove(moveId, context)` | Check if move is valid |
284
+ | `getValidMoves(playerId)` | Get all valid moves for player |
285
+ | `checkGameEnd()` | Check if game has ended |
286
+ | `getEngine()` | Access underlying RuleEngine |
287
+ | `getMode()` | Get current mode (server/client) |
288
+
289
+ ## Examples
290
+
291
+ See `multiplayer-engine.example.ts` for comprehensive examples including:
292
+
293
+ - Basic server setup
294
+ - Client implementation
295
+ - WebSocket integration
296
+ - Reconnection handling
297
+ - Full game simulation
298
+
299
+ ## Integration with Existing Projects
300
+
301
+ ### Using in Lorcana Engine
302
+
303
+ ```typescript
304
+ // packages/lorcana-engine/src/multiplayer/server.ts
305
+ import { MultiplayerEngine } from "@drmxrcy/tcg-core";
306
+ import { lorcanaGameDefinition } from "../game-definition";
307
+
308
+ export function createLorcanaServer(players) {
309
+ return new MultiplayerEngine(lorcanaGameDefinition, players, {
310
+ mode: "server",
311
+ seed: generateGameSeed(),
312
+ onPatchBroadcast: broadcastToClients
313
+ });
314
+ }
315
+ ```
316
+
317
+ ### Using in Gundam Engine
318
+
319
+ ```typescript
320
+ // packages/gundam-engine/src/multiplayer/server.ts
321
+ import { MultiplayerEngine } from "@drmxrcy/tcg-core";
322
+ import { gundamGameDefinition } from "../game-definition";
323
+
324
+ export function createGundamServer(players) {
325
+ return new MultiplayerEngine(gundamGameDefinition, players, {
326
+ mode: "server",
327
+ seed: generateGameSeed(),
328
+ onPatchBroadcast: broadcastToClients
329
+ });
330
+ }
331
+ ```
332
+
333
+ ## Benefits Over Direct RuleEngine Usage
334
+
335
+ 1. **Encapsulation**: Hides multiplayer complexity behind clean API
336
+ 2. **Safety**: Server/client separation prevents invalid operations
337
+ 3. **Callbacks**: Built-in hooks for network integration
338
+ 4. **Client Tracking**: Automatic sync state management
339
+ 5. **Reconnection**: Built-in catchup patch support
340
+ 6. **Type Safety**: Full TypeScript support with mode enforcement
341
+ 7. **Reusability**: Works across all game projects
342
+
343
+ ## Testing
344
+
345
+ See `multiplayer-engine.test.ts` for comprehensive test suite covering:
346
+
347
+ - Server mode operations
348
+ - Client mode operations
349
+ - Server-client synchronization
350
+ - Client reconnection
351
+ - Error handling
352
+ - Callbacks and hooks
353
+
354
+ ## Performance Considerations
355
+
356
+ 1. **Patch Size**: Immer patches are minimal - only changes are transmitted
357
+ 2. **Batching**: Consider batching multiple patches for better network efficiency
358
+ 3. **Compression**: Use gzip/compression for network transmission
359
+ 4. **ACK Protocol**: Track client acknowledgments to prevent packet loss
360
+ 5. **Delta Encoding**: Patches are already delta-encoded by Immer
361
+
362
+ ## Best Practices
363
+
364
+ 1. **Always use server mode for authoritative engine**
365
+ 2. **Use client mode for all connected players**
366
+ 3. **Implement reconnection logic for network stability**
367
+ 4. **Validate moves on both client (UI) and server (authority)**
368
+ 5. **Use player views to hide private information**
369
+ 6. **Track client sync state for monitoring**
370
+ 7. **Implement proper error handling and user feedback**
371
+ 8. **Test with network latency simulation**
372
+
373
+ ## Troubleshooting
374
+
375
+ ### States Out of Sync
376
+
377
+ - Ensure all clients apply patches in order
378
+ - Check that server seed is set for deterministic RNG
379
+ - Verify no client-side state mutations outside patches
380
+
381
+ ### Patches Not Broadcasting
382
+
383
+ - Check `onPatchBroadcast` callback is registered
384
+ - Verify move execution returned `success: true`
385
+ - Check network layer is transmitting messages
386
+
387
+ ### Client Can't Execute Moves
388
+
389
+ - Ensure client is in "client" mode
390
+ - Moves should only be executed on server
391
+ - Clients should only `applyServerPatches`
392
+
393
+ ### Reconnection Issues
394
+
395
+ - Use `getCatchupPatches(lastKnownIndex)` correctly
396
+ - Ensure `lastKnownIndex` is tracked on client
397
+ - Verify patches are applied in correct order
398
+
399
+ ## Migration from RuleEngine
400
+
401
+ If you're currently using `RuleEngine` directly:
402
+
403
+ ```typescript
404
+ // OLD CODE
405
+ const server = new RuleEngine(gameDefinition, players);
406
+ const result = server.executeMove("playCard", context);
407
+ if (result.success) {
408
+ broadcastToClients(result.patches);
409
+ }
410
+
411
+ // NEW CODE
412
+ const server = new MultiplayerEngine(gameDefinition, players, {
413
+ mode: "server",
414
+ onPatchBroadcast: (broadcast) => broadcastToClients(broadcast.patches)
415
+ });
416
+ const result = server.executeMove("playCard", context);
417
+ // Patches automatically broadcast via callback
418
+ ```
419
+
420
+ ## Related Documentation
421
+
422
+ - `rule-engine.ts` - Core game engine implementation
423
+ - `integration-network-sync.test.ts` - Integration test patterns
424
+ - `multiplayer-engine.example.ts` - Comprehensive examples
425
+ - Game Definition documentation for defining moves and state