quake2ts 0.0.213 → 0.0.215
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 +10 -10
- package/packages/client/dist/browser/index.global.js.map +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 +26 -22
- package/packages/game/dist/cjs/index.cjs.map +1 -1
- package/packages/game/dist/esm/index.js +26 -22
- package/packages/game/dist/esm/index.js.map +1 -1
- package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/game/dist/types/entities/monsters/berserk.d.ts.map +1 -1
- package/packages/server/dist/index.cjs +216 -24
- package/packages/server/dist/index.d.cts +2 -0
- package/packages/server/dist/index.d.ts +2 -0
- package/packages/server/dist/index.js +209 -17
|
@@ -112,7 +112,7 @@ var WebSocketNetDriver = class {
|
|
|
112
112
|
|
|
113
113
|
// src/dedicated.ts
|
|
114
114
|
import { WebSocketServer } from "ws";
|
|
115
|
-
import { createGame } from "@quake2ts/game";
|
|
115
|
+
import { createGame, MulticastType, Solid } from "@quake2ts/game";
|
|
116
116
|
|
|
117
117
|
// src/client.ts
|
|
118
118
|
import { UPDATE_BACKUP } from "@quake2ts/shared";
|
|
@@ -161,7 +161,8 @@ function createClient(index, net) {
|
|
|
161
161
|
lastMessage: 0,
|
|
162
162
|
lastConnect: Date.now(),
|
|
163
163
|
challenge: 0,
|
|
164
|
-
messageQueue: []
|
|
164
|
+
messageQueue: [],
|
|
165
|
+
lastPacketEntities: []
|
|
165
166
|
};
|
|
166
167
|
}
|
|
167
168
|
function createEmptyUserCommand() {
|
|
@@ -262,7 +263,7 @@ var ClientMessageParser = class {
|
|
|
262
263
|
};
|
|
263
264
|
|
|
264
265
|
// src/dedicated.ts
|
|
265
|
-
import { BinaryWriter, ServerCommand, BinaryStream as BinaryStream2, traceBox, MAX_CONFIGSTRINGS as MAX_CONFIGSTRINGS2, MAX_EDICTS, CollisionEntityIndex } from "@quake2ts/shared";
|
|
266
|
+
import { BinaryWriter as BinaryWriter2, ServerCommand as ServerCommand2, BinaryStream as BinaryStream2, traceBox, MAX_CONFIGSTRINGS as MAX_CONFIGSTRINGS2, MAX_EDICTS, CollisionEntityIndex, inPVS, inPHS } from "@quake2ts/shared";
|
|
266
267
|
import { parseBsp } from "@quake2ts/engine";
|
|
267
268
|
import fs from "fs/promises";
|
|
268
269
|
import { createPlayerInventory, createPlayerWeaponStates } from "@quake2ts/game";
|
|
@@ -305,6 +306,24 @@ var NULL_STATE = {
|
|
|
305
306
|
sound: 0,
|
|
306
307
|
event: 0
|
|
307
308
|
};
|
|
309
|
+
function writeRemoveEntity(number, writer) {
|
|
310
|
+
let bits = U_REMOVE;
|
|
311
|
+
if (number >= 256) {
|
|
312
|
+
bits |= U_NUMBER16;
|
|
313
|
+
}
|
|
314
|
+
if (bits & 65280) {
|
|
315
|
+
bits |= U_MOREBITS1;
|
|
316
|
+
}
|
|
317
|
+
writer.writeByte(bits & 255);
|
|
318
|
+
if (bits & U_MOREBITS1) {
|
|
319
|
+
writer.writeByte(bits >> 8 & 255);
|
|
320
|
+
}
|
|
321
|
+
if (bits & U_NUMBER16) {
|
|
322
|
+
writer.writeShort(number);
|
|
323
|
+
} else {
|
|
324
|
+
writer.writeByte(number);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
308
327
|
function writeDeltaEntity(from, to, writer, force, newEntity) {
|
|
309
328
|
let bits = 0;
|
|
310
329
|
if (newEntity) {
|
|
@@ -509,6 +528,113 @@ function writePlayerState(writer, ps) {
|
|
|
509
528
|
}
|
|
510
529
|
}
|
|
511
530
|
|
|
531
|
+
// src/protocol/write.ts
|
|
532
|
+
import { ServerCommand, TempEntity } from "@quake2ts/shared";
|
|
533
|
+
function writeServerCommand(writer, event, ...args) {
|
|
534
|
+
writer.writeByte(event);
|
|
535
|
+
switch (event) {
|
|
536
|
+
case ServerCommand.print: {
|
|
537
|
+
const level = args[0];
|
|
538
|
+
const text = args[1];
|
|
539
|
+
writer.writeByte(level);
|
|
540
|
+
writer.writeString(text);
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
case ServerCommand.muzzleflash: {
|
|
544
|
+
const entIndex = args[0];
|
|
545
|
+
const flashType = args[1];
|
|
546
|
+
writer.writeShort(entIndex);
|
|
547
|
+
writer.writeByte(flashType);
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
case ServerCommand.temp_entity: {
|
|
551
|
+
const type = args[0];
|
|
552
|
+
writer.writeByte(type);
|
|
553
|
+
writeTempEntity(writer, type, args.slice(1));
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
default:
|
|
557
|
+
console.warn(`writeServerCommand: Unhandled command ${event}`);
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function writeTempEntity(writer, type, args) {
|
|
562
|
+
switch (type) {
|
|
563
|
+
case TempEntity.ROCKET_EXPLOSION:
|
|
564
|
+
case TempEntity.GRENADE_EXPLOSION:
|
|
565
|
+
case TempEntity.EXPLOSION1:
|
|
566
|
+
case TempEntity.EXPLOSION2:
|
|
567
|
+
case TempEntity.ROCKET_EXPLOSION_WATER:
|
|
568
|
+
case TempEntity.GRENADE_EXPLOSION_WATER:
|
|
569
|
+
case TempEntity.BFG_EXPLOSION:
|
|
570
|
+
case TempEntity.BFG_BIGEXPLOSION:
|
|
571
|
+
case TempEntity.PLASMA_EXPLOSION:
|
|
572
|
+
case TempEntity.PLAIN_EXPLOSION:
|
|
573
|
+
case TempEntity.TRACKER_EXPLOSION:
|
|
574
|
+
case TempEntity.EXPLOSION1_BIG:
|
|
575
|
+
case TempEntity.EXPLOSION1_NP:
|
|
576
|
+
case TempEntity.EXPLOSION1_NL:
|
|
577
|
+
case TempEntity.EXPLOSION2_NL:
|
|
578
|
+
case TempEntity.BERSERK_SLAM:
|
|
579
|
+
writer.writePos(args[0]);
|
|
580
|
+
break;
|
|
581
|
+
case TempEntity.BLASTER:
|
|
582
|
+
case TempEntity.FLECHETTE:
|
|
583
|
+
writer.writePos(args[0]);
|
|
584
|
+
writer.writeDir(args[1]);
|
|
585
|
+
break;
|
|
586
|
+
case TempEntity.RAILTRAIL:
|
|
587
|
+
case TempEntity.DEBUGTRAIL:
|
|
588
|
+
case TempEntity.BUBBLETRAIL:
|
|
589
|
+
case TempEntity.BUBBLETRAIL2:
|
|
590
|
+
case TempEntity.BFG_LASER:
|
|
591
|
+
case TempEntity.LIGHTNING_BEAM:
|
|
592
|
+
case TempEntity.LIGHTNING:
|
|
593
|
+
writer.writePos(args[0]);
|
|
594
|
+
writer.writePos(args[1]);
|
|
595
|
+
break;
|
|
596
|
+
case TempEntity.LASER_SPARKS:
|
|
597
|
+
case TempEntity.WELDING_SPARKS:
|
|
598
|
+
case TempEntity.TUNNEL_SPARKS:
|
|
599
|
+
case TempEntity.ELECTRIC_SPARKS:
|
|
600
|
+
case TempEntity.HEATBEAM_SPARKS:
|
|
601
|
+
case TempEntity.HEATBEAM_STEAM:
|
|
602
|
+
case TempEntity.STEAM:
|
|
603
|
+
writer.writeByte(args[0]);
|
|
604
|
+
writer.writePos(args[1]);
|
|
605
|
+
writer.writeDir(args[2]);
|
|
606
|
+
writer.writeByte(args[3] || 0);
|
|
607
|
+
break;
|
|
608
|
+
case TempEntity.PARASITE_ATTACK:
|
|
609
|
+
case TempEntity.MEDIC_CABLE_ATTACK:
|
|
610
|
+
const ent = args[0];
|
|
611
|
+
writer.writeShort(ent ? ent.index : 0);
|
|
612
|
+
writer.writePos(args[1]);
|
|
613
|
+
writer.writePos(args[2]);
|
|
614
|
+
break;
|
|
615
|
+
case TempEntity.GUNSHOT:
|
|
616
|
+
case TempEntity.BLOOD:
|
|
617
|
+
case TempEntity.SPARKS:
|
|
618
|
+
case TempEntity.BULLET_SPARKS:
|
|
619
|
+
case TempEntity.SCREEN_SPARKS:
|
|
620
|
+
case TempEntity.SHIELD_SPARKS:
|
|
621
|
+
writer.writePos(args[0]);
|
|
622
|
+
writer.writeDir(args[1]);
|
|
623
|
+
break;
|
|
624
|
+
case TempEntity.SPLASH:
|
|
625
|
+
case TempEntity.POWER_SPLASH:
|
|
626
|
+
case TempEntity.WIDOWSPLASH:
|
|
627
|
+
writer.writeByte(args[0]);
|
|
628
|
+
writer.writePos(args[1]);
|
|
629
|
+
writer.writeDir(args[2]);
|
|
630
|
+
writer.writeByte(args[3] || 0);
|
|
631
|
+
break;
|
|
632
|
+
default:
|
|
633
|
+
console.warn(`writeTempEntity: Unhandled TempEntity ${type}`);
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
512
638
|
// src/dedicated.ts
|
|
513
639
|
var MAX_CLIENTS = 16;
|
|
514
640
|
var FRAME_RATE = 10;
|
|
@@ -649,10 +775,33 @@ var DedicatedServer = class {
|
|
|
649
775
|
});
|
|
650
776
|
this.game.init(0);
|
|
651
777
|
this.game.spawnWorld();
|
|
778
|
+
this.populateBaselines();
|
|
652
779
|
this.sv.state = 2 /* Game */;
|
|
653
780
|
this.frameInterval = setInterval(() => this.runFrame(), FRAME_TIME_MS);
|
|
654
781
|
console.log("Server started.");
|
|
655
782
|
}
|
|
783
|
+
populateBaselines() {
|
|
784
|
+
if (!this.game) return;
|
|
785
|
+
this.game.entities.forEachEntity((ent) => {
|
|
786
|
+
if (ent.index >= MAX_EDICTS) return;
|
|
787
|
+
if (ent.modelindex > 0 || ent.solid !== Solid.Not) {
|
|
788
|
+
this.sv.baselines[ent.index] = {
|
|
789
|
+
number: ent.index,
|
|
790
|
+
origin: { ...ent.origin },
|
|
791
|
+
angles: { ...ent.angles },
|
|
792
|
+
modelIndex: ent.modelindex,
|
|
793
|
+
frame: ent.frame,
|
|
794
|
+
skinNum: ent.skin,
|
|
795
|
+
effects: ent.effects,
|
|
796
|
+
renderfx: ent.renderfx,
|
|
797
|
+
solid: ent.solid,
|
|
798
|
+
sound: ent.sounds,
|
|
799
|
+
// Assuming ent.sounds maps to 'sound' field in EntityState
|
|
800
|
+
event: 0
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
}
|
|
656
805
|
stop() {
|
|
657
806
|
if (this.frameInterval) clearInterval(this.frameInterval);
|
|
658
807
|
if (this.wss) this.wss.close();
|
|
@@ -715,14 +864,14 @@ var DedicatedServer = class {
|
|
|
715
864
|
client.userInfo = userInfo;
|
|
716
865
|
console.log(`Client ${client.index} connected: ${userInfo}`);
|
|
717
866
|
this.sendServerData(client);
|
|
718
|
-
const writer = new
|
|
719
|
-
writer.writeByte(
|
|
867
|
+
const writer = new BinaryWriter2();
|
|
868
|
+
writer.writeByte(ServerCommand2.stufftext);
|
|
720
869
|
writer.writeString("precache\n");
|
|
721
870
|
client.net.send(writer.getData());
|
|
722
871
|
} else {
|
|
723
872
|
console.log(`Client ${client.index} rejected: ${result}`);
|
|
724
|
-
const writer = new
|
|
725
|
-
writer.writeByte(
|
|
873
|
+
const writer = new BinaryWriter2();
|
|
874
|
+
writer.writeByte(ServerCommand2.print);
|
|
726
875
|
writer.writeByte(2);
|
|
727
876
|
writer.writeString(`Connection rejected: ${result}
|
|
728
877
|
`);
|
|
@@ -746,8 +895,8 @@ var DedicatedServer = class {
|
|
|
746
895
|
console.log(`Client ${client.index} entered game`);
|
|
747
896
|
}
|
|
748
897
|
sendServerData(client) {
|
|
749
|
-
const writer = new
|
|
750
|
-
writer.writeByte(
|
|
898
|
+
const writer = new BinaryWriter2();
|
|
899
|
+
writer.writeByte(ServerCommand2.serverdata);
|
|
751
900
|
writer.writeLong(34);
|
|
752
901
|
writer.writeLong(this.sv.frame);
|
|
753
902
|
writer.writeByte(0);
|
|
@@ -761,7 +910,7 @@ var DedicatedServer = class {
|
|
|
761
910
|
}
|
|
762
911
|
for (let i = 0; i < MAX_EDICTS; i++) {
|
|
763
912
|
if (this.sv.baselines[i]) {
|
|
764
|
-
writer.writeByte(
|
|
913
|
+
writer.writeByte(ServerCommand2.spawnbaseline);
|
|
765
914
|
writeDeltaEntity({}, this.sv.baselines[i], writer, true, true);
|
|
766
915
|
}
|
|
767
916
|
}
|
|
@@ -770,7 +919,7 @@ var DedicatedServer = class {
|
|
|
770
919
|
SV_SetConfigString(index, value) {
|
|
771
920
|
if (index < 0 || index >= MAX_CONFIGSTRINGS2) return;
|
|
772
921
|
this.sv.configStrings[index] = value;
|
|
773
|
-
const writer = new
|
|
922
|
+
const writer = new BinaryWriter2();
|
|
774
923
|
this.SV_WriteConfigString(writer, index, value);
|
|
775
924
|
const data = writer.getData();
|
|
776
925
|
for (const client of this.svs.clients) {
|
|
@@ -780,7 +929,7 @@ var DedicatedServer = class {
|
|
|
780
929
|
}
|
|
781
930
|
}
|
|
782
931
|
SV_WriteConfigString(writer, index, value) {
|
|
783
|
-
writer.writeByte(
|
|
932
|
+
writer.writeByte(ServerCommand2.configstring);
|
|
784
933
|
writer.writeShort(index);
|
|
785
934
|
writer.writeString(value);
|
|
786
935
|
}
|
|
@@ -836,13 +985,13 @@ var DedicatedServer = class {
|
|
|
836
985
|
}
|
|
837
986
|
}
|
|
838
987
|
SV_SendClientFrame(client, snapshot) {
|
|
839
|
-
const writer = new
|
|
840
|
-
writer.writeByte(
|
|
988
|
+
const writer = new BinaryWriter2();
|
|
989
|
+
writer.writeByte(ServerCommand2.frame);
|
|
841
990
|
writer.writeLong(this.sv.frame);
|
|
842
991
|
writer.writeLong(0);
|
|
843
992
|
writer.writeByte(0);
|
|
844
993
|
writer.writeByte(0);
|
|
845
|
-
writer.writeByte(
|
|
994
|
+
writer.writeByte(ServerCommand2.playerinfo);
|
|
846
995
|
const ps = {
|
|
847
996
|
pm_type: snapshot.pmType,
|
|
848
997
|
origin: snapshot.origin,
|
|
@@ -870,24 +1019,67 @@ var DedicatedServer = class {
|
|
|
870
1019
|
stats: snapshot.stats
|
|
871
1020
|
};
|
|
872
1021
|
writePlayerState(writer, ps);
|
|
873
|
-
writer.writeByte(
|
|
1022
|
+
writer.writeByte(ServerCommand2.packetentities);
|
|
874
1023
|
const entities = snapshot.packetEntities || [];
|
|
1024
|
+
const currentEntityIds = [];
|
|
875
1025
|
for (const entity of entities) {
|
|
1026
|
+
currentEntityIds.push(entity.number);
|
|
876
1027
|
writeDeltaEntity({}, entity, writer, false, true);
|
|
877
1028
|
}
|
|
1029
|
+
for (const oldId of client.lastPacketEntities) {
|
|
1030
|
+
if (!currentEntityIds.includes(oldId)) {
|
|
1031
|
+
writeRemoveEntity(oldId, writer);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
878
1034
|
writer.writeShort(0);
|
|
879
1035
|
client.net.send(writer.getData());
|
|
880
1036
|
client.lastFrame = this.sv.frame;
|
|
1037
|
+
client.lastPacketEntities = currentEntityIds;
|
|
881
1038
|
}
|
|
882
1039
|
// GameEngine Implementation
|
|
883
1040
|
trace(start, end) {
|
|
884
1041
|
return { fraction: 1 };
|
|
885
1042
|
}
|
|
886
1043
|
multicast(origin, type, event, ...args) {
|
|
1044
|
+
const writer = new BinaryWriter2();
|
|
1045
|
+
writeServerCommand(writer, event, ...args);
|
|
1046
|
+
const data = writer.getData();
|
|
1047
|
+
const reliable = event === ServerCommand2.print || event === ServerCommand2.configstring;
|
|
1048
|
+
for (const client of this.svs.clients) {
|
|
1049
|
+
if (!client || client.state < 4 /* Active */ || !client.edict) {
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
let send = false;
|
|
1053
|
+
switch (type) {
|
|
1054
|
+
case MulticastType.All:
|
|
1055
|
+
send = true;
|
|
1056
|
+
break;
|
|
1057
|
+
case MulticastType.Pvs:
|
|
1058
|
+
if (this.sv.collisionModel) {
|
|
1059
|
+
send = inPVS(origin, client.edict.origin, this.sv.collisionModel);
|
|
1060
|
+
} else {
|
|
1061
|
+
send = true;
|
|
1062
|
+
}
|
|
1063
|
+
break;
|
|
1064
|
+
case MulticastType.Phs:
|
|
1065
|
+
if (this.sv.collisionModel) {
|
|
1066
|
+
send = inPHS(origin, client.edict.origin, this.sv.collisionModel);
|
|
1067
|
+
} else {
|
|
1068
|
+
send = true;
|
|
1069
|
+
}
|
|
1070
|
+
break;
|
|
1071
|
+
}
|
|
1072
|
+
if (send) {
|
|
1073
|
+
client.net.send(data);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
887
1076
|
}
|
|
888
1077
|
unicast(ent, reliable, event, ...args) {
|
|
889
1078
|
const client = this.svs.clients.find((c) => c?.edict === ent);
|
|
890
|
-
if (client) {
|
|
1079
|
+
if (client && client.state >= 2 /* Connected */) {
|
|
1080
|
+
const writer = new BinaryWriter2();
|
|
1081
|
+
writeServerCommand(writer, event, ...args);
|
|
1082
|
+
client.net.send(writer.getData());
|
|
891
1083
|
}
|
|
892
1084
|
}
|
|
893
1085
|
configstring(index, value) {
|