@phalanx-engine/server 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.
- package/README.md +507 -0
- package/dist/Phalanx.d.ts +85 -0
- package/dist/Phalanx.d.ts.map +1 -0
- package/dist/Phalanx.js +600 -0
- package/dist/Phalanx.js.map +1 -0
- package/dist/config/defaults.d.ts +10 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +51 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/validation.d.ts +15 -0
- package/dist/config/validation.d.ts.map +1 -0
- package/dist/config/validation.js +74 -0
- package/dist/config/validation.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/services/GameRoom.d.ts +359 -0
- package/dist/services/GameRoom.d.ts.map +1 -0
- package/dist/services/GameRoom.js +1272 -0
- package/dist/services/GameRoom.js.map +1 -0
- package/dist/services/MatchmakingService.d.ts +102 -0
- package/dist/services/MatchmakingService.d.ts.map +1 -0
- package/dist/services/MatchmakingService.js +286 -0
- package/dist/services/MatchmakingService.js.map +1 -0
- package/dist/services/OAuthExchangeService.d.ts +49 -0
- package/dist/services/OAuthExchangeService.d.ts.map +1 -0
- package/dist/services/OAuthExchangeService.js +96 -0
- package/dist/services/OAuthExchangeService.js.map +1 -0
- package/dist/services/PrivateRoomService.d.ts +136 -0
- package/dist/services/PrivateRoomService.d.ts.map +1 -0
- package/dist/services/PrivateRoomService.js +395 -0
- package/dist/services/PrivateRoomService.js.map +1 -0
- package/dist/services/TokenValidator.d.ts +60 -0
- package/dist/services/TokenValidator.d.ts.map +1 -0
- package/dist/services/TokenValidator.js +213 -0
- package/dist/services/TokenValidator.js.map +1 -0
- package/dist/types/index.d.ts +390 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/DeterministicRandom.d.ts +88 -0
- package/dist/utils/DeterministicRandom.d.ts.map +1 -0
- package/dist/utils/DeterministicRandom.js +140 -0
- package/dist/utils/DeterministicRandom.js.map +1 -0
- package/dist/utils/FixedMath.d.ts +22 -0
- package/dist/utils/FixedMath.d.ts.map +1 -0
- package/dist/utils/FixedMath.js +26 -0
- package/dist/utils/FixedMath.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +62 -0
package/dist/Phalanx.js
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Server as SocketIOServer } from 'socket.io';
|
|
3
|
+
import { createServer as createHttpServer, } from 'http';
|
|
4
|
+
import { createServer as createHttpsServer, } from 'https';
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
import { validateConfig } from './config/validation.js';
|
|
7
|
+
import { MatchmakingService } from './services/MatchmakingService.js';
|
|
8
|
+
import { PrivateRoomService } from './services/PrivateRoomService.js';
|
|
9
|
+
import { TokenValidatorService } from './services/TokenValidator.js';
|
|
10
|
+
import { OAuthExchangeService, } from './services/OAuthExchangeService.js';
|
|
11
|
+
/**
|
|
12
|
+
* Phalanx Engine
|
|
13
|
+
* A game-agnostic deterministic lockstep multiplayer engine
|
|
14
|
+
*/
|
|
15
|
+
export class Phalanx extends EventEmitter {
|
|
16
|
+
config;
|
|
17
|
+
httpServer = null;
|
|
18
|
+
io = null;
|
|
19
|
+
matchmaking = null;
|
|
20
|
+
privateRooms = null;
|
|
21
|
+
tokenValidator = null;
|
|
22
|
+
oauthExchange = null;
|
|
23
|
+
isRunning = false;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
super();
|
|
26
|
+
this.config = validateConfig(config);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create HTTP or HTTPS server based on TLS configuration
|
|
30
|
+
*/
|
|
31
|
+
createServer() {
|
|
32
|
+
const requestHandler = async (req, res) => {
|
|
33
|
+
// Handle CORS preflight
|
|
34
|
+
if (req.method === 'OPTIONS') {
|
|
35
|
+
this.setCorsHeaders(res, req);
|
|
36
|
+
res.writeHead(204);
|
|
37
|
+
res.end();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Delegate to consumer-provided handler first (e.g. bot webhook)
|
|
41
|
+
if (this.config.extraRequestHandler) {
|
|
42
|
+
try {
|
|
43
|
+
const consumed = await this.config.extraRequestHandler(req, res);
|
|
44
|
+
if (consumed)
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
console.error('[Phalanx] extraRequestHandler threw an error:', err);
|
|
49
|
+
if (!res.headersSent) {
|
|
50
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
51
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Health check endpoint
|
|
57
|
+
if (req.url === '/' || req.url === '/health') {
|
|
58
|
+
this.setCorsHeaders(res, req);
|
|
59
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
60
|
+
res.end(JSON.stringify({
|
|
61
|
+
status: 'ok',
|
|
62
|
+
timestamp: new Date().toISOString(),
|
|
63
|
+
tls: !!this.config.tls?.enabled,
|
|
64
|
+
}));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// OAuth token exchange endpoint
|
|
68
|
+
if (req.url === '/auth/token' && req.method === 'POST') {
|
|
69
|
+
await this.handleTokenExchange(req, res);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// 404 for other routes
|
|
73
|
+
this.setCorsHeaders(res, req);
|
|
74
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
75
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
76
|
+
};
|
|
77
|
+
if (this.config.tls?.enabled) {
|
|
78
|
+
try {
|
|
79
|
+
const tlsOptions = {
|
|
80
|
+
key: readFileSync(this.config.tls.keyPath),
|
|
81
|
+
cert: readFileSync(this.config.tls.certPath),
|
|
82
|
+
ca: this.config.tls.caPath
|
|
83
|
+
? readFileSync(this.config.tls.caPath)
|
|
84
|
+
: undefined,
|
|
85
|
+
};
|
|
86
|
+
console.log('[Phalanx] Starting with TLS enabled (WSS)');
|
|
87
|
+
return createHttpsServer(tlsOptions, (req, res) => void requestHandler(req, res));
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
91
|
+
throw new Error(`Failed to load TLS certificates: ${message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
console.log('[Phalanx] Starting without TLS (development mode)');
|
|
95
|
+
return createHttpServer((req, res) => void requestHandler(req, res));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Set CORS headers on response
|
|
99
|
+
*/
|
|
100
|
+
setCorsHeaders(res, req) {
|
|
101
|
+
const configuredOrigins = Array.isArray(this.config.cors.origin)
|
|
102
|
+
? this.config.cors.origin
|
|
103
|
+
: [this.config.cors.origin];
|
|
104
|
+
// Get the request Origin header
|
|
105
|
+
const requestOrigin = req?.headers.origin;
|
|
106
|
+
// Check if the request origin is in our allowed list
|
|
107
|
+
let allowedOrigin;
|
|
108
|
+
if (requestOrigin && configuredOrigins.includes(requestOrigin)) {
|
|
109
|
+
allowedOrigin = requestOrigin;
|
|
110
|
+
}
|
|
111
|
+
else if (configuredOrigins.includes('*')) {
|
|
112
|
+
allowedOrigin = '*';
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// Default to first configured origin (for preflight without Origin header)
|
|
116
|
+
allowedOrigin = configuredOrigins[0] || '*';
|
|
117
|
+
}
|
|
118
|
+
res.setHeader('Access-Control-Allow-Origin', allowedOrigin);
|
|
119
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
120
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
121
|
+
if (this.config.cors.credentials) {
|
|
122
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Handle OAuth token exchange request
|
|
127
|
+
*/
|
|
128
|
+
async handleTokenExchange(req, res) {
|
|
129
|
+
this.setCorsHeaders(res, req);
|
|
130
|
+
if (!this.oauthExchange) {
|
|
131
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
132
|
+
res.end(JSON.stringify({
|
|
133
|
+
success: false,
|
|
134
|
+
error: 'OAuth not configured',
|
|
135
|
+
errorCode: 'not_configured'
|
|
136
|
+
}));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
// Read request body
|
|
141
|
+
const body = await this.readRequestBody(req);
|
|
142
|
+
const request = JSON.parse(body);
|
|
143
|
+
// Validate required fields
|
|
144
|
+
if (!request.code || !request.codeVerifier || !request.redirectUri || !request.provider) {
|
|
145
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
146
|
+
res.end(JSON.stringify({
|
|
147
|
+
success: false,
|
|
148
|
+
error: 'Missing required fields: code, codeVerifier, redirectUri, provider',
|
|
149
|
+
errorCode: 'invalid_request'
|
|
150
|
+
}));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Exchange the code for tokens
|
|
154
|
+
const result = await this.oauthExchange.exchangeCode(request);
|
|
155
|
+
res.writeHead(result.success ? 200 : 400, { 'Content-Type': 'application/json' });
|
|
156
|
+
res.end(JSON.stringify(result));
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
console.error('[Phalanx] Token exchange error:', error);
|
|
160
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
161
|
+
res.end(JSON.stringify({
|
|
162
|
+
success: false,
|
|
163
|
+
error: 'Internal server error',
|
|
164
|
+
errorCode: 'server_error'
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Read the full request body as a string
|
|
170
|
+
*/
|
|
171
|
+
readRequestBody(req) {
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
let body = '';
|
|
174
|
+
req.on('data', (chunk) => {
|
|
175
|
+
body += chunk.toString();
|
|
176
|
+
// Limit body size to 1MB
|
|
177
|
+
if (body.length > 1024 * 1024) {
|
|
178
|
+
reject(new Error('Request body too large'));
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
req.on('end', () => resolve(body));
|
|
182
|
+
req.on('error', reject);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Start the Phalanx server
|
|
187
|
+
*/
|
|
188
|
+
async start() {
|
|
189
|
+
if (this.isRunning) {
|
|
190
|
+
throw new Error('Phalanx server is already running');
|
|
191
|
+
}
|
|
192
|
+
// Create HTTP/HTTPS server with health check endpoint
|
|
193
|
+
this.httpServer = this.createServer();
|
|
194
|
+
// Create Socket.IO server
|
|
195
|
+
this.io = new SocketIOServer(this.httpServer, {
|
|
196
|
+
cors: this.config.cors,
|
|
197
|
+
});
|
|
198
|
+
// Setup authentication if enabled
|
|
199
|
+
if (this.config.auth?.enabled) {
|
|
200
|
+
this.tokenValidator = new TokenValidatorService(this.config.auth);
|
|
201
|
+
this.oauthExchange = new OAuthExchangeService(this.config.auth);
|
|
202
|
+
this.setupAuthMiddleware();
|
|
203
|
+
console.log('[Phalanx] Authentication enabled');
|
|
204
|
+
if (this.config.auth.google?.clientSecret) {
|
|
205
|
+
console.log('[Phalanx] OAuth token exchange endpoint available at /auth/token');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
console.log('[Phalanx] Authentication disabled (development mode)');
|
|
210
|
+
}
|
|
211
|
+
// Create matchmaking service
|
|
212
|
+
this.matchmaking = new MatchmakingService(this.io, this.config, (event, ...args) => this.emit(event, ...args));
|
|
213
|
+
// Create private room service
|
|
214
|
+
this.privateRooms = new PrivateRoomService(this.io, this.config, (event, ...args) => this.emit(event, ...args), (gameType) => this.matchmaking.resolveGameTypeConfig(gameType), (playerId) => this.matchmaking.isInAnyQueue(playerId));
|
|
215
|
+
// Wire up match-ended event to prune finished matches from both services
|
|
216
|
+
this.on('match-ended', ((matchId) => {
|
|
217
|
+
this.matchmaking?.removeMatch(matchId);
|
|
218
|
+
this.privateRooms?.removeMatch(matchId);
|
|
219
|
+
}));
|
|
220
|
+
// Setup socket handlers
|
|
221
|
+
this.setupSocketHandlers();
|
|
222
|
+
// Start matchmaking
|
|
223
|
+
this.matchmaking.start();
|
|
224
|
+
// Start listening
|
|
225
|
+
return new Promise((resolve, reject) => {
|
|
226
|
+
this.httpServer.listen(this.config.port, () => {
|
|
227
|
+
this.isRunning = true;
|
|
228
|
+
resolve();
|
|
229
|
+
});
|
|
230
|
+
this.httpServer.on('error', (err) => {
|
|
231
|
+
reject(err);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Create or reuse a private room for a host that will connect later.
|
|
237
|
+
* Intended for trusted server-side integrations such as Telegram bot
|
|
238
|
+
* commands; browser clients should continue using the Socket.IO flow.
|
|
239
|
+
*/
|
|
240
|
+
createPrivateRoomForHost(params) {
|
|
241
|
+
if (!this.privateRooms) {
|
|
242
|
+
throw new Error('Private room service is not running');
|
|
243
|
+
}
|
|
244
|
+
return this.privateRooms.createRoomForDisconnectedHost(params.playerId, params.username ?? params.playerId, params.gameType);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Stop the Phalanx server
|
|
248
|
+
*/
|
|
249
|
+
async stop() {
|
|
250
|
+
if (!this.isRunning) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
this.isRunning = false;
|
|
254
|
+
// Stop matchmaking first
|
|
255
|
+
if (this.matchmaking) {
|
|
256
|
+
this.matchmaking.stop();
|
|
257
|
+
this.matchmaking = null;
|
|
258
|
+
}
|
|
259
|
+
// Stop private rooms
|
|
260
|
+
if (this.privateRooms) {
|
|
261
|
+
this.privateRooms.stop();
|
|
262
|
+
this.privateRooms = null;
|
|
263
|
+
}
|
|
264
|
+
// Disconnect all sockets first
|
|
265
|
+
if (this.io) {
|
|
266
|
+
this.io.disconnectSockets(true);
|
|
267
|
+
}
|
|
268
|
+
// Close HTTP server (this also closes Socket.IO)
|
|
269
|
+
if (this.httpServer) {
|
|
270
|
+
await new Promise((resolve) => {
|
|
271
|
+
this.httpServer.close(() => resolve());
|
|
272
|
+
});
|
|
273
|
+
this.httpServer = null;
|
|
274
|
+
}
|
|
275
|
+
this.io = null;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Setup authentication middleware for Socket.IO connections.
|
|
279
|
+
* Validates tokens before allowing connections.
|
|
280
|
+
*/
|
|
281
|
+
setupAuthMiddleware() {
|
|
282
|
+
if (!this.io || !this.tokenValidator)
|
|
283
|
+
return;
|
|
284
|
+
this.io.use(async (socket, next) => {
|
|
285
|
+
const token = socket.handshake.auth?.token;
|
|
286
|
+
// Check if token is provided
|
|
287
|
+
if (!token) {
|
|
288
|
+
// Allow anonymous if configured
|
|
289
|
+
if (this.config.auth?.allowAnonymous) {
|
|
290
|
+
console.log(`[Phalanx] Anonymous connection allowed: ${socket.id}`);
|
|
291
|
+
socket.data.authenticated = false;
|
|
292
|
+
return next();
|
|
293
|
+
}
|
|
294
|
+
console.log(`[Phalanx] Connection rejected - no token: ${socket.id}`);
|
|
295
|
+
return next(new Error('Authentication required'));
|
|
296
|
+
}
|
|
297
|
+
// Validate the token
|
|
298
|
+
const result = await this.tokenValidator.validate(token);
|
|
299
|
+
if (!result.valid) {
|
|
300
|
+
console.log(`[Phalanx] Connection rejected - invalid token: ${socket.id} - ${result.error}`);
|
|
301
|
+
return next(new Error(result.error || 'Invalid token'));
|
|
302
|
+
}
|
|
303
|
+
// Store authenticated user info on socket
|
|
304
|
+
socket.data.authenticated = true;
|
|
305
|
+
socket.data.userId = result.userId;
|
|
306
|
+
socket.data.username = result.username;
|
|
307
|
+
console.log(`[Phalanx] Authenticated connection: ${socket.id} - User: ${result.userId}`);
|
|
308
|
+
next();
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Setup socket event handlers
|
|
313
|
+
*/
|
|
314
|
+
setupSocketHandlers() {
|
|
315
|
+
if (!this.io)
|
|
316
|
+
return;
|
|
317
|
+
this.io.on('connection', (socket) => {
|
|
318
|
+
let playerId = null;
|
|
319
|
+
// Track activity on ANY message from client (LOCKSTEP-5)
|
|
320
|
+
// This replaces tick-ack - any message = player is alive
|
|
321
|
+
socket.onAny(() => {
|
|
322
|
+
if (playerId && socket.data.matchId) {
|
|
323
|
+
const gameRoom = this.findMatch(socket.data.matchId);
|
|
324
|
+
if (gameRoom) {
|
|
325
|
+
gameRoom.updatePlayerActivity(playerId);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
// Handle join queue (MATCH-1)
|
|
330
|
+
socket.on('queue-join', (data) => {
|
|
331
|
+
playerId = data.playerId;
|
|
332
|
+
const username = data.username ?? data.playerId;
|
|
333
|
+
this.matchmaking.joinQueue(playerId, username, socket, data.gameType);
|
|
334
|
+
});
|
|
335
|
+
// Handle leave queue (MATCH-2)
|
|
336
|
+
socket.on('queue-leave', () => {
|
|
337
|
+
if (playerId) {
|
|
338
|
+
this.matchmaking.leaveQueue(playerId, socket);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
// Handle room-create (private match)
|
|
342
|
+
socket.on('room-create', (data) => {
|
|
343
|
+
playerId = data.playerId;
|
|
344
|
+
const username = data.username ?? data.playerId;
|
|
345
|
+
this.privateRooms.createRoom(playerId, username, socket, data.gameType);
|
|
346
|
+
});
|
|
347
|
+
// Handle room-join (private match)
|
|
348
|
+
socket.on('room-join', (data) => {
|
|
349
|
+
playerId = data.playerId;
|
|
350
|
+
const username = data.username ?? data.playerId;
|
|
351
|
+
this.privateRooms.joinRoom(playerId, username, socket, data.code);
|
|
352
|
+
});
|
|
353
|
+
// Handle room-cancel (private match)
|
|
354
|
+
socket.on('room-cancel', () => {
|
|
355
|
+
if (playerId) {
|
|
356
|
+
this.privateRooms.cancelRoom(playerId, socket);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
// Handle room-recover (private match)
|
|
360
|
+
// Called when a host reconnects after a transient socket disconnect
|
|
361
|
+
// (e.g. mobile browser killing the WebSocket when the user switches
|
|
362
|
+
// to a messenger to share the invite link) and wants to reclaim
|
|
363
|
+
// their still-alive room. `code` is required to prove the caller
|
|
364
|
+
// is actually the host who created the room — in an anonymous
|
|
365
|
+
// socket environment, `playerId` alone is not an authentication
|
|
366
|
+
// token. If it's missing we reject with the same `Room expired`
|
|
367
|
+
// error the service itself uses, so clients can't distinguish
|
|
368
|
+
// "wrong code" from "missing code" from "no such room".
|
|
369
|
+
socket.on('room-recover', (payload) => {
|
|
370
|
+
// The payload is untrusted — a client can emit literally
|
|
371
|
+
// anything (including `null`, a primitive, or a missing
|
|
372
|
+
// argument, which Socket.IO will surface as `undefined`).
|
|
373
|
+
// Guard the top-level shape before dereferencing any field
|
|
374
|
+
// so a malformed message can't crash the connection
|
|
375
|
+
// handler, and validate each field before touching state
|
|
376
|
+
// on this connection. A failed recover must not mutate the
|
|
377
|
+
// captured `playerId` — otherwise a later handler like
|
|
378
|
+
// `room-cancel` would act on a playerId the socket was
|
|
379
|
+
// never authenticated to own.
|
|
380
|
+
if (!payload || typeof payload !== 'object') {
|
|
381
|
+
socket.emit('room-error', { message: 'Room expired' });
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const data = payload;
|
|
385
|
+
if (typeof data.code !== 'string' || data.code.length === 0) {
|
|
386
|
+
socket.emit('room-error', { message: 'Room expired' });
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (typeof data.playerId !== 'string' || data.playerId.length === 0) {
|
|
390
|
+
socket.emit('room-error', { message: 'Room expired' });
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const recovered = this.privateRooms.recoverRoom(data.playerId, socket, data.code);
|
|
394
|
+
if (recovered) {
|
|
395
|
+
playerId = data.playerId;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
// Handle player command
|
|
399
|
+
socket.on('player-command', (command) => {
|
|
400
|
+
if (!playerId)
|
|
401
|
+
return;
|
|
402
|
+
// Find the match this player is in (check both matchmaking and private rooms)
|
|
403
|
+
const matchId = socket.data.matchId;
|
|
404
|
+
const gameRoom = matchId ? this.findMatch(matchId) : undefined;
|
|
405
|
+
if (gameRoom) {
|
|
406
|
+
const accepted = gameRoom.handleCommand(playerId, command);
|
|
407
|
+
socket.emit('command-ack', {
|
|
408
|
+
tick: command.tick,
|
|
409
|
+
accepted,
|
|
410
|
+
});
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
socket.emit('command-ack', { tick: command.tick, accepted: false });
|
|
414
|
+
});
|
|
415
|
+
// Handle submit-commands (LOCKSTEP-2): batch command submission for a specific tick
|
|
416
|
+
// Clients can submit empty arrays if they have no commands for this tick
|
|
417
|
+
socket.on('submit-commands', (data) => {
|
|
418
|
+
if (!playerId)
|
|
419
|
+
return;
|
|
420
|
+
const { tick, commands } = data;
|
|
421
|
+
// Validate input
|
|
422
|
+
if (!Number.isFinite(tick) || !Array.isArray(commands)) {
|
|
423
|
+
socket.emit('submit-commands-ack', {
|
|
424
|
+
tick,
|
|
425
|
+
accepted: false,
|
|
426
|
+
reason: 'Invalid data',
|
|
427
|
+
});
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
// Find the match this player is in via socket.data
|
|
431
|
+
const matchId = socket.data.matchId;
|
|
432
|
+
if (!matchId) {
|
|
433
|
+
socket.emit('submit-commands-ack', {
|
|
434
|
+
tick,
|
|
435
|
+
accepted: false,
|
|
436
|
+
reason: 'Not in a match',
|
|
437
|
+
});
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
const gameRoom = this.findMatch(matchId);
|
|
441
|
+
if (!gameRoom) {
|
|
442
|
+
socket.emit('submit-commands-ack', {
|
|
443
|
+
tick,
|
|
444
|
+
accepted: false,
|
|
445
|
+
reason: 'Match not found',
|
|
446
|
+
});
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
// Validate each command (NET-1)
|
|
450
|
+
const validCommands = [];
|
|
451
|
+
for (const cmd of commands) {
|
|
452
|
+
// Validate required fields
|
|
453
|
+
if (typeof cmd.type !== 'string' || cmd.data === undefined) {
|
|
454
|
+
socket.emit('command-rejected', {
|
|
455
|
+
reason: 'Missing required fields (type, data)',
|
|
456
|
+
tick,
|
|
457
|
+
type: cmd.type,
|
|
458
|
+
});
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
// Enrich command with playerId and tick, preserve sequence if present
|
|
462
|
+
const enrichedCommand = {
|
|
463
|
+
type: cmd.type,
|
|
464
|
+
data: cmd.data,
|
|
465
|
+
playerId: playerId,
|
|
466
|
+
tick,
|
|
467
|
+
...(cmd.sequence !== undefined && { sequence: cmd.sequence }),
|
|
468
|
+
};
|
|
469
|
+
validCommands.push(enrichedCommand);
|
|
470
|
+
}
|
|
471
|
+
const result = gameRoom.receivePlayerCommands(playerId, tick, validCommands);
|
|
472
|
+
socket.emit('submit-commands-ack', {
|
|
473
|
+
tick,
|
|
474
|
+
accepted: result.accepted,
|
|
475
|
+
...(result.invalidCommands && {
|
|
476
|
+
rejectedCount: result.invalidCommands.length,
|
|
477
|
+
}),
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
// Handle state-hash for desync detection (2.1.3)
|
|
481
|
+
socket.on('state-hash', (data) => {
|
|
482
|
+
if (!playerId)
|
|
483
|
+
return;
|
|
484
|
+
const { tick, hash } = data;
|
|
485
|
+
// Validate input
|
|
486
|
+
if (typeof tick !== 'number' || typeof hash !== 'string') {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
const matchId = socket.data.matchId;
|
|
490
|
+
if (!matchId)
|
|
491
|
+
return;
|
|
492
|
+
const gameRoom = this.findMatch(matchId);
|
|
493
|
+
if (gameRoom) {
|
|
494
|
+
gameRoom.receiveStateHash(playerId, tick, hash);
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
// Note: tick-ack is no longer needed - we use socket.onAny() to track activity
|
|
498
|
+
// Any message from client (including Socket.IO ping) = player is alive
|
|
499
|
+
// Handle pause request
|
|
500
|
+
socket.on('pause-game', () => {
|
|
501
|
+
if (!playerId)
|
|
502
|
+
return;
|
|
503
|
+
const matchId = socket.data.matchId;
|
|
504
|
+
if (!matchId)
|
|
505
|
+
return;
|
|
506
|
+
const gameRoom = this.findMatch(matchId);
|
|
507
|
+
if (gameRoom) {
|
|
508
|
+
gameRoom.pause(playerId);
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
// Handle resume request
|
|
512
|
+
socket.on('resume-game', () => {
|
|
513
|
+
if (!playerId)
|
|
514
|
+
return;
|
|
515
|
+
const matchId = socket.data.matchId;
|
|
516
|
+
if (!matchId)
|
|
517
|
+
return;
|
|
518
|
+
const gameRoom = this.findMatch(matchId);
|
|
519
|
+
if (gameRoom) {
|
|
520
|
+
gameRoom.resume(playerId);
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
// Handle client-ready (ready handshake after asset loading)
|
|
524
|
+
socket.on('client-ready', () => {
|
|
525
|
+
if (!playerId)
|
|
526
|
+
return;
|
|
527
|
+
const matchId = socket.data.matchId;
|
|
528
|
+
if (!matchId)
|
|
529
|
+
return;
|
|
530
|
+
const gameRoom = this.findMatch(matchId);
|
|
531
|
+
if (gameRoom) {
|
|
532
|
+
gameRoom.handlePlayerReady(playerId);
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
// Handle reconnection
|
|
536
|
+
socket.on('reconnect-match', (data) => {
|
|
537
|
+
playerId = data.playerId;
|
|
538
|
+
const gameRoom = this.findMatch(data.matchId);
|
|
539
|
+
if (gameRoom) {
|
|
540
|
+
const success = gameRoom.handleReconnect(playerId, socket.id);
|
|
541
|
+
socket.emit('reconnect-status', { success });
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
socket.emit('reconnect-status', {
|
|
545
|
+
success: false,
|
|
546
|
+
reason: 'Match not found',
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
// Handle disconnect
|
|
551
|
+
socket.on('disconnect', () => {
|
|
552
|
+
if (this.matchmaking) {
|
|
553
|
+
this.matchmaking.handleDisconnect(socket.id);
|
|
554
|
+
}
|
|
555
|
+
if (this.privateRooms) {
|
|
556
|
+
this.privateRooms.handleDisconnect(socket.id);
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Find a GameRoom by matchId across both matchmaking and private room services.
|
|
563
|
+
*/
|
|
564
|
+
findMatch(matchId) {
|
|
565
|
+
return this.matchmaking?.getMatch(matchId) ?? this.privateRooms?.getMatch(matchId);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Register an event handler
|
|
569
|
+
*/
|
|
570
|
+
on(event, handler) {
|
|
571
|
+
return super.on(event, handler);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Remove an event handler
|
|
575
|
+
*/
|
|
576
|
+
off(event, handler) {
|
|
577
|
+
return super.off(event, handler);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Get all active matches (from both matchmaking and private rooms)
|
|
581
|
+
*/
|
|
582
|
+
getActiveMatches() {
|
|
583
|
+
const matchmakingMatches = this.matchmaking?.getActiveMatches() ?? [];
|
|
584
|
+
const privateMatches = this.privateRooms?.getActiveMatches().map((m) => m.getMatchInfo()) ?? [];
|
|
585
|
+
return [...matchmakingMatches, ...privateMatches];
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Get current matchmaking queue size
|
|
589
|
+
*/
|
|
590
|
+
getQueueSize() {
|
|
591
|
+
return this.matchmaking?.getQueueSize() ?? 0;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Get the current configuration
|
|
595
|
+
*/
|
|
596
|
+
getConfig() {
|
|
597
|
+
return { ...this.config };
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
//# sourceMappingURL=Phalanx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Phalanx.js","sourceRoot":"","sources":["../src/Phalanx.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PhalanxConfig, GameModePreset, CustomGameMode } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Game mode presets configuration
|
|
4
|
+
*/
|
|
5
|
+
export declare const GAME_MODES: Record<GameModePreset, CustomGameMode>;
|
|
6
|
+
/**
|
|
7
|
+
* Default configuration values
|
|
8
|
+
*/
|
|
9
|
+
export declare const DEFAULT_CONFIG: PhalanxConfig;
|
|
10
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACf,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,cAAc,EAAE,cAAc,CAM7D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,aA4C5B,CAAC"}
|