multyx-client 0.1.1 → 0.1.2

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Add } from './utils';
1
+ import { Add, Done } from './utils';
2
2
  import { RawObject } from "./types";
3
3
  import { Controller } from "./controller";
4
4
  import { MultyxClientObject } from "./items";
@@ -10,12 +10,16 @@ export default class Multyx {
10
10
  ping: number;
11
11
  events: Map<string | Symbol, ((data?: any) => void)[]>;
12
12
  self: RawObject;
13
+ tps: number;
13
14
  all: RawObject;
14
- clients: RawObject;
15
- teams: RawObject;
15
+ space: string;
16
+ clients: {
17
+ [key: string]: MultyxClientObject;
18
+ };
19
+ teams: MultyxClientObject;
16
20
  controller: Controller;
17
21
  options: Options;
18
- private listenerQueue;
22
+ [Done]: ((...args: any[]) => void)[];
19
23
  static Start: symbol;
20
24
  static Connection: symbol;
21
25
  static Disconnect: symbol;
@@ -24,8 +28,25 @@ export default class Multyx {
24
28
  static Custom: symbol;
25
29
  static Any: symbol;
26
30
  constructor(options?: Options, callback?: () => void);
27
- on(name: string | Symbol, callback: (data: RawObject) => void): void;
28
- send(name: string, data: any, expectResponse?: boolean): Promise<unknown>;
31
+ /**
32
+ * Listen for a message from the server
33
+ * @param name Name of the message
34
+ * @param callback Function to call when the message is received
35
+ */
36
+ on(name: string | Symbol, callback: (data: RawObject) => any): void;
37
+ /**
38
+ * Send a message to the server
39
+ * @param name Name of the message
40
+ * @param data Data to send
41
+ */
42
+ send(name: string, data: any): void;
43
+ /**
44
+ * Send a message to the server and wait for a response
45
+ * @param name Name of the message
46
+ * @param data Data to send
47
+ * @returns Promise that resolves when the message is received
48
+ */
49
+ await(name: string, data?: any): Promise<unknown>;
29
50
  /**
30
51
  * Loop over a function
31
52
  * @param callback Function to call on a loop
@@ -33,17 +54,16 @@ export default class Multyx {
33
54
  */
34
55
  loop(callback: () => void, timesPerSecond?: number): void;
35
56
  /**
36
- * Create a callback function that gets called for any current or future client
37
- * @param callbackfn Function to call for every client
57
+ * Add a function to be called after each frame
58
+ * @param callback Function to call after each frame
59
+ */
60
+ [Add](callback: () => void): void;
61
+ /**
62
+ * Parse a native event from the server
63
+ * @param msg Message to parse
38
64
  */
39
- forAll(callback: (client: MultyxClientObject) => void): void;
40
65
  private parseNativeEvent;
41
66
  private initialize;
42
- private parseEdit;
43
67
  private parseSelf;
44
- /**
45
- * Add function to listener queue
46
- * @param fn Function to call once frame is complete
47
- */
48
- [Add](fn: ((...args: any[]) => void)): void;
68
+ private updateSpace;
49
69
  }
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ var _a;
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  const message_1 = require("./message");
4
5
  const utils_1 = require("./utils");
@@ -7,45 +8,75 @@ const items_1 = require("./items");
7
8
  const options_1 = require("./options");
8
9
  class Multyx {
9
10
  constructor(options = {}, callback) {
11
+ var _b;
12
+ // Queue of functions to be called after each frame
13
+ this[_a] = [];
10
14
  this.options = Object.assign(Object.assign({}, options_1.DefaultOptions), options);
11
- const url = `ws${this.options.secure ? 's' : ''}://${this.options.uri}:${this.options.port}/`;
15
+ const url = `ws${this.options.secure ? 's' : ''}://${this.options.uri.split('/')[0]}:${this.options.port}/${(_b = this.options.uri.split('/')[1]) !== null && _b !== void 0 ? _b : ''}`;
12
16
  this.ws = new WebSocket(url);
13
17
  this.ping = 0;
18
+ this.space = 'default';
14
19
  this.events = new Map();
15
20
  this.self = {};
21
+ this.tps = 0;
16
22
  this.all = {};
17
- this.teams = {};
23
+ this.teams = new items_1.MultyxClientObject(this, {}, [], true);
18
24
  this.clients = {};
19
25
  this.controller = new controller_1.Controller(this.ws);
20
- this.listenerQueue = [];
21
26
  callback === null || callback === void 0 ? void 0 : callback();
22
27
  this.ws.onmessage = event => {
23
- var _a, _b, _c;
28
+ var _b, _c, _d, _e;
24
29
  const msg = message_1.Message.Parse(event.data);
25
30
  this.ping = 2 * (Date.now() - msg.time);
26
31
  if (msg.native) {
27
32
  this.parseNativeEvent(msg);
28
- (_a = this.events.get(Multyx.Native)) === null || _a === void 0 ? void 0 : _a.forEach(cb => cb(msg));
33
+ (_b = this.events.get(Multyx.Native)) === null || _b === void 0 ? void 0 : _b.forEach(cb => cb(msg));
29
34
  }
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));
35
+ else {
36
+ (_c = this.events.get(msg.name)) === null || _c === void 0 ? void 0 : _c.forEach(cb => {
37
+ const response = cb(msg.data);
38
+ if (response !== undefined)
39
+ this.send(msg.name, response);
40
+ });
41
+ (_d = this.events.get(Multyx.Custom)) === null || _d === void 0 ? void 0 : _d.forEach(cb => cb(msg));
33
42
  }
34
- (_c = this.events.get(Multyx.Any)) === null || _c === void 0 ? void 0 : _c.forEach(cb => cb(msg));
43
+ (_e = this.events.get(Multyx.Any)) === null || _e === void 0 ? void 0 : _e.forEach(cb => cb(msg));
35
44
  };
36
45
  }
46
+ /**
47
+ * Listen for a message from the server
48
+ * @param name Name of the message
49
+ * @param callback Function to call when the message is received
50
+ */
37
51
  on(name, callback) {
38
- var _a;
39
- const events = (_a = this.events.get(name)) !== null && _a !== void 0 ? _a : [];
52
+ var _b;
53
+ const events = (_b = this.events.get(name)) !== null && _b !== void 0 ? _b : [];
40
54
  events.push(callback);
41
55
  this.events.set(name, events);
42
56
  }
43
- send(name, data, expectResponse = false) {
57
+ /**
58
+ * Send a message to the server
59
+ * @param name Name of the message
60
+ * @param data Data to send
61
+ */
62
+ send(name, data) {
44
63
  if (name[0] === '_')
45
64
  name = '_' + name;
46
- this.ws.send(message_1.Message.Create(name, data));
47
- if (!expectResponse)
48
- return;
65
+ const update = {
66
+ instruction: 'resp',
67
+ name,
68
+ response: data
69
+ };
70
+ this.ws.send(message_1.Message.Native(update));
71
+ }
72
+ /**
73
+ * Send a message to the server and wait for a response
74
+ * @param name Name of the message
75
+ * @param data Data to send
76
+ * @returns Promise that resolves when the message is received
77
+ */
78
+ await(name, data) {
79
+ this.send(name, data);
49
80
  return new Promise(res => this.events.set(Symbol.for("_" + name), [res]));
50
81
  }
51
82
  /**
@@ -66,26 +97,28 @@ class Multyx {
66
97
  }
67
98
  }
68
99
  /**
69
- * Create a callback function that gets called for any current or future client
70
- * @param callbackfn Function to call for every client
100
+ * Add a function to be called after each frame
101
+ * @param callback Function to call after each frame
71
102
  */
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);
103
+ [(_a = utils_1.Done, utils_1.Add)](callback) {
104
+ this[utils_1.Done].push(callback);
77
105
  }
106
+ /**
107
+ * Parse a native event from the server
108
+ * @param msg Message to parse
109
+ */
78
110
  parseNativeEvent(msg) {
79
- var _a, _b, _c, _d;
111
+ var _b, _c, _d, _e;
112
+ msg.data = msg.data.map(message_1.UncompressUpdate);
80
113
  if (this.options.logUpdateFrame)
81
- console.log(msg);
114
+ console.log(msg.data);
82
115
  for (const update of msg.data) {
83
116
  switch (update.instruction) {
84
117
  // Initialization
85
118
  case 'init': {
86
119
  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));
120
+ for (const listener of (_b = this.events.get(Multyx.Start)) !== null && _b !== void 0 ? _b : []) {
121
+ this[utils_1.Done].push(() => listener(update));
89
122
  }
90
123
  // Clear start event as it will never be called again
91
124
  if (this.events.has(Multyx.Start))
@@ -94,9 +127,24 @@ class Multyx {
94
127
  }
95
128
  // Client or team data edit
96
129
  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));
130
+ if (update.path.length == 1) {
131
+ if (update.team) {
132
+ this.teams.set(update.path[0], new utils_1.EditWrapper(update.value));
133
+ }
134
+ else {
135
+ this.clients[update.path[0]] = new items_1.MultyxClientObject(this, new utils_1.EditWrapper(update.value), [update.path[0]], false);
136
+ }
137
+ }
138
+ else {
139
+ const agent = update.team
140
+ ? this.teams.get(update.path[0])
141
+ : this.clients[update.path[0]];
142
+ if (!agent)
143
+ return;
144
+ agent.set(update.path.slice(1), new utils_1.EditWrapper(update.value));
145
+ }
146
+ for (const listener of (_c = this.events.get(Multyx.Edit)) !== null && _c !== void 0 ? _c : []) {
147
+ this[utils_1.Done].push(() => listener(update));
100
148
  }
101
149
  break;
102
150
  }
@@ -108,16 +156,16 @@ class Multyx {
108
156
  // Connection
109
157
  case 'conn': {
110
158
  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]));
159
+ for (const listener of (_d = this.events.get(Multyx.Connection)) !== null && _d !== void 0 ? _d : []) {
160
+ this[utils_1.Done].push(() => listener(this.clients[update.uuid]));
113
161
  }
114
162
  break;
115
163
  }
116
164
  // Disconnection
117
165
  case 'dcon': {
118
- for (const listener of (_d = this.events.get(Multyx.Disconnect)) !== null && _d !== void 0 ? _d : []) {
166
+ for (const listener of (_e = this.events.get(Multyx.Disconnect)) !== null && _e !== void 0 ? _e : []) {
119
167
  const clientValue = this.clients[update.client].value;
120
- this.listenerQueue.push(() => listener(clientValue));
168
+ this[utils_1.Done].push(() => listener(clientValue));
121
169
  }
122
170
  delete this.clients[update.client];
123
171
  break;
@@ -125,7 +173,8 @@ class Multyx {
125
173
  // Response to client
126
174
  case 'resp': {
127
175
  const promiseResolve = this.events.get(Symbol.for("_" + update.name))[0];
128
- promiseResolve(update.response);
176
+ this.events.delete(Symbol.for("_" + update.name));
177
+ this[utils_1.Done].push(() => promiseResolve(update.response));
129
178
  break;
130
179
  }
131
180
  default: {
@@ -135,15 +184,15 @@ class Multyx {
135
184
  }
136
185
  }
137
186
  }
138
- this.listenerQueue.forEach(x => x());
139
- this.listenerQueue.length = 0;
187
+ this[utils_1.Done].forEach(x => x());
188
+ this[utils_1.Done].length = 0;
140
189
  }
141
190
  initialize(update) {
191
+ this.tps = update.tps;
142
192
  this.uuid = update.client.uuid;
143
193
  this.joinTime = update.client.joinTime;
144
194
  this.controller.listening = new Set(update.client.controller);
145
195
  // Create MultyxClientObject for all teams
146
- this.teams = new items_1.MultyxClientObject(this, {}, [], true);
147
196
  for (const team of Object.keys(update.teams)) {
148
197
  this.teams[team] = new utils_1.EditWrapper(update.teams[team]);
149
198
  }
@@ -165,28 +214,14 @@ class Multyx {
165
214
  obj[utils_1.Unpack](table);
166
215
  }
167
216
  }
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
217
  parseSelf(update) {
183
- if (update.prop == 'controller') {
218
+ if (update.property == 'controller') {
184
219
  this.controller.listening = new Set(update.data);
185
220
  }
186
- else if (update.prop == 'uuid') {
221
+ else if (update.property == 'uuid') {
187
222
  this.uuid = update.data;
188
223
  }
189
- else if (update.prop == 'constraint') {
224
+ else if (update.property == 'constraint') {
190
225
  let route = this.uuid == update.data.path[0] ? this.self : this.teams[update.data.path[0]];
191
226
  for (const prop of update.data.path.slice(1))
192
227
  route = route === null || route === void 0 ? void 0 : route[prop];
@@ -194,13 +229,24 @@ class Multyx {
194
229
  return;
195
230
  route[utils_1.Unpack]({ [update.data.name]: update.data.args });
196
231
  }
232
+ else if (update.property == 'space') {
233
+ this.space = update.data;
234
+ this.updateSpace();
235
+ }
197
236
  }
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);
237
+ // Hide all spaces except the current one
238
+ updateSpace() {
239
+ if (this.space == 'default') {
240
+ document.querySelectorAll('[data-multyx-space]').forEach(space => {
241
+ space.style.display = 'block';
242
+ space.style.pointerEvents = 'auto';
243
+ });
244
+ return;
245
+ }
246
+ document.querySelectorAll('[data-multyx-space]').forEach(space => {
247
+ space.style.display = space.dataset.multyxSpace == this.space ? 'block' : 'none';
248
+ space.style.pointerEvents = space.dataset.multyxSpace == this.space ? 'auto' : 'none';
249
+ });
204
250
  }
205
251
  }
206
252
  Multyx.Start = Symbol('start');
@@ -2,4 +2,5 @@ import MultyxClientList from "./list";
2
2
  import MultyxClientObject from "./object";
3
3
  import MultyxClientValue from "./value";
4
4
  type MultyxClientItem<T = any> = T extends any[] ? MultyxClientList : T extends object ? MultyxClientObject : MultyxClientValue;
5
- export { MultyxClientList, MultyxClientObject, MultyxClientValue, MultyxClientItem, };
5
+ declare function IsMultyxClientItem(value: any): value is MultyxClientItem;
6
+ export { MultyxClientList, MultyxClientObject, MultyxClientValue, MultyxClientItem, IsMultyxClientItem, };
@@ -1,9 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MultyxClientValue = exports.MultyxClientObject = exports.MultyxClientList = void 0;
4
+ exports.IsMultyxClientItem = IsMultyxClientItem;
4
5
  const list_1 = require("./list");
5
6
  exports.MultyxClientList = list_1.default;
6
7
  const object_1 = require("./object");
7
8
  exports.MultyxClientObject = object_1.default;
8
9
  const value_1 = require("./value");
9
10
  exports.MultyxClientValue = value_1.default;
11
+ function IsMultyxClientItem(value) {
12
+ return value instanceof list_1.default || value instanceof object_1.default || value instanceof value_1.default;
13
+ }
@@ -1,22 +1,42 @@
1
1
  import Multyx from '../';
2
- import { MultyxClientItem } from '.';
3
- import { EditWrapper } from '../utils';
4
- import MultyxClientObject from "./object";
5
- export default class MultyxClientList extends MultyxClientObject {
6
- length: number;
2
+ import { type MultyxClientItem, type MultyxClientObject, MultyxClientValue } from '.';
3
+ import { EditWrapper, Unpack } from '../utils';
4
+ export default class MultyxClientList {
5
+ protected list: MultyxClientItem[];
6
+ private multyx;
7
+ propertyPath: string[];
8
+ editable: boolean;
9
+ private editCallbacks;
10
+ addEditCallback(callback: (index: number, value: any, oldValue: any) => void): void;
7
11
  get value(): any[];
12
+ get length(): number;
13
+ set length(length: number);
14
+ /**
15
+ * Shifting operations are needed to ensure that operations on elements in
16
+ * the list do not need to worry about the index of the element.
17
+ *
18
+ * Instead of changing each element's value when shifting, these shift
19
+ * operations are used to ensure that each MultyxClientItem stays the same
20
+ * @param index Index to shift from, -1 if special operation
21
+ * @param shift Shift amount, positive for right, negative for left
22
+ */
23
+ private handleShiftOperation;
8
24
  constructor(multyx: Multyx, list: any[] | EditWrapper<any[]>, propertyPath: string[], editable: boolean);
9
- set(index: string | number, value: any): boolean;
10
- delete(index: string | number, native?: boolean): boolean;
25
+ has(index: number): boolean;
26
+ get(index: number | string[]): MultyxClientItem;
27
+ private recursiveSet;
28
+ set(index: number | string[], value: any): boolean;
29
+ delete(index: number, native?: boolean): boolean;
11
30
  /**
12
- * Create a callback function that gets called for any current or future element in list
13
- * @param callbackfn Function to call for every element
31
+ * Wait for a specific index to be set
32
+ * @param index Index to wait for
33
+ * @returns Promise that resolves when the value is set
14
34
  */
15
- forAll(callbackfn: (value: any, index: number) => void): void;
35
+ await(index: number): Promise<unknown>;
16
36
  push(...items: any): number;
17
37
  pop(): MultyxClientItem | null;
18
38
  unshift(...items: any[]): number;
19
- shift(): import("./value").default | MultyxClientObject;
39
+ shift(): MultyxClientList | MultyxClientObject | MultyxClientValue;
20
40
  splice(start: number, deleteCount?: number, ...items: any[]): void;
21
41
  filter(predicate: (value: any, index: number, array: MultyxClientList) => boolean): void;
22
42
  map(callbackfn: (value: any, index: number, array: MultyxClientList) => any): void;
@@ -27,12 +47,11 @@ export default class MultyxClientList extends MultyxClientObject {
27
47
  forEach(callbackfn: (value: any, index: number, array: MultyxClientList) => void): void;
28
48
  every(predicate: (value: any, index: number, array: MultyxClientList) => boolean): boolean;
29
49
  some(predicate: (value: any, index: number, array: MultyxClientList) => boolean): boolean;
30
- find(predicate: (value: any, index: number, array: MultyxClientList) => boolean): import("./value").default | MultyxClientObject;
50
+ find(predicate: (value: any, index: number, array: MultyxClientList) => boolean): MultyxClientList | MultyxClientObject | MultyxClientValue;
31
51
  findIndex(predicate: (value: any, index: number, array: MultyxClientList) => boolean): number;
32
- deorder(): MultyxClientItem[];
33
- deorderEntries(): [number, MultyxClientItem][];
34
52
  entries(): [any, number][];
35
53
  keys(): number[];
54
+ [Unpack](constraints: any[]): void;
36
55
  [Symbol.iterator](): Iterator<MultyxClientItem>;
37
56
  toString: () => string;
38
57
  valueOf: () => any[];