quake2ts 0.0.181 → 0.0.183
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/package.json +1 -1
- package/packages/client/dist/browser/index.global.js.map +1 -1
- package/packages/client/dist/cjs/index.cjs.map +1 -1
- package/packages/client/dist/esm/index.js.map +1 -1
- package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/engine/dist/browser/index.global.js +1 -1
- package/packages/engine/dist/browser/index.global.js.map +1 -1
- package/packages/engine/dist/cjs/index.cjs.map +1 -1
- package/packages/engine/dist/esm/index.js.map +1 -1
- package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/game/dist/browser/index.global.js +2 -2
- package/packages/game/dist/browser/index.global.js.map +1 -1
- package/packages/game/dist/cjs/index.cjs.map +1 -1
- package/packages/game/dist/esm/index.js.map +1 -1
- package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/server/dist/index.cjs +281 -57
- package/packages/server/dist/index.d.cts +33 -10
- package/packages/server/dist/index.d.ts +33 -10
- package/packages/server/dist/index.js +270 -46
- package/packages/shared/dist/browser/index.global.js +1 -1
- package/packages/shared/dist/browser/index.global.js.map +1 -1
- package/packages/shared/dist/cjs/index.cjs +17 -0
- package/packages/shared/dist/cjs/index.cjs.map +1 -1
- package/packages/shared/dist/esm/index.js +12 -0
- package/packages/shared/dist/esm/index.js.map +1 -1
- package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/shared/dist/types/protocol/constants.d.ts +6 -0
- package/packages/shared/dist/types/protocol/constants.d.ts.map +1 -0
- package/packages/shared/dist/types/protocol/index.d.ts +1 -0
- package/packages/shared/dist/types/protocol/index.d.ts.map +1 -1
- package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
|
@@ -115,32 +115,77 @@ import { WebSocketServer } from "ws";
|
|
|
115
115
|
import { createGame } from "@quake2ts/game";
|
|
116
116
|
|
|
117
117
|
// src/client.ts
|
|
118
|
+
import { UPDATE_BACKUP } from "@quake2ts/shared";
|
|
118
119
|
var ClientState = /* @__PURE__ */ ((ClientState2) => {
|
|
119
120
|
ClientState2[ClientState2["Free"] = 0] = "Free";
|
|
120
|
-
ClientState2[ClientState2["
|
|
121
|
-
ClientState2[ClientState2["
|
|
122
|
-
ClientState2[ClientState2["
|
|
123
|
-
ClientState2[ClientState2["
|
|
121
|
+
ClientState2[ClientState2["Zombie"] = 1] = "Zombie";
|
|
122
|
+
ClientState2[ClientState2["Connected"] = 2] = "Connected";
|
|
123
|
+
ClientState2[ClientState2["Spawned"] = 3] = "Spawned";
|
|
124
|
+
ClientState2[ClientState2["Active"] = 4] = "Active";
|
|
124
125
|
return ClientState2;
|
|
125
126
|
})(ClientState || {});
|
|
126
127
|
function createClient(index, net) {
|
|
128
|
+
const frames = [];
|
|
129
|
+
for (let i = 0; i < UPDATE_BACKUP; i++) {
|
|
130
|
+
frames.push({
|
|
131
|
+
areaBytes: 0,
|
|
132
|
+
areaBits: new Uint8Array(0),
|
|
133
|
+
// Size depends on map areas
|
|
134
|
+
playerState: createEmptyPlayerState(),
|
|
135
|
+
numEntities: 0,
|
|
136
|
+
firstEntity: 0,
|
|
137
|
+
sentTime: 0
|
|
138
|
+
});
|
|
139
|
+
}
|
|
127
140
|
return {
|
|
128
141
|
index,
|
|
129
|
-
state:
|
|
142
|
+
state: 2 /* Connected */,
|
|
130
143
|
net,
|
|
131
|
-
name: `Player ${index}`,
|
|
132
144
|
userInfo: "",
|
|
145
|
+
lastFrame: 0,
|
|
146
|
+
lastCmd: createEmptyUserCommand(),
|
|
147
|
+
commandMsec: 0,
|
|
148
|
+
frameLatency: [],
|
|
149
|
+
ping: 0,
|
|
150
|
+
messageSize: [],
|
|
151
|
+
rate: 25e3,
|
|
152
|
+
// Default rate
|
|
153
|
+
suppressCount: 0,
|
|
133
154
|
edict: null,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
name: `Player ${index}`,
|
|
156
|
+
messageLevel: 0,
|
|
157
|
+
datagram: new Uint8Array(0),
|
|
158
|
+
frames,
|
|
159
|
+
downloadSize: 0,
|
|
160
|
+
downloadCount: 0,
|
|
161
|
+
lastMessage: 0,
|
|
162
|
+
lastConnect: Date.now(),
|
|
163
|
+
challenge: 0,
|
|
164
|
+
messageQueue: []
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function createEmptyUserCommand() {
|
|
168
|
+
return {
|
|
169
|
+
msec: 0,
|
|
170
|
+
buttons: 0,
|
|
171
|
+
angles: { x: 0, y: 0, z: 0 },
|
|
172
|
+
forwardmove: 0,
|
|
173
|
+
sidemove: 0,
|
|
174
|
+
upmove: 0
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function createEmptyPlayerState() {
|
|
178
|
+
return {
|
|
179
|
+
origin: { x: 0, y: 0, z: 0 },
|
|
180
|
+
velocity: { x: 0, y: 0, z: 0 },
|
|
181
|
+
viewAngles: { x: 0, y: 0, z: 0 },
|
|
182
|
+
onGround: false,
|
|
183
|
+
waterLevel: 0,
|
|
184
|
+
mins: { x: -16, y: -16, z: -24 },
|
|
185
|
+
maxs: { x: 16, y: 16, z: 32 },
|
|
186
|
+
damageAlpha: 0,
|
|
187
|
+
damageIndicators: [],
|
|
188
|
+
blend: [0, 0, 0, 0]
|
|
144
189
|
};
|
|
145
190
|
}
|
|
146
191
|
|
|
@@ -211,10 +256,150 @@ var ClientMessageParser = class {
|
|
|
211
256
|
};
|
|
212
257
|
|
|
213
258
|
// src/dedicated.ts
|
|
214
|
-
import { BinaryWriter, ServerCommand, BinaryStream as BinaryStream2, traceBox } from "@quake2ts/shared";
|
|
259
|
+
import { BinaryWriter, ServerCommand, BinaryStream as BinaryStream2, traceBox, MAX_CONFIGSTRINGS as MAX_CONFIGSTRINGS2, MAX_EDICTS } from "@quake2ts/shared";
|
|
215
260
|
import { parseBsp } from "@quake2ts/engine";
|
|
216
261
|
import fs from "fs/promises";
|
|
217
262
|
import { createPlayerInventory, createPlayerWeaponStates } from "@quake2ts/game";
|
|
263
|
+
|
|
264
|
+
// src/protocol/entity.ts
|
|
265
|
+
var U_ORIGIN1 = 1 << 0;
|
|
266
|
+
var U_ORIGIN2 = 1 << 1;
|
|
267
|
+
var U_ANGLE2 = 1 << 2;
|
|
268
|
+
var U_ANGLE3 = 1 << 3;
|
|
269
|
+
var U_FRAME8 = 1 << 4;
|
|
270
|
+
var U_EVENT = 1 << 5;
|
|
271
|
+
var U_REMOVE = 1 << 6;
|
|
272
|
+
var U_MOREBITS1 = 1 << 7;
|
|
273
|
+
var U_NUMBER16 = 1 << 8;
|
|
274
|
+
var U_ORIGIN3 = 1 << 9;
|
|
275
|
+
var U_ANGLE1 = 1 << 10;
|
|
276
|
+
var U_MODEL = 1 << 11;
|
|
277
|
+
var U_RENDERFX8 = 1 << 12;
|
|
278
|
+
var U_EFFECTS8 = 1 << 14;
|
|
279
|
+
var U_MOREBITS2 = 1 << 15;
|
|
280
|
+
var U_SKIN8 = 1 << 16;
|
|
281
|
+
var U_FRAME16 = 1 << 17;
|
|
282
|
+
var U_RENDERFX16 = 1 << 18;
|
|
283
|
+
var U_EFFECTS16 = 1 << 19;
|
|
284
|
+
var U_MOREBITS3 = 1 << 23;
|
|
285
|
+
var U_OLDORIGIN = 1 << 24;
|
|
286
|
+
var U_SKIN16 = 1 << 25;
|
|
287
|
+
var U_SOUND = 1 << 26;
|
|
288
|
+
var U_SOLID = 1 << 27;
|
|
289
|
+
var NULL_STATE = {
|
|
290
|
+
number: 0,
|
|
291
|
+
origin: { x: 0, y: 0, z: 0 },
|
|
292
|
+
angles: { x: 0, y: 0, z: 0 },
|
|
293
|
+
modelIndex: 0,
|
|
294
|
+
frame: 0,
|
|
295
|
+
skinNum: 0,
|
|
296
|
+
effects: 0,
|
|
297
|
+
renderfx: 0,
|
|
298
|
+
solid: 0,
|
|
299
|
+
sound: 0,
|
|
300
|
+
event: 0
|
|
301
|
+
};
|
|
302
|
+
function writeDeltaEntity(from, to, writer, force, newEntity) {
|
|
303
|
+
let bits = 0;
|
|
304
|
+
if (newEntity) {
|
|
305
|
+
from = NULL_STATE;
|
|
306
|
+
}
|
|
307
|
+
if (to.modelIndex !== from.modelIndex || force) {
|
|
308
|
+
bits |= U_MODEL;
|
|
309
|
+
}
|
|
310
|
+
if (to.origin.x !== from.origin.x || force) {
|
|
311
|
+
bits |= U_ORIGIN1;
|
|
312
|
+
}
|
|
313
|
+
if (to.origin.y !== from.origin.y || force) {
|
|
314
|
+
bits |= U_ORIGIN2;
|
|
315
|
+
}
|
|
316
|
+
if (to.origin.z !== from.origin.z || force) {
|
|
317
|
+
bits |= U_ORIGIN3;
|
|
318
|
+
}
|
|
319
|
+
if (to.angles.x !== from.angles.x || force) {
|
|
320
|
+
bits |= U_ANGLE1;
|
|
321
|
+
}
|
|
322
|
+
if (to.angles.y !== from.angles.y || force) {
|
|
323
|
+
bits |= U_ANGLE2;
|
|
324
|
+
}
|
|
325
|
+
if (to.angles.z !== from.angles.z || force) {
|
|
326
|
+
bits |= U_ANGLE3;
|
|
327
|
+
}
|
|
328
|
+
if (to.frame !== from.frame || force) {
|
|
329
|
+
if (to.frame >= 256) bits |= U_FRAME16;
|
|
330
|
+
else bits |= U_FRAME8;
|
|
331
|
+
}
|
|
332
|
+
if (to.skinNum !== from.skinNum || force) {
|
|
333
|
+
if (to.skinNum >= 256) bits |= U_SKIN16;
|
|
334
|
+
else bits |= U_SKIN8;
|
|
335
|
+
}
|
|
336
|
+
if (to.effects !== from.effects || force) {
|
|
337
|
+
if (to.effects >= 256) bits |= U_EFFECTS16;
|
|
338
|
+
else bits |= U_EFFECTS8;
|
|
339
|
+
}
|
|
340
|
+
if (to.renderfx !== from.renderfx || force) {
|
|
341
|
+
if (to.renderfx >= 256) bits |= U_RENDERFX16;
|
|
342
|
+
else bits |= U_RENDERFX8;
|
|
343
|
+
}
|
|
344
|
+
if (to.solid !== from.solid || force) {
|
|
345
|
+
bits |= U_SOLID;
|
|
346
|
+
}
|
|
347
|
+
if (to.sound !== from.sound || force) {
|
|
348
|
+
bits |= U_SOUND;
|
|
349
|
+
}
|
|
350
|
+
if (to.event !== from.event || force) {
|
|
351
|
+
bits |= U_EVENT;
|
|
352
|
+
}
|
|
353
|
+
if (to.number >= 256) {
|
|
354
|
+
bits |= U_NUMBER16;
|
|
355
|
+
}
|
|
356
|
+
if (bits & 4294967040) {
|
|
357
|
+
bits |= U_MOREBITS1;
|
|
358
|
+
}
|
|
359
|
+
if (bits & 4294901760) {
|
|
360
|
+
bits |= U_MOREBITS2;
|
|
361
|
+
}
|
|
362
|
+
if (bits & 4278190080) {
|
|
363
|
+
bits |= U_MOREBITS3;
|
|
364
|
+
}
|
|
365
|
+
writer.writeByte(bits & 255);
|
|
366
|
+
if (bits & U_MOREBITS1) {
|
|
367
|
+
writer.writeByte(bits >> 8 & 255);
|
|
368
|
+
}
|
|
369
|
+
if (bits & U_MOREBITS2) {
|
|
370
|
+
writer.writeByte(bits >> 16 & 255);
|
|
371
|
+
}
|
|
372
|
+
if (bits & U_MOREBITS3) {
|
|
373
|
+
writer.writeByte(bits >> 24 & 255);
|
|
374
|
+
}
|
|
375
|
+
if (bits & U_NUMBER16) {
|
|
376
|
+
writer.writeShort(to.number);
|
|
377
|
+
} else {
|
|
378
|
+
writer.writeByte(to.number);
|
|
379
|
+
}
|
|
380
|
+
if (bits & U_MODEL) writer.writeByte(to.modelIndex);
|
|
381
|
+
if (bits & U_FRAME8) writer.writeByte(to.frame);
|
|
382
|
+
if (bits & U_FRAME16) writer.writeShort(to.frame);
|
|
383
|
+
if (bits & U_SKIN8) writer.writeByte(to.skinNum);
|
|
384
|
+
if (bits & U_SKIN16) writer.writeShort(to.skinNum);
|
|
385
|
+
if (bits & U_EFFECTS8) writer.writeByte(to.effects);
|
|
386
|
+
if (bits & U_EFFECTS16) writer.writeShort(to.effects);
|
|
387
|
+
if (bits & U_RENDERFX8) writer.writeByte(to.renderfx);
|
|
388
|
+
if (bits & U_RENDERFX16) writer.writeShort(to.renderfx);
|
|
389
|
+
if (bits & U_ORIGIN1) writer.writeCoord(to.origin.x);
|
|
390
|
+
if (bits & U_ORIGIN2) writer.writeCoord(to.origin.y);
|
|
391
|
+
if (bits & U_ORIGIN3) writer.writeCoord(to.origin.z);
|
|
392
|
+
if (bits & U_ANGLE1) writer.writeAngle(to.angles.x);
|
|
393
|
+
if (bits & U_ANGLE2) writer.writeAngle(to.angles.y);
|
|
394
|
+
if (bits & U_ANGLE3) writer.writeAngle(to.angles.z);
|
|
395
|
+
if (bits & U_OLDORIGIN) {
|
|
396
|
+
}
|
|
397
|
+
if (bits & U_SOUND) writer.writeByte(to.sound ?? 0);
|
|
398
|
+
if (bits & U_EVENT) writer.writeByte(to.event ?? 0);
|
|
399
|
+
if (bits & U_SOLID) writer.writeShort(to.solid);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/dedicated.ts
|
|
218
403
|
var MAX_CLIENTS = 16;
|
|
219
404
|
var FRAME_RATE = 10;
|
|
220
405
|
var FRAME_TIME_MS = 1e3 / FRAME_RATE;
|
|
@@ -225,27 +410,43 @@ var DedicatedServer = class {
|
|
|
225
410
|
this.game = null;
|
|
226
411
|
this.frameInterval = null;
|
|
227
412
|
this.svs = {
|
|
228
|
-
|
|
413
|
+
initialized: false,
|
|
414
|
+
realTime: 0,
|
|
415
|
+
mapCmd: "",
|
|
416
|
+
spawnCount: 0,
|
|
417
|
+
clients: new Array(MAX_CLIENTS).fill(null),
|
|
418
|
+
lastHeartbeat: 0,
|
|
419
|
+
challenges: []
|
|
229
420
|
};
|
|
230
421
|
this.sv = {
|
|
422
|
+
state: 0 /* Dead */,
|
|
423
|
+
attractLoop: false,
|
|
424
|
+
loadGame: false,
|
|
231
425
|
startTime: 0,
|
|
426
|
+
// Initialize startTime
|
|
232
427
|
time: 0,
|
|
233
428
|
frame: 0,
|
|
234
|
-
|
|
235
|
-
collisionModel: null
|
|
429
|
+
name: "",
|
|
430
|
+
collisionModel: null,
|
|
431
|
+
configStrings: new Array(MAX_CONFIGSTRINGS2).fill(""),
|
|
432
|
+
baselines: new Array(MAX_EDICTS).fill(null),
|
|
433
|
+
multicastBuf: new Uint8Array(0)
|
|
236
434
|
};
|
|
237
435
|
}
|
|
238
436
|
async start(mapName) {
|
|
239
437
|
console.log(`Starting Dedicated Server on port ${this.port}...`);
|
|
240
|
-
this.sv.
|
|
438
|
+
this.sv.name = mapName;
|
|
439
|
+
this.svs.initialized = true;
|
|
440
|
+
this.svs.spawnCount++;
|
|
241
441
|
this.wss = new WebSocketServer({ port: this.port });
|
|
242
442
|
this.wss.on("connection", (ws) => {
|
|
243
443
|
console.log("New connection");
|
|
244
444
|
this.handleConnection(ws);
|
|
245
445
|
});
|
|
246
446
|
try {
|
|
247
|
-
console.log(`Loading map ${this.sv.
|
|
248
|
-
|
|
447
|
+
console.log(`Loading map ${this.sv.name}...`);
|
|
448
|
+
this.sv.state = 1 /* Loading */;
|
|
449
|
+
const mapData = await fs.readFile(this.sv.name);
|
|
249
450
|
const arrayBuffer = mapData.buffer.slice(mapData.byteOffset, mapData.byteOffset + mapData.byteLength);
|
|
250
451
|
const bspMap = parseBsp(arrayBuffer);
|
|
251
452
|
this.sv.collisionModel = bspMap;
|
|
@@ -302,6 +503,7 @@ var DedicatedServer = class {
|
|
|
302
503
|
});
|
|
303
504
|
this.game.init(0);
|
|
304
505
|
this.game.spawnWorld();
|
|
506
|
+
this.sv.state = 2 /* Game */;
|
|
305
507
|
this.frameInterval = setInterval(() => this.runFrame(), FRAME_TIME_MS);
|
|
306
508
|
console.log("Server started.");
|
|
307
509
|
}
|
|
@@ -309,6 +511,7 @@ var DedicatedServer = class {
|
|
|
309
511
|
if (this.frameInterval) clearInterval(this.frameInterval);
|
|
310
512
|
if (this.wss) this.wss.close();
|
|
311
513
|
this.game?.shutdown();
|
|
514
|
+
this.sv.state = 0 /* Dead */;
|
|
312
515
|
}
|
|
313
516
|
handleConnection(ws) {
|
|
314
517
|
let clientIndex = -1;
|
|
@@ -331,19 +534,7 @@ var DedicatedServer = class {
|
|
|
331
534
|
}
|
|
332
535
|
onClientMessage(client, data) {
|
|
333
536
|
const buffer = data.byteOffset === 0 && data.byteLength === data.buffer.byteLength ? data.buffer : data.slice().buffer;
|
|
334
|
-
|
|
335
|
-
const parser = new ClientMessageParser(reader, {
|
|
336
|
-
onMove: (checksum, lastFrame, cmd) => this.handleMove(client, cmd),
|
|
337
|
-
onUserInfo: (info) => this.handleUserInfo(client, info),
|
|
338
|
-
onStringCmd: (cmd) => this.handleStringCmd(client, cmd),
|
|
339
|
-
onNop: () => {
|
|
340
|
-
},
|
|
341
|
-
onBad: () => {
|
|
342
|
-
console.warn(`Bad command from client ${client.index}`);
|
|
343
|
-
client.net.disconnect();
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
parser.parseMessage();
|
|
537
|
+
client.messageQueue.push(new Uint8Array(buffer));
|
|
347
538
|
}
|
|
348
539
|
onClientDisconnect(client) {
|
|
349
540
|
console.log(`Client ${client.index} disconnected`);
|
|
@@ -351,8 +542,8 @@ var DedicatedServer = class {
|
|
|
351
542
|
}
|
|
352
543
|
handleMove(client, cmd) {
|
|
353
544
|
client.lastCmd = cmd;
|
|
354
|
-
client.
|
|
355
|
-
if (client.state ===
|
|
545
|
+
client.lastMessage = this.sv.frame;
|
|
546
|
+
if (client.state === 2 /* Connected */) {
|
|
356
547
|
this.spawnClient(client);
|
|
357
548
|
}
|
|
358
549
|
}
|
|
@@ -369,7 +560,7 @@ var DedicatedServer = class {
|
|
|
369
560
|
buttons: 0
|
|
370
561
|
});
|
|
371
562
|
client.edict = ent;
|
|
372
|
-
client.state =
|
|
563
|
+
client.state = 4 /* Active */;
|
|
373
564
|
this.sendServerData(client);
|
|
374
565
|
}
|
|
375
566
|
sendServerData(client) {
|
|
@@ -384,31 +575,57 @@ var DedicatedServer = class {
|
|
|
384
575
|
client.net.send(writer.getData());
|
|
385
576
|
}
|
|
386
577
|
SV_ReadPackets() {
|
|
578
|
+
for (const client of this.svs.clients) {
|
|
579
|
+
if (!client || client.state === 0 /* Free */) continue;
|
|
580
|
+
while (client.messageQueue.length > 0) {
|
|
581
|
+
const data = client.messageQueue.shift();
|
|
582
|
+
if (!data) continue;
|
|
583
|
+
const reader = new BinaryStream2(data.buffer);
|
|
584
|
+
const parser = new ClientMessageParser(reader, {
|
|
585
|
+
onMove: (checksum, lastFrame, cmd) => this.handleMove(client, cmd),
|
|
586
|
+
onUserInfo: (info) => this.handleUserInfo(client, info),
|
|
587
|
+
onStringCmd: (cmd) => this.handleStringCmd(client, cmd),
|
|
588
|
+
onNop: () => {
|
|
589
|
+
},
|
|
590
|
+
onBad: () => {
|
|
591
|
+
console.warn(`Bad command from client ${client.index}`);
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
try {
|
|
595
|
+
parser.parseMessage();
|
|
596
|
+
} catch (e) {
|
|
597
|
+
console.error(`Error parsing message from client ${client.index}:`, e);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
387
601
|
}
|
|
388
602
|
runFrame() {
|
|
389
603
|
if (!this.game) return;
|
|
390
604
|
this.sv.frame++;
|
|
605
|
+
this.sv.time += 100;
|
|
391
606
|
this.SV_ReadPackets();
|
|
392
607
|
for (const client of this.svs.clients) {
|
|
393
|
-
if (client && client.state ===
|
|
608
|
+
if (client && client.state === 4 /* Active */ && client.edict) {
|
|
394
609
|
this.game.clientThink(client.edict, client.lastCmd);
|
|
395
610
|
}
|
|
396
611
|
}
|
|
397
|
-
this.game.frame({
|
|
612
|
+
const snapshot = this.game.frame({
|
|
398
613
|
frame: this.sv.frame,
|
|
399
614
|
deltaMs: FRAME_TIME_MS,
|
|
400
615
|
nowMs: Date.now()
|
|
401
616
|
});
|
|
402
|
-
|
|
617
|
+
if (snapshot && snapshot.state) {
|
|
618
|
+
this.SV_SendClientMessages(snapshot.state);
|
|
619
|
+
}
|
|
403
620
|
}
|
|
404
|
-
SV_SendClientMessages() {
|
|
621
|
+
SV_SendClientMessages(snapshot) {
|
|
405
622
|
for (const client of this.svs.clients) {
|
|
406
|
-
if (client && client.state ===
|
|
407
|
-
this.SV_SendClientFrame(client);
|
|
623
|
+
if (client && client.state === 4 /* Active */) {
|
|
624
|
+
this.SV_SendClientFrame(client, snapshot);
|
|
408
625
|
}
|
|
409
626
|
}
|
|
410
627
|
}
|
|
411
|
-
SV_SendClientFrame(client) {
|
|
628
|
+
SV_SendClientFrame(client, snapshot) {
|
|
412
629
|
const writer = new BinaryWriter();
|
|
413
630
|
writer.writeByte(ServerCommand.frame);
|
|
414
631
|
writer.writeLong(this.sv.frame);
|
|
@@ -418,7 +635,14 @@ var DedicatedServer = class {
|
|
|
418
635
|
writer.writeByte(ServerCommand.playerinfo);
|
|
419
636
|
writer.writeShort(0);
|
|
420
637
|
writer.writeLong(0);
|
|
638
|
+
writer.writeByte(ServerCommand.packetentities);
|
|
639
|
+
const entities = snapshot.packetEntities || [];
|
|
640
|
+
for (const entity of entities) {
|
|
641
|
+
writeDeltaEntity({}, entity, writer, false, true);
|
|
642
|
+
}
|
|
643
|
+
writer.writeShort(0);
|
|
421
644
|
client.net.send(writer.getData());
|
|
645
|
+
client.lastFrame = this.sv.frame;
|
|
422
646
|
}
|
|
423
647
|
// GameEngine Implementation
|
|
424
648
|
trace(start, end) {
|