@colyseus/schema 3.0.0-alpha.25 → 3.0.0-alpha.27
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/build/cjs/index.js +97 -102
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +97 -102
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +97 -102
- package/lib/Reflection.js +1 -3
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +1 -1
- package/lib/Schema.js +2 -2
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.js +13 -5
- package/lib/annotations.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +1 -0
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +1 -1
- package/lib/decoder/Decoder.js +2 -2
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.js +20 -17
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.js +3 -2
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +3 -3
- package/lib/encoder/Encoder.js +10 -11
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/StateView.d.ts +2 -2
- package/lib/encoder/StateView.js +45 -60
- package/lib/encoder/StateView.js.map +1 -1
- package/package.json +1 -1
- package/src/Reflection.ts +1 -3
- package/src/Schema.ts +2 -2
- package/src/annotations.ts +16 -5
- package/src/decoder/DecodeOperation.ts +4 -1
- package/src/decoder/Decoder.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +30 -20
- package/src/encoder/ChangeTree.ts +4 -2
- package/src/encoder/Encoder.ts +11 -13
- package/src/encoder/StateView.ts +50 -69
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateView.js","sourceRoot":"","sources":["../../src/encoder/StateView.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeTree, Ref } from \"./ChangeTree\";\nimport { $changes } from \"../types/symbols\";\nimport { DEFAULT_VIEW_TAG } from \"../annotations\";\nimport { OPERATION } from \"../encoding/spec\";\nimport { Metadata } from \"../Metadata\";\nimport type { Schema } from \"../Schema\";\n\nexport function createView(root: Schema) {\n}\n\nexport class StateView {\n /**\n * List of ChangeTree's that are visible to this view\n */\n items: WeakSet<ChangeTree> = new WeakSet<ChangeTree>();\n\n /**\n * List of ChangeTree's that are invisible to this view\n */\n invisible: WeakSet<ChangeTree> = new WeakSet<ChangeTree>();\n\n tags?: WeakMap<ChangeTree, Set<number>>; // TODO: use bit manipulation instead of Set<number> ()\n\n /**\n * Manual \"ADD\" operations for changes per ChangeTree, specific to this view.\n * (This is used to force encoding a property, even if it was not changed)\n */\n changes = new Map<ChangeTree, Map<number, OPERATION>>();\n\n // TODO: allow to set multiple tags at once\n add(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {\n if (!obj[$changes]) {\n console.warn(\"StateView#add(), invalid object:\", obj);\n return this;\n }\n\n // FIXME: ArraySchema/MapSchema does not have metadata\n const metadata: Metadata = obj.constructor[Symbol.metadata];\n\n let changeTree: ChangeTree = obj[$changes];\n this.items.add(changeTree);\n\n // Add children of this ChangeTree to this view\n changeTree.forEachChild((change, index) => {\n // Do not ADD children that don't have the same tag\n if (metadata && metadata[metadata[index]].tag !== tag) {\n return;\n }\n this.add(change.ref, tag);\n });\n\n // add parent ChangeTree's, if they are invisible to this view\n // TODO: REFACTOR addParent()\n this.addParent(changeTree, tag);\n\n //\n // TODO: when adding an item of a MapSchema, the changes may not\n // be set (only the parent's changes are set)\n //\n let changes = this.changes.get(changeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(changeTree, changes)\n }\n\n // set tag\n if (tag !== DEFAULT_VIEW_TAG) {\n if (!this.tags) {\n this.tags = new WeakMap<ChangeTree, Set<number>>();\n }\n let tags: Set<number>;\n if (!this.tags.has(changeTree)) {\n tags = new Set<number>();\n this.tags.set(changeTree, tags);\n } else {\n tags = this.tags.get(changeTree);\n }\n tags.add(tag);\n\n // Ref: add tagged properties\n metadata?.[-3]?.[tag]?.forEach((index) => {\n if (changeTree.getChange(index) !== OPERATION.DELETE) {\n changes.set(index, OPERATION.ADD)\n }\n });\n\n } else {\n\n // console.log(\"DEFAULT TAG\", changeTree.allChanges);\n\n // // add default tag properties\n // metadata?.[-3]?.[DEFAULT_VIEW_TAG]?.forEach((index) => {\n // if (changeTree.getChange(index) !== OPERATION.DELETE) {\n // changes.set(index, OPERATION.ADD);\n // }\n // });\n\n const allChangesSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)\n ? changeTree.allFilteredChanges\n : changeTree.allChanges;\n const it = allChangesSet.keys();\n const isInvisible = this.invisible.has(changeTree);\n\n for (const index of it) {\n if (\n (isInvisible || metadata?.[metadata?.[index]].tag === tag) &&\n changeTree.getChange(index) !== OPERATION.DELETE\n ) {\n changes.set(index, OPERATION.ADD);\n }\n }\n }\n\n // TODO: avoid unnecessary iteration here\n while (\n changeTree.parent &&\n (changeTree = changeTree.parent[$changes]) &&\n (changeTree.isFiltered || changeTree.isPartiallyFiltered)\n ) {\n this.items.add(changeTree);\n }\n\n return this;\n }\n\n protected addParent(changeTree: ChangeTree, tag: number) {\n const parentRef = changeTree.parent;\n if (!parentRef) { return; }\n\n const parentChangeTree = parentRef[$changes];\n const parentIndex = changeTree.parentIndex;\n\n if (!this.invisible.has(parentChangeTree)) {\n // parent is already available, no need to add it!\n return;\n }\n\n this.addParent(parentChangeTree, tag);\n\n // add parent's tag properties\n if (parentChangeTree.getChange(parentIndex) !== OPERATION.DELETE) {\n\n let parentChanges = this.changes.get(parentChangeTree);\n if (parentChanges === undefined) {\n parentChanges = new Map<number, OPERATION>();\n this.changes.set(parentChangeTree, parentChanges);\n }\n\n // console.log(\"add parent change\", {\n // parentIndex,\n // parentChanges,\n // parentChange: (\n // parentChangeTree.getChange(parentIndex) &&\n // OPERATION[parentChangeTree.getChange(parentIndex)]\n // ),\n // })\n\n if (!this.tags) { this.tags = new WeakMap<ChangeTree, Set<number>>(); }\n let tags: Set<number>;\n if (!this.tags.has(parentChangeTree)) {\n tags = new Set<number>();\n this.tags.set(parentChangeTree, tags);\n } else {\n tags = this.tags.get(parentChangeTree);\n }\n tags.add(tag);\n\n parentChanges.set(parentIndex, OPERATION.ADD);\n }\n\n }\n\n remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {\n const changeTree = obj[$changes];\n if (!changeTree) {\n console.warn(\"StateView#remove(), invalid object:\", obj);\n return this;\n }\n\n this.items.delete(changeTree);\n\n const ref = changeTree.ref;\n const metadata: Metadata = ref.constructor[Symbol.metadata];\n\n let changes = this.changes.get(changeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(changeTree, changes)\n }\n\n if (tag === DEFAULT_VIEW_TAG) {\n // parent is collection (Map/Array)\n const parent = changeTree.parent;\n if (!Metadata.isValidInstance(parent)) {\n const parentChangeTree = parent[$changes];\n let changes = this.changes.get(parentChangeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(parentChangeTree, changes)\n }\n // DELETE / DELETE BY REF ID\n changes.set(changeTree.parentIndex, OPERATION.DELETE);\n\n } else {\n // delete all \"tagged\" properties.\n metadata[-2].forEach((index) =>\n changes.set(index, OPERATION.DELETE));\n }\n\n\n } else {\n // delete only tagged properties\n metadata[-3][tag].forEach((index) =>\n changes.set(index, OPERATION.DELETE));\n }\n\n // remove tag\n if (this.tags && this.tags.has(changeTree)) {\n const tags = this.tags.get(changeTree);\n if (tag === undefined) {\n // delete all tags\n this.tags.delete(changeTree);\n } else {\n // delete specific tag\n tags.delete(tag);\n\n // if tag set is empty, delete it entirely\n if (tags.size === 0) {\n this.tags.delete(changeTree);\n }\n }\n }\n\n return this;\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"StateView.js","sourceRoot":"","sources":["../../src/encoder/StateView.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeTree, Ref } from \"./ChangeTree\";\nimport { $changes } from \"../types/symbols\";\nimport { DEFAULT_VIEW_TAG } from \"../annotations\";\nimport { OPERATION } from \"../encoding/spec\";\nimport { Metadata } from \"../Metadata\";\nimport type { Schema } from \"../Schema\";\n\nexport function createView(root: Schema) {\n}\n\nexport class StateView {\n /**\n * List of ChangeTree's that are visible to this view\n */\n items: WeakSet<ChangeTree> = new WeakSet<ChangeTree>();\n\n /**\n * List of ChangeTree's that are invisible to this view\n */\n invisible: WeakSet<ChangeTree> = new WeakSet<ChangeTree>();\n\n tags?: WeakMap<ChangeTree, Set<number>>; // TODO: use bit manipulation instead of Set<number> ()\n\n /**\n * Manual \"ADD\" operations for changes per ChangeTree, specific to this view.\n * (This is used to force encoding a property, even if it was not changed)\n */\n changes = new Map<ChangeTree, Map<number, OPERATION>>();\n\n // TODO: allow to set multiple tags at once\n add(obj: Ref, tag: number = DEFAULT_VIEW_TAG, checkIncludeParent: boolean = true) {\n if (!obj[$changes]) {\n console.warn(\"StateView#add(), invalid object:\", obj);\n return this;\n }\n\n // FIXME: ArraySchema/MapSchema does not have metadata\n const metadata: Metadata = obj.constructor[Symbol.metadata];\n const changeTree: ChangeTree = obj[$changes];\n this.items.add(changeTree);\n\n // add parent ChangeTree's\n // - if it was invisible to this view\n // - if it were previously filtered out\n if (checkIncludeParent && changeTree.parent) {\n this.addParent(changeTree.parent[$changes], changeTree.parentIndex, tag);\n }\n\n //\n // TODO: when adding an item of a MapSchema, the changes may not\n // be set (only the parent's changes are set)\n //\n let changes = this.changes.get(changeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(changeTree, changes)\n }\n\n // set tag\n if (tag !== DEFAULT_VIEW_TAG) {\n if (!this.tags) {\n this.tags = new WeakMap<ChangeTree, Set<number>>();\n }\n let tags: Set<number>;\n if (!this.tags.has(changeTree)) {\n tags = new Set<number>();\n this.tags.set(changeTree, tags);\n } else {\n tags = this.tags.get(changeTree);\n }\n tags.add(tag);\n\n // Ref: add tagged properties\n metadata?.[-3]?.[tag]?.forEach((index) => {\n if (changeTree.getChange(index) !== OPERATION.DELETE) {\n changes.set(index, OPERATION.ADD)\n }\n });\n\n } else {\n const isInvisible = this.invisible.has(changeTree);\n const changeSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)\n ? changeTree.allFilteredChanges\n : changeTree.allChanges;\n\n changeSet.forEach((op, index) => {\n const tagAtIndex = metadata?.[metadata?.[index]].tag;\n if (\n (\n isInvisible || // if \"invisible\", include all\n tagAtIndex === undefined || // \"all change\" with no tag\n tagAtIndex === tag // tagged property\n ) &&\n op !== OPERATION.DELETE\n ) {\n changes.set(index, op);\n }\n });\n }\n\n // Add children of this ChangeTree to this view\n changeTree.forEachChild((change, index) => {\n // Do not ADD children that don't have the same tag\n if (metadata && metadata[metadata[index]].tag !== tag) {\n return;\n }\n this.add(change.ref, tag, false);\n });\n\n return this;\n }\n\n protected addParent(changeTree: ChangeTree, parentIndex: number, tag: number) {\n // view must have all \"changeTree\" parent tree\n this.items.add(changeTree);\n\n // add parent's parent\n const parentChangeTree = changeTree.parent?.[$changes];\n if (parentChangeTree && (parentChangeTree.isFiltered || parentChangeTree.isPartiallyFiltered)) {\n this.addParent(parentChangeTree, changeTree.parentIndex, tag);\n }\n\n // parent is already available, no need to add it!\n if (!this.invisible.has(changeTree)) {\n return;\n }\n\n // add parent's tag properties\n if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {\n\n let changes = this.changes.get(changeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(changeTree, changes);\n }\n\n if (!this.tags) {\n this.tags = new WeakMap<ChangeTree, Set<number>>();\n }\n\n let tags: Set<number>;\n if (!this.tags.has(changeTree)) {\n tags = new Set<number>();\n this.tags.set(changeTree, tags);\n } else {\n tags = this.tags.get(changeTree);\n }\n tags.add(tag);\n\n changes.set(parentIndex, OPERATION.ADD);\n }\n }\n\n remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {\n const changeTree = obj[$changes];\n if (!changeTree) {\n console.warn(\"StateView#remove(), invalid object:\", obj);\n return this;\n }\n\n this.items.delete(changeTree);\n\n const ref = changeTree.ref;\n const metadata: Metadata = ref.constructor[Symbol.metadata];\n\n let changes = this.changes.get(changeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(changeTree, changes)\n }\n\n if (tag === DEFAULT_VIEW_TAG) {\n // parent is collection (Map/Array)\n const parent = changeTree.parent;\n if (!Metadata.isValidInstance(parent)) {\n const parentChangeTree = parent[$changes];\n let changes = this.changes.get(parentChangeTree);\n if (changes === undefined) {\n changes = new Map<number, OPERATION>();\n this.changes.set(parentChangeTree, changes)\n }\n // DELETE / DELETE BY REF ID\n changes.set(changeTree.parentIndex, OPERATION.DELETE);\n\n } else {\n // delete all \"tagged\" properties.\n metadata[-2].forEach((index) =>\n changes.set(index, OPERATION.DELETE));\n }\n\n\n } else {\n // delete only tagged properties\n metadata[-3][tag].forEach((index) =>\n changes.set(index, OPERATION.DELETE));\n }\n\n // remove tag\n if (this.tags && this.tags.has(changeTree)) {\n const tags = this.tags.get(changeTree);\n if (tag === undefined) {\n // delete all tags\n this.tags.delete(changeTree);\n } else {\n // delete specific tag\n tags.delete(tag);\n\n // if tag set is empty, delete it entirely\n if (tags.size === 0) {\n this.tags.delete(changeTree);\n }\n }\n }\n\n return this;\n }\n}"]}
|
package/package.json
CHANGED
package/src/Reflection.ts
CHANGED
|
@@ -25,9 +25,7 @@ export class Reflection extends Schema {
|
|
|
25
25
|
@type([ ReflectionType ]) types: ArraySchema<ReflectionType> = new ArraySchema<ReflectionType>();
|
|
26
26
|
|
|
27
27
|
static encode(instance: Schema, context?: TypeContext, it: Iterator = { offset: 0 }) {
|
|
28
|
-
|
|
29
|
-
context = new TypeContext(instance.constructor as typeof Schema);
|
|
30
|
-
}
|
|
28
|
+
context ??= new TypeContext(instance.constructor as typeof Schema);
|
|
31
29
|
|
|
32
30
|
const reflection = new Reflection();
|
|
33
31
|
const encoder = new Encoder(reflection);
|
package/src/Schema.ts
CHANGED
|
@@ -248,7 +248,7 @@ export abstract class Schema {
|
|
|
248
248
|
return output;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
static debugChangesDeep(ref: Ref) {
|
|
251
|
+
static debugChangesDeep(ref: Ref, changeSetName: "changes" | "allChanges" | "allFilteredChanges" | "filteredChanges" = "changes") {
|
|
252
252
|
let output = "";
|
|
253
253
|
|
|
254
254
|
const rootChangeTree = ref[$changes];
|
|
@@ -257,7 +257,7 @@ export abstract class Schema {
|
|
|
257
257
|
let totalInstances = 0;
|
|
258
258
|
let totalOperations = 0;
|
|
259
259
|
|
|
260
|
-
for (const [changeTree, changes] of (rootChangeTree.root.
|
|
260
|
+
for (const [changeTree, changes] of (rootChangeTree.root[changeSetName].entries())) {
|
|
261
261
|
let includeChangeTree = false;
|
|
262
262
|
let parentChangeTrees: ChangeTree[] = [];
|
|
263
263
|
let parentChangeTree = changeTree.parent?.[$changes];
|
package/src/annotations.ts
CHANGED
|
@@ -103,14 +103,14 @@ export class TypeContext {
|
|
|
103
103
|
return this.schemas.get(klass);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
private discoverTypes(klass: typeof Schema) {
|
|
106
|
+
private discoverTypes(klass: typeof Schema, parentFieldViewTag?: number) {
|
|
107
107
|
if (!this.add(klass)) {
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
// add classes inherited from this base class
|
|
112
112
|
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
113
|
-
this.discoverTypes(child);
|
|
113
|
+
this.discoverTypes(child, parentFieldViewTag);
|
|
114
114
|
});
|
|
115
115
|
|
|
116
116
|
// skip if no fields are defined for this class.
|
|
@@ -127,7 +127,18 @@ export class TypeContext {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
for (const field in metadata) {
|
|
130
|
+
//
|
|
131
|
+
// Modify the field's metadata to include the parent field's view tag
|
|
132
|
+
//
|
|
133
|
+
if (
|
|
134
|
+
parentFieldViewTag !== undefined &&
|
|
135
|
+
metadata[field].tag === undefined
|
|
136
|
+
) {
|
|
137
|
+
metadata[field].tag = parentFieldViewTag;
|
|
138
|
+
}
|
|
139
|
+
|
|
130
140
|
const fieldType = metadata[field].type;
|
|
141
|
+
const viewTag = metadata[field].tag;
|
|
131
142
|
|
|
132
143
|
if (typeof(fieldType) === "string") {
|
|
133
144
|
continue;
|
|
@@ -138,10 +149,10 @@ export class TypeContext {
|
|
|
138
149
|
if (type === "string") {
|
|
139
150
|
continue;
|
|
140
151
|
}
|
|
141
|
-
this.discoverTypes(type as typeof Schema);
|
|
152
|
+
this.discoverTypes(type as typeof Schema, viewTag);
|
|
142
153
|
|
|
143
154
|
} else if (typeof(fieldType) === "function") {
|
|
144
|
-
this.discoverTypes(fieldType);
|
|
155
|
+
this.discoverTypes(fieldType, viewTag);
|
|
145
156
|
|
|
146
157
|
} else {
|
|
147
158
|
const type = Object.values(fieldType)[0];
|
|
@@ -151,7 +162,7 @@ export class TypeContext {
|
|
|
151
162
|
continue;
|
|
152
163
|
}
|
|
153
164
|
|
|
154
|
-
this.discoverTypes(type as typeof Schema);
|
|
165
|
+
this.discoverTypes(type as typeof Schema, viewTag);
|
|
155
166
|
}
|
|
156
167
|
}
|
|
157
168
|
}
|
|
@@ -182,7 +182,10 @@ export const decodeSchemaOperation: DecodeOperation = function (
|
|
|
182
182
|
|
|
183
183
|
// skip early if field is not defined
|
|
184
184
|
const field = metadata[index];
|
|
185
|
-
if (field === undefined) {
|
|
185
|
+
if (field === undefined) {
|
|
186
|
+
console.warn("@colyseus/schema: field not defined at", { index, ref: ref.constructor.name, metadata });
|
|
187
|
+
return DEFINITION_MISMATCH;
|
|
188
|
+
}
|
|
186
189
|
|
|
187
190
|
const { value, previousValue } = decodeValue(
|
|
188
191
|
decoder,
|
package/src/decoder/Decoder.ts
CHANGED
|
@@ -21,7 +21,8 @@ export class Decoder<T extends Schema = any> {
|
|
|
21
21
|
triggerChanges?: (allChanges: DataChange[]) => void;
|
|
22
22
|
|
|
23
23
|
constructor(root: T, context?: TypeContext) {
|
|
24
|
-
this.
|
|
24
|
+
this.setState(root);
|
|
25
|
+
|
|
25
26
|
this.context = context || new TypeContext(root.constructor as typeof Schema);
|
|
26
27
|
|
|
27
28
|
// console.log(">>>>>>>>>>>>>>>> Decoder types");
|
|
@@ -30,7 +31,7 @@ export class Decoder<T extends Schema = any> {
|
|
|
30
31
|
// });
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
protected
|
|
34
|
+
protected setState(root: T) {
|
|
34
35
|
this.state = root;
|
|
35
36
|
this.root = new ReferenceTracker();
|
|
36
37
|
this.root.addRef(0, root);
|
|
@@ -6,7 +6,7 @@ import { DataChange } from "../DecodeOperation";
|
|
|
6
6
|
import { OPERATION } from "../../encoding/spec";
|
|
7
7
|
import { DefinitionType } from "../../annotations";
|
|
8
8
|
import { Schema } from "../../Schema";
|
|
9
|
-
import type {
|
|
9
|
+
import type { CollectionSchema } from "../../types/custom/CollectionSchema";
|
|
10
10
|
|
|
11
11
|
//
|
|
12
12
|
// Discussion: https://github.com/colyseus/schema/issues/155
|
|
@@ -100,7 +100,8 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
100
100
|
const $root = decoder.root;
|
|
101
101
|
const callbacks = $root.callbacks;
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
const onAddCalls: WeakMap<Function, boolean> = new WeakMap();
|
|
104
|
+
let currentOnAddCallback: Function | undefined;
|
|
104
105
|
|
|
105
106
|
decoder.triggerChanges = function (allChanges: DataChange[]) {
|
|
106
107
|
const uniqueRefIds = new Set<number>();
|
|
@@ -173,7 +174,6 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
// Handle DELETE_AND_ADD operations
|
|
176
|
-
// FIXME: should we set "isTriggeringOnAdd" here?
|
|
177
177
|
if ((change.op & OPERATION.ADD) === OPERATION.ADD) {
|
|
178
178
|
const addCallbacks = $callbacks[OPERATION.ADD];
|
|
179
179
|
for (let i = addCallbacks?.length - 1; i >= 0; i--) {
|
|
@@ -183,13 +183,10 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
183
183
|
|
|
184
184
|
} else if ((change.op & OPERATION.ADD) === OPERATION.ADD && change.previousValue === undefined) {
|
|
185
185
|
// triger onAdd
|
|
186
|
-
|
|
187
|
-
isTriggeringOnAdd = true;
|
|
188
186
|
const addCallbacks = $callbacks[OPERATION.ADD];
|
|
189
187
|
for (let i = addCallbacks?.length - 1; i >= 0; i--) {
|
|
190
188
|
addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
|
|
191
189
|
}
|
|
192
|
-
isTriggeringOnAdd = false;
|
|
193
190
|
}
|
|
194
191
|
|
|
195
192
|
// trigger onChange
|
|
@@ -205,7 +202,10 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
205
202
|
}
|
|
206
203
|
};
|
|
207
204
|
|
|
208
|
-
function getProxy(
|
|
205
|
+
function getProxy(
|
|
206
|
+
metadataOrType: Metadata | DefinitionType,
|
|
207
|
+
context: CallContext
|
|
208
|
+
) {
|
|
209
209
|
let metadata: Metadata = context.instance?.constructor[Symbol.metadata] || metadataOrType;
|
|
210
210
|
let isCollection = (
|
|
211
211
|
(context.instance && typeof (context.instance['forEach']) === "function") ||
|
|
@@ -223,7 +223,7 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
223
223
|
if (
|
|
224
224
|
immediate &&
|
|
225
225
|
context.instance[prop] !== undefined &&
|
|
226
|
-
!
|
|
226
|
+
!onAddCalls.has(callback) // Workaround for https://github.com/colyseus/schema/issues/147
|
|
227
227
|
) {
|
|
228
228
|
callback(context.instance[prop], undefined);
|
|
229
229
|
}
|
|
@@ -249,6 +249,7 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
249
249
|
return () => detachCallback();
|
|
250
250
|
}
|
|
251
251
|
},
|
|
252
|
+
|
|
252
253
|
onChange: function onChange(callback: () => void) {
|
|
253
254
|
return $root.addCallback(
|
|
254
255
|
$root.refIds.get(context.instance),
|
|
@@ -256,10 +257,12 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
256
257
|
callback
|
|
257
258
|
);
|
|
258
259
|
},
|
|
260
|
+
|
|
261
|
+
//
|
|
262
|
+
// TODO: refactor `bindTo()` implementation.
|
|
263
|
+
// There is room for improvement.
|
|
264
|
+
//
|
|
259
265
|
bindTo: function bindTo(targetObject: any, properties?: string[]) {
|
|
260
|
-
//
|
|
261
|
-
// TODO: refactor this implementation. There is room for improvement here.
|
|
262
|
-
//
|
|
263
266
|
if (!properties) {
|
|
264
267
|
properties = Object.keys(metadata);
|
|
265
268
|
}
|
|
@@ -295,7 +298,8 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
295
298
|
}
|
|
296
299
|
);
|
|
297
300
|
return getProxy(metadata[prop].type, {
|
|
298
|
-
instance
|
|
301
|
+
// make sure refId is available, otherwise need to wait for the instance to be available.
|
|
302
|
+
instance: ($root.refIds.get(instance) && instance),
|
|
299
303
|
parentInstance: context.instance,
|
|
300
304
|
onInstanceAvailable,
|
|
301
305
|
});
|
|
@@ -318,9 +322,15 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
318
322
|
const onAdd = function (ref: Ref, callback: (value: any, key: any) => void, immediate: boolean) {
|
|
319
323
|
// Trigger callback on existing items
|
|
320
324
|
if (immediate) {
|
|
321
|
-
(ref as
|
|
325
|
+
(ref as CollectionSchema).forEach((v, k) => callback(v, k));
|
|
322
326
|
}
|
|
323
|
-
|
|
327
|
+
|
|
328
|
+
return $root.addCallback($root.refIds.get(ref), OPERATION.ADD, (value, key) => {
|
|
329
|
+
onAddCalls.set(callback, true);
|
|
330
|
+
currentOnAddCallback = callback;
|
|
331
|
+
callback(value, key);
|
|
332
|
+
onAddCalls.delete(callback)
|
|
333
|
+
});
|
|
324
334
|
};
|
|
325
335
|
|
|
326
336
|
const onRemove = function (ref: Ref, callback: (value: any, key: any) => void) {
|
|
@@ -333,19 +343,19 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
333
343
|
// https://github.com/colyseus/schema/issues/147
|
|
334
344
|
// If parent instance has "onAdd" registered, avoid triggering immediate callback.
|
|
335
345
|
//
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
346
|
+
|
|
347
|
+
if (context.instance) {
|
|
348
|
+
return onAdd(context.instance, callback, immediate && !onAddCalls.has(currentOnAddCallback));
|
|
349
|
+
|
|
350
|
+
} else if (context.onInstanceAvailable) {
|
|
339
351
|
// collection instance not received yet
|
|
340
352
|
let detachCallback = () => {};
|
|
341
353
|
|
|
342
354
|
context.onInstanceAvailable((ref: Ref, existing: boolean) => {
|
|
343
|
-
detachCallback = onAdd(ref, callback, immediate && existing && !
|
|
355
|
+
detachCallback = onAdd(ref, callback, immediate && existing && !onAddCalls.has(currentOnAddCallback));
|
|
344
356
|
});
|
|
345
357
|
|
|
346
358
|
return () => detachCallback();
|
|
347
|
-
} else if (context.instance) {
|
|
348
|
-
return onAdd(context.instance, callback, immediate && !isTriggeringOnAdd);
|
|
349
359
|
}
|
|
350
360
|
},
|
|
351
361
|
onRemove: function(callback: (value, key) => void) {
|
|
@@ -204,7 +204,7 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
204
204
|
// MapSchema / ArraySchema, etc.
|
|
205
205
|
(this.ref as MapSchema).forEach((value, key) => {
|
|
206
206
|
if (Metadata.isValidInstance(value)) {
|
|
207
|
-
callback(value[$changes], this.ref[$changes].indexes[key]);
|
|
207
|
+
callback(value[$changes], this.ref[$changes].indexes[key] ?? key);
|
|
208
208
|
}
|
|
209
209
|
});
|
|
210
210
|
}
|
|
@@ -238,9 +238,11 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
238
238
|
//
|
|
239
239
|
|
|
240
240
|
if (isFiltered) {
|
|
241
|
-
this.allFilteredChanges.set(index, OPERATION.ADD);
|
|
242
241
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
243
242
|
|
|
243
|
+
this.allFilteredChanges.set(index, OPERATION.ADD);
|
|
244
|
+
this.root?.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
245
|
+
|
|
244
246
|
} else {
|
|
245
247
|
this.allChanges.set(index, OPERATION.ADD);
|
|
246
248
|
this.root?.changes.set(this, this.changes);
|
package/src/encoder/Encoder.ts
CHANGED
|
@@ -20,14 +20,16 @@ export class Encoder<T extends Schema = any> {
|
|
|
20
20
|
|
|
21
21
|
root: Root;
|
|
22
22
|
|
|
23
|
-
constructor(
|
|
23
|
+
constructor(state: T) {
|
|
24
|
+
this.root = new Root();
|
|
25
|
+
|
|
24
26
|
//
|
|
25
27
|
// TODO: cache and restore "Context" based on root schema
|
|
26
28
|
// (to avoid creating a new context for every new room)
|
|
27
29
|
//
|
|
28
|
-
this.context = new TypeContext(
|
|
30
|
+
this.context = new TypeContext(state.constructor as typeof Schema);
|
|
29
31
|
|
|
30
|
-
this.
|
|
32
|
+
this.setState(state);
|
|
31
33
|
|
|
32
34
|
// console.log(">>>>>>>>>>>>>>>> Encoder types");
|
|
33
35
|
// this.context.schemas.forEach((id, schema) => {
|
|
@@ -35,10 +37,9 @@ export class Encoder<T extends Schema = any> {
|
|
|
35
37
|
// });
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
protected
|
|
39
|
-
this.root = new Root();
|
|
40
|
+
protected setState(state: T) {
|
|
40
41
|
this.state = state;
|
|
41
|
-
state[$changes].setRoot(this.root);
|
|
42
|
+
this.state[$changes].setRoot(this.root);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
encode(
|
|
@@ -47,9 +48,8 @@ export class Encoder<T extends Schema = any> {
|
|
|
47
48
|
buffer = this.sharedBuffer,
|
|
48
49
|
changeTrees = this.root.changes,
|
|
49
50
|
isEncodeAll = this.root.allChanges === changeTrees,
|
|
51
|
+
initialOffset = it.offset // cache current offset in case we need to resize the buffer
|
|
50
52
|
): Buffer {
|
|
51
|
-
const initialOffset = it.offset; // cache current offset in case we need to resize the buffer
|
|
52
|
-
|
|
53
53
|
const hasView = (view !== undefined);
|
|
54
54
|
const rootChangeTree = this.state[$changes];
|
|
55
55
|
|
|
@@ -96,8 +96,6 @@ export class Encoder<T extends Schema = any> {
|
|
|
96
96
|
// TODO: avoid checking if no view tags were defined
|
|
97
97
|
//
|
|
98
98
|
if (filter && !filter(ref, fieldIndex, view)) {
|
|
99
|
-
// console.log("SKIP FIELD:", { ref: changeTree.ref.constructor.name, fieldIndex, })
|
|
100
|
-
|
|
101
99
|
// console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
|
|
102
100
|
// view?.invisible.add(changeTree);
|
|
103
101
|
continue;
|
|
@@ -194,9 +192,6 @@ export class Encoder<T extends Schema = any> {
|
|
|
194
192
|
encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {
|
|
195
193
|
const viewOffset = it.offset;
|
|
196
194
|
|
|
197
|
-
// try to encode "filtered" changes
|
|
198
|
-
this.encode(it, view, bytes, this.root.filteredChanges);
|
|
199
|
-
|
|
200
195
|
// encode visibility changes (add/remove for this view)
|
|
201
196
|
const viewChangesIterator = view.changes.entries();
|
|
202
197
|
for (const [changeTree, changes] of viewChangesIterator) {
|
|
@@ -230,6 +225,9 @@ export class Encoder<T extends Schema = any> {
|
|
|
230
225
|
// clear "view" changes after encoding
|
|
231
226
|
view.changes.clear();
|
|
232
227
|
|
|
228
|
+
// try to encode "filtered" changes
|
|
229
|
+
this.encode(it, view, bytes, this.root.filteredChanges, false, viewOffset);
|
|
230
|
+
|
|
233
231
|
return Buffer.concat([
|
|
234
232
|
bytes.subarray(0, sharedOffset),
|
|
235
233
|
bytes.subarray(viewOffset, it.offset)
|
package/src/encoder/StateView.ts
CHANGED
|
@@ -28,7 +28,7 @@ export class StateView {
|
|
|
28
28
|
changes = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
29
29
|
|
|
30
30
|
// TODO: allow to set multiple tags at once
|
|
31
|
-
add(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {
|
|
31
|
+
add(obj: Ref, tag: number = DEFAULT_VIEW_TAG, checkIncludeParent: boolean = true) {
|
|
32
32
|
if (!obj[$changes]) {
|
|
33
33
|
console.warn("StateView#add(), invalid object:", obj);
|
|
34
34
|
return this;
|
|
@@ -36,22 +36,15 @@ export class StateView {
|
|
|
36
36
|
|
|
37
37
|
// FIXME: ArraySchema/MapSchema does not have metadata
|
|
38
38
|
const metadata: Metadata = obj.constructor[Symbol.metadata];
|
|
39
|
-
|
|
40
|
-
let changeTree: ChangeTree = obj[$changes];
|
|
39
|
+
const changeTree: ChangeTree = obj[$changes];
|
|
41
40
|
this.items.add(changeTree);
|
|
42
41
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.add(change.ref, tag);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// add parent ChangeTree's, if they are invisible to this view
|
|
53
|
-
// TODO: REFACTOR addParent()
|
|
54
|
-
this.addParent(changeTree, tag);
|
|
42
|
+
// add parent ChangeTree's
|
|
43
|
+
// - if it was invisible to this view
|
|
44
|
+
// - if it were previously filtered out
|
|
45
|
+
if (checkIncludeParent && changeTree.parent) {
|
|
46
|
+
this.addParent(changeTree.parent[$changes], changeTree.parentIndex, tag);
|
|
47
|
+
}
|
|
55
48
|
|
|
56
49
|
//
|
|
57
50
|
// TODO: when adding an item of a MapSchema, the changes may not
|
|
@@ -85,89 +78,77 @@ export class StateView {
|
|
|
85
78
|
});
|
|
86
79
|
|
|
87
80
|
} else {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// // add default tag properties
|
|
92
|
-
// metadata?.[-3]?.[DEFAULT_VIEW_TAG]?.forEach((index) => {
|
|
93
|
-
// if (changeTree.getChange(index) !== OPERATION.DELETE) {
|
|
94
|
-
// changes.set(index, OPERATION.ADD);
|
|
95
|
-
// }
|
|
96
|
-
// });
|
|
97
|
-
|
|
98
|
-
const allChangesSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
81
|
+
const isInvisible = this.invisible.has(changeTree);
|
|
82
|
+
const changeSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
99
83
|
? changeTree.allFilteredChanges
|
|
100
84
|
: changeTree.allChanges;
|
|
101
|
-
const it = allChangesSet.keys();
|
|
102
|
-
const isInvisible = this.invisible.has(changeTree);
|
|
103
85
|
|
|
104
|
-
|
|
86
|
+
changeSet.forEach((op, index) => {
|
|
87
|
+
const tagAtIndex = metadata?.[metadata?.[index]].tag;
|
|
105
88
|
if (
|
|
106
|
-
(
|
|
107
|
-
|
|
89
|
+
(
|
|
90
|
+
isInvisible || // if "invisible", include all
|
|
91
|
+
tagAtIndex === undefined || // "all change" with no tag
|
|
92
|
+
tagAtIndex === tag // tagged property
|
|
93
|
+
) &&
|
|
94
|
+
op !== OPERATION.DELETE
|
|
108
95
|
) {
|
|
109
|
-
changes.set(index,
|
|
96
|
+
changes.set(index, op);
|
|
110
97
|
}
|
|
111
|
-
}
|
|
98
|
+
});
|
|
112
99
|
}
|
|
113
100
|
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this.
|
|
121
|
-
}
|
|
101
|
+
// Add children of this ChangeTree to this view
|
|
102
|
+
changeTree.forEachChild((change, index) => {
|
|
103
|
+
// Do not ADD children that don't have the same tag
|
|
104
|
+
if (metadata && metadata[metadata[index]].tag !== tag) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.add(change.ref, tag, false);
|
|
108
|
+
});
|
|
122
109
|
|
|
123
110
|
return this;
|
|
124
111
|
}
|
|
125
112
|
|
|
126
|
-
protected addParent(changeTree: ChangeTree, tag: number) {
|
|
127
|
-
|
|
128
|
-
|
|
113
|
+
protected addParent(changeTree: ChangeTree, parentIndex: number, tag: number) {
|
|
114
|
+
// view must have all "changeTree" parent tree
|
|
115
|
+
this.items.add(changeTree);
|
|
129
116
|
|
|
130
|
-
|
|
131
|
-
const
|
|
117
|
+
// add parent's parent
|
|
118
|
+
const parentChangeTree = changeTree.parent?.[$changes];
|
|
119
|
+
if (parentChangeTree && (parentChangeTree.isFiltered || parentChangeTree.isPartiallyFiltered)) {
|
|
120
|
+
this.addParent(parentChangeTree, changeTree.parentIndex, tag);
|
|
121
|
+
}
|
|
132
122
|
|
|
133
|
-
|
|
134
|
-
|
|
123
|
+
// parent is already available, no need to add it!
|
|
124
|
+
if (!this.invisible.has(changeTree)) {
|
|
135
125
|
return;
|
|
136
126
|
}
|
|
137
127
|
|
|
138
|
-
this.addParent(parentChangeTree, tag);
|
|
139
|
-
|
|
140
128
|
// add parent's tag properties
|
|
141
|
-
if (
|
|
129
|
+
if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
|
|
142
130
|
|
|
143
|
-
let
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
this.changes.set(
|
|
131
|
+
let changes = this.changes.get(changeTree);
|
|
132
|
+
if (changes === undefined) {
|
|
133
|
+
changes = new Map<number, OPERATION>();
|
|
134
|
+
this.changes.set(changeTree, changes);
|
|
147
135
|
}
|
|
148
136
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// parentChange: (
|
|
153
|
-
// parentChangeTree.getChange(parentIndex) &&
|
|
154
|
-
// OPERATION[parentChangeTree.getChange(parentIndex)]
|
|
155
|
-
// ),
|
|
156
|
-
// })
|
|
137
|
+
if (!this.tags) {
|
|
138
|
+
this.tags = new WeakMap<ChangeTree, Set<number>>();
|
|
139
|
+
}
|
|
157
140
|
|
|
158
|
-
if (!this.tags) { this.tags = new WeakMap<ChangeTree, Set<number>>(); }
|
|
159
141
|
let tags: Set<number>;
|
|
160
|
-
if (!this.tags.has(
|
|
142
|
+
if (!this.tags.has(changeTree)) {
|
|
161
143
|
tags = new Set<number>();
|
|
162
|
-
this.tags.set(
|
|
144
|
+
this.tags.set(changeTree, tags);
|
|
163
145
|
} else {
|
|
164
|
-
tags = this.tags.get(
|
|
146
|
+
tags = this.tags.get(changeTree);
|
|
165
147
|
}
|
|
166
148
|
tags.add(tag);
|
|
167
149
|
|
|
168
|
-
|
|
150
|
+
changes.set(parentIndex, OPERATION.ADD);
|
|
169
151
|
}
|
|
170
|
-
|
|
171
152
|
}
|
|
172
153
|
|
|
173
154
|
remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {
|