multyx-client 0.1.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.
- package/dist/controller.js +356 -0
- package/dist/index.js +213 -0
- package/dist/items/index.js +9 -0
- package/dist/items/list.js +250 -0
- package/dist/items/object.js +142 -0
- package/dist/items/router.js +8 -0
- package/dist/items/value.js +131 -0
- package/dist/message.js +36 -0
- package/dist/options.js +10 -0
- package/dist/types.js +2 -0
- package/dist/utils.js +74 -0
- package/multyx.js +1 -0
- package/package.json +34 -0
- package/src/controller.ts +353 -0
- package/src/index.ts +261 -0
- package/src/items/index.ts +14 -0
- package/src/items/list.ts +270 -0
- package/src/items/object.ts +170 -0
- package/src/items/router.ts +5 -0
- package/src/items/value.ts +150 -0
- package/src/message.ts +41 -0
- package/src/options.ts +15 -0
- package/src/types.ts +17 -0
- package/src/utils.ts +78 -0
- package/tsconfig.json +9 -0
- package/webpack.config.js +13 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Controller = void 0;
|
|
4
|
+
const message_1 = require("./message");
|
|
5
|
+
class Controller {
|
|
6
|
+
constructor(ws) {
|
|
7
|
+
this.listening = new Set();
|
|
8
|
+
this.ws = ws;
|
|
9
|
+
this.preventDefault = false;
|
|
10
|
+
this.keys = {};
|
|
11
|
+
this.mouse = {
|
|
12
|
+
x: NaN,
|
|
13
|
+
y: NaN,
|
|
14
|
+
down: false,
|
|
15
|
+
centerX: 0,
|
|
16
|
+
centerY: 0,
|
|
17
|
+
scaleX: 1,
|
|
18
|
+
scaleY: 1
|
|
19
|
+
};
|
|
20
|
+
document.addEventListener('keydown', e => {
|
|
21
|
+
if (this.preventDefault)
|
|
22
|
+
e.preventDefault;
|
|
23
|
+
const key = e.key.toLowerCase();
|
|
24
|
+
// When holding down key
|
|
25
|
+
if (this.keys[key] && this.listening.has('keyhold')) {
|
|
26
|
+
this.relayInput('keyhold', { code: key });
|
|
27
|
+
}
|
|
28
|
+
if (this.keys[e.code] && this.listening.has('keyhold')) {
|
|
29
|
+
this.relayInput('keyhold', { code: e.code });
|
|
30
|
+
}
|
|
31
|
+
// Change in key state
|
|
32
|
+
if (this.listening.has(key) && !this.keys[key]) {
|
|
33
|
+
this.relayInput('keydown', { code: e.key });
|
|
34
|
+
}
|
|
35
|
+
if (this.listening.has(e.code) && !this.keys[e.code]) {
|
|
36
|
+
this.relayInput('keydown', { code: e.code });
|
|
37
|
+
}
|
|
38
|
+
this.keys[key] = true;
|
|
39
|
+
this.keys[e.code] = true;
|
|
40
|
+
});
|
|
41
|
+
document.addEventListener('keyup', e => {
|
|
42
|
+
if (this.preventDefault)
|
|
43
|
+
e.preventDefault;
|
|
44
|
+
const key = e.key.toLowerCase();
|
|
45
|
+
delete this.keys[key];
|
|
46
|
+
delete this.keys[e.code];
|
|
47
|
+
if (this.listening.has(key))
|
|
48
|
+
this.relayInput('keyup', { code: key });
|
|
49
|
+
if (this.listening.has(e.code))
|
|
50
|
+
this.relayInput('keyup', { code: e.code });
|
|
51
|
+
});
|
|
52
|
+
// Mouse input events
|
|
53
|
+
document.addEventListener('mousedown', e => {
|
|
54
|
+
if (this.preventDefault)
|
|
55
|
+
e.preventDefault;
|
|
56
|
+
if (this.mouseGetter) {
|
|
57
|
+
const mouse = this.mouseGetter();
|
|
58
|
+
this.mouse.x = mouse.x;
|
|
59
|
+
this.mouse.y = mouse.y;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.mouse.x = (e.clientX - this.mouse.centerX) / this.mouse.scaleX;
|
|
63
|
+
this.mouse.y = (e.clientY - this.mouse.centerY) / this.mouse.scaleY;
|
|
64
|
+
}
|
|
65
|
+
this.mouse.down = true;
|
|
66
|
+
if (this.listening.has('mousedown'))
|
|
67
|
+
this.relayInput('mousedown', {
|
|
68
|
+
x: this.mouse.x, y: this.mouse.y
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
document.addEventListener('mouseup', e => {
|
|
72
|
+
if (this.preventDefault)
|
|
73
|
+
e.preventDefault;
|
|
74
|
+
if (this.mouseGetter) {
|
|
75
|
+
const mouse = this.mouseGetter();
|
|
76
|
+
this.mouse.x = mouse.x;
|
|
77
|
+
this.mouse.y = mouse.y;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.mouse.x = (e.clientX - this.mouse.centerX) / this.mouse.scaleX;
|
|
81
|
+
this.mouse.y = (e.clientY - this.mouse.centerY) / this.mouse.scaleY;
|
|
82
|
+
}
|
|
83
|
+
this.mouse.down = false;
|
|
84
|
+
if (this.listening.has('mouseup'))
|
|
85
|
+
this.relayInput('mouseup', {
|
|
86
|
+
x: this.mouse.x, y: this.mouse.y
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
document.addEventListener('mousemove', e => {
|
|
90
|
+
if (this.preventDefault)
|
|
91
|
+
e.preventDefault;
|
|
92
|
+
if (this.mouseGetter) {
|
|
93
|
+
const mouse = this.mouseGetter();
|
|
94
|
+
this.mouse.x = mouse.x;
|
|
95
|
+
this.mouse.y = mouse.y;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
this.mouse.x = (e.clientX - this.mouse.centerX) / this.mouse.scaleX;
|
|
99
|
+
this.mouse.y = (e.clientY - this.mouse.centerY) / this.mouse.scaleY;
|
|
100
|
+
}
|
|
101
|
+
if (this.listening.has('mousemove'))
|
|
102
|
+
this.relayInput('mousemove', {
|
|
103
|
+
x: this.mouse.x, y: this.mouse.y
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Map the canvas to specified top left and bottom right positions
|
|
109
|
+
* @param canvas HTML canvas element
|
|
110
|
+
* @param canvasContext 2D rendering context for canvas
|
|
111
|
+
* @param top Canvas position to correspond to top of canvas
|
|
112
|
+
* @param left Canvas position to correspond to left of canvas
|
|
113
|
+
* @param bottom Canvas position to correspond to bottom of canvas
|
|
114
|
+
* @param right Canvas position to correspond to right of canvas
|
|
115
|
+
* @param anchor Anchor the origin at a specific spot on the canvas
|
|
116
|
+
*/
|
|
117
|
+
mapCanvasPosition(canvas, position) {
|
|
118
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
119
|
+
const t = 'top' in position;
|
|
120
|
+
const b = 'bottom' in position;
|
|
121
|
+
const l = 'left' in position;
|
|
122
|
+
const r = 'right' in position;
|
|
123
|
+
const a = position.anchor;
|
|
124
|
+
const bounding = canvas.getBoundingClientRect();
|
|
125
|
+
const error = (included, ...pieces) => {
|
|
126
|
+
const p1 = included ? "Cannot include value for " : "Must include value for ";
|
|
127
|
+
const p2 = pieces.length == 1 ? pieces[0] : pieces.slice(0, -1).join(', ') + (included ? ' and ' : ' or ') + pieces.slice(-1)[0];
|
|
128
|
+
const p3 = a ? " if anchoring at " + a : " if not anchoring";
|
|
129
|
+
console.error(p1 + p2 + p3);
|
|
130
|
+
};
|
|
131
|
+
const wToH = bounding.width / bounding.height;
|
|
132
|
+
const hToW = bounding.height / bounding.width;
|
|
133
|
+
if (Number.isNaN(wToH) || Number.isNaN(hToW)) {
|
|
134
|
+
console.error("Canvas element bounding box is flat, canvas must be present on the screen");
|
|
135
|
+
}
|
|
136
|
+
// mb bruh jus trust it works
|
|
137
|
+
if (!a) {
|
|
138
|
+
if (!t && !b)
|
|
139
|
+
return error(false, 'top', 'bottom');
|
|
140
|
+
else if (!b)
|
|
141
|
+
position.bottom = position.top + canvas.height;
|
|
142
|
+
else if (!t)
|
|
143
|
+
position.top = position.bottom - canvas.height;
|
|
144
|
+
if (!l && !r)
|
|
145
|
+
return error(false, 'left', 'right');
|
|
146
|
+
else if (!r)
|
|
147
|
+
position.right = position.left + canvas.width;
|
|
148
|
+
else if (!l)
|
|
149
|
+
position.left = position.right - canvas.width;
|
|
150
|
+
}
|
|
151
|
+
else if (a == 'center') {
|
|
152
|
+
if (t && b && position.top !== -position.bottom
|
|
153
|
+
|| l && r && position.left !== -position.right)
|
|
154
|
+
return error(true, 'top', 'bottom', 'left', 'right');
|
|
155
|
+
if (t) {
|
|
156
|
+
position.left = l ? position.left : r ? -position.right : -Math.abs(wToH * position.top);
|
|
157
|
+
position.right = l ? -position.left : r ? position.right : Math.abs(wToH * position.top);
|
|
158
|
+
position.bottom = -position.top;
|
|
159
|
+
}
|
|
160
|
+
else if (b) {
|
|
161
|
+
position.left = l ? position.left : r ? -position.right : -Math.abs(wToH * position.bottom);
|
|
162
|
+
position.right = l ? -position.left : r ? position.right : Math.abs(wToH * position.bottom);
|
|
163
|
+
position.top = -position.bottom;
|
|
164
|
+
}
|
|
165
|
+
else if (l) {
|
|
166
|
+
position.top = t ? position.top : b ? -position.bottom : -Math.abs(hToW * position.left);
|
|
167
|
+
position.bottom = t ? -position.top : b ? position.bottom : Math.abs(hToW * position.left);
|
|
168
|
+
position.right = -position.left;
|
|
169
|
+
}
|
|
170
|
+
else if (r) {
|
|
171
|
+
position.top = t ? position.top : b ? -position.bottom : -Math.abs(hToW * position.right);
|
|
172
|
+
position.bottom = t ? -position.top : b ? position.bottom : Math.abs(hToW * position.right);
|
|
173
|
+
position.left = -position.right;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if (a == 'bottom') {
|
|
177
|
+
if (!l && !r && !t)
|
|
178
|
+
return error(false, 'left', 'right', 'top');
|
|
179
|
+
if (position.bottom)
|
|
180
|
+
return error(true, 'bottom');
|
|
181
|
+
position.bottom = 0;
|
|
182
|
+
if (l) {
|
|
183
|
+
(_a = position.top) !== null && _a !== void 0 ? _a : (position.top = Math.abs(hToW * position.left * 2));
|
|
184
|
+
(_b = position.right) !== null && _b !== void 0 ? _b : (position.right = -position.left);
|
|
185
|
+
}
|
|
186
|
+
else if (r) {
|
|
187
|
+
(_c = position.top) !== null && _c !== void 0 ? _c : (position.top = Math.abs(hToW * position.right * 2));
|
|
188
|
+
(_d = position.left) !== null && _d !== void 0 ? _d : (position.left = -position.right);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
position.left = -Math.abs(wToH * position.top / 2);
|
|
192
|
+
position.right = -position.left;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else if (a == 'top') {
|
|
196
|
+
if (!l && !r && !b)
|
|
197
|
+
return error(false, 'left', 'right', 'bottom');
|
|
198
|
+
if (position.top)
|
|
199
|
+
return error(true, 'top');
|
|
200
|
+
position.top = 0;
|
|
201
|
+
if (l) {
|
|
202
|
+
(_e = position.bottom) !== null && _e !== void 0 ? _e : (position.bottom = Math.abs(hToW * position.left * 2));
|
|
203
|
+
(_f = position.right) !== null && _f !== void 0 ? _f : (position.right = -position.left);
|
|
204
|
+
}
|
|
205
|
+
else if (r) {
|
|
206
|
+
(_g = position.bottom) !== null && _g !== void 0 ? _g : (position.bottom = Math.abs(hToW * position.right * 2));
|
|
207
|
+
(_h = position.left) !== null && _h !== void 0 ? _h : (position.left = -position.right);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
position.left = -Math.abs(wToH * position.bottom / 2);
|
|
211
|
+
position.right = -position.left;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else if (a == 'left') {
|
|
215
|
+
if (!t && !b && !r)
|
|
216
|
+
return error(false, 'top', 'bottom', 'right');
|
|
217
|
+
if (l)
|
|
218
|
+
return error(true, 'left');
|
|
219
|
+
position.left = 0;
|
|
220
|
+
if (t) {
|
|
221
|
+
(_j = position.right) !== null && _j !== void 0 ? _j : (position.right = -Math.abs(wToH * position.top * 2));
|
|
222
|
+
(_k = position.bottom) !== null && _k !== void 0 ? _k : (position.bottom = -position.top);
|
|
223
|
+
}
|
|
224
|
+
else if (b) {
|
|
225
|
+
(_l = position.right) !== null && _l !== void 0 ? _l : (position.right = Math.abs(wToH * position.bottom * 2));
|
|
226
|
+
(_m = position.top) !== null && _m !== void 0 ? _m : (position.top = -position.bottom);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
position.top = -Math.abs(hToW * position.right / 2);
|
|
230
|
+
position.bottom = -position.top;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else if (a == 'right') {
|
|
234
|
+
if (!t && !b && !l)
|
|
235
|
+
return error(false, 'top', 'bottom', 'left');
|
|
236
|
+
if (r)
|
|
237
|
+
return error(true, 'right');
|
|
238
|
+
position.right = 0;
|
|
239
|
+
if (t) {
|
|
240
|
+
(_o = position.left) !== null && _o !== void 0 ? _o : (position.left = -Math.abs(wToH * position.top * 2));
|
|
241
|
+
(_p = position.bottom) !== null && _p !== void 0 ? _p : (position.bottom = -position.top);
|
|
242
|
+
}
|
|
243
|
+
else if (b) {
|
|
244
|
+
(_q = position.left) !== null && _q !== void 0 ? _q : (position.left = Math.abs(wToH * position.bottom * 2));
|
|
245
|
+
(_r = position.top) !== null && _r !== void 0 ? _r : (position.top = -position.bottom);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
position.top = -Math.abs(hToW * position.right / 2);
|
|
249
|
+
position.bottom = -position.top;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else if (a == 'topleft') {
|
|
253
|
+
if (!r && !b)
|
|
254
|
+
return error(false, 'right', 'bottom');
|
|
255
|
+
if (l || t)
|
|
256
|
+
return error(true, 'left', 'top');
|
|
257
|
+
position.left = position.top = 0;
|
|
258
|
+
if (r)
|
|
259
|
+
position.bottom = Math.abs(hToW * position.right);
|
|
260
|
+
else
|
|
261
|
+
position.right = Math.abs(wToH * position.bottom);
|
|
262
|
+
}
|
|
263
|
+
else if (a == 'topright') {
|
|
264
|
+
if (!l && !b)
|
|
265
|
+
return error(false, 'left', 'bottom');
|
|
266
|
+
if (r || t)
|
|
267
|
+
return error(true, 'right', 'top');
|
|
268
|
+
position.right = position.top = 0;
|
|
269
|
+
if (l)
|
|
270
|
+
position.bottom = Math.abs(hToW * position.left);
|
|
271
|
+
else
|
|
272
|
+
position.left = Math.abs(wToH * position.bottom);
|
|
273
|
+
}
|
|
274
|
+
else if (a == 'bottomleft') {
|
|
275
|
+
if (!r && !t)
|
|
276
|
+
return error(false, 'right', 'top');
|
|
277
|
+
if (b || l)
|
|
278
|
+
return error(true, 'bottom', 'left');
|
|
279
|
+
position.left = position.bottom = 0;
|
|
280
|
+
if (r)
|
|
281
|
+
position.top = Math.abs(hToW * position.right);
|
|
282
|
+
else
|
|
283
|
+
position.right = Math.abs(wToH * position.top);
|
|
284
|
+
}
|
|
285
|
+
else if (a == 'bottomright') {
|
|
286
|
+
if (!t && !l)
|
|
287
|
+
return error(false, 'top', 'left');
|
|
288
|
+
if (r || b)
|
|
289
|
+
return error(true, 'bottom', 'right');
|
|
290
|
+
position.right = position.bottom = 0;
|
|
291
|
+
if (l)
|
|
292
|
+
position.top = Math.abs(hToW * position.left);
|
|
293
|
+
else
|
|
294
|
+
position.left = Math.abs(wToH * position.top);
|
|
295
|
+
}
|
|
296
|
+
const ctx = canvas.getContext("2d");
|
|
297
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
298
|
+
canvas.width = Math.floor(Math.abs(position.right - position.left));
|
|
299
|
+
canvas.height = Math.floor(Math.abs(position.bottom - position.top));
|
|
300
|
+
if (position.right < position.left)
|
|
301
|
+
ctx.scale(-1, 1);
|
|
302
|
+
if (position.top > position.bottom)
|
|
303
|
+
ctx.scale(1, -1);
|
|
304
|
+
ctx.translate(-position.left, -position.top);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* @param centerX Anchor x-value corresponding to mouse position x-value of 0
|
|
308
|
+
* @param centerY Anchor y-value corresponding to mouse position y-value of 0
|
|
309
|
+
* @param anchor HTML Element to read mouse position relative to
|
|
310
|
+
* @param scaleX Number of anchor pixels corresponding to a mouse position x-value change of 1
|
|
311
|
+
* @param scaleY Number of anchor pixels corresponding to a mouse position y-value change of 1
|
|
312
|
+
*/
|
|
313
|
+
mapMousePosition(centerX, centerY, anchor = document.body, scaleX = 1, scaleY = scaleX) {
|
|
314
|
+
const ratioX = window.innerWidth / (anchor instanceof HTMLCanvasElement
|
|
315
|
+
? anchor.width
|
|
316
|
+
: anchor.clientWidth);
|
|
317
|
+
const ratioY = window.innerHeight / (anchor instanceof HTMLCanvasElement
|
|
318
|
+
? anchor.height
|
|
319
|
+
: anchor.clientHeight);
|
|
320
|
+
const bounding = anchor.getBoundingClientRect();
|
|
321
|
+
this.mouse.centerX = bounding.left + centerX * ratioX;
|
|
322
|
+
this.mouse.centerY = bounding.top + centerY * ratioY;
|
|
323
|
+
this.mouse.scaleX = scaleX * ratioX;
|
|
324
|
+
this.mouse.scaleY = scaleY * ratioY;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Map mouse position to the corresponding canvas coordinates on screen
|
|
328
|
+
* @param canvas Canvas element in DOM
|
|
329
|
+
*/
|
|
330
|
+
mapMouseToCanvas(canvas) {
|
|
331
|
+
const ctx = canvas.getContext("2d");
|
|
332
|
+
const transform = ctx.getTransform();
|
|
333
|
+
const bounding = canvas.getBoundingClientRect();
|
|
334
|
+
// Ratio between canvas scale to unit pixels
|
|
335
|
+
const canvasRatioX = bounding.width / canvas.width;
|
|
336
|
+
const canvasRatioY = bounding.height / canvas.height;
|
|
337
|
+
this.mouse.centerX = bounding.left + transform.e * canvasRatioX;
|
|
338
|
+
this.mouse.centerY = bounding.top + transform.f * canvasRatioY;
|
|
339
|
+
this.mouse.scaleX = canvasRatioX * transform.a;
|
|
340
|
+
this.mouse.scaleY = canvasRatioY * transform.d;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Utilize mouse coordinates of another object
|
|
344
|
+
* @param mouseGetter Callback that returns the mouse coordinates at any given time
|
|
345
|
+
*/
|
|
346
|
+
setMouseAs(mouseGetter) {
|
|
347
|
+
this.mouseGetter = mouseGetter;
|
|
348
|
+
}
|
|
349
|
+
relayInput(input, data) {
|
|
350
|
+
if (this.ws.readyState !== 1) {
|
|
351
|
+
throw new Error('Websocket connection is ' + (this.ws.readyState == 2 ? 'closing' : 'closed'));
|
|
352
|
+
}
|
|
353
|
+
this.ws.send(message_1.Message.Native(Object.assign({ instruction: 'input', input: input }, (data ? { data } : {}))));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
exports.Controller = Controller;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const message_1 = require("./message");
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
const controller_1 = require("./controller");
|
|
6
|
+
const items_1 = require("./items");
|
|
7
|
+
const options_1 = require("./options");
|
|
8
|
+
class Multyx {
|
|
9
|
+
constructor(options = {}, callback) {
|
|
10
|
+
this.options = Object.assign(Object.assign({}, options_1.DefaultOptions), options);
|
|
11
|
+
const url = `ws${this.options.secure ? 's' : ''}://${this.options.uri}:${this.options.port}/`;
|
|
12
|
+
this.ws = new WebSocket(url);
|
|
13
|
+
this.ping = 0;
|
|
14
|
+
this.events = new Map();
|
|
15
|
+
this.self = {};
|
|
16
|
+
this.all = {};
|
|
17
|
+
this.teams = {};
|
|
18
|
+
this.clients = {};
|
|
19
|
+
this.controller = new controller_1.Controller(this.ws);
|
|
20
|
+
this.listenerQueue = [];
|
|
21
|
+
callback === null || callback === void 0 ? void 0 : callback();
|
|
22
|
+
this.ws.onmessage = event => {
|
|
23
|
+
var _a, _b, _c;
|
|
24
|
+
const msg = message_1.Message.Parse(event.data);
|
|
25
|
+
this.ping = 2 * (Date.now() - msg.time);
|
|
26
|
+
if (msg.native) {
|
|
27
|
+
this.parseNativeEvent(msg);
|
|
28
|
+
(_a = this.events.get(Multyx.Native)) === null || _a === void 0 ? void 0 : _a.forEach(cb => cb(msg));
|
|
29
|
+
}
|
|
30
|
+
else if (msg.name in this.events) {
|
|
31
|
+
this.events[msg.name](msg.data);
|
|
32
|
+
(_b = this.events.get(Multyx.Custom)) === null || _b === void 0 ? void 0 : _b.forEach(cb => cb(msg));
|
|
33
|
+
}
|
|
34
|
+
(_c = this.events.get(Multyx.Any)) === null || _c === void 0 ? void 0 : _c.forEach(cb => cb(msg));
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
on(name, callback) {
|
|
38
|
+
var _a;
|
|
39
|
+
const events = (_a = this.events.get(name)) !== null && _a !== void 0 ? _a : [];
|
|
40
|
+
events.push(callback);
|
|
41
|
+
this.events.set(name, events);
|
|
42
|
+
}
|
|
43
|
+
send(name, data, expectResponse = false) {
|
|
44
|
+
if (name[0] === '_')
|
|
45
|
+
name = '_' + name;
|
|
46
|
+
this.ws.send(message_1.Message.Create(name, data));
|
|
47
|
+
if (!expectResponse)
|
|
48
|
+
return;
|
|
49
|
+
return new Promise(res => this.events.set(Symbol.for("_" + name), [res]));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Loop over a function
|
|
53
|
+
* @param callback Function to call on a loop
|
|
54
|
+
* @param timesPerSecond Recommended to leave blank. Number of times to loop in each second, if undefined, use requestAnimationFrame
|
|
55
|
+
*/
|
|
56
|
+
loop(callback, timesPerSecond) {
|
|
57
|
+
if (timesPerSecond) {
|
|
58
|
+
this.on(Multyx.Start, () => setInterval(callback, Math.round(1000 / timesPerSecond)));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const caller = () => {
|
|
62
|
+
callback();
|
|
63
|
+
requestAnimationFrame(caller);
|
|
64
|
+
};
|
|
65
|
+
this.on(Multyx.Start, () => requestAnimationFrame(caller));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create a callback function that gets called for any current or future client
|
|
70
|
+
* @param callbackfn Function to call for every client
|
|
71
|
+
*/
|
|
72
|
+
forAll(callback) {
|
|
73
|
+
this.on(Multyx.Start, () => {
|
|
74
|
+
this.teams.all.clients.forAll((uuid) => callback(this.clients[uuid]));
|
|
75
|
+
});
|
|
76
|
+
this.on(Multyx.Connection, callback);
|
|
77
|
+
}
|
|
78
|
+
parseNativeEvent(msg) {
|
|
79
|
+
var _a, _b, _c, _d;
|
|
80
|
+
if (this.options.logUpdateFrame)
|
|
81
|
+
console.log(msg);
|
|
82
|
+
for (const update of msg.data) {
|
|
83
|
+
switch (update.instruction) {
|
|
84
|
+
// Initialization
|
|
85
|
+
case 'init': {
|
|
86
|
+
this.initialize(update);
|
|
87
|
+
for (const listener of (_a = this.events.get(Multyx.Start)) !== null && _a !== void 0 ? _a : []) {
|
|
88
|
+
this.listenerQueue.push(() => listener(update));
|
|
89
|
+
}
|
|
90
|
+
// Clear start event as it will never be called again
|
|
91
|
+
if (this.events.has(Multyx.Start))
|
|
92
|
+
this.events.get(Multyx.Start).length = 0;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
// Client or team data edit
|
|
96
|
+
case 'edit': {
|
|
97
|
+
this.parseEdit(update);
|
|
98
|
+
for (const listener of (_b = this.events.get(Multyx.Edit)) !== null && _b !== void 0 ? _b : []) {
|
|
99
|
+
this.listenerQueue.push(() => listener(update));
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
// Other data change
|
|
104
|
+
case 'self': {
|
|
105
|
+
this.parseSelf(update);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
// Connection
|
|
109
|
+
case 'conn': {
|
|
110
|
+
this.clients[update.uuid] = new items_1.MultyxClientObject(this, update.data, [update.uuid], false);
|
|
111
|
+
for (const listener of (_c = this.events.get(Multyx.Connection)) !== null && _c !== void 0 ? _c : []) {
|
|
112
|
+
this.listenerQueue.push(() => listener(this.clients[update.uuid]));
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
// Disconnection
|
|
117
|
+
case 'dcon': {
|
|
118
|
+
for (const listener of (_d = this.events.get(Multyx.Disconnect)) !== null && _d !== void 0 ? _d : []) {
|
|
119
|
+
const clientValue = this.clients[update.client].value;
|
|
120
|
+
this.listenerQueue.push(() => listener(clientValue));
|
|
121
|
+
}
|
|
122
|
+
delete this.clients[update.client];
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
// Response to client
|
|
126
|
+
case 'resp': {
|
|
127
|
+
const promiseResolve = this.events.get(Symbol.for("_" + update.name))[0];
|
|
128
|
+
promiseResolve(update.response);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
default: {
|
|
132
|
+
if (this.options.verbose) {
|
|
133
|
+
console.error("Server error: Unknown native Multyx instruction");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this.listenerQueue.forEach(x => x());
|
|
139
|
+
this.listenerQueue.length = 0;
|
|
140
|
+
}
|
|
141
|
+
initialize(update) {
|
|
142
|
+
this.uuid = update.client.uuid;
|
|
143
|
+
this.joinTime = update.client.joinTime;
|
|
144
|
+
this.controller.listening = new Set(update.client.controller);
|
|
145
|
+
// Create MultyxClientObject for all teams
|
|
146
|
+
this.teams = new items_1.MultyxClientObject(this, {}, [], true);
|
|
147
|
+
for (const team of Object.keys(update.teams)) {
|
|
148
|
+
this.teams[team] = new utils_1.EditWrapper(update.teams[team]);
|
|
149
|
+
}
|
|
150
|
+
this.all = this.teams['all'];
|
|
151
|
+
// Create MultyxClientObject for all clients
|
|
152
|
+
this.clients = {};
|
|
153
|
+
for (const [uuid, client] of Object.entries(update.clients)) {
|
|
154
|
+
if (uuid == this.uuid)
|
|
155
|
+
continue;
|
|
156
|
+
this.clients[uuid] = new items_1.MultyxClientObject(this, new utils_1.EditWrapper(client), [uuid], false);
|
|
157
|
+
}
|
|
158
|
+
;
|
|
159
|
+
const client = new items_1.MultyxClientObject(this, new utils_1.EditWrapper(update.client.self), [this.uuid], true);
|
|
160
|
+
this.self = client;
|
|
161
|
+
this.clients[this.uuid] = client;
|
|
162
|
+
// Apply all constraints on self and teams
|
|
163
|
+
for (const [uuid, table] of Object.entries(update.constraintTable)) {
|
|
164
|
+
const obj = this.uuid == uuid ? this.self : this.teams[uuid];
|
|
165
|
+
obj[utils_1.Unpack](table);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
parseEdit(update) {
|
|
169
|
+
let route = update.team ? this.teams : this.clients;
|
|
170
|
+
if (!route)
|
|
171
|
+
return;
|
|
172
|
+
// Loop through path to get to object being edited
|
|
173
|
+
for (const p of update.path.slice(0, -1)) {
|
|
174
|
+
// Create new object at path if non-existent
|
|
175
|
+
if (!(p in route))
|
|
176
|
+
route[p] = new utils_1.EditWrapper({});
|
|
177
|
+
route = route[p];
|
|
178
|
+
}
|
|
179
|
+
const prop = update.path.slice(-1)[0];
|
|
180
|
+
route[prop] = new utils_1.EditWrapper(update.value);
|
|
181
|
+
}
|
|
182
|
+
parseSelf(update) {
|
|
183
|
+
if (update.prop == 'controller') {
|
|
184
|
+
this.controller.listening = new Set(update.data);
|
|
185
|
+
}
|
|
186
|
+
else if (update.prop == 'uuid') {
|
|
187
|
+
this.uuid = update.data;
|
|
188
|
+
}
|
|
189
|
+
else if (update.prop == 'constraint') {
|
|
190
|
+
let route = this.uuid == update.data.path[0] ? this.self : this.teams[update.data.path[0]];
|
|
191
|
+
for (const prop of update.data.path.slice(1))
|
|
192
|
+
route = route === null || route === void 0 ? void 0 : route[prop];
|
|
193
|
+
if (route === undefined)
|
|
194
|
+
return;
|
|
195
|
+
route[utils_1.Unpack]({ [update.data.name]: update.data.args });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Add function to listener queue
|
|
200
|
+
* @param fn Function to call once frame is complete
|
|
201
|
+
*/
|
|
202
|
+
[utils_1.Add](fn) {
|
|
203
|
+
this.listenerQueue.push(fn);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
Multyx.Start = Symbol('start');
|
|
207
|
+
Multyx.Connection = Symbol('connection');
|
|
208
|
+
Multyx.Disconnect = Symbol('disconnect');
|
|
209
|
+
Multyx.Edit = Symbol('edit');
|
|
210
|
+
Multyx.Native = Symbol('native');
|
|
211
|
+
Multyx.Custom = Symbol('custom');
|
|
212
|
+
Multyx.Any = Symbol('any');
|
|
213
|
+
exports.default = Multyx;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MultyxClientValue = exports.MultyxClientObject = exports.MultyxClientList = void 0;
|
|
4
|
+
const list_1 = require("./list");
|
|
5
|
+
exports.MultyxClientList = list_1.default;
|
|
6
|
+
const object_1 = require("./object");
|
|
7
|
+
exports.MultyxClientObject = object_1.default;
|
|
8
|
+
const value_1 = require("./value");
|
|
9
|
+
exports.MultyxClientValue = value_1.default;
|