teeworlds 2.4.5 → 2.4.7
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 +7 -7
- package/docs/events.md +367 -0
- package/docs/examples/chat_bot.js +25 -0
- package/docs/examples/kill_on_freeze.js +20 -0
- package/lib/MsgUnpacker.js +6 -0
- package/lib/MsgUnpacker.ts +7 -0
- package/lib/UUIDManager.js +50 -0
- package/lib/UUIDManager.ts +45 -0
- package/lib/client.js +125 -30
- package/lib/client.ts +154 -34
- package/lib/components/movement.js +28 -0
- package/lib/components/movement.ts +25 -0
- package/lib/components/snapshot.js +58 -0
- package/lib/components/snapshot.ts +47 -2
- package/lib/snapshot.js +114 -20
- package/lib/snapshot.ts +130 -32
- package/lib/snapshots.d.ts +57 -9
- package/package.json +1 -1
- package/test.js +57 -0
|
@@ -52,10 +52,14 @@ var SnapshotWrapper = /** @class */ (function (_super) {
|
|
|
52
52
|
}
|
|
53
53
|
SnapshotWrapper.prototype.getParsed = function (type_id, id) {
|
|
54
54
|
var _a;
|
|
55
|
+
if (type_id == -1)
|
|
56
|
+
return undefined;
|
|
55
57
|
return (_a = this._client.rawSnapUnpacker.deltas.find(function (delta) { return delta.type_id == type_id && delta.id == id; })) === null || _a === void 0 ? void 0 : _a.parsed;
|
|
56
58
|
};
|
|
57
59
|
SnapshotWrapper.prototype.getAll = function (type_id) {
|
|
58
60
|
var _all = [];
|
|
61
|
+
if (type_id == -1)
|
|
62
|
+
return _all;
|
|
59
63
|
this._client.rawSnapUnpacker.deltas.forEach(function (delta) {
|
|
60
64
|
if (delta.type_id == type_id)
|
|
61
65
|
_all.push(delta.parsed);
|
|
@@ -187,6 +191,60 @@ var SnapshotWrapper = /** @class */ (function (_super) {
|
|
|
187
191
|
enumerable: false,
|
|
188
192
|
configurable: true
|
|
189
193
|
});
|
|
194
|
+
SnapshotWrapper.prototype.getTypeId = function (name) {
|
|
195
|
+
var _a;
|
|
196
|
+
return ((_a = this._client.rawSnapUnpacker.uuid_manager.LookupName(name)) === null || _a === void 0 ? void 0 : _a.type_id) || -1;
|
|
197
|
+
};
|
|
198
|
+
SnapshotWrapper.prototype.getObjExMyOwnObject = function (id) {
|
|
199
|
+
return this.getParsed(this.getTypeId("my-own-object@heinrich5991.de"), id);
|
|
200
|
+
};
|
|
201
|
+
Object.defineProperty(SnapshotWrapper.prototype, "AllObjExMyOwnObject", {
|
|
202
|
+
get: function () {
|
|
203
|
+
return this.getAll(this.getTypeId("my-own-object@heinrich5991.de"));
|
|
204
|
+
},
|
|
205
|
+
enumerable: false,
|
|
206
|
+
configurable: true
|
|
207
|
+
});
|
|
208
|
+
SnapshotWrapper.prototype.getObjExDDNetCharacter = function (id) {
|
|
209
|
+
return this.getParsed(this.getTypeId("character@netobj.ddnet.tw"), id);
|
|
210
|
+
};
|
|
211
|
+
Object.defineProperty(SnapshotWrapper.prototype, "AllObjExDDNetCharacter", {
|
|
212
|
+
get: function () {
|
|
213
|
+
return this.getAll(this.getTypeId("character@netobj.ddnet.tw"));
|
|
214
|
+
},
|
|
215
|
+
enumerable: false,
|
|
216
|
+
configurable: true
|
|
217
|
+
});
|
|
218
|
+
SnapshotWrapper.prototype.getObjExGameInfo = function (id) {
|
|
219
|
+
return this.getParsed(this.getTypeId("gameinfo@netobj.ddnet.tw"), id);
|
|
220
|
+
};
|
|
221
|
+
Object.defineProperty(SnapshotWrapper.prototype, "AllObjExGameInfo", {
|
|
222
|
+
get: function () {
|
|
223
|
+
return this.getAll(this.getTypeId("gameinfo@netobj.ddnet.tw"));
|
|
224
|
+
},
|
|
225
|
+
enumerable: false,
|
|
226
|
+
configurable: true
|
|
227
|
+
});
|
|
228
|
+
SnapshotWrapper.prototype.getObjExDDNetProjectile = function (id) {
|
|
229
|
+
return this.getParsed(this.getTypeId("projectile@netobj.ddnet.tw"), id);
|
|
230
|
+
};
|
|
231
|
+
Object.defineProperty(SnapshotWrapper.prototype, "AllObjExDDNetProjectile", {
|
|
232
|
+
get: function () {
|
|
233
|
+
return this.getAll(this.getTypeId("projectile@netobj.ddnet.tw"));
|
|
234
|
+
},
|
|
235
|
+
enumerable: false,
|
|
236
|
+
configurable: true
|
|
237
|
+
});
|
|
238
|
+
SnapshotWrapper.prototype.getObjExLaser = function (id) {
|
|
239
|
+
return this.getParsed(this.getTypeId("laser@netobj.ddnet.tw"), id);
|
|
240
|
+
};
|
|
241
|
+
Object.defineProperty(SnapshotWrapper.prototype, "AllObjExLaser", {
|
|
242
|
+
get: function () {
|
|
243
|
+
return this.getAll(this.getTypeId("laser@netobj.ddnet.tw"));
|
|
244
|
+
},
|
|
245
|
+
enumerable: false,
|
|
246
|
+
configurable: true
|
|
247
|
+
});
|
|
190
248
|
Object.defineProperty(SnapshotWrapper.prototype, "OwnID", {
|
|
191
249
|
get: function () {
|
|
192
250
|
var _a;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { Client } from "../client";
|
|
3
3
|
import { EventEmitter } from "stream";
|
|
4
|
-
import { PlayerInput, PlayerInfo, Projectile, Laser, Pickup, Flag, GameInfo, GameData, CharacterCore, Character, ClientInfo, SpectatorInfo, Common, Explosion, Spawn, HammerHit, Death, SoundGlobal, SoundWorld, DamageInd } from "../snapshots";
|
|
4
|
+
import { PlayerInput, PlayerInfo, Projectile, Laser, Pickup, Flag, GameInfo, GameData, CharacterCore, Character, ClientInfo, SpectatorInfo, Common, Explosion, Spawn, HammerHit, Death, SoundGlobal, SoundWorld, DamageInd, MyOwnObject, DDNetCharacter, DDNetProjectile, DDNetLaser, GameInfoEx } from "../snapshots";
|
|
5
5
|
|
|
6
6
|
enum items {
|
|
7
7
|
OBJ_EX,
|
|
@@ -58,12 +58,15 @@ export class SnapshotWrapper extends EventEmitter {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
private getParsed<T>(type_id: number, id: number) {
|
|
61
|
+
if (type_id == -1)
|
|
62
|
+
return undefined;
|
|
61
63
|
return this._client.rawSnapUnpacker.deltas.find(delta => delta.type_id == type_id && delta.id == id)?.parsed as unknown as T;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
private getAll<T>(type_id: number): T[] {
|
|
65
67
|
let _all: T[] = [];
|
|
66
|
-
|
|
68
|
+
if (type_id == -1)
|
|
69
|
+
return _all;
|
|
67
70
|
this._client.rawSnapUnpacker.deltas.forEach(delta => {
|
|
68
71
|
if (delta.type_id == type_id)
|
|
69
72
|
_all.push(delta.parsed as T);
|
|
@@ -163,6 +166,48 @@ export class SnapshotWrapper extends EventEmitter {
|
|
|
163
166
|
get AllObjSpectatorInfo(): SpectatorInfo[] {
|
|
164
167
|
return this.getAll(items.OBJ_SPECTATOR_INFO);
|
|
165
168
|
}
|
|
169
|
+
|
|
170
|
+
private getTypeId(name: string) {
|
|
171
|
+
return this._client.rawSnapUnpacker.uuid_manager.LookupName(name)?.type_id || -1;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
getObjExMyOwnObject(id: number): MyOwnObject | undefined {
|
|
175
|
+
return this.getParsed(this.getTypeId("my-own-object@heinrich5991.de"), id);
|
|
176
|
+
}
|
|
177
|
+
get AllObjExMyOwnObject(): MyOwnObject[] {
|
|
178
|
+
return this.getAll(this.getTypeId("my-own-object@heinrich5991.de"));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
getObjExDDNetCharacter(id: number): DDNetCharacter | undefined {
|
|
182
|
+
return this.getParsed(this.getTypeId("character@netobj.ddnet.tw"), id);
|
|
183
|
+
}
|
|
184
|
+
get AllObjExDDNetCharacter(): DDNetCharacter[] {
|
|
185
|
+
return this.getAll(this.getTypeId("character@netobj.ddnet.tw"));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
getObjExGameInfo(id: number): GameInfoEx | undefined {
|
|
189
|
+
return this.getParsed(this.getTypeId("gameinfo@netobj.ddnet.tw"), id);
|
|
190
|
+
}
|
|
191
|
+
get AllObjExGameInfo(): GameInfoEx[] {
|
|
192
|
+
return this.getAll(this.getTypeId("gameinfo@netobj.ddnet.tw"));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
getObjExDDNetProjectile(id: number): DDNetProjectile | undefined {
|
|
196
|
+
return this.getParsed(this.getTypeId("projectile@netobj.ddnet.tw"), id);
|
|
197
|
+
}
|
|
198
|
+
get AllObjExDDNetProjectile(): DDNetProjectile[] {
|
|
199
|
+
return this.getAll(this.getTypeId("projectile@netobj.ddnet.tw"));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getObjExLaser(id: number): DDNetLaser | undefined {
|
|
203
|
+
return this.getParsed(this.getTypeId("laser@netobj.ddnet.tw"), id);
|
|
204
|
+
}
|
|
205
|
+
get AllObjExLaser(): DDNetLaser[] {
|
|
206
|
+
return this.getAll(this.getTypeId("laser@netobj.ddnet.tw"));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
166
211
|
|
|
167
212
|
|
|
168
213
|
get OwnID(): number | undefined {
|
package/lib/snapshot.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Snapshot = exports.items = void 0;
|
|
4
|
+
var UUIDManager_1 = require("./UUIDManager");
|
|
4
5
|
var MsgUnpacker_1 = require("./MsgUnpacker");
|
|
5
6
|
var decoder = new TextDecoder('utf-8');
|
|
6
7
|
var ___itemAppendix = [
|
|
@@ -73,11 +74,21 @@ var items;
|
|
|
73
74
|
items[items["EVENT_SOUND_WORLD"] = 19] = "EVENT_SOUND_WORLD";
|
|
74
75
|
items[items["EVENT_DAMAGE_INDICATOR"] = 20] = "EVENT_DAMAGE_INDICATOR";
|
|
75
76
|
})(items = exports.items || (exports.items = {}));
|
|
77
|
+
// https://github.com/ddnet/ddnet/blob/571b0b36de83d18f2524ee371fc3223d04b94135/datasrc/network.py#L236
|
|
78
|
+
var supported_uuids = [
|
|
79
|
+
"my-own-object@heinrich5991.de",
|
|
80
|
+
"character@netobj.ddnet.tw",
|
|
81
|
+
"player@netobj.ddnet.tw",
|
|
82
|
+
"gameinfo@netobj.ddnet.tw",
|
|
83
|
+
"projectile@netobj.ddnet.tw",
|
|
84
|
+
"laser@netobj.ddnet.tw",
|
|
85
|
+
];
|
|
76
86
|
var Snapshot = /** @class */ (function () {
|
|
77
87
|
function Snapshot(_client) {
|
|
78
88
|
this.deltas = [];
|
|
79
89
|
this.eSnapHolder = [];
|
|
80
90
|
this.crc_errors = 0;
|
|
91
|
+
this.uuid_manager = new UUIDManager_1.UUIDManager(32767, true); // snapshot max_type
|
|
81
92
|
this.client = _client;
|
|
82
93
|
}
|
|
83
94
|
Snapshot.prototype.IntsToStr = function (pInts) {
|
|
@@ -100,7 +111,68 @@ var Snapshot = /** @class */ (function () {
|
|
|
100
111
|
return pStr;
|
|
101
112
|
};
|
|
102
113
|
Snapshot.prototype.parseItem = function (data, Type, id) {
|
|
114
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
103
115
|
var _item = {};
|
|
116
|
+
if (Type >= 0x4000) { // offset uuid type
|
|
117
|
+
if (((_a = this.uuid_manager.LookupType(Type)) === null || _a === void 0 ? void 0 : _a.name) == "my-own-object@heinrich5991.de") {
|
|
118
|
+
_item = {
|
|
119
|
+
m_Test: data[0]
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
else if (((_b = this.uuid_manager.LookupType(Type)) === null || _b === void 0 ? void 0 : _b.name) == "character@netobj.ddnet.tw") {
|
|
123
|
+
_item = {
|
|
124
|
+
m_Flags: data[0],
|
|
125
|
+
m_FreezeEnd: data[1],
|
|
126
|
+
m_Jumps: data[2],
|
|
127
|
+
m_TeleCheckpoint: data[3],
|
|
128
|
+
m_StrongWeakID: data[4],
|
|
129
|
+
// # New data fields for jump display, freeze bar and ninja bar
|
|
130
|
+
// # Default values indicate that these values should not be used
|
|
131
|
+
m_JumpedTotal: (_c = data[5]) !== null && _c !== void 0 ? _c : null,
|
|
132
|
+
m_NinjaActivationTick: (_d = data[6]) !== null && _d !== void 0 ? _d : null,
|
|
133
|
+
m_FreezeStart: (_e = data[7]) !== null && _e !== void 0 ? _e : null,
|
|
134
|
+
// # New data fields for improved target accuracy
|
|
135
|
+
m_TargetX: (_f = data[8]) !== null && _f !== void 0 ? _f : null,
|
|
136
|
+
m_TargetY: (_g = data[9]) !== null && _g !== void 0 ? _g : null,
|
|
137
|
+
id: id
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
else if (((_h = this.uuid_manager.LookupType(Type)) === null || _h === void 0 ? void 0 : _h.name) == "player@netobj.ddnet.tw") {
|
|
141
|
+
_item = {
|
|
142
|
+
m_Flags: data[0],
|
|
143
|
+
m_AuthLevel: data[1],
|
|
144
|
+
id: id
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
else if (((_j = this.uuid_manager.LookupType(Type)) === null || _j === void 0 ? void 0 : _j.name) == "gameinfo@netobj.ddnet.tw") {
|
|
148
|
+
_item = {
|
|
149
|
+
m_Flags: data[0],
|
|
150
|
+
m_Version: data[1],
|
|
151
|
+
m_Flags2: data[2]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
else if (((_k = this.uuid_manager.LookupType(Type)) === null || _k === void 0 ? void 0 : _k.name) == "projectile@netobj.ddnet.tw") {
|
|
155
|
+
_item = {
|
|
156
|
+
m_X: data[0],
|
|
157
|
+
m_Y: data[1],
|
|
158
|
+
m_Angle: data[2],
|
|
159
|
+
m_Data: data[3],
|
|
160
|
+
m_Type: data[3],
|
|
161
|
+
m_StartTick: data[3]
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
else if (((_l = this.uuid_manager.LookupType(Type)) === null || _l === void 0 ? void 0 : _l.name) == "laser@netobj.ddnet.tw") {
|
|
165
|
+
_item = {
|
|
166
|
+
m_ToX: data[0],
|
|
167
|
+
m_ToY: data[1],
|
|
168
|
+
m_FromX: data[2],
|
|
169
|
+
m_FromY: data[3],
|
|
170
|
+
m_Owner: data[3],
|
|
171
|
+
m_Type: data[3]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return _item;
|
|
175
|
+
}
|
|
104
176
|
switch (Type) {
|
|
105
177
|
case items.OBJ_EX:
|
|
106
178
|
break;
|
|
@@ -413,28 +485,52 @@ var Snapshot = /** @class */ (function () {
|
|
|
413
485
|
} // else no previous, use new data
|
|
414
486
|
}
|
|
415
487
|
var parsed = void 0;
|
|
416
|
-
if (
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
488
|
+
if (type_id !== 0) {
|
|
489
|
+
if (!changed) {
|
|
490
|
+
var oldDelta = oldDeltas.find(function (delta) { return delta.key == key; });
|
|
491
|
+
if (oldDelta !== undefined && compareArrays(data, oldDelta.data)) {
|
|
492
|
+
parsed = oldDelta.parsed;
|
|
493
|
+
}
|
|
494
|
+
else
|
|
495
|
+
parsed = this_1.parseItem(data, type_id, id);
|
|
420
496
|
}
|
|
421
497
|
else
|
|
422
498
|
parsed = this_1.parseItem(data, type_id, id);
|
|
499
|
+
this_1.eSnapHolder.push({ Snapshot: { Data: data, Key: key }, ack: recvTick });
|
|
500
|
+
this_1.deltas.push({
|
|
501
|
+
data: data,
|
|
502
|
+
key: key,
|
|
503
|
+
id: id,
|
|
504
|
+
type_id: type_id,
|
|
505
|
+
parsed: parsed
|
|
506
|
+
});
|
|
507
|
+
if (type_id >= items.EVENT_COMMON && type_id <= items.EVENT_DAMAGE_INDICATOR) {
|
|
508
|
+
// this.client.SnapshotUnpacker.
|
|
509
|
+
_events.push({ type_id: type_id, parsed: parsed });
|
|
510
|
+
// this.client.SnapshotUnpacker.emit(___itemAppendix[type_id].name, parsed);
|
|
511
|
+
}
|
|
423
512
|
}
|
|
424
|
-
else
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
513
|
+
else {
|
|
514
|
+
this_1.eSnapHolder.push({ Snapshot: { Data: data, Key: key }, ack: recvTick });
|
|
515
|
+
this_1.deltas.push({
|
|
516
|
+
data: data,
|
|
517
|
+
key: key,
|
|
518
|
+
id: id,
|
|
519
|
+
type_id: type_id,
|
|
520
|
+
parsed: {}
|
|
521
|
+
});
|
|
522
|
+
var test_1 = function (int) { return [(int >> 24) & 0xff, (int >> 16) & 0xff, (int >> 8) & 0xff, (int) & 0xff]; };
|
|
523
|
+
var test2 = function (ints) { return ints.map(function (a) { return test_1(a); }).flat(); };
|
|
524
|
+
var targetUUID_1 = Buffer.from(test2(data));
|
|
525
|
+
if (!this_1.uuid_manager.LookupType(id)) {
|
|
526
|
+
supported_uuids.forEach(function (a, i) {
|
|
527
|
+
var uuid = (0, UUIDManager_1.createTwMD5Hash)(a);
|
|
528
|
+
if (targetUUID_1.compare(uuid) == 0) {
|
|
529
|
+
_this.uuid_manager.RegisterName(a, id);
|
|
530
|
+
supported_uuids.splice(i, 1);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
}
|
|
438
534
|
}
|
|
439
535
|
};
|
|
440
536
|
var this_1 = this;
|
|
@@ -471,7 +567,6 @@ var Snapshot = /** @class */ (function () {
|
|
|
471
567
|
if (_crc !== WantedCrc) {
|
|
472
568
|
this.deltas = oldDeltas;
|
|
473
569
|
this.crc_errors++;
|
|
474
|
-
console.log("crc error", _crc, WantedCrc, this.crc_errors);
|
|
475
570
|
if (this.crc_errors > 5) {
|
|
476
571
|
recvTick = -1;
|
|
477
572
|
this.crc_errors = 0;
|
|
@@ -508,7 +603,6 @@ function UndiffItem(oldItem, newItem) {
|
|
|
508
603
|
out[i] += a;
|
|
509
604
|
}
|
|
510
605
|
else {
|
|
511
|
-
console.log("UNDEFINED UNDEFINED UNDEFINED");
|
|
512
606
|
out[i] = 0;
|
|
513
607
|
}
|
|
514
608
|
});
|
package/lib/snapshot.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { UUIDManager, createTwMD5Hash } from "./UUIDManager";
|
|
1
2
|
import { Client } from "./client";
|
|
2
3
|
import { MsgUnpacker } from "./MsgUnpacker";
|
|
3
|
-
import { PlayerInput, PlayerInfo, Projectile, Laser, Pickup, Flag, GameInfo, GameData, CharacterCore, Character, ClientInfo, SpectatorInfo, Common, Explosion, Spawn, HammerHit, Death, SoundGlobal, SoundWorld, DamageInd } from "./snapshots";
|
|
4
|
+
import { PlayerInput, PlayerInfo, Projectile, Laser, Pickup, Flag, GameInfo, GameData, CharacterCore, Character, ClientInfo, SpectatorInfo, Common, Explosion, Spawn, HammerHit, Death, SoundGlobal, SoundWorld, DamageInd, MyOwnObject, DDNetCharacter, DDNetPlayer, GameInfoEx, DDNetProjectile, DDNetLaser } from "./snapshots";
|
|
4
5
|
var decoder = new TextDecoder('utf-8');
|
|
5
6
|
|
|
6
7
|
const ___itemAppendix: {"type_id": number, "size": number, "name": string}[] = [ // only used for the events underneath. the actual itemAppendix below this is only used for size
|
|
@@ -75,15 +76,28 @@ export enum items {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
export declare type Item = PlayerInput | PlayerInfo | Projectile | Laser | Pickup | Flag | GameInfo | GameData | CharacterCore | Character | PlayerInfo | ClientInfo | SpectatorInfo | Common | Explosion | Spawn |HammerHit | Death | SoundGlobal | SoundWorld | DamageInd;
|
|
79
|
+
export declare type DDNetItem = MyOwnObject | DDNetCharacter | DDNetPlayer | GameInfoEx | DDNetProjectile | DDNetLaser;
|
|
78
80
|
interface eSnap {
|
|
79
81
|
Snapshot: {Key: number, Data: number[]},
|
|
80
82
|
ack: number,
|
|
81
83
|
}
|
|
84
|
+
|
|
85
|
+
// https://github.com/ddnet/ddnet/blob/571b0b36de83d18f2524ee371fc3223d04b94135/datasrc/network.py#L236
|
|
86
|
+
let supported_uuids = [
|
|
87
|
+
"my-own-object@heinrich5991.de",
|
|
88
|
+
"character@netobj.ddnet.tw", // validate_size=False
|
|
89
|
+
"player@netobj.ddnet.tw",
|
|
90
|
+
"gameinfo@netobj.ddnet.tw", // validate_size=False
|
|
91
|
+
"projectile@netobj.ddnet.tw",
|
|
92
|
+
"laser@netobj.ddnet.tw",
|
|
93
|
+
]
|
|
94
|
+
|
|
82
95
|
export class Snapshot {
|
|
83
|
-
deltas: {'data': number[], 'parsed': Item, 'type_id': number, 'id': number, 'key': number}[] = [];
|
|
96
|
+
deltas: {'data': number[], 'parsed': Item | DDNetItem, 'type_id': number, 'id': number, 'key': number}[] = [];
|
|
84
97
|
eSnapHolder: eSnap[] = [];
|
|
85
98
|
crc_errors: number = 0;
|
|
86
99
|
client: Client;
|
|
100
|
+
uuid_manager: UUIDManager = new UUIDManager(32767, true); // snapshot max_type
|
|
87
101
|
|
|
88
102
|
constructor(_client: Client) {
|
|
89
103
|
this.client = _client;
|
|
@@ -108,8 +122,69 @@ export class Snapshot {
|
|
|
108
122
|
pStr = pStr.replace(/\0.*/g, ''); // Remove content from first null char to end.
|
|
109
123
|
return pStr;
|
|
110
124
|
}
|
|
111
|
-
private parseItem(data: number[], Type: number, id: number): Item {
|
|
112
|
-
var _item = {} as Item;
|
|
125
|
+
private parseItem(data: number[], Type: number, id: number): Item | DDNetItem {
|
|
126
|
+
var _item = {} as Item | DDNetItem;
|
|
127
|
+
if (Type >= 0x4000) { // offset uuid type
|
|
128
|
+
if (this.uuid_manager.LookupType(Type)?.name == "my-own-object@heinrich5991.de") {
|
|
129
|
+
_item = {
|
|
130
|
+
m_Test: data[0]
|
|
131
|
+
} as MyOwnObject;
|
|
132
|
+
} else if (this.uuid_manager.LookupType(Type)?.name == "character@netobj.ddnet.tw") {
|
|
133
|
+
_item = {
|
|
134
|
+
m_Flags: data[0],
|
|
135
|
+
m_FreezeEnd: data[1],
|
|
136
|
+
m_Jumps: data[2],
|
|
137
|
+
m_TeleCheckpoint: data[3],
|
|
138
|
+
m_StrongWeakID: data[4],
|
|
139
|
+
|
|
140
|
+
// # New data fields for jump display, freeze bar and ninja bar
|
|
141
|
+
// # Default values indicate that these values should not be used
|
|
142
|
+
m_JumpedTotal: data[5] ?? null,
|
|
143
|
+
m_NinjaActivationTick: data[6] ?? null,
|
|
144
|
+
m_FreezeStart: data[7] ?? null,
|
|
145
|
+
// # New data fields for improved target accuracy
|
|
146
|
+
m_TargetX: data[8] ?? null,
|
|
147
|
+
m_TargetY: data[9] ?? null,
|
|
148
|
+
id: id
|
|
149
|
+
|
|
150
|
+
} as DDNetCharacter;
|
|
151
|
+
}
|
|
152
|
+
else if (this.uuid_manager.LookupType(Type)?.name == "player@netobj.ddnet.tw") {
|
|
153
|
+
_item = {
|
|
154
|
+
m_Flags: data[0],
|
|
155
|
+
m_AuthLevel: data[1],
|
|
156
|
+
id: id
|
|
157
|
+
} as DDNetPlayer
|
|
158
|
+
}
|
|
159
|
+
else if (this.uuid_manager.LookupType(Type)?.name == "gameinfo@netobj.ddnet.tw") {
|
|
160
|
+
_item = {
|
|
161
|
+
m_Flags: data[0],
|
|
162
|
+
m_Version: data[1],
|
|
163
|
+
m_Flags2: data[2]
|
|
164
|
+
} as GameInfoEx
|
|
165
|
+
}
|
|
166
|
+
else if (this.uuid_manager.LookupType(Type)?.name == "projectile@netobj.ddnet.tw") {
|
|
167
|
+
_item = {
|
|
168
|
+
m_X: data[0],
|
|
169
|
+
m_Y: data[1],
|
|
170
|
+
m_Angle: data[2],
|
|
171
|
+
m_Data: data[3],
|
|
172
|
+
m_Type: data[3],
|
|
173
|
+
m_StartTick: data[3]
|
|
174
|
+
} as DDNetProjectile
|
|
175
|
+
}
|
|
176
|
+
else if (this.uuid_manager.LookupType(Type)?.name == "laser@netobj.ddnet.tw") {
|
|
177
|
+
_item = {
|
|
178
|
+
m_ToX: data[0],
|
|
179
|
+
m_ToY: data[1],
|
|
180
|
+
m_FromX: data[2],
|
|
181
|
+
m_FromY: data[3],
|
|
182
|
+
m_Owner: data[3],
|
|
183
|
+
m_Type: data[3]
|
|
184
|
+
} as DDNetLaser
|
|
185
|
+
}
|
|
186
|
+
return _item;
|
|
187
|
+
}
|
|
113
188
|
switch (Type) {
|
|
114
189
|
case items.OBJ_EX:
|
|
115
190
|
break;
|
|
@@ -374,7 +449,7 @@ export class Snapshot {
|
|
|
374
449
|
* https://github.com/heinrich5991/libtw2/blob/master/snapshot/src/
|
|
375
450
|
* https://github.com/heinrich5991/libtw2/blob/master/doc/snapshot.md
|
|
376
451
|
*/
|
|
377
|
-
var _events: {type_id: number, parsed: Item}[] = [];
|
|
452
|
+
var _events: {type_id: number, parsed: Item | DDNetItem}[] = [];
|
|
378
453
|
|
|
379
454
|
let num_removed_items = unpacker.unpackInt();
|
|
380
455
|
let num_item_deltas = unpacker.unpackInt();
|
|
@@ -434,39 +509,64 @@ export class Snapshot {
|
|
|
434
509
|
changed = true;
|
|
435
510
|
} // else no previous, use new data
|
|
436
511
|
}
|
|
437
|
-
let parsed: Item;
|
|
438
|
-
if (
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
512
|
+
let parsed: Item | DDNetItem;
|
|
513
|
+
if (type_id !== 0) {
|
|
514
|
+
if (!changed) {
|
|
515
|
+
let oldDelta = oldDeltas.find(delta => delta.key == key);
|
|
516
|
+
if (oldDelta !== undefined && compareArrays(data, oldDelta.data)) {
|
|
517
|
+
parsed = oldDelta.parsed;
|
|
518
|
+
|
|
519
|
+
} else
|
|
520
|
+
parsed = this.parseItem(data, type_id, id)
|
|
521
|
+
|
|
443
522
|
} else
|
|
444
523
|
parsed = this.parseItem(data, type_id, id)
|
|
445
524
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
525
|
+
this.eSnapHolder.push({Snapshot: {Data: data, Key: key}, ack: recvTick});
|
|
526
|
+
|
|
527
|
+
this.deltas.push({
|
|
528
|
+
data,
|
|
529
|
+
key,
|
|
530
|
+
id,
|
|
531
|
+
type_id,
|
|
532
|
+
parsed
|
|
533
|
+
});
|
|
534
|
+
if (type_id >= items.EVENT_COMMON && type_id <= items.EVENT_DAMAGE_INDICATOR) {
|
|
535
|
+
// this.client.SnapshotUnpacker.
|
|
536
|
+
|
|
537
|
+
_events.push({type_id, parsed});
|
|
538
|
+
// this.client.SnapshotUnpacker.emit(___itemAppendix[type_id].name, parsed);
|
|
539
|
+
}
|
|
540
|
+
} else {
|
|
450
541
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
542
|
+
this.eSnapHolder.push({Snapshot: {Data: data, Key: key}, ack: recvTick});
|
|
543
|
+
|
|
544
|
+
this.deltas.push({
|
|
545
|
+
data,
|
|
546
|
+
key,
|
|
547
|
+
id,
|
|
548
|
+
type_id,
|
|
549
|
+
parsed: {} as Item
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
let test = (int: number) => [(int >> 24) & 0xff, (int >> 16) & 0xff, (int >> 8) & 0xff, (int) & 0xff ];
|
|
553
|
+
let test2 = (ints: number[]) => ints.map(a => test(a)).flat();
|
|
461
554
|
|
|
462
|
-
|
|
463
|
-
|
|
555
|
+
let targetUUID = Buffer.from(test2(data));
|
|
556
|
+
if (!this.uuid_manager.LookupType(id)) {
|
|
557
|
+
|
|
558
|
+
supported_uuids.forEach((a, i) => {
|
|
559
|
+
let uuid = createTwMD5Hash(a);
|
|
560
|
+
if (targetUUID.compare(uuid) == 0) {
|
|
561
|
+
this.uuid_manager.RegisterName(a, id);
|
|
562
|
+
supported_uuids.splice(i, 1);
|
|
563
|
+
}
|
|
564
|
+
})
|
|
565
|
+
}
|
|
464
566
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
567
|
}
|
|
469
568
|
|
|
569
|
+
|
|
470
570
|
for (let newSnap of deltaSnaps) {
|
|
471
571
|
if (deleted.includes(newSnap.Snapshot.Key)) {
|
|
472
572
|
continue;
|
|
@@ -494,7 +594,6 @@ export class Snapshot {
|
|
|
494
594
|
if (_crc !== WantedCrc) {
|
|
495
595
|
this.deltas = oldDeltas;
|
|
496
596
|
this.crc_errors++;
|
|
497
|
-
console.log("crc error", _crc, WantedCrc, this.crc_errors)
|
|
498
597
|
if (this.crc_errors > 5) {
|
|
499
598
|
recvTick = -1;
|
|
500
599
|
this.crc_errors = 0;
|
|
@@ -528,7 +627,6 @@ function UndiffItem(oldItem: number[], newItem: number[]): number[] {
|
|
|
528
627
|
if (a !== undefined && out[i] !== undefined) {
|
|
529
628
|
out[i] += a;
|
|
530
629
|
} else {
|
|
531
|
-
console.log("UNDEFINED UNDEFINED UNDEFINED")
|
|
532
630
|
out[i] = 0;
|
|
533
631
|
}
|
|
534
632
|
})
|
package/lib/snapshots.d.ts
CHANGED
|
@@ -110,14 +110,6 @@ export declare interface ClientInfo {
|
|
|
110
110
|
id: number
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export declare interface DdnetCharacter {
|
|
114
|
-
flags: number,
|
|
115
|
-
freeze_end: number,
|
|
116
|
-
jumps: number,
|
|
117
|
-
tele_checkpoint: number,
|
|
118
|
-
strong_weak_id: number,
|
|
119
|
-
}
|
|
120
|
-
|
|
121
113
|
export declare interface SpectatorInfo {
|
|
122
114
|
spectator_id: number,
|
|
123
115
|
x: number,
|
|
@@ -182,4 +174,60 @@ export declare enum items {
|
|
|
182
174
|
EVENT_SOUND_GLOBAL,
|
|
183
175
|
EVENT_SOUND_WORLD,
|
|
184
176
|
EVENT_DAMAGE_INDICATOR
|
|
185
|
-
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export declare interface MyOwnObject {
|
|
180
|
+
m_Test: number
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export declare interface DDNetCharacter {
|
|
184
|
+
m_Flags: number,
|
|
185
|
+
m_FreezeEnd: number,
|
|
186
|
+
m_Jumps: number,
|
|
187
|
+
m_TeleCheckpoint: number,
|
|
188
|
+
m_StrongWeakID: number,
|
|
189
|
+
|
|
190
|
+
// # New data fields for jump display, freeze bar and ninja bar
|
|
191
|
+
// # Default values indicate that these values should not be used
|
|
192
|
+
m_JumpedTotal?: number,
|
|
193
|
+
m_NinjaActivationTick?: number,
|
|
194
|
+
m_FreezeStart?: number,
|
|
195
|
+
// # New data fields for improved target accuracy
|
|
196
|
+
m_TargetX?: number,
|
|
197
|
+
m_TargetY?: number,
|
|
198
|
+
id: number
|
|
199
|
+
} //, validate_size=False),
|
|
200
|
+
/** m_AuthLevel "AUTHED_NO", "AUTHED_ADMIN" */
|
|
201
|
+
export declare interface DDNetPlayer {
|
|
202
|
+
m_Flags: number,
|
|
203
|
+
m_AuthLevel: number,
|
|
204
|
+
id: number
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export declare interface GameInfoEx {
|
|
208
|
+
|
|
209
|
+
m_Flags: number,
|
|
210
|
+
m_Version: number,
|
|
211
|
+
m_Flags2: number,
|
|
212
|
+
}//, validate_size=False),
|
|
213
|
+
|
|
214
|
+
// # The code assumes that this has the same in-memory representation as
|
|
215
|
+
// # the Projectile net object.
|
|
216
|
+
export declare interface DDNetProjectile {
|
|
217
|
+
m_X: number,
|
|
218
|
+
m_Y: number,
|
|
219
|
+
m_Angle: number,
|
|
220
|
+
m_Data: number,
|
|
221
|
+
m_Type: number,
|
|
222
|
+
m_StartTick: number,
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export declare interface DDNetLaser {
|
|
226
|
+
m_ToX: number,
|
|
227
|
+
m_ToY: number,
|
|
228
|
+
m_FromX: number,
|
|
229
|
+
m_FromY: number,
|
|
230
|
+
m_StartTick: number,
|
|
231
|
+
m_Owner: number,
|
|
232
|
+
m_Type: number,
|
|
233
|
+
}
|