@mml-io/3d-web-user-networking 0.0.0-experimental-c389fca-20250625 → 0.0.0-experimental-bcf0b7c-20250715
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/build/DeltaNetComponentMapping.d.ts +57 -0
- package/build/UserData.d.ts +3 -2
- package/build/UserNetworkingClient.d.ts +38 -14
- package/build/UserNetworkingMessages.d.ts +14 -53
- package/build/UserNetworkingServer.d.ts +28 -18
- package/build/index.d.ts +4 -2
- package/build/index.js +1318 -383
- package/build/index.js.map +4 -4
- package/build/legacy/LegacyAdapter.d.ts +27 -0
- package/build/legacy/LegacyUserNetworkingCodec.d.ts +17 -0
- package/build/legacy/LegacyUserNetworkingMessages.d.ts +76 -0
- package/build/{UserNetworkingCodec.d.ts → types.d.ts} +7 -5
- package/package.json +15 -6
- package/LICENSE +0 -19
- package/build/ReconnectingWebSocket.d.ts +0 -27
- package/build/user-networking-settings.d.ts +0 -3
package/build/index.js
CHANGED
@@ -1,5 +1,272 @@
|
|
1
|
-
// src/
|
2
|
-
|
1
|
+
// src/UserNetworkingServer.ts
|
2
|
+
import { encodeError, DeltaNetV01ServerErrors } from "/Users/marcuslongmuir/mml/3d-web-experience/packages/deltanet/delta-net-protocol/build/index.js";
|
3
|
+
import {
|
4
|
+
DeltaNetServer,
|
5
|
+
DeltaNetServerError as DeltaNetServerError2
|
6
|
+
} from "/Users/marcuslongmuir/mml/3d-web-experience/packages/deltanet/delta-net-server/build/index.js";
|
7
|
+
|
8
|
+
// src/DeltaNetComponentMapping.ts
|
9
|
+
import { BufferReader, BufferWriter } from "/Users/marcuslongmuir/mml/3d-web-experience/packages/deltanet/delta-net-protocol/build/index.js";
|
10
|
+
var COMPONENT_POSITION_X = 1;
|
11
|
+
var COMPONENT_POSITION_Y = 2;
|
12
|
+
var COMPONENT_POSITION_Z = 3;
|
13
|
+
var COMPONENT_ROTATION_Y = 4;
|
14
|
+
var COMPONENT_ROTATION_W = 5;
|
15
|
+
var COMPONENT_STATE = 6;
|
16
|
+
var STATE_INTERNAL_CONNECTION_ID = 0;
|
17
|
+
var STATE_CHARACTER_DESCRIPTION = 1;
|
18
|
+
var STATE_USERNAME = 2;
|
19
|
+
var STATE_COLORS = 3;
|
20
|
+
var rotationMultiplier = 360;
|
21
|
+
var positionMultiplier = 100;
|
22
|
+
var textDecoder = new TextDecoder();
|
23
|
+
var DeltaNetComponentMapping = class _DeltaNetComponentMapping {
|
24
|
+
/**
|
25
|
+
* Convert UserNetworkingClientUpdate to deltanet components
|
26
|
+
*/
|
27
|
+
static toComponents(update) {
|
28
|
+
const components = /* @__PURE__ */ new Map();
|
29
|
+
components.set(
|
30
|
+
COMPONENT_POSITION_X,
|
31
|
+
BigInt(Math.round(update.position.x * positionMultiplier))
|
32
|
+
);
|
33
|
+
components.set(
|
34
|
+
COMPONENT_POSITION_Y,
|
35
|
+
BigInt(Math.round(update.position.y * positionMultiplier))
|
36
|
+
);
|
37
|
+
components.set(
|
38
|
+
COMPONENT_POSITION_Z,
|
39
|
+
BigInt(Math.round(update.position.z * positionMultiplier))
|
40
|
+
);
|
41
|
+
components.set(
|
42
|
+
COMPONENT_ROTATION_Y,
|
43
|
+
BigInt(Math.round(update.rotation.quaternionY * rotationMultiplier))
|
44
|
+
);
|
45
|
+
components.set(
|
46
|
+
COMPONENT_ROTATION_W,
|
47
|
+
BigInt(Math.round(update.rotation.quaternionW * rotationMultiplier))
|
48
|
+
);
|
49
|
+
components.set(COMPONENT_STATE, BigInt(update.state));
|
50
|
+
return components;
|
51
|
+
}
|
52
|
+
/**
|
53
|
+
* Convert deltanet components back to UserNetworkingClientUpdate
|
54
|
+
*/
|
55
|
+
static fromComponents(components) {
|
56
|
+
const positionX = Number(components.get(COMPONENT_POSITION_X) || BigInt(0)) / positionMultiplier;
|
57
|
+
const positionY = Number(components.get(COMPONENT_POSITION_Y) || BigInt(0)) / positionMultiplier;
|
58
|
+
const positionZ = Number(components.get(COMPONENT_POSITION_Z) || BigInt(0)) / positionMultiplier;
|
59
|
+
const rotationY = Number(components.get(COMPONENT_ROTATION_Y) || BigInt(0)) / rotationMultiplier;
|
60
|
+
const rotationW = Number(components.get(COMPONENT_ROTATION_W) || BigInt(0)) / rotationMultiplier;
|
61
|
+
const state = Number(components.get(COMPONENT_STATE) || BigInt(0));
|
62
|
+
return {
|
63
|
+
position: { x: positionX, y: positionY, z: positionZ },
|
64
|
+
rotation: { quaternionY: rotationY, quaternionW: rotationW },
|
65
|
+
state
|
66
|
+
};
|
67
|
+
}
|
68
|
+
/**
|
69
|
+
* Encode character description and username to binary states
|
70
|
+
*/
|
71
|
+
static toStates(userIdentity) {
|
72
|
+
const states = /* @__PURE__ */ new Map();
|
73
|
+
const textEncoder = new TextEncoder();
|
74
|
+
if (userIdentity.username) {
|
75
|
+
states.set(STATE_USERNAME, textEncoder.encode(userIdentity.username));
|
76
|
+
}
|
77
|
+
if (userIdentity.characterDescription) {
|
78
|
+
states.set(
|
79
|
+
STATE_CHARACTER_DESCRIPTION,
|
80
|
+
textEncoder.encode(JSON.stringify(userIdentity.characterDescription))
|
81
|
+
);
|
82
|
+
}
|
83
|
+
if (userIdentity.colors) {
|
84
|
+
states.set(STATE_COLORS, _DeltaNetComponentMapping.encodeColors(userIdentity.colors));
|
85
|
+
}
|
86
|
+
return states;
|
87
|
+
}
|
88
|
+
/**
|
89
|
+
* Encode username to binary state
|
90
|
+
*/
|
91
|
+
static toUsernameState(username) {
|
92
|
+
const states = /* @__PURE__ */ new Map();
|
93
|
+
const textEncoder = new TextEncoder();
|
94
|
+
states.set(STATE_USERNAME, textEncoder.encode(username));
|
95
|
+
return states;
|
96
|
+
}
|
97
|
+
/**
|
98
|
+
* Encode character description to binary state
|
99
|
+
*/
|
100
|
+
static toCharacterDescriptionState(characterDescription) {
|
101
|
+
const states = /* @__PURE__ */ new Map();
|
102
|
+
const textEncoder = new TextEncoder();
|
103
|
+
states.set(
|
104
|
+
STATE_CHARACTER_DESCRIPTION,
|
105
|
+
textEncoder.encode(JSON.stringify(characterDescription))
|
106
|
+
);
|
107
|
+
return states;
|
108
|
+
}
|
109
|
+
/**
|
110
|
+
* Encode colors to binary state
|
111
|
+
*/
|
112
|
+
static toColorsState(colors) {
|
113
|
+
const states = /* @__PURE__ */ new Map();
|
114
|
+
states.set(STATE_COLORS, _DeltaNetComponentMapping.encodeColors(colors));
|
115
|
+
return states;
|
116
|
+
}
|
117
|
+
/**
|
118
|
+
* Encode single state value
|
119
|
+
*/
|
120
|
+
static toSingleState(stateId, value) {
|
121
|
+
const states = /* @__PURE__ */ new Map();
|
122
|
+
const textEncoder = new TextEncoder();
|
123
|
+
switch (stateId) {
|
124
|
+
case STATE_USERNAME:
|
125
|
+
if (typeof value === "string") {
|
126
|
+
states.set(stateId, textEncoder.encode(value));
|
127
|
+
}
|
128
|
+
break;
|
129
|
+
case STATE_CHARACTER_DESCRIPTION:
|
130
|
+
if (typeof value === "object" && value !== null) {
|
131
|
+
states.set(stateId, textEncoder.encode(JSON.stringify(value)));
|
132
|
+
}
|
133
|
+
break;
|
134
|
+
case STATE_COLORS:
|
135
|
+
if (Array.isArray(value)) {
|
136
|
+
states.set(stateId, _DeltaNetComponentMapping.encodeColors(value));
|
137
|
+
}
|
138
|
+
break;
|
139
|
+
}
|
140
|
+
return states;
|
141
|
+
}
|
142
|
+
static encodeColors(colors) {
|
143
|
+
const bufferWriter = new BufferWriter(3 * colors.length + 1);
|
144
|
+
bufferWriter.writeUVarint(colors.length);
|
145
|
+
for (const color of colors) {
|
146
|
+
bufferWriter.writeUVarint(color[0]);
|
147
|
+
bufferWriter.writeUVarint(color[1]);
|
148
|
+
bufferWriter.writeUVarint(color[2]);
|
149
|
+
}
|
150
|
+
return bufferWriter.getBuffer();
|
151
|
+
}
|
152
|
+
static decodeColors(colors) {
|
153
|
+
if (colors.byteLength === 0) {
|
154
|
+
return [];
|
155
|
+
}
|
156
|
+
try {
|
157
|
+
const bufferReader = new BufferReader(colors);
|
158
|
+
const colorsArray = [];
|
159
|
+
const count = bufferReader.readUVarint();
|
160
|
+
for (let i = 0; i < count; i++) {
|
161
|
+
colorsArray.push([
|
162
|
+
bufferReader.readUVarint(),
|
163
|
+
bufferReader.readUVarint(),
|
164
|
+
bufferReader.readUVarint()
|
165
|
+
]);
|
166
|
+
}
|
167
|
+
return colorsArray;
|
168
|
+
} catch (e) {
|
169
|
+
console.error("Error decoding colors", colors, e);
|
170
|
+
return [];
|
171
|
+
}
|
172
|
+
}
|
173
|
+
static fromUserStates(states) {
|
174
|
+
const usernameBytes = states.get(STATE_USERNAME);
|
175
|
+
const username = usernameBytes ? _DeltaNetComponentMapping.usernameFromBytes(usernameBytes) : null;
|
176
|
+
const characterDescBytes = states.get(STATE_CHARACTER_DESCRIPTION);
|
177
|
+
const characterDescription = characterDescBytes ? _DeltaNetComponentMapping.characterDescriptionFromBytes(characterDescBytes) : null;
|
178
|
+
const colorsBytes = states.get(STATE_COLORS);
|
179
|
+
const colorsArray = colorsBytes ? _DeltaNetComponentMapping.decodeColors(colorsBytes) : [];
|
180
|
+
return { username, characterDescription, colors: colorsArray };
|
181
|
+
}
|
182
|
+
static userIdFromBytes(bytes) {
|
183
|
+
if (bytes.length === 0) {
|
184
|
+
return null;
|
185
|
+
}
|
186
|
+
const reader = new BufferReader(bytes);
|
187
|
+
return reader.readUVarint(false);
|
188
|
+
}
|
189
|
+
static usernameFromBytes(bytes) {
|
190
|
+
if (bytes.length === 0) {
|
191
|
+
return null;
|
192
|
+
}
|
193
|
+
return textDecoder.decode(bytes);
|
194
|
+
}
|
195
|
+
static characterDescriptionFromBytes(bytes) {
|
196
|
+
if (bytes.length === 0) {
|
197
|
+
return null;
|
198
|
+
}
|
199
|
+
return JSON.parse(textDecoder.decode(bytes));
|
200
|
+
}
|
201
|
+
/**
|
202
|
+
* Decode binary states back to username and character description
|
203
|
+
*/
|
204
|
+
static fromStates(states) {
|
205
|
+
const userIdBytes = states.get(STATE_INTERNAL_CONNECTION_ID);
|
206
|
+
let userId = null;
|
207
|
+
if (userIdBytes) {
|
208
|
+
const reader = new BufferReader(userIdBytes);
|
209
|
+
userId = reader.readUVarint(false);
|
210
|
+
}
|
211
|
+
const userStates = _DeltaNetComponentMapping.fromUserStates(states);
|
212
|
+
return { userId, ...userStates };
|
213
|
+
}
|
214
|
+
};
|
215
|
+
|
216
|
+
// src/UserNetworkingMessages.ts
|
217
|
+
import { DeltaNetServerError } from "/Users/marcuslongmuir/mml/3d-web-experience/packages/deltanet/delta-net-server/build/index.js";
|
218
|
+
var UserNetworkingServerError = class extends DeltaNetServerError {
|
219
|
+
};
|
220
|
+
var SERVER_BROADCAST_MESSAGE_TYPE = 1;
|
221
|
+
var FROM_CLIENT_CHAT_MESSAGE_TYPE = 2;
|
222
|
+
var FROM_SERVER_CHAT_MESSAGE_TYPE = 3;
|
223
|
+
function parseClientChatMessage(contents) {
|
224
|
+
try {
|
225
|
+
const parsed = JSON.parse(contents);
|
226
|
+
if (typeof parsed === "object" && parsed !== null && "message" in parsed && typeof parsed.message === "string") {
|
227
|
+
return {
|
228
|
+
message: parsed.message
|
229
|
+
};
|
230
|
+
} else {
|
231
|
+
throw new Error("Invalid chat message");
|
232
|
+
}
|
233
|
+
} catch (error) {
|
234
|
+
return new Error(`Invalid chat message: ${error}`);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
function parseServerChatMessage(contents) {
|
238
|
+
try {
|
239
|
+
const parsed = JSON.parse(contents);
|
240
|
+
if (typeof parsed === "object" && parsed !== null && "fromUserId" in parsed && typeof parsed.fromUserId === "number" && "message" in parsed && typeof parsed.message === "string") {
|
241
|
+
return {
|
242
|
+
fromUserId: parsed.fromUserId,
|
243
|
+
message: parsed.message
|
244
|
+
};
|
245
|
+
} else {
|
246
|
+
throw new Error("Invalid server chat message");
|
247
|
+
}
|
248
|
+
} catch (error) {
|
249
|
+
return new Error(`Invalid server chat message: ${error}`);
|
250
|
+
}
|
251
|
+
}
|
252
|
+
function parseServerBroadcastMessage(contents) {
|
253
|
+
try {
|
254
|
+
const parsed = JSON.parse(contents);
|
255
|
+
if (typeof parsed === "object" && parsed !== null && "broadcastType" in parsed && typeof parsed.broadcastType === "string" && "payload" in parsed && typeof parsed.payload === "object") {
|
256
|
+
return {
|
257
|
+
broadcastType: parsed.broadcastType,
|
258
|
+
payload: parsed.payload
|
259
|
+
};
|
260
|
+
} else {
|
261
|
+
throw new Error("Invalid server broadcast message");
|
262
|
+
}
|
263
|
+
} catch (error) {
|
264
|
+
return new Error(`Invalid server broadcast message: ${error}`);
|
265
|
+
}
|
266
|
+
}
|
267
|
+
|
268
|
+
// src/legacy/LegacyUserNetworkingCodec.ts
|
269
|
+
var LegacyUserNetworkingCodec = class {
|
3
270
|
static encodeUpdate(update) {
|
4
271
|
const buffer = new ArrayBuffer(19);
|
5
272
|
const dataView = new DataView(buffer);
|
@@ -27,77 +294,62 @@ var UserNetworkingCodec = class {
|
|
27
294
|
}
|
28
295
|
};
|
29
296
|
|
30
|
-
// src/
|
31
|
-
var
|
32
|
-
var
|
33
|
-
var
|
34
|
-
|
35
|
-
|
36
|
-
var
|
37
|
-
var
|
38
|
-
var
|
39
|
-
var
|
40
|
-
var
|
41
|
-
var
|
42
|
-
var
|
43
|
-
var
|
44
|
-
var USER_NETWORKING_PONG_MESSAGE_TYPE = "pong";
|
45
|
-
var USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE = "CONNECTION_LIMIT_REACHED";
|
46
|
-
var USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE = "AUTHENTICATION_FAILED";
|
47
|
-
var USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE = "SERVER_SHUTDOWN";
|
48
|
-
var USER_NETWORKING_UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
297
|
+
// src/legacy/LegacyUserNetworkingMessages.ts
|
298
|
+
var LEGACY_USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE = "disconnected";
|
299
|
+
var LEGACY_USER_NETWORKING_IDENTITY_MESSAGE_TYPE = "identity";
|
300
|
+
var LEGACY_USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE = "user_auth";
|
301
|
+
var LEGACY_USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE = "user_profile";
|
302
|
+
var LEGACY_USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE = "user_update";
|
303
|
+
var LEGACY_USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE = "broadcast";
|
304
|
+
var LEGACY_USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE = "error";
|
305
|
+
var LEGACY_USER_NETWORKING_PING_MESSAGE_TYPE = "ping";
|
306
|
+
var LEGACY_USER_NETWORKING_PONG_MESSAGE_TYPE = "pong";
|
307
|
+
var LEGACY_USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE = "CONNECTION_LIMIT_REACHED";
|
308
|
+
var LEGACY_USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE = "AUTHENTICATION_FAILED";
|
309
|
+
var LEGACY_USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE = "SERVER_SHUTDOWN";
|
310
|
+
var LEGACY_USER_NETWORKING_UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
49
311
|
|
50
|
-
// src/
|
312
|
+
// src/legacy/LegacyAdapter.ts
|
313
|
+
function toArrayBuffer(buffer) {
|
314
|
+
const arrayBuffer = new ArrayBuffer(buffer.length);
|
315
|
+
const view = new Uint8Array(arrayBuffer);
|
316
|
+
for (let i = 0; i < buffer.length; ++i) {
|
317
|
+
view[i] = buffer[i];
|
318
|
+
}
|
319
|
+
return arrayBuffer;
|
320
|
+
}
|
51
321
|
var WebSocketOpenStatus = 1;
|
52
|
-
var
|
53
|
-
constructor(
|
54
|
-
this.
|
322
|
+
var LegacyAdapter = class {
|
323
|
+
constructor(userNetworkingServer, deltaNetServer) {
|
324
|
+
this.userNetworkingServer = userNetworkingServer;
|
325
|
+
this.deltaNetServer = deltaNetServer;
|
55
326
|
this.allClientsById = /* @__PURE__ */ new Map();
|
56
|
-
this.
|
57
|
-
this.sendUpdatesIntervalTimer = setInterval(this.sendUpdates.bind(this), packetsUpdateRate);
|
58
|
-
this.pingClientsIntervalTimer = setInterval(this.pingClients.bind(this), pingPongRate);
|
59
|
-
this.heartbeatIntervalTimer = setInterval(this.heartBeat.bind(this), heartBeatRate);
|
60
|
-
}
|
61
|
-
heartBeat() {
|
62
|
-
const now = Date.now();
|
63
|
-
this.allClientsById.forEach((client) => {
|
64
|
-
if (now - client.lastPong > heartBeatRate) {
|
65
|
-
client.socket.close();
|
66
|
-
this.handleDisconnectedClient(client);
|
67
|
-
}
|
68
|
-
});
|
69
|
-
}
|
70
|
-
pingClients() {
|
71
|
-
const message = { type: "ping" };
|
72
|
-
const messageString = JSON.stringify(message);
|
73
|
-
this.authenticatedClientsById.forEach((client) => {
|
74
|
-
if (client.socket.readyState === WebSocketOpenStatus) {
|
75
|
-
client.socket.send(messageString);
|
76
|
-
}
|
77
|
-
});
|
78
|
-
}
|
79
|
-
getId() {
|
80
|
-
let id = 1;
|
81
|
-
while (this.allClientsById.has(id)) {
|
82
|
-
id++;
|
83
|
-
}
|
84
|
-
return id;
|
327
|
+
this.legacyAuthenticatedClientsById = /* @__PURE__ */ new Map();
|
85
328
|
}
|
86
329
|
broadcastMessage(broadcastType, broadcastPayload) {
|
330
|
+
if (broadcastType !== SERVER_BROADCAST_MESSAGE_TYPE) {
|
331
|
+
return;
|
332
|
+
}
|
333
|
+
const parsedPayload = parseServerBroadcastMessage(broadcastPayload);
|
334
|
+
if (parsedPayload instanceof Error) {
|
335
|
+
console.error("Error parsing server broadcast message", parsedPayload);
|
336
|
+
return;
|
337
|
+
}
|
338
|
+
const { broadcastType: broadcastTypeString, payload } = parsedPayload;
|
87
339
|
const message = {
|
88
340
|
type: "broadcast",
|
89
|
-
broadcastType,
|
90
|
-
payload
|
341
|
+
broadcastType: broadcastTypeString,
|
342
|
+
payload
|
91
343
|
};
|
92
344
|
const messageString = JSON.stringify(message);
|
93
|
-
for (const [, client] of this.
|
345
|
+
for (const [, client] of this.legacyAuthenticatedClientsById) {
|
94
346
|
if (client.socket.readyState === WebSocketOpenStatus) {
|
95
347
|
client.socket.send(messageString);
|
96
348
|
}
|
97
349
|
}
|
98
350
|
}
|
99
|
-
|
100
|
-
const id = this.
|
351
|
+
addWebSocket(socket) {
|
352
|
+
const id = this.userNetworkingServer.getLegacyClientId();
|
101
353
|
console.log(`Client ID: ${id} joined, waiting for user-identification`);
|
102
354
|
const client = {
|
103
355
|
id,
|
@@ -112,99 +364,185 @@ var UserNetworkingServer = class {
|
|
112
364
|
}
|
113
365
|
};
|
114
366
|
this.allClientsById.set(id, client);
|
115
|
-
socket.
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
367
|
+
socket.addEventListener("message", (message) => {
|
368
|
+
try {
|
369
|
+
if (message.data instanceof ArrayBuffer || message.data instanceof Buffer) {
|
370
|
+
if (client.authenticatedUser) {
|
371
|
+
const arrayBuffer = message.data instanceof ArrayBuffer ? message.data : toArrayBuffer(message.data);
|
372
|
+
const update = LegacyUserNetworkingCodec.decodeUpdate(arrayBuffer);
|
373
|
+
update.id = id;
|
374
|
+
const index = this.deltaNetServer.dangerouslyGetConnectionsToComponentIndex().get(id);
|
375
|
+
client.update = update;
|
376
|
+
if (index !== void 0) {
|
377
|
+
this.deltaNetServer.setComponentValue(
|
378
|
+
COMPONENT_POSITION_X,
|
379
|
+
index,
|
380
|
+
BigInt(Math.round(update.position.x * positionMultiplier))
|
381
|
+
);
|
382
|
+
this.deltaNetServer.setComponentValue(
|
383
|
+
COMPONENT_POSITION_Y,
|
384
|
+
index,
|
385
|
+
BigInt(Math.round(update.position.y * positionMultiplier))
|
386
|
+
);
|
387
|
+
this.deltaNetServer.setComponentValue(
|
388
|
+
COMPONENT_POSITION_Z,
|
389
|
+
index,
|
390
|
+
BigInt(Math.round(update.position.z * positionMultiplier))
|
391
|
+
);
|
392
|
+
this.deltaNetServer.setComponentValue(
|
393
|
+
COMPONENT_ROTATION_Y,
|
394
|
+
index,
|
395
|
+
BigInt(Math.round(update.rotation.quaternionY * rotationMultiplier))
|
396
|
+
);
|
397
|
+
this.deltaNetServer.setComponentValue(
|
398
|
+
COMPONENT_ROTATION_W,
|
399
|
+
index,
|
400
|
+
BigInt(Math.round(update.rotation.quaternionW * rotationMultiplier))
|
401
|
+
);
|
402
|
+
this.deltaNetServer.setComponentValue(
|
403
|
+
COMPONENT_STATE,
|
404
|
+
index,
|
405
|
+
BigInt(Math.round(update.state))
|
406
|
+
);
|
407
|
+
}
|
408
|
+
}
|
409
|
+
} else {
|
410
|
+
let parsed;
|
411
|
+
try {
|
412
|
+
parsed = JSON.parse(message.data);
|
413
|
+
} catch (e) {
|
414
|
+
console.error("Error parsing JSON message", message, e);
|
415
|
+
return;
|
416
|
+
}
|
417
|
+
if (!client.authenticatedUser) {
|
418
|
+
if (parsed.type === LEGACY_USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE) {
|
419
|
+
this.handleUserAuth(client, parsed).then((authResult) => {
|
420
|
+
if (client.socket.readyState !== WebSocketOpenStatus) {
|
421
|
+
return;
|
422
|
+
}
|
423
|
+
if (!authResult) {
|
424
|
+
console.error(`Client-id ${client.id} user_auth failed`, authResult);
|
146
425
|
const serverError = JSON.stringify({
|
147
|
-
type:
|
148
|
-
errorType:
|
149
|
-
message: "
|
426
|
+
type: LEGACY_USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,
|
427
|
+
errorType: LEGACY_USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE,
|
428
|
+
message: "Authentication failed"
|
150
429
|
});
|
151
430
|
socket.send(serverError);
|
152
431
|
socket.close();
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
client.socket.send(userProfileMessage);
|
164
|
-
const identityMessage = JSON.stringify({
|
165
|
-
id: client.id,
|
166
|
-
type: USER_NETWORKING_IDENTITY_MESSAGE_TYPE
|
167
|
-
});
|
168
|
-
client.socket.send(identityMessage);
|
169
|
-
const userUpdateMessage = UserNetworkingCodec.encodeUpdate(client.update);
|
170
|
-
for (const [, otherClient] of this.authenticatedClientsById) {
|
171
|
-
if (otherClient.socket.readyState !== WebSocketOpenStatus || otherClient === client) {
|
172
|
-
continue;
|
432
|
+
} else {
|
433
|
+
if (!this.userNetworkingServer.hasCapacityForLegacyClient()) {
|
434
|
+
const serverError = JSON.stringify({
|
435
|
+
type: LEGACY_USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,
|
436
|
+
errorType: LEGACY_USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE,
|
437
|
+
message: "Connection limit reached"
|
438
|
+
});
|
439
|
+
socket.send(serverError);
|
440
|
+
socket.close();
|
441
|
+
return;
|
173
442
|
}
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
443
|
+
const userData = authResult;
|
444
|
+
this.deltaNetServer.dangerouslyAddNewJoinerCallback((index) => {
|
445
|
+
if (client.socket.readyState !== WebSocketOpenStatus) {
|
446
|
+
return null;
|
447
|
+
}
|
448
|
+
client.authenticatedUser = userData;
|
449
|
+
this.deltaNetServer.setComponentValue(COMPONENT_POSITION_X, index, BigInt(0));
|
450
|
+
this.deltaNetServer.setComponentValue(COMPONENT_POSITION_Y, index, BigInt(0));
|
451
|
+
this.deltaNetServer.setComponentValue(COMPONENT_POSITION_Z, index, BigInt(0));
|
452
|
+
this.deltaNetServer.setComponentValue(COMPONENT_ROTATION_Y, index, BigInt(0));
|
453
|
+
this.deltaNetServer.setComponentValue(COMPONENT_ROTATION_W, index, BigInt(0));
|
454
|
+
this.deltaNetServer.setComponentValue(COMPONENT_STATE, index, BigInt(0));
|
455
|
+
const asUserData = {
|
456
|
+
...userData,
|
457
|
+
colors: []
|
458
|
+
};
|
459
|
+
return {
|
460
|
+
id: client.id,
|
461
|
+
afterAddCallback: () => {
|
462
|
+
this.userNetworkingServer.setAuthenticatedLegacyClientConnection(
|
463
|
+
client.id,
|
464
|
+
client.socket,
|
465
|
+
asUserData
|
466
|
+
);
|
467
|
+
this.userNetworkingServer.updateUserCharacter(client.id, asUserData);
|
468
|
+
}
|
469
|
+
};
|
470
|
+
});
|
471
|
+
const userProfileMessage = JSON.stringify({
|
472
|
+
id: client.id,
|
473
|
+
type: LEGACY_USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
474
|
+
username: userData.username,
|
475
|
+
characterDescription: userData.characterDescription
|
476
|
+
});
|
477
|
+
client.socket.send(userProfileMessage);
|
478
|
+
const identityMessage = JSON.stringify({
|
479
|
+
id: client.id,
|
480
|
+
type: LEGACY_USER_NETWORKING_IDENTITY_MESSAGE_TYPE
|
481
|
+
});
|
482
|
+
client.socket.send(identityMessage);
|
483
|
+
const allUsers = this.deltaNetServer.dangerouslyGetConnectionsToComponentIndex();
|
484
|
+
for (const [connectionId, componentIndex] of allUsers) {
|
485
|
+
if (connectionId === client.id) {
|
486
|
+
continue;
|
487
|
+
}
|
488
|
+
const x = this.deltaNetServer.getComponentValue(COMPONENT_POSITION_X, componentIndex) / positionMultiplier;
|
489
|
+
const y = this.deltaNetServer.getComponentValue(COMPONENT_POSITION_Y, componentIndex) / positionMultiplier;
|
490
|
+
const z = this.deltaNetServer.getComponentValue(COMPONENT_POSITION_Z, componentIndex) / positionMultiplier;
|
491
|
+
const quaternionY = this.deltaNetServer.getComponentValue(COMPONENT_ROTATION_Y, componentIndex) / rotationMultiplier;
|
492
|
+
const quaternionW = this.deltaNetServer.getComponentValue(COMPONENT_ROTATION_W, componentIndex) / rotationMultiplier;
|
493
|
+
const state = this.deltaNetServer.getComponentValue(
|
494
|
+
COMPONENT_STATE,
|
495
|
+
componentIndex
|
496
|
+
);
|
497
|
+
const update = LegacyUserNetworkingCodec.encodeUpdate({
|
498
|
+
id: connectionId,
|
499
|
+
position: { x, y, z },
|
500
|
+
rotation: { quaternionY, quaternionW },
|
501
|
+
state
|
502
|
+
});
|
503
|
+
client.socket.send(
|
504
|
+
JSON.stringify({
|
505
|
+
id: connectionId,
|
506
|
+
type: LEGACY_USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
507
|
+
username: this.userNetworkingServer.getUsername(connectionId),
|
508
|
+
characterDescription: this.userNetworkingServer.getCharacterDescription(connectionId)
|
509
|
+
})
|
510
|
+
);
|
511
|
+
client.socket.send(update);
|
512
|
+
}
|
513
|
+
this.legacyAuthenticatedClientsById.set(id, client);
|
185
514
|
}
|
186
|
-
|
187
|
-
|
188
|
-
|
515
|
+
});
|
516
|
+
} else {
|
517
|
+
console.error(`Unhandled message pre-auth: ${JSON.stringify(parsed)}`);
|
518
|
+
socket.close();
|
519
|
+
}
|
189
520
|
} else {
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
break;
|
201
|
-
default:
|
202
|
-
console.error(`Unhandled message: ${JSON.stringify(parsed)}`);
|
521
|
+
switch (parsed.type) {
|
522
|
+
case LEGACY_USER_NETWORKING_PONG_MESSAGE_TYPE:
|
523
|
+
client.lastPong = Date.now();
|
524
|
+
break;
|
525
|
+
case LEGACY_USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE:
|
526
|
+
this.handleUserUpdate(id, parsed);
|
527
|
+
break;
|
528
|
+
default:
|
529
|
+
console.error(`Unhandled message: ${JSON.stringify(parsed)}`);
|
530
|
+
}
|
203
531
|
}
|
204
532
|
}
|
533
|
+
} catch (e) {
|
534
|
+
console.error("Error handling message", message, e);
|
535
|
+
socket.send(
|
536
|
+
JSON.stringify({
|
537
|
+
type: LEGACY_USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,
|
538
|
+
errorType: LEGACY_USER_NETWORKING_UNKNOWN_ERROR,
|
539
|
+
message: "Error handling message"
|
540
|
+
})
|
541
|
+
);
|
542
|
+
socket.close();
|
205
543
|
}
|
206
544
|
});
|
207
|
-
socket.
|
545
|
+
socket.addEventListener("close", () => {
|
208
546
|
console.log("Client disconnected", id);
|
209
547
|
this.handleDisconnectedClient(client);
|
210
548
|
});
|
@@ -215,21 +553,13 @@ var UserNetworkingServer = class {
|
|
215
553
|
}
|
216
554
|
this.allClientsById.delete(client.id);
|
217
555
|
if (client.authenticatedUser !== null) {
|
218
|
-
this.
|
219
|
-
this.
|
220
|
-
|
221
|
-
id: client.id,
|
222
|
-
type: USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE
|
223
|
-
});
|
224
|
-
for (const [, otherClient] of this.authenticatedClientsById) {
|
225
|
-
if (otherClient.socket.readyState === WebSocketOpenStatus) {
|
226
|
-
otherClient.socket.send(disconnectMessage);
|
227
|
-
}
|
228
|
-
}
|
556
|
+
this.userNetworkingServer.onLegacyClientDisconnect(client.id);
|
557
|
+
this.legacyAuthenticatedClientsById.delete(client.id);
|
558
|
+
this.deltaNetServer.clearInternalConnectionId(client.id);
|
229
559
|
}
|
230
560
|
}
|
231
561
|
async handleUserAuth(client, credentials) {
|
232
|
-
const userData = this.
|
562
|
+
const userData = this.userNetworkingServer.onLegacyClientConnect(
|
233
563
|
client.id,
|
234
564
|
credentials.sessionToken,
|
235
565
|
credentials.userIdentity
|
@@ -240,6 +570,15 @@ var UserNetworkingServer = class {
|
|
240
570
|
} else {
|
241
571
|
resolvedUserData = userData;
|
242
572
|
}
|
573
|
+
if (resolvedUserData instanceof Error) {
|
574
|
+
console.error(`Client-id ${client.id} user_auth failed`, resolvedUserData);
|
575
|
+
return false;
|
576
|
+
} else if (resolvedUserData === true) {
|
577
|
+
console.error(`Client-id ${client.id} user_auth failed`, resolvedUserData);
|
578
|
+
resolvedUserData = credentials.userIdentity;
|
579
|
+
} else {
|
580
|
+
resolvedUserData = resolvedUserData;
|
581
|
+
}
|
243
582
|
if (resolvedUserData === null) {
|
244
583
|
console.error(`Client-id ${client.id} user_auth unauthorized and ignored`);
|
245
584
|
return false;
|
@@ -251,31 +590,18 @@ var UserNetworkingServer = class {
|
|
251
590
|
this.internalUpdateUser(clientId, userData);
|
252
591
|
}
|
253
592
|
internalUpdateUser(clientId, userData) {
|
254
|
-
const client = this.
|
593
|
+
const client = this.legacyAuthenticatedClientsById.get(clientId);
|
255
594
|
client.authenticatedUser = userData;
|
256
|
-
this.
|
257
|
-
|
258
|
-
id: clientId,
|
259
|
-
type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
260
|
-
username: userData.username,
|
261
|
-
characterDescription: userData.characterDescription
|
262
|
-
});
|
263
|
-
for (const [otherClientId, otherClient] of this.authenticatedClientsById) {
|
264
|
-
if (otherClient.socket.readyState === WebSocketOpenStatus) {
|
265
|
-
otherClient.socket.send(newUserData);
|
266
|
-
}
|
267
|
-
}
|
595
|
+
this.legacyAuthenticatedClientsById.set(clientId, client);
|
596
|
+
this.userNetworkingServer.updateUserCharacter(client.id, { ...userData, colors: [] });
|
268
597
|
}
|
269
598
|
async handleUserUpdate(clientId, message) {
|
270
|
-
const client = this.
|
599
|
+
const client = this.legacyAuthenticatedClientsById.get(clientId);
|
271
600
|
if (!client) {
|
272
601
|
console.error(`Client-id ${clientId} user_update ignored, client not found`);
|
273
602
|
return;
|
274
603
|
}
|
275
|
-
const authorizedUserData =
|
276
|
-
clientId,
|
277
|
-
message.userIdentity
|
278
|
-
);
|
604
|
+
const authorizedUserData = message.userIdentity;
|
279
605
|
let resolvedAuthorizedUserData;
|
280
606
|
if (authorizedUserData instanceof Promise) {
|
281
607
|
resolvedAuthorizedUserData = await authorizedUserData;
|
@@ -288,23 +614,76 @@ var UserNetworkingServer = class {
|
|
288
614
|
}
|
289
615
|
this.internalUpdateUser(clientId, resolvedAuthorizedUserData);
|
290
616
|
}
|
291
|
-
sendUpdates() {
|
292
|
-
for (const
|
293
|
-
const
|
294
|
-
|
295
|
-
|
617
|
+
sendUpdates(removedIds, addedIds, updateUserProfilesInTick) {
|
618
|
+
for (const id of removedIds) {
|
619
|
+
const disconnectMessage = JSON.stringify({
|
620
|
+
id,
|
621
|
+
type: LEGACY_USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE
|
622
|
+
});
|
623
|
+
for (const [, otherClient] of this.legacyAuthenticatedClientsById) {
|
624
|
+
if (otherClient.socket.readyState === WebSocketOpenStatus) {
|
625
|
+
otherClient.socket.send(disconnectMessage);
|
626
|
+
}
|
627
|
+
}
|
628
|
+
}
|
629
|
+
for (const id of addedIds) {
|
630
|
+
const identityMessage = JSON.stringify({
|
631
|
+
id,
|
632
|
+
type: LEGACY_USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
633
|
+
username: this.userNetworkingServer.getUsername(id),
|
634
|
+
characterDescription: this.userNetworkingServer.getCharacterDescription(id)
|
635
|
+
});
|
636
|
+
for (const [, otherClient] of this.legacyAuthenticatedClientsById) {
|
637
|
+
if (otherClient.socket.readyState === WebSocketOpenStatus) {
|
638
|
+
otherClient.socket.send(identityMessage);
|
639
|
+
}
|
640
|
+
}
|
641
|
+
}
|
642
|
+
for (const id of updateUserProfilesInTick) {
|
643
|
+
const identityMessage = JSON.stringify({
|
644
|
+
id,
|
645
|
+
type: LEGACY_USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
646
|
+
username: this.userNetworkingServer.getUsername(id),
|
647
|
+
characterDescription: this.userNetworkingServer.getCharacterDescription(id)
|
648
|
+
});
|
649
|
+
for (const [, otherClient] of this.legacyAuthenticatedClientsById) {
|
650
|
+
if (otherClient.socket.readyState === WebSocketOpenStatus) {
|
651
|
+
otherClient.socket.send(identityMessage);
|
652
|
+
}
|
653
|
+
}
|
654
|
+
}
|
655
|
+
for (const [clientId, client] of this.legacyAuthenticatedClientsById) {
|
656
|
+
const encodedUpdate = LegacyUserNetworkingCodec.encodeUpdate(client.update);
|
657
|
+
for (const [otherClientId, otherClient] of this.legacyAuthenticatedClientsById) {
|
296
658
|
if (otherClientId !== clientId && otherClient.socket.readyState === WebSocketOpenStatus) {
|
297
659
|
otherClient.socket.send(encodedUpdate);
|
298
660
|
}
|
299
661
|
}
|
300
662
|
}
|
663
|
+
const allUsers = this.deltaNetServer.dangerouslyGetConnectionsToComponentIndex();
|
664
|
+
for (const [connectionId, componentIndex] of allUsers) {
|
665
|
+
const x = this.deltaNetServer.getComponentValue(COMPONENT_POSITION_X, componentIndex) / positionMultiplier;
|
666
|
+
const y = this.deltaNetServer.getComponentValue(COMPONENT_POSITION_Y, componentIndex) / positionMultiplier;
|
667
|
+
const z = this.deltaNetServer.getComponentValue(COMPONENT_POSITION_Z, componentIndex) / positionMultiplier;
|
668
|
+
const quaternionY = this.deltaNetServer.getComponentValue(COMPONENT_ROTATION_Y, componentIndex) / rotationMultiplier;
|
669
|
+
const quaternionW = this.deltaNetServer.getComponentValue(COMPONENT_ROTATION_W, componentIndex) / rotationMultiplier;
|
670
|
+
const state = this.deltaNetServer.getComponentValue(COMPONENT_STATE, componentIndex);
|
671
|
+
const encodedUpdate = LegacyUserNetworkingCodec.encodeUpdate({
|
672
|
+
id: connectionId,
|
673
|
+
position: { x, y, z },
|
674
|
+
rotation: { quaternionY, quaternionW },
|
675
|
+
state
|
676
|
+
});
|
677
|
+
for (const [otherClientId, otherClient] of this.legacyAuthenticatedClientsById) {
|
678
|
+
if (otherClientId !== connectionId && otherClient.socket.readyState === WebSocketOpenStatus) {
|
679
|
+
otherClient.socket.send(encodedUpdate);
|
680
|
+
}
|
681
|
+
}
|
682
|
+
}
|
301
683
|
}
|
302
684
|
dispose(clientCloseError) {
|
303
|
-
clearInterval(this.sendUpdatesIntervalTimer);
|
304
|
-
clearInterval(this.pingClientsIntervalTimer);
|
305
|
-
clearInterval(this.heartbeatIntervalTimer);
|
306
685
|
const stringifiedError = clientCloseError ? JSON.stringify(clientCloseError) : void 0;
|
307
|
-
for (const [, client] of this.
|
686
|
+
for (const [, client] of this.legacyAuthenticatedClientsById) {
|
308
687
|
if (stringifiedError) {
|
309
688
|
client.socket.send(stringifiedError);
|
310
689
|
}
|
@@ -313,239 +692,795 @@ var UserNetworkingServer = class {
|
|
313
692
|
}
|
314
693
|
};
|
315
694
|
|
316
|
-
// src/
|
317
|
-
var
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
if (this.
|
342
|
-
this.
|
343
|
-
this.statusUpdateCallback(status);
|
695
|
+
// src/UserNetworkingServer.ts
|
696
|
+
var UserNetworkingServer = class {
|
697
|
+
constructor(options) {
|
698
|
+
this.options = options;
|
699
|
+
this.authenticatedClientsById = /* @__PURE__ */ new Map();
|
700
|
+
this.legacyAdapter = null;
|
701
|
+
this.updatedUserProfilesInTick = /* @__PURE__ */ new Set();
|
702
|
+
this.deltaNetServer = new DeltaNetServer({
|
703
|
+
serverConnectionIdStateId: 0,
|
704
|
+
onJoiner: (joiner) => {
|
705
|
+
return this.handleJoiner(joiner);
|
706
|
+
},
|
707
|
+
onLeave: (leave) => {
|
708
|
+
this.handleLeave(leave);
|
709
|
+
},
|
710
|
+
onComponentsUpdate: (update) => {
|
711
|
+
return;
|
712
|
+
},
|
713
|
+
onStatesUpdate: (update) => {
|
714
|
+
return this.handleStatesUpdate(update);
|
715
|
+
},
|
716
|
+
onCustomMessage: (customMessage) => {
|
717
|
+
this.handleCustomMessage(customMessage);
|
718
|
+
}
|
719
|
+
});
|
720
|
+
if (this.options.legacyAdapterEnabled) {
|
721
|
+
this.legacyAdapter = new LegacyAdapter(this, this.deltaNetServer);
|
344
722
|
}
|
723
|
+
this.tickInterval = setInterval(() => {
|
724
|
+
const { removedIds, addedIds } = this.deltaNetServer.tick();
|
725
|
+
if (this.legacyAdapter) {
|
726
|
+
this.legacyAdapter.sendUpdates(removedIds, addedIds, this.updatedUserProfilesInTick);
|
727
|
+
this.updatedUserProfilesInTick.clear();
|
728
|
+
}
|
729
|
+
}, 50);
|
345
730
|
}
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
731
|
+
getCharacterDescription(connectionId) {
|
732
|
+
var _a, _b;
|
733
|
+
const client = this.authenticatedClientsById.get(connectionId);
|
734
|
+
console.log(
|
735
|
+
"getCharacterDescription",
|
736
|
+
connectionId,
|
737
|
+
(_a = client == null ? void 0 : client.authenticatedUser) == null ? void 0 : _a.characterDescription
|
738
|
+
);
|
739
|
+
return ((_b = client == null ? void 0 : client.authenticatedUser) == null ? void 0 : _b.characterDescription) ?? { mmlCharacterUrl: "" };
|
353
740
|
}
|
354
|
-
|
355
|
-
|
356
|
-
|
741
|
+
getUsername(connectionId) {
|
742
|
+
var _a, _b;
|
743
|
+
const client = this.authenticatedClientsById.get(connectionId);
|
744
|
+
console.log("getUsername", connectionId, (_a = client == null ? void 0 : client.authenticatedUser) == null ? void 0 : _a.username);
|
745
|
+
return ((_b = client == null ? void 0 : client.authenticatedUser) == null ? void 0 : _b.username) ?? "";
|
746
|
+
}
|
747
|
+
getLegacyClientId() {
|
748
|
+
return this.deltaNetServer.getNextConnectionId();
|
749
|
+
}
|
750
|
+
hasCapacityForLegacyClient() {
|
751
|
+
return true;
|
752
|
+
}
|
753
|
+
onLegacyClientConnect(id, sessionToken, userIdentity) {
|
754
|
+
return this.options.onClientConnect(id, sessionToken, {
|
755
|
+
username: (userIdentity == null ? void 0 : userIdentity.username) ?? null,
|
756
|
+
characterDescription: (userIdentity == null ? void 0 : userIdentity.characterDescription) ?? null,
|
757
|
+
colors: null
|
758
|
+
});
|
759
|
+
}
|
760
|
+
setAuthenticatedLegacyClientConnection(clientId, webSocket, userData) {
|
761
|
+
console.log("setAuthenticatedLegacyClientConnection", clientId, userData);
|
762
|
+
const authenticatedClient = {
|
763
|
+
id: clientId,
|
764
|
+
socket: webSocket,
|
765
|
+
lastPong: Date.now(),
|
766
|
+
authenticatedUser: userData,
|
767
|
+
deltaNetConnection: null
|
768
|
+
};
|
769
|
+
this.authenticatedClientsById.set(clientId, authenticatedClient);
|
770
|
+
}
|
771
|
+
onLegacyClientDisconnect(id) {
|
772
|
+
this.options.onClientDisconnect(id);
|
773
|
+
}
|
774
|
+
handleStatesUpdate(update) {
|
775
|
+
const deltaNetConnection = update.deltaNetV01Connection;
|
776
|
+
const clientId = deltaNetConnection.internalConnectionId;
|
777
|
+
const updatedStates = update.states;
|
778
|
+
const updatedStatesMap = new Map(updatedStates);
|
779
|
+
const updatedUserData = DeltaNetComponentMapping.fromUserStates(updatedStatesMap);
|
780
|
+
const existingClient = this.authenticatedClientsById.get(clientId);
|
781
|
+
if (!existingClient) {
|
782
|
+
return new DeltaNetServerError2(
|
783
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
784
|
+
"User not authenticated - no client found",
|
785
|
+
false
|
786
|
+
);
|
357
787
|
}
|
358
|
-
|
359
|
-
|
360
|
-
|
788
|
+
const existingUserData = existingClient.authenticatedUser ?? {};
|
789
|
+
const userData = {
|
790
|
+
...existingUserData,
|
791
|
+
...updatedUserData
|
792
|
+
};
|
793
|
+
const res = this.options.onClientUserIdentityUpdate(clientId, userData);
|
794
|
+
if (res instanceof Promise) {
|
795
|
+
return res.then((res2) => {
|
796
|
+
if (!this.authenticatedClientsById.get(clientId)) {
|
797
|
+
return new DeltaNetServerError2(
|
798
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
799
|
+
"User not authenticated - client disconnected",
|
800
|
+
false
|
801
|
+
);
|
802
|
+
}
|
803
|
+
if (res2 instanceof DeltaNetServerError2) {
|
804
|
+
return res2;
|
805
|
+
}
|
806
|
+
if (res2 instanceof Error) {
|
807
|
+
return new DeltaNetServerError2(
|
808
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
809
|
+
"User identity update failed",
|
810
|
+
false
|
811
|
+
);
|
812
|
+
}
|
813
|
+
if (res2 === null) {
|
814
|
+
return new DeltaNetServerError2(
|
815
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
816
|
+
"User identity update failed",
|
817
|
+
false
|
818
|
+
);
|
819
|
+
}
|
820
|
+
if (res2 === false) {
|
821
|
+
return new DeltaNetServerError2(
|
822
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
823
|
+
"User identity update failed",
|
824
|
+
false
|
825
|
+
);
|
826
|
+
}
|
827
|
+
if (!res2 || typeof res2 !== "object") {
|
828
|
+
return new DeltaNetServerError2(
|
829
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
830
|
+
"User identity update failed",
|
831
|
+
false
|
832
|
+
);
|
833
|
+
}
|
834
|
+
this.updatedUserProfilesInTick.add(clientId);
|
835
|
+
existingClient.authenticatedUser = {
|
836
|
+
...existingClient.authenticatedUser,
|
837
|
+
...res2
|
838
|
+
};
|
839
|
+
return {
|
840
|
+
success: true,
|
841
|
+
stateOverrides: Array.from(DeltaNetComponentMapping.toStates(res2).entries())
|
842
|
+
};
|
843
|
+
});
|
844
|
+
}
|
845
|
+
if (res instanceof DeltaNetServerError2) {
|
846
|
+
return res;
|
847
|
+
}
|
848
|
+
if (res instanceof Error) {
|
849
|
+
return new DeltaNetServerError2(
|
850
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
851
|
+
"User identity update failed",
|
852
|
+
false
|
853
|
+
);
|
854
|
+
}
|
855
|
+
if (res === null) {
|
856
|
+
return new DeltaNetServerError2(
|
857
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
858
|
+
"User identity update failed",
|
859
|
+
false
|
860
|
+
);
|
861
|
+
}
|
862
|
+
if (res === false) {
|
863
|
+
return new DeltaNetServerError2(
|
864
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
865
|
+
"User identity update failed",
|
866
|
+
false
|
867
|
+
);
|
868
|
+
}
|
869
|
+
if (!res || typeof res !== "object") {
|
870
|
+
return new DeltaNetServerError2(
|
871
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
872
|
+
"User identity update failed",
|
873
|
+
false
|
874
|
+
);
|
875
|
+
}
|
876
|
+
this.updatedUserProfilesInTick.add(clientId);
|
877
|
+
existingClient.authenticatedUser = {
|
878
|
+
...existingClient.authenticatedUser,
|
879
|
+
...res
|
880
|
+
};
|
881
|
+
return {
|
882
|
+
success: true,
|
883
|
+
stateOverrides: Array.from(DeltaNetComponentMapping.toStates(res).entries())
|
884
|
+
};
|
885
|
+
}
|
886
|
+
handleJoiner(joiner) {
|
887
|
+
const deltaNetConnection = joiner.deltaNetV01Connection;
|
888
|
+
const webSocket = deltaNetConnection.webSocket;
|
889
|
+
const states = joiner.states;
|
890
|
+
const clientId = joiner.internalConnectionId;
|
891
|
+
const statesMap = new Map(states);
|
892
|
+
const userData = DeltaNetComponentMapping.fromUserStates(statesMap);
|
893
|
+
return this.handleDeltaNetAuthentication(
|
894
|
+
clientId,
|
895
|
+
webSocket,
|
896
|
+
deltaNetConnection,
|
897
|
+
joiner.token,
|
898
|
+
userData
|
899
|
+
).then((authResult) => {
|
900
|
+
if (!authResult.success) {
|
901
|
+
console.warn(`Authentication failed for client ID: ${clientId}`);
|
902
|
+
return new DeltaNetServerError2(
|
903
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
904
|
+
"Authentication failed",
|
905
|
+
false
|
906
|
+
);
|
907
|
+
} else {
|
908
|
+
return {
|
909
|
+
success: true,
|
910
|
+
stateOverrides: authResult.stateOverrides
|
911
|
+
};
|
361
912
|
}
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
913
|
+
}).catch((error) => {
|
914
|
+
console.error(`Authentication error for client ID: ${clientId}:`, error);
|
915
|
+
return new DeltaNetServerError2(
|
916
|
+
DeltaNetV01ServerErrors.USER_AUTHENTICATION_FAILED_ERROR_TYPE,
|
917
|
+
"Authentication error",
|
918
|
+
false
|
919
|
+
);
|
920
|
+
});
|
921
|
+
}
|
922
|
+
handleLeave(leave) {
|
923
|
+
const deltaNetConnection = leave.deltaNetV01Connection;
|
924
|
+
const clientId = deltaNetConnection.internalConnectionId;
|
925
|
+
if (clientId !== void 0) {
|
926
|
+
const client = this.authenticatedClientsById.get(clientId);
|
927
|
+
if (client) {
|
928
|
+
this.options.onClientDisconnect(clientId);
|
929
|
+
this.authenticatedClientsById.delete(clientId);
|
368
930
|
}
|
369
931
|
}
|
370
932
|
}
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
933
|
+
handleCustomMessage(customMessage) {
|
934
|
+
const deltaNetConnection = customMessage.deltaNetV01Connection;
|
935
|
+
const clientId = deltaNetConnection.internalConnectionId;
|
936
|
+
const client = this.authenticatedClientsById.get(clientId);
|
937
|
+
if (client && client.authenticatedUser) {
|
938
|
+
if (customMessage.customType === FROM_CLIENT_CHAT_MESSAGE_TYPE) {
|
939
|
+
const chatMessage = parseClientChatMessage(customMessage.contents);
|
940
|
+
if (chatMessage instanceof Error) {
|
941
|
+
console.error(`Invalid chat message from client ${clientId}:`, chatMessage);
|
942
|
+
} else {
|
943
|
+
const serverChatMessage = {
|
944
|
+
fromUserId: clientId,
|
945
|
+
message: chatMessage.message
|
946
|
+
};
|
947
|
+
this.deltaNetServer.broadcastCustomMessage(
|
948
|
+
FROM_SERVER_CHAT_MESSAGE_TYPE,
|
949
|
+
JSON.stringify(serverChatMessage)
|
950
|
+
);
|
951
|
+
}
|
952
|
+
}
|
953
|
+
} else {
|
954
|
+
console.warn(`Custom message from unauthenticated client ${clientId} - ignoring`);
|
955
|
+
}
|
379
956
|
}
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
957
|
+
async handleDeltaNetAuthentication(clientId, webSocket, deltaNetConnection, sessionToken, userIdentity) {
|
958
|
+
try {
|
959
|
+
let userData = deltaNetConnection.isObserver ? null : await this.options.onClientConnect(clientId, sessionToken, userIdentity);
|
960
|
+
if (!deltaNetConnection.isObserver && !userData) {
|
961
|
+
console.warn(`Authentication failed for client ${clientId} - no user data returned`);
|
962
|
+
return { success: false };
|
963
|
+
}
|
964
|
+
if (this.options.connectionLimit !== void 0 && this.authenticatedClientsById.size >= this.options.connectionLimit) {
|
965
|
+
return { success: false };
|
966
|
+
}
|
967
|
+
if (userData instanceof Error) {
|
968
|
+
return { success: false, error: userData };
|
969
|
+
}
|
970
|
+
if (userData === true) {
|
971
|
+
userData = userIdentity;
|
972
|
+
}
|
973
|
+
const authenticatedClient = {
|
974
|
+
id: clientId,
|
975
|
+
socket: webSocket,
|
976
|
+
lastPong: Date.now(),
|
977
|
+
authenticatedUser: userData,
|
978
|
+
deltaNetConnection
|
979
|
+
};
|
980
|
+
this.authenticatedClientsById.set(clientId, authenticatedClient);
|
981
|
+
let stateOverrides = [];
|
982
|
+
if (userData) {
|
983
|
+
const officialStates = DeltaNetComponentMapping.toStates(userData);
|
984
|
+
stateOverrides = Array.from(officialStates.entries());
|
985
|
+
}
|
986
|
+
return {
|
987
|
+
success: true,
|
988
|
+
stateOverrides
|
989
|
+
};
|
990
|
+
} catch (error) {
|
991
|
+
console.error("Authentication error:", error);
|
992
|
+
return { success: false };
|
384
993
|
}
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
this.
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
clearTimeout(timeoutId);
|
401
|
-
this.receivedMessageSinceOpen = false;
|
402
|
-
this.websocket = websocket;
|
403
|
-
this.setStatus(1 /* Connected */);
|
404
|
-
websocket.addEventListener("message", (event) => {
|
405
|
-
if (websocket !== this.websocket) {
|
406
|
-
console.log("Ignoring websocket message event because it is no longer current");
|
407
|
-
websocket.close();
|
408
|
-
return;
|
409
|
-
}
|
410
|
-
if (!this.receivedMessageSinceOpen) {
|
411
|
-
this.receivedMessageSinceOpen = true;
|
412
|
-
}
|
413
|
-
this.handleIncomingWebsocketMessage(event);
|
414
|
-
});
|
415
|
-
const onWebsocketClose = async () => {
|
416
|
-
if (websocket !== this.websocket) {
|
417
|
-
console.log("Ignoring websocket close event because it is no longer current");
|
418
|
-
return;
|
419
|
-
}
|
420
|
-
this.websocket = null;
|
421
|
-
if (this.stopped) {
|
422
|
-
this.setStatus(3 /* Disconnected */);
|
423
|
-
return;
|
424
|
-
}
|
425
|
-
if (!this.receivedMessageSinceOpen) {
|
426
|
-
await this.waitBackoffTime();
|
427
|
-
}
|
428
|
-
this.setStatus(2 /* Reconnecting */);
|
429
|
-
this.startWebSocketConnectionAttempt();
|
430
|
-
};
|
431
|
-
websocket.addEventListener("close", (e) => {
|
432
|
-
if (websocket !== this.websocket) {
|
433
|
-
console.warn("Ignoring websocket close event because it is no longer current");
|
434
|
-
return;
|
435
|
-
}
|
436
|
-
console.log("ReconnectingWebSocket close", e);
|
437
|
-
onWebsocketClose();
|
438
|
-
});
|
439
|
-
websocket.addEventListener("error", (e) => {
|
440
|
-
if (websocket !== this.websocket) {
|
441
|
-
console.log("Ignoring websocket error event because it is no longer current");
|
442
|
-
return;
|
443
|
-
}
|
444
|
-
console.error("ReconnectingWebSocket error", e);
|
445
|
-
onWebsocketClose();
|
446
|
-
});
|
447
|
-
resolve(websocket);
|
448
|
-
});
|
449
|
-
websocket.addEventListener("error", (e) => {
|
450
|
-
clearTimeout(timeoutId);
|
451
|
-
reject(e);
|
452
|
-
});
|
994
|
+
}
|
995
|
+
connectClient(socket) {
|
996
|
+
if (socket.protocol === "") {
|
997
|
+
if (this.legacyAdapter) {
|
998
|
+
console.log("Legacy client detected - using legacy adapter");
|
999
|
+
this.legacyAdapter.addWebSocket(socket);
|
1000
|
+
return;
|
1001
|
+
} else {
|
1002
|
+
socket.close(1e3, "Legacy client detected (no subprotocol) - not supported");
|
1003
|
+
return;
|
1004
|
+
}
|
1005
|
+
}
|
1006
|
+
this.deltaNetServer.addWebSocket(socket);
|
1007
|
+
socket.addEventListener("close", () => {
|
1008
|
+
this.deltaNetServer.removeWebSocket(socket);
|
453
1009
|
});
|
454
1010
|
}
|
455
|
-
|
456
|
-
this.
|
457
|
-
if (this.
|
458
|
-
this.
|
459
|
-
this.websocket = null;
|
1011
|
+
broadcastMessage(broadcastType, broadcastPayload) {
|
1012
|
+
this.deltaNetServer.broadcastCustomMessage(broadcastType, broadcastPayload);
|
1013
|
+
if (this.legacyAdapter) {
|
1014
|
+
this.legacyAdapter.broadcastMessage(broadcastType, broadcastPayload);
|
460
1015
|
}
|
461
1016
|
}
|
1017
|
+
updateUserCharacter(clientId, userData) {
|
1018
|
+
console.log("updateUserCharacter", clientId, userData);
|
1019
|
+
this.internalUpdateUser(clientId, userData);
|
1020
|
+
}
|
1021
|
+
updateUserUsername(clientId, username) {
|
1022
|
+
const client = this.authenticatedClientsById.get(clientId);
|
1023
|
+
if (!client || !client.authenticatedUser) return;
|
1024
|
+
client.authenticatedUser = {
|
1025
|
+
...client.authenticatedUser,
|
1026
|
+
username
|
1027
|
+
};
|
1028
|
+
this.updatedUserProfilesInTick.add(clientId);
|
1029
|
+
const states = DeltaNetComponentMapping.toUsernameState(username);
|
1030
|
+
const asArray = Array.from(states.entries());
|
1031
|
+
this.deltaNetServer.overrideUserStates(client.deltaNetConnection, clientId, asArray);
|
1032
|
+
}
|
1033
|
+
updateUserCharacterDescription(clientId, characterDescription) {
|
1034
|
+
const client = this.authenticatedClientsById.get(clientId);
|
1035
|
+
if (!client || !client.authenticatedUser) return;
|
1036
|
+
client.authenticatedUser = {
|
1037
|
+
...client.authenticatedUser,
|
1038
|
+
characterDescription
|
1039
|
+
};
|
1040
|
+
this.updatedUserProfilesInTick.add(clientId);
|
1041
|
+
const states = DeltaNetComponentMapping.toCharacterDescriptionState(characterDescription);
|
1042
|
+
const asArray = Array.from(states.entries());
|
1043
|
+
this.deltaNetServer.overrideUserStates(client.deltaNetConnection, clientId, asArray);
|
1044
|
+
}
|
1045
|
+
updateUserColors(clientId, colors) {
|
1046
|
+
const client = this.authenticatedClientsById.get(clientId);
|
1047
|
+
if (!client || !client.authenticatedUser) return;
|
1048
|
+
client.authenticatedUser = {
|
1049
|
+
...client.authenticatedUser,
|
1050
|
+
colors
|
1051
|
+
};
|
1052
|
+
this.updatedUserProfilesInTick.add(clientId);
|
1053
|
+
const states = DeltaNetComponentMapping.toColorsState(colors);
|
1054
|
+
const asArray = Array.from(states.entries());
|
1055
|
+
this.deltaNetServer.overrideUserStates(client.deltaNetConnection, clientId, asArray);
|
1056
|
+
}
|
1057
|
+
updateUserStates(clientId, updates) {
|
1058
|
+
const client = this.authenticatedClientsById.get(clientId);
|
1059
|
+
if (!client || !client.authenticatedUser) return;
|
1060
|
+
const states = /* @__PURE__ */ new Map();
|
1061
|
+
let hasUpdates = false;
|
1062
|
+
let updatedUserData = client.authenticatedUser;
|
1063
|
+
this.updatedUserProfilesInTick.add(clientId);
|
1064
|
+
if (updates.username !== null) {
|
1065
|
+
updatedUserData = {
|
1066
|
+
...updatedUserData,
|
1067
|
+
username: updates.username
|
1068
|
+
};
|
1069
|
+
const usernameStates = DeltaNetComponentMapping.toUsernameState(updates.username);
|
1070
|
+
for (const [stateId, stateValue] of usernameStates) {
|
1071
|
+
states.set(stateId, stateValue);
|
1072
|
+
}
|
1073
|
+
hasUpdates = true;
|
1074
|
+
}
|
1075
|
+
if (updates.characterDescription !== null) {
|
1076
|
+
updatedUserData = {
|
1077
|
+
...updatedUserData,
|
1078
|
+
characterDescription: updates.characterDescription
|
1079
|
+
};
|
1080
|
+
const characterDescStates = DeltaNetComponentMapping.toCharacterDescriptionState(
|
1081
|
+
updates.characterDescription
|
1082
|
+
);
|
1083
|
+
for (const [stateId, stateValue] of characterDescStates) {
|
1084
|
+
states.set(stateId, stateValue);
|
1085
|
+
}
|
1086
|
+
hasUpdates = true;
|
1087
|
+
}
|
1088
|
+
if (updates.colors !== null) {
|
1089
|
+
updatedUserData = {
|
1090
|
+
...updatedUserData,
|
1091
|
+
colors: updates.colors
|
1092
|
+
};
|
1093
|
+
const colorsStates = DeltaNetComponentMapping.toColorsState(updates.colors);
|
1094
|
+
for (const [stateId, stateValue] of colorsStates) {
|
1095
|
+
states.set(stateId, stateValue);
|
1096
|
+
}
|
1097
|
+
hasUpdates = true;
|
1098
|
+
}
|
1099
|
+
if (hasUpdates) {
|
1100
|
+
client.authenticatedUser = updatedUserData;
|
1101
|
+
const asArray = Array.from(states.entries());
|
1102
|
+
this.deltaNetServer.overrideUserStates(client.deltaNetConnection, clientId, asArray);
|
1103
|
+
}
|
1104
|
+
}
|
1105
|
+
internalUpdateUser(clientId, userData) {
|
1106
|
+
const client = this.authenticatedClientsById.get(clientId);
|
1107
|
+
if (!client) {
|
1108
|
+
throw new Error(`internalUpdateUser - client not found for clientId ${clientId}`);
|
1109
|
+
}
|
1110
|
+
console.log("internalUpdateUser", clientId, userData);
|
1111
|
+
this.updatedUserProfilesInTick.add(clientId);
|
1112
|
+
client.authenticatedUser = {
|
1113
|
+
...client.authenticatedUser,
|
1114
|
+
...userData
|
1115
|
+
};
|
1116
|
+
const states = DeltaNetComponentMapping.toStates(userData);
|
1117
|
+
const asArray = Array.from(states.entries());
|
1118
|
+
this.deltaNetServer.overrideUserStates(client.deltaNetConnection, clientId, asArray);
|
1119
|
+
}
|
1120
|
+
dispose(clientCloseError) {
|
1121
|
+
if (this.tickInterval) {
|
1122
|
+
clearInterval(this.tickInterval);
|
1123
|
+
}
|
1124
|
+
let errorMessage = null;
|
1125
|
+
if (clientCloseError) {
|
1126
|
+
errorMessage = encodeError({
|
1127
|
+
type: "error",
|
1128
|
+
errorType: clientCloseError.errorType,
|
1129
|
+
message: clientCloseError.message,
|
1130
|
+
retryable: clientCloseError.retryable
|
1131
|
+
}).getBuffer();
|
1132
|
+
}
|
1133
|
+
for (const [, client] of this.authenticatedClientsById) {
|
1134
|
+
if (errorMessage) {
|
1135
|
+
client.socket.send(errorMessage);
|
1136
|
+
}
|
1137
|
+
client.socket.close();
|
1138
|
+
}
|
1139
|
+
this.authenticatedClientsById.clear();
|
1140
|
+
}
|
462
1141
|
};
|
463
1142
|
|
464
1143
|
// src/UserNetworkingClient.ts
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
1144
|
+
import {
|
1145
|
+
DeltaNetClientState,
|
1146
|
+
DeltaNetClientWebsocket,
|
1147
|
+
DeltaNetClientWebsocketStatus
|
1148
|
+
} from "/Users/marcuslongmuir/mml/3d-web-experience/packages/deltanet/delta-net-web/build/index.js";
|
1149
|
+
|
1150
|
+
// src/types.ts
|
1151
|
+
var WebsocketStatus = /* @__PURE__ */ ((WebsocketStatus2) => {
|
1152
|
+
WebsocketStatus2[WebsocketStatus2["Connecting"] = 0] = "Connecting";
|
1153
|
+
WebsocketStatus2[WebsocketStatus2["Connected"] = 1] = "Connected";
|
1154
|
+
WebsocketStatus2[WebsocketStatus2["Reconnecting"] = 2] = "Reconnecting";
|
1155
|
+
WebsocketStatus2[WebsocketStatus2["Disconnected"] = 3] = "Disconnected";
|
1156
|
+
return WebsocketStatus2;
|
1157
|
+
})(WebsocketStatus || {});
|
1158
|
+
|
1159
|
+
// src/UserNetworkingClient.ts
|
1160
|
+
var UserNetworkingClient = class {
|
1161
|
+
constructor(config, initialUserState, initialUpdate) {
|
476
1162
|
this.config = config;
|
1163
|
+
this.userId = null;
|
1164
|
+
this.userIndex = null;
|
1165
|
+
this.userState = {
|
1166
|
+
username: null,
|
1167
|
+
characterDescription: null,
|
1168
|
+
colors: null
|
1169
|
+
};
|
1170
|
+
this.stableIdToUserId = /* @__PURE__ */ new Map();
|
1171
|
+
this.userProfiles = /* @__PURE__ */ new Map();
|
1172
|
+
this.isAuthenticated = false;
|
1173
|
+
this.pendingUpdate = initialUpdate ?? {
|
1174
|
+
position: { x: 0, y: 0, z: 0 },
|
1175
|
+
rotation: { quaternionY: 0, quaternionW: 1 },
|
1176
|
+
state: 0
|
1177
|
+
};
|
1178
|
+
this.userState = initialUserState ?? {
|
1179
|
+
username: null,
|
1180
|
+
characterDescription: null,
|
1181
|
+
colors: null
|
1182
|
+
};
|
1183
|
+
this.deltaNetState = new DeltaNetClientState();
|
1184
|
+
this.deltaNetClient = new DeltaNetClientWebsocket(
|
1185
|
+
config.url,
|
1186
|
+
(url) => {
|
1187
|
+
const ws = config.websocketFactory(url);
|
1188
|
+
return ws;
|
1189
|
+
},
|
1190
|
+
config.sessionToken,
|
1191
|
+
{
|
1192
|
+
ignoreData: false,
|
1193
|
+
onInitialCheckout: (initialCheckout) => {
|
1194
|
+
const { addedStableIds } = this.deltaNetState.handleInitialCheckout(initialCheckout);
|
1195
|
+
const networkUpdate = this.processNetworkUpdate([], addedStableIds, []);
|
1196
|
+
this.config.onUpdate(networkUpdate);
|
1197
|
+
if (this.userIndex !== null) {
|
1198
|
+
const userIds = this.deltaNetState.getStableIds();
|
1199
|
+
if (this.userIndex < userIds.length) {
|
1200
|
+
const stableId = userIds[this.userIndex];
|
1201
|
+
const userId = this.stableIdToUserId.get(stableId);
|
1202
|
+
if (!userId) {
|
1203
|
+
throw new Error(`No userId found for stableId ${stableId}`);
|
1204
|
+
}
|
1205
|
+
this.userId = userId;
|
1206
|
+
this.isAuthenticated = true;
|
1207
|
+
this.config.assignedIdentity(this.userId);
|
1208
|
+
} else {
|
1209
|
+
console.error(
|
1210
|
+
`Invalid userIndex ${this.userIndex}, userIds length: ${userIds.length}`
|
1211
|
+
);
|
1212
|
+
}
|
1213
|
+
}
|
1214
|
+
},
|
1215
|
+
onTick: (tick) => {
|
1216
|
+
const { stateUpdates, removedStableIds, addedStableIds } = this.deltaNetState.handleTick(tick);
|
1217
|
+
const networkUpdate = this.processNetworkUpdate(
|
1218
|
+
removedStableIds,
|
1219
|
+
addedStableIds,
|
1220
|
+
stateUpdates
|
1221
|
+
);
|
1222
|
+
this.config.onUpdate(networkUpdate);
|
1223
|
+
},
|
1224
|
+
onUserIndex: (userIndex) => {
|
1225
|
+
this.userIndex = userIndex.userIndex;
|
1226
|
+
this.deltaNetState.setLocalIndex(userIndex.userIndex);
|
1227
|
+
console.log(
|
1228
|
+
`Received userIndex: ${userIndex.userIndex}, waiting for initial checkout to resolve stable userId...`
|
1229
|
+
);
|
1230
|
+
},
|
1231
|
+
onError: (errorType, errorMessage, retryable) => {
|
1232
|
+
console.error(
|
1233
|
+
"DeltaNet error:",
|
1234
|
+
errorType,
|
1235
|
+
"errorMessage:",
|
1236
|
+
errorMessage,
|
1237
|
+
"retryable:",
|
1238
|
+
retryable
|
1239
|
+
);
|
1240
|
+
this.config.onServerError({
|
1241
|
+
message: errorMessage,
|
1242
|
+
errorType
|
1243
|
+
});
|
1244
|
+
},
|
1245
|
+
onWarning: (warning) => {
|
1246
|
+
console.warn("DeltaNet warning:", warning);
|
1247
|
+
},
|
1248
|
+
onServerCustom: (customType, contents) => {
|
1249
|
+
var _a, _b;
|
1250
|
+
(_b = (_a = this.config).onCustomMessage) == null ? void 0 : _b.call(_a, customType, contents);
|
1251
|
+
}
|
1252
|
+
},
|
1253
|
+
void 0,
|
1254
|
+
// timeCallback is optional
|
1255
|
+
(status) => {
|
1256
|
+
let mappedStatus;
|
1257
|
+
switch (status) {
|
1258
|
+
case DeltaNetClientWebsocketStatus.Connected:
|
1259
|
+
mappedStatus = 1 /* Connected */;
|
1260
|
+
break;
|
1261
|
+
case DeltaNetClientWebsocketStatus.ConnectionOpen:
|
1262
|
+
this.sendInitialAuthentication();
|
1263
|
+
mappedStatus = 1 /* Connected */;
|
1264
|
+
break;
|
1265
|
+
case DeltaNetClientWebsocketStatus.Disconnected:
|
1266
|
+
mappedStatus = 3 /* Disconnected */;
|
1267
|
+
this.reset();
|
1268
|
+
break;
|
1269
|
+
case DeltaNetClientWebsocketStatus.Reconnecting:
|
1270
|
+
mappedStatus = 2 /* Reconnecting */;
|
1271
|
+
this.reset();
|
1272
|
+
break;
|
1273
|
+
default:
|
1274
|
+
mappedStatus = 3 /* Disconnected */;
|
1275
|
+
}
|
1276
|
+
this.config.statusUpdateCallback(mappedStatus);
|
1277
|
+
}
|
1278
|
+
);
|
477
1279
|
}
|
478
|
-
|
479
|
-
|
480
|
-
this.
|
481
|
-
|
482
|
-
|
483
|
-
this.
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
1280
|
+
reset() {
|
1281
|
+
this.deltaNetState.reset();
|
1282
|
+
this.userProfiles.clear();
|
1283
|
+
this.stableIdToUserId.clear();
|
1284
|
+
this.isAuthenticated = false;
|
1285
|
+
this.userId = null;
|
1286
|
+
this.userIndex = null;
|
1287
|
+
}
|
1288
|
+
sendInitialAuthentication() {
|
1289
|
+
const components = DeltaNetComponentMapping.toComponents(this.pendingUpdate);
|
1290
|
+
const states = DeltaNetComponentMapping.toStates(this.userState);
|
1291
|
+
this.deltaNetClient.setUserComponents(components, states);
|
1292
|
+
}
|
1293
|
+
processNetworkUpdate(removedStableIds, addedStableIdsArray, stateUpdates) {
|
1294
|
+
const addedUserIds = /* @__PURE__ */ new Map();
|
1295
|
+
const removedUserIds = /* @__PURE__ */ new Set();
|
1296
|
+
for (const stableId of removedStableIds) {
|
1297
|
+
const userId = this.stableIdToUserId.get(stableId);
|
1298
|
+
if (userId) {
|
1299
|
+
removedUserIds.add(userId);
|
1300
|
+
this.userProfiles.delete(userId);
|
1301
|
+
this.stableIdToUserId.delete(stableId);
|
1302
|
+
} else {
|
1303
|
+
throw new Error(`No userId found for stableId ${stableId}`);
|
1304
|
+
}
|
1305
|
+
}
|
1306
|
+
for (const stableId of addedStableIdsArray) {
|
1307
|
+
const stableUserData = this.deltaNetState.byStableId.get(stableId);
|
1308
|
+
if (!stableUserData) {
|
1309
|
+
throw new Error(`No stableUserData found for stableId ${stableId}`);
|
1310
|
+
}
|
1311
|
+
const userIdState = stableUserData.states.get(STATE_INTERNAL_CONNECTION_ID);
|
1312
|
+
if (!userIdState) {
|
1313
|
+
throw new Error(`No userIdState found for stableId ${stableId}`);
|
1314
|
+
}
|
1315
|
+
const userId = DeltaNetComponentMapping.userIdFromBytes(userIdState);
|
1316
|
+
if (!userId) {
|
1317
|
+
throw new Error(`Failed to extract userId from bytes for stableId ${stableId}`);
|
1318
|
+
}
|
1319
|
+
this.stableIdToUserId.set(stableId, userId);
|
1320
|
+
const newProfile = DeltaNetComponentMapping.fromStates(stableUserData.states);
|
1321
|
+
this.userProfiles.set(userId, newProfile);
|
1322
|
+
const clientUpdate = DeltaNetComponentMapping.fromComponents(stableUserData.components);
|
1323
|
+
addedUserIds.set(userId, {
|
1324
|
+
userState: newProfile,
|
1325
|
+
components: clientUpdate
|
1326
|
+
});
|
1327
|
+
}
|
1328
|
+
const updatedUsers = /* @__PURE__ */ new Map();
|
1329
|
+
for (const [stableUserId, userInfo] of this.deltaNetState.byStableId) {
|
1330
|
+
const userId = this.stableIdToUserId.get(stableUserId);
|
1331
|
+
if (!userId) {
|
1332
|
+
throw new Error(`No userId found for stableUserId ${stableUserId}`);
|
1333
|
+
}
|
1334
|
+
if (!addedUserIds.has(userId)) {
|
1335
|
+
if (userInfo.components.size > 0) {
|
1336
|
+
const clientUpdate = DeltaNetComponentMapping.fromComponents(userInfo.components);
|
1337
|
+
updatedUsers.set(userId, {
|
1338
|
+
components: clientUpdate
|
1339
|
+
});
|
1340
|
+
}
|
1341
|
+
}
|
1342
|
+
}
|
1343
|
+
for (const update of stateUpdates) {
|
1344
|
+
const stableUserId = update.stableId;
|
1345
|
+
const userId = this.stableIdToUserId.get(stableUserId);
|
1346
|
+
if (!userId) {
|
1347
|
+
throw new Error(`No userId found for stableUserId ${stableUserId}`);
|
1348
|
+
}
|
1349
|
+
if (addedUserIds.has(userId)) {
|
1350
|
+
continue;
|
1351
|
+
}
|
1352
|
+
const profile = this.userProfiles.get(userId);
|
1353
|
+
if (!profile) {
|
1354
|
+
console.warn(`No profile found for user ${userId}, skipping update`);
|
1355
|
+
continue;
|
1356
|
+
}
|
1357
|
+
const existingUpdate = updatedUsers.get(userId);
|
1358
|
+
let existingUserStateUpdate = existingUpdate.userState;
|
1359
|
+
if (!existingUserStateUpdate) {
|
1360
|
+
existingUserStateUpdate = {};
|
1361
|
+
existingUpdate.userState = existingUserStateUpdate;
|
1362
|
+
}
|
1363
|
+
switch (update.stateId) {
|
1364
|
+
case STATE_INTERNAL_CONNECTION_ID:
|
1365
|
+
console.error("STATE_INTERNAL_CONNECTION_ID is not expected to change in state updates");
|
500
1366
|
break;
|
501
|
-
case
|
502
|
-
|
503
|
-
|
1367
|
+
case STATE_USERNAME:
|
1368
|
+
const username = DeltaNetComponentMapping.usernameFromBytes(update.state);
|
1369
|
+
if (username) {
|
1370
|
+
profile.username = username;
|
1371
|
+
existingUserStateUpdate.username = username;
|
1372
|
+
}
|
504
1373
|
break;
|
505
|
-
case
|
506
|
-
|
1374
|
+
case STATE_CHARACTER_DESCRIPTION:
|
1375
|
+
const characterDescription = DeltaNetComponentMapping.characterDescriptionFromBytes(
|
1376
|
+
update.state
|
1377
|
+
);
|
1378
|
+
profile.characterDescription = characterDescription;
|
1379
|
+
existingUserStateUpdate.characterDescription = characterDescription;
|
507
1380
|
break;
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
broadcastType: parsed.broadcastType,
|
513
|
-
payload: parsed.payload
|
514
|
-
});
|
515
|
-
} else {
|
516
|
-
console.warn("Unhandled broadcast", parsed);
|
517
|
-
}
|
1381
|
+
case STATE_COLORS:
|
1382
|
+
const colors = DeltaNetComponentMapping.decodeColors(update.state);
|
1383
|
+
profile.colors = colors;
|
1384
|
+
existingUserStateUpdate.colors = colors;
|
518
1385
|
break;
|
519
|
-
}
|
520
1386
|
default:
|
521
|
-
console.
|
1387
|
+
console.warn(`Unknown state ID: ${update.stateId}`);
|
522
1388
|
}
|
523
|
-
} else if (message.data instanceof ArrayBuffer) {
|
524
|
-
const userNetworkingClientUpdate = UserNetworkingCodec.decodeUpdate(message.data);
|
525
|
-
this.config.clientUpdate(userNetworkingClientUpdate.id, userNetworkingClientUpdate);
|
526
|
-
} else {
|
527
|
-
console.error("Unhandled message type", message.data);
|
528
1389
|
}
|
1390
|
+
return {
|
1391
|
+
removedUserIds,
|
1392
|
+
addedUserIds,
|
1393
|
+
updatedUsers
|
1394
|
+
};
|
1395
|
+
}
|
1396
|
+
sendUpdate(update) {
|
1397
|
+
if (!this.isAuthenticated || this.userId === null) {
|
1398
|
+
this.pendingUpdate = update;
|
1399
|
+
return;
|
1400
|
+
}
|
1401
|
+
const components = DeltaNetComponentMapping.toComponents(update);
|
1402
|
+
this.deltaNetClient.setUserComponents(components, /* @__PURE__ */ new Map());
|
1403
|
+
}
|
1404
|
+
sendCustomMessage(customType, contents) {
|
1405
|
+
if (!this.isAuthenticated || this.userId === null) {
|
1406
|
+
console.warn("Cannot send custom message before authentication");
|
1407
|
+
return;
|
1408
|
+
}
|
1409
|
+
this.deltaNetClient.sendCustomMessage(customType, contents);
|
1410
|
+
}
|
1411
|
+
updateUsername(username) {
|
1412
|
+
if (!this.isAuthenticated || this.userId === null) {
|
1413
|
+
return;
|
1414
|
+
}
|
1415
|
+
this.userState.username = username;
|
1416
|
+
const states = DeltaNetComponentMapping.toUsernameState(username);
|
1417
|
+
this.deltaNetClient.setUserComponents(/* @__PURE__ */ new Map(), states);
|
1418
|
+
}
|
1419
|
+
updateCharacterDescription(characterDescription) {
|
1420
|
+
if (!this.isAuthenticated || this.userId === null) {
|
1421
|
+
return;
|
1422
|
+
}
|
1423
|
+
this.userState.characterDescription = characterDescription;
|
1424
|
+
const states = DeltaNetComponentMapping.toCharacterDescriptionState(characterDescription);
|
1425
|
+
this.deltaNetClient.setUserComponents(/* @__PURE__ */ new Map(), states);
|
1426
|
+
}
|
1427
|
+
updateColors(colors) {
|
1428
|
+
if (!this.isAuthenticated || this.userId === null) {
|
1429
|
+
return;
|
1430
|
+
}
|
1431
|
+
this.userState.colors = colors;
|
1432
|
+
const states = DeltaNetComponentMapping.toColorsState(colors);
|
1433
|
+
this.deltaNetClient.setUserComponents(/* @__PURE__ */ new Map(), states);
|
1434
|
+
}
|
1435
|
+
stop() {
|
1436
|
+
this.deltaNetClient.stop();
|
1437
|
+
this.reset();
|
529
1438
|
}
|
530
1439
|
};
|
1440
|
+
|
1441
|
+
// src/index.ts
|
1442
|
+
import {
|
1443
|
+
DeltaNetV01ServerErrors as DeltaNetV01ServerErrors2,
|
1444
|
+
deltaNetProtocolSubProtocol_v0_1
|
1445
|
+
} from "/Users/marcuslongmuir/mml/3d-web-experience/packages/deltanet/delta-net-protocol/build/index.js";
|
531
1446
|
export {
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
1447
|
+
COMPONENT_POSITION_X,
|
1448
|
+
COMPONENT_POSITION_Y,
|
1449
|
+
COMPONENT_POSITION_Z,
|
1450
|
+
COMPONENT_ROTATION_W,
|
1451
|
+
COMPONENT_ROTATION_Y,
|
1452
|
+
COMPONENT_STATE,
|
1453
|
+
DeltaNetComponentMapping,
|
1454
|
+
DeltaNetV01ServerErrors2 as DeltaNetV01ServerErrors,
|
1455
|
+
FROM_CLIENT_CHAT_MESSAGE_TYPE,
|
1456
|
+
FROM_SERVER_CHAT_MESSAGE_TYPE,
|
1457
|
+
LEGACY_USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE,
|
1458
|
+
LEGACY_USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE,
|
1459
|
+
LEGACY_USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE,
|
1460
|
+
LEGACY_USER_NETWORKING_IDENTITY_MESSAGE_TYPE,
|
1461
|
+
LEGACY_USER_NETWORKING_PING_MESSAGE_TYPE,
|
1462
|
+
LEGACY_USER_NETWORKING_PONG_MESSAGE_TYPE,
|
1463
|
+
LEGACY_USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE,
|
1464
|
+
LEGACY_USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,
|
1465
|
+
LEGACY_USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE,
|
1466
|
+
LEGACY_USER_NETWORKING_UNKNOWN_ERROR,
|
1467
|
+
LEGACY_USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE,
|
1468
|
+
LEGACY_USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
1469
|
+
LEGACY_USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE,
|
1470
|
+
SERVER_BROADCAST_MESSAGE_TYPE,
|
1471
|
+
STATE_CHARACTER_DESCRIPTION,
|
1472
|
+
STATE_COLORS,
|
1473
|
+
STATE_INTERNAL_CONNECTION_ID,
|
1474
|
+
STATE_USERNAME,
|
546
1475
|
UserNetworkingClient,
|
547
|
-
UserNetworkingCodec,
|
548
1476
|
UserNetworkingServer,
|
549
|
-
|
1477
|
+
UserNetworkingServerError,
|
1478
|
+
WebsocketStatus,
|
1479
|
+
deltaNetProtocolSubProtocol_v0_1,
|
1480
|
+
parseClientChatMessage,
|
1481
|
+
parseServerBroadcastMessage,
|
1482
|
+
parseServerChatMessage,
|
1483
|
+
positionMultiplier,
|
1484
|
+
rotationMultiplier
|
550
1485
|
};
|
551
1486
|
//# sourceMappingURL=index.js.map
|