@zigrivers/scaffold 3.4.1 → 3.5.0

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 (194) hide show
  1. package/README.md +91 -0
  2. package/content/knowledge/game/game-accessibility.md +328 -0
  3. package/content/knowledge/game/game-ai-patterns.md +542 -0
  4. package/content/knowledge/game/game-asset-pipeline.md +359 -0
  5. package/content/knowledge/game/game-audio-design.md +342 -0
  6. package/content/knowledge/game/game-binary-vcs-strategy.md +396 -0
  7. package/content/knowledge/game/game-design-document.md +260 -0
  8. package/content/knowledge/game/game-domain-patterns.md +297 -0
  9. package/content/knowledge/game/game-economy-design.md +355 -0
  10. package/content/knowledge/game/game-engine-selection.md +242 -0
  11. package/content/knowledge/game/game-input-systems.md +357 -0
  12. package/content/knowledge/game/game-level-content-design.md +455 -0
  13. package/content/knowledge/game/game-liveops-analytics.md +280 -0
  14. package/content/knowledge/game/game-localization.md +323 -0
  15. package/content/knowledge/game/game-milestone-definitions.md +337 -0
  16. package/content/knowledge/game/game-modding-ugc.md +390 -0
  17. package/content/knowledge/game/game-narrative-design.md +404 -0
  18. package/content/knowledge/game/game-networking.md +391 -0
  19. package/content/knowledge/game/game-performance-budgeting.md +378 -0
  20. package/content/knowledge/game/game-platform-certification.md +417 -0
  21. package/content/knowledge/game/game-project-structure.md +360 -0
  22. package/content/knowledge/game/game-save-systems.md +452 -0
  23. package/content/knowledge/game/game-testing-strategy.md +470 -0
  24. package/content/knowledge/game/game-ui-patterns.md +475 -0
  25. package/content/knowledge/game/game-vr-ar-design.md +313 -0
  26. package/content/knowledge/review/review-art-bible.md +305 -0
  27. package/content/knowledge/review/review-game-design.md +303 -0
  28. package/content/knowledge/review/review-game-economy.md +272 -0
  29. package/content/knowledge/review/review-netcode.md +280 -0
  30. package/content/knowledge/review/review-platform-cert.md +341 -0
  31. package/content/methodology/custom-defaults.yml +25 -0
  32. package/content/methodology/deep.yml +25 -0
  33. package/content/methodology/game-overlay.yml +145 -0
  34. package/content/methodology/mvp.yml +25 -0
  35. package/content/pipeline/architecture/ai-behavior-design.md +87 -0
  36. package/content/pipeline/architecture/netcode-spec.md +86 -0
  37. package/content/pipeline/architecture/review-netcode.md +78 -0
  38. package/content/pipeline/foundation/performance-budgets.md +91 -0
  39. package/content/pipeline/modeling/narrative-bible.md +84 -0
  40. package/content/pipeline/pre/game-design-document.md +89 -0
  41. package/content/pipeline/pre/review-gdd.md +74 -0
  42. package/content/pipeline/quality/analytics-telemetry.md +98 -0
  43. package/content/pipeline/quality/live-ops-plan.md +99 -0
  44. package/content/pipeline/quality/platform-cert-prep.md +129 -0
  45. package/content/pipeline/quality/playtest-plan.md +83 -0
  46. package/content/pipeline/specification/art-bible.md +87 -0
  47. package/content/pipeline/specification/audio-design.md +96 -0
  48. package/content/pipeline/specification/content-structure-design.md +141 -0
  49. package/content/pipeline/specification/economy-design.md +104 -0
  50. package/content/pipeline/specification/game-accessibility.md +82 -0
  51. package/content/pipeline/specification/game-ui-spec.md +97 -0
  52. package/content/pipeline/specification/input-controls-spec.md +81 -0
  53. package/content/pipeline/specification/localization-plan.md +113 -0
  54. package/content/pipeline/specification/modding-ugc-spec.md +116 -0
  55. package/content/pipeline/specification/online-services-spec.md +104 -0
  56. package/content/pipeline/specification/review-economy.md +87 -0
  57. package/content/pipeline/specification/review-game-ui.md +73 -0
  58. package/content/pipeline/specification/save-system-spec.md +116 -0
  59. package/dist/cli/commands/adopt.d.ts.map +1 -1
  60. package/dist/cli/commands/adopt.js +25 -0
  61. package/dist/cli/commands/adopt.js.map +1 -1
  62. package/dist/cli/commands/adopt.test.js +28 -1
  63. package/dist/cli/commands/adopt.test.js.map +1 -1
  64. package/dist/cli/commands/build.test.js +3 -0
  65. package/dist/cli/commands/build.test.js.map +1 -1
  66. package/dist/cli/commands/init.d.ts +1 -0
  67. package/dist/cli/commands/init.d.ts.map +1 -1
  68. package/dist/cli/commands/init.js +6 -0
  69. package/dist/cli/commands/init.js.map +1 -1
  70. package/dist/cli/commands/init.test.js +12 -1
  71. package/dist/cli/commands/init.test.js.map +1 -1
  72. package/dist/cli/commands/knowledge.test.js +8 -0
  73. package/dist/cli/commands/knowledge.test.js.map +1 -1
  74. package/dist/cli/commands/next.d.ts.map +1 -1
  75. package/dist/cli/commands/next.js +19 -5
  76. package/dist/cli/commands/next.js.map +1 -1
  77. package/dist/cli/commands/next.test.js +56 -0
  78. package/dist/cli/commands/next.test.js.map +1 -1
  79. package/dist/cli/commands/rework.d.ts.map +1 -1
  80. package/dist/cli/commands/rework.js +11 -2
  81. package/dist/cli/commands/rework.js.map +1 -1
  82. package/dist/cli/commands/rework.test.js +5 -0
  83. package/dist/cli/commands/rework.test.js.map +1 -1
  84. package/dist/cli/commands/run.d.ts.map +1 -1
  85. package/dist/cli/commands/run.js +54 -4
  86. package/dist/cli/commands/run.js.map +1 -1
  87. package/dist/cli/commands/run.test.js +384 -0
  88. package/dist/cli/commands/run.test.js.map +1 -1
  89. package/dist/cli/commands/skip.test.js +3 -0
  90. package/dist/cli/commands/skip.test.js.map +1 -1
  91. package/dist/cli/commands/status.d.ts.map +1 -1
  92. package/dist/cli/commands/status.js +16 -3
  93. package/dist/cli/commands/status.js.map +1 -1
  94. package/dist/cli/commands/status.test.js +55 -0
  95. package/dist/cli/commands/status.test.js.map +1 -1
  96. package/dist/cli/output/auto.d.ts +3 -0
  97. package/dist/cli/output/auto.d.ts.map +1 -1
  98. package/dist/cli/output/auto.js +9 -0
  99. package/dist/cli/output/auto.js.map +1 -1
  100. package/dist/cli/output/context.d.ts +6 -0
  101. package/dist/cli/output/context.d.ts.map +1 -1
  102. package/dist/cli/output/context.js.map +1 -1
  103. package/dist/cli/output/context.test.js +87 -0
  104. package/dist/cli/output/context.test.js.map +1 -1
  105. package/dist/cli/output/error-display.test.js +3 -0
  106. package/dist/cli/output/error-display.test.js.map +1 -1
  107. package/dist/cli/output/interactive.d.ts +3 -0
  108. package/dist/cli/output/interactive.d.ts.map +1 -1
  109. package/dist/cli/output/interactive.js +76 -0
  110. package/dist/cli/output/interactive.js.map +1 -1
  111. package/dist/cli/output/json.d.ts +3 -0
  112. package/dist/cli/output/json.d.ts.map +1 -1
  113. package/dist/cli/output/json.js +9 -0
  114. package/dist/cli/output/json.js.map +1 -1
  115. package/dist/config/loader.d.ts.map +1 -1
  116. package/dist/config/loader.js +3 -2
  117. package/dist/config/loader.js.map +1 -1
  118. package/dist/config/schema.d.ts +641 -15
  119. package/dist/config/schema.d.ts.map +1 -1
  120. package/dist/config/schema.js +26 -1
  121. package/dist/config/schema.js.map +1 -1
  122. package/dist/config/schema.test.js +192 -1
  123. package/dist/config/schema.test.js.map +1 -1
  124. package/dist/core/assembly/overlay-loader.d.ts +24 -0
  125. package/dist/core/assembly/overlay-loader.d.ts.map +1 -0
  126. package/dist/core/assembly/overlay-loader.js +190 -0
  127. package/dist/core/assembly/overlay-loader.js.map +1 -0
  128. package/dist/core/assembly/overlay-loader.test.d.ts +2 -0
  129. package/dist/core/assembly/overlay-loader.test.d.ts.map +1 -0
  130. package/dist/core/assembly/overlay-loader.test.js +106 -0
  131. package/dist/core/assembly/overlay-loader.test.js.map +1 -0
  132. package/dist/core/assembly/overlay-resolver.d.ts +15 -0
  133. package/dist/core/assembly/overlay-resolver.d.ts.map +1 -0
  134. package/dist/core/assembly/overlay-resolver.js +58 -0
  135. package/dist/core/assembly/overlay-resolver.js.map +1 -0
  136. package/dist/core/assembly/overlay-resolver.test.d.ts +2 -0
  137. package/dist/core/assembly/overlay-resolver.test.d.ts.map +1 -0
  138. package/dist/core/assembly/overlay-resolver.test.js +246 -0
  139. package/dist/core/assembly/overlay-resolver.test.js.map +1 -0
  140. package/dist/core/assembly/overlay-state-resolver.d.ts +26 -0
  141. package/dist/core/assembly/overlay-state-resolver.d.ts.map +1 -0
  142. package/dist/core/assembly/overlay-state-resolver.js +63 -0
  143. package/dist/core/assembly/overlay-state-resolver.js.map +1 -0
  144. package/dist/core/assembly/overlay-state-resolver.test.d.ts +2 -0
  145. package/dist/core/assembly/overlay-state-resolver.test.d.ts.map +1 -0
  146. package/dist/core/assembly/overlay-state-resolver.test.js +256 -0
  147. package/dist/core/assembly/overlay-state-resolver.test.js.map +1 -0
  148. package/dist/core/assembly/preset-loader.d.ts +1 -0
  149. package/dist/core/assembly/preset-loader.d.ts.map +1 -1
  150. package/dist/core/assembly/preset-loader.js +2 -0
  151. package/dist/core/assembly/preset-loader.js.map +1 -1
  152. package/dist/core/dependency/eligibility.test.js +3 -0
  153. package/dist/core/dependency/eligibility.test.js.map +1 -1
  154. package/dist/e2e/game-pipeline.test.d.ts +10 -0
  155. package/dist/e2e/game-pipeline.test.d.ts.map +1 -0
  156. package/dist/e2e/game-pipeline.test.js +298 -0
  157. package/dist/e2e/game-pipeline.test.js.map +1 -0
  158. package/dist/e2e/init.test.js +3 -0
  159. package/dist/e2e/init.test.js.map +1 -1
  160. package/dist/project/adopt.d.ts +3 -1
  161. package/dist/project/adopt.d.ts.map +1 -1
  162. package/dist/project/adopt.js +29 -1
  163. package/dist/project/adopt.js.map +1 -1
  164. package/dist/project/adopt.test.js +51 -1
  165. package/dist/project/adopt.test.js.map +1 -1
  166. package/dist/types/config.d.ts +50 -4
  167. package/dist/types/config.d.ts.map +1 -1
  168. package/dist/types/config.test.d.ts +2 -0
  169. package/dist/types/config.test.d.ts.map +1 -0
  170. package/dist/types/config.test.js +97 -0
  171. package/dist/types/config.test.js.map +1 -0
  172. package/dist/utils/eligible.d.ts +3 -2
  173. package/dist/utils/eligible.d.ts.map +1 -1
  174. package/dist/utils/eligible.js +18 -4
  175. package/dist/utils/eligible.js.map +1 -1
  176. package/dist/utils/errors.d.ts +4 -0
  177. package/dist/utils/errors.d.ts.map +1 -1
  178. package/dist/utils/errors.js +31 -0
  179. package/dist/utils/errors.js.map +1 -1
  180. package/dist/utils/errors.test.js +4 -1
  181. package/dist/utils/errors.test.js.map +1 -1
  182. package/dist/wizard/questions.d.ts +4 -0
  183. package/dist/wizard/questions.d.ts.map +1 -1
  184. package/dist/wizard/questions.js +59 -1
  185. package/dist/wizard/questions.js.map +1 -1
  186. package/dist/wizard/questions.test.js +178 -4
  187. package/dist/wizard/questions.test.js.map +1 -1
  188. package/dist/wizard/wizard.d.ts +1 -0
  189. package/dist/wizard/wizard.d.ts.map +1 -1
  190. package/dist/wizard/wizard.js +4 -1
  191. package/dist/wizard/wizard.js.map +1 -1
  192. package/dist/wizard/wizard.test.js +102 -4
  193. package/dist/wizard/wizard.test.js.map +1 -1
  194. package/package.json +1 -1
@@ -0,0 +1,391 @@
1
+ ---
2
+ name: game-networking
3
+ description: Client-server and P2P architectures, tick rates, client prediction, server reconciliation, lag compensation, and anti-cheat
4
+ topics: [game-dev, networking, netcode, multiplayer, prediction, reconciliation]
5
+ ---
6
+
7
+ Game networking is fundamentally different from web or API networking because it must maintain a shared simulation across multiple machines with divergent latencies, all while feeling instantaneous to each player. The core tension is between responsiveness (the player's actions feel immediate) and authority (the server is the source of truth). Every multiplayer game exists on a spectrum between these two poles, and the netcode architecture determines where on that spectrum the game sits. Getting this wrong produces unplayable results — rubber-banding, ghost hits, desync, and exploitable clients.
8
+
9
+ ## Summary
10
+
11
+ ### Architecture Models
12
+
13
+ **Client-Server (Dedicated Server):**
14
+ - One authoritative server runs the simulation; clients send inputs and receive state
15
+ - Server validates all actions — clients cannot cheat by modifying their local state
16
+ - Latency is client-to-server round trip (typically 20–150 ms)
17
+ - Requires server infrastructure (cost scales with concurrent players)
18
+ - Standard for competitive multiplayer, MMOs, and any game where cheating matters
19
+
20
+ **Client-Server (Listen Server):**
21
+ - One player's machine acts as both client and server
22
+ - That player has zero latency advantage (host advantage)
23
+ - No infrastructure cost but poor experience for non-host players with high latency to host
24
+ - Common in casual co-op, LAN games, console party games
25
+
26
+ **Peer-to-Peer (P2P):**
27
+ - Each client communicates directly with every other client
28
+ - No central authority — consensus or lockstep determines game state
29
+ - NAT traversal is a major challenge; relay fallback is usually required
30
+ - Bandwidth scales with O(n^2) connections instead of O(n) for client-server
31
+ - Used in fighting games (GGPO/rollback), RTS (lockstep), and some racing games
32
+
33
+ ### Tick Rate Selection
34
+
35
+ The server tick rate determines how frequently the server processes inputs and sends state updates:
36
+
37
+ - **128 Hz** (7.8 ms): Competitive FPS (Counter-Strike 2, Valorant). High CPU cost, high bandwidth.
38
+ - **60 Hz** (16.67 ms): Standard for action games, battle royale. Good responsiveness, moderate cost.
39
+ - **30 Hz** (33.33 ms): Acceptable for slower-paced games (RPGs, survival, strategy). Lower cost.
40
+ - **20 Hz** (50 ms): Common for MMOs with large player counts. Noticeable lag in fast combat.
41
+ - **10 Hz** (100 ms): Turn-based or very slow-paced games. Minimal server load.
42
+
43
+ Higher tick rates reduce the gap between what the player sees and what the server knows, but multiply bandwidth and CPU cost linearly. Choose the lowest tick rate that feels acceptable for the game's genre and combat pacing.
44
+
45
+ ### Client Prediction and Server Reconciliation
46
+
47
+ Client prediction makes the game feel responsive despite network latency. The client immediately applies the player's input locally without waiting for server confirmation. When the server responds with the authoritative state, the client reconciles any differences.
48
+
49
+ **Prediction workflow:**
50
+ 1. Player presses move-forward at client frame 100
51
+ 2. Client immediately applies movement locally (predicted state)
52
+ 3. Client sends input to server with timestamp/frame number
53
+ 4. Server processes input, calculates authoritative result
54
+ 5. Server sends authoritative state back to client
55
+ 6. Client compares predicted state at that frame with server state
56
+ 7. If they match: prediction was correct, no correction needed
57
+ 8. If they differ: client snaps or interpolates to server state (reconciliation)
58
+
59
+ ### Lag Compensation
60
+
61
+ Lag compensation allows the server to evaluate hit detection from the shooter's perspective at the time they fired, accounting for their network latency. Without it, players must "lead" their targets by the amount of their ping, which feels terrible.
62
+
63
+ The server rewinds the game state to the timestamp of the shot, performs the hit check against historical positions, and applies the result. This can cause "I was already behind cover but still got hit" situations for the target — the tradeoff favors the shooter's experience.
64
+
65
+ ## Deep Guidance
66
+
67
+ ### Client-Server Architecture in Detail
68
+
69
+ ```typescript
70
+ // Simplified server-authoritative game loop
71
+
72
+ interface PlayerInput {
73
+ sequenceNumber: number; // Monotonically increasing per client
74
+ timestamp: number; // Client-side timestamp for lag compensation
75
+ moveDirection: { x: number; y: number };
76
+ actions: string[]; // "fire", "jump", "reload", etc.
77
+ }
78
+
79
+ interface ServerState {
80
+ tick: number;
81
+ entities: Map<string, EntityState>;
82
+ }
83
+
84
+ interface EntityState {
85
+ position: { x: number; y: number; z: number };
86
+ velocity: { x: number; y: number; z: number };
87
+ health: number;
88
+ animation: string;
89
+ }
90
+
91
+ // --- SERVER SIDE ---
92
+
93
+ class GameServer {
94
+ private tickRate = 60;
95
+ private tickInterval = 1000 / this.tickRate;
96
+ private currentTick = 0;
97
+ private stateHistory: ServerState[] = []; // For lag compensation
98
+ private inputQueues: Map<string, PlayerInput[]> = new Map();
99
+
100
+ tick(): void {
101
+ this.currentTick++;
102
+
103
+ // 1. Process buffered inputs from all clients
104
+ for (const [playerId, inputs] of this.inputQueues) {
105
+ for (const input of inputs) {
106
+ this.applyInput(playerId, input);
107
+ }
108
+ inputs.length = 0; // Clear processed inputs
109
+ }
110
+
111
+ // 2. Run simulation (physics, AI, game logic)
112
+ this.simulate(this.tickInterval / 1000);
113
+
114
+ // 3. Store state snapshot for lag compensation
115
+ this.stateHistory.push(this.captureState());
116
+ if (this.stateHistory.length > this.tickRate * 2) {
117
+ this.stateHistory.shift(); // Keep ~2 seconds of history
118
+ }
119
+
120
+ // 4. Send authoritative state to all clients
121
+ this.broadcastState();
122
+ }
123
+
124
+ handleFireAction(shooterId: string, input: PlayerInput): void {
125
+ // Lag compensation: rewind to the shooter's perceived time
126
+ const rtt = this.getClientRTT(shooterId);
127
+ const rewindTicks = Math.round((rtt / 2) / this.tickInterval);
128
+ const historicalState = this.stateHistory[
129
+ Math.max(0, this.stateHistory.length - 1 - rewindTicks)
130
+ ];
131
+
132
+ // Perform hit detection against historical positions
133
+ const hit = this.raycast(
134
+ historicalState,
135
+ shooterId,
136
+ input.moveDirection
137
+ );
138
+
139
+ if (hit) {
140
+ // Apply damage in current (not historical) state
141
+ this.applyDamage(hit.entityId, this.getWeaponDamage(shooterId));
142
+ }
143
+ }
144
+
145
+ // ... additional methods omitted for brevity
146
+ private applyInput(id: string, input: PlayerInput): void { /* ... */ }
147
+ private simulate(dt: number): void { /* ... */ }
148
+ private captureState(): ServerState {
149
+ return { tick: this.currentTick, entities: new Map() };
150
+ }
151
+ private broadcastState(): void { /* ... */ }
152
+ private getClientRTT(id: string): number { return 0; }
153
+ private raycast(state: ServerState, id: string, dir: any): any { return null; }
154
+ private applyDamage(id: string, dmg: number): void { /* ... */ }
155
+ private getWeaponDamage(id: string): number { return 0; }
156
+ }
157
+
158
+ // --- CLIENT SIDE ---
159
+
160
+ class GameClient {
161
+ private pendingInputs: PlayerInput[] = [];
162
+ private sequenceNumber = 0;
163
+ private localState: EntityState;
164
+
165
+ processLocalInput(raw: RawInput): void {
166
+ const input: PlayerInput = {
167
+ sequenceNumber: this.sequenceNumber++,
168
+ timestamp: Date.now(),
169
+ moveDirection: raw.moveDirection,
170
+ actions: raw.actions,
171
+ };
172
+
173
+ // Predict: apply input locally immediately
174
+ this.localState = this.applyInputToState(this.localState, input);
175
+
176
+ // Store for reconciliation
177
+ this.pendingInputs.push(input);
178
+
179
+ // Send to server
180
+ this.sendToServer(input);
181
+ }
182
+
183
+ onServerState(serverState: EntityState, lastProcessedSeq: number): void {
184
+ // Discard inputs the server has already processed
185
+ this.pendingInputs = this.pendingInputs.filter(
186
+ i => i.sequenceNumber > lastProcessedSeq
187
+ );
188
+
189
+ // Start from server-authoritative state
190
+ let reconciledState = { ...serverState };
191
+
192
+ // Re-apply unprocessed inputs on top of server state
193
+ for (const input of this.pendingInputs) {
194
+ reconciledState = this.applyInputToState(reconciledState, input);
195
+ }
196
+
197
+ // Smooth correction: interpolate toward reconciled state
198
+ this.localState = this.smoothCorrection(
199
+ this.localState,
200
+ reconciledState,
201
+ 0.2 // Blend factor — higher = snappier, lower = smoother
202
+ );
203
+ }
204
+
205
+ private applyInputToState(
206
+ state: EntityState, input: PlayerInput
207
+ ): EntityState {
208
+ return { ...state }; // Placeholder
209
+ }
210
+ private sendToServer(input: PlayerInput): void { /* ... */ }
211
+ private smoothCorrection(
212
+ current: EntityState, target: EntityState, blend: number
213
+ ): EntityState {
214
+ return { ...target }; // Placeholder — real impl lerps position
215
+ }
216
+ }
217
+
218
+ interface RawInput {
219
+ moveDirection: { x: number; y: number };
220
+ actions: string[];
221
+ }
222
+ ```
223
+
224
+ ### Entity Interpolation
225
+
226
+ Clients receive server state updates at the tick rate (e.g., 60 Hz), but render at the display's refresh rate (e.g., 144 Hz). Between server updates, remote entities must be interpolated to appear smooth.
227
+
228
+ **Interpolation** (rendering slightly in the past):
229
+ - Buffer the two most recent server states for each remote entity
230
+ - Render the entity at a position interpolated between these two states
231
+ - Introduces additional visual latency equal to one server tick (16.67 ms at 60 Hz)
232
+ - Produces smooth, glitch-free movement for remote entities
233
+
234
+ **Extrapolation** (predicting the future based on last known velocity):
235
+ - Uses the last known position and velocity to project forward
236
+ - No additional visual latency
237
+ - Produces jittery or incorrect results when entities change direction
238
+ - Should be used as a fallback when interpolation data is missing (packet loss)
239
+
240
+ Most games use interpolation for remote entities and prediction for the local player.
241
+
242
+ ### Bandwidth Optimization
243
+
244
+ Multiplayer games are bandwidth-constrained, especially on mobile networks and in games with many simultaneous players.
245
+
246
+ **Delta compression:**
247
+ - Send only what changed since the last acknowledged state, not the full state every tick
248
+ - A 1000-entity state might be 50 KB full, but only 2 KB as a delta if few entities moved
249
+ - Requires reliable delivery of the baseline state and tracking of per-client acknowledgment
250
+
251
+ **Quantization:**
252
+ - Reduce precision of transmitted values: positions to centimeter precision (16-bit per axis instead of 32-bit float), rotations to 10-bit per axis using smallest-three encoding
253
+ - A float is 4 bytes; a 10-bit quantized value is ~1.25 bytes — 3x savings per value
254
+ - Quantization must match on client and server to avoid desync
255
+
256
+ **Interest management / relevance filtering:**
257
+ - Do not send state for entities the player cannot perceive
258
+ - Divide the world into spatial cells; send updates only for cells near the player
259
+ - MMOs with thousands of players depend entirely on aggressive relevance filtering
260
+ - Prioritize: nearby entities get full tick rate updates; distant entities get updates every 2–4 ticks
261
+
262
+ **Bit packing:**
263
+ - Pack boolean flags and small enums into individual bits rather than full bytes
264
+ - A weapon type enum with 8 values needs 3 bits, not 32
265
+ - Use a bitstream writer/reader that tracks bit position within a byte buffer
266
+
267
+ ### NAT Traversal
268
+
269
+ Players behind routers with NAT (Network Address Translation) cannot receive incoming connections by default. P2P games and listen servers must solve this.
270
+
271
+ **NAT traversal techniques (in order of preference):**
272
+ 1. **STUN (Session Traversal Utilities for NAT)**: Asks a public STUN server to discover the client's public IP and port mapping. Works for most consumer NATs (cone NAT types).
273
+ 2. **TURN (Traversal Using Relays around NAT)**: Falls back to relaying traffic through a public server. Always works, but adds latency and server bandwidth cost. Essentially becomes client-server.
274
+ 3. **UDP hole punching**: Both clients simultaneously send packets to each other's discovered public endpoint. The NAT creates a mapping for the outgoing packet, allowing the incoming packet through. Requires a signaling server to coordinate.
275
+ 4. **Relay fallback**: If all else fails, route traffic through a dedicated relay. Steam Networking, Epic Online Services, and Xbox Live all provide relay infrastructure.
276
+
277
+ Steam's networking API (SteamNetworkingSockets) and Epic's EOS transport handle NAT traversal transparently. Using these saves months of implementation work.
278
+
279
+ ### Anti-Cheat Architecture
280
+
281
+ Anti-cheat operates at two levels: server-side validation (essential) and client-side detection (supplementary).
282
+
283
+ **Server-side validation (non-negotiable):**
284
+ - Never trust the client. The client sends inputs, not results.
285
+ - Validate movement speed: if a player moved 100 units in one tick but max speed is 10 units/tick, reject the input
286
+ - Validate fire rate: if a weapon fires every 500 ms and two shots arrive 100 ms apart, reject the second
287
+ - Validate resource changes: if the client claims to have gained 1000 gold, verify the server's economy simulation agrees
288
+ - Validate line-of-sight for hit registration: a player behind a wall cannot hit someone on the other side
289
+
290
+ **Client-side detection (supplementary):**
291
+ - Memory scanning for known cheat signatures (aimbots, wallhacks, speed hacks)
292
+ - Integrity checking of game binaries and loaded DLLs
293
+ - Screenshot or frame capture for manual review
294
+ - Kernel-level anti-cheat drivers (EAC, BattlEye, Vanguard) for competitive titles
295
+ - Client-side detection is always bypassable given enough effort — it raises the bar, not the ceiling
296
+
297
+ **Architectural anti-cheat patterns:**
298
+ - **Fog of war / server-side culling**: Do not send positions of enemies the player cannot see. A wallhack cannot display what the client never received.
299
+ - **Server-side hit detection**: Never let the client report "I hit player X for Y damage." The server performs the raycast.
300
+ - **Rate limiting**: Cap the rate of any client action to match game design limits. Even if the client sends garbage inputs, the server processes at most one action per allowed interval.
301
+ - **Statistical anomaly detection**: Track per-player accuracy, headshot ratio, reaction time, and movement patterns. Flag statistical outliers for review. A 95% headshot accuracy in an FPS is not human.
302
+
303
+ ### Lockstep Networking (RTS / Fighting Games)
304
+
305
+ Lockstep is an alternative to client-server prediction that is deterministic: all clients run the same simulation with the same inputs and arrive at the same state.
306
+
307
+ **How it works:**
308
+ 1. Each client sends their inputs to all other clients (or via a relay)
309
+ 2. No client advances to the next simulation frame until all inputs for that frame are received
310
+ 3. Because the simulation is deterministic, all clients compute identical state without needing to send state at all
311
+ 4. Only inputs are sent — bandwidth is minimal regardless of entity count
312
+
313
+ **Requirements:**
314
+ - The simulation must be perfectly deterministic: same inputs must produce bit-identical outputs on all platforms
315
+ - Floating-point determinism is extremely hard across different CPUs and compilers — many lockstep games use fixed-point math
316
+ - A single desync (one client computes a different result) is catastrophic — desyncs must be detected (via state hash comparison) and recovered from (resync or disconnect)
317
+
318
+ **Rollback networking (GGPO):**
319
+ - Used primarily in fighting games (Street Fighter, Guilty Gear, MultiVersus)
320
+ - Clients predict remote player inputs (usually "same as last frame")
321
+ - If the prediction was wrong, the game rolls back to the last confirmed state, re-applies corrected inputs, and fast-forwards to the current frame
322
+ - Produces very low-latency feel (no waiting for remote inputs) at the cost of occasional visual corrections
323
+ - Requires the simulation to be cheaply restorable to previous states (snapshot + replay)
324
+
325
+ ### Social Layer and Matchmaking
326
+
327
+ The networking layer splits into two distinct concerns: low-level netcode (above) and high-level social/matchmaking services.
328
+
329
+ **Matchmaking architecture:**
330
+ - **Skill rating**: ELO, Glicko-2, TrueSkill, or custom MMR systems. Track mean skill and uncertainty separately. Decay rating for inactive players.
331
+ - **Queue management**: Accept players into a queue, form matches when enough players of similar skill are available. Widen the skill window over wait time to avoid infinite queues.
332
+ - **Region selection**: Match players within the same geographic region to minimize latency. Allow region override for players willing to accept higher ping for faster matches.
333
+ - **Party handling**: Parties must be matched together. Average party MMR vs highest-member MMR depends on game design. Pre-made teams should preferentially match against other pre-mades.
334
+
335
+ **Lobby and session management:**
336
+ - Use a service (Steam, EOS, PlayFab, GameLift) rather than building custom. Session management is complex (host migration, join-in-progress, backfill) and solved by existing platforms.
337
+ - Implement host migration for listen-server games: if the host disconnects, the session must seamlessly transfer authority to another player.
338
+ - Handle join-in-progress carefully: the joining player needs the full current game state, which must be serialized and transmitted without disrupting the game for existing players.
339
+
340
+ ### Bandwidth Budget Example
341
+
342
+ ```yaml
343
+ # Bandwidth budget for a 20-player battle royale at 30 Hz tick rate
344
+ # Per-player downstream (server -> client)
345
+
346
+ per_entity_update:
347
+ position: 6 bytes # 3 axes * 16-bit quantized
348
+ rotation: 4 bytes # Smallest-three quaternion, 10-bit per component
349
+ velocity: 6 bytes # 3 axes * 16-bit quantized
350
+ health: 1 byte # 0-255 mapped to 0-100%
351
+ animation_id: 2 bytes # Current animation state
352
+ flags: 1 byte # Crouching, sprinting, aiming, etc.
353
+ total: 20 bytes
354
+
355
+ entities_in_relevance: 15 # Nearby players (not all 20)
356
+ updates_per_second: 30 # Tick rate
357
+ delta_ratio: 0.4 # ~40% of entities change per tick
358
+
359
+ downstream_per_second:
360
+ entity_data: 15 * 20 * 30 * 0.4 = 3,600 bytes = 3.5 KB/s
361
+ game_events: ~1 KB/s # Damage, pickups, zone changes
362
+ overhead: ~0.5 KB/s # Packet headers, ack, padding
363
+ total: ~5 KB/s per player
364
+
365
+ upstream_per_second:
366
+ player_input: ~1.5 KB/s # Input at 60 Hz client, quantized
367
+ ack_and_meta: ~0.5 KB/s
368
+ total: ~2 KB/s per player
369
+
370
+ server_total_bandwidth:
371
+ downstream: 5 KB/s * 20 = 100 KB/s = ~0.8 Mbps
372
+ upstream: 2 KB/s * 20 = 40 KB/s = ~0.3 Mbps
373
+ # Very manageable — bandwidth only becomes a concern at 100+ players
374
+ ```
375
+
376
+ ### Network Testing and Simulation
377
+
378
+ Never test multiplayer only on localhost. Real networks have latency, jitter, and packet loss.
379
+
380
+ **Network condition simulation:**
381
+ - Use `tc` (Linux traffic control), `clumsy` (Windows), or Network Link Conditioner (macOS/iOS) to add artificial latency, jitter, and packet loss
382
+ - Test profiles: LAN (1 ms, 0% loss), broadband (30 ms, 0.1% loss), average (80 ms, 1% loss), poor (150 ms, 3% loss), mobile (200 ms, 5% loss, high jitter)
383
+ - Run automated multiplayer playtests with bots under each profile
384
+ - Measure desync rate, rubber-banding frequency, and hit registration accuracy under each condition
385
+
386
+ **Minimum test matrix:**
387
+ - 2 players on localhost (baseline correctness)
388
+ - 2 players with 100 ms simulated RTT (typical online)
389
+ - Full lobby with 150 ms + 2% loss (stress test)
390
+ - One player with intermittent disconnects (reconnection handling)
391
+ - Host migration (for listen-server games) — kill the host process mid-game