@gamerstake/game-core 0.1.0 → 0.2.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.
@@ -0,0 +1,634 @@
1
+ # Game Core Client SDK
2
+
3
+ **Version:** 0.2.0
4
+ **Status:** ✅ Production Ready
5
+
6
+ ---
7
+
8
+ ## 🎮 What is the Client SDK?
9
+
10
+ The Client SDK is the **browser-side** component of `@gamerstake/game-core` that eliminates the need for custom networking code in multiplayer games.
11
+
12
+ ### Before Client SDK
13
+
14
+ ```javascript
15
+ // Custom networking code (2,000+ lines)
16
+ class NetClient {
17
+ /* 547 lines */
18
+ }
19
+ class TimeSync {
20
+ /* 429 lines */
21
+ }
22
+ class InputBuffer {
23
+ /* 270 lines */
24
+ }
25
+ class Reconciler {
26
+ /* 587 lines */
27
+ }
28
+ class Interpolator {
29
+ /* 200+ lines */
30
+ }
31
+ ```
32
+
33
+ ### After Client SDK
34
+
35
+ ```typescript
36
+ import { GameClient } from '@gamerstake/game-core/client';
37
+
38
+ const client = new GameClient({
39
+ serverUrl: 'http://localhost:3000',
40
+ });
41
+
42
+ await client.connect();
43
+ ```
44
+
45
+ **Result:** 2,000+ lines → 5 lines (99.7% reduction)
46
+
47
+ ---
48
+
49
+ ## 📦 Installation
50
+
51
+ ```bash
52
+ pnpm add @gamerstake/game-core
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 🚀 Quick Start
58
+
59
+ ### 1. Import Client SDK
60
+
61
+ ```typescript
62
+ import { GameClient } from '@gamerstake/game-core/client';
63
+ ```
64
+
65
+ ### 2. Create Client
66
+
67
+ ```typescript
68
+ const client = new GameClient({
69
+ serverUrl: 'http://localhost:3000',
70
+ enablePrediction: true,
71
+ enableReconciliation: true,
72
+ enableInterpolation: true,
73
+ });
74
+ ```
75
+
76
+ ### 3. Connect to Server
77
+
78
+ ```typescript
79
+ await client.connect();
80
+ ```
81
+
82
+ ### 4. Listen for Events
83
+
84
+ ```typescript
85
+ client.on('stateUpdate', (state) => {
86
+ // Update game entities
87
+ state.players?.forEach((player) => {
88
+ updatePlayerPosition(player.id, player.x, player.z);
89
+ });
90
+ });
91
+ ```
92
+
93
+ ### 5. Send Commands
94
+
95
+ ```typescript
96
+ // Movement
97
+ client.sendMove(targetX, targetZ);
98
+
99
+ // Custom actions
100
+ client.sendAction('attack', { targetId: 'enemy-1' });
101
+ client.sendAction('collect', { itemId: 'item-5' });
102
+ ```
103
+
104
+ ### 6. Update Every Frame
105
+
106
+ ```typescript
107
+ function gameLoop(deltaMs) {
108
+ client.update(deltaMs); // Handles interpolation, prediction
109
+ render();
110
+ requestAnimationFrame(gameLoop);
111
+ }
112
+
113
+ gameLoop(16);
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 📚 API Reference
119
+
120
+ ### GameClient
121
+
122
+ #### Constructor
123
+
124
+ ```typescript
125
+ new GameClient(config: GameClientConfig)
126
+ ```
127
+
128
+ **Config Options:**
129
+
130
+ | Option | Type | Default | Description |
131
+ | :--------------------- | :------ | :----------- | :---------------------------- |
132
+ | `serverUrl` | string | **required** | Server URL to connect to |
133
+ | `enablePrediction` | boolean | `true` | Enable client-side prediction |
134
+ | `enableReconciliation` | boolean | `true` | Enable server reconciliation |
135
+ | `enableInterpolation` | boolean | `true` | Enable entity interpolation |
136
+ | `interpolationDelay` | number | `100` | Interpolation delay (ms) |
137
+ | `reconnectAttempts` | number | `5` | Number of reconnect attempts |
138
+ | `reconnectDelay` | number | `1000` | Delay between reconnects (ms) |
139
+
140
+ #### Methods
141
+
142
+ **`connect(): Promise<void>`**
143
+ Connect to game server.
144
+
145
+ ```typescript
146
+ await client.connect();
147
+ ```
148
+
149
+ **`disconnect(): void`**
150
+ Disconnect from server.
151
+
152
+ ```typescript
153
+ client.disconnect();
154
+ ```
155
+
156
+ **`on(event, handler): void`**
157
+ Register event handler.
158
+
159
+ ```typescript
160
+ client.on('stateUpdate', (state) => {
161
+ /* ... */
162
+ });
163
+ client.on('customEvent', (data) => {
164
+ /* ... */
165
+ });
166
+ ```
167
+
168
+ **`sendMove(targetX, targetZ): number`**
169
+ Send movement command.
170
+
171
+ ```typescript
172
+ const actionId = client.sendMove(100, 50);
173
+ ```
174
+
175
+ **`sendAction(type, data): number`**
176
+ Send custom action command.
177
+
178
+ ```typescript
179
+ client.sendAction('attack', { targetId: 'enemy-1' });
180
+ client.sendAction('knife_throw', { targetX: 100, targetZ: 50 });
181
+ ```
182
+
183
+ **`update(deltaMs): void`**
184
+ Update client (call every frame).
185
+
186
+ ```typescript
187
+ client.update(16); // ~60 FPS
188
+ ```
189
+
190
+ **`getStats(): NetworkStats`**
191
+ Get network statistics.
192
+
193
+ ```typescript
194
+ const stats = client.getStats();
195
+ console.log('RTT:', stats.rtt);
196
+ console.log('Jitter:', stats.jitter);
197
+ console.log('Messages sent:', stats.messagesSent);
198
+ ```
199
+
200
+ **`getServerTime(): number`**
201
+ Get estimated server time.
202
+
203
+ ```typescript
204
+ const serverTime = client.getServerTime();
205
+ ```
206
+
207
+ **`isConnected(): boolean`**
208
+ Check if connected to server.
209
+
210
+ ```typescript
211
+ if (client.isConnected()) {
212
+ // Connected
213
+ }
214
+ ```
215
+
216
+ ---
217
+
218
+ ## 🎯 Features
219
+
220
+ ### 1. Time Synchronization
221
+
222
+ Automatically synchronizes client clock with server for accurate lag compensation.
223
+
224
+ ```typescript
225
+ // Get server time
226
+ const serverTime = client.getServerTime();
227
+
228
+ // Get network stats
229
+ const stats = client.getStats();
230
+ console.log('RTT:', stats.rtt, 'ms');
231
+ console.log('Clock offset:', stats.offset, 'ms');
232
+ ```
233
+
234
+ ### 2. Client Prediction
235
+
236
+ Applies commands locally before server confirmation for responsive gameplay.
237
+
238
+ ```typescript
239
+ // Enabled by default
240
+ const client = new GameClient({
241
+ serverUrl: 'http://localhost:3000',
242
+ enablePrediction: true,
243
+ });
244
+
245
+ // Movement feels instant!
246
+ client.sendMove(x, z);
247
+ ```
248
+
249
+ ### 3. Server Reconciliation
250
+
251
+ Corrects prediction errors when server state arrives.
252
+
253
+ ```typescript
254
+ const client = new GameClient({
255
+ serverUrl: 'http://localhost:3000',
256
+ enableReconciliation: true,
257
+ });
258
+
259
+ // Automatically corrects position differences
260
+ // Smoothly interpolates corrections
261
+ ```
262
+
263
+ ### 4. Entity Interpolation
264
+
265
+ Smoothly renders remote entities between server updates.
266
+
267
+ ```typescript
268
+ const client = new GameClient({
269
+ serverUrl: 'http://localhost:3000',
270
+ enableInterpolation: true,
271
+ interpolationDelay: 100, // 100ms delay for smooth rendering
272
+ });
273
+
274
+ // Remote players move smoothly even at low update rates
275
+ ```
276
+
277
+ ### 5. Input Buffering
278
+
279
+ Buffers inputs and tracks acknowledgments for reliable networking.
280
+
281
+ ```typescript
282
+ // Automatically buffers inputs
283
+ const actionId = client.sendMove(x, z);
284
+
285
+ // Tracks acknowledgment
286
+ client.on('moveAck', (data) => {
287
+ if (data.actionId === actionId) {
288
+ // Input acknowledged by server
289
+ }
290
+ });
291
+ ```
292
+
293
+ ### 6. Auto-Reconnection
294
+
295
+ Automatically reconnects on disconnect with exponential backoff.
296
+
297
+ ```typescript
298
+ const client = new GameClient({
299
+ serverUrl: 'http://localhost:3000',
300
+ reconnectAttempts: 5,
301
+ reconnectDelay: 1000, // Initial delay, increases exponentially
302
+ });
303
+
304
+ client.on('disconnect', (reason) => {
305
+ console.log('Disconnected:', reason);
306
+ // Will automatically attempt reconnection
307
+ });
308
+
309
+ client.on('reconnect', () => {
310
+ console.log('Reconnected!');
311
+ });
312
+ ```
313
+
314
+ ---
315
+
316
+ ## 🎮 Complete Example
317
+
318
+ ### Client (Browser)
319
+
320
+ ```typescript
321
+ import { GameClient } from '@gamerstake/game-core/client';
322
+
323
+ class MyGame {
324
+ private client: GameClient;
325
+ private players = new Map();
326
+
327
+ async init() {
328
+ // Create client
329
+ this.client = new GameClient({
330
+ serverUrl: 'http://localhost:3000',
331
+ enablePrediction: true,
332
+ enableReconciliation: true,
333
+ enableInterpolation: true,
334
+ });
335
+
336
+ // Register events
337
+ this.client.on('connected', () => {
338
+ console.log('Connected to server!');
339
+ });
340
+
341
+ this.client.on('stateUpdate', (state) => {
342
+ this.handleStateUpdate(state);
343
+ });
344
+
345
+ this.client.on('playerDied', (data) => {
346
+ this.showDeathAnimation(data.playerId);
347
+ });
348
+
349
+ // Connect
350
+ await this.client.connect();
351
+ }
352
+
353
+ handleStateUpdate(state) {
354
+ // Update player positions
355
+ state.players?.forEach((player) => {
356
+ const entity = this.players.get(player.playerId);
357
+ if (entity) {
358
+ entity.position.set(player.x, 0, player.z);
359
+ entity.health = player.health;
360
+ }
361
+ });
362
+ }
363
+
364
+ onPlayerClick(x, z) {
365
+ // Send movement command
366
+ this.client.sendMove(x, z);
367
+ }
368
+
369
+ onAttackClick(targetId) {
370
+ // Send attack command
371
+ this.client.sendAction('attack', { targetId });
372
+ }
373
+
374
+ update(deltaMs) {
375
+ // Update client (interpolation, prediction)
376
+ this.client.update(deltaMs);
377
+
378
+ // Game logic
379
+ this.updateAnimations(deltaMs);
380
+ this.updateEffects(deltaMs);
381
+ }
382
+
383
+ render() {
384
+ // Render game
385
+ this.renderer.render(this.scene, this.camera);
386
+ }
387
+
388
+ gameLoop(deltaMs) {
389
+ this.update(deltaMs);
390
+ this.render();
391
+ requestAnimationFrame(() => this.gameLoop(16));
392
+ }
393
+ }
394
+
395
+ // Start game
396
+ const game = new MyGame();
397
+ await game.init();
398
+ game.gameLoop(16);
399
+ ```
400
+
401
+ ### Server (Node.js)
402
+
403
+ ```typescript
404
+ import { Server as SocketIOServer } from 'socket.io';
405
+ import { GameServer, Entity } from '@gamerstake/game-core';
406
+ import { MyGameRules } from './MyGameRules';
407
+
408
+ const io = new SocketIOServer(3000);
409
+ const gameServer = new GameServer();
410
+ gameServer.setServer(io);
411
+
412
+ const room = gameServer.createRoom('room-1', new MyGameRules(), {
413
+ tickRate: 60,
414
+ });
415
+
416
+ io.on('connection', (socket) => {
417
+ const player = new Entity(socket.id, 0, 0);
418
+ room.addPlayer(player);
419
+ room.getNetwork().registerSocket(socket.id, socket);
420
+
421
+ socket.on('disconnect', () => {
422
+ room.removePlayer(socket.id);
423
+ });
424
+ });
425
+ ```
426
+
427
+ ---
428
+
429
+ ## 🔧 Advanced Usage
430
+
431
+ ### Custom Event Handlers
432
+
433
+ ```typescript
434
+ // Register any custom event
435
+ client.on('knifeSpawn', (data) => {
436
+ spawnKnife(data.knifeId, data.x, data.z);
437
+ });
438
+
439
+ client.on('knifeHit', (data) => {
440
+ playHitSound();
441
+ showBloodEffect(data.hitX, data.hitZ);
442
+ });
443
+
444
+ client.on('gameOver', (data) => {
445
+ showWinner(data.winner);
446
+ });
447
+ ```
448
+
449
+ ### Network Statistics
450
+
451
+ ```typescript
452
+ const stats = client.getStats();
453
+
454
+ console.log({
455
+ rtt: stats.rtt, // Round-trip time
456
+ jitter: stats.jitter, // Network jitter
457
+ connected: stats.connected, // Connection status
458
+ messagesSent: stats.messagesSent, // Total sent
459
+ messagesReceived: stats.messagesReceived, // Total received
460
+ });
461
+
462
+ // Display to user
463
+ showNetworkQuality(stats.rtt < 50 ? 'Good' : 'Poor');
464
+ ```
465
+
466
+ ### Adaptive Interpolation
467
+
468
+ ```typescript
469
+ // Automatically adjust interpolation based on network conditions
470
+ const adaptiveDelay = client.getAdaptiveInterpolationDelay();
471
+
472
+ // Use it for rendering
473
+ const renderTime = Date.now() - adaptiveDelay;
474
+ ```
475
+
476
+ ---
477
+
478
+ ## 🧪 Testing
479
+
480
+ ### Unit Tests
481
+
482
+ ```typescript
483
+ import { GameClient } from '@gamerstake/game-core/client';
484
+
485
+ describe('MyGame', () => {
486
+ let client: GameClient;
487
+
488
+ beforeEach(() => {
489
+ client = new GameClient({
490
+ serverUrl: 'http://localhost:3000',
491
+ });
492
+ });
493
+
494
+ it('should connect to server', async () => {
495
+ await client.connect();
496
+ expect(client.isConnected()).toBe(true);
497
+ });
498
+
499
+ it('should send movement', () => {
500
+ const actionId = client.sendMove(100, 50);
501
+ expect(actionId).toBeGreaterThan(0);
502
+ });
503
+ });
504
+ ```
505
+
506
+ ---
507
+
508
+ ## 🐛 Troubleshooting
509
+
510
+ ### Connection Issues
511
+
512
+ **Problem:** Can't connect to server
513
+
514
+ **Solutions:**
515
+
516
+ ```typescript
517
+ // Check server URL
518
+ const client = new GameClient({
519
+ serverUrl: 'http://localhost:3000', // Correct port?
520
+ });
521
+
522
+ // Check CORS on server
523
+ const io = new SocketIOServer(PORT, {
524
+ cors: { origin: '*' }, // Allow all origins
525
+ });
526
+
527
+ // Check connection event
528
+ client.on('error', (error) => {
529
+ console.error('Connection error:', error);
530
+ });
531
+ ```
532
+
533
+ ### High Latency
534
+
535
+ **Problem:** Movement feels laggy
536
+
537
+ **Solutions:**
538
+
539
+ ```typescript
540
+ // Check RTT
541
+ const stats = client.getStats();
542
+ console.log('RTT:', stats.rtt); // Should be < 100ms
543
+
544
+ // Increase interpolation delay
545
+ const client = new GameClient({
546
+ serverUrl: 'http://localhost:3000',
547
+ interpolationDelay: 150, // Increase for high latency
548
+ });
549
+ ```
550
+
551
+ ### Position Desync
552
+
553
+ **Problem:** Player position not matching server
554
+
555
+ **Solutions:**
556
+
557
+ ```typescript
558
+ // Enable reconciliation
559
+ const client = new GameClient({
560
+ serverUrl: 'http://localhost:3000',
561
+ enableReconciliation: true,
562
+ });
563
+
564
+ // Check for prediction errors in console
565
+ // Reconciler will automatically correct
566
+ ```
567
+
568
+ ---
569
+
570
+ ## 📊 Performance
571
+
572
+ ### Network Performance
573
+
574
+ - **RTT:** < 100ms (typical)
575
+ - **Jitter:** < 20ms (typical)
576
+ - **Bandwidth:** ~10-50 KB/s per player
577
+ - **Update Rate:** 20-60 Hz
578
+
579
+ ### Client Performance
580
+
581
+ - **CPU Usage:** < 5% (at 60 FPS)
582
+ - **Memory:** < 10MB per client
583
+ - **Frame Impact:** < 1ms per frame
584
+
585
+ ---
586
+
587
+ ## 🔄 Migration Guide
588
+
589
+ ### From Custom NetClient
590
+
591
+ If you have custom networking code:
592
+
593
+ **Before:**
594
+
595
+ ```javascript
596
+ import NetClient from './net/NetClient.js';
597
+
598
+ const socket = io('http://localhost:3000');
599
+ const netClient = new NetClient(socket);
600
+ ```
601
+
602
+ **After:**
603
+
604
+ ```typescript
605
+ import { GameClient } from '@gamerstake/game-core/client';
606
+
607
+ const client = new GameClient({
608
+ serverUrl: 'http://localhost:3000',
609
+ });
610
+ await client.connect();
611
+ ```
612
+
613
+ See [MUNDO-CLEAVER-MIGRATION-GUIDE.md](../../docs/features/game-core/MUNDO-CLEAVER-MIGRATION-GUIDE.md) for complete migration guide.
614
+
615
+ ---
616
+
617
+ ## 📚 Resources
618
+
619
+ - [Main README](./README.md) - Package overview
620
+ - [Developer Guide](./DEVELOPER_GUIDE.md) - Complete tutorial
621
+ - [API Documentation](./API.md) - Full API reference
622
+ - [Examples](./examples/) - Working examples
623
+
624
+ ---
625
+
626
+ ## 🆘 Support
627
+
628
+ - **Issues:** https://github.com/gamerstake/gamerstake/issues
629
+ - **Documentation:** https://docs.gamerstake.com
630
+ - **Discord:** https://discord.gg/gamerstake
631
+
632
+ ---
633
+
634
+ **Built with ❤️ by the GamerStake team**
package/README.md CHANGED
@@ -44,6 +44,12 @@ Reusable multiplayer game engine for the GamerStake platform.
44
44
 
45
45
  ## Installation
46
46
 
47
+ ### From NPM Registry
48
+
49
+ ```bash
50
+ pnpm add @gamerstake/game-core
51
+ ```
52
+
47
53
  ### From Monorepo Workspace
48
54
 
49
55
  If you're in the GamerStake monorepo:
@@ -56,15 +62,62 @@ If you're in the GamerStake monorepo:
56
62
  }
57
63
  ```
58
64
 
59
- ### From NPM Registry
65
+ See [PUBLISHING.md](./PUBLISHING.md) for publishing and distribution options.
60
66
 
61
- ```bash
62
- pnpm add @gamerstake/game-core
67
+ ## Quick Start
68
+
69
+ ### Client SDK (Browser/Game)
70
+
71
+ Build multiplayer games with **zero networking code**:
72
+
73
+ ```typescript
74
+ import { GameClient } from '@gamerstake/game-core/client';
75
+
76
+ // Create client
77
+ const client = new GameClient({
78
+ serverUrl: 'http://localhost:3000',
79
+ enablePrediction: true, // Smooth local movement
80
+ enableReconciliation: true, // Server correction
81
+ enableInterpolation: true, // Smooth remote players
82
+ });
83
+
84
+ // Connect
85
+ await client.connect();
86
+
87
+ // Listen for state updates
88
+ client.on('stateUpdate', (state) => {
89
+ // Update your game entities
90
+ updatePlayers(state.players);
91
+ updateEntities(state.entities);
92
+ });
93
+
94
+ // Listen for custom events
95
+ client.on('playerDied', (data) => {
96
+ showDeathAnimation(data.playerId);
97
+ });
98
+
99
+ // Send movement
100
+ client.sendMove(targetX, targetZ);
101
+
102
+ // Send custom actions
103
+ client.sendAction('attack', { targetId: 'enemy-1' });
104
+
105
+ // Update every frame
106
+ function gameLoop(deltaMs) {
107
+ client.update(deltaMs); // Handles interpolation, prediction
108
+ render();
109
+ requestAnimationFrame(gameLoop);
110
+ }
111
+
112
+ // Get network stats
113
+ const stats = client.getStats();
114
+ console.log('RTT:', stats.rtt, 'ms');
115
+ console.log('Jitter:', stats.jitter, 'ms');
63
116
  ```
64
117
 
65
- See [PUBLISHING.md](./PUBLISHING.md) for publishing and distribution options.
118
+ **That's it!** No Socket.io code, no custom networking, no prediction logic. Just game logic! 🎮
66
119
 
67
- ## Quick Start
120
+ ### Server SDK (Node.js)
68
121
 
69
122
  ### 1. Implement GameRules
70
123