@colyseus/schema 3.0.75 → 4.0.0
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 +780 -429
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +778 -430
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +780 -429
- package/lib/Reflection.d.ts +50 -17
- package/lib/Reflection.js +151 -202
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +13 -1
- package/lib/Schema.js +73 -9
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +6 -1
- package/lib/annotations.js +8 -34
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.js +34 -1
- package/lib/bench_encode.js.map +1 -1
- package/lib/codegen/api.js +35 -2
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/cli.js +4 -1
- package/lib/codegen/cli.js.map +1 -1
- package/lib/codegen/parser.js +35 -2
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +34 -1
- package/lib/codegen/types.js.map +1 -1
- package/lib/decoder/DecodeOperation.d.ts +2 -2
- package/lib/decoder/DecodeOperation.js +3 -3
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +3 -3
- package/lib/decoder/Decoder.js +2 -2
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/ReferenceTracker.d.ts +0 -1
- package/lib/decoder/ReferenceTracker.js +9 -7
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/Callbacks.d.ts +154 -0
- package/lib/decoder/strategy/Callbacks.js +340 -0
- package/lib/decoder/strategy/Callbacks.js.map +1 -0
- package/lib/decoder/strategy/{StateCallbacks.d.ts → getDecoderStateCallbacks.d.ts} +6 -0
- package/lib/decoder/strategy/{StateCallbacks.js → getDecoderStateCallbacks.js} +17 -10
- package/lib/decoder/strategy/getDecoderStateCallbacks.js.map +1 -0
- package/lib/encoder/ChangeTree.d.ts +2 -2
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +2 -2
- package/lib/encoder/EncodeOperation.js +3 -3
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +6 -6
- package/lib/encoder/Encoder.js +19 -18
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.js +17 -14
- package/lib/encoder/Root.js.map +1 -1
- package/lib/encoder/StateView.js +13 -12
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/decode.d.ts +2 -2
- package/lib/encoding/encode.d.ts +3 -1
- package/lib/encoding/encode.js.map +1 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.js +7 -3
- package/lib/index.js.map +1 -1
- package/lib/types/HelperTypes.d.ts +7 -14
- package/lib/types/HelperTypes.js.map +1 -1
- package/lib/types/custom/ArraySchema.d.ts +2 -1
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.d.ts +2 -1
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.d.ts +3 -2
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.d.ts +2 -1
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/symbols.d.ts +1 -0
- package/lib/types/symbols.js +2 -1
- package/lib/types/symbols.js.map +1 -1
- package/lib/utils.js +1 -1
- package/lib/utils.js.map +1 -1
- package/package.json +12 -16
- package/src/Reflection.ts +185 -174
- package/src/Schema.ts +81 -13
- package/src/annotations.ts +14 -40
- package/src/codegen/parser.ts +1 -1
- package/src/decoder/DecodeOperation.ts +9 -9
- package/src/decoder/Decoder.ts +6 -6
- package/src/decoder/ReferenceTracker.ts +10 -8
- package/src/decoder/strategy/Callbacks.ts +547 -0
- package/src/decoder/strategy/{StateCallbacks.ts → getDecoderStateCallbacks.ts} +17 -11
- package/src/encoder/ChangeTree.ts +4 -7
- package/src/encoder/EncodeOperation.ts +9 -9
- package/src/encoder/Encoder.ts +26 -18
- package/src/encoder/Root.ts +20 -15
- package/src/encoder/StateView.ts +15 -13
- package/src/encoding/encode.ts +1 -1
- package/src/index.ts +3 -2
- package/src/types/HelperTypes.ts +13 -11
- package/src/types/custom/ArraySchema.ts +2 -1
- package/src/types/custom/CollectionSchema.ts +4 -2
- package/src/types/custom/MapSchema.ts +4 -2
- package/src/types/custom/SetSchema.ts +3 -1
- package/src/types/symbols.ts +1 -0
- package/src/utils.ts +2 -2
- package/lib/Decoder.d.ts +0 -16
- package/lib/Decoder.js +0 -182
- package/lib/Decoder.js.map +0 -1
- package/lib/Encoder.d.ts +0 -13
- package/lib/Encoder.js +0 -79
- package/lib/Encoder.js.map +0 -1
- package/lib/changes/ChangeSet.d.ts +0 -12
- package/lib/changes/ChangeSet.js +0 -35
- package/lib/changes/ChangeSet.js.map +0 -1
- package/lib/changes/ChangeTree.d.ts +0 -53
- package/lib/changes/ChangeTree.js +0 -202
- package/lib/changes/ChangeTree.js.map +0 -1
- package/lib/changes/DecodeOperation.d.ts +0 -15
- package/lib/changes/DecodeOperation.js +0 -186
- package/lib/changes/DecodeOperation.js.map +0 -1
- package/lib/changes/EncodeOperation.d.ts +0 -18
- package/lib/changes/EncodeOperation.js +0 -130
- package/lib/changes/EncodeOperation.js.map +0 -1
- package/lib/changes/ReferenceTracker.d.ts +0 -14
- package/lib/changes/ReferenceTracker.js +0 -83
- package/lib/changes/ReferenceTracker.js.map +0 -1
- package/lib/changes/consts.d.ts +0 -14
- package/lib/changes/consts.js +0 -18
- package/lib/changes/consts.js.map +0 -1
- package/lib/decoder/strategy/StateCallbacks.js.map +0 -1
- package/lib/decoding/decode.d.ts +0 -48
- package/lib/decoding/decode.js +0 -267
- package/lib/decoding/decode.js.map +0 -1
- package/lib/ecs.d.ts +0 -11
- package/lib/ecs.js +0 -160
- package/lib/ecs.js.map +0 -1
- package/lib/filters/index.d.ts +0 -8
- package/lib/filters/index.js +0 -24
- package/lib/filters/index.js.map +0 -1
- package/lib/spec.d.ts +0 -13
- package/lib/spec.js +0 -42
- package/lib/spec.js.map +0 -1
- package/lib/types/ArraySchema.d.ts +0 -238
- package/lib/types/ArraySchema.js +0 -555
- package/lib/types/ArraySchema.js.map +0 -1
- package/lib/types/CollectionSchema.d.ts +0 -35
- package/lib/types/CollectionSchema.js +0 -150
- package/lib/types/CollectionSchema.js.map +0 -1
- package/lib/types/MapSchema.d.ts +0 -38
- package/lib/types/MapSchema.js +0 -215
- package/lib/types/MapSchema.js.map +0 -1
- package/lib/types/SetSchema.d.ts +0 -32
- package/lib/types/SetSchema.js +0 -162
- package/lib/types/SetSchema.js.map +0 -1
- package/lib/types/typeRegistry.d.ts +0 -5
- package/lib/types/typeRegistry.js +0 -13
- package/lib/types/typeRegistry.js.map +0 -1
- package/lib/usage.d.ts +0 -1
- package/lib/usage.js +0 -22
- package/lib/usage.js.map +0 -1
- package/lib/v3.d.ts +0 -1
- package/lib/v3.js +0 -427
- package/lib/v3.js.map +0 -1
- package/lib/v3_experiment.d.ts +0 -1
- package/lib/v3_experiment.js +0 -407
- package/lib/v3_experiment.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Decoder.js","sourceRoot":"","sources":["../../src/decoder/Decoder.ts"],"names":[],"mappings":";;;AAAA,sDAAmD;AACnD,
|
|
1
|
+
{"version":3,"file":"Decoder.js","sourceRoot":"","sources":["../../src/decoder/Decoder.ts"],"names":[],"mappings":"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","sourcesContent":["import { TypeContext } from \"../types/TypeContext\";\nimport { $changes, $childType, $decoder, $onDecodeEnd, $refId } from \"../types/symbols\";\nimport { Schema } from \"../Schema\";\n\nimport { decode } from \"../encoding/decode\";\nimport { OPERATION, SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec';\nimport type { Ref } from \"../encoder/ChangeTree\";\nimport type { Iterator } from \"../encoding/decode\";\nimport { ReferenceTracker } from \"./ReferenceTracker\";\nimport { DEFINITION_MISMATCH, type DataChange, type DecodeOperation } from \"./DecodeOperation\";\nimport { Collection } from \"../types/HelperTypes\";\n\nexport class Decoder<T extends Schema = any> {\n context: TypeContext;\n\n state: T;\n root: ReferenceTracker;\n\n currentRefId: number = 0;\n\n triggerChanges?: (allChanges: DataChange[]) => void;\n\n constructor(root: T, context?: TypeContext) {\n this.setState(root);\n\n this.context = context || new TypeContext(root.constructor as typeof Schema);\n\n // console.log(\">>>>>>>>>>>>>>>> Decoder types\");\n // this.context.schemas.forEach((id, schema) => {\n // console.log(\"type:\", id, schema.name, Object.keys(schema[Symbol.metadata]));\n // });\n }\n\n protected setState(root: T) {\n this.state = root;\n this.root = new ReferenceTracker();\n this.root.addRef(0, root);\n }\n\n decode(\n bytes: Uint8Array,\n it: Iterator = { offset: 0 },\n ref: Ref = this.state,\n ) {\n const allChanges: DataChange[] = [];\n\n const $root = this.root;\n const totalBytes = bytes.byteLength;\n\n let decoder: DecodeOperation = ref['constructor'][$decoder];\n\n this.currentRefId = 0;\n\n while (it.offset < totalBytes) {\n //\n // Peek ahead, check if it's a switch to a different structure\n //\n if (bytes[it.offset] == SWITCH_TO_STRUCTURE) {\n it.offset++;\n\n (ref as any)[$onDecodeEnd]?.()\n\n const nextRefId = decode.number(bytes, it);\n const nextRef = $root.refs.get(nextRefId);\n\n //\n // Trying to access a reference that haven't been decoded yet.\n //\n if (!nextRef) {\n // throw new Error(`\"refId\" not found: ${nextRefId}`);\n console.error(`\"refId\" not found: ${nextRefId}`, { previousRef: ref, previousRefId: this.currentRefId });\n console.warn(\"Please report this issue to the developers.\");\n this.skipCurrentStructure(bytes, it, totalBytes);\n\n } else {\n ref = nextRef;\n decoder = ref.constructor[$decoder];\n this.currentRefId = nextRefId;\n }\n\n continue;\n }\n\n const result = decoder(this, bytes, it, ref, allChanges);\n\n if (result === DEFINITION_MISMATCH) {\n console.warn(\"@colyseus/schema: definition mismatch\");\n this.skipCurrentStructure(bytes, it, totalBytes);\n continue;\n }\n }\n\n // FIXME: DRY with SWITCH_TO_STRUCTURE block.\n (ref as any)[$onDecodeEnd]?.()\n\n // trigger changes\n this.triggerChanges?.(allChanges);\n\n // drop references of unused schemas\n $root.garbageCollectDeletedRefs();\n\n return allChanges;\n }\n\n skipCurrentStructure(bytes: Uint8Array, it: Iterator, totalBytes: number) {\n //\n // keep skipping next bytes until reaches a known structure\n // by local decoder.\n //\n const nextIterator: Iterator = { offset: it.offset };\n while (it.offset < totalBytes) {\n if (bytes[it.offset] === SWITCH_TO_STRUCTURE) {\n nextIterator.offset = it.offset + 1;\n if (this.root.refs.has(decode.number(bytes, nextIterator))) {\n break;\n }\n }\n it.offset++;\n }\n }\n\n getInstanceType(bytes: Uint8Array, it: Iterator, defaultType: typeof Schema): typeof Schema {\n let type: typeof Schema;\n\n if (bytes[it.offset] === TYPE_ID) {\n it.offset++;\n const type_id = decode.number(bytes, it);\n type = this.context.get(type_id);\n }\n\n return type || defaultType;\n }\n\n createInstanceOfType (type: typeof Schema): Schema {\n return new (type as any)();\n }\n\n removeChildRefs(ref: Collection, allChanges: DataChange[]) {\n const needRemoveRef = typeof ((ref as any)[$childType]) !== \"string\";\n const refId = (ref as Ref)[$refId];\n\n ref.forEach((value: any, key: any) => {\n allChanges.push({\n ref: ref as Ref,\n refId,\n op: OPERATION.DELETE,\n field: key,\n value: undefined,\n previousValue: value\n });\n\n if (needRemoveRef) {\n this.root.removeRef(value[$refId]);\n }\n });\n }\n\n}\n"]}
|
|
@@ -17,7 +17,6 @@ class ReferenceTracker {
|
|
|
17
17
|
// For direct access of structures during decoding time.
|
|
18
18
|
//
|
|
19
19
|
this.refs = new Map();
|
|
20
|
-
this.refIds = new WeakMap();
|
|
21
20
|
this.refCount = {};
|
|
22
21
|
this.deletedRefs = new Set();
|
|
23
22
|
this.callbacks = {};
|
|
@@ -29,7 +28,7 @@ class ReferenceTracker {
|
|
|
29
28
|
// for decoding
|
|
30
29
|
addRef(refId, ref, incrementCount = true) {
|
|
31
30
|
this.refs.set(refId, ref);
|
|
32
|
-
|
|
31
|
+
ref[symbols_1.$refId] = refId;
|
|
33
32
|
if (incrementCount) {
|
|
34
33
|
this.refCount[refId] = (this.refCount[refId] || 0) + 1;
|
|
35
34
|
}
|
|
@@ -86,9 +85,12 @@ class ReferenceTracker {
|
|
|
86
85
|
const metadata = ref.constructor[Symbol.metadata];
|
|
87
86
|
for (const index in metadata) {
|
|
88
87
|
const field = metadata[index].name;
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
91
|
-
|
|
88
|
+
const child = ref[field];
|
|
89
|
+
if (typeof (child) === "object" && child) {
|
|
90
|
+
const childRefId = child[symbols_1.$refId];
|
|
91
|
+
if (childRefId !== undefined && !this.deletedRefs.has(childRefId)) {
|
|
92
|
+
this.removeRef(childRefId);
|
|
93
|
+
}
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
}
|
|
@@ -96,8 +98,8 @@ class ReferenceTracker {
|
|
|
96
98
|
if (typeof (ref[symbols_1.$childType]) === "function") {
|
|
97
99
|
Array.from(ref.values())
|
|
98
100
|
.forEach((child) => {
|
|
99
|
-
const childRefId =
|
|
100
|
-
if (!this.deletedRefs.has(childRefId)) {
|
|
101
|
+
const childRefId = child[symbols_1.$refId];
|
|
102
|
+
if (childRefId !== undefined && !this.deletedRefs.has(childRefId)) {
|
|
101
103
|
this.removeRef(childRefId);
|
|
102
104
|
}
|
|
103
105
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReferenceTracker.js","sourceRoot":"","sources":["../../src/decoder/ReferenceTracker.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata } from \"../Metadata\";\nimport { $childType } from \"../types/symbols\";\nimport { Ref } from \"../encoder/ChangeTree\";\nimport { spliceOne } from \"../types/utils\";\nimport { OPERATION } from \"../encoding/spec\";\n\nimport type { MapSchema } from \"../types/custom/MapSchema\";\nimport type { Schema } from \"../Schema\";\n\nclass DecodingWarning extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DecodingWarning\";\n }\n}\n\n/**\n * Used for decoding only.\n */\n\nexport type SchemaCallbacks = { [field: string | number]: Function[] };\n\nexport class ReferenceTracker {\n //\n // Relation of refId => Schema structure\n // For direct access of structures during decoding time.\n //\n public refs = new Map<number, Ref>();\n public refIds = new WeakMap<Ref, number>();\n\n public refCount: { [refId: number]: number; } = {};\n public deletedRefs = new Set<number>();\n\n public callbacks: { [refId: number]: SchemaCallbacks } = {};\n protected nextUniqueId: number = 0;\n\n getNextUniqueId() {\n return this.nextUniqueId++;\n }\n\n // for decoding\n addRef(refId: number, ref: Ref, incrementCount: boolean = true) {\n this.refs.set(refId, ref);\n this.refIds.set(ref, refId);\n\n if (incrementCount) {\n this.refCount[refId] = (this.refCount[refId] || 0) + 1;\n }\n\n if (this.deletedRefs.has(refId)) {\n this.deletedRefs.delete(refId);\n }\n }\n\n // for decoding\n removeRef(refId: number) {\n const refCount = this.refCount[refId];\n\n if (refCount === undefined) {\n try {\n throw new DecodingWarning(\"trying to remove refId that doesn't exist: \" + refId);\n } catch (e) {\n console.warn(e);\n }\n return;\n }\n\n if (refCount === 0) {\n try {\n const ref = this.refs.get(refId);\n throw new DecodingWarning(`trying to remove refId '${refId}' with 0 refCount (${ref.constructor.name}: ${JSON.stringify(ref)})`);\n } catch (e) {\n console.warn(e);\n }\n return;\n }\n\n if ((this.refCount[refId] = refCount - 1) <= 0) {\n this.deletedRefs.add(refId);\n }\n }\n\n clearRefs() {\n this.refs.clear();\n this.deletedRefs.clear();\n this.callbacks = {};\n this.refCount = {};\n }\n\n // for decoding\n garbageCollectDeletedRefs() {\n this.deletedRefs.forEach((refId) => {\n //\n // Skip active references.\n //\n if (this.refCount[refId] > 0) { return; }\n\n const ref = this.refs.get(refId);\n\n //\n // Ensure child schema instances have their references removed as well.\n //\n if ((ref.constructor as typeof Schema)[Symbol.metadata] !== undefined) {\n const metadata: Metadata = (ref.constructor as typeof Schema)[Symbol.metadata];\n for (const index in metadata) {\n const field = metadata[index as any as number].name;\n const childRefId = typeof(ref[field as keyof Ref]) === \"object\" && this.refIds.get((ref as any)[field]);\n if (childRefId && !this.deletedRefs.has(childRefId)) {\n this.removeRef(childRefId);\n }\n }\n\n } else {\n if (typeof ((ref as any)[$childType]) === \"function\") {\n Array.from((ref as MapSchema).values())\n .forEach((child) => {\n const childRefId = this.refIds.get(child);\n if (!this.deletedRefs.has(childRefId)) {\n this.removeRef(childRefId);\n }\n });\n }\n }\n\n this.refs.delete(refId); // remove ref\n delete this.refCount[refId]; // remove ref count\n delete this.callbacks[refId]; // remove callbacks\n });\n\n // clear deleted refs.\n this.deletedRefs.clear();\n }\n\n addCallback(refId: number, fieldOrOperation: string | number, callback: Function) {\n if (refId === undefined) {\n const name = (typeof(fieldOrOperation) === \"number\")\n ? OPERATION[fieldOrOperation]\n : fieldOrOperation\n throw new Error(\n `Can't addCallback on '${name}' (refId is undefined)`\n );\n }\n if (!this.callbacks[refId]) {\n this.callbacks[refId] = {};\n }\n if (!this.callbacks[refId][fieldOrOperation]) {\n this.callbacks[refId][fieldOrOperation] = [];\n }\n this.callbacks[refId][fieldOrOperation].push(callback);\n return () => this.removeCallback(refId, fieldOrOperation, callback);\n }\n\n removeCallback(refId: number, field: string | number, callback: Function) {\n const index: number | undefined = this.callbacks?.[refId]?.[field]?.indexOf(callback);\n if (index !== undefined && index !== -1) {\n spliceOne(this.callbacks[refId][field], index);\n }\n }\n\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ReferenceTracker.js","sourceRoot":"","sources":["../../src/decoder/ReferenceTracker.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata } from \"../Metadata\";\nimport { $childType, $refId } from \"../types/symbols\";\nimport { Ref } from \"../encoder/ChangeTree\";\nimport { spliceOne } from \"../types/utils\";\nimport { OPERATION } from \"../encoding/spec\";\n\nimport type { MapSchema } from \"../types/custom/MapSchema\";\nimport type { Schema } from \"../Schema\";\n\nclass DecodingWarning extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DecodingWarning\";\n }\n}\n\n/**\n * Used for decoding only.\n */\n\nexport type SchemaCallbacks = { [field: string | number]: Function[] };\n\nexport class ReferenceTracker {\n //\n // Relation of refId => Schema structure\n // For direct access of structures during decoding time.\n //\n public refs = new Map<number, Ref>();\n\n public refCount: { [refId: number]: number; } = {};\n public deletedRefs = new Set<number>();\n\n public callbacks: { [refId: number]: SchemaCallbacks } = {};\n protected nextUniqueId: number = 0;\n\n getNextUniqueId() {\n return this.nextUniqueId++;\n }\n\n // for decoding\n addRef(refId: number, ref: Ref, incrementCount: boolean = true) {\n this.refs.set(refId, ref);\n ref[$refId] = refId;\n\n if (incrementCount) {\n this.refCount[refId] = (this.refCount[refId] || 0) + 1;\n }\n\n if (this.deletedRefs.has(refId)) {\n this.deletedRefs.delete(refId);\n }\n }\n\n // for decoding\n removeRef(refId: number) {\n const refCount = this.refCount[refId];\n\n if (refCount === undefined) {\n try {\n throw new DecodingWarning(\"trying to remove refId that doesn't exist: \" + refId);\n } catch (e) {\n console.warn(e);\n }\n return;\n }\n\n if (refCount === 0) {\n try {\n const ref = this.refs.get(refId);\n throw new DecodingWarning(`trying to remove refId '${refId}' with 0 refCount (${ref.constructor.name}: ${JSON.stringify(ref)})`);\n } catch (e) {\n console.warn(e);\n }\n return;\n }\n\n if ((this.refCount[refId] = refCount - 1) <= 0) {\n this.deletedRefs.add(refId);\n }\n }\n\n clearRefs() {\n this.refs.clear();\n this.deletedRefs.clear();\n this.callbacks = {};\n this.refCount = {};\n }\n\n // for decoding\n garbageCollectDeletedRefs() {\n this.deletedRefs.forEach((refId) => {\n //\n // Skip active references.\n //\n if (this.refCount[refId] > 0) { return; }\n\n const ref = this.refs.get(refId);\n\n //\n // Ensure child schema instances have their references removed as well.\n //\n if ((ref.constructor as typeof Schema)[Symbol.metadata] !== undefined) {\n const metadata: Metadata = (ref.constructor as typeof Schema)[Symbol.metadata];\n for (const index in metadata) {\n const field = metadata[index as any as number].name;\n const child = ref[field as keyof Ref];\n if (typeof(child) === \"object\" && child) {\n const childRefId = (child as any)[$refId];\n if (childRefId !== undefined && !this.deletedRefs.has(childRefId)) {\n this.removeRef(childRefId);\n }\n }\n }\n\n } else {\n if (typeof ((ref as any)[$childType]) === \"function\") {\n Array.from((ref as MapSchema).values())\n .forEach((child) => {\n const childRefId = child[$refId];\n if (childRefId !== undefined && !this.deletedRefs.has(childRefId)) {\n this.removeRef(childRefId);\n }\n });\n }\n }\n\n this.refs.delete(refId); // remove ref\n delete this.refCount[refId]; // remove ref count\n delete this.callbacks[refId]; // remove callbacks\n });\n\n // clear deleted refs.\n this.deletedRefs.clear();\n }\n\n addCallback(refId: number, fieldOrOperation: string | number, callback: Function) {\n if (refId === undefined) {\n const name = (typeof(fieldOrOperation) === \"number\")\n ? OPERATION[fieldOrOperation]\n : fieldOrOperation\n throw new Error(\n `Can't addCallback on '${name}' (refId is undefined)`\n );\n }\n if (!this.callbacks[refId]) {\n this.callbacks[refId] = {};\n }\n if (!this.callbacks[refId][fieldOrOperation]) {\n this.callbacks[refId][fieldOrOperation] = [];\n }\n this.callbacks[refId][fieldOrOperation].push(callback);\n return () => this.removeCallback(refId, fieldOrOperation, callback);\n }\n\n removeCallback(refId: number, field: string | number, callback: Function) {\n const index: number | undefined = this.callbacks?.[refId]?.[field]?.indexOf(callback);\n if (index !== undefined && index !== -1) {\n spliceOne(this.callbacks[refId][field], index);\n }\n }\n\n}\n"]}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Collection, NonFunctionPropNames } from "../../types/HelperTypes";
|
|
2
|
+
import { Ref } from "../../encoder/ChangeTree";
|
|
3
|
+
import { Decoder } from "../Decoder";
|
|
4
|
+
import { DataChange } from "../DecodeOperation";
|
|
5
|
+
import { OPERATION } from "../../encoding/spec";
|
|
6
|
+
import { Schema } from "../../Schema";
|
|
7
|
+
import { $refId } from "../../types/symbols";
|
|
8
|
+
import { MapSchema } from "../../types/custom/MapSchema";
|
|
9
|
+
import { ArraySchema } from "../../types/custom/ArraySchema";
|
|
10
|
+
import { type SchemaCallbackProxy } from "./getDecoderStateCallbacks";
|
|
11
|
+
type PropertyChangeCallback<K> = (currentValue: K, previousValue: K) => void;
|
|
12
|
+
type KeyValueCallback<K, V> = (key: K, value: V) => void;
|
|
13
|
+
type InstanceChangeCallback = () => void;
|
|
14
|
+
type PublicPropNames<T> = Exclude<NonFunctionPropNames<T>, typeof $refId> & string;
|
|
15
|
+
type CollectionPropNames<T> = Exclude<{
|
|
16
|
+
[K in keyof T]: T[K] extends Collection<any, any> ? K : never;
|
|
17
|
+
}[keyof T] & string, typeof $refId>;
|
|
18
|
+
type CollectionValueType<T, K extends keyof T> = T[K] extends MapSchema<infer V, any> ? V : T[K] extends ArraySchema<infer V> ? V : T[K] extends Collection<any, infer V, any> ? V : never;
|
|
19
|
+
type CollectionKeyType<T, K extends keyof T> = T[K] extends MapSchema<any, infer Key> ? Key : T[K] extends ArraySchema<any> ? number : T[K] extends Collection<infer Key, any, any> ? Key : never;
|
|
20
|
+
/**
|
|
21
|
+
* State Callbacks handler
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* ```ts
|
|
25
|
+
* const $ = Callbacks.get(decoder);
|
|
26
|
+
*
|
|
27
|
+
* // Listen to property changes
|
|
28
|
+
* $.listen("currentTurn", (currentValue, previousValue) => { ... });
|
|
29
|
+
*
|
|
30
|
+
* // Listen to collection additions
|
|
31
|
+
* $.onAdd("entities", (sessionId, entity) => {
|
|
32
|
+
* // Nested property listening
|
|
33
|
+
* $.listen(entity, "hp", (currentHp, previousHp) => { ... });
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Listen to collection removals
|
|
37
|
+
* $.onRemove("entities", (sessionId, entity) => { ... });
|
|
38
|
+
*
|
|
39
|
+
* // Listen to any property change on an instance
|
|
40
|
+
* $.onChange(entity, () => { ... });
|
|
41
|
+
*
|
|
42
|
+
* // Bind properties to another object
|
|
43
|
+
* $.bindTo(player, playerVisual);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare class StateCallbackStrategy<TState extends Schema> {
|
|
47
|
+
protected decoder: Decoder<TState>;
|
|
48
|
+
protected uniqueRefIds: Set<number>;
|
|
49
|
+
protected isTriggering: boolean;
|
|
50
|
+
constructor(decoder: Decoder<TState>);
|
|
51
|
+
protected get callbacks(): {
|
|
52
|
+
[refId: number]: import("../ReferenceTracker").SchemaCallbacks;
|
|
53
|
+
};
|
|
54
|
+
protected get state(): TState;
|
|
55
|
+
protected addCallback(refId: number, operationOrProperty: OPERATION | string, handler: Function): () => void;
|
|
56
|
+
protected addCallbackOrWaitCollectionAvailable<TInstance extends Schema, TReturn extends Ref>(instance: TInstance, propertyName: string, operation: OPERATION, handler: Function, immediate?: boolean): () => void;
|
|
57
|
+
/**
|
|
58
|
+
* Listen to property changes on the root state.
|
|
59
|
+
*/
|
|
60
|
+
listen<K extends PublicPropNames<TState>>(property: K, handler: PropertyChangeCallback<TState[K]>, immediate?: boolean): () => void;
|
|
61
|
+
/**
|
|
62
|
+
* Listen to property changes on a nested instance.
|
|
63
|
+
*/
|
|
64
|
+
listen<TInstance extends Schema, K extends PublicPropNames<TInstance>>(instance: TInstance, property: K, handler: PropertyChangeCallback<TInstance[K]>, immediate?: boolean): () => void;
|
|
65
|
+
protected listenInstance<TInstance extends Schema>(instance: TInstance, propertyName: string, handler: PropertyChangeCallback<any>, immediate?: boolean): () => void;
|
|
66
|
+
/**
|
|
67
|
+
* Listen to any property change on an instance.
|
|
68
|
+
*/
|
|
69
|
+
onChange<TInstance extends Schema>(instance: TInstance, handler: InstanceChangeCallback): () => void;
|
|
70
|
+
/**
|
|
71
|
+
* Listen to item changes in a collection on root state.
|
|
72
|
+
*/
|
|
73
|
+
onChange<K extends CollectionPropNames<TState>>(property: K, handler: KeyValueCallback<CollectionKeyType<TState, K>, CollectionValueType<TState, K>>): () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Listen to item changes in a nested collection.
|
|
76
|
+
*/
|
|
77
|
+
onChange<TInstance extends Schema, K extends CollectionPropNames<TInstance>>(instance: TInstance, property: K, handler: KeyValueCallback<CollectionKeyType<TInstance, K>, CollectionValueType<TInstance, K>>): () => void;
|
|
78
|
+
/**
|
|
79
|
+
* Listen to items added to a collection on root state.
|
|
80
|
+
*/
|
|
81
|
+
onAdd<K extends CollectionPropNames<TState>>(property: K, handler: KeyValueCallback<CollectionKeyType<TState, K>, CollectionValueType<TState, K>>, immediate?: boolean): () => void;
|
|
82
|
+
/**
|
|
83
|
+
* Listen to items added to a nested collection.
|
|
84
|
+
*/
|
|
85
|
+
onAdd<TInstance extends Schema, K extends CollectionPropNames<TInstance>>(instance: TInstance, property: K, handler: KeyValueCallback<CollectionKeyType<TInstance, K>, CollectionValueType<TInstance, K>>, immediate?: boolean): () => void;
|
|
86
|
+
/**
|
|
87
|
+
* Listen to items removed from a collection on root state.
|
|
88
|
+
*/
|
|
89
|
+
onRemove<K extends CollectionPropNames<TState>>(property: K, handler: KeyValueCallback<CollectionKeyType<TState, K>, CollectionValueType<TState, K>>): () => void;
|
|
90
|
+
/**
|
|
91
|
+
* Listen to items removed from a nested collection.
|
|
92
|
+
*/
|
|
93
|
+
onRemove<TInstance extends Schema, K extends CollectionPropNames<TInstance>>(instance: TInstance, property: K, handler: KeyValueCallback<CollectionKeyType<TInstance, K>, CollectionValueType<TInstance, K>>): () => void;
|
|
94
|
+
/**
|
|
95
|
+
* Bind properties from a Schema instance to a target object.
|
|
96
|
+
* Changes will be automatically reflected on the target object.
|
|
97
|
+
*/
|
|
98
|
+
bindTo<TInstance extends Schema, TTarget>(from: TInstance, to: TTarget, properties?: string[], immediate?: boolean): () => void;
|
|
99
|
+
protected triggerChanges(allChanges: DataChange[]): void;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Factory class for retrieving the callbacks API.
|
|
103
|
+
*/
|
|
104
|
+
export declare const Callbacks: {
|
|
105
|
+
/**
|
|
106
|
+
* Get the new callbacks standard API.
|
|
107
|
+
*
|
|
108
|
+
* Usage:
|
|
109
|
+
* ```ts
|
|
110
|
+
* const callbacks = Callbacks.get(roomOrDecoder);
|
|
111
|
+
*
|
|
112
|
+
* // Listen to property changes
|
|
113
|
+
* callbacks.listen("currentTurn", (currentValue, previousValue) => { ... });
|
|
114
|
+
*
|
|
115
|
+
* // Listen to collection additions
|
|
116
|
+
* callbacks.onAdd("entities", (sessionId, entity) => {
|
|
117
|
+
* // Nested property listening
|
|
118
|
+
* callbacks.listen(entity, "hp", (currentHp, previousHp) => { ... });
|
|
119
|
+
* });
|
|
120
|
+
*
|
|
121
|
+
* // Listen to collection removals
|
|
122
|
+
* callbacks.onRemove("entities", (sessionId, entity) => { ... });
|
|
123
|
+
*
|
|
124
|
+
* // Listen to any property change on an instance
|
|
125
|
+
* callbacks.onChange(entity, () => { ... });
|
|
126
|
+
*
|
|
127
|
+
* // Bind properties to another object
|
|
128
|
+
* callbacks.bindTo(player, playerVisual);
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* @param roomOrDecoder - Room or Decoder instance to get the callbacks for.
|
|
132
|
+
* @returns the new callbacks standard API.
|
|
133
|
+
*/
|
|
134
|
+
get<T extends Schema>(roomOrDecoder: Decoder<T> | {
|
|
135
|
+
serializer: {
|
|
136
|
+
decoder: Decoder<T>;
|
|
137
|
+
};
|
|
138
|
+
}): StateCallbackStrategy<T>;
|
|
139
|
+
/**
|
|
140
|
+
* Get the legacy callbacks API.
|
|
141
|
+
*
|
|
142
|
+
* We aim to deprecate this API on 1.0, and iterate on improving Callbacks.get() API.
|
|
143
|
+
*
|
|
144
|
+
* @param roomOrDecoder - Room or Decoder instance to get the legacy callbacks for.
|
|
145
|
+
* @returns the legacy callbacks API.
|
|
146
|
+
*/
|
|
147
|
+
getLegacy<T extends Schema>(roomOrDecoder: Decoder<T> | {
|
|
148
|
+
serializer: {
|
|
149
|
+
decoder: Decoder<T>;
|
|
150
|
+
};
|
|
151
|
+
}): SchemaCallbackProxy<T>;
|
|
152
|
+
getRawChanges(decoder: Decoder, callback: (changes: DataChange[]) => void): void;
|
|
153
|
+
};
|
|
154
|
+
export {};
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Callbacks = exports.StateCallbackStrategy = void 0;
|
|
4
|
+
const Decoder_1 = require("../Decoder");
|
|
5
|
+
const spec_1 = require("../../encoding/spec");
|
|
6
|
+
const Schema_1 = require("../../Schema");
|
|
7
|
+
const symbols_1 = require("../../types/symbols");
|
|
8
|
+
const getDecoderStateCallbacks_1 = require("./getDecoderStateCallbacks");
|
|
9
|
+
const RawChanges_1 = require("./RawChanges");
|
|
10
|
+
/**
|
|
11
|
+
* State Callbacks handler
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```ts
|
|
15
|
+
* const $ = Callbacks.get(decoder);
|
|
16
|
+
*
|
|
17
|
+
* // Listen to property changes
|
|
18
|
+
* $.listen("currentTurn", (currentValue, previousValue) => { ... });
|
|
19
|
+
*
|
|
20
|
+
* // Listen to collection additions
|
|
21
|
+
* $.onAdd("entities", (sessionId, entity) => {
|
|
22
|
+
* // Nested property listening
|
|
23
|
+
* $.listen(entity, "hp", (currentHp, previousHp) => { ... });
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Listen to collection removals
|
|
27
|
+
* $.onRemove("entities", (sessionId, entity) => { ... });
|
|
28
|
+
*
|
|
29
|
+
* // Listen to any property change on an instance
|
|
30
|
+
* $.onChange(entity, () => { ... });
|
|
31
|
+
*
|
|
32
|
+
* // Bind properties to another object
|
|
33
|
+
* $.bindTo(player, playerVisual);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
class StateCallbackStrategy {
|
|
37
|
+
constructor(decoder) {
|
|
38
|
+
this.uniqueRefIds = new Set();
|
|
39
|
+
this.isTriggering = false;
|
|
40
|
+
this.decoder = decoder;
|
|
41
|
+
this.decoder.triggerChanges = this.triggerChanges.bind(this);
|
|
42
|
+
}
|
|
43
|
+
get callbacks() {
|
|
44
|
+
return this.decoder.root.callbacks;
|
|
45
|
+
}
|
|
46
|
+
get state() {
|
|
47
|
+
return this.decoder.state;
|
|
48
|
+
}
|
|
49
|
+
addCallback(refId, operationOrProperty, handler) {
|
|
50
|
+
const $root = this.decoder.root;
|
|
51
|
+
return $root.addCallback(refId, operationOrProperty, handler);
|
|
52
|
+
}
|
|
53
|
+
addCallbackOrWaitCollectionAvailable(instance, propertyName, operation, handler, immediate = true) {
|
|
54
|
+
let removeHandler = () => { };
|
|
55
|
+
const removeOnAdd = () => removeHandler();
|
|
56
|
+
const collection = instance[propertyName];
|
|
57
|
+
// Collection not available yet. Listen for its availability before attaching the handler.
|
|
58
|
+
if (collection === null || collection === undefined) {
|
|
59
|
+
removeHandler = this.addCallback(instance[symbols_1.$refId], propertyName, (value, _) => {
|
|
60
|
+
if (value !== null && value !== undefined) {
|
|
61
|
+
removeHandler = this.addCallback(value[symbols_1.$refId], operation, handler);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return removeOnAdd;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
//
|
|
68
|
+
// Call immediately if collection is already available, if it's an ADD operation.
|
|
69
|
+
//
|
|
70
|
+
immediate = immediate && this.isTriggering === false;
|
|
71
|
+
if (operation === spec_1.OPERATION.ADD && immediate) {
|
|
72
|
+
collection.forEach((value, key) => {
|
|
73
|
+
handler(key, value);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return this.addCallback(collection[symbols_1.$refId], operation, handler);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
listen(...args) {
|
|
80
|
+
if (typeof args[0] === 'string') {
|
|
81
|
+
// listen(property, handler, immediate?)
|
|
82
|
+
return this.listenInstance(this.state, args[0], args[1], args[2]);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// listen(instance, property, handler, immediate?)
|
|
86
|
+
return this.listenInstance(args[0], args[1], args[2], args[3]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
listenInstance(instance, propertyName, handler, immediate = true) {
|
|
90
|
+
immediate = immediate && this.isTriggering === false;
|
|
91
|
+
//
|
|
92
|
+
// Call handler immediately if property is already available.
|
|
93
|
+
//
|
|
94
|
+
const currentValue = instance[propertyName];
|
|
95
|
+
if (immediate && currentValue !== null && currentValue !== undefined) {
|
|
96
|
+
handler(currentValue, undefined);
|
|
97
|
+
}
|
|
98
|
+
return this.addCallback(instance[symbols_1.$refId], propertyName, handler);
|
|
99
|
+
}
|
|
100
|
+
onChange(...args) {
|
|
101
|
+
if (args.length === 2 && typeof args[0] !== 'string') {
|
|
102
|
+
// onChange(instance, handler) - instance change
|
|
103
|
+
const instance = args[0];
|
|
104
|
+
const handler = args[1];
|
|
105
|
+
return this.addCallback(instance[symbols_1.$refId], spec_1.OPERATION.REPLACE, handler);
|
|
106
|
+
}
|
|
107
|
+
if (typeof args[0] === 'string') {
|
|
108
|
+
// onChange(property, handler) - collection on root state
|
|
109
|
+
return this.addCallbackOrWaitCollectionAvailable(this.state, args[0], spec_1.OPERATION.REPLACE, args[1]);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// onChange(instance, property, handler) - nested collection
|
|
113
|
+
return this.addCallbackOrWaitCollectionAvailable(args[0], args[1], spec_1.OPERATION.REPLACE, args[2]);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
onAdd(...args) {
|
|
117
|
+
if (typeof args[0] === 'string') {
|
|
118
|
+
// onAdd(property, handler, immediate?) - collection on root state
|
|
119
|
+
return this.addCallbackOrWaitCollectionAvailable(this.state, args[0], spec_1.OPERATION.ADD, args[1], args[2] !== false);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// onAdd(instance, property, handler, immediate?) - nested collection
|
|
123
|
+
return this.addCallbackOrWaitCollectionAvailable(args[0], args[1], spec_1.OPERATION.ADD, args[2], args[3] !== false);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
onRemove(...args) {
|
|
127
|
+
if (typeof args[0] === 'string') {
|
|
128
|
+
// onRemove(property, handler) - collection on root state
|
|
129
|
+
return this.addCallbackOrWaitCollectionAvailable(this.state, args[0], spec_1.OPERATION.DELETE, args[1]);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// onRemove(instance, property, handler) - nested collection
|
|
133
|
+
return this.addCallbackOrWaitCollectionAvailable(args[0], args[1], spec_1.OPERATION.DELETE, args[2]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Bind properties from a Schema instance to a target object.
|
|
138
|
+
* Changes will be automatically reflected on the target object.
|
|
139
|
+
*/
|
|
140
|
+
bindTo(from, to, properties, immediate = true) {
|
|
141
|
+
const metadata = from.constructor[Symbol.metadata];
|
|
142
|
+
// If no properties specified, bind all properties
|
|
143
|
+
if (!properties) {
|
|
144
|
+
properties = Object.keys(metadata)
|
|
145
|
+
.filter(key => !isNaN(Number(key)))
|
|
146
|
+
.map((index) => metadata[index].name);
|
|
147
|
+
}
|
|
148
|
+
const action = () => {
|
|
149
|
+
for (const prop of properties) {
|
|
150
|
+
const fromValue = from[prop];
|
|
151
|
+
if (fromValue !== undefined) {
|
|
152
|
+
to[prop] = fromValue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
if (immediate) {
|
|
157
|
+
action();
|
|
158
|
+
}
|
|
159
|
+
return this.addCallback(from[symbols_1.$refId], spec_1.OPERATION.REPLACE, action);
|
|
160
|
+
}
|
|
161
|
+
triggerChanges(allChanges) {
|
|
162
|
+
this.uniqueRefIds.clear();
|
|
163
|
+
for (let i = 0, l = allChanges.length; i < l; i++) {
|
|
164
|
+
const change = allChanges[i];
|
|
165
|
+
const refId = change.refId;
|
|
166
|
+
const ref = change.ref;
|
|
167
|
+
const $callbacks = this.callbacks[refId];
|
|
168
|
+
if (!$callbacks) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
//
|
|
172
|
+
// trigger onRemove on child structure.
|
|
173
|
+
//
|
|
174
|
+
if ((change.op & spec_1.OPERATION.DELETE) === spec_1.OPERATION.DELETE &&
|
|
175
|
+
change.previousValue instanceof Schema_1.Schema) {
|
|
176
|
+
const childRefId = change.previousValue[symbols_1.$refId];
|
|
177
|
+
const deleteCallbacks = this.callbacks[childRefId]?.[spec_1.OPERATION.DELETE];
|
|
178
|
+
if (deleteCallbacks) {
|
|
179
|
+
for (let j = deleteCallbacks.length - 1; j >= 0; j--) {
|
|
180
|
+
deleteCallbacks[j]();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (ref instanceof Schema_1.Schema) {
|
|
185
|
+
//
|
|
186
|
+
// Handle Schema instance
|
|
187
|
+
//
|
|
188
|
+
if (!this.uniqueRefIds.has(refId)) {
|
|
189
|
+
// trigger onChange
|
|
190
|
+
const replaceCallbacks = $callbacks[spec_1.OPERATION.REPLACE];
|
|
191
|
+
if (replaceCallbacks) {
|
|
192
|
+
for (let j = replaceCallbacks.length - 1; j >= 0; j--) {
|
|
193
|
+
try {
|
|
194
|
+
replaceCallbacks[j]();
|
|
195
|
+
}
|
|
196
|
+
catch (e) {
|
|
197
|
+
console.error(e);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// trigger field callbacks
|
|
203
|
+
const fieldCallbacks = $callbacks[change.field];
|
|
204
|
+
if (fieldCallbacks) {
|
|
205
|
+
for (let j = fieldCallbacks.length - 1; j >= 0; j--) {
|
|
206
|
+
try {
|
|
207
|
+
this.isTriggering = true;
|
|
208
|
+
fieldCallbacks[j](change.value, change.previousValue);
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
console.error(e);
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
this.isTriggering = false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
//
|
|
221
|
+
// Handle collection of items
|
|
222
|
+
//
|
|
223
|
+
const dynamicIndex = change.dynamicIndex ?? change.field;
|
|
224
|
+
if ((change.op & spec_1.OPERATION.DELETE) === spec_1.OPERATION.DELETE) {
|
|
225
|
+
//
|
|
226
|
+
// FIXME: `previousValue` should always be available.
|
|
227
|
+
//
|
|
228
|
+
if (change.previousValue !== undefined) {
|
|
229
|
+
// trigger onRemove (key, value)
|
|
230
|
+
const deleteCallbacks = $callbacks[spec_1.OPERATION.DELETE];
|
|
231
|
+
if (deleteCallbacks) {
|
|
232
|
+
for (let j = deleteCallbacks.length - 1; j >= 0; j--) {
|
|
233
|
+
deleteCallbacks[j](dynamicIndex, change.previousValue);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Handle DELETE_AND_ADD operation
|
|
238
|
+
if ((change.op & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD) {
|
|
239
|
+
const addCallbacks = $callbacks[spec_1.OPERATION.ADD];
|
|
240
|
+
if (addCallbacks) {
|
|
241
|
+
this.isTriggering = true;
|
|
242
|
+
for (let j = addCallbacks.length - 1; j >= 0; j--) {
|
|
243
|
+
addCallbacks[j](dynamicIndex, change.value);
|
|
244
|
+
}
|
|
245
|
+
this.isTriggering = false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else if ((change.op & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD &&
|
|
250
|
+
change.previousValue !== change.value) {
|
|
251
|
+
// trigger onAdd (key, value)
|
|
252
|
+
const addCallbacks = $callbacks[spec_1.OPERATION.ADD];
|
|
253
|
+
if (addCallbacks) {
|
|
254
|
+
this.isTriggering = true;
|
|
255
|
+
for (let j = addCallbacks.length - 1; j >= 0; j--) {
|
|
256
|
+
addCallbacks[j](dynamicIndex, change.value);
|
|
257
|
+
}
|
|
258
|
+
this.isTriggering = false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// trigger onChange (key, value)
|
|
262
|
+
if (change.value !== change.previousValue) {
|
|
263
|
+
const replaceCallbacks = $callbacks[spec_1.OPERATION.REPLACE];
|
|
264
|
+
if (replaceCallbacks) {
|
|
265
|
+
for (let j = replaceCallbacks.length - 1; j >= 0; j--) {
|
|
266
|
+
replaceCallbacks[j](dynamicIndex, change.value);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
this.uniqueRefIds.add(refId);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
exports.StateCallbackStrategy = StateCallbackStrategy;
|
|
276
|
+
/**
|
|
277
|
+
* Factory class for retrieving the callbacks API.
|
|
278
|
+
*/
|
|
279
|
+
exports.Callbacks = {
|
|
280
|
+
/**
|
|
281
|
+
* Get the new callbacks standard API.
|
|
282
|
+
*
|
|
283
|
+
* Usage:
|
|
284
|
+
* ```ts
|
|
285
|
+
* const callbacks = Callbacks.get(roomOrDecoder);
|
|
286
|
+
*
|
|
287
|
+
* // Listen to property changes
|
|
288
|
+
* callbacks.listen("currentTurn", (currentValue, previousValue) => { ... });
|
|
289
|
+
*
|
|
290
|
+
* // Listen to collection additions
|
|
291
|
+
* callbacks.onAdd("entities", (sessionId, entity) => {
|
|
292
|
+
* // Nested property listening
|
|
293
|
+
* callbacks.listen(entity, "hp", (currentHp, previousHp) => { ... });
|
|
294
|
+
* });
|
|
295
|
+
*
|
|
296
|
+
* // Listen to collection removals
|
|
297
|
+
* callbacks.onRemove("entities", (sessionId, entity) => { ... });
|
|
298
|
+
*
|
|
299
|
+
* // Listen to any property change on an instance
|
|
300
|
+
* callbacks.onChange(entity, () => { ... });
|
|
301
|
+
*
|
|
302
|
+
* // Bind properties to another object
|
|
303
|
+
* callbacks.bindTo(player, playerVisual);
|
|
304
|
+
* ```
|
|
305
|
+
*
|
|
306
|
+
* @param roomOrDecoder - Room or Decoder instance to get the callbacks for.
|
|
307
|
+
* @returns the new callbacks standard API.
|
|
308
|
+
*/
|
|
309
|
+
get(roomOrDecoder) {
|
|
310
|
+
if (roomOrDecoder instanceof Decoder_1.Decoder) {
|
|
311
|
+
return new StateCallbackStrategy(roomOrDecoder);
|
|
312
|
+
}
|
|
313
|
+
else if (roomOrDecoder.serializer.decoder) {
|
|
314
|
+
return new StateCallbackStrategy(roomOrDecoder.serializer.decoder);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
throw new Error('Invalid room or decoder');
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
/**
|
|
321
|
+
* Get the legacy callbacks API.
|
|
322
|
+
*
|
|
323
|
+
* We aim to deprecate this API on 1.0, and iterate on improving Callbacks.get() API.
|
|
324
|
+
*
|
|
325
|
+
* @param roomOrDecoder - Room or Decoder instance to get the legacy callbacks for.
|
|
326
|
+
* @returns the legacy callbacks API.
|
|
327
|
+
*/
|
|
328
|
+
getLegacy(roomOrDecoder) {
|
|
329
|
+
if (roomOrDecoder instanceof Decoder_1.Decoder) {
|
|
330
|
+
return (0, getDecoderStateCallbacks_1.getDecoderStateCallbacks)(roomOrDecoder);
|
|
331
|
+
}
|
|
332
|
+
else if (roomOrDecoder.serializer.decoder) {
|
|
333
|
+
return (0, getDecoderStateCallbacks_1.getDecoderStateCallbacks)(roomOrDecoder.serializer.decoder);
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
getRawChanges(decoder, callback) {
|
|
337
|
+
return (0, RawChanges_1.getRawChangesCallback)(decoder, callback);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
//# sourceMappingURL=Callbacks.js.map
|