@mml-io/3d-web-user-networking 0.18.0 → 0.19.0
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.
@@ -1,6 +1,6 @@
|
|
1
1
|
import { ReconnectingWebSocket, WebsocketFactory, WebsocketStatus } from "./ReconnectingWebSocket";
|
2
2
|
import { UserNetworkingClientUpdate } from "./UserNetworkingCodec";
|
3
|
-
import { CharacterDescription,
|
3
|
+
import { CharacterDescription, FromUserNetworkingClientMessage, UserNetworkingServerErrorType } from "./UserNetworkingMessages";
|
4
4
|
export type UserNetworkingClientConfig = {
|
5
5
|
url: string;
|
6
6
|
sessionToken: string;
|
@@ -11,13 +11,17 @@ export type UserNetworkingClientConfig = {
|
|
11
11
|
clientProfileUpdated: (id: number, username: string, characterDescription: CharacterDescription) => void;
|
12
12
|
onServerError: (error: {
|
13
13
|
message: string;
|
14
|
-
errorType:
|
14
|
+
errorType: UserNetworkingServerErrorType;
|
15
|
+
}) => void;
|
16
|
+
onServerBroadcast?: (broadcast: {
|
17
|
+
broadcastType: string;
|
18
|
+
payload: any;
|
15
19
|
}) => void;
|
16
20
|
};
|
17
21
|
export declare class UserNetworkingClient extends ReconnectingWebSocket {
|
18
22
|
private config;
|
19
23
|
constructor(config: UserNetworkingClientConfig);
|
20
24
|
sendUpdate(update: UserNetworkingClientUpdate): void;
|
21
|
-
sendMessage(message:
|
25
|
+
sendMessage(message: FromUserNetworkingClientMessage): void;
|
22
26
|
protected handleIncomingWebsocketMessage(message: MessageEvent): void;
|
23
27
|
}
|
@@ -1,13 +1,14 @@
|
|
1
|
-
export declare const
|
2
|
-
export declare const
|
3
|
-
export declare const
|
4
|
-
export declare const
|
5
|
-
export declare const
|
6
|
-
export declare const
|
7
|
-
export declare const
|
8
|
-
export declare const
|
9
|
-
export
|
10
|
-
|
1
|
+
export declare const USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE = "disconnected";
|
2
|
+
export declare const USER_NETWORKING_IDENTITY_MESSAGE_TYPE = "identity";
|
3
|
+
export declare const USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE = "user_auth";
|
4
|
+
export declare const USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE = "user_profile";
|
5
|
+
export declare const USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE = "user_update";
|
6
|
+
export declare const USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE = "broadcast";
|
7
|
+
export declare const USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE = "error";
|
8
|
+
export declare const USER_NETWORKING_PING_MESSAGE_TYPE = "ping";
|
9
|
+
export declare const USER_NETWORKING_PONG_MESSAGE_TYPE = "pong";
|
10
|
+
export type UserNetworkingIdentityMessage = {
|
11
|
+
type: typeof USER_NETWORKING_IDENTITY_MESSAGE_TYPE;
|
11
12
|
id: number;
|
12
13
|
};
|
13
14
|
export type CharacterDescription = {
|
@@ -21,42 +22,49 @@ export type CharacterDescription = {
|
|
21
22
|
} | {
|
22
23
|
mmlCharacterString: string;
|
23
24
|
});
|
24
|
-
export type
|
25
|
-
type: typeof
|
25
|
+
export type UserNetworkingProfileMessage = {
|
26
|
+
type: typeof USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE;
|
26
27
|
id: number;
|
27
28
|
username: string;
|
28
29
|
characterDescription: CharacterDescription;
|
29
30
|
};
|
30
|
-
export type
|
31
|
-
type: typeof
|
31
|
+
export type UserNetworkingDisconnectedMessage = {
|
32
|
+
type: typeof USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE;
|
32
33
|
id: number;
|
33
34
|
};
|
34
|
-
export declare const
|
35
|
-
export declare const
|
36
|
-
export
|
37
|
-
export
|
38
|
-
|
39
|
-
|
35
|
+
export declare const USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE = "CONNECTION_LIMIT_REACHED";
|
36
|
+
export declare const USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE = "AUTHENTICATION_FAILED";
|
37
|
+
export declare const USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE = "SERVER_SHUTDOWN";
|
38
|
+
export declare const USER_NETWORKING_UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
39
|
+
export type UserNetworkingServerErrorType = typeof USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE | typeof USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE | typeof USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE | typeof USER_NETWORKING_UNKNOWN_ERROR;
|
40
|
+
export type UserNetworkingServerError = {
|
41
|
+
type: typeof USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE;
|
42
|
+
errorType: UserNetworkingServerErrorType;
|
40
43
|
message: string;
|
41
44
|
};
|
42
|
-
export type
|
43
|
-
type: typeof
|
45
|
+
export type UserNetworkingServerBroadcast = {
|
46
|
+
type: typeof USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE;
|
47
|
+
broadcastType: string;
|
48
|
+
payload: any;
|
44
49
|
};
|
45
|
-
export type
|
46
|
-
|
47
|
-
|
50
|
+
export type UserNetworkingServerPingMessage = {
|
51
|
+
type: typeof USER_NETWORKING_PING_MESSAGE_TYPE;
|
52
|
+
};
|
53
|
+
export type FromUserNetworkingServerMessage = UserNetworkingIdentityMessage | UserNetworkingProfileMessage | UserNetworkingDisconnectedMessage | UserNetworkingServerPingMessage | UserNetworkingServerBroadcast | UserNetworkingServerError;
|
54
|
+
export type UserNetworkingClientPongMessage = {
|
55
|
+
type: typeof USER_NETWORKING_PONG_MESSAGE_TYPE;
|
48
56
|
};
|
49
57
|
export type UserIdentity = {
|
50
58
|
characterDescription: CharacterDescription | null;
|
51
59
|
username: string | null;
|
52
60
|
};
|
53
|
-
export type
|
54
|
-
type: typeof
|
61
|
+
export type UserNetworkingAuthenticateMessage = {
|
62
|
+
type: typeof USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE;
|
55
63
|
sessionToken: string;
|
56
64
|
userIdentity?: UserIdentity;
|
57
65
|
};
|
58
|
-
export type
|
59
|
-
type: typeof
|
66
|
+
export type UserNetworkingUserUpdateMessage = {
|
67
|
+
type: typeof USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE;
|
60
68
|
userIdentity: UserIdentity;
|
61
69
|
};
|
62
|
-
export type
|
70
|
+
export type FromUserNetworkingClientMessage = UserNetworkingClientPongMessage | UserNetworkingAuthenticateMessage | UserNetworkingUserUpdateMessage;
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import WebSocket from "ws";
|
2
2
|
import { UserData } from "./UserData";
|
3
3
|
import { UserNetworkingClientUpdate } from "./UserNetworkingCodec";
|
4
|
-
import { UserIdentity } from "./UserNetworkingMessages";
|
5
|
-
export type
|
4
|
+
import { UserIdentity, UserNetworkingServerError } from "./UserNetworkingMessages";
|
5
|
+
export type UserNetworkingServerClient = {
|
6
6
|
socket: WebSocket;
|
7
7
|
id: number;
|
8
8
|
lastPong: number;
|
@@ -19,10 +19,14 @@ export declare class UserNetworkingServer {
|
|
19
19
|
private options;
|
20
20
|
private allClientsById;
|
21
21
|
private authenticatedClientsById;
|
22
|
+
private sendUpdatesIntervalTimer;
|
23
|
+
private pingClientsIntervalTimer;
|
24
|
+
private heartbeatIntervalTimer;
|
22
25
|
constructor(options: UserNetworkingServerOptions);
|
23
26
|
private heartBeat;
|
24
27
|
private pingClients;
|
25
28
|
private getId;
|
29
|
+
broadcastMessage(broadcastType: string, broadcastPayload: any): void;
|
26
30
|
connectClient(socket: WebSocket): void;
|
27
31
|
private handleDisconnectedClient;
|
28
32
|
private handleUserAuth;
|
@@ -30,4 +34,5 @@ export declare class UserNetworkingServer {
|
|
30
34
|
private internalUpdateUser;
|
31
35
|
private handleUserUpdate;
|
32
36
|
private sendUpdates;
|
37
|
+
dispose(clientCloseError?: UserNetworkingServerError): void;
|
33
38
|
}
|
package/build/index.js
CHANGED
@@ -33,16 +33,19 @@ var heartBeatRate = 15e3;
|
|
33
33
|
var packetsUpdateRate = 1 / 30 * 1e3;
|
34
34
|
|
35
35
|
// src/UserNetworkingMessages.ts
|
36
|
-
var
|
37
|
-
var
|
38
|
-
var
|
39
|
-
var
|
40
|
-
var
|
41
|
-
var
|
42
|
-
var
|
43
|
-
var
|
44
|
-
var
|
45
|
-
var
|
36
|
+
var USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE = "disconnected";
|
37
|
+
var USER_NETWORKING_IDENTITY_MESSAGE_TYPE = "identity";
|
38
|
+
var USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE = "user_auth";
|
39
|
+
var USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE = "user_profile";
|
40
|
+
var USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE = "user_update";
|
41
|
+
var USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE = "broadcast";
|
42
|
+
var USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE = "error";
|
43
|
+
var USER_NETWORKING_PING_MESSAGE_TYPE = "ping";
|
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";
|
46
49
|
|
47
50
|
// src/UserNetworkingServer.ts
|
48
51
|
var WebSocketOpenStatus = 1;
|
@@ -51,9 +54,9 @@ var UserNetworkingServer = class {
|
|
51
54
|
this.options = options;
|
52
55
|
this.allClientsById = /* @__PURE__ */ new Map();
|
53
56
|
this.authenticatedClientsById = /* @__PURE__ */ new Map();
|
54
|
-
setInterval(this.sendUpdates.bind(this), packetsUpdateRate);
|
55
|
-
setInterval(this.pingClients.bind(this), pingPongRate);
|
56
|
-
setInterval(this.heartBeat.bind(this), heartBeatRate);
|
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);
|
57
60
|
}
|
58
61
|
heartBeat() {
|
59
62
|
const now = Date.now();
|
@@ -65,9 +68,11 @@ var UserNetworkingServer = class {
|
|
65
68
|
});
|
66
69
|
}
|
67
70
|
pingClients() {
|
71
|
+
const message = { type: "ping" };
|
72
|
+
const messageString = JSON.stringify(message);
|
68
73
|
this.authenticatedClientsById.forEach((client) => {
|
69
74
|
if (client.socket.readyState === WebSocketOpenStatus) {
|
70
|
-
client.socket.send(
|
75
|
+
client.socket.send(messageString);
|
71
76
|
}
|
72
77
|
});
|
73
78
|
}
|
@@ -78,6 +83,19 @@ var UserNetworkingServer = class {
|
|
78
83
|
}
|
79
84
|
return id;
|
80
85
|
}
|
86
|
+
broadcastMessage(broadcastType, broadcastPayload) {
|
87
|
+
const message = {
|
88
|
+
type: "broadcast",
|
89
|
+
broadcastType,
|
90
|
+
payload: broadcastPayload
|
91
|
+
};
|
92
|
+
const messageString = JSON.stringify(message);
|
93
|
+
for (const [, client] of this.authenticatedClientsById) {
|
94
|
+
if (client.socket.readyState === WebSocketOpenStatus) {
|
95
|
+
client.socket.send(messageString);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
81
99
|
connectClient(socket) {
|
82
100
|
const id = this.getId();
|
83
101
|
console.log(`Client ID: ${id} joined, waiting for user-identification`);
|
@@ -109,13 +127,16 @@ var UserNetworkingServer = class {
|
|
109
127
|
return;
|
110
128
|
}
|
111
129
|
if (!client.authenticatedUser) {
|
112
|
-
if (parsed.type ===
|
130
|
+
if (parsed.type === USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE) {
|
113
131
|
this.handleUserAuth(client, parsed).then((authResult) => {
|
114
132
|
var _a, _b;
|
133
|
+
if (client.socket.readyState !== WebSocketOpenStatus) {
|
134
|
+
return;
|
135
|
+
}
|
115
136
|
if (!authResult) {
|
116
137
|
const serverError = JSON.stringify({
|
117
|
-
type:
|
118
|
-
errorType:
|
138
|
+
type: USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,
|
139
|
+
errorType: USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE,
|
119
140
|
message: "Authentication failed"
|
120
141
|
});
|
121
142
|
socket.send(serverError);
|
@@ -123,8 +144,8 @@ var UserNetworkingServer = class {
|
|
123
144
|
} else {
|
124
145
|
if (this.options.connectionLimit !== void 0 && this.authenticatedClientsById.size >= this.options.connectionLimit) {
|
125
146
|
const serverError = JSON.stringify({
|
126
|
-
type:
|
127
|
-
errorType:
|
147
|
+
type: USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,
|
148
|
+
errorType: USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE,
|
128
149
|
message: "Connection limit reached"
|
129
150
|
});
|
130
151
|
socket.send(serverError);
|
@@ -132,16 +153,17 @@ var UserNetworkingServer = class {
|
|
132
153
|
return;
|
133
154
|
}
|
134
155
|
const userData = authResult;
|
156
|
+
client.authenticatedUser = userData;
|
135
157
|
const userProfileMessage = JSON.stringify({
|
136
158
|
id: client.id,
|
137
|
-
type:
|
159
|
+
type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
138
160
|
username: userData.username,
|
139
161
|
characterDescription: userData.characterDescription
|
140
162
|
});
|
141
163
|
client.socket.send(userProfileMessage);
|
142
164
|
const identityMessage = JSON.stringify({
|
143
165
|
id: client.id,
|
144
|
-
type:
|
166
|
+
type: USER_NETWORKING_IDENTITY_MESSAGE_TYPE
|
145
167
|
});
|
146
168
|
client.socket.send(identityMessage);
|
147
169
|
const userUpdateMessage = UserNetworkingCodec.encodeUpdate(client.update);
|
@@ -152,7 +174,7 @@ var UserNetworkingServer = class {
|
|
152
174
|
client.socket.send(
|
153
175
|
JSON.stringify({
|
154
176
|
id: otherClient.update.id,
|
155
|
-
type:
|
177
|
+
type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
156
178
|
username: (_a = otherClient.authenticatedUser) == null ? void 0 : _a.username,
|
157
179
|
characterDescription: (_b = otherClient.authenticatedUser) == null ? void 0 : _b.characterDescription
|
158
180
|
})
|
@@ -170,10 +192,10 @@ var UserNetworkingServer = class {
|
|
170
192
|
}
|
171
193
|
} else {
|
172
194
|
switch (parsed.type) {
|
173
|
-
case
|
195
|
+
case USER_NETWORKING_PONG_MESSAGE_TYPE:
|
174
196
|
client.lastPong = Date.now();
|
175
197
|
break;
|
176
|
-
case
|
198
|
+
case USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE:
|
177
199
|
this.handleUserUpdate(id, parsed);
|
178
200
|
break;
|
179
201
|
default:
|
@@ -197,7 +219,7 @@ var UserNetworkingServer = class {
|
|
197
219
|
this.authenticatedClientsById.delete(client.id);
|
198
220
|
const disconnectMessage = JSON.stringify({
|
199
221
|
id: client.id,
|
200
|
-
type:
|
222
|
+
type: USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE
|
201
223
|
});
|
202
224
|
for (const [, otherClient] of this.authenticatedClientsById) {
|
203
225
|
if (otherClient.socket.readyState === WebSocketOpenStatus) {
|
@@ -223,7 +245,6 @@ var UserNetworkingServer = class {
|
|
223
245
|
return false;
|
224
246
|
}
|
225
247
|
console.log("Client authenticated", client.id, resolvedUserData);
|
226
|
-
client.authenticatedUser = resolvedUserData;
|
227
248
|
return resolvedUserData;
|
228
249
|
}
|
229
250
|
updateUserCharacter(clientId, userData) {
|
@@ -235,7 +256,7 @@ var UserNetworkingServer = class {
|
|
235
256
|
this.authenticatedClientsById.set(clientId, client);
|
236
257
|
const newUserData = JSON.stringify({
|
237
258
|
id: clientId,
|
238
|
-
type:
|
259
|
+
type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
239
260
|
username: userData.username,
|
240
261
|
characterDescription: userData.characterDescription
|
241
262
|
});
|
@@ -278,6 +299,18 @@ var UserNetworkingServer = class {
|
|
278
299
|
}
|
279
300
|
}
|
280
301
|
}
|
302
|
+
dispose(clientCloseError) {
|
303
|
+
clearInterval(this.sendUpdatesIntervalTimer);
|
304
|
+
clearInterval(this.pingClientsIntervalTimer);
|
305
|
+
clearInterval(this.heartbeatIntervalTimer);
|
306
|
+
const stringifiedError = clientCloseError ? JSON.stringify(clientCloseError) : void 0;
|
307
|
+
for (const [, client] of this.authenticatedClientsById) {
|
308
|
+
if (stringifiedError) {
|
309
|
+
client.socket.send(stringifiedError);
|
310
|
+
}
|
311
|
+
client.socket.close();
|
312
|
+
}
|
313
|
+
}
|
281
314
|
};
|
282
315
|
|
283
316
|
// src/ReconnectingWebSocket.ts
|
@@ -433,7 +466,7 @@ var UserNetworkingClient = class extends ReconnectingWebSocket {
|
|
433
466
|
super(config.url, config.websocketFactory, (status) => {
|
434
467
|
if (status === 1 /* Connected */) {
|
435
468
|
this.sendMessage({
|
436
|
-
type:
|
469
|
+
type: USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE,
|
437
470
|
sessionToken: config.sessionToken
|
438
471
|
});
|
439
472
|
}
|
@@ -452,26 +485,37 @@ var UserNetworkingClient = class extends ReconnectingWebSocket {
|
|
452
485
|
if (typeof message.data === "string") {
|
453
486
|
const parsed = JSON.parse(message.data);
|
454
487
|
switch (parsed.type) {
|
455
|
-
case
|
488
|
+
case USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE:
|
456
489
|
console.error(`Server error: ${parsed.message}. errorType: ${parsed.errorType}`);
|
457
490
|
this.config.onServerError(parsed);
|
458
491
|
break;
|
459
|
-
case
|
492
|
+
case USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE:
|
460
493
|
console.log(`Client ID: ${parsed.id} left`);
|
461
494
|
this.config.clientUpdate(parsed.id, null);
|
462
495
|
break;
|
463
|
-
case
|
496
|
+
case USER_NETWORKING_IDENTITY_MESSAGE_TYPE:
|
464
497
|
console.log(`Client ID: ${parsed.id} assigned to self`);
|
465
498
|
this.config.assignedIdentity(parsed.id);
|
466
499
|
break;
|
467
|
-
case
|
500
|
+
case USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE:
|
468
501
|
console.log(`Client ID: ${parsed.id} updated profile`);
|
469
502
|
this.config.clientProfileUpdated(parsed.id, parsed.username, parsed.characterDescription);
|
470
503
|
break;
|
471
|
-
case
|
504
|
+
case USER_NETWORKING_PING_MESSAGE_TYPE: {
|
472
505
|
this.sendMessage({ type: "pong" });
|
473
506
|
break;
|
474
507
|
}
|
508
|
+
case USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE: {
|
509
|
+
if (this.config.onServerBroadcast) {
|
510
|
+
this.config.onServerBroadcast({
|
511
|
+
broadcastType: parsed.broadcastType,
|
512
|
+
payload: parsed.payload
|
513
|
+
});
|
514
|
+
} else {
|
515
|
+
console.warn("Unhandled broadcast", parsed);
|
516
|
+
}
|
517
|
+
break;
|
518
|
+
}
|
475
519
|
default:
|
476
520
|
console.error("Unhandled message", parsed);
|
477
521
|
}
|
@@ -484,17 +528,20 @@ var UserNetworkingClient = class extends ReconnectingWebSocket {
|
|
484
528
|
}
|
485
529
|
};
|
486
530
|
export {
|
487
|
-
AUTHENTICATION_FAILED_ERROR_TYPE,
|
488
|
-
CONNECTION_LIMIT_REACHED_ERROR_TYPE,
|
489
|
-
DISCONNECTED_MESSAGE_TYPE,
|
490
|
-
IDENTITY_MESSAGE_TYPE,
|
491
|
-
PING_MESSAGE_TYPE,
|
492
|
-
PONG_MESSAGE_TYPE,
|
493
531
|
ReconnectingWebSocket,
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
532
|
+
USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE,
|
533
|
+
USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE,
|
534
|
+
USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE,
|
535
|
+
USER_NETWORKING_IDENTITY_MESSAGE_TYPE,
|
536
|
+
USER_NETWORKING_PING_MESSAGE_TYPE,
|
537
|
+
USER_NETWORKING_PONG_MESSAGE_TYPE,
|
538
|
+
USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE,
|
539
|
+
USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,
|
540
|
+
USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE,
|
541
|
+
USER_NETWORKING_UNKNOWN_ERROR,
|
542
|
+
USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE,
|
543
|
+
USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,
|
544
|
+
USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE,
|
498
545
|
UserNetworkingClient,
|
499
546
|
UserNetworkingCodec,
|
500
547
|
UserNetworkingServer,
|
package/build/index.js.map
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../src/UserNetworkingCodec.ts", "../src/user-networking-settings.ts", "../src/UserNetworkingMessages.ts", "../src/UserNetworkingServer.ts", "../src/ReconnectingWebSocket.ts", "../src/UserNetworkingClient.ts"],
|
4
|
-
"sourcesContent": ["export type UserNetworkingClientUpdate = {\n id: number;\n position: { x: number; y: number; z: number };\n rotation: { quaternionY: number; quaternionW: number };\n state: number;\n};\n\nexport class UserNetworkingCodec {\n static encodeUpdate(update: UserNetworkingClientUpdate): Uint8Array {\n const buffer = new ArrayBuffer(19);\n const dataView = new DataView(buffer);\n dataView.setUint16(0, update.id); // id\n dataView.setFloat32(2, update.position.x); // position.x\n dataView.setFloat32(6, update.position.y); // position.y\n dataView.setFloat32(10, update.position.z); // position.z\n dataView.setInt16(14, update.rotation.quaternionY * 32767); // quaternion.y\n dataView.setInt16(16, update.rotation.quaternionW * 32767); // quaternion.w\n dataView.setUint8(18, update.state); // animationState\n return new Uint8Array(buffer);\n }\n\n static decodeUpdate(buffer: ArrayBuffer): UserNetworkingClientUpdate {\n const dataView = new DataView(buffer);\n const id = dataView.getUint16(0); // id\n const x = dataView.getFloat32(2); // position.x\n const y = dataView.getFloat32(6); // position.y\n const z = dataView.getFloat32(10); // position.z\n const quaternionY = dataView.getInt16(14) / 32767; // quaternion.y\n const quaternionW = dataView.getInt16(16) / 32767; // quaternion.w\n const state = dataView.getUint8(18); // animationState\n const position = { x, y, z };\n const rotation = { quaternionY, quaternionW };\n return { id, position, rotation, state };\n }\n}\n", "export const pingPongRate: number = 1500;\nexport const heartBeatRate: number = 15000;\nexport const packetsUpdateRate: number = (1 / 30) * 1000;\n", "export const DISCONNECTED_MESSAGE_TYPE = \"disconnected\";\nexport const IDENTITY_MESSAGE_TYPE = \"identity\";\nexport const USER_AUTHENTICATE_MESSAGE_TYPE = \"user_auth\";\nexport const USER_PROFILE_MESSAGE_TYPE = \"user_profile\";\nexport const USER_UPDATE_MESSAGE_TYPE = \"user_update\";\nexport const SERVER_ERROR_MESSAGE_TYPE = \"error\";\nexport const PING_MESSAGE_TYPE = \"ping\";\nexport const PONG_MESSAGE_TYPE = \"pong\";\n\nexport type IdentityMessage = {\n type: typeof IDENTITY_MESSAGE_TYPE;\n id: number;\n};\n\nexport type CharacterDescription = {\n meshFileUrl?: string;\n mmlCharacterUrl?: string;\n mmlCharacterString?: string;\n} & (\n | {\n meshFileUrl: string;\n }\n | {\n mmlCharacterUrl: string;\n }\n | {\n mmlCharacterString: string;\n }\n);\n\nexport type UserProfileMessage = {\n type: typeof USER_PROFILE_MESSAGE_TYPE;\n id: number;\n username: string;\n characterDescription: CharacterDescription;\n};\n\nexport type DisconnectedMessage = {\n type: typeof DISCONNECTED_MESSAGE_TYPE;\n id: number;\n};\n\nexport const CONNECTION_LIMIT_REACHED_ERROR_TYPE = \"CONNECTION_LIMIT_REACHED\";\nexport const AUTHENTICATION_FAILED_ERROR_TYPE = \"AUTHENTICATION_FAILED\";\n\nexport type ServerErrorType =\n | typeof CONNECTION_LIMIT_REACHED_ERROR_TYPE\n | typeof AUTHENTICATION_FAILED_ERROR_TYPE;\n\nexport type ServerError = {\n type: typeof SERVER_ERROR_MESSAGE_TYPE;\n errorType: ServerErrorType;\n message: string;\n};\n\nexport type FromServerPingMessage = {\n type: typeof PING_MESSAGE_TYPE;\n};\n\nexport type FromServerMessage =\n | IdentityMessage\n | UserProfileMessage\n | DisconnectedMessage\n | FromServerPingMessage\n | ServerError;\n\nexport type FromClientPongMessage = {\n type: typeof PONG_MESSAGE_TYPE;\n};\n\nexport type UserIdentity = {\n characterDescription: CharacterDescription | null;\n username: string | null;\n};\n\nexport type UserAuthenticateMessage = {\n type: typeof USER_AUTHENTICATE_MESSAGE_TYPE;\n sessionToken: string;\n // The client can send a UserIdentity to use as the initial user profile and the server can choose to accept it or not\n userIdentity?: UserIdentity;\n};\n\nexport type UserUpdateMessage = {\n type: typeof USER_UPDATE_MESSAGE_TYPE;\n userIdentity: UserIdentity;\n};\n\nexport type FromClientMessage = FromClientPongMessage | UserAuthenticateMessage | UserUpdateMessage;\n", "import WebSocket from \"ws\";\n\nimport { heartBeatRate, packetsUpdateRate, pingPongRate } from \"./user-networking-settings\";\nimport { UserData } from \"./UserData\";\nimport { UserNetworkingClientUpdate, UserNetworkingCodec } from \"./UserNetworkingCodec\";\nimport {\n AUTHENTICATION_FAILED_ERROR_TYPE,\n CONNECTION_LIMIT_REACHED_ERROR_TYPE,\n DISCONNECTED_MESSAGE_TYPE,\n FromClientMessage,\n FromServerMessage,\n IDENTITY_MESSAGE_TYPE,\n PONG_MESSAGE_TYPE,\n SERVER_ERROR_MESSAGE_TYPE,\n USER_AUTHENTICATE_MESSAGE_TYPE,\n USER_PROFILE_MESSAGE_TYPE,\n USER_UPDATE_MESSAGE_TYPE as USER_UPDATE_MESSAGE_TYPE,\n UserAuthenticateMessage,\n UserIdentity,\n UserUpdateMessage,\n} from \"./UserNetworkingMessages\";\n\nexport type Client = {\n socket: WebSocket;\n id: number;\n lastPong: number;\n update: UserNetworkingClientUpdate;\n authenticatedUser: UserData | null;\n};\n\nconst WebSocketOpenStatus = 1;\n\nexport type UserNetworkingServerOptions = {\n connectionLimit?: number;\n onClientConnect: (\n clientId: number,\n sessionToken: string,\n userIdentity?: UserIdentity,\n ) => Promise<UserData | null> | UserData | null;\n onClientUserIdentityUpdate: (\n clientId: number,\n userIdentity: UserIdentity,\n ) => Promise<UserData | null> | UserData | null;\n onClientDisconnect: (clientId: number) => void;\n};\n\nexport class UserNetworkingServer {\n private allClientsById = new Map<number, Client>();\n private authenticatedClientsById: Map<number, Client> = new Map();\n\n constructor(private options: UserNetworkingServerOptions) {\n setInterval(this.sendUpdates.bind(this), packetsUpdateRate);\n setInterval(this.pingClients.bind(this), pingPongRate);\n setInterval(this.heartBeat.bind(this), heartBeatRate);\n }\n\n private heartBeat() {\n const now = Date.now();\n this.allClientsById.forEach((client) => {\n if (now - client.lastPong > heartBeatRate) {\n client.socket.close();\n this.handleDisconnectedClient(client);\n }\n });\n }\n\n private pingClients() {\n this.authenticatedClientsById.forEach((client) => {\n if (client.socket.readyState === WebSocketOpenStatus) {\n client.socket.send(JSON.stringify({ type: \"ping\" } as FromServerMessage));\n }\n });\n }\n\n private getId(): number {\n let id = 1;\n while (this.allClientsById.has(id)) {\n id++;\n }\n return id;\n }\n\n public connectClient(socket: WebSocket) {\n const id = this.getId();\n console.log(`Client ID: ${id} joined, waiting for user-identification`);\n\n // Create a client but without user information\n const client: Client = {\n id,\n lastPong: Date.now(),\n socket: socket as WebSocket,\n authenticatedUser: null,\n update: {\n id,\n position: { x: 0, y: 0, z: 0 },\n rotation: { quaternionY: 0, quaternionW: 1 },\n state: 0,\n },\n };\n this.allClientsById.set(id, client);\n\n socket.on(\"message\", (message: WebSocket.Data, _isBinary: boolean) => {\n if (message instanceof Buffer) {\n const arrayBuffer = new Uint8Array(message).buffer;\n const update = UserNetworkingCodec.decodeUpdate(arrayBuffer);\n update.id = id;\n client.update = update;\n } else {\n let parsed;\n try {\n parsed = JSON.parse(message as string) as FromClientMessage;\n } catch (e) {\n console.error(\"Error parsing JSON message\", message, e);\n return;\n }\n if (!client.authenticatedUser) {\n if (parsed.type === USER_AUTHENTICATE_MESSAGE_TYPE) {\n this.handleUserAuth(client, parsed).then((authResult) => {\n if (!authResult) {\n // If the user is not authorized, disconnect the client\n const serverError = JSON.stringify({\n type: SERVER_ERROR_MESSAGE_TYPE,\n errorType: AUTHENTICATION_FAILED_ERROR_TYPE,\n message: \"Authentication failed\",\n } as FromServerMessage);\n socket.send(serverError);\n socket.close();\n } else {\n if (\n this.options.connectionLimit !== undefined &&\n this.authenticatedClientsById.size >= this.options.connectionLimit\n ) {\n // There is a connection limit and it has been met - disconnect the user\n const serverError = JSON.stringify({\n type: SERVER_ERROR_MESSAGE_TYPE,\n errorType: CONNECTION_LIMIT_REACHED_ERROR_TYPE,\n message: \"Connection limit reached\",\n } as FromServerMessage);\n socket.send(serverError);\n socket.close();\n return;\n }\n\n const userData = authResult;\n\n // Give the client its own profile\n const userProfileMessage = JSON.stringify({\n id: client.id,\n type: USER_PROFILE_MESSAGE_TYPE,\n username: userData.username,\n characterDescription: userData.characterDescription,\n } as FromServerMessage);\n client.socket.send(userProfileMessage);\n\n // Give the client its own identity\n const identityMessage = JSON.stringify({\n id: client.id,\n type: IDENTITY_MESSAGE_TYPE,\n } as FromServerMessage);\n client.socket.send(identityMessage);\n\n const userUpdateMessage = UserNetworkingCodec.encodeUpdate(client.update);\n\n // Send information about all other clients to the freshly connected client and vice versa\n for (const [, otherClient] of this.authenticatedClientsById) {\n if (\n otherClient.socket.readyState !== WebSocketOpenStatus ||\n otherClient === client\n ) {\n // Do not send updates for any clients which have not yet authenticated or not yet connected\n continue;\n }\n // Send the character information\n client.socket.send(\n JSON.stringify({\n id: otherClient.update.id,\n type: USER_PROFILE_MESSAGE_TYPE,\n username: otherClient.authenticatedUser?.username,\n characterDescription: otherClient.authenticatedUser?.characterDescription,\n } as FromServerMessage),\n );\n client.socket.send(UserNetworkingCodec.encodeUpdate(otherClient.update));\n\n otherClient.socket.send(userProfileMessage);\n otherClient.socket.send(userUpdateMessage);\n }\n\n this.authenticatedClientsById.set(id, client);\n }\n });\n } else {\n console.error(`Unhandled message pre-auth: ${JSON.stringify(parsed)}`);\n socket.close();\n }\n } else {\n switch (parsed.type) {\n case PONG_MESSAGE_TYPE:\n client.lastPong = Date.now();\n break;\n\n case USER_UPDATE_MESSAGE_TYPE:\n this.handleUserUpdate(id, parsed as UserUpdateMessage);\n break;\n\n default:\n console.error(`Unhandled message: ${JSON.stringify(parsed)}`);\n }\n }\n }\n });\n\n socket.on(\"close\", () => {\n console.log(\"Client disconnected\", id);\n this.handleDisconnectedClient(client);\n });\n }\n\n private handleDisconnectedClient(client: Client) {\n if (!this.allClientsById.has(client.id)) {\n return;\n }\n this.allClientsById.delete(client.id);\n if (client.authenticatedUser !== null) {\n // Only report disconnections of clients that were authenticated\n this.options.onClientDisconnect(client.id);\n this.authenticatedClientsById.delete(client.id);\n const disconnectMessage = JSON.stringify({\n id: client.id,\n type: DISCONNECTED_MESSAGE_TYPE,\n } as FromServerMessage);\n for (const [, otherClient] of this.authenticatedClientsById) {\n if (otherClient.socket.readyState === WebSocketOpenStatus) {\n otherClient.socket.send(disconnectMessage);\n }\n }\n }\n }\n\n private async handleUserAuth(\n client: Client,\n credentials: UserAuthenticateMessage,\n ): Promise<false | UserData> {\n const userData = this.options.onClientConnect(\n client.id,\n credentials.sessionToken,\n credentials.userIdentity,\n );\n let resolvedUserData;\n if (userData instanceof Promise) {\n resolvedUserData = await userData;\n } else {\n resolvedUserData = userData;\n }\n if (resolvedUserData === null) {\n console.error(`Client-id ${client.id} user_auth unauthorized and ignored`);\n return false;\n }\n\n console.log(\"Client authenticated\", client.id, resolvedUserData);\n client.authenticatedUser = resolvedUserData;\n\n return resolvedUserData;\n }\n\n public updateUserCharacter(clientId: number, userData: UserData) {\n this.internalUpdateUser(clientId, userData);\n }\n\n private internalUpdateUser(clientId: number, userData: UserData) {\n // This function assumes authorization has already been done\n const client = this.authenticatedClientsById.get(clientId)!;\n\n client.authenticatedUser = userData;\n this.authenticatedClientsById.set(clientId, client);\n\n const newUserData = JSON.stringify({\n id: clientId,\n type: USER_PROFILE_MESSAGE_TYPE,\n username: userData.username,\n characterDescription: userData.characterDescription,\n } as FromServerMessage);\n\n // Broadcast the new userdata to all sockets, INCLUDING the user of the calling socket\n // Clients will always render based on the public userProfile.\n // This makes it intuitive, as it is \"what you see is what other's see\" from a user's perspective.\n for (const [otherClientId, otherClient] of this.authenticatedClientsById) {\n if (otherClient.socket.readyState === WebSocketOpenStatus) {\n otherClient.socket.send(newUserData);\n }\n }\n }\n\n private async handleUserUpdate(clientId: number, message: UserUpdateMessage): Promise<void> {\n const client = this.authenticatedClientsById.get(clientId);\n if (!client) {\n console.error(`Client-id ${clientId} user_update ignored, client not found`);\n return;\n }\n\n // Verify using the user authenticator what the allowed version of this update is\n const authorizedUserData = this.options.onClientUserIdentityUpdate(\n clientId,\n message.userIdentity,\n );\n\n let resolvedAuthorizedUserData;\n if (authorizedUserData instanceof Promise) {\n resolvedAuthorizedUserData = await authorizedUserData;\n } else {\n resolvedAuthorizedUserData = authorizedUserData;\n }\n if (!resolvedAuthorizedUserData) {\n // TODO - inform the client about the unauthorized update\n console.warn(`Client-id ${clientId} user_update unauthorized and ignored`);\n return;\n }\n\n this.internalUpdateUser(clientId, resolvedAuthorizedUserData);\n }\n\n private sendUpdates(): void {\n for (const [clientId, client] of this.authenticatedClientsById) {\n const update = client.update;\n const encodedUpdate = UserNetworkingCodec.encodeUpdate(update);\n\n for (const [otherClientId, otherClient] of this.authenticatedClientsById) {\n if (otherClientId !== clientId && otherClient.socket.readyState === WebSocketOpenStatus) {\n otherClient.socket.send(encodedUpdate);\n }\n }\n }\n }\n}\n", "import { UserNetworkingClientUpdate, UserNetworkingCodec } from \"./UserNetworkingCodec\";\n\nexport type WebsocketFactory = (url: string) => WebSocket;\n\nexport enum WebsocketStatus {\n Connecting,\n Connected,\n Reconnecting,\n Disconnected,\n}\n\nconst startingBackoffTimeMilliseconds = 100;\nconst maximumBackoffTimeMilliseconds = 10000;\nconst maximumWebsocketConnectionTimeout = 5000;\n\nexport abstract class ReconnectingWebSocket {\n private websocket: WebSocket | null = null;\n private status: WebsocketStatus | null = null;\n private receivedMessageSinceOpen = false;\n private backoffTime = startingBackoffTimeMilliseconds;\n private stopped = false;\n\n constructor(\n private url: string,\n private websocketFactory: WebsocketFactory,\n private statusUpdateCallback: (status: WebsocketStatus) => void,\n ) {\n this.setStatus(WebsocketStatus.Connecting);\n this.startWebSocketConnectionAttempt();\n }\n\n private setStatus(status: WebsocketStatus) {\n if (this.status !== status) {\n this.status = status;\n this.statusUpdateCallback(status);\n }\n }\n\n public sendUpdate(update: UserNetworkingClientUpdate): void {\n if (!this.websocket) {\n console.error(\"Not connected to the server\");\n return;\n }\n const encodedUpdate = UserNetworkingCodec.encodeUpdate(update);\n this.send(encodedUpdate);\n }\n\n private async startWebSocketConnectionAttempt() {\n if (this.stopped) {\n return;\n }\n // eslint-disable-next-line no-constant-condition\n while (true) {\n if (this.stopped) {\n return;\n }\n try {\n await this.createWebsocketWithTimeout(maximumWebsocketConnectionTimeout);\n break;\n } catch (e) {\n // Connection failed, retry with backoff\n this.setStatus(WebsocketStatus.Reconnecting);\n await this.waitBackoffTime();\n }\n }\n }\n\n private async waitBackoffTime(): Promise<void> {\n console.warn(`Websocket connection to '${this.url}' failed: retrying in ${this.backoffTime}ms`);\n await new Promise((resolve) => setTimeout(resolve, this.backoffTime));\n this.backoffTime = Math.min(\n // Introduce a small amount of randomness to prevent clients from retrying in lockstep\n this.backoffTime * (1.5 + Math.random() * 0.5),\n maximumBackoffTimeMilliseconds,\n );\n }\n\n protected abstract handleIncomingWebsocketMessage(message: MessageEvent): void;\n\n protected send(message: object | Uint8Array): void {\n if (!this.websocket) {\n console.error(\"Not connected to the server\");\n return;\n }\n if (message instanceof Uint8Array) {\n this.websocket.send(message);\n } else {\n this.websocket.send(JSON.stringify(message));\n }\n }\n\n private createWebsocketWithTimeout(timeout: number): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(new Error(\"websocket connection timed out\"));\n }, timeout);\n const websocket = this.websocketFactory(this.url);\n websocket.binaryType = \"arraybuffer\";\n websocket.addEventListener(\"open\", () => {\n clearTimeout(timeoutId);\n this.receivedMessageSinceOpen = false;\n this.websocket = websocket;\n this.setStatus(WebsocketStatus.Connected);\n\n websocket.addEventListener(\"message\", (event) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket message event because it is no longer current\");\n websocket.close();\n return;\n }\n if (!this.receivedMessageSinceOpen) {\n this.receivedMessageSinceOpen = true;\n }\n this.handleIncomingWebsocketMessage(event);\n });\n\n const onWebsocketClose = async () => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket close event because it is no longer current\");\n return;\n }\n this.websocket = null;\n if (this.stopped) {\n // This closing is expected. The client closed the websocket.\n this.setStatus(WebsocketStatus.Disconnected);\n return;\n }\n if (!this.receivedMessageSinceOpen) {\n // The websocket did not deliver any contents. It may have been successfully opened, but immediately closed. This client should back off to prevent this happening in a rapid loop.\n await this.waitBackoffTime();\n }\n // The websocket closed unexpectedly. Try to reconnect.\n this.setStatus(WebsocketStatus.Reconnecting);\n this.startWebSocketConnectionAttempt();\n };\n\n websocket.addEventListener(\"close\", (e) => {\n if (websocket !== this.websocket) {\n console.warn(\"Ignoring websocket close event because it is no longer current\");\n return;\n }\n console.log(\"ReconnectingWebSocket close\", e);\n onWebsocketClose();\n });\n websocket.addEventListener(\"error\", (e) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket error event because it is no longer current\");\n return;\n }\n console.error(\"ReconnectingWebSocket error\", e);\n onWebsocketClose();\n });\n\n resolve(websocket);\n });\n websocket.addEventListener(\"error\", (e) => {\n clearTimeout(timeoutId);\n reject(e);\n });\n });\n }\n\n public stop() {\n this.stopped = true;\n if (this.websocket !== null) {\n this.websocket.close();\n this.websocket = null;\n }\n }\n}\n", "import { ReconnectingWebSocket, WebsocketFactory, WebsocketStatus } from \"./ReconnectingWebSocket\";\nimport { UserNetworkingClientUpdate, UserNetworkingCodec } from \"./UserNetworkingCodec\";\nimport {\n CharacterDescription,\n DISCONNECTED_MESSAGE_TYPE,\n FromClientMessage,\n FromServerMessage,\n IDENTITY_MESSAGE_TYPE,\n PING_MESSAGE_TYPE,\n SERVER_ERROR_MESSAGE_TYPE,\n ServerErrorType,\n USER_AUTHENTICATE_MESSAGE_TYPE,\n USER_PROFILE_MESSAGE_TYPE,\n} from \"./UserNetworkingMessages\";\n\nexport type UserNetworkingClientConfig = {\n url: string;\n sessionToken: string;\n websocketFactory: WebsocketFactory;\n statusUpdateCallback: (status: WebsocketStatus) => void;\n assignedIdentity: (clientId: number) => void;\n clientUpdate: (id: number, update: null | UserNetworkingClientUpdate) => void;\n clientProfileUpdated: (\n id: number,\n username: string,\n characterDescription: CharacterDescription,\n ) => void;\n onServerError: (error: { message: string; errorType: ServerErrorType }) => void;\n};\n\nexport class UserNetworkingClient extends ReconnectingWebSocket {\n constructor(private config: UserNetworkingClientConfig) {\n super(config.url, config.websocketFactory, (status: WebsocketStatus) => {\n if (status === WebsocketStatus.Connected) {\n this.sendMessage({\n type: USER_AUTHENTICATE_MESSAGE_TYPE,\n sessionToken: config.sessionToken,\n });\n }\n config.statusUpdateCallback(status);\n });\n }\n\n public sendUpdate(update: UserNetworkingClientUpdate): void {\n const encodedUpdate = UserNetworkingCodec.encodeUpdate(update);\n this.send(encodedUpdate);\n }\n\n public sendMessage(message: FromClientMessage): void {\n this.send(message);\n }\n\n protected handleIncomingWebsocketMessage(message: MessageEvent) {\n if (typeof message.data === \"string\") {\n const parsed = JSON.parse(message.data) as FromServerMessage;\n switch (parsed.type) {\n case SERVER_ERROR_MESSAGE_TYPE:\n console.error(`Server error: ${parsed.message}. errorType: ${parsed.errorType}`);\n this.config.onServerError(parsed);\n break;\n case DISCONNECTED_MESSAGE_TYPE:\n console.log(`Client ID: ${parsed.id} left`);\n this.config.clientUpdate(parsed.id, null);\n break;\n case IDENTITY_MESSAGE_TYPE:\n console.log(`Client ID: ${parsed.id} assigned to self`);\n this.config.assignedIdentity(parsed.id);\n break;\n case USER_PROFILE_MESSAGE_TYPE:\n console.log(`Client ID: ${parsed.id} updated profile`);\n this.config.clientProfileUpdated(parsed.id, parsed.username, parsed.characterDescription);\n break;\n case PING_MESSAGE_TYPE: {\n this.sendMessage({ type: \"pong\" } as FromClientMessage);\n break;\n }\n default:\n console.error(\"Unhandled message\", parsed);\n }\n } else if (message.data instanceof ArrayBuffer) {\n const userNetworkingClientUpdate = UserNetworkingCodec.decodeUpdate(message.data);\n this.config.clientUpdate(userNetworkingClientUpdate.id, userNetworkingClientUpdate);\n } else {\n console.error(\"Unhandled message type\", message.data);\n }\n }\n}\n"],
|
5
|
-
"mappings": ";AAOO,IAAM,sBAAN,MAA0B;AAAA,EAC/B,OAAO,aAAa,QAAgD;AAClE,UAAM,SAAS,IAAI,YAAY,EAAE;AACjC,UAAM,WAAW,IAAI,SAAS,MAAM;AACpC,aAAS,UAAU,GAAG,OAAO,EAAE;AAC/B,aAAS,WAAW,GAAG,OAAO,SAAS,CAAC;AACxC,aAAS,WAAW,GAAG,OAAO,SAAS,CAAC;AACxC,aAAS,WAAW,IAAI,OAAO,SAAS,CAAC;AACzC,aAAS,SAAS,IAAI,OAAO,SAAS,cAAc,KAAK;AACzD,aAAS,SAAS,IAAI,OAAO,SAAS,cAAc,KAAK;AACzD,aAAS,SAAS,IAAI,OAAO,KAAK;AAClC,WAAO,IAAI,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEA,OAAO,aAAa,QAAiD;AACnE,UAAM,WAAW,IAAI,SAAS,MAAM;AACpC,UAAM,KAAK,SAAS,UAAU,CAAC;AAC/B,UAAM,IAAI,SAAS,WAAW,CAAC;AAC/B,UAAM,IAAI,SAAS,WAAW,CAAC;AAC/B,UAAM,IAAI,SAAS,WAAW,EAAE;AAChC,UAAM,cAAc,SAAS,SAAS,EAAE,IAAI;AAC5C,UAAM,cAAc,SAAS,SAAS,EAAE,IAAI;AAC5C,UAAM,QAAQ,SAAS,SAAS,EAAE;AAClC,UAAM,WAAW,EAAE,GAAG,GAAG,EAAE;AAC3B,UAAM,WAAW,EAAE,aAAa,YAAY;AAC5C,WAAO,EAAE,IAAI,UAAU,UAAU,MAAM;AAAA,EACzC;AACF;;;AClCO,IAAM,eAAuB;AAC7B,IAAM,gBAAwB;AAC9B,IAAM,oBAA6B,IAAI,KAAM;;;ACF7C,IAAM,4BAA4B;AAClC,IAAM,wBAAwB;AAC9B,IAAM,iCAAiC;AACvC,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,4BAA4B;AAClC,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAmC1B,IAAM,sCAAsC;AAC5C,IAAM,mCAAmC;;;ACbhD,IAAM,sBAAsB;AAgBrB,IAAM,uBAAN,MAA2B;AAAA,EAIhC,YAAoB,SAAsC;AAAtC;AAHpB,SAAQ,iBAAiB,oBAAI,IAAoB;AACjD,SAAQ,2BAAgD,oBAAI,IAAI;AAG9D,gBAAY,KAAK,YAAY,KAAK,IAAI,GAAG,iBAAiB;AAC1D,gBAAY,KAAK,YAAY,KAAK,IAAI,GAAG,YAAY;AACrD,gBAAY,KAAK,UAAU,KAAK,IAAI,GAAG,aAAa;AAAA,EACtD;AAAA,EAEQ,YAAY;AAClB,UAAM,MAAM,KAAK,IAAI;AACrB,SAAK,eAAe,QAAQ,CAAC,WAAW;AACtC,UAAI,MAAM,OAAO,WAAW,eAAe;AACzC,eAAO,OAAO,MAAM;AACpB,aAAK,yBAAyB,MAAM;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,cAAc;AACpB,SAAK,yBAAyB,QAAQ,CAAC,WAAW;AAChD,UAAI,OAAO,OAAO,eAAe,qBAAqB;AACpD,eAAO,OAAO,KAAK,KAAK,UAAU,EAAE,MAAM,OAAO,CAAsB,CAAC;AAAA,MAC1E;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,QAAgB;AACtB,QAAI,KAAK;AACT,WAAO,KAAK,eAAe,IAAI,EAAE,GAAG;AAClC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEO,cAAc,QAAmB;AACtC,UAAM,KAAK,KAAK,MAAM;AACtB,YAAQ,IAAI,cAAc,EAAE,0CAA0C;AAGtE,UAAM,SAAiB;AAAA,MACrB;AAAA,MACA,UAAU,KAAK,IAAI;AAAA,MACnB;AAAA,MACA,mBAAmB;AAAA,MACnB,QAAQ;AAAA,QACN;AAAA,QACA,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,QAC7B,UAAU,EAAE,aAAa,GAAG,aAAa,EAAE;AAAA,QAC3C,OAAO;AAAA,MACT;AAAA,IACF;AACA,SAAK,eAAe,IAAI,IAAI,MAAM;AAElC,WAAO,GAAG,WAAW,CAAC,SAAyB,cAAuB;AACpE,UAAI,mBAAmB,QAAQ;AAC7B,cAAM,cAAc,IAAI,WAAW,OAAO,EAAE;AAC5C,cAAM,SAAS,oBAAoB,aAAa,WAAW;AAC3D,eAAO,KAAK;AACZ,eAAO,SAAS;AAAA,MAClB,OAAO;AACL,YAAI;AACJ,YAAI;AACF,mBAAS,KAAK,MAAM,OAAiB;AAAA,QACvC,SAAS,GAAG;AACV,kBAAQ,MAAM,8BAA8B,SAAS,CAAC;AACtD;AAAA,QACF;AACA,YAAI,CAAC,OAAO,mBAAmB;AAC7B,cAAI,OAAO,SAAS,gCAAgC;AAClD,iBAAK,eAAe,QAAQ,MAAM,EAAE,KAAK,CAAC,eAAe;AArHrE;AAsHc,kBAAI,CAAC,YAAY;AAEf,sBAAM,cAAc,KAAK,UAAU;AAAA,kBACjC,MAAM;AAAA,kBACN,WAAW;AAAA,kBACX,SAAS;AAAA,gBACX,CAAsB;AACtB,uBAAO,KAAK,WAAW;AACvB,uBAAO,MAAM;AAAA,cACf,OAAO;AACL,oBACE,KAAK,QAAQ,oBAAoB,UACjC,KAAK,yBAAyB,QAAQ,KAAK,QAAQ,iBACnD;AAEA,wBAAM,cAAc,KAAK,UAAU;AAAA,oBACjC,MAAM;AAAA,oBACN,WAAW;AAAA,oBACX,SAAS;AAAA,kBACX,CAAsB;AACtB,yBAAO,KAAK,WAAW;AACvB,yBAAO,MAAM;AACb;AAAA,gBACF;AAEA,sBAAM,WAAW;AAGjB,sBAAM,qBAAqB,KAAK,UAAU;AAAA,kBACxC,IAAI,OAAO;AAAA,kBACX,MAAM;AAAA,kBACN,UAAU,SAAS;AAAA,kBACnB,sBAAsB,SAAS;AAAA,gBACjC,CAAsB;AACtB,uBAAO,OAAO,KAAK,kBAAkB;AAGrC,sBAAM,kBAAkB,KAAK,UAAU;AAAA,kBACrC,IAAI,OAAO;AAAA,kBACX,MAAM;AAAA,gBACR,CAAsB;AACtB,uBAAO,OAAO,KAAK,eAAe;AAElC,sBAAM,oBAAoB,oBAAoB,aAAa,OAAO,MAAM;AAGxE,2BAAW,CAAC,EAAE,WAAW,KAAK,KAAK,0BAA0B;AAC3D,sBACE,YAAY,OAAO,eAAe,uBAClC,gBAAgB,QAChB;AAEA;AAAA,kBACF;AAEA,yBAAO,OAAO;AAAA,oBACZ,KAAK,UAAU;AAAA,sBACb,IAAI,YAAY,OAAO;AAAA,sBACvB,MAAM;AAAA,sBACN,WAAU,iBAAY,sBAAZ,mBAA+B;AAAA,sBACzC,uBAAsB,iBAAY,sBAAZ,mBAA+B;AAAA,oBACvD,CAAsB;AAAA,kBACxB;AACA,yBAAO,OAAO,KAAK,oBAAoB,aAAa,YAAY,MAAM,CAAC;AAEvE,8BAAY,OAAO,KAAK,kBAAkB;AAC1C,8BAAY,OAAO,KAAK,iBAAiB;AAAA,gBAC3C;AAEA,qBAAK,yBAAyB,IAAI,IAAI,MAAM;AAAA,cAC9C;AAAA,YACF,CAAC;AAAA,UACH,OAAO;AACL,oBAAQ,MAAM,+BAA+B,KAAK,UAAU,MAAM,CAAC,EAAE;AACrE,mBAAO,MAAM;AAAA,UACf;AAAA,QACF,OAAO;AACL,kBAAQ,OAAO,MAAM;AAAA,YACnB,KAAK;AACH,qBAAO,WAAW,KAAK,IAAI;AAC3B;AAAA,YAEF,KAAK;AACH,mBAAK,iBAAiB,IAAI,MAA2B;AACrD;AAAA,YAEF;AACE,sBAAQ,MAAM,sBAAsB,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,UAChE;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO,GAAG,SAAS,MAAM;AACvB,cAAQ,IAAI,uBAAuB,EAAE;AACrC,WAAK,yBAAyB,MAAM;AAAA,IACtC,CAAC;AAAA,EACH;AAAA,EAEQ,yBAAyB,QAAgB;AAC/C,QAAI,CAAC,KAAK,eAAe,IAAI,OAAO,EAAE,GAAG;AACvC;AAAA,IACF;AACA,SAAK,eAAe,OAAO,OAAO,EAAE;AACpC,QAAI,OAAO,sBAAsB,MAAM;AAErC,WAAK,QAAQ,mBAAmB,OAAO,EAAE;AACzC,WAAK,yBAAyB,OAAO,OAAO,EAAE;AAC9C,YAAM,oBAAoB,KAAK,UAAU;AAAA,QACvC,IAAI,OAAO;AAAA,QACX,MAAM;AAAA,MACR,CAAsB;AACtB,iBAAW,CAAC,EAAE,WAAW,KAAK,KAAK,0BAA0B;AAC3D,YAAI,YAAY,OAAO,eAAe,qBAAqB;AACzD,sBAAY,OAAO,KAAK,iBAAiB;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,eACZ,QACA,aAC2B;AAC3B,UAAM,WAAW,KAAK,QAAQ;AAAA,MAC5B,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,YAAY;AAAA,IACd;AACA,QAAI;AACJ,QAAI,oBAAoB,SAAS;AAC/B,yBAAmB,MAAM;AAAA,IAC3B,OAAO;AACL,yBAAmB;AAAA,IACrB;AACA,QAAI,qBAAqB,MAAM;AAC7B,cAAQ,MAAM,aAAa,OAAO,EAAE,qCAAqC;AACzE,aAAO;AAAA,IACT;AAEA,YAAQ,IAAI,wBAAwB,OAAO,IAAI,gBAAgB;AAC/D,WAAO,oBAAoB;AAE3B,WAAO;AAAA,EACT;AAAA,EAEO,oBAAoB,UAAkB,UAAoB;AAC/D,SAAK,mBAAmB,UAAU,QAAQ;AAAA,EAC5C;AAAA,EAEQ,mBAAmB,UAAkB,UAAoB;AAE/D,UAAM,SAAS,KAAK,yBAAyB,IAAI,QAAQ;AAEzD,WAAO,oBAAoB;AAC3B,SAAK,yBAAyB,IAAI,UAAU,MAAM;AAElD,UAAM,cAAc,KAAK,UAAU;AAAA,MACjC,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,UAAU,SAAS;AAAA,MACnB,sBAAsB,SAAS;AAAA,IACjC,CAAsB;AAKtB,eAAW,CAAC,eAAe,WAAW,KAAK,KAAK,0BAA0B;AACxE,UAAI,YAAY,OAAO,eAAe,qBAAqB;AACzD,oBAAY,OAAO,KAAK,WAAW;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,UAAkB,SAA2C;AAC1F,UAAM,SAAS,KAAK,yBAAyB,IAAI,QAAQ;AACzD,QAAI,CAAC,QAAQ;AACX,cAAQ,MAAM,aAAa,QAAQ,wCAAwC;AAC3E;AAAA,IACF;AAGA,UAAM,qBAAqB,KAAK,QAAQ;AAAA,MACtC;AAAA,MACA,QAAQ;AAAA,IACV;AAEA,QAAI;AACJ,QAAI,8BAA8B,SAAS;AACzC,mCAA6B,MAAM;AAAA,IACrC,OAAO;AACL,mCAA6B;AAAA,IAC/B;AACA,QAAI,CAAC,4BAA4B;AAE/B,cAAQ,KAAK,aAAa,QAAQ,uCAAuC;AACzE;AAAA,IACF;AAEA,SAAK,mBAAmB,UAAU,0BAA0B;AAAA,EAC9D;AAAA,EAEQ,cAAoB;AAC1B,eAAW,CAAC,UAAU,MAAM,KAAK,KAAK,0BAA0B;AAC9D,YAAM,SAAS,OAAO;AACtB,YAAM,gBAAgB,oBAAoB,aAAa,MAAM;AAE7D,iBAAW,CAAC,eAAe,WAAW,KAAK,KAAK,0BAA0B;AACxE,YAAI,kBAAkB,YAAY,YAAY,OAAO,eAAe,qBAAqB;AACvF,sBAAY,OAAO,KAAK,aAAa;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACxUO,IAAK,kBAAL,kBAAKA,qBAAL;AACL,EAAAA,kCAAA;AACA,EAAAA,kCAAA;AACA,EAAAA,kCAAA;AACA,EAAAA,kCAAA;AAJU,SAAAA;AAAA,GAAA;AAOZ,IAAM,kCAAkC;AACxC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAEnC,IAAe,wBAAf,MAAqC;AAAA,EAO1C,YACU,KACA,kBACA,sBACR;AAHQ;AACA;AACA;AATV,SAAQ,YAA8B;AACtC,SAAQ,SAAiC;AACzC,SAAQ,2BAA2B;AACnC,SAAQ,cAAc;AACtB,SAAQ,UAAU;AAOhB,SAAK,UAAU,kBAA0B;AACzC,SAAK,gCAAgC;AAAA,EACvC;AAAA,EAEQ,UAAU,QAAyB;AACzC,QAAI,KAAK,WAAW,QAAQ;AAC1B,WAAK,SAAS;AACd,WAAK,qBAAqB,MAAM;AAAA,IAClC;AAAA,EACF;AAAA,EAEO,WAAW,QAA0C;AAC1D,QAAI,CAAC,KAAK,WAAW;AACnB,cAAQ,MAAM,6BAA6B;AAC3C;AAAA,IACF;AACA,UAAM,gBAAgB,oBAAoB,aAAa,MAAM;AAC7D,SAAK,KAAK,aAAa;AAAA,EACzB;AAAA,EAEA,MAAc,kCAAkC;AAC9C,QAAI,KAAK,SAAS;AAChB;AAAA,IACF;AAEA,WAAO,MAAM;AACX,UAAI,KAAK,SAAS;AAChB;AAAA,MACF;AACA,UAAI;AACF,cAAM,KAAK,2BAA2B,iCAAiC;AACvE;AAAA,MACF,SAAS,GAAG;AAEV,aAAK,UAAU,oBAA4B;AAC3C,cAAM,KAAK,gBAAgB;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,kBAAiC;AAC7C,YAAQ,KAAK,4BAA4B,KAAK,GAAG,yBAAyB,KAAK,WAAW,IAAI;AAC9F,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,WAAW,CAAC;AACpE,SAAK,cAAc,KAAK;AAAA;AAAA,MAEtB,KAAK,eAAe,MAAM,KAAK,OAAO,IAAI;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAAA,EAIU,KAAK,SAAoC;AACjD,QAAI,CAAC,KAAK,WAAW;AACnB,cAAQ,MAAM,6BAA6B;AAC3C;AAAA,IACF;AACA,QAAI,mBAAmB,YAAY;AACjC,WAAK,UAAU,KAAK,OAAO;AAAA,IAC7B,OAAO;AACL,WAAK,UAAU,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,IAC7C;AAAA,EACF;AAAA,EAEQ,2BAA2B,SAAqC;AACtE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,YAAY,WAAW,MAAM;AACjC,eAAO,IAAI,MAAM,gCAAgC,CAAC;AAAA,MACpD,GAAG,OAAO;AACV,YAAM,YAAY,KAAK,iBAAiB,KAAK,GAAG;AAChD,gBAAU,aAAa;AACvB,gBAAU,iBAAiB,QAAQ,MAAM;AACvC,qBAAa,SAAS;AACtB,aAAK,2BAA2B;AAChC,aAAK,YAAY;AACjB,aAAK,UAAU,iBAAyB;AAExC,kBAAU,iBAAiB,WAAW,CAAC,UAAU;AAC/C,cAAI,cAAc,KAAK,WAAW;AAChC,oBAAQ,IAAI,kEAAkE;AAC9E,sBAAU,MAAM;AAChB;AAAA,UACF;AACA,cAAI,CAAC,KAAK,0BAA0B;AAClC,iBAAK,2BAA2B;AAAA,UAClC;AACA,eAAK,+BAA+B,KAAK;AAAA,QAC3C,CAAC;AAED,cAAM,mBAAmB,YAAY;AACnC,cAAI,cAAc,KAAK,WAAW;AAChC,oBAAQ,IAAI,gEAAgE;AAC5E;AAAA,UACF;AACA,eAAK,YAAY;AACjB,cAAI,KAAK,SAAS;AAEhB,iBAAK,UAAU,oBAA4B;AAC3C;AAAA,UACF;AACA,cAAI,CAAC,KAAK,0BAA0B;AAElC,kBAAM,KAAK,gBAAgB;AAAA,UAC7B;AAEA,eAAK,UAAU,oBAA4B;AAC3C,eAAK,gCAAgC;AAAA,QACvC;AAEA,kBAAU,iBAAiB,SAAS,CAAC,MAAM;AACzC,cAAI,cAAc,KAAK,WAAW;AAChC,oBAAQ,KAAK,gEAAgE;AAC7E;AAAA,UACF;AACA,kBAAQ,IAAI,+BAA+B,CAAC;AAC5C,2BAAiB;AAAA,QACnB,CAAC;AACD,kBAAU,iBAAiB,SAAS,CAAC,MAAM;AACzC,cAAI,cAAc,KAAK,WAAW;AAChC,oBAAQ,IAAI,gEAAgE;AAC5E;AAAA,UACF;AACA,kBAAQ,MAAM,+BAA+B,CAAC;AAC9C,2BAAiB;AAAA,QACnB,CAAC;AAED,gBAAQ,SAAS;AAAA,MACnB,CAAC;AACD,gBAAU,iBAAiB,SAAS,CAAC,MAAM;AACzC,qBAAa,SAAS;AACtB,eAAO,CAAC;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEO,OAAO;AACZ,SAAK,UAAU;AACf,QAAI,KAAK,cAAc,MAAM;AAC3B,WAAK,UAAU,MAAM;AACrB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AACF;;;AC3IO,IAAM,uBAAN,cAAmC,sBAAsB;AAAA,EAC9D,YAAoB,QAAoC;AACtD,UAAM,OAAO,KAAK,OAAO,kBAAkB,CAAC,WAA4B;AACtE,UAAI,8BAAsC;AACxC,aAAK,YAAY;AAAA,UACf,MAAM;AAAA,UACN,cAAc,OAAO;AAAA,QACvB,CAAC;AAAA,MACH;AACA,aAAO,qBAAqB,MAAM;AAAA,IACpC,CAAC;AATiB;AAAA,EAUpB;AAAA,EAEO,WAAW,QAA0C;AAC1D,UAAM,gBAAgB,oBAAoB,aAAa,MAAM;AAC7D,SAAK,KAAK,aAAa;AAAA,EACzB;AAAA,EAEO,YAAY,SAAkC;AACnD,SAAK,KAAK,OAAO;AAAA,EACnB;AAAA,EAEU,+BAA+B,SAAuB;AAC9D,QAAI,OAAO,QAAQ,SAAS,UAAU;AACpC,YAAM,SAAS,KAAK,MAAM,QAAQ,IAAI;AACtC,cAAQ,OAAO,MAAM;AAAA,QACnB,KAAK;AACH,kBAAQ,MAAM,iBAAiB,OAAO,OAAO,gBAAgB,OAAO,SAAS,EAAE;AAC/E,eAAK,OAAO,cAAc,MAAM;AAChC;AAAA,QACF,KAAK;AACH,kBAAQ,IAAI,cAAc,OAAO,EAAE,OAAO;AAC1C,eAAK,OAAO,aAAa,OAAO,IAAI,IAAI;AACxC;AAAA,QACF,KAAK;AACH,kBAAQ,IAAI,cAAc,OAAO,EAAE,mBAAmB;AACtD,eAAK,OAAO,iBAAiB,OAAO,EAAE;AACtC;AAAA,QACF,KAAK;AACH,kBAAQ,IAAI,cAAc,OAAO,EAAE,kBAAkB;AACrD,eAAK,OAAO,qBAAqB,OAAO,IAAI,OAAO,UAAU,OAAO,oBAAoB;AACxF;AAAA,QACF,KAAK,mBAAmB;AACtB,eAAK,YAAY,EAAE,MAAM,OAAO,CAAsB;AACtD;AAAA,QACF;AAAA,QACA;AACE,kBAAQ,MAAM,qBAAqB,MAAM;AAAA,MAC7C;AAAA,IACF,WAAW,QAAQ,gBAAgB,aAAa;AAC9C,YAAM,6BAA6B,oBAAoB,aAAa,QAAQ,IAAI;AAChF,WAAK,OAAO,aAAa,2BAA2B,IAAI,0BAA0B;AAAA,IACpF,OAAO;AACL,cAAQ,MAAM,0BAA0B,QAAQ,IAAI;AAAA,IACtD;AAAA,EACF;AACF;",
|
4
|
+
"sourcesContent": ["export type UserNetworkingClientUpdate = {\n id: number;\n position: { x: number; y: number; z: number };\n rotation: { quaternionY: number; quaternionW: number };\n state: number;\n};\n\nexport class UserNetworkingCodec {\n static encodeUpdate(update: UserNetworkingClientUpdate): Uint8Array {\n const buffer = new ArrayBuffer(19);\n const dataView = new DataView(buffer);\n dataView.setUint16(0, update.id); // id\n dataView.setFloat32(2, update.position.x); // position.x\n dataView.setFloat32(6, update.position.y); // position.y\n dataView.setFloat32(10, update.position.z); // position.z\n dataView.setInt16(14, update.rotation.quaternionY * 32767); // quaternion.y\n dataView.setInt16(16, update.rotation.quaternionW * 32767); // quaternion.w\n dataView.setUint8(18, update.state); // animationState\n return new Uint8Array(buffer);\n }\n\n static decodeUpdate(buffer: ArrayBuffer): UserNetworkingClientUpdate {\n const dataView = new DataView(buffer);\n const id = dataView.getUint16(0); // id\n const x = dataView.getFloat32(2); // position.x\n const y = dataView.getFloat32(6); // position.y\n const z = dataView.getFloat32(10); // position.z\n const quaternionY = dataView.getInt16(14) / 32767; // quaternion.y\n const quaternionW = dataView.getInt16(16) / 32767; // quaternion.w\n const state = dataView.getUint8(18); // animationState\n const position = { x, y, z };\n const rotation = { quaternionY, quaternionW };\n return { id, position, rotation, state };\n }\n}\n", "export const pingPongRate: number = 1500;\nexport const heartBeatRate: number = 15000;\nexport const packetsUpdateRate: number = (1 / 30) * 1000;\n", "export const USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE = \"disconnected\";\nexport const USER_NETWORKING_IDENTITY_MESSAGE_TYPE = \"identity\";\nexport const USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE = \"user_auth\";\nexport const USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE = \"user_profile\";\nexport const USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE = \"user_update\";\nexport const USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE = \"broadcast\";\nexport const USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE = \"error\";\nexport const USER_NETWORKING_PING_MESSAGE_TYPE = \"ping\";\nexport const USER_NETWORKING_PONG_MESSAGE_TYPE = \"pong\";\n\nexport type UserNetworkingIdentityMessage = {\n type: typeof USER_NETWORKING_IDENTITY_MESSAGE_TYPE;\n id: number;\n};\n\nexport type CharacterDescription = {\n meshFileUrl?: string;\n mmlCharacterUrl?: string;\n mmlCharacterString?: string;\n} & (\n | {\n meshFileUrl: string;\n }\n | {\n mmlCharacterUrl: string;\n }\n | {\n mmlCharacterString: string;\n }\n);\n\nexport type UserNetworkingProfileMessage = {\n type: typeof USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE;\n id: number;\n username: string;\n characterDescription: CharacterDescription;\n};\n\nexport type UserNetworkingDisconnectedMessage = {\n type: typeof USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE;\n id: number;\n};\n\nexport const USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE = \"CONNECTION_LIMIT_REACHED\";\nexport const USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE = \"AUTHENTICATION_FAILED\";\nexport const USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE = \"SERVER_SHUTDOWN\";\nexport const USER_NETWORKING_UNKNOWN_ERROR = \"UNKNOWN_ERROR\";\n\nexport type UserNetworkingServerErrorType =\n | typeof USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE\n | typeof USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE\n | typeof USER_NETWORKING_SERVER_SHUTDOWN_ERROR_TYPE\n | typeof USER_NETWORKING_UNKNOWN_ERROR;\n\nexport type UserNetworkingServerError = {\n type: typeof USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE;\n errorType: UserNetworkingServerErrorType;\n message: string;\n};\n\nexport type UserNetworkingServerBroadcast = {\n type: typeof USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE;\n broadcastType: string;\n payload: any;\n};\n\nexport type UserNetworkingServerPingMessage = {\n type: typeof USER_NETWORKING_PING_MESSAGE_TYPE;\n};\n\nexport type FromUserNetworkingServerMessage =\n | UserNetworkingIdentityMessage\n | UserNetworkingProfileMessage\n | UserNetworkingDisconnectedMessage\n | UserNetworkingServerPingMessage\n | UserNetworkingServerBroadcast\n | UserNetworkingServerError;\n\nexport type UserNetworkingClientPongMessage = {\n type: typeof USER_NETWORKING_PONG_MESSAGE_TYPE;\n};\n\nexport type UserIdentity = {\n characterDescription: CharacterDescription | null;\n username: string | null;\n};\n\nexport type UserNetworkingAuthenticateMessage = {\n type: typeof USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE;\n sessionToken: string;\n // The client can send a UserIdentity to use as the initial user profile and the server can choose to accept it or not\n userIdentity?: UserIdentity;\n};\n\nexport type UserNetworkingUserUpdateMessage = {\n type: typeof USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE;\n userIdentity: UserIdentity;\n};\n\nexport type FromUserNetworkingClientMessage =\n | UserNetworkingClientPongMessage\n | UserNetworkingAuthenticateMessage\n | UserNetworkingUserUpdateMessage;\n", "import WebSocket from \"ws\";\n\nimport { heartBeatRate, packetsUpdateRate, pingPongRate } from \"./user-networking-settings\";\nimport { UserData } from \"./UserData\";\nimport { UserNetworkingClientUpdate, UserNetworkingCodec } from \"./UserNetworkingCodec\";\nimport {\n FromUserNetworkingClientMessage,\n FromUserNetworkingServerMessage,\n USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE,\n USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE,\n USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE,\n USER_NETWORKING_IDENTITY_MESSAGE_TYPE,\n USER_NETWORKING_PONG_MESSAGE_TYPE,\n USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,\n USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE,\n USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,\n USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE,\n UserIdentity,\n UserNetworkingAuthenticateMessage,\n UserNetworkingServerError,\n UserNetworkingUserUpdateMessage,\n} from \"./UserNetworkingMessages\";\n\nexport type UserNetworkingServerClient = {\n socket: WebSocket;\n id: number;\n lastPong: number;\n update: UserNetworkingClientUpdate;\n authenticatedUser: UserData | null;\n};\n\nconst WebSocketOpenStatus = 1;\n\nexport type UserNetworkingServerOptions = {\n connectionLimit?: number;\n onClientConnect: (\n clientId: number,\n sessionToken: string,\n userIdentity?: UserIdentity,\n ) => Promise<UserData | null> | UserData | null;\n onClientUserIdentityUpdate: (\n clientId: number,\n userIdentity: UserIdentity,\n ) => Promise<UserData | null> | UserData | null;\n onClientDisconnect: (clientId: number) => void;\n};\n\nexport class UserNetworkingServer {\n private allClientsById = new Map<number, UserNetworkingServerClient>();\n private authenticatedClientsById: Map<number, UserNetworkingServerClient> = new Map();\n\n private sendUpdatesIntervalTimer: NodeJS.Timeout;\n private pingClientsIntervalTimer: NodeJS.Timeout;\n private heartbeatIntervalTimer: NodeJS.Timeout;\n\n constructor(private options: UserNetworkingServerOptions) {\n this.sendUpdatesIntervalTimer = setInterval(this.sendUpdates.bind(this), packetsUpdateRate);\n this.pingClientsIntervalTimer = setInterval(this.pingClients.bind(this), pingPongRate);\n this.heartbeatIntervalTimer = setInterval(this.heartBeat.bind(this), heartBeatRate);\n }\n\n private heartBeat() {\n const now = Date.now();\n this.allClientsById.forEach((client) => {\n if (now - client.lastPong > heartBeatRate) {\n client.socket.close();\n this.handleDisconnectedClient(client);\n }\n });\n }\n\n private pingClients() {\n const message: FromUserNetworkingServerMessage = { type: \"ping\" };\n const messageString = JSON.stringify(message);\n this.authenticatedClientsById.forEach((client) => {\n if (client.socket.readyState === WebSocketOpenStatus) {\n client.socket.send(messageString);\n }\n });\n }\n\n private getId(): number {\n let id = 1;\n while (this.allClientsById.has(id)) {\n id++;\n }\n return id;\n }\n\n public broadcastMessage(broadcastType: string, broadcastPayload: any) {\n const message: FromUserNetworkingServerMessage = {\n type: \"broadcast\",\n broadcastType,\n payload: broadcastPayload,\n };\n const messageString = JSON.stringify(message);\n for (const [, client] of this.authenticatedClientsById) {\n if (client.socket.readyState === WebSocketOpenStatus) {\n client.socket.send(messageString);\n }\n }\n }\n\n public connectClient(socket: WebSocket) {\n const id = this.getId();\n console.log(`Client ID: ${id} joined, waiting for user-identification`);\n\n // Create a client but without user information\n const client: UserNetworkingServerClient = {\n id,\n lastPong: Date.now(),\n socket: socket as WebSocket,\n authenticatedUser: null,\n update: {\n id,\n position: { x: 0, y: 0, z: 0 },\n rotation: { quaternionY: 0, quaternionW: 1 },\n state: 0,\n },\n };\n this.allClientsById.set(id, client);\n\n socket.on(\"message\", (message: WebSocket.Data, _isBinary: boolean) => {\n if (message instanceof Buffer) {\n const arrayBuffer = new Uint8Array(message).buffer;\n const update = UserNetworkingCodec.decodeUpdate(arrayBuffer);\n update.id = id;\n client.update = update;\n } else {\n let parsed;\n try {\n parsed = JSON.parse(message as string) as FromUserNetworkingClientMessage;\n } catch (e) {\n console.error(\"Error parsing JSON message\", message, e);\n return;\n }\n if (!client.authenticatedUser) {\n if (parsed.type === USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE) {\n this.handleUserAuth(client, parsed).then((authResult) => {\n if (client.socket.readyState !== WebSocketOpenStatus) {\n // The client disconnected before the authentication was completed\n return;\n }\n if (!authResult) {\n // If the user is not authorized, disconnect the client\n const serverError = JSON.stringify({\n type: USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,\n errorType: USER_NETWORKING_AUTHENTICATION_FAILED_ERROR_TYPE,\n message: \"Authentication failed\",\n } as FromUserNetworkingServerMessage);\n socket.send(serverError);\n socket.close();\n } else {\n if (\n this.options.connectionLimit !== undefined &&\n this.authenticatedClientsById.size >= this.options.connectionLimit\n ) {\n // There is a connection limit and it has been met - disconnect the user\n const serverError = JSON.stringify({\n type: USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,\n errorType: USER_NETWORKING_CONNECTION_LIMIT_REACHED_ERROR_TYPE,\n message: \"Connection limit reached\",\n } as FromUserNetworkingServerMessage);\n socket.send(serverError);\n socket.close();\n return;\n }\n\n const userData = authResult;\n client.authenticatedUser = userData;\n\n // Give the client its own profile\n const userProfileMessage = JSON.stringify({\n id: client.id,\n type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,\n username: userData.username,\n characterDescription: userData.characterDescription,\n } as FromUserNetworkingServerMessage);\n client.socket.send(userProfileMessage);\n\n // Give the client its own identity\n const identityMessage = JSON.stringify({\n id: client.id,\n type: USER_NETWORKING_IDENTITY_MESSAGE_TYPE,\n } as FromUserNetworkingServerMessage);\n client.socket.send(identityMessage);\n\n const userUpdateMessage = UserNetworkingCodec.encodeUpdate(client.update);\n\n // Send information about all other clients to the freshly connected client and vice versa\n for (const [, otherClient] of this.authenticatedClientsById) {\n if (\n otherClient.socket.readyState !== WebSocketOpenStatus ||\n otherClient === client\n ) {\n // Do not send updates for any clients which have not yet authenticated or not yet connected\n continue;\n }\n // Send the character information\n client.socket.send(\n JSON.stringify({\n id: otherClient.update.id,\n type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,\n username: otherClient.authenticatedUser?.username,\n characterDescription: otherClient.authenticatedUser?.characterDescription,\n } as FromUserNetworkingServerMessage),\n );\n client.socket.send(UserNetworkingCodec.encodeUpdate(otherClient.update));\n\n otherClient.socket.send(userProfileMessage);\n otherClient.socket.send(userUpdateMessage);\n }\n\n this.authenticatedClientsById.set(id, client);\n }\n });\n } else {\n console.error(`Unhandled message pre-auth: ${JSON.stringify(parsed)}`);\n socket.close();\n }\n } else {\n switch (parsed.type) {\n case USER_NETWORKING_PONG_MESSAGE_TYPE:\n client.lastPong = Date.now();\n break;\n\n case USER_NETWORKING_USER_UPDATE_MESSAGE_TYPE:\n this.handleUserUpdate(id, parsed as UserNetworkingUserUpdateMessage);\n break;\n\n default:\n console.error(`Unhandled message: ${JSON.stringify(parsed)}`);\n }\n }\n }\n });\n\n socket.on(\"close\", () => {\n console.log(\"Client disconnected\", id);\n this.handleDisconnectedClient(client);\n });\n }\n\n private handleDisconnectedClient(client: UserNetworkingServerClient) {\n if (!this.allClientsById.has(client.id)) {\n return;\n }\n this.allClientsById.delete(client.id);\n if (client.authenticatedUser !== null) {\n // Only report disconnections of clients that were authenticated\n this.options.onClientDisconnect(client.id);\n this.authenticatedClientsById.delete(client.id);\n const disconnectMessage = JSON.stringify({\n id: client.id,\n type: USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE,\n } as FromUserNetworkingServerMessage);\n for (const [, otherClient] of this.authenticatedClientsById) {\n if (otherClient.socket.readyState === WebSocketOpenStatus) {\n otherClient.socket.send(disconnectMessage);\n }\n }\n }\n }\n\n private async handleUserAuth(\n client: UserNetworkingServerClient,\n credentials: UserNetworkingAuthenticateMessage,\n ): Promise<false | UserData> {\n const userData = this.options.onClientConnect(\n client.id,\n credentials.sessionToken,\n credentials.userIdentity,\n );\n let resolvedUserData;\n if (userData instanceof Promise) {\n resolvedUserData = await userData;\n } else {\n resolvedUserData = userData;\n }\n if (resolvedUserData === null) {\n console.error(`Client-id ${client.id} user_auth unauthorized and ignored`);\n return false;\n }\n\n console.log(\"Client authenticated\", client.id, resolvedUserData);\n\n return resolvedUserData;\n }\n\n public updateUserCharacter(clientId: number, userData: UserData) {\n this.internalUpdateUser(clientId, userData);\n }\n\n private internalUpdateUser(clientId: number, userData: UserData) {\n // This function assumes authorization has already been done\n const client = this.authenticatedClientsById.get(clientId)!;\n\n client.authenticatedUser = userData;\n this.authenticatedClientsById.set(clientId, client);\n\n const newUserData = JSON.stringify({\n id: clientId,\n type: USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,\n username: userData.username,\n characterDescription: userData.characterDescription,\n } as FromUserNetworkingServerMessage);\n\n // Broadcast the new userdata to all sockets, INCLUDING the user of the calling socket\n // Clients will always render based on the public userProfile.\n // This makes it intuitive, as it is \"what you see is what other's see\" from a user's perspective.\n for (const [otherClientId, otherClient] of this.authenticatedClientsById) {\n if (otherClient.socket.readyState === WebSocketOpenStatus) {\n otherClient.socket.send(newUserData);\n }\n }\n }\n\n private async handleUserUpdate(\n clientId: number,\n message: UserNetworkingUserUpdateMessage,\n ): Promise<void> {\n const client = this.authenticatedClientsById.get(clientId);\n if (!client) {\n console.error(`Client-id ${clientId} user_update ignored, client not found`);\n return;\n }\n\n // Verify using the user authenticator what the allowed version of this update is\n const authorizedUserData = this.options.onClientUserIdentityUpdate(\n clientId,\n message.userIdentity,\n );\n\n let resolvedAuthorizedUserData;\n if (authorizedUserData instanceof Promise) {\n resolvedAuthorizedUserData = await authorizedUserData;\n } else {\n resolvedAuthorizedUserData = authorizedUserData;\n }\n if (!resolvedAuthorizedUserData) {\n // TODO - inform the client about the unauthorized update\n console.warn(`Client-id ${clientId} user_update unauthorized and ignored`);\n return;\n }\n\n this.internalUpdateUser(clientId, resolvedAuthorizedUserData);\n }\n\n private sendUpdates(): void {\n for (const [clientId, client] of this.authenticatedClientsById) {\n const update = client.update;\n const encodedUpdate = UserNetworkingCodec.encodeUpdate(update);\n\n for (const [otherClientId, otherClient] of this.authenticatedClientsById) {\n if (otherClientId !== clientId && otherClient.socket.readyState === WebSocketOpenStatus) {\n otherClient.socket.send(encodedUpdate);\n }\n }\n }\n }\n\n public dispose(clientCloseError?: UserNetworkingServerError) {\n clearInterval(this.sendUpdatesIntervalTimer);\n clearInterval(this.pingClientsIntervalTimer);\n clearInterval(this.heartbeatIntervalTimer);\n\n const stringifiedError = clientCloseError ? JSON.stringify(clientCloseError) : undefined;\n\n for (const [, client] of this.authenticatedClientsById) {\n if (stringifiedError) {\n client.socket.send(stringifiedError);\n }\n client.socket.close();\n }\n }\n}\n", "import { UserNetworkingClientUpdate, UserNetworkingCodec } from \"./UserNetworkingCodec\";\n\nexport type WebsocketFactory = (url: string) => WebSocket;\n\nexport enum WebsocketStatus {\n Connecting,\n Connected,\n Reconnecting,\n Disconnected,\n}\n\nconst startingBackoffTimeMilliseconds = 100;\nconst maximumBackoffTimeMilliseconds = 10000;\nconst maximumWebsocketConnectionTimeout = 5000;\n\nexport abstract class ReconnectingWebSocket {\n private websocket: WebSocket | null = null;\n private status: WebsocketStatus | null = null;\n private receivedMessageSinceOpen = false;\n private backoffTime = startingBackoffTimeMilliseconds;\n private stopped = false;\n\n constructor(\n private url: string,\n private websocketFactory: WebsocketFactory,\n private statusUpdateCallback: (status: WebsocketStatus) => void,\n ) {\n this.setStatus(WebsocketStatus.Connecting);\n this.startWebSocketConnectionAttempt();\n }\n\n private setStatus(status: WebsocketStatus) {\n if (this.status !== status) {\n this.status = status;\n this.statusUpdateCallback(status);\n }\n }\n\n public sendUpdate(update: UserNetworkingClientUpdate): void {\n if (!this.websocket) {\n console.error(\"Not connected to the server\");\n return;\n }\n const encodedUpdate = UserNetworkingCodec.encodeUpdate(update);\n this.send(encodedUpdate);\n }\n\n private async startWebSocketConnectionAttempt() {\n if (this.stopped) {\n return;\n }\n // eslint-disable-next-line no-constant-condition\n while (true) {\n if (this.stopped) {\n return;\n }\n try {\n await this.createWebsocketWithTimeout(maximumWebsocketConnectionTimeout);\n break;\n } catch (e) {\n // Connection failed, retry with backoff\n this.setStatus(WebsocketStatus.Reconnecting);\n await this.waitBackoffTime();\n }\n }\n }\n\n private async waitBackoffTime(): Promise<void> {\n console.warn(`Websocket connection to '${this.url}' failed: retrying in ${this.backoffTime}ms`);\n await new Promise((resolve) => setTimeout(resolve, this.backoffTime));\n this.backoffTime = Math.min(\n // Introduce a small amount of randomness to prevent clients from retrying in lockstep\n this.backoffTime * (1.5 + Math.random() * 0.5),\n maximumBackoffTimeMilliseconds,\n );\n }\n\n protected abstract handleIncomingWebsocketMessage(message: MessageEvent): void;\n\n protected send(message: object | Uint8Array): void {\n if (!this.websocket) {\n console.error(\"Not connected to the server\");\n return;\n }\n if (message instanceof Uint8Array) {\n this.websocket.send(message);\n } else {\n this.websocket.send(JSON.stringify(message));\n }\n }\n\n private createWebsocketWithTimeout(timeout: number): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(new Error(\"websocket connection timed out\"));\n }, timeout);\n const websocket = this.websocketFactory(this.url);\n websocket.binaryType = \"arraybuffer\";\n websocket.addEventListener(\"open\", () => {\n clearTimeout(timeoutId);\n this.receivedMessageSinceOpen = false;\n this.websocket = websocket;\n this.setStatus(WebsocketStatus.Connected);\n\n websocket.addEventListener(\"message\", (event) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket message event because it is no longer current\");\n websocket.close();\n return;\n }\n if (!this.receivedMessageSinceOpen) {\n this.receivedMessageSinceOpen = true;\n }\n this.handleIncomingWebsocketMessage(event);\n });\n\n const onWebsocketClose = async () => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket close event because it is no longer current\");\n return;\n }\n this.websocket = null;\n if (this.stopped) {\n // This closing is expected. The client closed the websocket.\n this.setStatus(WebsocketStatus.Disconnected);\n return;\n }\n if (!this.receivedMessageSinceOpen) {\n // The websocket did not deliver any contents. It may have been successfully opened, but immediately closed. This client should back off to prevent this happening in a rapid loop.\n await this.waitBackoffTime();\n }\n // The websocket closed unexpectedly. Try to reconnect.\n this.setStatus(WebsocketStatus.Reconnecting);\n this.startWebSocketConnectionAttempt();\n };\n\n websocket.addEventListener(\"close\", (e) => {\n if (websocket !== this.websocket) {\n console.warn(\"Ignoring websocket close event because it is no longer current\");\n return;\n }\n console.log(\"ReconnectingWebSocket close\", e);\n onWebsocketClose();\n });\n websocket.addEventListener(\"error\", (e) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket error event because it is no longer current\");\n return;\n }\n console.error(\"ReconnectingWebSocket error\", e);\n onWebsocketClose();\n });\n\n resolve(websocket);\n });\n websocket.addEventListener(\"error\", (e) => {\n clearTimeout(timeoutId);\n reject(e);\n });\n });\n }\n\n public stop() {\n this.stopped = true;\n if (this.websocket !== null) {\n this.websocket.close();\n this.websocket = null;\n }\n }\n}\n", "import { ReconnectingWebSocket, WebsocketFactory, WebsocketStatus } from \"./ReconnectingWebSocket\";\nimport { UserNetworkingClientUpdate, UserNetworkingCodec } from \"./UserNetworkingCodec\";\nimport {\n CharacterDescription,\n FromUserNetworkingClientMessage,\n FromUserNetworkingServerMessage,\n USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE,\n USER_NETWORKING_IDENTITY_MESSAGE_TYPE,\n USER_NETWORKING_PING_MESSAGE_TYPE,\n USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE,\n USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE,\n USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE,\n USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE,\n UserNetworkingServerErrorType,\n} from \"./UserNetworkingMessages\";\n\nexport type UserNetworkingClientConfig = {\n url: string;\n sessionToken: string;\n websocketFactory: WebsocketFactory;\n statusUpdateCallback: (status: WebsocketStatus) => void;\n assignedIdentity: (clientId: number) => void;\n clientUpdate: (id: number, update: null | UserNetworkingClientUpdate) => void;\n clientProfileUpdated: (\n id: number,\n username: string,\n characterDescription: CharacterDescription,\n ) => void;\n onServerError: (error: { message: string; errorType: UserNetworkingServerErrorType }) => void;\n onServerBroadcast?: (broadcast: { broadcastType: string; payload: any }) => void;\n};\n\nexport class UserNetworkingClient extends ReconnectingWebSocket {\n constructor(private config: UserNetworkingClientConfig) {\n super(config.url, config.websocketFactory, (status: WebsocketStatus) => {\n if (status === WebsocketStatus.Connected) {\n this.sendMessage({\n type: USER_NETWORKING_USER_AUTHENTICATE_MESSAGE_TYPE,\n sessionToken: config.sessionToken,\n });\n }\n config.statusUpdateCallback(status);\n });\n }\n\n public sendUpdate(update: UserNetworkingClientUpdate): void {\n const encodedUpdate = UserNetworkingCodec.encodeUpdate(update);\n this.send(encodedUpdate);\n }\n\n public sendMessage(message: FromUserNetworkingClientMessage): void {\n this.send(message);\n }\n\n protected handleIncomingWebsocketMessage(message: MessageEvent) {\n if (typeof message.data === \"string\") {\n const parsed = JSON.parse(message.data) as FromUserNetworkingServerMessage;\n switch (parsed.type) {\n case USER_NETWORKING_SERVER_ERROR_MESSAGE_TYPE:\n console.error(`Server error: ${parsed.message}. errorType: ${parsed.errorType}`);\n this.config.onServerError(parsed);\n break;\n case USER_NETWORKING_DISCONNECTED_MESSAGE_TYPE:\n console.log(`Client ID: ${parsed.id} left`);\n this.config.clientUpdate(parsed.id, null);\n break;\n case USER_NETWORKING_IDENTITY_MESSAGE_TYPE:\n console.log(`Client ID: ${parsed.id} assigned to self`);\n this.config.assignedIdentity(parsed.id);\n break;\n case USER_NETWORKING_USER_PROFILE_MESSAGE_TYPE:\n console.log(`Client ID: ${parsed.id} updated profile`);\n this.config.clientProfileUpdated(parsed.id, parsed.username, parsed.characterDescription);\n break;\n case USER_NETWORKING_PING_MESSAGE_TYPE: {\n this.sendMessage({ type: \"pong\" } as FromUserNetworkingClientMessage);\n break;\n }\n case USER_NETWORKING_SERVER_BROADCAST_MESSAGE_TYPE: {\n if (this.config.onServerBroadcast) {\n this.config.onServerBroadcast({\n broadcastType: parsed.broadcastType,\n payload: parsed.payload,\n });\n } else {\n console.warn(\"Unhandled broadcast\", parsed);\n }\n break;\n }\n default:\n console.error(\"Unhandled message\", parsed);\n }\n } else if (message.data instanceof ArrayBuffer) {\n const userNetworkingClientUpdate = UserNetworkingCodec.decodeUpdate(message.data);\n this.config.clientUpdate(userNetworkingClientUpdate.id, userNetworkingClientUpdate);\n } else {\n console.error(\"Unhandled message type\", message.data);\n }\n }\n}\n"],
|
5
|
+
"mappings": "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",
|
6
6
|
"names": ["WebsocketStatus"]
|
7
7
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@mml-io/3d-web-user-networking",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.19.0",
|
4
4
|
"publishConfig": {
|
5
5
|
"access": "public"
|
6
6
|
},
|
@@ -29,5 +29,5 @@
|
|
29
29
|
"express": "4.19.2",
|
30
30
|
"express-ws": "5.0.2"
|
31
31
|
},
|
32
|
-
"gitHead": "
|
32
|
+
"gitHead": "1d785e68643dd46c63b49d9fcb0fc1d73097a414"
|
33
33
|
}
|