@colyseus/schema 5.0.11 → 5.0.13

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 (62) 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 +25 -9
  9. package/build/encoder/EncodeDescriptor.d.ts +11 -12
  10. package/build/encoder/StateView.d.ts +26 -2
  11. package/build/encoder/changeTree/inheritedFlags.d.ts +1 -1
  12. package/build/encoder/changeTree/parentChain.d.ts +9 -0
  13. package/build/encoder/streaming.d.ts +7 -0
  14. package/build/index.cjs +449 -233
  15. package/build/index.cjs.map +1 -1
  16. package/build/index.d.ts +1 -1
  17. package/build/index.js +449 -233
  18. package/build/index.mjs +448 -232
  19. package/build/index.mjs.map +1 -1
  20. package/build/types/builder.d.ts +31 -22
  21. package/build/types/custom/ArraySchema.d.ts +17 -0
  22. package/build/types/custom/StreamSchema.d.ts +1 -1
  23. package/build/types/symbols.d.ts +4 -10
  24. package/package.json +1 -1
  25. package/src/Metadata.ts +58 -31
  26. package/src/annotations.ts +56 -32
  27. package/src/codegen/api.ts +2 -1
  28. package/src/codegen/languages/c.ts +21 -3
  29. package/src/codegen/languages/csharp.ts +7 -1
  30. package/src/codegen/languages/dart.ts +274 -0
  31. package/src/codegen/languages/haxe.ts +7 -1
  32. package/src/codegen/languages/lua.ts +16 -4
  33. package/src/codegen/languages/ts.ts +5 -0
  34. package/src/codegen/parser.ts +97 -3
  35. package/src/codegen/types.ts +24 -0
  36. package/src/decoder/Resync.ts +8 -8
  37. package/src/encoder/ChangeRecorder.ts +1 -1
  38. package/src/encoder/ChangeTree.ts +46 -26
  39. package/src/encoder/EncodeDescriptor.ts +17 -38
  40. package/src/encoder/EncodeOperation.ts +3 -1
  41. package/src/encoder/Encoder.ts +97 -21
  42. package/src/encoder/Root.ts +18 -20
  43. package/src/encoder/StateView.ts +102 -12
  44. package/src/encoder/changeTree/inheritedFlags.ts +10 -10
  45. package/src/encoder/changeTree/liveIteration.ts +9 -9
  46. package/src/encoder/changeTree/parentChain.ts +29 -0
  47. package/src/encoder/streaming.ts +8 -0
  48. package/src/encoding/spec.ts +1 -1
  49. package/src/index.ts +2 -2
  50. package/src/types/builder.ts +35 -31
  51. package/src/types/custom/ArraySchema.ts +40 -1
  52. package/src/types/custom/StreamSchema.ts +1 -1
  53. package/src/types/symbols.ts +4 -11
  54. package/src/bench_bloat.ts +0 -173
  55. package/src/bench_churn.ts +0 -121
  56. package/src/bench_decode.ts +0 -221
  57. package/src/bench_decode_mem.ts +0 -165
  58. package/src/bench_encode.ts +0 -108
  59. package/src/bench_init.ts +0 -150
  60. package/src/bench_static.ts +0 -109
  61. package/src/bench_stream.ts +0 -295
  62. package/src/bench_view_cmp.ts +0 -142
@@ -172,11 +172,22 @@ class Enum {
172
172
  this.properties.push(property);
173
173
  }
174
174
  }
175
+ /**
176
+ * Mirror of the runtime's `resolveQuantize()` scale math (wrap spreads 2^bits
177
+ * steps across [min,max); clamp maps the endpoints onto 0 and 2^bits-1).
178
+ */
179
+ function resolveQuantized(q) {
180
+ return {
181
+ range: q.max - q.min,
182
+ span: q.wrap ? 2 ** q.bits : 2 ** q.bits - 1,
183
+ };
184
+ }
175
185
  class Property {
176
186
  index;
177
187
  name;
178
188
  type;
179
189
  childType;
190
+ quantized;
180
191
  deprecated;
181
192
  }
182
193
  /**
@@ -234,6 +245,96 @@ function extractBuilderBase(node) {
234
245
  };
235
246
  }
236
247
  }
248
+ /**
249
+ * Statically evaluate a numeric option expression. Codegen has no runtime, so
250
+ * only constant arithmetic is supported: literals, unary +/-, `Math.PI`-style
251
+ * constants and add/sub/mul/div combinations of those (e.g. `Math.PI * 2`).
252
+ * Returns
253
+ * undefined for anything it cannot resolve (a `const` reference, a call).
254
+ */
255
+ function evalNumericExpression(node) {
256
+ if (ts__namespace.isNumericLiteral(node)) {
257
+ return Number(node.text);
258
+ }
259
+ if (ts__namespace.isParenthesizedExpression(node)) {
260
+ return evalNumericExpression(node.expression);
261
+ }
262
+ if (ts__namespace.isPrefixUnaryExpression(node)) {
263
+ const operand = evalNumericExpression(node.operand);
264
+ if (operand === undefined) {
265
+ return undefined;
266
+ }
267
+ if (node.operator === ts__namespace.SyntaxKind.MinusToken) {
268
+ return -operand;
269
+ }
270
+ if (node.operator === ts__namespace.SyntaxKind.PlusToken) {
271
+ return operand;
272
+ }
273
+ return undefined;
274
+ }
275
+ if (ts__namespace.isPropertyAccessExpression(node) && node.expression.getText() === "Math") {
276
+ const constant = Math[node.name.text];
277
+ return (typeof constant === "number") ? constant : undefined;
278
+ }
279
+ if (ts__namespace.isBinaryExpression(node)) {
280
+ const left = evalNumericExpression(node.left);
281
+ const right = evalNumericExpression(node.right);
282
+ if (left === undefined || right === undefined) {
283
+ return undefined;
284
+ }
285
+ switch (node.operatorToken.kind) {
286
+ case ts__namespace.SyntaxKind.PlusToken: return left + right;
287
+ case ts__namespace.SyntaxKind.MinusToken: return left - right;
288
+ case ts__namespace.SyntaxKind.AsteriskToken: return left * right;
289
+ case ts__namespace.SyntaxKind.SlashToken: return left / right;
290
+ default: return undefined;
291
+ }
292
+ }
293
+ return undefined;
294
+ }
295
+ /**
296
+ * Extract `{ min, max, bits?, mode? }` from a `t.quantized({...})` /
297
+ * `@type({ quantized: {...} })` object literal. Throws on anything codegen
298
+ * cannot statically resolve — silently dropping an option would generate a
299
+ * client that decodes every value of that field wrong.
300
+ */
301
+ function parseQuantizedOptions(node, propertyName) {
302
+ const fail = (reason) => {
303
+ throw new Error(`schema-codegen: cannot statically resolve t.quantized() options of field '${propertyName}' — ${reason}. ` +
304
+ `Use literal numbers or constant Math expressions (e.g. \`Math.PI * 2\`).`);
305
+ };
306
+ if (!node || !ts__namespace.isObjectLiteralExpression(node)) {
307
+ return fail("expected an inline `{ min, max, ... }` object literal");
308
+ }
309
+ const result = {};
310
+ for (const prop of node.properties) {
311
+ if (!ts__namespace.isPropertyAssignment(prop) || !prop.name) {
312
+ continue;
313
+ }
314
+ const key = prop.name.text;
315
+ if (key === "mode") {
316
+ if (!ts__namespace.isStringLiteral(prop.initializer)) {
317
+ return fail("`mode` must be a string literal");
318
+ }
319
+ result.mode = prop.initializer.text;
320
+ }
321
+ else if (key === "min" || key === "max" || key === "bits") {
322
+ const value = evalNumericExpression(prop.initializer);
323
+ if (value === undefined) {
324
+ return fail(`\`${key}\` is not a constant expression`);
325
+ }
326
+ result[key] = value;
327
+ }
328
+ }
329
+ if (typeof result.min !== "number" || typeof result.max !== "number") {
330
+ return fail("`min` and `max` are required");
331
+ }
332
+ const bits = result.bits ?? 16;
333
+ if (bits !== 8 && bits !== 16 && bits !== 32) {
334
+ return fail("`bits` must be 8, 16 or 32");
335
+ }
336
+ return { min: result.min, max: result.max, bits, wrap: result.mode === "wrap" };
337
+ }
237
338
  function defineProperty(property, initializer) {
238
339
  // Builder-style: t.number(), t.array(Item), t.map(Item).view(), etc.
239
340
  if (ts__namespace.isCallExpression(initializer)) {
@@ -251,6 +352,10 @@ function defineProperty(property, initializer) {
251
352
  property.childType = base.firstArg.text ?? base.firstArg.getText();
252
353
  }
253
354
  }
355
+ else if (base.methodName === "quantized") {
356
+ property.type = "quantized";
357
+ property.quantized = parseQuantizedOptions(base.firstArg, property.name);
358
+ }
254
359
  else {
255
360
  property.type = base.methodName;
256
361
  }
@@ -262,8 +367,15 @@ function defineProperty(property, initializer) {
262
367
  property.childType = initializer.text;
263
368
  }
264
369
  else if (initializer.kind == ts__namespace.SyntaxKind.ObjectLiteralExpression) {
265
- property.type = initializer.properties[0].name.text;
266
- property.childType = initializer.properties[0].initializer.text;
370
+ if (initializer.properties[0].name.text === "quantized") {
371
+ // decorator-style: @type({ quantized: { min, max, ... } })
372
+ property.type = "quantized";
373
+ property.quantized = parseQuantizedOptions(initializer.properties[0].initializer, property.name);
374
+ }
375
+ else {
376
+ property.type = initializer.properties[0].name.text;
377
+ property.childType = initializer.properties[0].initializer.text;
378
+ }
267
379
  }
268
380
  else if (initializer.kind == ts__namespace.SyntaxKind.ArrayLiteralExpression) {
269
381
  property.type = "array";
@@ -629,8 +741,8 @@ function getDecorators(node) {
629
741
  return node.modifiers?.filter(ts__namespace.isDecorator);
630
742
  }
631
743
 
632
- const name$8 = "Unity/C#";
633
- const typeMaps$8 = {
744
+ const name$9 = "Unity/C#";
745
+ const typeMaps$9 = {
634
746
  "string": "string",
635
747
  "number": "float",
636
748
  "boolean": "bool",
@@ -645,7 +757,7 @@ const typeMaps$8 = {
645
757
  "float32": "float",
646
758
  "float64": "double",
647
759
  };
648
- const COMMON_IMPORTS$5 = `using Colyseus.Schema;
760
+ const COMMON_IMPORTS$6 = `using Colyseus.Schema;
649
761
  #if UNITY_5_3_OR_NEWER
650
762
  using UnityEngine.Scripting;
651
763
  #endif`;
@@ -660,46 +772,46 @@ const capitalize$1 = (s) => {
660
772
  /**
661
773
  * Generate individual files for each class/interface/enum
662
774
  */
663
- function generate$9(context, options) {
775
+ function generate$a(context, options) {
664
776
  // enrich typeMaps with enums
665
777
  context.enums.forEach((structure) => {
666
- typeMaps$8[structure.name] = structure.name;
778
+ typeMaps$9[structure.name] = structure.name;
667
779
  });
668
780
  return [
669
781
  ...context.classes.map(structure => ({
670
782
  name: `${structure.name}.cs`,
671
- content: generateClass$8(structure, options.namespace)
783
+ content: generateClass$9(structure, options.namespace)
672
784
  })),
673
785
  ...context.interfaces.map(structure => ({
674
786
  name: `${structure.name}.cs`,
675
- content: generateInterface$1(structure, options.namespace),
787
+ content: generateInterface$2(structure, options.namespace),
676
788
  })),
677
789
  ...context.enums.filter(structure => structure.name !== 'OPERATION').map((structure) => ({
678
790
  name: `${structure.name}.cs`,
679
- content: generateEnum$1(structure, options.namespace),
791
+ content: generateEnum$2(structure, options.namespace),
680
792
  })),
681
793
  ];
682
794
  }
683
795
  /**
684
796
  * Generate a single bundled file containing all classes, interfaces, and enums
685
797
  */
686
- function renderBundle$8(context, options) {
798
+ function renderBundle$9(context, options) {
687
799
  const fileName = options.namespace ? `${options.namespace}.cs` : "Schema.cs";
688
800
  const indent = options.namespace ? "\t" : "";
689
801
  // enrich typeMaps with enums
690
802
  context.enums.forEach((structure) => {
691
- typeMaps$8[structure.name] = structure.name;
803
+ typeMaps$9[structure.name] = structure.name;
692
804
  });
693
805
  // Collect all bodies
694
- const classBodies = context.classes.map(klass => generateClassBody$8(klass, indent));
695
- const interfaceBodies = context.interfaces.map(iface => generateInterfaceBody$1(iface, indent));
806
+ const classBodies = context.classes.map(klass => generateClassBody$9(klass, indent));
807
+ const interfaceBodies = context.interfaces.map(iface => generateInterfaceBody$2(iface, indent));
696
808
  const enumBodies = context.enums
697
809
  .filter(structure => structure.name !== 'OPERATION')
698
- .map(e => generateEnumBody$1(e, indent));
810
+ .map(e => generateEnumBody$2(e, indent));
699
811
  const allBodies = [...classBodies, ...interfaceBodies, ...enumBodies].join("\n\n");
700
812
  const content = `${getCommentHeader()}
701
813
 
702
- ${COMMON_IMPORTS$5}
814
+ ${COMMON_IMPORTS$6}
703
815
  ${options.namespace ? `\nnamespace ${options.namespace} {\n` : ""}
704
816
  ${allBodies}
705
817
  ${options.namespace ? "}" : ""}`;
@@ -708,7 +820,7 @@ ${options.namespace ? "}" : ""}`;
708
820
  /**
709
821
  * Generate just the class body (without imports/namespace) for bundling
710
822
  */
711
- function generateClassBody$8(klass, indent = "") {
823
+ function generateClassBody$9(klass, indent = "") {
712
824
  return `${indent}public partial class ${klass.name} : ${klass.extends} {
713
825
  #if UNITY_5_3_OR_NEWER
714
826
  [Preserve]
@@ -720,13 +832,13 @@ ${indent}}`;
720
832
  /**
721
833
  * Generate a complete class file with imports/namespace (for individual file mode)
722
834
  */
723
- function generateClass$8(klass, namespace) {
835
+ function generateClass$9(klass, namespace) {
724
836
  const indent = (namespace) ? "\t" : "";
725
837
  return `${getCommentHeader()}
726
838
 
727
- ${COMMON_IMPORTS$5}
839
+ ${COMMON_IMPORTS$6}
728
840
  ${namespace ? `\nnamespace ${namespace} {` : ""}
729
- ${generateClassBody$8(klass, indent)}
841
+ ${generateClassBody$9(klass, indent)}
730
842
  ${namespace ? "}" : ""}
731
843
  `;
732
844
  }
@@ -745,7 +857,7 @@ function canUseNativeEnum(_enum) {
745
857
  /**
746
858
  * Generate just the enum body (without imports/namespace) for bundling
747
859
  */
748
- function generateEnumBody$1(_enum, indent = "") {
860
+ function generateEnumBody$2(_enum, indent = "") {
749
861
  if (canUseNativeEnum(_enum)) {
750
862
  const members = _enum.properties
751
863
  .map((prop, i) => {
@@ -784,11 +896,11 @@ ${indent}}`;
784
896
  /**
785
897
  * Generate a complete enum file with imports/namespace (for individual file mode)
786
898
  */
787
- function generateEnum$1(_enum, namespace) {
899
+ function generateEnum$2(_enum, namespace) {
788
900
  const indent = namespace ? "\t" : "";
789
901
  return `${getCommentHeader()}
790
902
  ${namespace ? `\nnamespace ${namespace} {` : ""}
791
- ${generateEnumBody$1(_enum, indent)}
903
+ ${generateEnumBody$2(_enum, indent)}
792
904
  ${namespace ? "}" : ""}`;
793
905
  }
794
906
  function generateProperty$4(prop, indent = "") {
@@ -796,7 +908,13 @@ function generateProperty$4(prop, indent = "") {
796
908
  let property = "public";
797
909
  let langType;
798
910
  let initializer = "";
799
- if (prop.childType) {
911
+ if (prop.quantized) {
912
+ const q = prop.quantized;
913
+ typeArgs += `, QuantizeMin = ${q.min}, QuantizeMax = ${q.max}, QuantizeBits = ${q.bits}, QuantizeWrap = ${q.wrap}`;
914
+ langType = "double";
915
+ initializer = "default(double)";
916
+ }
917
+ else if (prop.childType) {
800
918
  const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
801
919
  langType = getType(prop);
802
920
  typeArgs += `, typeof(${langType})`;
@@ -817,7 +935,7 @@ function generateProperty$4(prop, indent = "") {
817
935
  /**
818
936
  * Generate just the interface body (without imports/namespace) for bundling
819
937
  */
820
- function generateInterfaceBody$1(struct, indent = "") {
938
+ function generateInterfaceBody$2(struct, indent = "") {
821
939
  return `${indent}public class ${struct.name} {
822
940
  ${struct.properties.map(prop => `\t${indent}public ${getType(prop)} ${prop.name};`).join("\n")}
823
941
  ${indent}}`;
@@ -825,18 +943,18 @@ ${indent}}`;
825
943
  /**
826
944
  * Generate a complete interface file with imports/namespace (for individual file mode)
827
945
  */
828
- function generateInterface$1(struct, namespace) {
946
+ function generateInterface$2(struct, namespace) {
829
947
  const indent = (namespace) ? "\t" : "";
830
948
  return `${getCommentHeader()}
831
949
 
832
950
  using Colyseus.Schema;
833
951
  ${namespace ? `\nnamespace ${namespace} {` : ""}
834
- ${generateInterfaceBody$1(struct, indent)}
952
+ ${generateInterfaceBody$2(struct, indent)}
835
953
  ${namespace ? "}" : ""}
836
954
  `;
837
955
  }
838
956
  function getChildType(prop) {
839
- return typeMaps$8[prop.childType];
957
+ return typeMaps$9[prop.childType];
840
958
  }
841
959
  function getType(prop) {
842
960
  if (prop.childType) {
@@ -857,20 +975,20 @@ function getType(prop) {
857
975
  }
858
976
  else {
859
977
  return (prop.type === "array")
860
- ? `${typeMaps$8[prop.childType] || prop.childType}[]`
861
- : typeMaps$8[prop.type];
978
+ ? `${typeMaps$9[prop.childType] || prop.childType}[]`
979
+ : typeMaps$9[prop.type];
862
980
  }
863
981
  }
864
982
 
865
983
  var csharp = /*#__PURE__*/Object.freeze({
866
984
  __proto__: null,
867
- generate: generate$9,
868
- name: name$8,
869
- renderBundle: renderBundle$8
985
+ generate: generate$a,
986
+ name: name$9,
987
+ renderBundle: renderBundle$9
870
988
  });
871
989
 
872
- const name$7 = "C++";
873
- const typeMaps$7 = {
990
+ const name$8 = "C++";
991
+ const typeMaps$8 = {
874
992
  "string": "string",
875
993
  "number": "varint_t",
876
994
  "boolean": "bool",
@@ -913,23 +1031,23 @@ const capitalize = (s) => {
913
1031
  return '';
914
1032
  return s.charAt(0).toUpperCase() + s.slice(1);
915
1033
  };
916
- const distinct$5 = (value, index, self) => self.indexOf(value) === index;
1034
+ const distinct$6 = (value, index, self) => self.indexOf(value) === index;
917
1035
  /**
918
1036
  * Generate individual files for each class
919
1037
  */
920
- function generate$8(context, options) {
1038
+ function generate$9(context, options) {
921
1039
  return context.classes.map(klass => ({
922
1040
  name: klass.name + ".hpp",
923
- content: generateClass$7(klass, options.namespace, context.classes)
1041
+ content: generateClass$8(klass, options.namespace, context.classes)
924
1042
  }));
925
1043
  }
926
1044
  /**
927
1045
  * Generate a single bundled header file containing all classes
928
1046
  */
929
- function renderBundle$7(context, options) {
1047
+ function renderBundle$8(context, options) {
930
1048
  const fileName = options.namespace ? `${options.namespace}.hpp` : "schema.hpp";
931
1049
  const guardName = `__SCHEMA_CODEGEN_${(options.namespace || "SCHEMA").toUpperCase()}_H__`;
932
- const classBodies = context.classes.map(klass => generateClassBody$7(klass, context.classes, options.namespace));
1050
+ const classBodies = context.classes.map(klass => generateClassBody$8(klass, context.classes, options.namespace));
933
1051
  const content = `${getCommentHeader()}
934
1052
  #ifndef ${guardName}
935
1053
  #define ${guardName} 1
@@ -947,7 +1065,7 @@ ${options.namespace ? "}" : ""}
947
1065
  /**
948
1066
  * Generate just the class body (without includes/guards) for bundling
949
1067
  */
950
- function generateClassBody$7(klass, allClasses, namespace) {
1068
+ function generateClassBody$8(klass, allClasses, namespace) {
951
1069
  const propertiesPerType = {};
952
1070
  const allRefs = [];
953
1071
  klass.properties.forEach(property => {
@@ -964,7 +1082,7 @@ function generateClassBody$7(klass, allClasses, namespace) {
964
1082
  const allProperties = getAllProperties$1(klass, allClasses);
965
1083
  const createInstanceMethod = (allRefs.length === 0) ? "" :
966
1084
  `\tinline Schema* createInstance(std::type_index type) {
967
- \t\t${generateFieldIfElseChain(allRefs, (property) => `type == typeid(${property.childType})`, (property) => `return new ${property.childType}();`, (property) => typeMaps$7[property.childType] === undefined)}
1085
+ \t\t${generateFieldIfElseChain(allRefs, (property) => `type == typeid(${property.childType})`, (property) => `return new ${property.childType}();`, (property) => typeMaps$8[property.childType] === undefined)}
968
1086
  \t\treturn ${klass.extends}::createInstance(type);
969
1087
  \t}`;
970
1088
  return `class ${klass.name} : public ${klass.extends} {
@@ -992,7 +1110,7 @@ ${createInstanceMethod}
992
1110
  /**
993
1111
  * Generate a complete class file with includes/guards (for individual file mode)
994
1112
  */
995
- function generateClass$7(klass, namespace, allClasses) {
1113
+ function generateClass$8(klass, namespace, allClasses) {
996
1114
  const allRefs = [];
997
1115
  klass.properties.forEach(property => {
998
1116
  let type = property.type;
@@ -1002,10 +1120,10 @@ function generateClass$7(klass, namespace, allClasses) {
1002
1120
  }
1003
1121
  });
1004
1122
  const localIncludes = allRefs.
1005
- filter(ref => ref.childType && typeMaps$7[ref.childType] === undefined).
1123
+ filter(ref => ref.childType && typeMaps$8[ref.childType] === undefined).
1006
1124
  map(ref => ref.childType).
1007
1125
  concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
1008
- filter(distinct$5).
1126
+ filter(distinct$6).
1009
1127
  map(childType => `#include "${childType}.hpp"`).
1010
1128
  join("\n");
1011
1129
  return `${getCommentHeader()}
@@ -1016,7 +1134,7 @@ ${COMMON_INCLUDES$1}
1016
1134
  ${localIncludes}
1017
1135
 
1018
1136
  ${namespace ? `namespace ${namespace} {` : ""}
1019
- ${generateClassBody$7(klass, allClasses)}
1137
+ ${generateClassBody$8(klass, allClasses)}
1020
1138
  ${namespace ? "}" : ""}
1021
1139
 
1022
1140
  #endif
@@ -1036,26 +1154,26 @@ function generateProperty$3(prop) {
1036
1154
  else if (prop.type === "array") {
1037
1155
  langType = (isUpcaseFirst)
1038
1156
  ? `ArraySchema<${prop.childType}*>`
1039
- : `ArraySchema<${typeMaps$7[prop.childType]}>`;
1157
+ : `ArraySchema<${typeMaps$8[prop.childType]}>`;
1040
1158
  initializer = `new ${langType}()`;
1041
1159
  }
1042
1160
  else if (prop.type === "map") {
1043
1161
  langType = (isUpcaseFirst)
1044
1162
  ? `MapSchema<${prop.childType}*>`
1045
- : `MapSchema<${typeMaps$7[prop.childType]}>`;
1163
+ : `MapSchema<${typeMaps$8[prop.childType]}>`;
1046
1164
  initializer = `new ${langType}()`;
1047
1165
  }
1048
1166
  isPropPointer = "*";
1049
1167
  }
1050
1168
  else {
1051
- langType = typeMaps$7[prop.type];
1169
+ langType = typeMaps$8[prop.type];
1052
1170
  initializer = typeInitializer$2[prop.type];
1053
1171
  }
1054
1172
  property += ` ${langType} ${isPropPointer}${prop.name}`;
1055
1173
  return `\t${property} = ${initializer};`;
1056
1174
  }
1057
1175
  function generateGettersAndSetters(klass, type, properties) {
1058
- let langType = typeMaps$7[type];
1176
+ let langType = typeMaps$8[type];
1059
1177
  let typeCast = "";
1060
1178
  const getMethodName = `get${capitalize(type)}`;
1061
1179
  const setMethodName = `set${capitalize(type)}`;
@@ -1079,7 +1197,7 @@ function generateGettersAndSetters(klass, type, properties) {
1079
1197
  \tinline void ${setMethodName}(const string &field, ${langType} value)
1080
1198
  \t{
1081
1199
  \t\t${generateFieldIfElseChain(properties, (property) => `field == "${property.name}"`, (property) => {
1082
- const isSchemaType = (typeMaps$7[property.childType] === undefined);
1200
+ const isSchemaType = (typeMaps$8[property.childType] === undefined);
1083
1201
  if (type === "ref") {
1084
1202
  langType = `${property.childType}*`;
1085
1203
  typeCast = (isSchemaType)
@@ -1089,12 +1207,12 @@ function generateGettersAndSetters(klass, type, properties) {
1089
1207
  else if (type === "array") {
1090
1208
  typeCast = (isSchemaType)
1091
1209
  ? `(ArraySchema<${property.childType}*> *)`
1092
- : `(ArraySchema<${typeMaps$7[property.childType]}> *)`;
1210
+ : `(ArraySchema<${typeMaps$8[property.childType]}> *)`;
1093
1211
  }
1094
1212
  else if (type === "map") {
1095
1213
  typeCast = (isSchemaType)
1096
1214
  ? `(MapSchema<${property.childType}*> *)`
1097
- : `(MapSchema<${typeMaps$7[property.childType]}> *)`;
1215
+ : `(MapSchema<${typeMaps$8[property.childType]}> *)`;
1098
1216
  }
1099
1217
  return `this->${property.name} = ${typeCast}value;\n\t\t\treturn;`;
1100
1218
  })}
@@ -1133,7 +1251,7 @@ function generateAllTypes(properties) {
1133
1251
  }
1134
1252
  function generateAllChildSchemaTypes(properties) {
1135
1253
  return `{${properties.map((property, i) => {
1136
- if (property.childType && typeMaps$7[property.childType] === undefined) {
1254
+ if (property.childType && typeMaps$8[property.childType] === undefined) {
1137
1255
  return `{${i}, typeid(${property.childType})}`;
1138
1256
  }
1139
1257
  else {
@@ -1143,7 +1261,7 @@ function generateAllChildSchemaTypes(properties) {
1143
1261
  }
1144
1262
  function generateAllChildPrimitiveTypes(properties) {
1145
1263
  return `{${properties.map((property, i) => {
1146
- if (typeMaps$7[property.childType] !== undefined) {
1264
+ if (typeMaps$8[property.childType] !== undefined) {
1147
1265
  return `{${i}, "${property.childType}"}`;
1148
1266
  }
1149
1267
  else {
@@ -1171,13 +1289,13 @@ function getAllProperties$1(klass, allClasses) {
1171
1289
 
1172
1290
  var cpp = /*#__PURE__*/Object.freeze({
1173
1291
  __proto__: null,
1174
- generate: generate$8,
1175
- name: name$7,
1176
- renderBundle: renderBundle$7
1292
+ generate: generate$9,
1293
+ name: name$8,
1294
+ renderBundle: renderBundle$8
1177
1295
  });
1178
1296
 
1179
- const name$6 = "Haxe";
1180
- const typeMaps$6 = {
1297
+ const name$7 = "Haxe";
1298
+ const typeMaps$7 = {
1181
1299
  "string": "String",
1182
1300
  "number": "Dynamic",
1183
1301
  "boolean": "Bool",
@@ -1207,27 +1325,27 @@ const typeInitializer$1 = {
1207
1325
  "float32": "0",
1208
1326
  "float64": "0",
1209
1327
  };
1210
- const COMMON_IMPORTS$4 = `import io.colyseus.serializer.schema.Schema;
1328
+ const COMMON_IMPORTS$5 = `import io.colyseus.serializer.schema.Schema;
1211
1329
  import io.colyseus.serializer.schema.types.*;`;
1212
1330
  /**
1213
1331
  * Generate individual files for each class
1214
1332
  */
1215
- function generate$7(context, options) {
1333
+ function generate$8(context, options) {
1216
1334
  return context.classes.map(klass => ({
1217
1335
  name: klass.name + ".hx",
1218
- content: generateClass$6(klass, options.namespace, context.classes)
1336
+ content: generateClass$7(klass, options.namespace, context.classes)
1219
1337
  }));
1220
1338
  }
1221
1339
  /**
1222
1340
  * Generate a single bundled file containing all classes
1223
1341
  */
1224
- function renderBundle$6(context, options) {
1342
+ function renderBundle$7(context, options) {
1225
1343
  const fileName = options.namespace ? `${options.namespace}.hx` : "Schema.hx";
1226
- const classBodies = context.classes.map(klass => generateClassBody$6(klass));
1344
+ const classBodies = context.classes.map(klass => generateClassBody$7(klass));
1227
1345
  const content = `${getCommentHeader()}
1228
1346
 
1229
1347
  ${options.namespace ? `package ${options.namespace};` : ""}
1230
- ${COMMON_IMPORTS$4}
1348
+ ${COMMON_IMPORTS$5}
1231
1349
 
1232
1350
  ${classBodies.join("\n\n")}
1233
1351
  `;
@@ -1236,7 +1354,7 @@ ${classBodies.join("\n\n")}
1236
1354
  /**
1237
1355
  * Generate just the class body (without package/imports) for bundling
1238
1356
  */
1239
- function generateClassBody$6(klass) {
1357
+ function generateClassBody$7(klass) {
1240
1358
  return `class ${klass.name} extends ${klass.extends} {
1241
1359
  ${klass.properties.map(prop => generateProperty$2(prop)).join("\n")}
1242
1360
  }`;
@@ -1244,20 +1362,26 @@ ${klass.properties.map(prop => generateProperty$2(prop)).join("\n")}
1244
1362
  /**
1245
1363
  * Generate a complete class file with package/imports (for individual file mode)
1246
1364
  */
1247
- function generateClass$6(klass, namespace, allClasses) {
1365
+ function generateClass$7(klass, namespace, allClasses) {
1248
1366
  return `${getCommentHeader()}
1249
1367
 
1250
1368
  ${namespace ? `package ${namespace};` : ""}
1251
- ${COMMON_IMPORTS$4}
1369
+ ${COMMON_IMPORTS$5}
1252
1370
 
1253
- ${generateClassBody$6(klass)}
1371
+ ${generateClassBody$7(klass)}
1254
1372
  `;
1255
1373
  }
1256
1374
  function generateProperty$2(prop) {
1257
1375
  let langType;
1258
1376
  let initializer = "";
1259
1377
  let typeArgs = `"${prop.type}"`;
1260
- if (prop.childType) {
1378
+ if (prop.quantized) {
1379
+ const q = prop.quantized;
1380
+ typeArgs += `, {min: ${q.min}, max: ${q.max}, bits: ${q.bits}, mode: ${q.wrap ? 1 : 0}}`;
1381
+ langType = "Float";
1382
+ initializer = "0";
1383
+ }
1384
+ else if (prop.childType) {
1261
1385
  const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
1262
1386
  if (isUpcaseFirst) {
1263
1387
  typeArgs += `, ${prop.childType}`;
@@ -1272,18 +1396,18 @@ function generateProperty$2(prop) {
1272
1396
  else if (prop.type === "array") {
1273
1397
  langType = (isUpcaseFirst)
1274
1398
  ? `ArraySchema<${prop.childType}>`
1275
- : `ArraySchema<${typeMaps$6[prop.childType]}>`;
1399
+ : `ArraySchema<${typeMaps$7[prop.childType]}>`;
1276
1400
  initializer = `new ${langType}()`;
1277
1401
  }
1278
1402
  else if (prop.type === "map") {
1279
1403
  langType = (isUpcaseFirst)
1280
1404
  ? `MapSchema<${prop.childType}>`
1281
- : `MapSchema<${typeMaps$6[prop.childType]}>`;
1405
+ : `MapSchema<${typeMaps$7[prop.childType]}>`;
1282
1406
  initializer = `new ${langType}()`;
1283
1407
  }
1284
1408
  }
1285
1409
  else {
1286
- langType = typeMaps$6[prop.type];
1410
+ langType = typeMaps$7[prop.type];
1287
1411
  initializer = typeInitializer$1[prop.type];
1288
1412
  }
1289
1413
  // TODO: remove initializer. The callbacks at the Haxe decoder side have a
@@ -1294,13 +1418,13 @@ function generateProperty$2(prop) {
1294
1418
 
1295
1419
  var haxe = /*#__PURE__*/Object.freeze({
1296
1420
  __proto__: null,
1297
- generate: generate$7,
1298
- name: name$6,
1299
- renderBundle: renderBundle$6
1421
+ generate: generate$8,
1422
+ name: name$7,
1423
+ renderBundle: renderBundle$7
1300
1424
  });
1301
1425
 
1302
- const name$5 = "TypeScript";
1303
- const typeMaps$5 = {
1426
+ const name$6 = "TypeScript";
1427
+ const typeMaps$6 = {
1304
1428
  "string": "string",
1305
1429
  "number": "number",
1306
1430
  "boolean": "boolean",
@@ -1315,35 +1439,35 @@ const typeMaps$5 = {
1315
1439
  "float32": "number",
1316
1440
  "float64": "number",
1317
1441
  };
1318
- const COMMON_IMPORTS$3 = `import { Schema, type, ArraySchema, MapSchema, SetSchema, DataChange } from '@colyseus/schema';`;
1319
- const distinct$4 = (value, index, self) => self.indexOf(value) === index;
1442
+ const COMMON_IMPORTS$4 = `import { Schema, type, ArraySchema, MapSchema, SetSchema, DataChange } from '@colyseus/schema';`;
1443
+ const distinct$5 = (value, index, self) => self.indexOf(value) === index;
1320
1444
  /**
1321
1445
  * Generate individual files for each class/interface
1322
1446
  */
1323
- function generate$6(context, options) {
1447
+ function generate$7(context, options) {
1324
1448
  return [
1325
1449
  ...context.classes.map(structure => ({
1326
1450
  name: structure.name + ".ts",
1327
- content: generateClass$5(structure, options.namespace, context.classes)
1451
+ content: generateClass$6(structure, options.namespace, context.classes)
1328
1452
  })),
1329
1453
  ...context.interfaces.map(structure => ({
1330
1454
  name: structure.name + ".ts",
1331
- content: generateInterface(structure, options.namespace, context.classes),
1455
+ content: generateInterface$1(structure, options.namespace, context.classes),
1332
1456
  }))
1333
1457
  ];
1334
1458
  }
1335
1459
  /**
1336
1460
  * Generate a single bundled file containing all classes and interfaces
1337
1461
  */
1338
- function renderBundle$5(context, options) {
1462
+ function renderBundle$6(context, options) {
1339
1463
  const fileName = options.namespace ? `${options.namespace}.ts` : "schema.ts";
1340
1464
  // Collect all class bodies
1341
- const classBodies = context.classes.map(klass => generateClassBody$5(klass));
1465
+ const classBodies = context.classes.map(klass => generateClassBody$6(klass));
1342
1466
  // Collect all interface bodies
1343
- const interfaceBodies = context.interfaces.map(iface => generateInterfaceBody(iface));
1467
+ const interfaceBodies = context.interfaces.map(iface => generateInterfaceBody$1(iface));
1344
1468
  const content = `${getCommentHeader()}
1345
1469
 
1346
- ${COMMON_IMPORTS$3}
1470
+ ${COMMON_IMPORTS$4}
1347
1471
 
1348
1472
  ${classBodies.join("\n\n")}
1349
1473
  ${interfaceBodies.length > 0 ? "\n" + interfaceBodies.join("\n\n") : ""}`;
@@ -1352,7 +1476,7 @@ ${interfaceBodies.length > 0 ? "\n" + interfaceBodies.join("\n\n") : ""}`;
1352
1476
  /**
1353
1477
  * Generate just the class body (without imports) for bundling
1354
1478
  */
1355
- function generateClassBody$5(klass) {
1479
+ function generateClassBody$6(klass) {
1356
1480
  return `export class ${klass.name} extends ${klass.extends} {
1357
1481
  ${klass.properties.map(prop => ` ${generateProperty$1(prop)}`).join("\n")}
1358
1482
  }`;
@@ -1360,7 +1484,7 @@ ${klass.properties.map(prop => ` ${generateProperty$1(prop)}`).join("\n")}
1360
1484
  /**
1361
1485
  * Generate just the interface body (without imports) for bundling
1362
1486
  */
1363
- function generateInterfaceBody(iface) {
1487
+ function generateInterfaceBody$1(iface) {
1364
1488
  return `export interface ${iface.name} {
1365
1489
  ${iface.properties.map(prop => ` ${prop.name}: ${prop.type};`).join("\n")}
1366
1490
  }`;
@@ -1368,7 +1492,7 @@ ${iface.properties.map(prop => ` ${prop.name}: ${prop.type};`).join("\n")}
1368
1492
  /**
1369
1493
  * Generate a complete class file with imports (for individual file mode)
1370
1494
  */
1371
- function generateClass$5(klass, namespace, allClasses) {
1495
+ function generateClass$6(klass, namespace, allClasses) {
1372
1496
  const allRefs = [];
1373
1497
  klass.properties.forEach(property => {
1374
1498
  let type = property.type;
@@ -1378,18 +1502,18 @@ function generateClass$5(klass, namespace, allClasses) {
1378
1502
  }
1379
1503
  });
1380
1504
  const localImports = allRefs.
1381
- filter(ref => ref.childType && typeMaps$5[ref.childType] === undefined).
1505
+ filter(ref => ref.childType && typeMaps$6[ref.childType] === undefined).
1382
1506
  map(ref => ref.childType).
1383
1507
  concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
1384
- filter(distinct$4).
1508
+ filter(distinct$5).
1385
1509
  map(childType => `import { ${childType} } from './${childType}'`).
1386
1510
  join("\n");
1387
1511
  return `${getCommentHeader()}
1388
1512
 
1389
- ${COMMON_IMPORTS$3}
1513
+ ${COMMON_IMPORTS$4}
1390
1514
  ${localImports}
1391
1515
 
1392
- ${generateClassBody$5(klass)}
1516
+ ${generateClassBody$6(klass)}
1393
1517
  `;
1394
1518
  }
1395
1519
  function generateProperty$1(prop) {
@@ -1412,7 +1536,7 @@ function generateProperty$1(prop) {
1412
1536
  else if (prop.type === "array") {
1413
1537
  langType = (isUpcaseFirst)
1414
1538
  ? `ArraySchema<${prop.childType}>`
1415
- : `ArraySchema<${typeMaps$5[prop.childType]}>`;
1539
+ : `ArraySchema<${typeMaps$6[prop.childType]}>`;
1416
1540
  initializer = `new ${langType}()`;
1417
1541
  typeArgs = (isUpcaseFirst)
1418
1542
  ? `[ ${prop.childType} ]`
@@ -1421,7 +1545,7 @@ function generateProperty$1(prop) {
1421
1545
  else if (prop.type === "map") {
1422
1546
  langType = (isUpcaseFirst)
1423
1547
  ? `MapSchema<${prop.childType}>`
1424
- : `MapSchema<${typeMaps$5[prop.childType]}>`;
1548
+ : `MapSchema<${typeMaps$6[prop.childType]}>`;
1425
1549
  initializer = `new ${langType}()`;
1426
1550
  typeArgs = (isUpcaseFirst)
1427
1551
  ? `{ map: ${prop.childType} }`
@@ -1430,15 +1554,20 @@ function generateProperty$1(prop) {
1430
1554
  else if (prop.type === "set") {
1431
1555
  langType = (isUpcaseFirst)
1432
1556
  ? `SetSchema<${prop.childType}>`
1433
- : `SetSchema<${typeMaps$5[prop.childType]}>`;
1557
+ : `SetSchema<${typeMaps$6[prop.childType]}>`;
1434
1558
  initializer = `new ${langType}()`;
1435
1559
  typeArgs = (isUpcaseFirst)
1436
1560
  ? `{ set: ${prop.childType} }`
1437
1561
  : `{ set: "${prop.childType}" }`;
1438
1562
  }
1439
1563
  }
1564
+ else if (prop.quantized) {
1565
+ const q = prop.quantized;
1566
+ langType = "number";
1567
+ typeArgs = `{ quantized: { min: ${q.min}, max: ${q.max}, bits: ${q.bits}${q.wrap ? `, mode: "wrap"` : ""} } }`;
1568
+ }
1440
1569
  else {
1441
- langType = typeMaps$5[prop.type];
1570
+ langType = typeMaps$6[prop.type];
1442
1571
  typeArgs = `"${prop.type}"`;
1443
1572
  }
1444
1573
  // TS1263: "Declarations with initializers cannot also have definite assignment assertions"
@@ -1448,22 +1577,22 @@ function generateProperty$1(prop) {
1448
1577
  /**
1449
1578
  * Generate a complete interface file with header (for individual file mode)
1450
1579
  */
1451
- function generateInterface(structure, namespace, allClasses) {
1580
+ function generateInterface$1(structure, namespace, allClasses) {
1452
1581
  return `${getCommentHeader()}
1453
1582
 
1454
- ${generateInterfaceBody(structure)}
1583
+ ${generateInterfaceBody$1(structure)}
1455
1584
  `;
1456
1585
  }
1457
1586
 
1458
1587
  var ts = /*#__PURE__*/Object.freeze({
1459
1588
  __proto__: null,
1460
- generate: generate$6,
1461
- name: name$5,
1462
- renderBundle: renderBundle$5
1589
+ generate: generate$7,
1590
+ name: name$6,
1591
+ renderBundle: renderBundle$6
1463
1592
  });
1464
1593
 
1465
- const name$4 = "JavaScript";
1466
- const typeMaps$4 = {
1594
+ const name$5 = "JavaScript";
1595
+ const typeMaps$5 = {
1467
1596
  "string": "string",
1468
1597
  "number": "number",
1469
1598
  "boolean": "boolean",
@@ -1478,29 +1607,29 @@ const typeMaps$4 = {
1478
1607
  "float32": "number",
1479
1608
  "float64": "number",
1480
1609
  };
1481
- const COMMON_IMPORTS$2 = `const schema = require("@colyseus/schema");
1610
+ const COMMON_IMPORTS$3 = `const schema = require("@colyseus/schema");
1482
1611
  const Schema = schema.Schema;
1483
1612
  const type = schema.type;`;
1484
- const distinct$3 = (value, index, self) => self.indexOf(value) === index;
1613
+ const distinct$4 = (value, index, self) => self.indexOf(value) === index;
1485
1614
  /**
1486
1615
  * Generate individual files for each class
1487
1616
  */
1488
- function generate$5(context, options) {
1617
+ function generate$6(context, options) {
1489
1618
  return context.classes.map(klass => ({
1490
1619
  name: klass.name + ".js",
1491
- content: generateClass$4(klass, options.namespace, context.classes)
1620
+ content: generateClass$5(klass, options.namespace, context.classes)
1492
1621
  }));
1493
1622
  }
1494
1623
  /**
1495
1624
  * Generate a single bundled file containing all classes
1496
1625
  */
1497
- function renderBundle$4(context, options) {
1626
+ function renderBundle$5(context, options) {
1498
1627
  const fileName = options.namespace ? `${options.namespace}.js` : "schema.js";
1499
- const classBodies = context.classes.map(klass => generateClassBody$4(klass));
1628
+ const classBodies = context.classes.map(klass => generateClassBody$5(klass));
1500
1629
  const classExports = context.classes.map(klass => ` ${klass.name},`).join("\n");
1501
1630
  const content = `${getCommentHeader()}
1502
1631
 
1503
- ${COMMON_IMPORTS$2}
1632
+ ${COMMON_IMPORTS$3}
1504
1633
 
1505
1634
  ${classBodies.join("\n\n")}
1506
1635
 
@@ -1513,7 +1642,7 @@ ${classExports}
1513
1642
  /**
1514
1643
  * Generate just the class body (without imports) for bundling
1515
1644
  */
1516
- function generateClassBody$4(klass) {
1645
+ function generateClassBody$5(klass) {
1517
1646
  return `class ${klass.name} extends ${klass.extends} {
1518
1647
  constructor () {
1519
1648
  super();
@@ -1527,7 +1656,7 @@ ${klass.properties.map(prop => generatePropertyDeclaration$1(klass.name, prop)).
1527
1656
  /**
1528
1657
  * Generate a complete class file with imports (for individual file mode)
1529
1658
  */
1530
- function generateClass$4(klass, namespace, allClasses) {
1659
+ function generateClass$5(klass, namespace, allClasses) {
1531
1660
  const allRefs = [];
1532
1661
  klass.properties.forEach(property => {
1533
1662
  let type = property.type;
@@ -1537,18 +1666,18 @@ function generateClass$4(klass, namespace, allClasses) {
1537
1666
  }
1538
1667
  });
1539
1668
  const localImports = allRefs.
1540
- filter(ref => ref.childType && typeMaps$4[ref.childType] === undefined).
1669
+ filter(ref => ref.childType && typeMaps$5[ref.childType] === undefined).
1541
1670
  map(ref => ref.childType).
1542
1671
  concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
1543
- filter(distinct$3).
1672
+ filter(distinct$4).
1544
1673
  map(childType => `const ${childType} = require("./${childType}");`).
1545
1674
  join("\n");
1546
1675
  return `${getCommentHeader()}
1547
1676
 
1548
- ${COMMON_IMPORTS$2}
1677
+ ${COMMON_IMPORTS$3}
1549
1678
  ${localImports}
1550
1679
 
1551
- ${generateClassBody$4(klass)}
1680
+ ${generateClassBody$5(klass)}
1552
1681
 
1553
1682
  export default ${klass.name};
1554
1683
  `;
@@ -1598,13 +1727,13 @@ function generatePropertyInitializer(prop) {
1598
1727
 
1599
1728
  var js = /*#__PURE__*/Object.freeze({
1600
1729
  __proto__: null,
1601
- generate: generate$5,
1602
- name: name$4,
1603
- renderBundle: renderBundle$4
1730
+ generate: generate$6,
1731
+ name: name$5,
1732
+ renderBundle: renderBundle$5
1604
1733
  });
1605
1734
 
1606
- const name$3 = "Java";
1607
- const typeMaps$3 = {
1735
+ const name$4 = "Java";
1736
+ const typeMaps$4 = {
1608
1737
  "string": "String",
1609
1738
  "number": "float",
1610
1739
  "boolean": "boolean",
@@ -1634,7 +1763,7 @@ const typeInitializer = {
1634
1763
  "float32": "0",
1635
1764
  "float64": "0",
1636
1765
  };
1637
- const COMMON_IMPORTS$1 = `import io.colyseus.serializer.schema.Schema;
1766
+ const COMMON_IMPORTS$2 = `import io.colyseus.serializer.schema.Schema;
1638
1767
  import io.colyseus.serializer.schema.annotations.SchemaClass;
1639
1768
  import io.colyseus.serializer.schema.annotations.SchemaField;`;
1640
1769
  /**
@@ -1643,10 +1772,10 @@ import io.colyseus.serializer.schema.annotations.SchemaField;`;
1643
1772
  /**
1644
1773
  * Generate individual files for each class
1645
1774
  */
1646
- function generate$4(context, options) {
1775
+ function generate$5(context, options) {
1647
1776
  return context.classes.map(klass => ({
1648
1777
  name: klass.name + ".java",
1649
- content: generateClass$3(klass, options.namespace)
1778
+ content: generateClass$4(klass, options.namespace)
1650
1779
  }));
1651
1780
  }
1652
1781
  /**
@@ -1654,13 +1783,13 @@ function generate$4(context, options) {
1654
1783
  * Note: Java typically requires one public class per file, so bundled mode
1655
1784
  * generates all classes in a single file with package-private visibility
1656
1785
  */
1657
- function renderBundle$3(context, options) {
1786
+ function renderBundle$4(context, options) {
1658
1787
  const fileName = options.namespace ? `Schema.java` : "Schema.java";
1659
- const classBodies = context.classes.map(klass => generateClassBody$3(klass));
1788
+ const classBodies = context.classes.map(klass => generateClassBody$4(klass));
1660
1789
  const content = `${getCommentHeader()}
1661
1790
  ${options.namespace ? `\npackage ${options.namespace};` : ""}
1662
1791
 
1663
- ${COMMON_IMPORTS$1}
1792
+ ${COMMON_IMPORTS$2}
1664
1793
 
1665
1794
  ${classBodies.join("\n\n")}
1666
1795
  `;
@@ -1669,7 +1798,7 @@ ${classBodies.join("\n\n")}
1669
1798
  /**
1670
1799
  * Generate just the class body (without package/imports) for bundling
1671
1800
  */
1672
- function generateClassBody$3(klass) {
1801
+ function generateClassBody$4(klass) {
1673
1802
  return `@SchemaClass
1674
1803
  class ${klass.name} extends ${klass.extends} {
1675
1804
  ${klass.properties.map(prop => generateProperty(prop, "")).join("\n\n")}
@@ -1678,12 +1807,12 @@ ${klass.properties.map(prop => generateProperty(prop, "")).join("\n\n")}
1678
1807
  /**
1679
1808
  * Generate a complete class file with package/imports (for individual file mode)
1680
1809
  */
1681
- function generateClass$3(klass, namespace) {
1810
+ function generateClass$4(klass, namespace) {
1682
1811
  const indent = (namespace) ? "\t" : "";
1683
1812
  return `${getCommentHeader()}
1684
1813
  ${namespace ? `\npackage ${namespace};` : ""}
1685
1814
 
1686
- ${COMMON_IMPORTS$1}
1815
+ ${COMMON_IMPORTS$2}
1687
1816
 
1688
1817
  @SchemaClass
1689
1818
  ${indent}public class ${klass.name} extends ${klass.extends} {
@@ -1706,7 +1835,7 @@ function generateProperty(prop, indent = "") {
1706
1835
  if (prop.type === "ref") {
1707
1836
  langType = (isUpcaseFirst)
1708
1837
  ? prop.childType
1709
- : typeMaps$3[prop.childType];
1838
+ : typeMaps$4[prop.childType];
1710
1839
  initializer = `new ${langType}${(prop.type !== "ref" && isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
1711
1840
  }
1712
1841
  else if (prop.type === "array") {
@@ -1728,7 +1857,7 @@ function generateProperty(prop, indent = "") {
1728
1857
  }
1729
1858
  }
1730
1859
  else {
1731
- langType = typeMaps$3[prop.type];
1860
+ langType = typeMaps$4[prop.type];
1732
1861
  initializer = typeInitializer[prop.type];
1733
1862
  }
1734
1863
  property += ` ${langType} ${prop.name}`;
@@ -1738,18 +1867,18 @@ function generateProperty(prop, indent = "") {
1738
1867
 
1739
1868
  var java = /*#__PURE__*/Object.freeze({
1740
1869
  __proto__: null,
1741
- generate: generate$4,
1742
- name: name$3,
1743
- renderBundle: renderBundle$3
1870
+ generate: generate$5,
1871
+ name: name$4,
1872
+ renderBundle: renderBundle$4
1744
1873
  });
1745
1874
 
1746
- const name$2 = "LUA";
1875
+ const name$3 = "LUA";
1747
1876
  /**
1748
1877
  TODO:
1749
1878
  - Support inheritance
1750
1879
  - Support importing Schema dependencies
1751
1880
  */
1752
- const typeMaps$2 = {
1881
+ const typeMaps$3 = {
1753
1882
  "string": "string",
1754
1883
  "number": "number",
1755
1884
  "boolean": "boolean",
@@ -1764,27 +1893,29 @@ const typeMaps$2 = {
1764
1893
  "float32": "number",
1765
1894
  "float64": "number",
1766
1895
  };
1767
- const COMMON_IMPORTS = `local schema = require 'colyseus.serializer.schema.schema'`;
1768
- const distinct$2 = (value, index, self) => self.indexOf(value) === index;
1896
+ const COMMON_IMPORTS$1 = `local schema = require 'colyseus.serializer.schema.schema'`;
1897
+ const QUANTIZE_IMPORT = `local quantize = require 'colyseus.serializer.schema.quantize'`;
1898
+ const distinct$3 = (value, index, self) => self.indexOf(value) === index;
1899
+ const hasQuantized = (classes) => classes.some(klass => klass.properties.some(prop => prop.quantized));
1769
1900
  /**
1770
1901
  * Generate individual files for each class
1771
1902
  */
1772
- function generate$3(context, options) {
1903
+ function generate$4(context, options) {
1773
1904
  return context.classes.map(klass => ({
1774
1905
  name: klass.name + ".lua",
1775
- content: generateClass$2(klass, options.namespace, context.classes)
1906
+ content: generateClass$3(klass, options.namespace, context.classes)
1776
1907
  }));
1777
1908
  }
1778
1909
  /**
1779
1910
  * Generate a single bundled file containing all classes
1780
1911
  */
1781
- function renderBundle$2(context, options) {
1912
+ function renderBundle$3(context, options) {
1782
1913
  const fileName = options.namespace ? `${options.namespace}.lua` : "schema.lua";
1783
- const classBodies = context.classes.map(klass => generateClassBody$2(klass));
1914
+ const classBodies = context.classes.map(klass => generateClassBody$3(klass));
1784
1915
  const classNames = context.classes.map(klass => ` ${klass.name} = ${klass.name},`).join("\n");
1785
1916
  const content = `${getCommentHeader().replace(/\/\//mg, "--")}
1786
1917
 
1787
- ${COMMON_IMPORTS}
1918
+ ${COMMON_IMPORTS$1}${hasQuantized(context.classes) ? `\n${QUANTIZE_IMPORT}` : ""}
1788
1919
 
1789
1920
  ${classBodies.join("\n\n")}
1790
1921
 
@@ -1797,7 +1928,7 @@ ${classNames}
1797
1928
  /**
1798
1929
  * Generate just the class body (without requires) for bundling
1799
1930
  */
1800
- function generateClassBody$2(klass) {
1931
+ function generateClassBody$3(klass) {
1801
1932
  // Inheritance support
1802
1933
  const inherits = (klass.extends !== "Schema")
1803
1934
  ? `, ${klass.extends}`
@@ -1812,7 +1943,7 @@ ${klass.properties.map(prop => generatePropertyDeclaration(prop)).join(",\n")},
1812
1943
  /**
1813
1944
  * Generate a complete class file with requires (for individual file mode)
1814
1945
  */
1815
- function generateClass$2(klass, namespace, allClasses) {
1946
+ function generateClass$3(klass, namespace, allClasses) {
1816
1947
  const allRefs = [];
1817
1948
  klass.properties.forEach(property => {
1818
1949
  let type = property.type;
@@ -1822,25 +1953,30 @@ function generateClass$2(klass, namespace, allClasses) {
1822
1953
  }
1823
1954
  });
1824
1955
  const localRequires = allRefs.
1825
- filter(ref => ref.childType && typeMaps$2[ref.childType] === undefined).
1956
+ filter(ref => ref.childType && typeMaps$3[ref.childType] === undefined).
1826
1957
  map(ref => ref.childType).
1827
1958
  concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
1828
- filter(distinct$2).
1959
+ filter(distinct$3).
1829
1960
  map(childType => `local ${childType} = require '${(namespace ? `${namespace}.` : '')}${childType}'`).
1830
1961
  join("\n");
1831
1962
  return `${getCommentHeader().replace(/\/\//mg, "--")}
1832
1963
 
1833
- ${COMMON_IMPORTS}
1964
+ ${COMMON_IMPORTS$1}${hasQuantized([klass]) ? `\n${QUANTIZE_IMPORT}` : ""}
1834
1965
  ${localRequires}
1835
1966
 
1836
- ${generateClassBody$2(klass)}
1967
+ ${generateClassBody$3(klass)}
1837
1968
 
1838
1969
  return ${klass.name}
1839
1970
  `;
1840
1971
  }
1841
1972
  function generatePropertyDeclaration(prop) {
1842
1973
  let typeArgs;
1843
- if (prop.childType) {
1974
+ if (prop.quantized) {
1975
+ // resolve at class-definition time — the decoder expects `.wire`/`.span`
1976
+ const q = prop.quantized;
1977
+ typeArgs = `{ quantized = quantize.resolve({ min = ${q.min}, max = ${q.max}, bits = ${q.bits}, mode = ${q.wrap ? 1 : 0} }) }`;
1978
+ }
1979
+ else if (prop.childType) {
1844
1980
  const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
1845
1981
  if (isUpcaseFirst) {
1846
1982
  typeArgs += `${prop.childType}`;
@@ -1865,7 +2001,10 @@ function generatePropertyDeclaration(prop) {
1865
2001
  return ` ["${prop.name}"] = ${typeArgs}`;
1866
2002
  }
1867
2003
  function getLUATypeAnnotation(prop) {
1868
- if (prop.type === "ref") {
2004
+ if (prop.type === "quantized") {
2005
+ return "number";
2006
+ }
2007
+ else if (prop.type === "ref") {
1869
2008
  return prop.childType;
1870
2009
  }
1871
2010
  else if (prop.type === "array") {
@@ -1875,22 +2014,22 @@ function getLUATypeAnnotation(prop) {
1875
2014
  return "MapSchema";
1876
2015
  }
1877
2016
  else {
1878
- return typeMaps$2[prop.type];
2017
+ return typeMaps$3[prop.type];
1879
2018
  }
1880
2019
  }
1881
2020
 
1882
2021
  var lua = /*#__PURE__*/Object.freeze({
1883
2022
  __proto__: null,
1884
- generate: generate$3,
1885
- name: name$2,
1886
- renderBundle: renderBundle$2
2023
+ generate: generate$4,
2024
+ name: name$3,
2025
+ renderBundle: renderBundle$3
1887
2026
  });
1888
2027
 
1889
- const name$1 = "C";
2028
+ const name$2 = "C";
1890
2029
  /**
1891
2030
  * Type mappings for C
1892
2031
  */
1893
- const typeMaps$1 = {
2032
+ const typeMaps$2 = {
1894
2033
  "string": "char*",
1895
2034
  "number": "double",
1896
2035
  "boolean": "bool",
@@ -1904,6 +2043,7 @@ const typeMaps$1 = {
1904
2043
  "uint64": "uint64_t",
1905
2044
  "float32": "float",
1906
2045
  "float64": "double",
2046
+ "quantized": "double",
1907
2047
  };
1908
2048
  /**
1909
2049
  * Colyseus field type enum mappings
@@ -1925,6 +2065,7 @@ const fieldTypeMaps = {
1925
2065
  "ref": "COLYSEUS_FIELD_REF",
1926
2066
  "array": "COLYSEUS_FIELD_ARRAY",
1927
2067
  "map": "COLYSEUS_FIELD_MAP",
2068
+ "quantized": "COLYSEUS_FIELD_QUANTIZED",
1928
2069
  };
1929
2070
  const COMMON_INCLUDES = `#include "colyseus/schema/types.h"
1930
2071
  #include "colyseus/schema/collections.h"
@@ -1937,23 +2078,23 @@ const COMMON_INCLUDES = `#include "colyseus/schema/types.h"
1937
2078
  const toSnakeCase = (s) => {
1938
2079
  return s.replace(/([A-Z])/g, (match, p1, offset) => (offset > 0 ? '_' : '') + p1.toLowerCase());
1939
2080
  };
1940
- const distinct$1 = (value, index, self) => self.indexOf(value) === index;
2081
+ const distinct$2 = (value, index, self) => self.indexOf(value) === index;
1941
2082
  /**
1942
2083
  * Generate individual files for each class
1943
2084
  */
1944
- function generate$2(context, options) {
2085
+ function generate$3(context, options) {
1945
2086
  return context.classes.map(klass => ({
1946
2087
  name: toSnakeCase(klass.name) + ".h",
1947
- content: generateClass$1(klass, options.namespace, context.classes)
2088
+ content: generateClass$2(klass, options.namespace, context.classes)
1948
2089
  }));
1949
2090
  }
1950
2091
  /**
1951
2092
  * Generate a single bundled header file containing all classes
1952
2093
  */
1953
- function renderBundle$1(context, options) {
2094
+ function renderBundle$2(context, options) {
1954
2095
  const fileName = options.namespace ? `${toSnakeCase(options.namespace)}.h` : "schema.h";
1955
2096
  const guardName = `__SCHEMA_CODEGEN_${(options.namespace || "SCHEMA").toUpperCase()}_H__`;
1956
- const classBodies = context.classes.map(klass => generateClassBody$1(klass, context.classes)).join("\n\n");
2097
+ const classBodies = context.classes.map(klass => generateClassBody$2(klass, context.classes)).join("\n\n");
1957
2098
  const content = `${getCommentHeader()}
1958
2099
  #ifndef ${guardName}
1959
2100
  #define ${guardName} 1
@@ -1969,7 +2110,7 @@ ${classBodies}
1969
2110
  /**
1970
2111
  * Generate just the class body (without guards/includes) for bundling
1971
2112
  */
1972
- function generateClassBody$1(klass, allClasses) {
2113
+ function generateClassBody$2(klass, allClasses) {
1973
2114
  const snakeName = toSnakeCase(klass.name);
1974
2115
  const typeName = `${snakeName}_t`;
1975
2116
  const allProperties = getAllProperties(klass, allClasses);
@@ -1986,7 +2127,7 @@ ${generateVtable(klass, snakeName, typeName, allProperties)}`;
1986
2127
  /**
1987
2128
  * Generate a complete class file with guards/includes (for individual file mode)
1988
2129
  */
1989
- function generateClass$1(klass, namespace, allClasses) {
2130
+ function generateClass$2(klass, namespace, allClasses) {
1990
2131
  toSnakeCase(klass.name);
1991
2132
  const guardName = `__SCHEMA_CODEGEN_${klass.name.toUpperCase()}_H__`;
1992
2133
  const allRefs = [];
@@ -1997,10 +2138,10 @@ function generateClass$1(klass, namespace, allClasses) {
1997
2138
  });
1998
2139
  // Generate includes for referenced schema types
1999
2140
  const refIncludes = allRefs
2000
- .filter(ref => ref.childType && typeMaps$1[ref.childType] === undefined)
2141
+ .filter(ref => ref.childType && typeMaps$2[ref.childType] === undefined)
2001
2142
  .map(ref => ref.childType)
2002
2143
  .concat(getInheritanceTree(klass, allClasses, false).map(k => k.name))
2003
- .filter(distinct$1)
2144
+ .filter(distinct$2)
2004
2145
  .map(childType => `#include "${toSnakeCase(childType)}.h"`)
2005
2146
  .join("\n");
2006
2147
  return `${getCommentHeader()}
@@ -2009,7 +2150,7 @@ function generateClass$1(klass, namespace, allClasses) {
2009
2150
 
2010
2151
  ${COMMON_INCLUDES}
2011
2152
  ${refIncludes ? `\n${refIncludes}\n` : ""}
2012
- ${generateClassBody$1(klass, allClasses)}
2153
+ ${generateClassBody$2(klass, allClasses)}
2013
2154
 
2014
2155
  #endif
2015
2156
  `;
@@ -2030,7 +2171,7 @@ function getCType(prop) {
2030
2171
  return `${toSnakeCase(prop.childType)}_t*`;
2031
2172
  }
2032
2173
  else if (prop.type === "array") {
2033
- if (typeMaps$1[prop.childType]) {
2174
+ if (typeMaps$2[prop.childType]) {
2034
2175
  return `colyseus_array_schema_t*`;
2035
2176
  }
2036
2177
  else {
@@ -2038,7 +2179,7 @@ function getCType(prop) {
2038
2179
  }
2039
2180
  }
2040
2181
  else if (prop.type === "map") {
2041
- if (typeMaps$1[prop.childType]) {
2182
+ if (typeMaps$2[prop.childType]) {
2042
2183
  return `colyseus_map_schema_t*`;
2043
2184
  }
2044
2185
  else {
@@ -2046,7 +2187,7 @@ function getCType(prop) {
2046
2187
  }
2047
2188
  }
2048
2189
  else {
2049
- return typeMaps$1[prop.type] || `${toSnakeCase(prop.type)}_t*`;
2190
+ return typeMaps$2[prop.type] || `${toSnakeCase(prop.type)}_t*`;
2050
2191
  }
2051
2192
  }
2052
2193
  function getFieldType(prop) {
@@ -2060,21 +2201,38 @@ function generateFieldsArray(klass, typeName, snakeName, allProperties) {
2060
2201
  if (allProperties.length === 0) {
2061
2202
  return `static const colyseus_field_t ${snakeName}_fields[] = {};`;
2062
2203
  }
2204
+ // one pre-resolved static descriptor per quantized field
2205
+ const descriptors = allProperties
2206
+ .filter(prop => prop.quantized)
2207
+ .map(prop => {
2208
+ const q = prop.quantized;
2209
+ const { range, span } = resolveQuantized(q);
2210
+ return `static const colyseus_quantized_descriptor_t ${snakeName}_${prop.name}_quantized = {${q.min}, ${q.max}, ${range}, ${span}, ${q.bits}, ${q.wrap}};`;
2211
+ });
2063
2212
  const fields = allProperties.map((prop, i) => {
2064
2213
  const fieldType = getFieldType(prop);
2065
2214
  const typeString = getFieldTypeString(prop);
2066
2215
  let vtableRef = "NULL";
2067
- if (prop.type === "ref" && prop.childType && !typeMaps$1[prop.childType]) {
2216
+ let childPrimitiveRef = "NULL";
2217
+ let quantizedRef = "NULL";
2218
+ if (prop.type === "ref" && prop.childType && !typeMaps$2[prop.childType]) {
2068
2219
  const childSnake = toSnakeCase(prop.childType);
2069
2220
  vtableRef = `&${childSnake}_vtable`;
2070
2221
  }
2071
- else if ((prop.type === "array" || prop.type === "map") && prop.childType && !typeMaps$1[prop.childType]) {
2222
+ else if ((prop.type === "array" || prop.type === "map") && prop.childType && !typeMaps$2[prop.childType]) {
2072
2223
  const childSnake = toSnakeCase(prop.childType);
2073
2224
  vtableRef = `&${childSnake}_vtable`;
2074
2225
  }
2075
- return ` {${prop.index}, "${prop.name}", ${fieldType}, "${typeString}", offsetof(${typeName}, ${prop.name}), ${vtableRef}, NULL}`;
2226
+ else if ((prop.type === "array" || prop.type === "map") && prop.childType) {
2227
+ // collection of primitives — the decoder strcmp()s this to pick the reader
2228
+ childPrimitiveRef = `"${prop.childType}"`;
2229
+ }
2230
+ else if (prop.quantized) {
2231
+ quantizedRef = `&${snakeName}_${prop.name}_quantized`;
2232
+ }
2233
+ return ` {${prop.index}, "${prop.name}", ${fieldType}, "${typeString}", offsetof(${typeName}, ${prop.name}), ${vtableRef}, ${childPrimitiveRef}, ${quantizedRef}}`;
2076
2234
  }).join(",\n");
2077
- return `static const colyseus_field_t ${snakeName}_fields[] = {
2235
+ return `${descriptors.length ? descriptors.join("\n") + "\n\n" : ""}static const colyseus_field_t ${snakeName}_fields[] = {
2078
2236
  ${fields}
2079
2237
  };`;
2080
2238
  }
@@ -2091,7 +2249,7 @@ function generateDestroyFunction(klass, snakeName, typeName, allProperties) {
2091
2249
  freeStatements.push(` if (instance->${prop.name}) free(instance->${prop.name});`);
2092
2250
  }
2093
2251
  else if (prop.type === "ref") {
2094
- if (typeMaps$1[prop.childType]) {
2252
+ if (typeMaps$2[prop.childType]) {
2095
2253
  freeStatements.push(` if (instance->${prop.name}) free(instance->${prop.name});`);
2096
2254
  }
2097
2255
  else {
@@ -2128,16 +2286,16 @@ function getAllProperties(klass, allClasses) {
2128
2286
 
2129
2287
  var c = /*#__PURE__*/Object.freeze({
2130
2288
  __proto__: null,
2131
- generate: generate$2,
2132
- name: name$1,
2133
- renderBundle: renderBundle$1
2289
+ generate: generate$3,
2290
+ name: name$2,
2291
+ renderBundle: renderBundle$2
2134
2292
  });
2135
2293
 
2136
- const name = "GDScript";
2294
+ const name$1 = "GDScript";
2137
2295
  /**
2138
2296
  * Type mappings from schema types to GDScript Colyseus.Schema type constants
2139
2297
  */
2140
- const typeMaps = {
2298
+ const typeMaps$1 = {
2141
2299
  "string": "Colyseus.Schema.STRING",
2142
2300
  "number": "Colyseus.Schema.NUMBER",
2143
2301
  "boolean": "Colyseus.Schema.BOOLEAN",
@@ -2157,42 +2315,42 @@ const containerMaps = {
2157
2315
  "map": "Colyseus.Schema.MAP",
2158
2316
  "ref": "Colyseus.Schema.REF",
2159
2317
  };
2160
- const distinct = (value, index, self) => self.indexOf(value) === index;
2318
+ const distinct$1 = (value, index, self) => self.indexOf(value) === index;
2161
2319
  /**
2162
2320
  * GDScript Code Generator
2163
2321
  */
2164
2322
  /**
2165
2323
  * Generate individual files for each class
2166
2324
  */
2167
- function generate$1(context, options) {
2325
+ function generate$2(context, options) {
2168
2326
  // Enrich typeMaps with enums
2169
2327
  context.enums.forEach((structure) => {
2170
- typeMaps[structure.name] = structure.name;
2328
+ typeMaps$1[structure.name] = structure.name;
2171
2329
  });
2172
2330
  return [
2173
2331
  ...context.classes.map(klass => ({
2174
2332
  name: `${klass.name}.gd`,
2175
- content: generateClass(klass, options.namespace, context.classes)
2333
+ content: generateClass$1(klass, options.namespace, context.classes)
2176
2334
  })),
2177
2335
  ...context.enums.filter(structure => structure.name !== 'OPERATION').map((structure) => ({
2178
2336
  name: `${structure.name}.gd`,
2179
- content: generateEnum(structure, options.namespace),
2337
+ content: generateEnum$1(structure, options.namespace),
2180
2338
  })),
2181
2339
  ];
2182
2340
  }
2183
2341
  /**
2184
2342
  * Generate a single bundled file containing all classes and enums
2185
2343
  */
2186
- function renderBundle(context, options) {
2344
+ function renderBundle$1(context, options) {
2187
2345
  const fileName = options.namespace ? `${options.namespace}.gd` : "schema.gd";
2188
2346
  // Enrich typeMaps with enums
2189
2347
  context.enums.forEach((structure) => {
2190
- typeMaps[structure.name] = structure.name;
2348
+ typeMaps$1[structure.name] = structure.name;
2191
2349
  });
2192
2350
  const enumBodies = context.enums
2193
2351
  .filter(structure => structure.name !== 'OPERATION')
2194
- .map(e => generateEnumBody(e));
2195
- const classBodies = context.classes.map(klass => generateClassBody(klass));
2352
+ .map(e => generateEnumBody$1(e));
2353
+ const classBodies = context.classes.map(klass => generateClassBody$1(klass));
2196
2354
  const content = `${getCommentHeader("#")}
2197
2355
 
2198
2356
  ${enumBodies.length > 0 ? enumBodies.join("\n\n") + "\n\n" : ""}${classBodies.join("\n\n")}
@@ -2202,7 +2360,7 @@ ${enumBodies.length > 0 ? enumBodies.join("\n\n") + "\n\n" : ""}${classBodies.jo
2202
2360
  /**
2203
2361
  * Generate just the class body (without preload) for bundling
2204
2362
  */
2205
- function generateClassBody(klass) {
2363
+ function generateClassBody$1(klass) {
2206
2364
  // Determine parent class
2207
2365
  const parentClass = (klass.extends !== "Schema")
2208
2366
  ? klass.extends
@@ -2236,7 +2394,7 @@ function generateToStringMethod(className, properties) {
2236
2394
  /**
2237
2395
  * Generate a complete class file with preload (for individual file mode)
2238
2396
  */
2239
- function generateClass(klass, namespace, allClasses) {
2397
+ function generateClass$1(klass, namespace, allClasses) {
2240
2398
  const allRefs = [];
2241
2399
  klass.properties.forEach(property => {
2242
2400
  let type = property.type;
@@ -2247,15 +2405,15 @@ function generateClass(klass, namespace, allClasses) {
2247
2405
  });
2248
2406
  // Get required preloads for referenced types
2249
2407
  const preloads = allRefs
2250
- .filter(ref => ref.childType && typeMaps[ref.childType] === undefined)
2408
+ .filter(ref => ref.childType && typeMaps$1[ref.childType] === undefined)
2251
2409
  .map(ref => ref.childType)
2252
2410
  .concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name))
2253
- .filter(distinct)
2411
+ .filter(distinct$1)
2254
2412
  .map(childType => `const ${childType} = preload("${childType}.gd")`)
2255
2413
  .join("\n");
2256
2414
  return `${getCommentHeader("#")}
2257
2415
 
2258
- ${preloads ? preloads + "\n\n" : ""}${generateClassBody(klass)}
2416
+ ${preloads ? preloads + "\n\n" : ""}${generateClassBody$1(klass)}
2259
2417
  `;
2260
2418
  }
2261
2419
  /**
@@ -2267,12 +2425,12 @@ function generateFieldDefinition(prop) {
2267
2425
  const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
2268
2426
  // Array or Map container
2269
2427
  const containerType = containerMaps[prop.type];
2270
- const childTypeRef = isUpcaseFirst ? prop.childType : typeMaps[prop.childType] || `"${prop.childType}"`;
2428
+ const childTypeRef = isUpcaseFirst ? prop.childType : typeMaps$1[prop.childType] || `"${prop.childType}"`;
2271
2429
  args = [`"${prop.name}"`, containerType, childTypeRef];
2272
2430
  }
2273
2431
  else {
2274
2432
  // Primitive type
2275
- const typeRef = typeMaps[prop.type] || `"${prop.type}"`;
2433
+ const typeRef = typeMaps$1[prop.type] || `"${prop.type}"`;
2276
2434
  args = [`"${prop.name}"`, typeRef];
2277
2435
  }
2278
2436
  return `\t\t\tColyseus.Schema.Field.new(${args.join(", ")})`;
@@ -2280,7 +2438,7 @@ function generateFieldDefinition(prop) {
2280
2438
  /**
2281
2439
  * Generate just the enum body for bundling
2282
2440
  */
2283
- function generateEnumBody(_enum) {
2441
+ function generateEnumBody$1(_enum) {
2284
2442
  const enumValues = _enum.properties.map((prop, index) => {
2285
2443
  let value;
2286
2444
  if (prop.type) {
@@ -2303,21 +2461,274 @@ ${enumValues}
2303
2461
  /**
2304
2462
  * Generate a complete enum file (for individual file mode)
2305
2463
  */
2306
- function generateEnum(_enum, _namespace) {
2464
+ function generateEnum$1(_enum, _namespace) {
2307
2465
  return `${getCommentHeader("#")}
2308
2466
 
2309
- ${generateEnumBody(_enum)}
2467
+ ${generateEnumBody$1(_enum)}
2310
2468
  `;
2311
2469
  }
2312
2470
 
2313
2471
  var gdscript = /*#__PURE__*/Object.freeze({
2472
+ __proto__: null,
2473
+ generate: generate$2,
2474
+ name: name$1,
2475
+ renderBundle: renderBundle$1
2476
+ });
2477
+
2478
+ const name = "Dart/Flutter";
2479
+ /**
2480
+ * Dart types for interface (plain message) properties. Schema scalar getters
2481
+ * don't use this table: the `colyseus` package reads every numeric field as
2482
+ * `double` through `SchemaView`, so all numeric schema types collapse there.
2483
+ */
2484
+ const typeMaps = {
2485
+ "string": "String",
2486
+ "number": "double",
2487
+ "boolean": "bool",
2488
+ "int8": "double",
2489
+ "uint8": "double",
2490
+ "int16": "double",
2491
+ "uint16": "double",
2492
+ "int32": "double",
2493
+ "uint32": "double",
2494
+ "int64": "double",
2495
+ "uint64": "double",
2496
+ "float32": "double",
2497
+ "float64": "double",
2498
+ };
2499
+ const enumNames = new Set();
2500
+ const COMMON_IMPORTS = `import 'package:colyseus/colyseus.dart';`;
2501
+ // Field names come from the server schema and may not be lowerCamelCase.
2502
+ const LINT_HEADER = `// ignore_for_file: non_constant_identifier_names, constant_identifier_names`;
2503
+ const distinct = (value, index, self) => self.indexOf(value) === index;
2504
+ const isSchemaType = (childType) => childType !== undefined && /^[A-Z]/.test(childType) && !enumNames.has(childType);
2505
+ /**
2506
+ * Dart Code Generator
2507
+ *
2508
+ * Emits typed façades over the `colyseus` Flutter package's runtime: one
2509
+ * `SchemaRef` subclass per schema, with typed getters over the shared native
2510
+ * handle. Collection getters return `MapSchema<T>` / `ArraySchema<T>`, which
2511
+ * also carry the field they came from — that is what
2512
+ * `callbacks.onAdd(state.players, ...)` registers against.
2513
+ */
2514
+ /**
2515
+ * Generate individual files for each class/interface/enum
2516
+ */
2517
+ function generate$1(context, options) {
2518
+ context.enums.forEach((structure) => enumNames.add(structure.name));
2519
+ return [
2520
+ ...context.classes.map(klass => ({
2521
+ name: `${klass.name}.dart`,
2522
+ content: generateClass(klass, context.classes)
2523
+ })),
2524
+ ...context.interfaces.map(structure => ({
2525
+ name: `${structure.name}.dart`,
2526
+ content: generateInterface(structure),
2527
+ })),
2528
+ ...context.enums.filter(structure => structure.name !== 'OPERATION').map((structure) => ({
2529
+ name: `${structure.name}.dart`,
2530
+ content: generateEnum(structure),
2531
+ })),
2532
+ ];
2533
+ }
2534
+ /**
2535
+ * Generate a single bundled file containing all classes, interfaces, and enums
2536
+ */
2537
+ function renderBundle(context, options) {
2538
+ const fileName = options.namespace ? `${options.namespace}.dart` : "schema.dart";
2539
+ context.enums.forEach((structure) => enumNames.add(structure.name));
2540
+ const bodies = [
2541
+ ...context.classes.map(klass => generateClassBody(klass, context.classes)),
2542
+ ...context.interfaces.map(iface => generateInterfaceBody(iface)),
2543
+ ...context.enums
2544
+ .filter(structure => structure.name !== 'OPERATION')
2545
+ .map(e => generateEnumBody(e)),
2546
+ ].join("\n\n");
2547
+ const content = `${getCommentHeader()}
2548
+ ${LINT_HEADER}
2549
+
2550
+ ${COMMON_IMPORTS}
2551
+
2552
+ ${bodies}
2553
+ `;
2554
+ return { name: fileName, content };
2555
+ }
2556
+ /**
2557
+ * Generate just the class body (without imports) for bundling
2558
+ */
2559
+ function generateClassBody(klass, allClasses) {
2560
+ // `SchemaRef` is a `base` class, so subclasses carry a modifier: `base`
2561
+ // when the class is itself extended (extendable from any file), `final`
2562
+ // otherwise.
2563
+ const isExtended = allClasses.some(other => other.extends === klass.name);
2564
+ const modifier = isExtended ? "base" : "final";
2565
+ const parent = (klass.extends === "Schema") ? "SchemaRef" : klass.extends;
2566
+ const getters = klass.properties
2567
+ .map(prop => generateGetter(prop))
2568
+ .filter(Boolean)
2569
+ .join("\n");
2570
+ return `${modifier} class ${klass.name} extends ${parent} {
2571
+ ${klass.name}(super.handle);
2572
+
2573
+ ${getters}
2574
+ }`;
2575
+ }
2576
+ /**
2577
+ * Generate a complete class file with imports (for individual file mode)
2578
+ */
2579
+ function generateClass(klass, allClasses) {
2580
+ const localRefs = klass.properties
2581
+ .filter(prop => isSchemaType(prop.childType))
2582
+ .map(prop => prop.childType)
2583
+ .concat(klass.extends !== "Schema" ? [klass.extends] : [])
2584
+ .filter(distinct)
2585
+ .filter(ref => ref !== klass.name)
2586
+ .map(ref => `import '${ref}.dart';`)
2587
+ .join("\n");
2588
+ return `${getCommentHeader()}
2589
+ ${LINT_HEADER}
2590
+
2591
+ ${COMMON_IMPORTS}
2592
+ ${localRefs ? localRefs + "\n" : ""}
2593
+ ${generateClassBody(klass, allClasses)}
2594
+ `;
2595
+ }
2596
+ /**
2597
+ * The Dart type a scalar schema field reads as, or undefined when the field
2598
+ * can only be read dynamically (enum-typed and unknown types).
2599
+ */
2600
+ function scalarDartType(type) {
2601
+ if (type === "string") {
2602
+ return "String";
2603
+ }
2604
+ if (type === "boolean") {
2605
+ return "bool";
2606
+ }
2607
+ if (typeMaps[type] === "double" || type === "quantized" || type === "number") {
2608
+ return "double";
2609
+ }
2610
+ return undefined;
2611
+ }
2612
+ function generateGetter(prop) {
2613
+ const deprecation = (prop.deprecated)
2614
+ ? ` @Deprecated("field '${prop.name}' is deprecated.")\n`
2615
+ : '';
2616
+ let body;
2617
+ if (prop.childType && isSchemaType(prop.childType)) {
2618
+ if (prop.type === "ref") {
2619
+ body = ` ${prop.childType}? get ${prop.name} => refOf('${prop.name}', ${prop.childType}.new);`;
2620
+ }
2621
+ else if (prop.type === "map") {
2622
+ body = ` MapSchema<${prop.childType}> get ${prop.name} => mapOf('${prop.name}', ${prop.childType}.new);`;
2623
+ }
2624
+ else {
2625
+ body = ` ArraySchema<${prop.childType}> get ${prop.name} => arrayOf('${prop.name}', ${prop.childType}.new);`;
2626
+ }
2627
+ }
2628
+ else if (prop.childType) {
2629
+ const child = typeMaps[prop.childType] ?? "dynamic";
2630
+ if (prop.type === "map") {
2631
+ body = ` MapSchema<${child}> get ${prop.name} => primitiveMapOf('${prop.name}');`;
2632
+ }
2633
+ else if (prop.type === "array") {
2634
+ body = ` ArraySchema<${child}> get ${prop.name} => primitiveArrayOf('${prop.name}');`;
2635
+ }
2636
+ else {
2637
+ // A "ref" with a primitive child has no typed shape to offer.
2638
+ body = ` dynamic get ${prop.name} => this['${prop.name}'];`;
2639
+ }
2640
+ }
2641
+ else {
2642
+ const dartType = scalarDartType(prop.type);
2643
+ if (dartType === "String") {
2644
+ body = ` String get ${prop.name} => view.getString('${prop.name}') ?? '';`;
2645
+ }
2646
+ else if (dartType === "bool") {
2647
+ body = ` bool get ${prop.name} => view.getBool('${prop.name}');`;
2648
+ }
2649
+ else if (dartType === "double") {
2650
+ body = ` double get ${prop.name} => view['${prop.name}'];`;
2651
+ }
2652
+ else {
2653
+ // Enum-typed or unknown: read through the untyped accessor.
2654
+ body = ` dynamic get ${prop.name} => this['${prop.name}'];`;
2655
+ }
2656
+ }
2657
+ return deprecation + body;
2658
+ }
2659
+ /**
2660
+ * Generate just the interface body for bundling
2661
+ */
2662
+ function generateInterfaceBody(struct) {
2663
+ const fields = struct.properties
2664
+ .map(prop => ` ${getInterfaceType(prop)}? ${prop.name};`)
2665
+ .join("\n");
2666
+ return `class ${struct.name} {
2667
+ ${fields}
2668
+ }`;
2669
+ }
2670
+ /**
2671
+ * Generate a complete interface file (for individual file mode)
2672
+ */
2673
+ function generateInterface(struct) {
2674
+ const localRefs = struct.properties
2675
+ .filter(prop => isSchemaType(prop.childType ?? (typeMaps[prop.type] ? undefined : prop.type)))
2676
+ .map(prop => prop.childType ?? prop.type)
2677
+ .filter(distinct)
2678
+ .map(ref => `import '${ref}.dart';`)
2679
+ .join("\n");
2680
+ return `${getCommentHeader()}
2681
+ ${LINT_HEADER}
2682
+ ${localRefs ? "\n" + localRefs + "\n" : ""}
2683
+ ${generateInterfaceBody(struct)}
2684
+ `;
2685
+ }
2686
+ function getInterfaceType(prop) {
2687
+ if (prop.type === "array") {
2688
+ return `List<${typeMaps[prop.childType] ?? prop.childType ?? "dynamic"}>`;
2689
+ }
2690
+ return typeMaps[prop.type] ?? prop.type ?? "dynamic";
2691
+ }
2692
+ /**
2693
+ * Generate just the enum body for bundling: a namespace of consts, since
2694
+ * Colyseus enums may carry string or float values Dart enums can't.
2695
+ */
2696
+ function generateEnumBody(_enum) {
2697
+ const members = _enum.properties
2698
+ .map((prop, i) => {
2699
+ let value;
2700
+ if (prop.type) {
2701
+ value = isNaN(Number(prop.type)) ? `"${prop.type}"` : `${Number(prop.type)}`;
2702
+ }
2703
+ else {
2704
+ value = `${i}`;
2705
+ }
2706
+ return ` static const ${prop.name} = ${value};`;
2707
+ })
2708
+ .join("\n");
2709
+ return `abstract final class ${_enum.name} {
2710
+ ${members}
2711
+ }`;
2712
+ }
2713
+ /**
2714
+ * Generate a complete enum file (for individual file mode)
2715
+ */
2716
+ function generateEnum(_enum) {
2717
+ return `${getCommentHeader()}
2718
+ ${LINT_HEADER}
2719
+
2720
+ ${generateEnumBody(_enum)}
2721
+ `;
2722
+ }
2723
+
2724
+ var dart = /*#__PURE__*/Object.freeze({
2314
2725
  __proto__: null,
2315
2726
  generate: generate$1,
2316
2727
  name: name,
2317
2728
  renderBundle: renderBundle
2318
2729
  });
2319
2730
 
2320
- const generators = { csharp, cpp, haxe, ts, js, java, lua, c, gdscript, };
2731
+ const generators = { csharp, cpp, haxe, ts, js, java, lua, c, gdscript, dart, };
2321
2732
  function generate(targetId, options) {
2322
2733
  const generator = generators[targetId];
2323
2734
  if (!generator) {