@gamerstake/game-core 0.1.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 (48) hide show
  1. package/.eslintrc.json +22 -0
  2. package/.testing-guide-summary.md +261 -0
  3. package/DEVELOPER_GUIDE.md +996 -0
  4. package/MANUAL_TESTING.md +369 -0
  5. package/QUICK_START.md +368 -0
  6. package/README.md +379 -0
  7. package/TESTING_OVERVIEW.md +378 -0
  8. package/dist/index.d.ts +1266 -0
  9. package/dist/index.js +1632 -0
  10. package/dist/index.js.map +1 -0
  11. package/examples/simple-game/README.md +176 -0
  12. package/examples/simple-game/client.ts +201 -0
  13. package/examples/simple-game/package.json +14 -0
  14. package/examples/simple-game/server.ts +233 -0
  15. package/jest.config.ts +39 -0
  16. package/package.json +54 -0
  17. package/src/core/GameLoop.ts +214 -0
  18. package/src/core/GameRules.ts +103 -0
  19. package/src/core/GameServer.ts +200 -0
  20. package/src/core/Room.ts +368 -0
  21. package/src/entities/Entity.ts +118 -0
  22. package/src/entities/Registry.ts +161 -0
  23. package/src/index.ts +51 -0
  24. package/src/input/Command.ts +41 -0
  25. package/src/input/InputQueue.ts +130 -0
  26. package/src/network/Network.ts +112 -0
  27. package/src/network/Snapshot.ts +59 -0
  28. package/src/physics/AABB.ts +104 -0
  29. package/src/physics/Movement.ts +124 -0
  30. package/src/spatial/Grid.ts +202 -0
  31. package/src/types/index.ts +117 -0
  32. package/src/types/protocol.ts +161 -0
  33. package/src/utils/Logger.ts +112 -0
  34. package/src/utils/RingBuffer.ts +116 -0
  35. package/tests/AABB.test.ts +38 -0
  36. package/tests/Entity.test.ts +35 -0
  37. package/tests/GameLoop.test.ts +58 -0
  38. package/tests/GameServer.test.ts +64 -0
  39. package/tests/Grid.test.ts +28 -0
  40. package/tests/InputQueue.test.ts +42 -0
  41. package/tests/Movement.test.ts +37 -0
  42. package/tests/Network.test.ts +39 -0
  43. package/tests/Registry.test.ts +36 -0
  44. package/tests/RingBuffer.test.ts +38 -0
  45. package/tests/Room.test.ts +80 -0
  46. package/tests/Snapshot.test.ts +19 -0
  47. package/tsconfig.json +28 -0
  48. package/tsup.config.ts +14 -0
@@ -0,0 +1,369 @@
1
+ # Manual Testing Guide
2
+
3
+ This guide explains how to manually test the `@gamerstake/game-core` package with a live server and clients.
4
+
5
+ ## Why Manual Testing?
6
+
7
+ While automated tests verify individual components, **manual testing lets you**:
8
+
9
+ See the game engine running in real-time
10
+ Test networking and state synchronization
11
+ Monitor performance metrics
12
+ Simulate real player behavior
13
+ Debug issues interactively
14
+
15
+ ## Quick Start
16
+
17
+ ### Step 1: Build the Package
18
+
19
+ ```bash
20
+ cd /Users/nbjekovic/GAMESTAKES/gamerstake/packages/game-core
21
+ pnpm build
22
+ ```
23
+
24
+ ### Step 2: Start the Test Server
25
+
26
+ ```bash
27
+ node examples/simple-game/server.js
28
+ ```
29
+
30
+ **Expected output:**
31
+
32
+ ```
33
+ Game server started on port 3000
34
+ Room: test-room
35
+ Tick rate: 20 TPS
36
+
37
+ Connect with: node examples/simple-game/client.js
38
+ ```
39
+
40
+ The server:
41
+
42
+ - Runs a game loop at **20 TPS** (50ms per tick)
43
+ - Creates a persistent world (1000x1000 units)
44
+ - Spawns 5 random obstacle entities
45
+ - Logs player activity and metrics
46
+
47
+ ### Step 3: Connect Clients
48
+
49
+ **In a new terminal:**
50
+
51
+ ```bash
52
+ node examples/simple-game/client.js
53
+ ```
54
+
55
+ **Expected output:**
56
+
57
+ ```
58
+ Connecting to server: http://localhost:3000
59
+ Connected! Socket ID: abc123
60
+ Initialized! Player ID: abc123
61
+ Initial entities: 6
62
+ You are at (542, 789)
63
+
64
+ Starting movement test...
65
+
66
+ Moving right
67
+ Position: (592, 789) | Velocity: (200, 0) | Total entities: 6
68
+ Moving down
69
+ Position: (592, 839) | Velocity: (0, 200) | Total entities: 6
70
+ ```
71
+
72
+ The client:
73
+
74
+ - Connects to the server
75
+ - Receives initial game state
76
+ - **Automatically moves in patterns** (right, down, left, up, diagonal)
77
+ - Logs position updates every 20 ticks
78
+ - Demonstrates all command types (move, stop, action)
79
+
80
+ ### Step 4: Test with Multiple Clients
81
+
82
+ **Open 3-4 more terminals and run:**
83
+
84
+ ```bash
85
+ node examples/simple-game/client.js # Terminal 3
86
+ node examples/simple-game/client.js # Terminal 4
87
+ node examples/simple-game/client.js # Terminal 5
88
+ ```
89
+
90
+ **On the server, you'll see:**
91
+
92
+ ```
93
+ Socket connected: def456
94
+ Player def456 joined at (234, 567)
95
+ Player def456 joined at (234, 567)
96
+
97
+ Socket connected: ghi789
98
+ Player ghi789 joined at (890, 123)
99
+ ```
100
+
101
+ ## What to Observe
102
+
103
+ ### On the Server Side
104
+
105
+ **Player Lifecycle**
106
+
107
+ ```
108
+ Socket connected: <id>
109
+ Player <id> joined at (x, y)
110
+ Player <id> moving: (dx, dy)
111
+ ⏸ Player <id> stopped
112
+ Player <id> performed action: {"action":"jump","height":100}
113
+ Player <id> left
114
+ ```
115
+
116
+ **Performance Metrics** (every 10 seconds)
117
+
118
+ ```
119
+ Room: 3 players, 8 entities, Avg tick: 12.34ms
120
+ ```
121
+
122
+ **Good tick time:** < 40ms (80% of 50ms budget)
123
+ **Warning:** > 40ms means optimization needed
124
+ **Critical:** > 50ms means dropped frames
125
+
126
+ ### On the Client Side
127
+
128
+ **State Synchronization**
129
+
130
+ ```
131
+ Position: (100, 200) | Velocity: (200, 0) | Total entities: 8
132
+ ```
133
+
134
+ - Position updates smoothly as player moves
135
+ - Total entities increases as more players join
136
+ - Other players' positions are received in updates
137
+
138
+ **Multiplayer Events**
139
+
140
+ ```
141
+ Player def456 joined at (234, 567)
142
+ Player ghi789 performed action: jump
143
+ Player def456 left
144
+ ```
145
+
146
+ ## Testing Scenarios
147
+
148
+ ### Scenario 1: Basic Functionality
149
+
150
+ **Goal:** Verify core features work
151
+
152
+ 1. Start server
153
+ 2. Connect 1 client
154
+ 3. Watch client move automatically
155
+ 4. Verify position updates on both sides
156
+
157
+ **Expected:**
158
+
159
+ - Player spawns at random position
160
+ - Movement commands processed correctly
161
+ - State broadcasted every tick (50ms)
162
+
163
+ ### Scenario 2: Multiplayer
164
+
165
+ **Goal:** Test multiple players
166
+
167
+ 1. Start server
168
+ 2. Connect 3-5 clients simultaneously
169
+ 3. Watch all clients move in different patterns
170
+ 4. Stop one client (Ctrl+C), verify others continue
171
+
172
+ **Expected:**
173
+
174
+ - All players see each other
175
+ - State synchronized across clients
176
+ - Server handles disconnections gracefully
177
+ - No crashes or errors
178
+
179
+ ### Scenario 3: Performance
180
+
181
+ **Goal:** Verify performance under load
182
+
183
+ 1. Start server
184
+ 2. Connect 10+ clients
185
+ 3. Watch server metrics logs
186
+ 4. Monitor tick time
187
+
188
+ **Expected:**
189
+
190
+ - Tick time stays < 40ms
191
+ - No memory leaks over time
192
+ - Smooth updates for all clients
193
+
194
+ ### Scenario 4: Connection Stability
195
+
196
+ **Goal:** Test network reliability
197
+
198
+ 1. Start server with 2-3 clients
199
+ 2. Stop and restart a client
200
+ 3. Stop and restart the server
201
+ 4. Simulate poor network (if possible)
202
+
203
+ **Expected:**
204
+
205
+ - Clients reconnect successfully
206
+ - State resynchronized on reconnect
207
+ - Graceful error handling
208
+
209
+ ### Scenario 5: Commands
210
+
211
+ **Goal:** Verify input processing
212
+
213
+ The automated client cycles through:
214
+
215
+ - **Move commands** (right, down, left, up, diagonal)
216
+ - **Stop command** (velocity = 0)
217
+ - **Action command** (custom game event)
218
+
219
+ **Expected:**
220
+
221
+ - All command types processed
222
+ - Server logs show correct commands
223
+ - State updated accordingly
224
+
225
+ ## Customizing Tests
226
+
227
+ ### Change Server Port
228
+
229
+ ```bash
230
+ PORT=4000 node examples/simple-game/server.js
231
+ ```
232
+
233
+ ```bash
234
+ SERVER_URL=http://localhost:4000 node examples/simple-game/client.js
235
+ ```
236
+
237
+ ### Modify Client Behavior
238
+
239
+ Edit `examples/simple-game/client.ts` to:
240
+
241
+ - Change movement patterns
242
+ - Add custom commands
243
+ - Test specific scenarios
244
+ - Simulate player behavior
245
+
246
+ ### Modify Server Rules
247
+
248
+ Edit `examples/simple-game/server.ts` to:
249
+
250
+ - Change world size or boundaries
251
+ - Add collision detection
252
+ - Implement game mechanics
253
+ - Test custom logic
254
+
255
+ ## Troubleshooting
256
+
257
+ ### Server won't start
258
+
259
+ **"Port 3000 already in use"**
260
+
261
+ **Solution:**
262
+
263
+ ```bash
264
+ PORT=4000 node examples/simple-game/server.js
265
+ ```
266
+
267
+ Or kill the process using port 3000:
268
+
269
+ ```bash
270
+ lsof -ti:3000 | xargs kill
271
+ ```
272
+
273
+ ---
274
+
275
+ **"Cannot find module './dist/index.js'"**
276
+
277
+ **Solution:** Build the package first:
278
+
279
+ ```bash
280
+ pnpm build
281
+ ```
282
+
283
+ ### Client can't connect
284
+
285
+ **"Connection error: xhr poll error"**
286
+
287
+ **Check:**
288
+
289
+ 1. Is the server running?
290
+ 2. Is the port correct? (default: 3000)
291
+ 3. Is there a firewall blocking?
292
+ 4. Try `localhost` vs `127.0.0.1`
293
+
294
+ ---
295
+
296
+ **Client connects but no updates**
297
+
298
+ **Check:**
299
+
300
+ 1. Are you seeing `S_INIT` event?
301
+ 2. Check server logs for errors
302
+ 3. Verify client is sending commands
303
+
304
+ ### Performance Issues
305
+
306
+ **Tick time > 50ms**
307
+
308
+ **Causes:**
309
+
310
+ - Too many entities
311
+ - Expensive operations in `onTick()`
312
+ - Not using spatial grid for queries
313
+ - Memory leak (growing entity count)
314
+
315
+ **Solutions:**
316
+
317
+ - Profile with console.time()
318
+ - Use grid for spatial queries
319
+ - Limit entity count
320
+ - Check for memory leaks
321
+
322
+ ## Interpreting Results
323
+
324
+ ### Success Indicators
325
+
326
+ - Server starts without errors
327
+ - Clients connect successfully
328
+ - Position updates smoothly
329
+ - Tick time < 40ms consistently
330
+ - Multiple clients work simultaneously
331
+ - No crashes or disconnects
332
+
333
+ ### Warning Signs
334
+
335
+ - Tick time 40-50ms (optimization recommended)
336
+ - Occasional disconnects
337
+ - Delayed state updates
338
+ - Growing memory usage
339
+
340
+ ### Failure Indicators
341
+
342
+ - Tick time > 50ms (dropping frames)
343
+ - Clients can't connect
344
+ - Frequent crashes
345
+ - State desync between clients
346
+ - Memory leaks
347
+
348
+ ## Next Steps
349
+
350
+ After manual testing works:
351
+
352
+ 1. **Build your game** - Use this as a template
353
+ 2. **Add game mechanics** - Combat, items, scoring
354
+ 3. **Create a UI client** - Web-based with Canvas/Phaser
355
+ 4. **Add automated tests** - For your game rules
356
+ 5. **Deploy** - Docker, cloud hosting
357
+
358
+ See the **Developer Guide** for building complete games!
359
+
360
+ ## Additional Resources
361
+
362
+ - **[Quick Start](./QUICK_START.md)** - Get started in 5 minutes
363
+ - **[Developer Guide](./DEVELOPER_GUIDE.md)** - Complete game development guide
364
+ - **[Example Code](./examples/simple-game/)** - Server and client source code
365
+ - **[Automated Tests](./tests/)** - Unit test examples
366
+
367
+ ---
368
+
369
+ **Happy testing! **
package/QUICK_START.md ADDED
@@ -0,0 +1,368 @@
1
+ # Quick Start Guide
2
+
3
+ **Get a multiplayer game running in 5 minutes!**
4
+
5
+ ## Prerequisites
6
+
7
+ ```bash
8
+ node --version # Should be 20+
9
+ ```
10
+
11
+ ## 1. Installation
12
+
13
+ ```bash
14
+ pnpm add @gamerstake/game-core socket.io
15
+ pnpm add -D socket.io-client typescript @types/node
16
+ ```
17
+
18
+ ## 2. Create Game Rules
19
+
20
+ Create `server.ts`:
21
+
22
+ ```typescript
23
+ import { Server } from 'socket.io';
24
+ import { GameServer, GameRules, Room, Entity, Command, MoveCommand } from '@gamerstake/game-core';
25
+
26
+ // Step 1: Define your game logic
27
+ class MyGameRules implements GameRules {
28
+ onRoomCreated(room: Room) {
29
+ console.log(' Room created!');
30
+ }
31
+
32
+ onPlayerJoin(room: Room, player: Entity) {
33
+ // Spawn player at random position
34
+ player.setPosition(Math.random() * 1000, Math.random() * 1000);
35
+ console.log(` Player ${player.id} joined`);
36
+ }
37
+
38
+ onPlayerLeave(room: Room, playerId: string) {
39
+ console.log(` Player ${playerId} left`);
40
+ }
41
+
42
+ onTick(room: Room, delta: number) {
43
+ // Update all moving entities
44
+ room.getRegistry().forEach((entity) => {
45
+ if (entity.vx !== 0 || entity.vy !== 0) {
46
+ entity.updatePosition(delta);
47
+ }
48
+ });
49
+ }
50
+
51
+ onCommand(room: Room, playerId: string, command: Command) {
52
+ const player = room.getRegistry().get(playerId);
53
+ if (!player) return;
54
+
55
+ if (command.type === 'move') {
56
+ const moveCmd = command as MoveCommand;
57
+ const speed = 200;
58
+
59
+ // Normalize direction and apply speed
60
+ const len = Math.hypot(moveCmd.dir.x, moveCmd.dir.y);
61
+ if (len > 0) {
62
+ player.setVelocity((moveCmd.dir.x / len) * speed, (moveCmd.dir.y / len) * speed);
63
+ }
64
+ } else if (command.type === 'stop') {
65
+ player.setVelocity(0, 0);
66
+ }
67
+ }
68
+
69
+ shouldEndRoom(room: Room) {
70
+ return false; // Persistent world
71
+ }
72
+ }
73
+
74
+ // Step 2: Create server and room
75
+ const io = new Server(3000, { cors: { origin: '*' } });
76
+ const gameServer = new GameServer();
77
+ gameServer.setServer(io);
78
+
79
+ const room = gameServer.createRoom('my-room', new MyGameRules(), {
80
+ tickRate: 20,
81
+ cellSize: 512,
82
+ });
83
+
84
+ // Step 3: Handle connections
85
+ io.on('connection', (socket) => {
86
+ const playerId = socket.id;
87
+
88
+ // Create player entity
89
+ const player = new Entity(playerId, 0, 0);
90
+ room.addPlayer(player);
91
+ room.getNetwork().registerSocket(playerId, socket);
92
+
93
+ // Send initial state
94
+ socket.emit('S_INIT', {
95
+ playerId,
96
+ ...room.getSnapshot(),
97
+ });
98
+
99
+ // Handle player inputs
100
+ socket.on('C_MOVE', (data) => {
101
+ room.queueInput(playerId, {
102
+ seq: data.seq,
103
+ type: 'move',
104
+ dir: data.dir,
105
+ timestamp: Date.now(),
106
+ });
107
+ });
108
+
109
+ socket.on('C_STOP', (data) => {
110
+ room.queueInput(playerId, {
111
+ seq: data.seq,
112
+ type: 'stop',
113
+ timestamp: Date.now(),
114
+ });
115
+ });
116
+
117
+ socket.on('disconnect', () => {
118
+ room.removePlayer(playerId);
119
+ room.getNetwork().unregisterSocket(playerId);
120
+ });
121
+ });
122
+
123
+ console.log(' Server running on http://localhost:3000');
124
+ ```
125
+
126
+ ## 3. Run the Server
127
+
128
+ ```bash
129
+ npx tsx server.ts
130
+ ```
131
+
132
+ You should see:
133
+
134
+ ```
135
+ Server running on http://localhost:3000
136
+ ```
137
+
138
+ ## 4. Create a Test Client
139
+
140
+ Create `client.ts`:
141
+
142
+ ```typescript
143
+ import { io } from 'socket.io-client';
144
+
145
+ const socket = io('http://localhost:3000');
146
+ let seq = 0;
147
+
148
+ socket.on('S_INIT', (data) => {
149
+ console.log(' Connected! Player ID:', data.playerId);
150
+ console.log(' Entities:', data.entities.length);
151
+
152
+ // Start moving right after 1 second
153
+ setTimeout(() => {
154
+ console.log(' Moving right...');
155
+ socket.emit('C_MOVE', {
156
+ seq: ++seq,
157
+ dir: { x: 1, y: 0 },
158
+ });
159
+ }, 1000);
160
+ });
161
+
162
+ socket.on('S_UPDATE', (data) => {
163
+ const player = data.entities?.find((e) => e.id === socket.id);
164
+ if (player && seq % 20 === 0) {
165
+ console.log(` Position: (${player.x.toFixed(0)}, ${player.y.toFixed(0)})`);
166
+ }
167
+ });
168
+
169
+ socket.on('connect_error', (err) => {
170
+ console.error(' Connection failed:', err.message);
171
+ });
172
+ ```
173
+
174
+ ## 5. Run the Client
175
+
176
+ In a new terminal:
177
+
178
+ ```bash
179
+ npx tsx client.ts
180
+ ```
181
+
182
+ You should see:
183
+
184
+ ```
185
+ Connected! Player ID: abc123
186
+ Entities: 1
187
+ Moving right...
188
+ Position: (50, 0)
189
+ Position: (100, 0)
190
+ ```
191
+
192
+ ## 6. Test with Multiple Clients
193
+
194
+ Open more terminals and run more clients:
195
+
196
+ ```bash
197
+ npx tsx client.ts # Terminal 3
198
+ npx tsx client.ts # Terminal 4
199
+ npx tsx client.ts # Terminal 5
200
+ ```
201
+
202
+ Watch the server logs to see all players connecting!
203
+
204
+ ## What Just Happened?
205
+
206
+ You created a **multiplayer game server** with game-core
207
+ The server runs a **game loop at 20 TPS** (20 ticks per second)
208
+ Players can **join and move around** in real-time
209
+ The server **broadcasts state updates** to all clients
210
+ All inputs are **processed server-side** (authoritative)
211
+
212
+ ## Next Steps
213
+
214
+ ### 1. Manual Testing
215
+
216
+ Use the built-in example:
217
+
218
+ ```bash
219
+ # Build the package
220
+ pnpm build
221
+
222
+ # Run the example server
223
+ node examples/simple-game/server.js
224
+
225
+ # In another terminal, run a client
226
+ node examples/simple-game/client.js
227
+ ```
228
+
229
+ ### 2. Build a Real Game
230
+
231
+ Check out the **Developer Guide** (`DEVELOPER_GUIDE.md`) for:
232
+
233
+ - Complete tag game tutorial
234
+ - Custom entity types
235
+ - Collision detection
236
+ - Advanced patterns
237
+ - Performance optimization
238
+
239
+ ### 3. Add a Client UI
240
+
241
+ Create a web-based client with:
242
+
243
+ - **Canvas** for 2D rendering
244
+ - **Phaser** for game development
245
+ - **Three.js** for 3D graphics
246
+
247
+ ### 4. Add Features
248
+
249
+ - **Combat system** - Health, damage, abilities
250
+ - **Inventory** - Items, equipment, crafting
251
+ - **Persistence** - Save/load game state
252
+ - **Matchmaking** - Create/join rooms
253
+ - **Chat** - In-game messaging
254
+
255
+ ## Common Issues
256
+
257
+ ### "Cannot find module '@gamerstake/game-core'"
258
+
259
+ If developing locally in a monorepo, build the package first:
260
+
261
+ ```bash
262
+ pnpm build
263
+ ```
264
+
265
+ ### "Port 3000 already in use"
266
+
267
+ Change the port:
268
+
269
+ ```typescript
270
+ const io = new Server(4000, { cors: { origin: '*' } });
271
+ ```
272
+
273
+ ### Client can't connect
274
+
275
+ Check:
276
+
277
+ 1. Server is running
278
+ 2. Port matches (default 3000)
279
+ 3. No firewall blocking
280
+
281
+ ## Architecture Quick Reference
282
+
283
+ ```
284
+ Client Server
285
+
286
+ C_MOVE > [InputQueue]
287
+
288
+ [Game Tick]
289
+ - onCommand()
290
+ - onTick()
291
+
292
+ < S_UPDATE [Network]
293
+
294
+ [Render]
295
+ ```
296
+
297
+ ## API Cheat Sheet
298
+
299
+ ### Server Side
300
+
301
+ ```typescript
302
+ // Create room
303
+ const room = gameServer.createRoom(id, rules, config);
304
+
305
+ // Add/remove players
306
+ room.addPlayer(entity);
307
+ room.removePlayer(playerId);
308
+
309
+ // Spawn/destroy entities
310
+ room.spawnEntity(entity);
311
+ room.destroyEntity(entityId);
312
+
313
+ // Networking
314
+ room.broadcast(event);
315
+ room.sendTo(playerId, event);
316
+
317
+ // Get state
318
+ const snapshot = room.getSnapshot();
319
+ const entity = room.getRegistry().get(id);
320
+ ```
321
+
322
+ ### Client Side
323
+
324
+ ```typescript
325
+ // Connect
326
+ const socket = io('http://localhost:3000');
327
+
328
+ // Receive events
329
+ socket.on('S_INIT', (data) => {
330
+ /* initial state */
331
+ });
332
+ socket.on('S_UPDATE', (data) => {
333
+ /* delta update */
334
+ });
335
+
336
+ // Send inputs
337
+ socket.emit('C_MOVE', { seq: 1, dir: { x: 1, y: 0 } });
338
+ socket.emit('C_STOP', { seq: 2 });
339
+ ```
340
+
341
+ ## Testing
342
+
343
+ ```bash
344
+ # Run unit tests
345
+ pnpm test
346
+
347
+ # Run with coverage
348
+ pnpm test:coverage
349
+
350
+ # Type check
351
+ pnpm typecheck
352
+
353
+ # Build
354
+ pnpm build
355
+ ```
356
+
357
+ ## Resources
358
+
359
+ - **Developer Guide** - `DEVELOPER_GUIDE.md` - Complete guide with examples
360
+ - **Examples** - `examples/` - Working game examples
361
+ - **Tests** - `tests/` - Usage patterns
362
+ - **API Docs** - `README.md` - Full API reference
363
+
364
+ ---
365
+
366
+ **You're ready to build multiplayer games! **
367
+
368
+ For more advanced usage, see the **Developer Guide**.