@colyseus/schema 3.0.0-alpha.24 → 3.0.0-alpha.26

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.
@@ -20,14 +20,16 @@ export class Encoder<T extends Schema = any> {
20
20
 
21
21
  root: Root;
22
22
 
23
- constructor(root: T) {
24
- this.setRoot(root);
23
+ constructor(state: T) {
24
+ this.root = new Root();
25
25
 
26
26
  //
27
27
  // TODO: cache and restore "Context" based on root schema
28
28
  // (to avoid creating a new context for every new room)
29
29
  //
30
- this.context = new TypeContext(root.constructor as typeof Schema);
30
+ this.context = new TypeContext(state.constructor as typeof Schema);
31
+
32
+ this.setState(state);
31
33
 
32
34
  // console.log(">>>>>>>>>>>>>>>> Encoder types");
33
35
  // this.context.schemas.forEach((id, schema) => {
@@ -35,16 +37,9 @@ export class Encoder<T extends Schema = any> {
35
37
  // });
36
38
  }
37
39
 
38
- protected setRoot(state: T) {
39
- this.root = new Root();
40
+ protected setState(state: T) {
40
41
  this.state = state;
41
-
42
- // Workaround to allow using an empty Schema.
43
- if (state.constructor[Symbol.metadata] === undefined) {
44
- Metadata.init(state);
45
- }
46
-
47
- state[$changes].setRoot(this.root);
42
+ this.state[$changes].setRoot(this.root);
48
43
  }
49
44
 
50
45
  encode(
@@ -53,9 +48,8 @@ export class Encoder<T extends Schema = any> {
53
48
  buffer = this.sharedBuffer,
54
49
  changeTrees = this.root.changes,
55
50
  isEncodeAll = this.root.allChanges === changeTrees,
51
+ initialOffset = it.offset // cache current offset in case we need to resize the buffer
56
52
  ): Buffer {
57
- const initialOffset = it.offset; // cache current offset in case we need to resize the buffer
58
-
59
53
  const hasView = (view !== undefined);
60
54
  const rootChangeTree = this.state[$changes];
61
55
 
@@ -102,8 +96,6 @@ export class Encoder<T extends Schema = any> {
102
96
  // TODO: avoid checking if no view tags were defined
103
97
  //
104
98
  if (filter && !filter(ref, fieldIndex, view)) {
105
- // console.log("SKIP FIELD:", { ref: changeTree.ref.constructor.name, fieldIndex, })
106
-
107
99
  // console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
108
100
  // view?.invisible.add(changeTree);
109
101
  continue;
@@ -200,9 +192,6 @@ export class Encoder<T extends Schema = any> {
200
192
  encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {
201
193
  const viewOffset = it.offset;
202
194
 
203
- // try to encode "filtered" changes
204
- this.encode(it, view, bytes, this.root.filteredChanges);
205
-
206
195
  // encode visibility changes (add/remove for this view)
207
196
  const viewChangesIterator = view.changes.entries();
208
197
  for (const [changeTree, changes] of viewChangesIterator) {
@@ -236,6 +225,9 @@ export class Encoder<T extends Schema = any> {
236
225
  // clear "view" changes after encoding
237
226
  view.changes.clear();
238
227
 
228
+ // try to encode "filtered" changes
229
+ this.encode(it, view, bytes, this.root.filteredChanges, false, viewOffset);
230
+
239
231
  return Buffer.concat([
240
232
  bytes.subarray(0, sharedOffset),
241
233
  bytes.subarray(viewOffset, it.offset)
@@ -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
- // Add children of this ChangeTree to this view
44
- changeTree.forEachChild((change, index) => {
45
- // Do not ADD children that don't have the same tag
46
- if (metadata && metadata[metadata[index]].tag !== tag) {
47
- return;
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
- // console.log("DEFAULT TAG", changeTree.allChanges);
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
- for (const index of it) {
86
+ changeSet.forEach((op, index) => {
87
+ const tagAtIndex = metadata?.[metadata?.[index]].tag;
105
88
  if (
106
- (isInvisible || metadata?.[metadata?.[index]].tag === tag) &&
107
- changeTree.getChange(index) !== OPERATION.DELETE
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, OPERATION.ADD);
96
+ changes.set(index, op);
110
97
  }
111
- }
98
+ });
112
99
  }
113
100
 
114
- // TODO: avoid unnecessary iteration here
115
- while (
116
- changeTree.parent &&
117
- (changeTree = changeTree.parent[$changes]) &&
118
- (changeTree.isFiltered || changeTree.isPartiallyFiltered)
119
- ) {
120
- this.items.add(changeTree);
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
- const parentRef = changeTree.parent;
128
- if (!parentRef) { return; }
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
- const parentChangeTree = parentRef[$changes];
131
- const parentIndex = changeTree.parentIndex;
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
- if (!this.invisible.has(parentChangeTree)) {
134
- // parent is already available, no need to add it!
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 (parentChangeTree.getChange(parentIndex) !== OPERATION.DELETE) {
129
+ if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
142
130
 
143
- let parentChanges = this.changes.get(parentChangeTree);
144
- if (parentChanges === undefined) {
145
- parentChanges = new Map<number, OPERATION>();
146
- this.changes.set(parentChangeTree, parentChanges);
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
- // console.log("add parent change", {
150
- // parentIndex,
151
- // parentChanges,
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(parentChangeTree)) {
142
+ if (!this.tags.has(changeTree)) {
161
143
  tags = new Set<number>();
162
- this.tags.set(parentChangeTree, tags);
144
+ this.tags.set(changeTree, tags);
163
145
  } else {
164
- tags = this.tags.get(parentChangeTree);
146
+ tags = this.tags.get(changeTree);
165
147
  }
166
148
  tags.add(tag);
167
149
 
168
- parentChanges.set(parentIndex, OPERATION.ADD);
150
+ changes.set(parentIndex, OPERATION.ADD);
169
151
  }
170
-
171
152
  }
172
153
 
173
154
  remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {