@bloopjs/web 0.0.87 → 0.0.89
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/dist/App.d.ts.map +1 -1
- package/dist/mod.js +351 -245
- package/dist/mod.js.map +8 -8
- package/dist/netcode/mod.d.ts +0 -2
- package/dist/netcode/mod.d.ts.map +1 -1
- package/dist/netcode/reconcile.d.ts +3 -0
- package/dist/netcode/reconcile.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/App.ts +8 -0
- package/src/netcode/mod.ts +0 -2
- package/src/netcode/reconcile.ts +171 -0
- package/dist/netcode/scaffold.d.ts +0 -13
- package/dist/netcode/scaffold.d.ts.map +0 -1
- package/src/netcode/scaffold.ts +0 -168
package/dist/mod.js
CHANGED
|
@@ -82,16 +82,21 @@ __export2(exports_engine, {
|
|
|
82
82
|
SNAPSHOT_HEADER_ENGINE_LEN_OFFSET: () => SNAPSHOT_HEADER_ENGINE_LEN_OFFSET,
|
|
83
83
|
PlayerInputContext: () => PlayerInputContext,
|
|
84
84
|
PLAYER_INPUTS_SIZE: () => PLAYER_INPUTS_SIZE,
|
|
85
|
+
PLAYER_INPUTS_MOUSE_CTX_OFFSET: () => PLAYER_INPUTS_MOUSE_CTX_OFFSET,
|
|
86
|
+
PLAYER_INPUTS_KEY_CTX_OFFSET: () => PLAYER_INPUTS_KEY_CTX_OFFSET,
|
|
85
87
|
NetContext: () => NetContext,
|
|
86
88
|
NET_CTX_OFFSET: () => NET_CTX_OFFSET,
|
|
87
89
|
MouseContext: () => MouseContext,
|
|
88
|
-
MOUSE_OFFSET: () =>
|
|
89
|
-
|
|
90
|
+
MOUSE_OFFSET: () => PLAYER_INPUTS_MOUSE_CTX_OFFSET,
|
|
91
|
+
MOUSE_CTX_SIZE: () => MOUSE_CTX_SIZE,
|
|
92
|
+
MOUSE_CTX_BUTTON_STATES_OFFSET: () => MOUSE_CTX_BUTTON_STATES_OFFSET,
|
|
93
|
+
MOUSE_BUTTONS_OFFSET: () => MOUSE_CTX_BUTTON_STATES_OFFSET,
|
|
90
94
|
MAX_ROLLBACK_FRAMES: () => MAX_ROLLBACK_FRAMES,
|
|
91
95
|
MAX_PLAYERS: () => MAX_PLAYERS,
|
|
92
96
|
KeyboardContext: () => KeyboardContext,
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
KEY_CTX_SIZE: () => KEY_CTX_SIZE,
|
|
98
|
+
KEYBOARD_SIZE: () => KEY_CTX_SIZE,
|
|
99
|
+
KEYBOARD_OFFSET: () => PLAYER_INPUTS_KEY_CTX_OFFSET,
|
|
95
100
|
InputContext: () => InputContext,
|
|
96
101
|
INPUT_CTX_SIZE: () => INPUT_CTX_SIZE,
|
|
97
102
|
INPUT_CTX_OFFSET: () => INPUT_CTX_OFFSET,
|
|
@@ -387,33 +392,38 @@ var NetJoinFailReason;
|
|
|
387
392
|
NetJoinFailReason2[NetJoinFailReason2["room_not_found"] = 3] = "room_not_found";
|
|
388
393
|
NetJoinFailReason2[NetJoinFailReason2["already_in_room"] = 4] = "already_in_room";
|
|
389
394
|
})(NetJoinFailReason ||= {});
|
|
390
|
-
var
|
|
391
|
-
var
|
|
392
|
-
var
|
|
393
|
-
var
|
|
394
|
-
var
|
|
395
|
+
var TIME_CTX_FRAME_OFFSET = 0;
|
|
396
|
+
var TIME_CTX_DT_MS_OFFSET = 4;
|
|
397
|
+
var TIME_CTX_TOTAL_MS_OFFSET = 8;
|
|
398
|
+
var PEER_CTX_CONNECTED_OFFSET = 0;
|
|
399
|
+
var PEER_CTX_SEQ_OFFSET = 2;
|
|
400
|
+
var PEER_CTX_ACK_OFFSET = 4;
|
|
401
|
+
var PEER_CTX_SIZE = 8;
|
|
402
|
+
var NET_CTX_PEER_COUNT_OFFSET = 0;
|
|
403
|
+
var NET_CTX_LOCAL_PEER_ID_OFFSET = 1;
|
|
404
|
+
var NET_CTX_IN_SESSION_OFFSET = 2;
|
|
405
|
+
var NET_CTX_STATUS_OFFSET = 3;
|
|
406
|
+
var NET_CTX_MATCH_FRAME_OFFSET = 4;
|
|
407
|
+
var NET_CTX_SESSION_START_FRAME_OFFSET = 8;
|
|
408
|
+
var NET_CTX_ROOM_CODE_OFFSET = 12;
|
|
409
|
+
var NET_CTX_WANTS_ROOM_CODE_OFFSET = 20;
|
|
410
|
+
var NET_CTX_WANTS_DISCONNECT_OFFSET = 28;
|
|
411
|
+
var NET_CTX_PEERS_OFFSET = 32;
|
|
412
|
+
var NET_CTX_LAST_ROLLBACK_DEPTH_OFFSET = 128;
|
|
413
|
+
var NET_CTX_TOTAL_ROLLBACKS_OFFSET = 132;
|
|
414
|
+
var NET_CTX_FRAMES_RESIMULATED_OFFSET = 136;
|
|
415
|
+
var MOUSE_CTX_X_OFFSET = 0;
|
|
416
|
+
var MOUSE_CTX_Y_OFFSET = 4;
|
|
417
|
+
var MOUSE_CTX_WHEEL_X_OFFSET = 8;
|
|
418
|
+
var MOUSE_CTX_WHEEL_Y_OFFSET = 12;
|
|
419
|
+
var MOUSE_CTX_BUTTON_STATES_OFFSET = 16;
|
|
420
|
+
var MOUSE_CTX_SIZE = 24;
|
|
421
|
+
var KEY_CTX_SIZE = 256;
|
|
422
|
+
var PLAYER_INPUTS_KEY_CTX_OFFSET = 0;
|
|
423
|
+
var PLAYER_INPUTS_MOUSE_CTX_OFFSET = 256;
|
|
395
424
|
var PLAYER_INPUTS_SIZE = 280;
|
|
396
|
-
var INPUT_CTX_SIZE =
|
|
397
|
-
var
|
|
398
|
-
var EVENT_PAYLOAD_ALIGN = 4;
|
|
399
|
-
function keyToKeyCode(key) {
|
|
400
|
-
return Key[key];
|
|
401
|
-
}
|
|
402
|
-
function keyCodeToKey(code) {
|
|
403
|
-
return Key[code];
|
|
404
|
-
}
|
|
405
|
-
function mouseButtonToMouseButtonCode(button) {
|
|
406
|
-
return MouseButton[button];
|
|
407
|
-
}
|
|
408
|
-
function mouseButtonCodeToMouseButton(code) {
|
|
409
|
-
return MouseButton[code];
|
|
410
|
-
}
|
|
411
|
-
function inputSourceToInputSourceCode(source) {
|
|
412
|
-
return InputSource[source];
|
|
413
|
-
}
|
|
414
|
-
function inputSourceCodeToInputSource(code) {
|
|
415
|
-
return InputSource[code];
|
|
416
|
-
}
|
|
425
|
+
var INPUT_CTX_SIZE = 3360;
|
|
426
|
+
var MAX_PLAYERS = 12;
|
|
417
427
|
|
|
418
428
|
class PlayerInputContext {
|
|
419
429
|
#dataView;
|
|
@@ -424,13 +434,13 @@ class PlayerInputContext {
|
|
|
424
434
|
}
|
|
425
435
|
get keys() {
|
|
426
436
|
if (!this.#keys) {
|
|
427
|
-
this.#keys = new KeyboardContext(new DataView(this.#dataView.buffer, this.#dataView.byteOffset +
|
|
437
|
+
this.#keys = new KeyboardContext(new DataView(this.#dataView.buffer, this.#dataView.byteOffset + PLAYER_INPUTS_KEY_CTX_OFFSET));
|
|
428
438
|
}
|
|
429
439
|
return this.#keys;
|
|
430
440
|
}
|
|
431
441
|
get mouse() {
|
|
432
442
|
if (!this.#mouse) {
|
|
433
|
-
this.#mouse = new MouseContext(new DataView(this.#dataView.buffer, this.#dataView.byteOffset +
|
|
443
|
+
this.#mouse = new MouseContext(new DataView(this.#dataView.buffer, this.#dataView.byteOffset + PLAYER_INPUTS_MOUSE_CTX_OFFSET));
|
|
434
444
|
}
|
|
435
445
|
return this.#mouse;
|
|
436
446
|
}
|
|
@@ -455,6 +465,9 @@ class InputContext {
|
|
|
455
465
|
this.#dataView = dataView;
|
|
456
466
|
this.#buildPlayers();
|
|
457
467
|
}
|
|
468
|
+
hasDataView() {
|
|
469
|
+
return !!this.#dataView;
|
|
470
|
+
}
|
|
458
471
|
#buildPlayers() {
|
|
459
472
|
this.#players = [];
|
|
460
473
|
for (let i = 0;i < MAX_PLAYERS; i++) {
|
|
@@ -487,19 +500,19 @@ class MouseContext {
|
|
|
487
500
|
this.#dataView = dataView;
|
|
488
501
|
}
|
|
489
502
|
get x() {
|
|
490
|
-
return this.#dataView.getFloat32(
|
|
503
|
+
return this.#dataView.getFloat32(MOUSE_CTX_X_OFFSET, true);
|
|
491
504
|
}
|
|
492
505
|
get y() {
|
|
493
|
-
return this.#dataView.getFloat32(
|
|
506
|
+
return this.#dataView.getFloat32(MOUSE_CTX_Y_OFFSET, true);
|
|
494
507
|
}
|
|
495
508
|
get wheel() {
|
|
496
509
|
return { x: this.wheelX, y: this.wheelY };
|
|
497
510
|
}
|
|
498
511
|
get wheelX() {
|
|
499
|
-
return this.#dataView.getFloat32(
|
|
512
|
+
return this.#dataView.getFloat32(MOUSE_CTX_WHEEL_X_OFFSET, true);
|
|
500
513
|
}
|
|
501
514
|
get wheelY() {
|
|
502
|
-
return this.#dataView.getFloat32(
|
|
515
|
+
return this.#dataView.getFloat32(MOUSE_CTX_WHEEL_Y_OFFSET, true);
|
|
503
516
|
}
|
|
504
517
|
get left() {
|
|
505
518
|
return this.#buttonState(1);
|
|
@@ -518,7 +531,7 @@ class MouseContext {
|
|
|
518
531
|
state = { down: false, held: false, up: false };
|
|
519
532
|
this.#buttonStates.set(code, state);
|
|
520
533
|
}
|
|
521
|
-
const offset =
|
|
534
|
+
const offset = MOUSE_CTX_BUTTON_STATES_OFFSET;
|
|
522
535
|
state.held = !!(this.#dataView.getUint8(offset + code) & 1);
|
|
523
536
|
state.down = state.held && !(this.#dataView.getUint8(offset + code) & 2);
|
|
524
537
|
state.up = !state.held && !!(this.#dataView.getUint8(offset + code) & 2);
|
|
@@ -1140,14 +1153,6 @@ class KeyboardContext {
|
|
|
1140
1153
|
return state;
|
|
1141
1154
|
}
|
|
1142
1155
|
}
|
|
1143
|
-
var MAX_PEERS = 12;
|
|
1144
|
-
var PEERS_ARRAY_OFFSET = 32;
|
|
1145
|
-
var PEER_CTX_SIZE = 8;
|
|
1146
|
-
var PEER_CONNECTED_OFFSET = 0;
|
|
1147
|
-
var PEER_PACKET_COUNT_OFFSET = 1;
|
|
1148
|
-
var PEER_SEQ_OFFSET = 2;
|
|
1149
|
-
var PEER_ACK_OFFSET = 4;
|
|
1150
|
-
var PEER_ACK_COUNT_OFFSET = 6;
|
|
1151
1156
|
var STATUS_MAP = {
|
|
1152
1157
|
0: "offline",
|
|
1153
1158
|
1: "local",
|
|
@@ -1158,7 +1163,7 @@ var STATUS_MAP = {
|
|
|
1158
1163
|
|
|
1159
1164
|
class NetContext {
|
|
1160
1165
|
dataView;
|
|
1161
|
-
#peers = Array.from({ length:
|
|
1166
|
+
#peers = Array.from({ length: MAX_PLAYERS }, () => ({
|
|
1162
1167
|
isLocal: false,
|
|
1163
1168
|
seq: -1,
|
|
1164
1169
|
ack: -1
|
|
@@ -1176,38 +1181,38 @@ class NetContext {
|
|
|
1176
1181
|
if (!this.#hasValidBuffer()) {
|
|
1177
1182
|
throw new Error("NetContext dataView is not valid");
|
|
1178
1183
|
}
|
|
1179
|
-
return this.dataView.getUint8(
|
|
1184
|
+
return this.dataView.getUint8(NET_CTX_PEER_COUNT_OFFSET);
|
|
1180
1185
|
}
|
|
1181
1186
|
get localPeerId() {
|
|
1182
1187
|
if (!this.#hasValidBuffer()) {
|
|
1183
1188
|
throw new Error("NetContext dataView is not valid");
|
|
1184
1189
|
}
|
|
1185
|
-
return this.dataView.getUint8(
|
|
1190
|
+
return this.dataView.getUint8(NET_CTX_LOCAL_PEER_ID_OFFSET);
|
|
1186
1191
|
}
|
|
1187
1192
|
get isInSession() {
|
|
1188
1193
|
if (!this.#hasValidBuffer()) {
|
|
1189
1194
|
throw new Error("NetContext dataView is not valid");
|
|
1190
1195
|
}
|
|
1191
|
-
return this.dataView.getUint8(
|
|
1196
|
+
return this.dataView.getUint8(NET_CTX_IN_SESSION_OFFSET) !== 0;
|
|
1192
1197
|
}
|
|
1193
1198
|
get status() {
|
|
1194
1199
|
if (!this.#hasValidBuffer()) {
|
|
1195
1200
|
throw new Error("NetContext dataView is not valid");
|
|
1196
1201
|
}
|
|
1197
|
-
const statusByte = this.dataView.getUint8(
|
|
1202
|
+
const statusByte = this.dataView.getUint8(NET_CTX_STATUS_OFFSET);
|
|
1198
1203
|
return STATUS_MAP[statusByte] ?? "local";
|
|
1199
1204
|
}
|
|
1200
1205
|
get matchFrame() {
|
|
1201
1206
|
if (!this.#hasValidBuffer()) {
|
|
1202
1207
|
throw new Error("NetContext dataView is not valid");
|
|
1203
1208
|
}
|
|
1204
|
-
return this.dataView.getUint32(
|
|
1209
|
+
return this.dataView.getUint32(NET_CTX_MATCH_FRAME_OFFSET, true);
|
|
1205
1210
|
}
|
|
1206
1211
|
get sessionStartFrame() {
|
|
1207
1212
|
if (!this.#hasValidBuffer()) {
|
|
1208
1213
|
throw new Error("NetContext dataView is not valid");
|
|
1209
1214
|
}
|
|
1210
|
-
return this.dataView.getUint32(
|
|
1215
|
+
return this.dataView.getUint32(NET_CTX_SESSION_START_FRAME_OFFSET, true);
|
|
1211
1216
|
}
|
|
1212
1217
|
get roomCode() {
|
|
1213
1218
|
if (!this.#hasValidBuffer()) {
|
|
@@ -1215,7 +1220,7 @@ class NetContext {
|
|
|
1215
1220
|
}
|
|
1216
1221
|
const bytes = [];
|
|
1217
1222
|
for (let i = 0;i < 8; i++) {
|
|
1218
|
-
const byte = this.dataView.getUint8(
|
|
1223
|
+
const byte = this.dataView.getUint8(NET_CTX_ROOM_CODE_OFFSET + i);
|
|
1219
1224
|
if (byte === 0)
|
|
1220
1225
|
break;
|
|
1221
1226
|
bytes.push(byte);
|
|
@@ -1228,7 +1233,7 @@ class NetContext {
|
|
|
1228
1233
|
}
|
|
1229
1234
|
const bytes = [];
|
|
1230
1235
|
for (let i = 0;i < 8; i++) {
|
|
1231
|
-
const byte = this.dataView.getUint8(
|
|
1236
|
+
const byte = this.dataView.getUint8(NET_CTX_WANTS_ROOM_CODE_OFFSET + i);
|
|
1232
1237
|
if (byte === 0)
|
|
1233
1238
|
break;
|
|
1234
1239
|
bytes.push(byte);
|
|
@@ -1240,11 +1245,11 @@ class NetContext {
|
|
|
1240
1245
|
throw new Error("NetContext dataView is not valid");
|
|
1241
1246
|
}
|
|
1242
1247
|
for (let i = 0;i < 8; i++) {
|
|
1243
|
-
this.dataView.setUint8(
|
|
1248
|
+
this.dataView.setUint8(NET_CTX_WANTS_ROOM_CODE_OFFSET + i, 0);
|
|
1244
1249
|
}
|
|
1245
1250
|
if (code) {
|
|
1246
1251
|
for (let i = 0;i < Math.min(code.length, 7); i++) {
|
|
1247
|
-
this.dataView.setUint8(
|
|
1252
|
+
this.dataView.setUint8(NET_CTX_WANTS_ROOM_CODE_OFFSET + i, code.charCodeAt(i));
|
|
1248
1253
|
}
|
|
1249
1254
|
}
|
|
1250
1255
|
}
|
|
@@ -1252,13 +1257,13 @@ class NetContext {
|
|
|
1252
1257
|
if (!this.#hasValidBuffer()) {
|
|
1253
1258
|
return false;
|
|
1254
1259
|
}
|
|
1255
|
-
return this.dataView.getUint8(
|
|
1260
|
+
return this.dataView.getUint8(NET_CTX_WANTS_DISCONNECT_OFFSET) !== 0;
|
|
1256
1261
|
}
|
|
1257
1262
|
set wantsDisconnect(value) {
|
|
1258
1263
|
if (!this.#hasValidBuffer()) {
|
|
1259
1264
|
throw new Error("NetContext dataView is not valid");
|
|
1260
1265
|
}
|
|
1261
|
-
this.dataView.setUint8(
|
|
1266
|
+
this.dataView.setUint8(NET_CTX_WANTS_DISCONNECT_OFFSET, value ? 1 : 0);
|
|
1262
1267
|
}
|
|
1263
1268
|
get peers() {
|
|
1264
1269
|
if (!this.#hasValidBuffer()) {
|
|
@@ -1268,23 +1273,23 @@ class NetContext {
|
|
|
1268
1273
|
const localPeerId = this.localPeerId;
|
|
1269
1274
|
const matchFrame = this.matchFrame;
|
|
1270
1275
|
let minRemoteSeq = -1;
|
|
1271
|
-
for (let i = 0;i <
|
|
1276
|
+
for (let i = 0;i < MAX_PLAYERS; i++) {
|
|
1272
1277
|
if (i === localPeerId)
|
|
1273
1278
|
continue;
|
|
1274
|
-
const peerOffset =
|
|
1275
|
-
if (dv.getUint8(peerOffset +
|
|
1279
|
+
const peerOffset = NET_CTX_PEERS_OFFSET + i * PEER_CTX_SIZE;
|
|
1280
|
+
if (dv.getUint8(peerOffset + PEER_CTX_CONNECTED_OFFSET) !== 1)
|
|
1276
1281
|
continue;
|
|
1277
|
-
|
|
1282
|
+
const seq = dv.getInt16(peerOffset + PEER_CTX_SEQ_OFFSET, true);
|
|
1283
|
+
if (seq < 0)
|
|
1278
1284
|
continue;
|
|
1279
|
-
const seq = dv.getUint16(peerOffset + PEER_SEQ_OFFSET, true);
|
|
1280
1285
|
if (minRemoteSeq === -1 || seq < minRemoteSeq) {
|
|
1281
1286
|
minRemoteSeq = seq;
|
|
1282
1287
|
}
|
|
1283
1288
|
}
|
|
1284
1289
|
this.#peersResult.length = 0;
|
|
1285
|
-
for (let i = 0;i <
|
|
1286
|
-
const peerOffset =
|
|
1287
|
-
if (dv.getUint8(peerOffset +
|
|
1290
|
+
for (let i = 0;i < MAX_PLAYERS; i++) {
|
|
1291
|
+
const peerOffset = NET_CTX_PEERS_OFFSET + i * PEER_CTX_SIZE;
|
|
1292
|
+
if (dv.getUint8(peerOffset + PEER_CTX_CONNECTED_OFFSET) !== 1)
|
|
1288
1293
|
continue;
|
|
1289
1294
|
const peer = this.#peers[i];
|
|
1290
1295
|
if (!peer) {
|
|
@@ -1296,15 +1301,31 @@ class NetContext {
|
|
|
1296
1301
|
peer.seq = matchFrame;
|
|
1297
1302
|
peer.ack = minRemoteSeq;
|
|
1298
1303
|
} else {
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
peer.seq = packetCount === 0 ? -1 : dv.getUint16(peerOffset + PEER_SEQ_OFFSET, true);
|
|
1302
|
-
peer.ack = ackCount === 0 ? -1 : dv.getUint16(peerOffset + PEER_ACK_OFFSET, true);
|
|
1304
|
+
peer.seq = dv.getInt16(peerOffset + PEER_CTX_SEQ_OFFSET, true);
|
|
1305
|
+
peer.ack = dv.getInt16(peerOffset + PEER_CTX_ACK_OFFSET, true);
|
|
1303
1306
|
}
|
|
1304
1307
|
this.#peersResult.push(peer);
|
|
1305
1308
|
}
|
|
1306
1309
|
return this.#peersResult;
|
|
1307
1310
|
}
|
|
1311
|
+
get lastRollbackDepth() {
|
|
1312
|
+
if (!this.#hasValidBuffer()) {
|
|
1313
|
+
throw new Error("NetContext dataView is not valid");
|
|
1314
|
+
}
|
|
1315
|
+
return this.dataView.getUint32(NET_CTX_LAST_ROLLBACK_DEPTH_OFFSET, true);
|
|
1316
|
+
}
|
|
1317
|
+
get totalRollbacks() {
|
|
1318
|
+
if (!this.#hasValidBuffer()) {
|
|
1319
|
+
throw new Error("NetContext dataView is not valid");
|
|
1320
|
+
}
|
|
1321
|
+
return this.dataView.getUint32(NET_CTX_TOTAL_ROLLBACKS_OFFSET, true);
|
|
1322
|
+
}
|
|
1323
|
+
get framesResimulated() {
|
|
1324
|
+
if (!this.#hasValidBuffer()) {
|
|
1325
|
+
throw new Error("NetContext dataView is not valid");
|
|
1326
|
+
}
|
|
1327
|
+
return Number(this.dataView.getBigUint64(NET_CTX_FRAMES_RESIMULATED_OFFSET, true));
|
|
1328
|
+
}
|
|
1308
1329
|
}
|
|
1309
1330
|
|
|
1310
1331
|
class TimeContext {
|
|
@@ -1316,21 +1337,41 @@ class TimeContext {
|
|
|
1316
1337
|
if (!this.dataView) {
|
|
1317
1338
|
throw new Error("TimeContext DataView is not initialized");
|
|
1318
1339
|
}
|
|
1319
|
-
return this.dataView.getUint32(
|
|
1340
|
+
return this.dataView.getUint32(TIME_CTX_FRAME_OFFSET, true);
|
|
1320
1341
|
}
|
|
1321
1342
|
get dt() {
|
|
1322
1343
|
if (!this.dataView) {
|
|
1323
1344
|
throw new Error("TimeContext DataView is not initialized");
|
|
1324
1345
|
}
|
|
1325
|
-
return this.dataView.getUint32(
|
|
1346
|
+
return this.dataView.getUint32(TIME_CTX_DT_MS_OFFSET, true) / 1000;
|
|
1326
1347
|
}
|
|
1327
1348
|
get time() {
|
|
1328
1349
|
if (!this.dataView) {
|
|
1329
1350
|
throw new Error("TimeContext DataView is not initialized");
|
|
1330
1351
|
}
|
|
1331
|
-
return this.dataView.getUint32(
|
|
1352
|
+
return this.dataView.getUint32(TIME_CTX_TOTAL_MS_OFFSET, true) / 1000;
|
|
1332
1353
|
}
|
|
1333
1354
|
}
|
|
1355
|
+
var EVENT_PAYLOAD_SIZE = 8;
|
|
1356
|
+
var EVENT_PAYLOAD_ALIGN = 4;
|
|
1357
|
+
function keyToKeyCode(key) {
|
|
1358
|
+
return Key[key];
|
|
1359
|
+
}
|
|
1360
|
+
function keyCodeToKey(code) {
|
|
1361
|
+
return Key[code];
|
|
1362
|
+
}
|
|
1363
|
+
function mouseButtonToMouseButtonCode(button) {
|
|
1364
|
+
return MouseButton[button];
|
|
1365
|
+
}
|
|
1366
|
+
function mouseButtonCodeToMouseButton(code) {
|
|
1367
|
+
return MouseButton[code];
|
|
1368
|
+
}
|
|
1369
|
+
function inputSourceToInputSourceCode(source) {
|
|
1370
|
+
return InputSource[source];
|
|
1371
|
+
}
|
|
1372
|
+
function inputSourceCodeToInputSource(code) {
|
|
1373
|
+
return InputSource[code];
|
|
1374
|
+
}
|
|
1334
1375
|
var TAPE_MAGIC = 1413566533;
|
|
1335
1376
|
function readTapeHeader(tape) {
|
|
1336
1377
|
const view = new DataView(tape.buffer, tape.byteOffset, tape.byteLength);
|
|
@@ -1346,7 +1387,7 @@ function readTapeHeader(tape) {
|
|
|
1346
1387
|
eventCount: view.getUint16(14, true)
|
|
1347
1388
|
};
|
|
1348
1389
|
}
|
|
1349
|
-
var DEFAULT_WASM_URL = new URL("https://unpkg.com/@bloopjs/engine@0.0.
|
|
1390
|
+
var DEFAULT_WASM_URL = new URL("https://unpkg.com/@bloopjs/engine@0.0.89/wasm/bloop.wasm");
|
|
1350
1391
|
var MAX_ROLLBACK_FRAMES = 500;
|
|
1351
1392
|
var TIME_CTX_OFFSET = 0;
|
|
1352
1393
|
var INPUT_CTX_OFFSET = TIME_CTX_OFFSET + 4;
|
|
@@ -1611,6 +1652,7 @@ async function mount(mountable, options) {
|
|
|
1611
1652
|
memory,
|
|
1612
1653
|
__systems: function(system_handle, ptr) {
|
|
1613
1654
|
mountable.hooks.setBuffer(memory.buffer);
|
|
1655
|
+
mountable.hooks.setContext(ptr);
|
|
1614
1656
|
mountable.hooks.systemsCallback(system_handle, ptr);
|
|
1615
1657
|
},
|
|
1616
1658
|
__before_frame: function(ptr, frame) {
|
|
@@ -1757,9 +1799,15 @@ class Bloop {
|
|
|
1757
1799
|
const inputCtxPtr = dv.getUint32(INPUT_CTX_OFFSET, true);
|
|
1758
1800
|
const netCtxPtr = dv.getUint32(NET_CTX_OFFSET, true);
|
|
1759
1801
|
this.#context.rawPointer = ptr;
|
|
1760
|
-
this.#context.inputs.dataView
|
|
1761
|
-
|
|
1762
|
-
|
|
1802
|
+
if (!this.#context.inputs.hasDataView() || this.#context.inputs.dataView.buffer !== this.#engineBuffer || this.#context.inputs.dataView.byteOffset !== inputCtxPtr) {
|
|
1803
|
+
this.#context.inputs.dataView = new DataView(this.#engineBuffer, inputCtxPtr);
|
|
1804
|
+
}
|
|
1805
|
+
if (this.#context.time.dataView?.buffer !== this.#engineBuffer || this.#context.time.dataView?.byteOffset !== timeCtxPtr) {
|
|
1806
|
+
this.#context.time.dataView = new DataView(this.#engineBuffer, timeCtxPtr);
|
|
1807
|
+
}
|
|
1808
|
+
if (this.#context.net.dataView?.buffer !== this.#engineBuffer || this.#context.net.dataView?.byteOffset !== netCtxPtr) {
|
|
1809
|
+
this.#context.net.dataView = new DataView(this.#engineBuffer, netCtxPtr);
|
|
1810
|
+
}
|
|
1763
1811
|
},
|
|
1764
1812
|
systemsCallback: (system_handle, ptr) => {
|
|
1765
1813
|
this.hooks.setContext(ptr);
|
|
@@ -1864,6 +1912,13 @@ class Bloop {
|
|
|
1864
1912
|
system.netcode?.(this.#context);
|
|
1865
1913
|
break;
|
|
1866
1914
|
}
|
|
1915
|
+
case exports_enums.EventType.NetSessionInit:
|
|
1916
|
+
console.log("[bloop] NetSessionInit event received");
|
|
1917
|
+
this.#context.event = {
|
|
1918
|
+
type: "session:start"
|
|
1919
|
+
};
|
|
1920
|
+
system.netcode?.(this.#context);
|
|
1921
|
+
break;
|
|
1867
1922
|
default:
|
|
1868
1923
|
break;
|
|
1869
1924
|
}
|
|
@@ -2166,15 +2221,33 @@ var NetJoinFailReason2;
|
|
|
2166
2221
|
NetJoinFailReason22[NetJoinFailReason22["room_not_found"] = 3] = "room_not_found";
|
|
2167
2222
|
NetJoinFailReason22[NetJoinFailReason22["already_in_room"] = 4] = "already_in_room";
|
|
2168
2223
|
})(NetJoinFailReason2 ||= {});
|
|
2169
|
-
var
|
|
2170
|
-
var
|
|
2171
|
-
var
|
|
2172
|
-
var
|
|
2224
|
+
var PEER_CTX_CONNECTED_OFFSET2 = 0;
|
|
2225
|
+
var PEER_CTX_SEQ_OFFSET2 = 2;
|
|
2226
|
+
var PEER_CTX_ACK_OFFSET2 = 4;
|
|
2227
|
+
var PEER_CTX_SIZE2 = 8;
|
|
2228
|
+
var NET_CTX_PEER_COUNT_OFFSET2 = 0;
|
|
2229
|
+
var NET_CTX_LOCAL_PEER_ID_OFFSET2 = 1;
|
|
2230
|
+
var NET_CTX_IN_SESSION_OFFSET2 = 2;
|
|
2231
|
+
var NET_CTX_STATUS_OFFSET2 = 3;
|
|
2232
|
+
var NET_CTX_MATCH_FRAME_OFFSET2 = 4;
|
|
2233
|
+
var NET_CTX_SESSION_START_FRAME_OFFSET2 = 8;
|
|
2234
|
+
var NET_CTX_ROOM_CODE_OFFSET2 = 12;
|
|
2235
|
+
var NET_CTX_WANTS_ROOM_CODE_OFFSET2 = 20;
|
|
2236
|
+
var NET_CTX_WANTS_DISCONNECT_OFFSET2 = 28;
|
|
2237
|
+
var NET_CTX_PEERS_OFFSET2 = 32;
|
|
2238
|
+
var NET_CTX_LAST_ROLLBACK_DEPTH_OFFSET2 = 128;
|
|
2239
|
+
var NET_CTX_TOTAL_ROLLBACKS_OFFSET2 = 132;
|
|
2240
|
+
var NET_CTX_FRAMES_RESIMULATED_OFFSET2 = 136;
|
|
2241
|
+
var MOUSE_CTX_X_OFFSET2 = 0;
|
|
2242
|
+
var MOUSE_CTX_Y_OFFSET2 = 4;
|
|
2243
|
+
var MOUSE_CTX_WHEEL_X_OFFSET2 = 8;
|
|
2244
|
+
var MOUSE_CTX_WHEEL_Y_OFFSET2 = 12;
|
|
2245
|
+
var MOUSE_CTX_BUTTON_STATES_OFFSET2 = 16;
|
|
2246
|
+
var PLAYER_INPUTS_KEY_CTX_OFFSET2 = 0;
|
|
2247
|
+
var PLAYER_INPUTS_MOUSE_CTX_OFFSET2 = 256;
|
|
2173
2248
|
var PLAYER_INPUTS_SIZE2 = 280;
|
|
2174
|
-
var
|
|
2175
|
-
|
|
2176
|
-
return MouseButton2[code];
|
|
2177
|
-
}
|
|
2249
|
+
var MAX_PLAYERS2 = 12;
|
|
2250
|
+
|
|
2178
2251
|
class PlayerInputContext2 {
|
|
2179
2252
|
#dataView;
|
|
2180
2253
|
#keys;
|
|
@@ -2184,13 +2257,13 @@ class PlayerInputContext2 {
|
|
|
2184
2257
|
}
|
|
2185
2258
|
get keys() {
|
|
2186
2259
|
if (!this.#keys) {
|
|
2187
|
-
this.#keys = new KeyboardContext2(new DataView(this.#dataView.buffer, this.#dataView.byteOffset +
|
|
2260
|
+
this.#keys = new KeyboardContext2(new DataView(this.#dataView.buffer, this.#dataView.byteOffset + PLAYER_INPUTS_KEY_CTX_OFFSET2));
|
|
2188
2261
|
}
|
|
2189
2262
|
return this.#keys;
|
|
2190
2263
|
}
|
|
2191
2264
|
get mouse() {
|
|
2192
2265
|
if (!this.#mouse) {
|
|
2193
|
-
this.#mouse = new MouseContext2(new DataView(this.#dataView.buffer, this.#dataView.byteOffset +
|
|
2266
|
+
this.#mouse = new MouseContext2(new DataView(this.#dataView.buffer, this.#dataView.byteOffset + PLAYER_INPUTS_MOUSE_CTX_OFFSET2));
|
|
2194
2267
|
}
|
|
2195
2268
|
return this.#mouse;
|
|
2196
2269
|
}
|
|
@@ -2215,6 +2288,9 @@ class InputContext2 {
|
|
|
2215
2288
|
this.#dataView = dataView;
|
|
2216
2289
|
this.#buildPlayers();
|
|
2217
2290
|
}
|
|
2291
|
+
hasDataView() {
|
|
2292
|
+
return !!this.#dataView;
|
|
2293
|
+
}
|
|
2218
2294
|
#buildPlayers() {
|
|
2219
2295
|
this.#players = [];
|
|
2220
2296
|
for (let i = 0;i < MAX_PLAYERS2; i++) {
|
|
@@ -2247,19 +2323,19 @@ class MouseContext2 {
|
|
|
2247
2323
|
this.#dataView = dataView;
|
|
2248
2324
|
}
|
|
2249
2325
|
get x() {
|
|
2250
|
-
return this.#dataView.getFloat32(
|
|
2326
|
+
return this.#dataView.getFloat32(MOUSE_CTX_X_OFFSET2, true);
|
|
2251
2327
|
}
|
|
2252
2328
|
get y() {
|
|
2253
|
-
return this.#dataView.getFloat32(
|
|
2329
|
+
return this.#dataView.getFloat32(MOUSE_CTX_Y_OFFSET2, true);
|
|
2254
2330
|
}
|
|
2255
2331
|
get wheel() {
|
|
2256
2332
|
return { x: this.wheelX, y: this.wheelY };
|
|
2257
2333
|
}
|
|
2258
2334
|
get wheelX() {
|
|
2259
|
-
return this.#dataView.getFloat32(
|
|
2335
|
+
return this.#dataView.getFloat32(MOUSE_CTX_WHEEL_X_OFFSET2, true);
|
|
2260
2336
|
}
|
|
2261
2337
|
get wheelY() {
|
|
2262
|
-
return this.#dataView.getFloat32(
|
|
2338
|
+
return this.#dataView.getFloat32(MOUSE_CTX_WHEEL_Y_OFFSET2, true);
|
|
2263
2339
|
}
|
|
2264
2340
|
get left() {
|
|
2265
2341
|
return this.#buttonState(1);
|
|
@@ -2278,7 +2354,7 @@ class MouseContext2 {
|
|
|
2278
2354
|
state = { down: false, held: false, up: false };
|
|
2279
2355
|
this.#buttonStates.set(code, state);
|
|
2280
2356
|
}
|
|
2281
|
-
const offset =
|
|
2357
|
+
const offset = MOUSE_CTX_BUTTON_STATES_OFFSET2;
|
|
2282
2358
|
state.held = !!(this.#dataView.getUint8(offset + code) & 1);
|
|
2283
2359
|
state.down = state.held && !(this.#dataView.getUint8(offset + code) & 2);
|
|
2284
2360
|
state.up = !state.held && !!(this.#dataView.getUint8(offset + code) & 2);
|
|
@@ -2900,14 +2976,6 @@ class KeyboardContext2 {
|
|
|
2900
2976
|
return state;
|
|
2901
2977
|
}
|
|
2902
2978
|
}
|
|
2903
|
-
var MAX_PEERS2 = 12;
|
|
2904
|
-
var PEERS_ARRAY_OFFSET2 = 32;
|
|
2905
|
-
var PEER_CTX_SIZE2 = 8;
|
|
2906
|
-
var PEER_CONNECTED_OFFSET2 = 0;
|
|
2907
|
-
var PEER_PACKET_COUNT_OFFSET2 = 1;
|
|
2908
|
-
var PEER_SEQ_OFFSET2 = 2;
|
|
2909
|
-
var PEER_ACK_OFFSET2 = 4;
|
|
2910
|
-
var PEER_ACK_COUNT_OFFSET2 = 6;
|
|
2911
2979
|
var STATUS_MAP2 = {
|
|
2912
2980
|
0: "offline",
|
|
2913
2981
|
1: "local",
|
|
@@ -2918,7 +2986,7 @@ var STATUS_MAP2 = {
|
|
|
2918
2986
|
|
|
2919
2987
|
class NetContext2 {
|
|
2920
2988
|
dataView;
|
|
2921
|
-
#peers = Array.from({ length:
|
|
2989
|
+
#peers = Array.from({ length: MAX_PLAYERS2 }, () => ({
|
|
2922
2990
|
isLocal: false,
|
|
2923
2991
|
seq: -1,
|
|
2924
2992
|
ack: -1
|
|
@@ -2936,38 +3004,38 @@ class NetContext2 {
|
|
|
2936
3004
|
if (!this.#hasValidBuffer()) {
|
|
2937
3005
|
throw new Error("NetContext dataView is not valid");
|
|
2938
3006
|
}
|
|
2939
|
-
return this.dataView.getUint8(
|
|
3007
|
+
return this.dataView.getUint8(NET_CTX_PEER_COUNT_OFFSET2);
|
|
2940
3008
|
}
|
|
2941
3009
|
get localPeerId() {
|
|
2942
3010
|
if (!this.#hasValidBuffer()) {
|
|
2943
3011
|
throw new Error("NetContext dataView is not valid");
|
|
2944
3012
|
}
|
|
2945
|
-
return this.dataView.getUint8(
|
|
3013
|
+
return this.dataView.getUint8(NET_CTX_LOCAL_PEER_ID_OFFSET2);
|
|
2946
3014
|
}
|
|
2947
3015
|
get isInSession() {
|
|
2948
3016
|
if (!this.#hasValidBuffer()) {
|
|
2949
3017
|
throw new Error("NetContext dataView is not valid");
|
|
2950
3018
|
}
|
|
2951
|
-
return this.dataView.getUint8(
|
|
3019
|
+
return this.dataView.getUint8(NET_CTX_IN_SESSION_OFFSET2) !== 0;
|
|
2952
3020
|
}
|
|
2953
3021
|
get status() {
|
|
2954
3022
|
if (!this.#hasValidBuffer()) {
|
|
2955
3023
|
throw new Error("NetContext dataView is not valid");
|
|
2956
3024
|
}
|
|
2957
|
-
const statusByte = this.dataView.getUint8(
|
|
3025
|
+
const statusByte = this.dataView.getUint8(NET_CTX_STATUS_OFFSET2);
|
|
2958
3026
|
return STATUS_MAP2[statusByte] ?? "local";
|
|
2959
3027
|
}
|
|
2960
3028
|
get matchFrame() {
|
|
2961
3029
|
if (!this.#hasValidBuffer()) {
|
|
2962
3030
|
throw new Error("NetContext dataView is not valid");
|
|
2963
3031
|
}
|
|
2964
|
-
return this.dataView.getUint32(
|
|
3032
|
+
return this.dataView.getUint32(NET_CTX_MATCH_FRAME_OFFSET2, true);
|
|
2965
3033
|
}
|
|
2966
3034
|
get sessionStartFrame() {
|
|
2967
3035
|
if (!this.#hasValidBuffer()) {
|
|
2968
3036
|
throw new Error("NetContext dataView is not valid");
|
|
2969
3037
|
}
|
|
2970
|
-
return this.dataView.getUint32(
|
|
3038
|
+
return this.dataView.getUint32(NET_CTX_SESSION_START_FRAME_OFFSET2, true);
|
|
2971
3039
|
}
|
|
2972
3040
|
get roomCode() {
|
|
2973
3041
|
if (!this.#hasValidBuffer()) {
|
|
@@ -2975,7 +3043,7 @@ class NetContext2 {
|
|
|
2975
3043
|
}
|
|
2976
3044
|
const bytes = [];
|
|
2977
3045
|
for (let i = 0;i < 8; i++) {
|
|
2978
|
-
const byte = this.dataView.getUint8(
|
|
3046
|
+
const byte = this.dataView.getUint8(NET_CTX_ROOM_CODE_OFFSET2 + i);
|
|
2979
3047
|
if (byte === 0)
|
|
2980
3048
|
break;
|
|
2981
3049
|
bytes.push(byte);
|
|
@@ -2988,7 +3056,7 @@ class NetContext2 {
|
|
|
2988
3056
|
}
|
|
2989
3057
|
const bytes = [];
|
|
2990
3058
|
for (let i = 0;i < 8; i++) {
|
|
2991
|
-
const byte = this.dataView.getUint8(
|
|
3059
|
+
const byte = this.dataView.getUint8(NET_CTX_WANTS_ROOM_CODE_OFFSET2 + i);
|
|
2992
3060
|
if (byte === 0)
|
|
2993
3061
|
break;
|
|
2994
3062
|
bytes.push(byte);
|
|
@@ -3000,11 +3068,11 @@ class NetContext2 {
|
|
|
3000
3068
|
throw new Error("NetContext dataView is not valid");
|
|
3001
3069
|
}
|
|
3002
3070
|
for (let i = 0;i < 8; i++) {
|
|
3003
|
-
this.dataView.setUint8(
|
|
3071
|
+
this.dataView.setUint8(NET_CTX_WANTS_ROOM_CODE_OFFSET2 + i, 0);
|
|
3004
3072
|
}
|
|
3005
3073
|
if (code) {
|
|
3006
3074
|
for (let i = 0;i < Math.min(code.length, 7); i++) {
|
|
3007
|
-
this.dataView.setUint8(
|
|
3075
|
+
this.dataView.setUint8(NET_CTX_WANTS_ROOM_CODE_OFFSET2 + i, code.charCodeAt(i));
|
|
3008
3076
|
}
|
|
3009
3077
|
}
|
|
3010
3078
|
}
|
|
@@ -3012,13 +3080,13 @@ class NetContext2 {
|
|
|
3012
3080
|
if (!this.#hasValidBuffer()) {
|
|
3013
3081
|
return false;
|
|
3014
3082
|
}
|
|
3015
|
-
return this.dataView.getUint8(
|
|
3083
|
+
return this.dataView.getUint8(NET_CTX_WANTS_DISCONNECT_OFFSET2) !== 0;
|
|
3016
3084
|
}
|
|
3017
3085
|
set wantsDisconnect(value) {
|
|
3018
3086
|
if (!this.#hasValidBuffer()) {
|
|
3019
3087
|
throw new Error("NetContext dataView is not valid");
|
|
3020
3088
|
}
|
|
3021
|
-
this.dataView.setUint8(
|
|
3089
|
+
this.dataView.setUint8(NET_CTX_WANTS_DISCONNECT_OFFSET2, value ? 1 : 0);
|
|
3022
3090
|
}
|
|
3023
3091
|
get peers() {
|
|
3024
3092
|
if (!this.#hasValidBuffer()) {
|
|
@@ -3028,23 +3096,23 @@ class NetContext2 {
|
|
|
3028
3096
|
const localPeerId = this.localPeerId;
|
|
3029
3097
|
const matchFrame = this.matchFrame;
|
|
3030
3098
|
let minRemoteSeq = -1;
|
|
3031
|
-
for (let i = 0;i <
|
|
3099
|
+
for (let i = 0;i < MAX_PLAYERS2; i++) {
|
|
3032
3100
|
if (i === localPeerId)
|
|
3033
3101
|
continue;
|
|
3034
|
-
const peerOffset =
|
|
3035
|
-
if (dv.getUint8(peerOffset +
|
|
3102
|
+
const peerOffset = NET_CTX_PEERS_OFFSET2 + i * PEER_CTX_SIZE2;
|
|
3103
|
+
if (dv.getUint8(peerOffset + PEER_CTX_CONNECTED_OFFSET2) !== 1)
|
|
3036
3104
|
continue;
|
|
3037
|
-
|
|
3105
|
+
const seq = dv.getInt16(peerOffset + PEER_CTX_SEQ_OFFSET2, true);
|
|
3106
|
+
if (seq < 0)
|
|
3038
3107
|
continue;
|
|
3039
|
-
const seq = dv.getUint16(peerOffset + PEER_SEQ_OFFSET2, true);
|
|
3040
3108
|
if (minRemoteSeq === -1 || seq < minRemoteSeq) {
|
|
3041
3109
|
minRemoteSeq = seq;
|
|
3042
3110
|
}
|
|
3043
3111
|
}
|
|
3044
3112
|
this.#peersResult.length = 0;
|
|
3045
|
-
for (let i = 0;i <
|
|
3046
|
-
const peerOffset =
|
|
3047
|
-
if (dv.getUint8(peerOffset +
|
|
3113
|
+
for (let i = 0;i < MAX_PLAYERS2; i++) {
|
|
3114
|
+
const peerOffset = NET_CTX_PEERS_OFFSET2 + i * PEER_CTX_SIZE2;
|
|
3115
|
+
if (dv.getUint8(peerOffset + PEER_CTX_CONNECTED_OFFSET2) !== 1)
|
|
3048
3116
|
continue;
|
|
3049
3117
|
const peer = this.#peers[i];
|
|
3050
3118
|
if (!peer) {
|
|
@@ -3056,15 +3124,34 @@ class NetContext2 {
|
|
|
3056
3124
|
peer.seq = matchFrame;
|
|
3057
3125
|
peer.ack = minRemoteSeq;
|
|
3058
3126
|
} else {
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
peer.seq = packetCount === 0 ? -1 : dv.getUint16(peerOffset + PEER_SEQ_OFFSET2, true);
|
|
3062
|
-
peer.ack = ackCount === 0 ? -1 : dv.getUint16(peerOffset + PEER_ACK_OFFSET2, true);
|
|
3127
|
+
peer.seq = dv.getInt16(peerOffset + PEER_CTX_SEQ_OFFSET2, true);
|
|
3128
|
+
peer.ack = dv.getInt16(peerOffset + PEER_CTX_ACK_OFFSET2, true);
|
|
3063
3129
|
}
|
|
3064
3130
|
this.#peersResult.push(peer);
|
|
3065
3131
|
}
|
|
3066
3132
|
return this.#peersResult;
|
|
3067
3133
|
}
|
|
3134
|
+
get lastRollbackDepth() {
|
|
3135
|
+
if (!this.#hasValidBuffer()) {
|
|
3136
|
+
throw new Error("NetContext dataView is not valid");
|
|
3137
|
+
}
|
|
3138
|
+
return this.dataView.getUint32(NET_CTX_LAST_ROLLBACK_DEPTH_OFFSET2, true);
|
|
3139
|
+
}
|
|
3140
|
+
get totalRollbacks() {
|
|
3141
|
+
if (!this.#hasValidBuffer()) {
|
|
3142
|
+
throw new Error("NetContext dataView is not valid");
|
|
3143
|
+
}
|
|
3144
|
+
return this.dataView.getUint32(NET_CTX_TOTAL_ROLLBACKS_OFFSET2, true);
|
|
3145
|
+
}
|
|
3146
|
+
get framesResimulated() {
|
|
3147
|
+
if (!this.#hasValidBuffer()) {
|
|
3148
|
+
throw new Error("NetContext dataView is not valid");
|
|
3149
|
+
}
|
|
3150
|
+
return Number(this.dataView.getBigUint64(NET_CTX_FRAMES_RESIMULATED_OFFSET2, true));
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
function mouseButtonCodeToMouseButton2(code) {
|
|
3154
|
+
return MouseButton2[code];
|
|
3068
3155
|
}
|
|
3069
3156
|
var TAPE_MAGIC2 = 1413566533;
|
|
3070
3157
|
function readTapeHeader2(tape) {
|
|
@@ -3081,7 +3168,7 @@ function readTapeHeader2(tape) {
|
|
|
3081
3168
|
eventCount: view.getUint16(14, true)
|
|
3082
3169
|
};
|
|
3083
3170
|
}
|
|
3084
|
-
var DEFAULT_WASM_URL2 = new URL("https://unpkg.com/@bloopjs/engine@0.0.
|
|
3171
|
+
var DEFAULT_WASM_URL2 = new URL("https://unpkg.com/@bloopjs/engine@0.0.89/wasm/bloop.wasm");
|
|
3085
3172
|
var TIME_CTX_OFFSET2 = 0;
|
|
3086
3173
|
var INPUT_CTX_OFFSET2 = TIME_CTX_OFFSET2 + 4;
|
|
3087
3174
|
var EVENTS_OFFSET2 = INPUT_CTX_OFFSET2 + 4;
|
|
@@ -6293,6 +6380,138 @@ function joinRoom(brokerUrl, _roomId, cbs) {
|
|
|
6293
6380
|
}
|
|
6294
6381
|
}
|
|
6295
6382
|
|
|
6383
|
+
// src/netcode/reconcile.ts
|
|
6384
|
+
var udp = null;
|
|
6385
|
+
var localPeerId = null;
|
|
6386
|
+
var remotePeerId = null;
|
|
6387
|
+
var localStringPeerId = null;
|
|
6388
|
+
var remoteStringPeerId = null;
|
|
6389
|
+
var incomingPackets = [];
|
|
6390
|
+
var actual = {
|
|
6391
|
+
roomCode: ""
|
|
6392
|
+
};
|
|
6393
|
+
async function reconcile(app, signal) {
|
|
6394
|
+
app.beforeFrame.subscribe((_frame) => {
|
|
6395
|
+
if (!app.game.context.net.isInSession) {
|
|
6396
|
+
return;
|
|
6397
|
+
}
|
|
6398
|
+
try {
|
|
6399
|
+
receivePackets(app);
|
|
6400
|
+
sendPacket(app);
|
|
6401
|
+
} catch (e4) {
|
|
6402
|
+
console.error("Error in beforeFrame:", e4);
|
|
6403
|
+
}
|
|
6404
|
+
});
|
|
6405
|
+
logger.onLog = (log) => {
|
|
6406
|
+
addLog(log);
|
|
6407
|
+
};
|
|
6408
|
+
while (!signal.aborted) {
|
|
6409
|
+
const { net } = app.game.context;
|
|
6410
|
+
if (net.wantsRoomCode && actual.roomCode !== net.wantsRoomCode) {
|
|
6411
|
+
console.log("[netcode] wants a room code", {
|
|
6412
|
+
actual: actual.roomCode,
|
|
6413
|
+
wants: net.wantsRoomCode
|
|
6414
|
+
});
|
|
6415
|
+
actual.roomCode = net.wantsRoomCode;
|
|
6416
|
+
joinRollbackRoom(net.wantsRoomCode, app);
|
|
6417
|
+
}
|
|
6418
|
+
await sleep(150);
|
|
6419
|
+
}
|
|
6420
|
+
}
|
|
6421
|
+
async function sleep(ms) {
|
|
6422
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6423
|
+
}
|
|
6424
|
+
function joinRollbackRoom(roomId, app) {
|
|
6425
|
+
app.joinRoom(roomId, {
|
|
6426
|
+
onPeerIdAssign: (peerId) => {
|
|
6427
|
+
localStringPeerId = peerId;
|
|
6428
|
+
},
|
|
6429
|
+
onBrokerMessage: (_message) => {},
|
|
6430
|
+
onMessage(_peerId, data, _reliable) {
|
|
6431
|
+
incomingPackets.push(new Uint8Array(data));
|
|
6432
|
+
},
|
|
6433
|
+
onDataChannelClose(_peerId, reliable) {
|
|
6434
|
+
if (!reliable && remotePeerId !== null) {
|
|
6435
|
+
app.sim.emit.network("peer:leave", { peerId: remotePeerId });
|
|
6436
|
+
}
|
|
6437
|
+
},
|
|
6438
|
+
onDataChannelOpen(peerId, reliable, channel) {
|
|
6439
|
+
if (!reliable) {
|
|
6440
|
+
udp = channel;
|
|
6441
|
+
if (localStringPeerId === null) {
|
|
6442
|
+
console.error("[netcode] Local peer ID not assigned yet!");
|
|
6443
|
+
return;
|
|
6444
|
+
}
|
|
6445
|
+
const ids = assignPeerIds(localStringPeerId, peerId);
|
|
6446
|
+
localPeerId = ids.local;
|
|
6447
|
+
setLocalId(localPeerId);
|
|
6448
|
+
remotePeerId = ids.remote;
|
|
6449
|
+
remoteStringPeerId = peerId;
|
|
6450
|
+
setRemoteId(remotePeerId);
|
|
6451
|
+
app.sim.emit.network("peer:join", { peerId: localPeerId });
|
|
6452
|
+
app.sim.emit.network("peer:join", { peerId: remotePeerId });
|
|
6453
|
+
app.sim.emit.network("peer:assign_local_id", { peerId: localPeerId });
|
|
6454
|
+
app.sim.emit.network("session:start", {});
|
|
6455
|
+
}
|
|
6456
|
+
},
|
|
6457
|
+
onPeerConnected(peerId) {
|
|
6458
|
+
addPeer({
|
|
6459
|
+
id: peerId,
|
|
6460
|
+
nickname: peerId.substring(0, 6),
|
|
6461
|
+
ack: -1,
|
|
6462
|
+
seq: -1,
|
|
6463
|
+
lastPacketTime: performance.now()
|
|
6464
|
+
});
|
|
6465
|
+
console.log(`[netcode] Peer connected: ${peerId}. Total peers: ${debugState.netStatus.value.peers.length}`);
|
|
6466
|
+
},
|
|
6467
|
+
onPeerDisconnected(peerId) {
|
|
6468
|
+
removePeer(peerId);
|
|
6469
|
+
if (remotePeerId !== null && peerId === remoteStringPeerId) {
|
|
6470
|
+
app.sim.emit.network("peer:leave", { peerId: remotePeerId });
|
|
6471
|
+
app.sim.emit.network("session:end", {});
|
|
6472
|
+
}
|
|
6473
|
+
}
|
|
6474
|
+
});
|
|
6475
|
+
}
|
|
6476
|
+
function assignPeerIds(localId, remoteId) {
|
|
6477
|
+
if (localId < remoteId) {
|
|
6478
|
+
return { local: 0, remote: 1 };
|
|
6479
|
+
} else {
|
|
6480
|
+
return { local: 1, remote: 0 };
|
|
6481
|
+
}
|
|
6482
|
+
}
|
|
6483
|
+
function receivePackets(app) {
|
|
6484
|
+
for (const packetData of incomingPackets) {
|
|
6485
|
+
app.sim.emit.packet(packetData);
|
|
6486
|
+
if (remotePeerId == null) {
|
|
6487
|
+
return;
|
|
6488
|
+
}
|
|
6489
|
+
const peerState = unwrap(app.sim.net.peers[remotePeerId], `Remote peer state not found for peerId ${remotePeerId}`);
|
|
6490
|
+
updatePeer(remoteStringPeerId, {
|
|
6491
|
+
ack: peerState.ack,
|
|
6492
|
+
seq: peerState.seq,
|
|
6493
|
+
lastPacketTime: performance.now()
|
|
6494
|
+
});
|
|
6495
|
+
}
|
|
6496
|
+
incomingPackets.length = 0;
|
|
6497
|
+
}
|
|
6498
|
+
function sendPacket(app) {
|
|
6499
|
+
if (!udp || remotePeerId === null) {
|
|
6500
|
+
console.warn("[netcode] Cannot send packet, udp or remotePeerId is null");
|
|
6501
|
+
return;
|
|
6502
|
+
}
|
|
6503
|
+
if (udp.readyState !== "open") {
|
|
6504
|
+
console.warn("[netcode] Data channel not open, cannot send packet. readyState=", udp.readyState);
|
|
6505
|
+
return;
|
|
6506
|
+
}
|
|
6507
|
+
const packet = app.sim.getOutboundPacket(remotePeerId);
|
|
6508
|
+
if (!packet) {
|
|
6509
|
+
console.warn("[netcode] No packet to send");
|
|
6510
|
+
return;
|
|
6511
|
+
}
|
|
6512
|
+
udp.send(packet);
|
|
6513
|
+
}
|
|
6514
|
+
|
|
6296
6515
|
// src/App.ts
|
|
6297
6516
|
var DEFAULT_BROKER_URL = "wss://webrtc-divine-glade-8064.fly.dev/ws";
|
|
6298
6517
|
async function start(opts) {
|
|
@@ -6316,6 +6535,7 @@ class App {
|
|
|
6316
6535
|
#unsubscribe = null;
|
|
6317
6536
|
#now = performance.now();
|
|
6318
6537
|
#debugUi = null;
|
|
6538
|
+
#abortController = new AbortController;
|
|
6319
6539
|
constructor(sim, game, brokerUrl, debugUiOpts) {
|
|
6320
6540
|
this.#sim = sim;
|
|
6321
6541
|
this.game = game;
|
|
@@ -6329,6 +6549,9 @@ class App {
|
|
|
6329
6549
|
this.beforeFrame.notify(frame);
|
|
6330
6550
|
};
|
|
6331
6551
|
this.subscribe();
|
|
6552
|
+
reconcile(this, this.#abortController.signal).catch((err) => {
|
|
6553
|
+
console.error("Error in lemmyloop:", err);
|
|
6554
|
+
});
|
|
6332
6555
|
}
|
|
6333
6556
|
get sim() {
|
|
6334
6557
|
return this.#sim;
|
|
@@ -6534,6 +6757,7 @@ class App {
|
|
|
6534
6757
|
this.afterFrame.unsubscribeAll();
|
|
6535
6758
|
this.onHmr.unsubscribeAll();
|
|
6536
6759
|
this.#debugUi?.unmount();
|
|
6760
|
+
this.#abortController.abort();
|
|
6537
6761
|
}
|
|
6538
6762
|
async acceptHmr(module, opts) {
|
|
6539
6763
|
const game = module.game ?? module;
|
|
@@ -6578,131 +6802,13 @@ var PacketType;
|
|
|
6578
6802
|
PacketType2[PacketType2["None"] = 0] = "None";
|
|
6579
6803
|
PacketType2[PacketType2["Inputs"] = 1] = "Inputs";
|
|
6580
6804
|
})(PacketType ||= {});
|
|
6581
|
-
// src/netcode/scaffold.ts
|
|
6582
|
-
function joinRollbackRoom(roomId, app, opts) {
|
|
6583
|
-
let udp = null;
|
|
6584
|
-
let sessionActive = false;
|
|
6585
|
-
let localPeerId = null;
|
|
6586
|
-
let remotePeerId = null;
|
|
6587
|
-
let localStringPeerId = null;
|
|
6588
|
-
let remoteStringPeerId = null;
|
|
6589
|
-
const incomingPackets = [];
|
|
6590
|
-
function assignPeerIds(localId, remoteId) {
|
|
6591
|
-
if (localId < remoteId) {
|
|
6592
|
-
return { local: 0, remote: 1 };
|
|
6593
|
-
} else {
|
|
6594
|
-
return { local: 1, remote: 0 };
|
|
6595
|
-
}
|
|
6596
|
-
}
|
|
6597
|
-
function receivePackets() {
|
|
6598
|
-
for (const packetData of incomingPackets) {
|
|
6599
|
-
app.sim.emit.packet(packetData);
|
|
6600
|
-
if (remotePeerId == null) {
|
|
6601
|
-
return;
|
|
6602
|
-
}
|
|
6603
|
-
const peerState = unwrap(app.sim.net.peers[remotePeerId], `Remote peer state not found for peerId ${remotePeerId}`);
|
|
6604
|
-
updatePeer(remoteStringPeerId, {
|
|
6605
|
-
ack: peerState.ack,
|
|
6606
|
-
seq: peerState.seq,
|
|
6607
|
-
lastPacketTime: performance.now()
|
|
6608
|
-
});
|
|
6609
|
-
}
|
|
6610
|
-
incomingPackets.length = 0;
|
|
6611
|
-
}
|
|
6612
|
-
function sendPacket() {
|
|
6613
|
-
if (!udp || remotePeerId === null) {
|
|
6614
|
-
console.warn("[netcode] Cannot send packet, udp or remotePeerId is null");
|
|
6615
|
-
return;
|
|
6616
|
-
}
|
|
6617
|
-
if (udp.readyState !== "open") {
|
|
6618
|
-
console.warn("[netcode] Data channel not open, cannot send packet. readyState=", udp.readyState);
|
|
6619
|
-
return;
|
|
6620
|
-
}
|
|
6621
|
-
const packet = app.sim.getOutboundPacket(remotePeerId);
|
|
6622
|
-
if (!packet) {
|
|
6623
|
-
console.warn("[netcode] No packet to send");
|
|
6624
|
-
return;
|
|
6625
|
-
}
|
|
6626
|
-
udp.send(packet);
|
|
6627
|
-
}
|
|
6628
|
-
logger.onLog = (log) => {
|
|
6629
|
-
addLog(log);
|
|
6630
|
-
};
|
|
6631
|
-
app.joinRoom(roomId, {
|
|
6632
|
-
onPeerIdAssign: (peerId) => {
|
|
6633
|
-
localStringPeerId = peerId;
|
|
6634
|
-
},
|
|
6635
|
-
onBrokerMessage: (_message) => {},
|
|
6636
|
-
onMessage(_peerId, data, _reliable) {
|
|
6637
|
-
incomingPackets.push(new Uint8Array(data));
|
|
6638
|
-
},
|
|
6639
|
-
onDataChannelClose(peerId, reliable) {
|
|
6640
|
-
if (!reliable && remotePeerId !== null) {
|
|
6641
|
-
app.sim.emit.network("peer:leave", { peerId: remotePeerId });
|
|
6642
|
-
sessionActive = false;
|
|
6643
|
-
opts?.onSessionEnd?.();
|
|
6644
|
-
}
|
|
6645
|
-
},
|
|
6646
|
-
onDataChannelOpen(peerId, reliable, channel) {
|
|
6647
|
-
if (!reliable) {
|
|
6648
|
-
udp = channel;
|
|
6649
|
-
if (localStringPeerId === null) {
|
|
6650
|
-
console.error("[netcode] Local peer ID not assigned yet!");
|
|
6651
|
-
return;
|
|
6652
|
-
}
|
|
6653
|
-
const ids = assignPeerIds(localStringPeerId, peerId);
|
|
6654
|
-
localPeerId = ids.local;
|
|
6655
|
-
setLocalId(localPeerId);
|
|
6656
|
-
remotePeerId = ids.remote;
|
|
6657
|
-
remoteStringPeerId = peerId;
|
|
6658
|
-
setRemoteId(remotePeerId);
|
|
6659
|
-
app.sim.emit.network("peer:join", { peerId: localPeerId });
|
|
6660
|
-
app.sim.emit.network("peer:join", { peerId: remotePeerId });
|
|
6661
|
-
app.sim.emit.network("peer:assign_local_id", { peerId: localPeerId });
|
|
6662
|
-
app.sim.emit.network("session:start", {});
|
|
6663
|
-
sessionActive = true;
|
|
6664
|
-
opts?.onSessionStart?.();
|
|
6665
|
-
}
|
|
6666
|
-
},
|
|
6667
|
-
onPeerConnected(peerId) {
|
|
6668
|
-
addPeer({
|
|
6669
|
-
id: peerId,
|
|
6670
|
-
nickname: peerId.substring(0, 6),
|
|
6671
|
-
ack: -1,
|
|
6672
|
-
seq: -1,
|
|
6673
|
-
lastPacketTime: performance.now()
|
|
6674
|
-
});
|
|
6675
|
-
console.log(`[netcode] Peer connected: ${peerId}. Total peers: ${debugState.netStatus.value.peers.length}`);
|
|
6676
|
-
},
|
|
6677
|
-
onPeerDisconnected(peerId) {
|
|
6678
|
-
removePeer(peerId);
|
|
6679
|
-
if (remotePeerId !== null && peerId === remoteStringPeerId) {
|
|
6680
|
-
app.sim.emit.network("peer:leave", { peerId: remotePeerId });
|
|
6681
|
-
sessionActive = false;
|
|
6682
|
-
opts?.onSessionEnd?.();
|
|
6683
|
-
}
|
|
6684
|
-
}
|
|
6685
|
-
});
|
|
6686
|
-
app.beforeFrame.subscribe((_frame) => {
|
|
6687
|
-
if (!sessionActive || !udp || remotePeerId === null) {
|
|
6688
|
-
return;
|
|
6689
|
-
}
|
|
6690
|
-
try {
|
|
6691
|
-
receivePackets();
|
|
6692
|
-
sendPacket();
|
|
6693
|
-
} catch (e4) {
|
|
6694
|
-
console.error("Error in beforeFrame:", e4);
|
|
6695
|
-
}
|
|
6696
|
-
});
|
|
6697
|
-
}
|
|
6698
6805
|
export {
|
|
6699
6806
|
start,
|
|
6700
6807
|
logger,
|
|
6701
|
-
joinRollbackRoom,
|
|
6702
6808
|
PacketType,
|
|
6703
6809
|
exports_mod as Debug,
|
|
6704
6810
|
App
|
|
6705
6811
|
};
|
|
6706
6812
|
|
|
6707
|
-
//# debugId=
|
|
6813
|
+
//# debugId=164BA35FD7424E1864756E2164756E21
|
|
6708
6814
|
//# sourceMappingURL=mod.js.map
|