multyx-client 0.1.1 → 0.1.3
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 +35 -15
- package/dist/index.js +106 -60
- package/dist/items/index.d.ts +2 -1
- package/dist/items/index.js +4 -0
- package/dist/items/list.d.ts +33 -14
- package/dist/items/list.js +186 -46
- package/dist/items/object.d.ts +14 -10
- package/dist/items/object.js +84 -38
- package/dist/items/value.d.ts +7 -8
- package/dist/items/value.js +27 -59
- package/dist/message.d.ts +111 -1
- package/dist/message.js +69 -4
- package/dist/types.d.ts +6 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +2 -1
- package/multyx.js +1 -1
- package/package.json +6 -3
- package/src/index.ts +102 -59
- package/src/items/index.ts +5 -0
- package/src/items/list.ts +220 -55
- package/src/items/object.ts +96 -49
- package/src/items/value.ts +37 -66
- package/src/message.ts +61 -4
- package/src/types.ts +7 -1
- package/src/utils.ts +1 -0
package/dist/items/list.js
CHANGED
|
@@ -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
|
|
6
|
-
|
|
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
|
-
|
|
73
|
+
this.editCallbacks = [];
|
|
15
74
|
this.toString = () => this.value.toString();
|
|
16
75
|
this.valueOf = () => this.value;
|
|
17
76
|
this[_a] = () => this.value;
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
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
|
|
23
|
-
return
|
|
24
|
-
return o
|
|
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
|
-
|
|
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 (
|
|
45
|
-
|
|
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,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
*
|
|
65
|
-
* @param
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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 = [];
|
package/dist/items/object.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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:
|
|
15
|
-
|
|
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
|
package/dist/items/object.js
CHANGED
|
@@ -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
|
-
|
|
37
|
+
const isEditWrapper = object instanceof utils_1.EditWrapper;
|
|
20
38
|
if (object instanceof MultyxClientObject)
|
|
21
39
|
object = object.value;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (!
|
|
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
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
}
|
package/dist/items/value.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/items/value.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
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;
|