@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.
@@ -2,6 +2,8 @@ export type { PeerId, BrokerMessage, PeerMessage } from "./protocol.ts";
2
2
  export type { Log, LogOpts, LogDirection, LogSeverity, OnLogCallback, } from "./logs.ts";
3
3
  export type { WebRtcPipe } from "./transport.ts";
4
4
  export type { RoomEvents } from "./broker.ts";
5
+ export type { JoinRollbackRoomOptions } from "./scaffold.ts";
5
6
  export { PacketType } from "./protocol.ts";
6
7
  export { logger } from "./logs.ts";
8
+ export { joinRollbackRoom } from "./scaffold.ts";
7
9
  //# sourceMappingURL=mod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/netcode/mod.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACxE,YAAY,EACV,GAAG,EACH,OAAO,EACP,YAAY,EACZ,WAAW,EACX,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/netcode/mod.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACxE,YAAY,EACV,GAAG,EACH,OAAO,EACP,YAAY,EACZ,WAAW,EACX,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { App } from "../App.ts";
2
+ export type JoinRollbackRoomOptions = {
3
+ /** Called when session becomes active */
4
+ onSessionStart?: () => void;
5
+ /** Called when session ends */
6
+ onSessionEnd?: () => void;
7
+ };
8
+ /**
9
+ * Join a rollback netcode room and wire up packet processing.
10
+ * This is a scaffold/stopgap - not the final architecture.
11
+ */
12
+ export declare function joinRollbackRoom(roomId: string, app: App, opts?: JoinRollbackRoomOptions): void;
13
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/netcode/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAIrC,MAAM,MAAM,uBAAuB,GAAG;IACpC,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,GAAG,EACR,IAAI,CAAC,EAAE,uBAAuB,GAC7B,IAAI,CAqJN"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloopjs/web",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "author": "Neil Sarkar",
5
5
  "type": "module",
6
6
  "repository": {
@@ -33,8 +33,8 @@
33
33
  "typescript": "^5"
34
34
  },
35
35
  "dependencies": {
36
- "@bloopjs/bloop": "0.0.49",
37
- "@bloopjs/engine": "0.0.49",
36
+ "@bloopjs/bloop": "0.0.51",
37
+ "@bloopjs/engine": "0.0.51",
38
38
  "@preact/signals": "^1.3.1",
39
39
  "partysocket": "^1.1.6",
40
40
  "preact": "^10.25.4"
package/src/App.ts CHANGED
@@ -88,7 +88,7 @@ export class App {
88
88
 
89
89
  this.game.hooks.beforeFrame = (frame: number) => {
90
90
  logger.frameNumber = this.#sim.time.frame;
91
- logger.matchFrame = this.#sim.wasm.get_match_frame();
91
+ logger.matchFrame = this.game.context.net.matchFrame;
92
92
  this.beforeFrame.notify(frame);
93
93
  };
94
94
 
@@ -9,6 +9,8 @@ export type {
9
9
  } from "./logs.ts";
10
10
  export type { WebRtcPipe } from "./transport.ts";
11
11
  export type { RoomEvents } from "./broker.ts";
12
+ export type { JoinRollbackRoomOptions } from "./scaffold.ts";
12
13
 
13
14
  export { PacketType } from "./protocol.ts";
14
15
  export { logger } from "./logs.ts";
16
+ export { joinRollbackRoom } from "./scaffold.ts";
@@ -0,0 +1,169 @@
1
+ import type { App } from "../App.ts";
2
+ import * as Debug from "../debugui/mod.ts";
3
+ import { logger } from "./logs.ts";
4
+
5
+ export type JoinRollbackRoomOptions = {
6
+ /** Called when session becomes active */
7
+ onSessionStart?: () => void;
8
+ /** Called when session ends */
9
+ onSessionEnd?: () => void;
10
+ };
11
+
12
+ /**
13
+ * Join a rollback netcode room and wire up packet processing.
14
+ * This is a scaffold/stopgap - not the final architecture.
15
+ */
16
+ export function joinRollbackRoom(
17
+ roomId: string,
18
+ app: App,
19
+ opts?: JoinRollbackRoomOptions,
20
+ ): void {
21
+ // State
22
+ let udp: RTCDataChannel | null = null;
23
+ let sessionActive = false;
24
+ let localPeerId: number | null = null;
25
+ let remotePeerId: number | null = null;
26
+ let localStringPeerId: string | null = null;
27
+ let remoteStringPeerId: string | null = null;
28
+ const incomingPackets: Uint8Array[] = [];
29
+
30
+ function assignPeerIds(
31
+ localId: string,
32
+ remoteId: string,
33
+ ): { local: number; remote: number } {
34
+ if (localId < remoteId) {
35
+ return { local: 0, remote: 1 };
36
+ } else {
37
+ return { local: 1, remote: 0 };
38
+ }
39
+ }
40
+
41
+ function receivePackets() {
42
+ for (const packetData of incomingPackets) {
43
+ app.sim.net.receivePacket(packetData);
44
+
45
+ if (remotePeerId == null) {
46
+ return;
47
+ }
48
+
49
+ const peerState = app.sim.net.getPeerState(remotePeerId);
50
+ Debug.updatePeer(remoteStringPeerId!, {
51
+ ack: peerState.ack,
52
+ seq: peerState.seq,
53
+ lastPacketTime: performance.now(),
54
+ });
55
+ }
56
+ incomingPackets.length = 0;
57
+ }
58
+
59
+ function sendPacket() {
60
+ if (!udp || remotePeerId === null) {
61
+ console.warn("[netcode] Cannot send packet, udp or remotePeerId is null");
62
+ return;
63
+ }
64
+
65
+ if (udp.readyState !== "open") {
66
+ console.warn(
67
+ "[netcode] Data channel not open, cannot send packet. readyState=",
68
+ udp.readyState,
69
+ );
70
+ return;
71
+ }
72
+
73
+ const packet = app.sim.net.getOutboundPacket(remotePeerId);
74
+
75
+ if (!packet) {
76
+ console.warn("[netcode] No packet to send");
77
+ return;
78
+ }
79
+
80
+ udp.send(packet);
81
+ }
82
+
83
+ // Wire up logger to debug state
84
+ logger.onLog = (log) => {
85
+ Debug.addLog(log);
86
+ };
87
+
88
+ app.joinRoom(roomId, {
89
+ onPeerIdAssign: (peerId) => {
90
+ console.log(`Assigned peer ID: ${peerId}`);
91
+ localStringPeerId = peerId;
92
+ },
93
+ onBrokerMessage: (_message) => {},
94
+ onMessage(_peerId, data, _reliable) {
95
+ incomingPackets.push(new Uint8Array(data));
96
+ },
97
+ onDataChannelClose(peerId, reliable) {
98
+ console.log(`Data channel closed: ${peerId} (reliable: ${reliable})`);
99
+ if (!reliable && remotePeerId !== null) {
100
+ app.sim.net.disconnectPeer(remotePeerId);
101
+ sessionActive = false;
102
+ opts?.onSessionEnd?.();
103
+ }
104
+ },
105
+ onDataChannelOpen(peerId, reliable, channel) {
106
+ console.log(`Data channel opened: ${peerId} (reliable: ${reliable})`);
107
+ if (!reliable) {
108
+ udp = channel;
109
+
110
+ if (localStringPeerId === null) {
111
+ console.error("[netcode] Local peer ID not assigned yet!");
112
+ return;
113
+ }
114
+
115
+ const ids = assignPeerIds(localStringPeerId, peerId);
116
+ localPeerId = ids.local;
117
+ Debug.setLocalId(localPeerId);
118
+ remotePeerId = ids.remote;
119
+ remoteStringPeerId = peerId;
120
+ Debug.setRemoteId(remotePeerId);
121
+
122
+ // Initialize the session in the engine (2 players)
123
+ app.sim.sessionInit(2);
124
+
125
+ // Set up local and remote peers in net state
126
+ app.sim.net.setLocalPeer(localPeerId);
127
+ app.sim.net.connectPeer(remotePeerId);
128
+
129
+ sessionActive = true;
130
+ console.log(`[netcode] Session started at frame ${app.sim.time.frame}`);
131
+ opts?.onSessionStart?.();
132
+ }
133
+ },
134
+ onPeerConnected(peerId) {
135
+ Debug.addPeer({
136
+ id: peerId,
137
+ nickname: peerId.substring(0, 6),
138
+ ack: -1,
139
+ seq: -1,
140
+ lastPacketTime: performance.now(),
141
+ });
142
+ console.log(
143
+ `[netcode] Peer connected: ${peerId}. Total peers: ${Debug.debugState.netStatus.value.peers.length}`,
144
+ );
145
+ },
146
+ onPeerDisconnected(peerId) {
147
+ Debug.removePeer(peerId);
148
+ if (remotePeerId !== null && peerId === remoteStringPeerId) {
149
+ app.sim.net.disconnectPeer(remotePeerId);
150
+ sessionActive = false;
151
+ opts?.onSessionEnd?.();
152
+ }
153
+ },
154
+ });
155
+
156
+ // Process packets and send our state each frame
157
+ app.beforeFrame.subscribe((_frame) => {
158
+ if (!sessionActive || !udp || remotePeerId === null) {
159
+ return;
160
+ }
161
+
162
+ try {
163
+ receivePackets();
164
+ sendPacket();
165
+ } catch (e) {
166
+ console.error("Error in beforeFrame:", e);
167
+ }
168
+ });
169
+ }