@colyseus/schema 5.0.10 → 5.0.12

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.
Files changed (58) hide show
  1. package/build/Metadata.d.ts +20 -12
  2. package/build/annotations.d.ts +23 -10
  3. package/build/codegen/cli.cjs +615 -204
  4. package/build/codegen/cli.cjs.map +1 -1
  5. package/build/codegen/languages/dart.d.ts +20 -0
  6. package/build/codegen/types.d.ts +20 -0
  7. package/build/decoder/Resync.d.ts +3 -3
  8. package/build/encoder/ChangeTree.d.ts +22 -10
  9. package/build/encoder/EncodeDescriptor.d.ts +11 -12
  10. package/build/encoder/StateView.d.ts +26 -8
  11. package/build/encoder/changeTree/inheritedFlags.d.ts +1 -1
  12. package/build/encoder/streaming.d.ts +7 -0
  13. package/build/index.cjs +393 -287
  14. package/build/index.cjs.map +1 -1
  15. package/build/index.d.ts +1 -1
  16. package/build/index.js +393 -287
  17. package/build/index.mjs +392 -286
  18. package/build/index.mjs.map +1 -1
  19. package/build/types/builder.d.ts +31 -22
  20. package/build/types/custom/StreamSchema.d.ts +1 -1
  21. package/build/types/symbols.d.ts +4 -10
  22. package/package.json +1 -1
  23. package/src/Metadata.ts +58 -31
  24. package/src/annotations.ts +56 -32
  25. package/src/codegen/api.ts +2 -1
  26. package/src/codegen/languages/c.ts +21 -3
  27. package/src/codegen/languages/csharp.ts +7 -1
  28. package/src/codegen/languages/dart.ts +274 -0
  29. package/src/codegen/languages/haxe.ts +7 -1
  30. package/src/codegen/languages/lua.ts +16 -4
  31. package/src/codegen/languages/ts.ts +5 -0
  32. package/src/codegen/parser.ts +97 -3
  33. package/src/codegen/types.ts +24 -0
  34. package/src/decoder/Resync.ts +8 -8
  35. package/src/encoder/ChangeRecorder.ts +1 -1
  36. package/src/encoder/ChangeTree.ts +41 -28
  37. package/src/encoder/EncodeDescriptor.ts +17 -38
  38. package/src/encoder/EncodeOperation.ts +3 -1
  39. package/src/encoder/Encoder.ts +100 -37
  40. package/src/encoder/Root.ts +18 -20
  41. package/src/encoder/StateView.ts +118 -47
  42. package/src/encoder/changeTree/inheritedFlags.ts +10 -10
  43. package/src/encoder/changeTree/liveIteration.ts +9 -9
  44. package/src/encoder/streaming.ts +8 -0
  45. package/src/encoding/spec.ts +1 -1
  46. package/src/index.ts +2 -2
  47. package/src/types/builder.ts +35 -31
  48. package/src/types/custom/StreamSchema.ts +1 -1
  49. package/src/types/symbols.ts +4 -11
  50. package/src/bench_bloat.ts +0 -173
  51. package/src/bench_churn.ts +0 -121
  52. package/src/bench_decode.ts +0 -221
  53. package/src/bench_decode_mem.ts +0 -165
  54. package/src/bench_encode.ts +0 -108
  55. package/src/bench_init.ts +0 -150
  56. package/src/bench_static.ts +0 -109
  57. package/src/bench_stream.ts +0 -295
  58. package/src/bench_view_cmp.ts +0 -142
@@ -0,0 +1,20 @@
1
+ import { File, Context } from "../types.js";
2
+ import { GenerateOptions } from "../api.js";
3
+ export declare const name = "Dart/Flutter";
4
+ /**
5
+ * Dart Code Generator
6
+ *
7
+ * Emits typed façades over the `colyseus` Flutter package's runtime: one
8
+ * `SchemaRef` subclass per schema, with typed getters over the shared native
9
+ * handle. Collection getters return `MapSchema<T>` / `ArraySchema<T>`, which
10
+ * also carry the field they came from — that is what
11
+ * `callbacks.onAdd(state.players, ...)` registers against.
12
+ */
13
+ /**
14
+ * Generate individual files for each class/interface/enum
15
+ */
16
+ export declare function generate(context: Context, options: GenerateOptions): File[];
17
+ /**
18
+ * Generate a single bundled file containing all classes, interfaces, and enums
19
+ */
20
+ export declare function renderBundle(context: Context, options: GenerateOptions): File;
@@ -37,11 +37,31 @@ export declare class Enum implements IStructure {
37
37
  properties: Property[];
38
38
  addProperty(property: Property): void;
39
39
  }
40
+ /**
41
+ * Statically-extracted `t.quantized()` options. `wrap` is already normalized
42
+ * from the source's `mode` string; emitters derive `range`/`span` via
43
+ * {@link resolveQuantized} so every language ships identical precomputed values.
44
+ */
45
+ export interface QuantizedProperty {
46
+ min: number;
47
+ max: number;
48
+ bits: 8 | 16 | 32;
49
+ wrap: boolean;
50
+ }
51
+ /**
52
+ * Mirror of the runtime's `resolveQuantize()` scale math (wrap spreads 2^bits
53
+ * steps across [min,max); clamp maps the endpoints onto 0 and 2^bits-1).
54
+ */
55
+ export declare function resolveQuantized(q: QuantizedProperty): {
56
+ range: number;
57
+ span: number;
58
+ };
40
59
  export declare class Property {
41
60
  index: number;
42
61
  name: string;
43
62
  type: string;
44
63
  childType: string;
64
+ quantized?: QuantizedProperty;
45
65
  deprecated?: boolean;
46
66
  }
47
67
  export interface File {
@@ -42,8 +42,8 @@ export declare function resyncTouchEntry(decoder: Decoder, ref: any, operation:
42
42
  /**
43
43
  * Mark a collection as present in the payload — even with zero entries.
44
44
  * The sweep only prunes collections reported here: absence means "not part
45
- * of full-sync" (@transient, view-invisible), where pruning would destroy
46
- * live data. Reflected clients have no @transient metadata, so payload
45
+ * of full-sync" (@patchOnly, view-invisible), where pruning would destroy
46
+ * live data. Reflected clients have no @patchOnly metadata, so payload
47
47
  * presence is the only reliable signal.
48
48
  */
49
49
  export declare function resyncMarkPresent(decoder: Decoder, refId: number): void;
@@ -52,7 +52,7 @@ export declare function resyncMarkPresent(decoder: Decoder, refId: number): void
52
52
  * entry the snapshot did not visit.
53
53
  *
54
54
  * Walks the tree from the root — NOT `root.refs` — for three reasons:
55
- * `@transient` fields are never part of a snapshot and must be left alone;
55
+ * `@patchOnly` fields are never part of a snapshot and must be left alone;
56
56
  * entries of subtrees removed by the sweep itself are left to the GC's
57
57
  * transitive walk (sweeping them directly would double-decrement shared
58
58
  * children); and collections the snapshot never mentions (emptied
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * - parentChain.ts addParent / removeParent / find / has / getAll
10
10
  * - liveIteration.ts forEachLive
11
- * - inheritedFlags.ts filter / unreliable / transient / static inheritance
11
+ * - inheritedFlags.ts filter / unreliable / patchOnly / static inheritance
12
12
  * - treeAttachment.ts setRoot / setParent / forEachChild(+WithCtx)
13
13
  *
14
14
  * Public surface on ChangeTree is unchanged — methods are thin pass-throughs
@@ -51,6 +51,7 @@ export interface ChangeTreeNode {
51
51
  export interface ChangeTreeList {
52
52
  next?: ChangeTreeNode;
53
53
  tail?: ChangeTreeNode;
54
+ nextPosition: number;
54
55
  }
55
56
  export declare function createChangeTreeList(): ChangeTreeList;
56
57
  export interface ParentChain {
@@ -59,7 +60,7 @@ export interface ParentChain {
59
60
  next?: ParentChain;
60
61
  }
61
62
  export declare const IS_FILTERED = 1, IS_VISIBILITY_SHARED = 2, IS_NEW = 4;
62
- export declare const IS_UNRELIABLE = 8, IS_TRANSIENT = 16, IS_STATIC = 32;
63
+ export declare const IS_UNRELIABLE = 8, IS_PATCH_ONLY = 16, IS_FULL_STATE_ONLY = 32;
63
64
  export declare const IS_STREAM_COLLECTION = 64;
64
65
  export declare const NEEDS_RESTAGE = 128;
65
66
  /**
@@ -95,8 +96,8 @@ export declare class ChangeTree<T extends Ref = any> implements ChangeRecorder {
95
96
  refTarget: T;
96
97
  metadata: Metadata;
97
98
  /**
98
- * Per-class cache of encoder fn / filter fn / isSchema / filterBitmask /
99
- * metadata, looked up once at construction. The encode loop reads
99
+ * Per-class cache of encoder fn / filter fn / isSchema / metadata /
100
+ * per-field arrays, looked up once at construction. The encode loop reads
100
101
  * `tree.encDescriptor` and never touches `ref.constructor` again. See
101
102
  * EncodeDescriptor.ts.
102
103
  */
@@ -129,7 +130,6 @@ export declare class ChangeTree<T extends Ref = any> implements ChangeRecorder {
129
130
  changesNode?: ChangeTreeNode;
130
131
  unreliableChangesNode?: ChangeTreeNode;
131
132
  visibleViews?: number[];
132
- invisibleViews?: number[];
133
133
  tagViews?: Map<number, number[]>;
134
134
  /**
135
135
  * Per-view subscription bitmap — same layout as `visibleViews`. Set by
@@ -149,10 +149,10 @@ export declare class ChangeTree<T extends Ref = any> implements ChangeRecorder {
149
149
  set isNew(v: boolean);
150
150
  get isUnreliable(): boolean;
151
151
  set isUnreliable(v: boolean);
152
- get isTransient(): boolean;
153
- set isTransient(v: boolean);
154
- get isStatic(): boolean;
155
- set isStatic(v: boolean);
152
+ get isPatchOnly(): boolean;
153
+ set isPatchOnly(v: boolean);
154
+ get isFullStateOnly(): boolean;
155
+ set isFullStateOnly(v: boolean);
156
156
  get isStreamCollection(): boolean;
157
157
  set isStreamCollection(v: boolean);
158
158
  get needsRestage(): boolean;
@@ -160,7 +160,7 @@ export declare class ChangeTree<T extends Ref = any> implements ChangeRecorder {
160
160
  get hasFilteredFields(): boolean;
161
161
  ensureUnreliableRecorder(): ChangeRecorder;
162
162
  isFieldUnreliable(index: number): boolean;
163
- isFieldStatic(index: number): boolean;
163
+ isFieldFullStateOnly(index: number): boolean;
164
164
  isFieldStream(index: number): boolean;
165
165
  constructor(ref: T);
166
166
  private _opAt;
@@ -219,6 +219,18 @@ export declare class ChangeTree<T extends Ref = any> implements ChangeRecorder {
219
219
  * fields (see annotations.ts), so the per-field unreliable flag here
220
220
  * always means "primitive value updates" — the structural-ADD-routes-
221
221
  * reliable footgun for ref-type fields can't reach this code path.
222
+ *
223
+ * `!isNew` holds an `@unreliable` field on the RELIABLE channel until this
224
+ * tree's own ADD has shipped there. A decoder can only apply a field write
225
+ * to a ref it already knows, so a value emitted before the ADD is dropped —
226
+ * permanently, if the field is never written again. `isNew` clears in
227
+ * `endEncode()`, i.e. after a reliable pass, and recording reliably is
228
+ * itself what enqueues the tree for that pass; the state is self-clearing
229
+ * and no tree can be stranded on the wrong channel. Mirrors `encodeAll`,
230
+ * which has always seeded these fields for late joiners.
231
+ *
232
+ * Ordering matters: `isFieldUnreliable` short-circuits on the class-level
233
+ * `hasAnyUnreliable`, so schemas without the modifier never read `flags`.
222
234
  */
223
235
  private _routeAndRecord;
224
236
  change(index: number, operation?: OPERATION): void;
@@ -7,34 +7,33 @@ export interface EncodeDescriptor {
7
7
  isSchema: boolean;
8
8
  /**
9
9
  * Bit i set iff field i has a @view tag. 0 for collection trees.
10
- * Lets `encodeChangeCb` do a single bitwise op instead of a
11
- * per-field metadata[i]?.tag chase.
10
+ * Lets `encodeChangeCb` do a single bitwise op instead of a per-field
11
+ * metadata[i]?.tag chase. Fields 0–31 only, like the bitmasks below —
12
+ * `encodeChangeCb` reads `tags` past that.
12
13
  */
13
14
  filterBitmask: number;
14
15
  /**
15
16
  * Class-level "any field has the flag" booleans + per-field bitmasks.
16
- * Hot path: per-mutation `_routeAndRecord` calls `isFieldStatic` and
17
+ * Hot path: per-mutation `_routeAndRecord` calls `isFieldFullStateOnly` and
17
18
  * `isFieldUnreliable`. The common case is "no static/unreliable fields
18
19
  * anywhere on this class" (booleans short-circuit before the symbol-keyed
19
20
  * metadata lookup); the secondary common case is "this class has some
20
21
  * such fields and we need to know if THIS field is one" — the bitmask
21
22
  * answers in one bitwise op instead of an `Array.includes` linear scan.
22
23
  *
23
- * Bitmasks cover fields 0–31 only (matches the `filterBitmask` limitation).
24
- * Fields ≥32 fall back to `Metadata.hasXAtIndex` — same handling as the
25
- * filter-bitmask path.
24
+ * Bitmasks cover fields 0–31 only shift counts wrap at 32. Fields ≥32
25
+ * fall back to `Metadata.hasXAtIndex`.
26
26
  */
27
- hasAnyStatic: boolean;
27
+ hasAnyFullStateOnly: boolean;
28
28
  hasAnyUnreliable: boolean;
29
29
  hasAnyStream: boolean;
30
30
  /**
31
- * Class-level "any field carries a `@view` tag" covers fields both
32
- * within and beyond index 31 (unlike `filterBitmask`, which only
33
- * captures the low 32). Read by `ChangeTree.hasFilteredFields` to
34
- * decide whether a parent tree must be included in a view's bootstrap.
31
+ * Class-level "any field carries a `@view` tag". Read by
32
+ * `ChangeTree.hasFilteredFields` to decide whether a parent tree must
33
+ * be included in a view's bootstrap.
35
34
  */
36
35
  hasAnyView: boolean;
37
- staticBitmask: number;
36
+ fullStateOnlyBitmask: number;
38
37
  unreliableBitmask: number;
39
38
  /**
40
39
  * Bit i set iff field i holds a `t.stream(...)` collection. Hot encode
@@ -1,5 +1,9 @@
1
1
  import { ChangeTree, Ref } from "./ChangeTree.js";
2
2
  import { OPERATION } from "../encoding/spec.js";
3
+ import type { StreamSchema } from "../types/custom/StreamSchema.js";
4
+ import type { MapSchema } from "../types/custom/MapSchema.js";
5
+ import type { SetSchema } from "../types/custom/SetSchema.js";
6
+ import type { CollectionSchema } from "../types/custom/CollectionSchema.js";
3
7
  export declare function createView(iterable?: boolean): StateView;
4
8
  export declare class StateView {
5
9
  iterable: boolean;
@@ -64,12 +68,6 @@ export declare class StateView {
64
68
  private _setSubscribed;
65
69
  /** Clear the subscription bit on `tree`. */
66
70
  private _clearSubscribed;
67
- /** True iff this view has previously marked `tree` as invisible. */
68
- isInvisible(tree: ChangeTree): boolean;
69
- /** Mark `tree` as invisible to this view (used by encode loop). */
70
- markInvisible(tree: ChangeTree): void;
71
- /** Clear invisible bit. */
72
- unmarkInvisible(tree: ChangeTree): void;
73
71
  /**
74
72
  * True iff this view shares at least one tag bit with `tree`.
75
73
  *
@@ -151,9 +149,29 @@ export declare class StateView {
151
149
  * enqueued into `_pendingByView` so the priority pass drains them
152
150
  * respecting `maxPerTick`.
153
151
  *
154
- * Idempotent on re-subscribe. Subscribing to an already-subscribed
155
- * collection is a no-op.
152
+ * On a streaming collection, pass a `priority` callback to order THIS
153
+ * client's backlog. It receives only the element, so whatever the
154
+ * client sorts by is captured in the closure — nothing is attached to
155
+ * the view, and both the element and the captured entity stay typed:
156
+ *
157
+ * ```ts
158
+ * onJoin(client) {
159
+ * const player = this.state.players.get(client.sessionId);
160
+ * client.view.subscribe(this.state.enemies, (enemy) =>
161
+ * -((enemy.x - player.x) ** 2 + (enemy.y - player.y) ** 2));
162
+ * }
163
+ * ```
164
+ *
165
+ * A per-view callback overrides the collection's declaration-scope
166
+ * `.priority()` for this client only.
167
+ *
168
+ * Idempotent on re-subscribe: subscribing to an already-subscribed
169
+ * collection is a no-op, EXCEPT that a supplied `priority` always
170
+ * replaces the previous one — re-subscribe to retarget the ordering.
171
+ * Omitting the argument leaves any existing callback in place; pass
172
+ * `null` to drop it and fall back to the declaration-scope callback.
156
173
  */
174
+ subscribe<V>(collection: StreamSchema<V> | MapSchema<V, any> | SetSchema<V> | CollectionSchema<V>, priority?: ((element: V) => number) | null): this;
157
175
  subscribe(collection: Ref): this;
158
176
  /**
159
177
  * End a persistent subscription. Queues DELETE for every already-sent
@@ -6,7 +6,7 @@ import { type ChangeTree, type Ref } from "../ChangeTree.js";
6
6
  */
7
7
  export declare function checkIsFiltered(tree: ChangeTree, parent: Ref, parentIndex: number, _isNewChangeTree: boolean): void;
8
8
  /**
9
- * Inherit filter / unreliable / transient / static classification from
9
+ * Inherit filter / unreliable / patchOnly / static classification from
10
10
  * the parent field's annotation. Collections (MapSchema / ArraySchema /
11
11
  * etc.) inherit these from the Schema field that holds them.
12
12
  *
@@ -30,6 +30,13 @@ export interface StreamableState {
30
30
  * Instance-level override: assign to `stream.priority`.
31
31
  */
32
32
  priority?: (view: any, element: any) => number;
33
+ /**
34
+ * Per-view priority registered by `StateView.subscribe(collection, fn)`.
35
+ * Takes precedence over the declaration-scope `priority` for that view.
36
+ * Receives only the element — the client's own entity is captured in
37
+ * the closure, so nothing has to be attached to the view.
38
+ */
39
+ priorityByView?: Map<number, (element: any) => number>;
33
40
  }
34
41
  export declare function createStreamableState(): StreamableState;
35
42
  /** Allocate `_stream` on first use (idempotent). Returns the state. */