@bloopjs/web 0.0.49 → 0.0.51
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/mod.js +153 -4
- package/dist/mod.js.map +8 -7
- package/dist/netcode/mod.d.ts +2 -0
- package/dist/netcode/mod.d.ts.map +1 -1
- package/dist/netcode/scaffold.d.ts +13 -0
- package/dist/netcode/scaffold.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/App.ts +1 -1
- package/src/netcode/mod.ts +2 -0
- package/src/netcode/scaffold.ts +169 -0
package/dist/mod.js
CHANGED
|
@@ -81,6 +81,8 @@ __export2(exports_engine, {
|
|
|
81
81
|
SNAPSHOT_HEADER_ENGINE_LEN_OFFSET: () => SNAPSHOT_HEADER_ENGINE_LEN_OFFSET,
|
|
82
82
|
PlayerInputContext: () => PlayerInputContext,
|
|
83
83
|
PLAYER_INPUTS_SIZE: () => PLAYER_INPUTS_SIZE,
|
|
84
|
+
NetContext: () => NetContext,
|
|
85
|
+
NET_CTX_OFFSET: () => NET_CTX_OFFSET,
|
|
84
86
|
MouseContext: () => MouseContext,
|
|
85
87
|
MOUSE_OFFSET: () => MOUSE_OFFSET,
|
|
86
88
|
MOUSE_BUTTONS_OFFSET: () => MOUSE_BUTTONS_OFFSET,
|
|
@@ -1145,10 +1147,30 @@ class TimeContext {
|
|
|
1145
1147
|
return this.dataView.getUint32(8, true) / 1000;
|
|
1146
1148
|
}
|
|
1147
1149
|
}
|
|
1150
|
+
|
|
1151
|
+
class NetContext {
|
|
1152
|
+
dataView;
|
|
1153
|
+
constructor(dataView) {
|
|
1154
|
+
this.dataView = dataView;
|
|
1155
|
+
}
|
|
1156
|
+
get peerCount() {
|
|
1157
|
+
if (!this.dataView) {
|
|
1158
|
+
throw new Error("NetContext DataView is not initialized");
|
|
1159
|
+
}
|
|
1160
|
+
return this.dataView.getUint8(0);
|
|
1161
|
+
}
|
|
1162
|
+
get matchFrame() {
|
|
1163
|
+
if (!this.dataView) {
|
|
1164
|
+
throw new Error("NetContext DataView is not initialized");
|
|
1165
|
+
}
|
|
1166
|
+
return this.dataView.getUint32(4, true);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1148
1169
|
var DEFAULT_WASM_URL = new URL("../wasm/bloop.wasm", import.meta.url);
|
|
1149
1170
|
var TIME_CTX_OFFSET = 0;
|
|
1150
1171
|
var INPUT_CTX_OFFSET = TIME_CTX_OFFSET + 4;
|
|
1151
1172
|
var EVENTS_OFFSET = INPUT_CTX_OFFSET + 4;
|
|
1173
|
+
var NET_CTX_OFFSET = EVENTS_OFFSET + 4;
|
|
1152
1174
|
var SNAPSHOT_HEADER_LEN = 16;
|
|
1153
1175
|
var SNAPSHOT_HEADER_USER_LEN_OFFSET = 4;
|
|
1154
1176
|
var SNAPSHOT_HEADER_ENGINE_LEN_OFFSET = 8;
|
|
@@ -1401,8 +1423,10 @@ async function mount(opts) {
|
|
|
1401
1423
|
opts.hooks.setBuffer(memory.buffer);
|
|
1402
1424
|
opts.hooks.systemsCallback(system_handle, ptr);
|
|
1403
1425
|
},
|
|
1404
|
-
__before_frame: function(frame) {
|
|
1426
|
+
__before_frame: function(ptr, frame) {
|
|
1405
1427
|
try {
|
|
1428
|
+
opts.hooks.setBuffer(memory.buffer);
|
|
1429
|
+
opts.hooks.setContext(ptr);
|
|
1406
1430
|
opts.hooks.beforeFrame?.(frame);
|
|
1407
1431
|
} catch (e) {
|
|
1408
1432
|
console.error("Error in beforeFrame hook:", e);
|
|
@@ -1461,7 +1485,8 @@ class Bloop {
|
|
|
1461
1485
|
get players() {
|
|
1462
1486
|
return inputs.players;
|
|
1463
1487
|
},
|
|
1464
|
-
rawPointer: -1
|
|
1488
|
+
rawPointer: -1,
|
|
1489
|
+
net: new NetContext
|
|
1465
1490
|
};
|
|
1466
1491
|
}
|
|
1467
1492
|
get bag() {
|
|
@@ -1508,9 +1533,11 @@ class Bloop {
|
|
|
1508
1533
|
const dv = new DataView(this.#engineBuffer, ptr);
|
|
1509
1534
|
const timeCtxPtr = dv.getUint32(TIME_CTX_OFFSET, true);
|
|
1510
1535
|
const inputCtxPtr = dv.getUint32(INPUT_CTX_OFFSET, true);
|
|
1536
|
+
const netCtxPtr = dv.getUint32(NET_CTX_OFFSET, true);
|
|
1511
1537
|
this.#context.rawPointer = ptr;
|
|
1512
1538
|
this.#context.inputs.dataView = new DataView(this.#engineBuffer, inputCtxPtr);
|
|
1513
1539
|
this.#context.time.dataView = new DataView(this.#engineBuffer, timeCtxPtr);
|
|
1540
|
+
this.#context.net.dataView = new DataView(this.#engineBuffer, netCtxPtr);
|
|
1514
1541
|
},
|
|
1515
1542
|
systemsCallback: (system_handle, ptr) => {
|
|
1516
1543
|
this.hooks.setContext(ptr);
|
|
@@ -2588,6 +2615,7 @@ var DEFAULT_WASM_URL2 = new URL("../wasm/bloop.wasm", import.meta.url);
|
|
|
2588
2615
|
var TIME_CTX_OFFSET2 = 0;
|
|
2589
2616
|
var INPUT_CTX_OFFSET2 = TIME_CTX_OFFSET2 + 4;
|
|
2590
2617
|
var EVENTS_OFFSET2 = INPUT_CTX_OFFSET2 + 4;
|
|
2618
|
+
var NET_CTX_OFFSET2 = EVENTS_OFFSET2 + 4;
|
|
2591
2619
|
|
|
2592
2620
|
// ../../node_modules/partysocket/dist/chunk-V6LO7DXK.mjs
|
|
2593
2621
|
if (!globalThis.EventTarget || !globalThis.Event) {
|
|
@@ -5105,7 +5133,7 @@ class App {
|
|
|
5105
5133
|
}
|
|
5106
5134
|
this.game.hooks.beforeFrame = (frame) => {
|
|
5107
5135
|
logger.frameNumber = this.#sim.time.frame;
|
|
5108
|
-
logger.matchFrame = this
|
|
5136
|
+
logger.matchFrame = this.game.context.net.matchFrame;
|
|
5109
5137
|
this.beforeFrame.notify(frame);
|
|
5110
5138
|
};
|
|
5111
5139
|
this.subscribe();
|
|
@@ -5274,13 +5302,134 @@ var PacketType;
|
|
|
5274
5302
|
PacketType2[PacketType2["None"] = 0] = "None";
|
|
5275
5303
|
PacketType2[PacketType2["Inputs"] = 1] = "Inputs";
|
|
5276
5304
|
})(PacketType ||= {});
|
|
5305
|
+
// src/netcode/scaffold.ts
|
|
5306
|
+
function joinRollbackRoom(roomId, app, opts) {
|
|
5307
|
+
let udp = null;
|
|
5308
|
+
let sessionActive = false;
|
|
5309
|
+
let localPeerId = null;
|
|
5310
|
+
let remotePeerId = null;
|
|
5311
|
+
let localStringPeerId = null;
|
|
5312
|
+
let remoteStringPeerId = null;
|
|
5313
|
+
const incomingPackets = [];
|
|
5314
|
+
function assignPeerIds(localId, remoteId) {
|
|
5315
|
+
if (localId < remoteId) {
|
|
5316
|
+
return { local: 0, remote: 1 };
|
|
5317
|
+
} else {
|
|
5318
|
+
return { local: 1, remote: 0 };
|
|
5319
|
+
}
|
|
5320
|
+
}
|
|
5321
|
+
function receivePackets() {
|
|
5322
|
+
for (const packetData of incomingPackets) {
|
|
5323
|
+
app.sim.net.receivePacket(packetData);
|
|
5324
|
+
if (remotePeerId == null) {
|
|
5325
|
+
return;
|
|
5326
|
+
}
|
|
5327
|
+
const peerState = app.sim.net.getPeerState(remotePeerId);
|
|
5328
|
+
updatePeer(remoteStringPeerId, {
|
|
5329
|
+
ack: peerState.ack,
|
|
5330
|
+
seq: peerState.seq,
|
|
5331
|
+
lastPacketTime: performance.now()
|
|
5332
|
+
});
|
|
5333
|
+
}
|
|
5334
|
+
incomingPackets.length = 0;
|
|
5335
|
+
}
|
|
5336
|
+
function sendPacket() {
|
|
5337
|
+
if (!udp || remotePeerId === null) {
|
|
5338
|
+
console.warn("[netcode] Cannot send packet, udp or remotePeerId is null");
|
|
5339
|
+
return;
|
|
5340
|
+
}
|
|
5341
|
+
if (udp.readyState !== "open") {
|
|
5342
|
+
console.warn("[netcode] Data channel not open, cannot send packet. readyState=", udp.readyState);
|
|
5343
|
+
return;
|
|
5344
|
+
}
|
|
5345
|
+
const packet = app.sim.net.getOutboundPacket(remotePeerId);
|
|
5346
|
+
if (!packet) {
|
|
5347
|
+
console.warn("[netcode] No packet to send");
|
|
5348
|
+
return;
|
|
5349
|
+
}
|
|
5350
|
+
udp.send(packet);
|
|
5351
|
+
}
|
|
5352
|
+
logger.onLog = (log) => {
|
|
5353
|
+
addLog(log);
|
|
5354
|
+
};
|
|
5355
|
+
app.joinRoom(roomId, {
|
|
5356
|
+
onPeerIdAssign: (peerId) => {
|
|
5357
|
+
console.log(`Assigned peer ID: ${peerId}`);
|
|
5358
|
+
localStringPeerId = peerId;
|
|
5359
|
+
},
|
|
5360
|
+
onBrokerMessage: (_message) => {},
|
|
5361
|
+
onMessage(_peerId, data, _reliable) {
|
|
5362
|
+
incomingPackets.push(new Uint8Array(data));
|
|
5363
|
+
},
|
|
5364
|
+
onDataChannelClose(peerId, reliable) {
|
|
5365
|
+
console.log(`Data channel closed: ${peerId} (reliable: ${reliable})`);
|
|
5366
|
+
if (!reliable && remotePeerId !== null) {
|
|
5367
|
+
app.sim.net.disconnectPeer(remotePeerId);
|
|
5368
|
+
sessionActive = false;
|
|
5369
|
+
opts?.onSessionEnd?.();
|
|
5370
|
+
}
|
|
5371
|
+
},
|
|
5372
|
+
onDataChannelOpen(peerId, reliable, channel) {
|
|
5373
|
+
console.log(`Data channel opened: ${peerId} (reliable: ${reliable})`);
|
|
5374
|
+
if (!reliable) {
|
|
5375
|
+
udp = channel;
|
|
5376
|
+
if (localStringPeerId === null) {
|
|
5377
|
+
console.error("[netcode] Local peer ID not assigned yet!");
|
|
5378
|
+
return;
|
|
5379
|
+
}
|
|
5380
|
+
const ids = assignPeerIds(localStringPeerId, peerId);
|
|
5381
|
+
localPeerId = ids.local;
|
|
5382
|
+
setLocalId(localPeerId);
|
|
5383
|
+
remotePeerId = ids.remote;
|
|
5384
|
+
remoteStringPeerId = peerId;
|
|
5385
|
+
setRemoteId(remotePeerId);
|
|
5386
|
+
app.sim.sessionInit(2);
|
|
5387
|
+
app.sim.net.setLocalPeer(localPeerId);
|
|
5388
|
+
app.sim.net.connectPeer(remotePeerId);
|
|
5389
|
+
sessionActive = true;
|
|
5390
|
+
console.log(`[netcode] Session started at frame ${app.sim.time.frame}`);
|
|
5391
|
+
opts?.onSessionStart?.();
|
|
5392
|
+
}
|
|
5393
|
+
},
|
|
5394
|
+
onPeerConnected(peerId) {
|
|
5395
|
+
addPeer({
|
|
5396
|
+
id: peerId,
|
|
5397
|
+
nickname: peerId.substring(0, 6),
|
|
5398
|
+
ack: -1,
|
|
5399
|
+
seq: -1,
|
|
5400
|
+
lastPacketTime: performance.now()
|
|
5401
|
+
});
|
|
5402
|
+
console.log(`[netcode] Peer connected: ${peerId}. Total peers: ${debugState.netStatus.value.peers.length}`);
|
|
5403
|
+
},
|
|
5404
|
+
onPeerDisconnected(peerId) {
|
|
5405
|
+
removePeer(peerId);
|
|
5406
|
+
if (remotePeerId !== null && peerId === remoteStringPeerId) {
|
|
5407
|
+
app.sim.net.disconnectPeer(remotePeerId);
|
|
5408
|
+
sessionActive = false;
|
|
5409
|
+
opts?.onSessionEnd?.();
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
});
|
|
5413
|
+
app.beforeFrame.subscribe((_frame) => {
|
|
5414
|
+
if (!sessionActive || !udp || remotePeerId === null) {
|
|
5415
|
+
return;
|
|
5416
|
+
}
|
|
5417
|
+
try {
|
|
5418
|
+
receivePackets();
|
|
5419
|
+
sendPacket();
|
|
5420
|
+
} catch (e4) {
|
|
5421
|
+
console.error("Error in beforeFrame:", e4);
|
|
5422
|
+
}
|
|
5423
|
+
});
|
|
5424
|
+
}
|
|
5277
5425
|
export {
|
|
5278
5426
|
start,
|
|
5279
5427
|
logger,
|
|
5428
|
+
joinRollbackRoom,
|
|
5280
5429
|
PacketType,
|
|
5281
5430
|
exports_mod as Debug,
|
|
5282
5431
|
App
|
|
5283
5432
|
};
|
|
5284
5433
|
|
|
5285
|
-
//# debugId=
|
|
5434
|
+
//# debugId=9734AFFABAFBA4F864756E2164756E21
|
|
5286
5435
|
//# sourceMappingURL=mod.js.map
|