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.
@@ -1,31 +1,104 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ const _1 = require(".");
4
5
  const utils_1 = require("../utils");
5
- const object_1 = require("./object");
6
- class MultyxClientList extends object_1.default {
6
+ const router_1 = require("./router");
7
+ const message_1 = require("../message");
8
+ class MultyxClientList {
9
+ addEditCallback(callback) {
10
+ this.editCallbacks.push(callback);
11
+ }
7
12
  get value() {
13
+ var _b;
8
14
  const parsed = [];
9
15
  for (let i = 0; i < this.length; i++)
10
- parsed[i] = this.get(i).value;
16
+ parsed[i] = (_b = this.get(i)) === null || _b === void 0 ? void 0 : _b.value;
11
17
  return parsed;
12
18
  }
19
+ get length() {
20
+ return this.list.length;
21
+ }
22
+ set length(length) {
23
+ this.list.length = length;
24
+ }
25
+ /**
26
+ * Shifting operations are needed to ensure that operations on elements in
27
+ * the list do not need to worry about the index of the element.
28
+ *
29
+ * Instead of changing each element's value when shifting, these shift
30
+ * operations are used to ensure that each MultyxClientItem stays the same
31
+ * @param index Index to shift from, -1 if special operation
32
+ * @param shift Shift amount, positive for right, negative for left
33
+ */
34
+ handleShiftOperation(index, shift) {
35
+ const operation = index >= 0
36
+ ? shift >= 0 ? 'right' : 'left'
37
+ : shift == 0 ? 'reverse' : shift < 0 ? 'length' : 'unknown';
38
+ switch (operation) {
39
+ // Reverse the array
40
+ case 'reverse':
41
+ for (let i = 0; i < Math.floor(this.length / 2); i++) {
42
+ const temp = this.list[i];
43
+ this.list[i] = this.list[this.length - 1 - i];
44
+ this.list[this.length - 1 - i] = temp;
45
+ }
46
+ break;
47
+ // Shift items to the left
48
+ case 'left':
49
+ for (let i = index; i < this.length; i++) {
50
+ if (i + shift < 0)
51
+ continue;
52
+ this.list[i + shift] = this.list[i];
53
+ }
54
+ break;
55
+ // Shift items to the right
56
+ case 'right':
57
+ for (let i = this.length - 1; i >= index; i--) {
58
+ this.list[i + shift] = this.list[i];
59
+ }
60
+ break;
61
+ // Alter the length of the array
62
+ case 'length':
63
+ this.length += shift;
64
+ break;
65
+ // Unknown operation
66
+ default:
67
+ if (this.multyx.options.verbose) {
68
+ console.error("Unknown shift operation: " + operation);
69
+ }
70
+ }
71
+ }
13
72
  constructor(multyx, list, propertyPath = [], editable) {
14
- super(multyx, {}, propertyPath, editable);
73
+ this.editCallbacks = [];
15
74
  this.toString = () => this.value.toString();
16
75
  this.valueOf = () => this.value;
17
76
  this[_a] = () => this.value;
18
- this.length = 0;
19
- this.push(...(list instanceof utils_1.EditWrapper ? list.value.map(x => new utils_1.EditWrapper(x)) : list));
77
+ this.list = [];
78
+ this.propertyPath = propertyPath;
79
+ this.multyx = multyx;
80
+ this.editable = editable;
81
+ const isEditWrapper = list instanceof utils_1.EditWrapper;
82
+ if (list instanceof MultyxClientList)
83
+ list = list.value;
84
+ if (list instanceof utils_1.EditWrapper)
85
+ list = list.value;
86
+ for (let i = 0; i < list.length; i++) {
87
+ this.set(i, isEditWrapper
88
+ ? new utils_1.EditWrapper(list[i])
89
+ : list[i]);
90
+ }
20
91
  return new Proxy(this, {
21
92
  has: (o, p) => {
22
- if (p in o)
23
- return true;
24
- return o.has(p);
93
+ if (typeof p == 'number')
94
+ return o.has(p);
95
+ return p in o;
25
96
  },
26
97
  get: (o, p) => {
27
98
  if (p in o)
28
99
  return o[p];
100
+ if (!isNaN(parseInt(p)))
101
+ p = parseInt(p);
29
102
  return o.get(p);
30
103
  },
31
104
  set: (o, p, v) => {
@@ -33,42 +106,116 @@ class MultyxClientList extends object_1.default {
33
106
  o[p] = v;
34
107
  return true;
35
108
  }
36
- return o.set(p, v);
109
+ return !!o.set(p, v);
37
110
  },
38
111
  deleteProperty: (o, p) => {
39
- return o.delete(p, false);
112
+ if (typeof p == 'number')
113
+ return o.delete(p);
114
+ return false;
40
115
  }
41
116
  });
42
117
  }
118
+ has(index) {
119
+ return index >= 0 && index < this.length;
120
+ }
121
+ get(index) {
122
+ if (typeof index === 'number')
123
+ return this.list[index];
124
+ if (index.length == 0)
125
+ return this;
126
+ if (index.length == 1)
127
+ return this.list[parseInt(index[0])];
128
+ const item = this.list[parseInt(index[0])];
129
+ if (!item || (item instanceof _1.MultyxClientValue))
130
+ return undefined;
131
+ return item.get(index.slice(1));
132
+ }
133
+ recursiveSet(path, value) {
134
+ if (path.length == 0) {
135
+ if (this.multyx.options.verbose) {
136
+ console.error(`Attempting to edit MultyxClientList with no path. Setting '${this.propertyPath.join('.')}' to ${value}`);
137
+ }
138
+ return false;
139
+ }
140
+ if (path[0] == "shift" && value instanceof utils_1.EditWrapper) {
141
+ this.handleShiftOperation(parseInt(path[1]), value.value);
142
+ return true;
143
+ }
144
+ if (path.length == 1)
145
+ return this.set(parseInt(path[0]), value);
146
+ let next = this.get(parseInt(path[0]));
147
+ if (next instanceof _1.MultyxClientValue || next == undefined) {
148
+ this.set(parseInt(path[0]), new utils_1.EditWrapper({}));
149
+ next = this.get(parseInt(path[0]));
150
+ }
151
+ return next.set(path.slice(1), value);
152
+ }
43
153
  set(index, value) {
44
- if (typeof index == 'string')
45
- index = parseInt(index);
154
+ if (Array.isArray(index))
155
+ return this.recursiveSet(index, value);
156
+ const oldValue = this.get(index);
157
+ const serverSet = value instanceof utils_1.EditWrapper;
158
+ const allowed = serverSet || this.editable;
159
+ if (serverSet || (0, _1.IsMultyxClientItem)(value))
160
+ value = value.value;
46
161
  if (value === undefined)
47
- return this.delete(index, false);
48
- if (value instanceof utils_1.EditWrapper && value.value === undefined)
49
- return this.delete(index, true);
50
- const result = super.set(index, value);
51
- if (result && index >= this.length)
52
- this.length = index + 1;
53
- return result;
162
+ return this.delete(index, serverSet);
163
+ // If value is a MultyxClientValue, set the value
164
+ if (this.list[index] instanceof _1.MultyxClientValue && typeof value != 'object') {
165
+ return this.list[index].set(serverSet ? new utils_1.EditWrapper(value) : value);
166
+ }
167
+ // Attempting to edit property not editable to client
168
+ if (!allowed) {
169
+ if (this.multyx.options.verbose) {
170
+ console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join('.') + '.' + index}' to ${value}`);
171
+ }
172
+ return false;
173
+ }
174
+ this.list[index] = new ((0, router_1.default)(value))(this.multyx, serverSet ? new utils_1.EditWrapper(value) : value, [...this.propertyPath, index.toString()], this.editable);
175
+ const propSymbol = Symbol.for("_" + this.propertyPath.join('.') + '.' + index);
176
+ if (this.multyx.events.has(propSymbol)) {
177
+ this.multyx[utils_1.Done].push(...this.multyx.events.get(propSymbol).map(e => () => e(this.list[index])));
178
+ }
179
+ // We have to push into queue, since object may not be fully created
180
+ // and there may still be more updates to parse
181
+ for (const listener of this.editCallbacks) {
182
+ this.multyx[utils_1.Add](() => listener(index, this.get(index), oldValue));
183
+ }
184
+ return true;
54
185
  }
55
186
  delete(index, native = false) {
187
+ const oldValue = this.get(index);
56
188
  if (typeof index == 'string')
57
189
  index = parseInt(index);
58
- const res = super.delete(index, native);
59
- if (res)
60
- this.length = this.reduce((a, c, i) => c !== undefined ? i + 1 : a, 0);
61
- return res;
190
+ if (!this.editable && !native) {
191
+ if (this.multyx.options.verbose) {
192
+ console.error(`Attempting to delete property that is not editable. Deleting '${this.propertyPath.join('.') + '.' + index}'`);
193
+ }
194
+ return false;
195
+ }
196
+ delete this.list[index];
197
+ for (const listener of this.editCallbacks) {
198
+ this.multyx[utils_1.Add](() => listener(index, undefined, oldValue));
199
+ }
200
+ if (!native) {
201
+ this.multyx.ws.send(message_1.Message.Native({
202
+ instruction: 'edit',
203
+ path: [...this.propertyPath, index.toString()],
204
+ value: undefined
205
+ }));
206
+ }
207
+ return true;
62
208
  }
63
209
  /**
64
- * Create a callback function that gets called for any current or future element in list
65
- * @param callbackfn Function to call for every element
210
+ * Wait for a specific index to be set
211
+ * @param index Index to wait for
212
+ * @returns Promise that resolves when the value is set
66
213
  */
67
- forAll(callbackfn) {
68
- for (let i = 0; i < this.length; i++) {
69
- callbackfn(this.get(i), i);
70
- }
71
- super.forAll((key, value) => callbackfn(value, key));
214
+ await(index) {
215
+ if (this.has(index))
216
+ return Promise.resolve(this.get(index));
217
+ const propSymbol = Symbol.for("_" + this.propertyPath.join('.') + '.' + index);
218
+ return new Promise(res => this.multyx.on(propSymbol, res));
72
219
  }
73
220
  /* All general array methods */
74
221
  push(...items) {
@@ -144,8 +291,9 @@ class MultyxClientList extends object_1.default {
144
291
  }
145
292
  }
146
293
  map(callbackfn) {
294
+ const mapped = [];
147
295
  for (let i = 0; i < this.length; i++) {
148
- this.set(i, callbackfn(this.get(i), i, this));
296
+ mapped.push(callbackfn(this.get(i), i, this));
149
297
  }
150
298
  }
151
299
  flat() {
@@ -214,20 +362,6 @@ class MultyxClientList extends object_1.default {
214
362
  }
215
363
  return -1;
216
364
  }
217
- deorder() {
218
- const values = [];
219
- for (const index in this.object) {
220
- values.push(this.get(index));
221
- }
222
- return values;
223
- }
224
- deorderEntries() {
225
- const values = [];
226
- for (const index in this.object) {
227
- values.push([parseInt(index), this.get(index)]);
228
- }
229
- return values;
230
- }
231
365
  entries() {
232
366
  const entryList = [];
233
367
  for (let i = 0; i < this.length; i++) {
@@ -238,6 +372,12 @@ class MultyxClientList extends object_1.default {
238
372
  keys() {
239
373
  return Array(this.length).fill(0).map((_, i) => i);
240
374
  }
375
+ [utils_1.Unpack](constraints) {
376
+ var _b;
377
+ for (let i = 0; i < this.length; i++) {
378
+ (_b = this.get(i)) === null || _b === void 0 ? void 0 : _b[utils_1.Unpack](constraints[i]);
379
+ }
380
+ }
241
381
  /* Native methods to allow MultyxClientList to be treated as array */
242
382
  [Symbol.iterator]() {
243
383
  const values = [];
@@ -1,27 +1,31 @@
1
1
  import { RawObject } from '../types';
2
- import { EditWrapper, Unpack } from "../utils";
2
+ import { Edit, EditWrapper, Unpack } from "../utils";
3
3
  import type Multyx from '../index';
4
- import type { MultyxClientItem } from ".";
4
+ import { type MultyxClientItem } from ".";
5
5
  export default class MultyxClientObject {
6
6
  protected object: RawObject<MultyxClientItem>;
7
7
  private multyx;
8
8
  propertyPath: string[];
9
9
  editable: boolean;
10
- private setterListeners;
10
+ private editCallbacks;
11
11
  get value(): {};
12
+ addEditCallback(callback: (key: any, value: any) => void): void;
13
+ [Edit](updatePath: string[], value: any): void;
12
14
  constructor(multyx: Multyx, object: RawObject | EditWrapper<RawObject>, propertyPath: string[], editable: boolean);
13
15
  has(property: any): boolean;
14
- get(property: any): MultyxClientItem;
15
- set(property: any, value: any): boolean;
16
+ get(property: string | string[]): MultyxClientItem;
17
+ private recursiveSet;
18
+ set(property: string | string[], value: any): boolean;
16
19
  delete(property: any, native?: boolean): boolean;
17
- /**
18
- * Create a callback function that gets called for any current or future property in object
19
- * @param callbackfn Function to call for every property
20
- */
21
- forAll(callbackfn: (key: any, value: any) => void): void;
22
20
  keys(): any[];
23
21
  values(): any[];
24
22
  entries(): [any, any][];
23
+ /**
24
+ * Wait for a specific property to be set
25
+ * @param property Property to wait for
26
+ * @returns Promise that resolves when the value is set
27
+ */
28
+ await(property: string): Promise<unknown>;
25
29
  /**
26
30
  * Unpack constraints from server
27
31
  * @param constraints Packed constraints object mirroring MultyxClientObject shape
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const message_1 = require("../message");
4
4
  const utils_1 = require("../utils");
5
+ const _1 = require(".");
5
6
  const router_1 = require("./router");
6
7
  const value_1 = require("./value");
7
8
  class MultyxClientObject {
@@ -11,17 +12,36 @@ class MultyxClientObject {
11
12
  parsed[prop] = this.object[prop];
12
13
  return parsed;
13
14
  }
15
+ addEditCallback(callback) {
16
+ this.editCallbacks.push(callback);
17
+ }
18
+ [utils_1.Edit](updatePath, value) {
19
+ if (updatePath.length == 1) {
20
+ this.set(updatePath[0], new utils_1.EditWrapper(value));
21
+ return;
22
+ }
23
+ if (updatePath.length == 0 && this.multyx.options.verbose) {
24
+ console.error("Update path is empty. Attempting to edit MultyxClientObject with no path.");
25
+ }
26
+ if (!this.has(updatePath[0])) {
27
+ this.set(updatePath[0], new utils_1.EditWrapper({}));
28
+ }
29
+ this.get(updatePath[0])[utils_1.Edit](updatePath.slice(1), value);
30
+ }
14
31
  constructor(multyx, object, propertyPath = [], editable) {
32
+ this.editCallbacks = [];
15
33
  this.object = {};
16
34
  this.propertyPath = propertyPath;
17
35
  this.multyx = multyx;
18
36
  this.editable = editable;
19
- this.setterListeners = [];
37
+ const isEditWrapper = object instanceof utils_1.EditWrapper;
20
38
  if (object instanceof MultyxClientObject)
21
39
  object = object.value;
22
- for (const prop in (object instanceof utils_1.EditWrapper ? object.value : object)) {
23
- this.set(prop, object instanceof utils_1.EditWrapper
24
- ? new utils_1.EditWrapper(object.value[prop])
40
+ if (object instanceof utils_1.EditWrapper)
41
+ object = object.value;
42
+ for (const prop in object) {
43
+ this.set(prop, isEditWrapper
44
+ ? new utils_1.EditWrapper(object[prop])
25
45
  : object[prop]);
26
46
  }
27
47
  if (this.constructor !== MultyxClientObject)
@@ -51,41 +71,65 @@ class MultyxClientObject {
51
71
  return property in this.object;
52
72
  }
53
73
  get(property) {
54
- return this.object[property];
74
+ if (typeof property === 'string')
75
+ return this.object[property];
76
+ if (property.length == 0)
77
+ return this;
78
+ if (property.length == 1)
79
+ return this.object[property[0]];
80
+ const next = this.object[property[0]];
81
+ if (!next || (next instanceof value_1.default))
82
+ return undefined;
83
+ return next.get(property.slice(1));
84
+ }
85
+ recursiveSet(path, value) {
86
+ if (path.length == 0) {
87
+ if (this.multyx.options.verbose) {
88
+ console.error(`Attempting to edit MultyxClientObject with no path. Setting '${this.propertyPath.join('.')}' to ${value}`);
89
+ }
90
+ return false;
91
+ }
92
+ if (path.length == 1)
93
+ return this.set(path[0], value);
94
+ let next = this.get(path[0]);
95
+ if (next instanceof value_1.default || next == undefined) {
96
+ if (isNaN(parseInt(path[1]))) {
97
+ this.set(path[0], new utils_1.EditWrapper({}));
98
+ next = this.get(path[0]);
99
+ }
100
+ else {
101
+ this.set(path[0], new utils_1.EditWrapper([]));
102
+ next = this.get(path[0]);
103
+ }
104
+ }
105
+ return next.set(path.slice(1), value);
55
106
  }
56
107
  set(property, value) {
108
+ if (Array.isArray(property))
109
+ return this.recursiveSet(property, value);
110
+ const serverSet = value instanceof utils_1.EditWrapper;
111
+ const allowed = serverSet || this.editable;
112
+ if (serverSet || (0, _1.IsMultyxClientItem)(value))
113
+ value = value.value;
57
114
  if (value === undefined)
58
- return this.delete(property);
115
+ return this.delete(property, serverSet);
59
116
  // Only create new MultyxClientItem when needed
60
- if (this.object[property] instanceof value_1.default)
61
- return this.object[property].set(value);
62
- // If value was deleted by the server
63
- if (value instanceof utils_1.EditWrapper && value.value === undefined)
64
- return this.delete(property, true);
117
+ if (this.object[property] instanceof value_1.default && typeof value != 'object') {
118
+ return this.object[property].set(serverSet ? new utils_1.EditWrapper(value) : value);
119
+ }
65
120
  // Attempting to edit property not editable to client
66
- if (!(value instanceof utils_1.EditWrapper) && !this.editable) {
121
+ if (!allowed) {
67
122
  if (this.multyx.options.verbose) {
68
123
  console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join('.') + '.' + property}' to ${value}`);
69
124
  }
70
125
  return false;
71
126
  }
72
127
  // Creating a new value
73
- this.object[property] = new ((0, router_1.default)(value instanceof utils_1.EditWrapper ? value.value : value))(this.multyx, value, [...this.propertyPath, property], this.editable);
74
- // We have to push into queue, since object may not be fully created
75
- // and there may still be more updates to parse
76
- for (const listener of this.setterListeners) {
77
- this.multyx[utils_1.Add](() => {
78
- if (this.has(property))
79
- listener(property, this.get(property));
80
- });
128
+ this.object[property] = new ((0, router_1.default)(value))(this.multyx, serverSet ? new utils_1.EditWrapper(value) : value, [...this.propertyPath, property], this.editable);
129
+ const propSymbol = Symbol.for("_" + this.propertyPath.join('.') + '.' + property);
130
+ if (this.multyx.events.has(propSymbol)) {
131
+ this.multyx[utils_1.Done].push(...this.multyx.events.get(propSymbol).map(e => () => e(this.object[property])));
81
132
  }
82
- // Relay change to server if not edit wrapped
83
- if (!(value instanceof utils_1.EditWrapper))
84
- this.multyx.ws.send(message_1.Message.Native({
85
- instruction: 'edit',
86
- path: this.propertyPath,
87
- value: this.object[property].value
88
- }));
89
133
  return true;
90
134
  }
91
135
  delete(property, native = false) {
@@ -106,16 +150,6 @@ class MultyxClientObject {
106
150
  }
107
151
  return true;
108
152
  }
109
- /**
110
- * Create a callback function that gets called for any current or future property in object
111
- * @param callbackfn Function to call for every property
112
- */
113
- forAll(callbackfn) {
114
- for (let prop in this.object) {
115
- callbackfn(prop, this.get(prop));
116
- }
117
- this.setterListeners.push(callbackfn);
118
- }
119
153
  keys() {
120
154
  return Object.keys(this.object);
121
155
  }
@@ -129,13 +163,25 @@ class MultyxClientObject {
129
163
  }
130
164
  return entryList;
131
165
  }
166
+ /**
167
+ * Wait for a specific property to be set
168
+ * @param property Property to wait for
169
+ * @returns Promise that resolves when the value is set
170
+ */
171
+ await(property) {
172
+ if (this.has(property))
173
+ return Promise.resolve(this.get(property));
174
+ const propSymbol = Symbol.for("_" + this.propertyPath.join('.') + '.' + property);
175
+ return new Promise(res => this.multyx.on(propSymbol, res));
176
+ }
132
177
  /**
133
178
  * Unpack constraints from server
134
179
  * @param constraints Packed constraints object mirroring MultyxClientObject shape
135
180
  */
136
181
  [utils_1.Unpack](constraints) {
182
+ var _a;
137
183
  for (const prop in constraints) {
138
- this.object[prop][utils_1.Unpack](constraints[prop]);
184
+ (_a = this.object[prop]) === null || _a === void 0 ? void 0 : _a[utils_1.Unpack](constraints[prop]);
139
185
  }
140
186
  }
141
187
  }
@@ -1,6 +1,6 @@
1
1
  import type Multyx from '../';
2
2
  import { Constraint, RawObject, Value } from "../types";
3
- import { EditWrapper, Unpack } from '../utils';
3
+ import { Edit, EditWrapper, Unpack } from '../utils';
4
4
  export default class MultyxClientValue {
5
5
  private _value;
6
6
  private multyx;
@@ -9,22 +9,21 @@ export default class MultyxClientValue {
9
9
  constraints: {
10
10
  [key: string]: Constraint;
11
11
  };
12
- private interpolator;
12
+ private readModifiers;
13
+ private editCallbacks;
13
14
  get value(): Value;
14
15
  set value(v: Value);
16
+ addReadModifier(modifier: (value: Value) => Value): void;
17
+ addEditCallback(callback: (value: Value, previousValue: Value) => void): void;
18
+ [Edit](updatePath: string[], value: any): void;
15
19
  constructor(multyx: Multyx, value: Value | EditWrapper<Value>, propertyPath: string[], editable: boolean);
16
20
  set(value: Value | EditWrapper<Value>): boolean;
21
+ bindElement(element: HTMLElement): void;
17
22
  /**
18
23
  * Unpack constraints sent from server and store
19
24
  * @param constraints Packed constraints from server
20
25
  */
21
26
  [Unpack](constraints: RawObject): void;
22
- /**
23
- * Linearly interpolate value across frames
24
- * Will run 1 frame behind on average
25
- */
26
- Lerp(): void;
27
- PredictiveLerp(): void;
28
27
  toString: () => string;
29
28
  valueOf: () => Value;
30
29
  [Symbol.toPrimitive]: () => Value;
@@ -5,16 +5,25 @@ const message_1 = require("../message");
5
5
  const utils_1 = require("../utils");
6
6
  class MultyxClientValue {
7
7
  get value() {
8
- if (this.interpolator)
9
- return this.interpolator.get();
10
- return this._value;
8
+ return this.readModifiers.reduce((value, modifier) => modifier(value), this._value);
11
9
  }
12
10
  set value(v) {
13
11
  this._value = v;
14
- if (this.interpolator)
15
- this.interpolator.set();
12
+ }
13
+ addReadModifier(modifier) {
14
+ this.readModifiers.push(modifier);
15
+ }
16
+ addEditCallback(callback) {
17
+ this.editCallbacks.push(callback);
18
+ }
19
+ [utils_1.Edit](updatePath, value) {
20
+ if (updatePath.length != 0)
21
+ return;
22
+ this.set(new utils_1.EditWrapper(value));
16
23
  }
17
24
  constructor(multyx, value, propertyPath = [], editable) {
25
+ this.readModifiers = [];
26
+ this.editCallbacks = [];
18
27
  /* Native methods to allow MultyxValue to be treated as primitive */
19
28
  this.toString = () => this.value.toString();
20
29
  this.valueOf = () => this.value;
@@ -24,10 +33,16 @@ class MultyxClientValue {
24
33
  this.multyx = multyx;
25
34
  this.constraints = {};
26
35
  this.set(value);
36
+ const propSymbol = Symbol.for("_" + this.propertyPath.join('.'));
37
+ if (this.multyx.events.has(propSymbol)) {
38
+ this.multyx[utils_1.Done].push(...this.multyx.events.get(propSymbol).map(e => () => e(this.value)));
39
+ }
27
40
  }
28
41
  set(value) {
29
42
  if (value instanceof utils_1.EditWrapper) {
43
+ const oldValue = this.value;
30
44
  this.value = value.value;
45
+ this.editCallbacks.forEach(fn => fn(value.value, oldValue));
31
46
  return true;
32
47
  }
33
48
  // Attempting to edit property not editable to client
@@ -60,6 +75,13 @@ class MultyxClientValue {
60
75
  }));
61
76
  return true;
62
77
  }
78
+ bindElement(element) {
79
+ this.addEditCallback((value, previousValue) => {
80
+ if (value !== previousValue) {
81
+ element.innerText = value.toString();
82
+ }
83
+ });
84
+ }
63
85
  /**
64
86
  * Unpack constraints sent from server and store
65
87
  * @param constraints Packed constraints from server
@@ -72,60 +94,6 @@ class MultyxClientValue {
72
94
  this.constraints[cname] = constraint;
73
95
  }
74
96
  }
75
- /**
76
- * Linearly interpolate value across frames
77
- * Will run 1 frame behind on average
78
- */
79
- Lerp() {
80
- this.interpolator = {
81
- history: [
82
- { value: this._value, time: Date.now() },
83
- { value: this._value, time: Date.now() }
84
- ],
85
- get: () => {
86
- const [e, s] = this.interpolator.history;
87
- const ratio = Math.min(1, (Date.now() - e.time) / Math.min(250, e.time - s.time));
88
- if (Number.isNaN(ratio) || typeof e.value != 'number' || typeof s.value != 'number')
89
- return e.value;
90
- return e.value * ratio + s.value * (1 - ratio);
91
- },
92
- set: () => {
93
- this.interpolator.history.pop();
94
- this.interpolator.history.unshift({
95
- value: this._value,
96
- time: Date.now()
97
- });
98
- }
99
- };
100
- }
101
- PredictiveLerp() {
102
- this.interpolator = {
103
- history: [
104
- { value: this._value, time: Date.now() },
105
- { value: this._value, time: Date.now() },
106
- { value: this._value, time: Date.now() }
107
- ],
108
- get: () => {
109
- const [e, s, p] = this.interpolator.history;
110
- const ratio = Math.min(1, (Date.now() - e.time) / (e.time - s.time));
111
- if (Number.isNaN(ratio) || typeof p.value != 'number')
112
- return e.value;
113
- if (typeof e.value != 'number' || typeof s.value != 'number')
114
- return e.value;
115
- // Speed changed too fast, don't interpolate, return new value
116
- if (Math.abs((e.value - s.value) / (s.value - p.value) - 1) > 0.2)
117
- return e.value;
118
- return e.value * (1 + ratio) - s.value * ratio;
119
- },
120
- set: () => {
121
- this.interpolator.history.pop();
122
- this.interpolator.history.unshift({
123
- value: this._value,
124
- time: Date.now()
125
- });
126
- }
127
- };
128
- }
129
97
  }
130
98
  _a = Symbol.toPrimitive;
131
99
  exports.default = MultyxClientValue;