@daneren2005/shared-memory-ecs 1.9.0 → 1.10.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/README.md CHANGED
@@ -926,6 +926,52 @@ through `system.addEntities(batch)`. Entities with the same component keys are g
926
926
  test runs once per group instead of once per entity; system membership keeps load order. A system that overrides
927
927
  `checkAddEntity` (or an `EntityWorkerSystem` that overrides `matchesQuery`) still has it called for each entity.
928
928
 
929
+ ### Compressing saves
930
+
931
+ Big maps are mostly entities whose save is a `type` plus a few integers. `compressEntities(entities, definitions)`
932
+ packs each config that fits a definition into a short ASCII string and leaves every other config as an object:
933
+
934
+ ```ts
935
+ import { compressEntities } from '@daneren2005/shared-memory-ecs';
936
+
937
+ const save = compressEntities(entities, [
938
+ { type: 'grass', properties: [
939
+ // Stored as (value - offset) / step; tile centres become small tile indices.
940
+ { name: 'x', type: 'uint', step: 32, offset: 16 },
941
+ { name: 'y', type: 'uint', step: 32, offset: 16 },
942
+ { name: 'harvestAmount', type: 'uint' },
943
+ { name: 'harvestProgress', type: 'uint' },
944
+ ] },
945
+ ]);
946
+ // { type: 'grass', x: 7920, y: 15440, harvestProgress: 633000 } becomes '#g(q-!ok{)'; a worker stays an object.
947
+ // => { entityDefinitions: { 0: { type: 'grass', properties: [...] } }, entities: ['#g(q-!ok{)', { type: 'worker', ... }] }
948
+ await world.load({ ...save, gameTime });
949
+ ```
950
+
951
+ `world.load()` expands string entities with the bundled `entityDefinitions`, and `decompressEntities` /
952
+ `decompressEntity` do the same for tools. Property types are `int` (signed), `uint`, `boolean`, `float32` and `string`. `int`
953
+ and `uint` decode as `stored * step / 10 ** decimals + offset` (defaults 1, 0, 0), so `decimals: 2` keeps hundredths.
954
+ `float32` takes any number a `Float32Array` holds exactly, such as positions and velocities read from shared memory. A config stays an
955
+ object when it has a property its definition lacks, or a value that wouldn't decode back exactly. Only definitions some
956
+ string uses are bundled, so defining rare types costs nothing until one appears.
957
+
958
+ Types with the same properties can share one definition by listing `types` instead of `type`; the save then stores
959
+ the property list once:
960
+
961
+ ```ts
962
+ { types: ['oak', 'pine', 'birch'], properties: [...] }
963
+ ``` Missing values decode as absent. The definitions travel inside the save, so a later build can append,
964
+ reorder or drop properties without breaking older saves.
965
+
966
+ The string format lets other tools read saves without this library. A string is the definition key, then one field
967
+ per property in definition order. A shared definition saved at key `n` gives its `types` the keys `n`, `n + 1`, ... in
968
+ order, so every type still has its own key and sharing adds nothing to the strings. A field is `!` for absent, or a varint: little-endian base-45 digits, where every
969
+ digit except the last comes from `` PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|} `` and the last from
970
+ `#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO` (digit = position in its alphabet). Fields after the last present
971
+ value are left out. `int` values are zigzag encoded (`n >= 0 ? 2n : -2n - 1`), booleans are 0 or 1, and a `float32` is
972
+ the varint of its 32 IEEE 754 bits. A `string` is a varint length in UTF-16 code units followed by the raw characters,
973
+ which may be any character; length 0 means `null`, and empty strings stay objects.
974
+
929
975
  ## Measuring performance
930
976
 
931
977
  `PerformanceTiming` watches a world and reports what running it costs. Hand it the world and it hooks itself
@@ -0,0 +1,40 @@
1
+ export type CompressedPropertyType = 'int' | 'uint' | 'boolean' | 'float32' | 'string';
2
+ export interface CompressedEntityProperty {
3
+ name: string;
4
+ type: CompressedPropertyType;
5
+ step?: number;
6
+ decimals?: number;
7
+ offset?: number;
8
+ }
9
+ interface DefinitionProperties {
10
+ properties: ReadonlyArray<CompressedEntityProperty>;
11
+ }
12
+ export type CompressedEntityDefinition = DefinitionProperties & ({
13
+ type: string;
14
+ types?: never;
15
+ } | {
16
+ types: ReadonlyArray<string>;
17
+ type?: never;
18
+ });
19
+ export type CompressedEntityDefinitions = Record<string, CompressedEntityDefinition>;
20
+ export interface CompressedEntities<Cfg> {
21
+ entityDefinitions: CompressedEntityDefinitions;
22
+ entities: Array<Cfg | string>;
23
+ }
24
+ type CompressibleConfig = object & {
25
+ type?: string;
26
+ };
27
+ type DecompressedValue = number | boolean | string | null;
28
+ export declare class EntityCompressor {
29
+ private readonly encoders;
30
+ private readonly used;
31
+ constructor(definitions: ReadonlyArray<CompressedEntityDefinition>);
32
+ get entityDefinitions(): CompressedEntityDefinitions;
33
+ compress<Cfg extends CompressibleConfig>(config: Cfg): Cfg | string;
34
+ compressAll<Cfg extends CompressibleConfig>(entities: ReadonlyArray<Cfg>): CompressedEntities<Cfg>;
35
+ private encode;
36
+ }
37
+ export declare function compressEntities<Cfg extends CompressibleConfig>(entities: ReadonlyArray<Cfg>, definitions: ReadonlyArray<CompressedEntityDefinition>): CompressedEntities<Cfg>;
38
+ export declare function decompressEntity(encoded: string, definitions: CompressedEntityDefinitions): Record<string, DecompressedValue | string>;
39
+ export declare function decompressEntities<Cfg>(entities: ReadonlyArray<Cfg | string>, definitions: CompressedEntityDefinitions | undefined): Array<Cfg>;
40
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export { default as BaseWorld } from './world';
2
- export type { WorldOptions, WorldConfig } from './world';
2
+ export type { WorldOptions, WorldConfig, CompressedWorldConfig } from './world';
3
+ export { EntityCompressor, compressEntities, decompressEntity, decompressEntities } from './entity-compression';
4
+ export type { CompressedEntities, CompressedEntityDefinition, CompressedEntityDefinitions, CompressedEntityProperty, CompressedPropertyType, } from './entity-compression';
3
5
  export { default as DefaultScheduler } from './scheduling/default-scheduler';
4
6
  export { default as ConflictScheduler } from './scheduling/conflict-scheduler';
5
7
  export type { ConflictSchedule } from './scheduling/conflict-scheduler';
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
- import { _ as e, a as t, c as n, d as r, f as i, g as a, h as o, i as s, l as c, m as l, n as u, o as d, p as f, r as p, s as m, t as h, u as g, v as _, y as v } from "./create-system-worker-CNpRs2FO.js";
2
- import y from "@daneren2005/shared-memory-objects/memory-heap";
3
- import { MAX_BYTE_OFFSET_LENGTH as b } from "@daneren2005/shared-memory-objects/utils/pointer";
1
+ import { _ as e, a as t, c as n, d as r, f as i, g as a, h as o, i as s, l as c, m as l, n as u, o as d, p as f, r as p, s as m, t as ee, u as te, v as h, y as g } from "./create-system-worker-CNpRs2FO.js";
2
+ import ne from "@daneren2005/shared-memory-objects/memory-heap";
3
+ import { MAX_BYTE_OFFSET_LENGTH as _ } from "@daneren2005/shared-memory-objects/utils/pointer";
4
4
  //#region \0rolldown/runtime.js
5
- var x = Object.create, S = Object.defineProperty, C = Object.getOwnPropertyDescriptor, w = Object.getOwnPropertyNames, T = Object.getPrototypeOf, E = Object.prototype.hasOwnProperty, D = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), O = (e, t, n, r) => {
6
- if (t && typeof t == "object" || typeof t == "function") for (var i = w(t), a = 0, o = i.length, s; a < o; a++) s = i[a], !E.call(e, s) && s !== n && S(e, s, {
5
+ var v = Object.create, y = Object.defineProperty, re = Object.getOwnPropertyDescriptor, b = Object.getOwnPropertyNames, x = Object.getPrototypeOf, S = Object.prototype.hasOwnProperty, ie = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), ae = (e, t, n, r) => {
6
+ if (t && typeof t == "object" || typeof t == "function") for (var i = b(t), a = 0, o = i.length, s; a < o; a++) s = i[a], !S.call(e, s) && s !== n && y(e, s, {
7
7
  get: ((e) => t[e]).bind(null, s),
8
- enumerable: !(r = C(t, s)) || r.enumerable
8
+ enumerable: !(r = re(t, s)) || r.enumerable
9
9
  });
10
10
  return e;
11
- }, k = /* @__PURE__ */ ((e, t, n) => (n = e == null ? {} : x(T(e)), O(t || !e || !e.__esModule || !E.call(e, "default") ? S(n, "default", {
11
+ }, C = /* @__PURE__ */ ((e, t, n) => (n = e == null ? {} : v(x(e)), ae(t || !e || !e.__esModule || !S.call(e, "default") ? y(n, "default", {
12
12
  value: e,
13
13
  enumerable: !0
14
- }) : n, e)))((/* @__PURE__ */ D(((e, t) => {
14
+ }) : n, e)))((/* @__PURE__ */ ie(((e, t) => {
15
15
  var n = Object.prototype.hasOwnProperty, r = "~";
16
16
  function i() {}
17
17
  Object.create && (i.prototype = Object.create(null), new i().__proto__ || (r = !1));
@@ -98,7 +98,7 @@ var x = Object.create, S = Object.defineProperty, C = Object.getOwnPropertyDescr
98
98
  var t;
99
99
  return e ? (t = r ? r + e : e, this._events[t] && s(this, t)) : (this._events = new i(), this._eventsCount = 0), this;
100
100
  }, c.prototype.off = c.prototype.removeListener, c.prototype.addListener = c.prototype.on, c.prefixed = r, c.EventEmitter = c, t !== void 0 && (t.exports = c);
101
- })))(), 1), A = class extends k.default {
101
+ })))(), 1), w = class extends C.default {
102
102
  world;
103
103
  name;
104
104
  currentDelta = 0;
@@ -174,13 +174,13 @@ var x = Object.create, S = Object.defineProperty, C = Object.getOwnPropertyDescr
174
174
  this.removeAllListeners();
175
175
  }
176
176
  };
177
- function j(e, t, n) {
177
+ function T(e, t, n) {
178
178
  let r = e.groups.map(t);
179
179
  for (let t = 0; t < e.entities.length; t++) r[e.groupIndexes[t]] && n(e.entities[t]);
180
180
  }
181
181
  //#endregion
182
182
  //#region src/systems/iterable-system.ts
183
- var M = class extends A {
183
+ var E = class extends w {
184
184
  remainingInstancesToRun = [];
185
185
  remainingInstancesStartTime = null;
186
186
  iterationsPerCheck;
@@ -230,7 +230,7 @@ var M = class extends A {
230
230
  }
231
231
  beforeRunIterables() {}
232
232
  getIterableEntityId(e) {}
233
- }, N = class e extends M {
233
+ }, D = class e extends E {
234
234
  entities = /* @__PURE__ */ new Map();
235
235
  options;
236
236
  constructor(e, t = { name: "EntitySystem" }) {
@@ -268,7 +268,7 @@ var M = class extends A {
268
268
  t.entities.forEach((e) => this.onEntityAdded(e));
269
269
  return;
270
270
  }
271
- j(t, (e) => this.hasComponents(e), (e) => {
271
+ T(t, (e) => this.hasComponents(e), (e) => {
272
272
  this.filterEntity(e) && (this.entities.set(e.eid, e), this.options.updateEntityOnAdd && this.updateEntity(e, 0));
273
273
  });
274
274
  }
@@ -300,9 +300,9 @@ var M = class extends A {
300
300
  ...this.reads ?? []
301
301
  ] : void 0;
302
302
  }
303
- }, P = class {
303
+ }, O = class {
304
304
  onmessage(e, t = []) {}
305
- }, F = class extends P {
305
+ }, k = class extends O {
306
306
  updateFunction;
307
307
  entities = [];
308
308
  workState = new a();
@@ -460,7 +460,7 @@ var M = class extends A {
460
460
  onMessageTyped(e) {
461
461
  this.onmessage({ data: e });
462
462
  }
463
- }, I = "___main", L = class e extends A {
463
+ }, A = "___main", j = class e extends w {
464
464
  entities = /* @__PURE__ */ new Map();
465
465
  options;
466
466
  worker;
@@ -493,13 +493,13 @@ var M = class extends A {
493
493
  type: "grow-buffer",
494
494
  buffer: e
495
495
  });
496
- })) : (this.worker = new F(t.updateFunction, e, !!t.createsEntities, !!t.addsComponents), this.isWorkerThread = !1), this.initWorker();
496
+ })) : (this.worker = new k(t.updateFunction, e, !!t.createsEntities, !!t.addsComponents), this.isWorkerThread = !1), this.initWorker();
497
497
  }
498
498
  initWorker() {
499
499
  let e = (e) => {
500
500
  console.error(e, e.cause), this.initialized || (this.initError = e, this.initPromise?.reject(e));
501
501
  };
502
- if (!(this.worker instanceof F)) {
502
+ if (!(this.worker instanceof k)) {
503
503
  let t = (t) => {
504
504
  e(Error(`Worker ${this.name} failed to load`, { cause: t }));
505
505
  };
@@ -604,7 +604,7 @@ var M = class extends A {
604
604
  type: "load",
605
605
  data: this.options.getInitData?.(),
606
606
  gameTime: this.gameTime,
607
- entities: this.buildQueryDelta(I, this.options),
607
+ entities: this.buildQueryDelta(A, this.options),
608
608
  queries: n,
609
609
  heap: this.isWorkerThread ? this.world.heap.getSharedMemory() : void 0,
610
610
  sharedMemory: this.isWorkerThread ? this.world.getSharedComponentMemory() : void 0,
@@ -704,7 +704,7 @@ var M = class extends A {
704
704
  first: t.first,
705
705
  last: t.last
706
706
  }, this.isRunning = !0, this.completeEffects = this.world.scheduler.prepareEffects?.(this.world, this);
707
- let i = this.buildQueryDelta(I, this.options), a = {};
707
+ let i = this.buildQueryDelta(A, this.options), a = {};
708
708
  Object.entries(this.options.queries ?? {}).forEach(([e, t]) => {
709
709
  a[e] = this.buildQueryDelta(e, t);
710
710
  });
@@ -773,7 +773,7 @@ var M = class extends A {
773
773
  }
774
774
  checkAddEntity(e) {
775
775
  let t = this.tracksMainQuery && this.matchesQuery(e, this.options);
776
- return this.updateEntityList(I, this.entities, e, t), Object.entries(this.options.queries ?? {}).forEach(([t, n]) => {
776
+ return this.updateEntityList(A, this.entities, e, t), Object.entries(this.options.queries ?? {}).forEach(([t, n]) => {
777
777
  let r = this.queryEntities[t] ?? (this.queryEntities[t] = /* @__PURE__ */ new Map());
778
778
  this.updateEntityList(t, r, e, this.matchesQuery(e, n));
779
779
  }), t;
@@ -783,19 +783,19 @@ var M = class extends A {
783
783
  t.entities.forEach((e) => this.checkAddEntity(e));
784
784
  return;
785
785
  }
786
- this.tracksMainQuery && this.addBatchToQuery(I, this.entities, this.options, t), Object.entries(this.options.queries ?? {}).forEach(([e, n]) => {
786
+ this.tracksMainQuery && this.addBatchToQuery(A, this.entities, this.options, t), Object.entries(this.options.queries ?? {}).forEach(([e, n]) => {
787
787
  let r = this.queryEntities[e] ?? (this.queryEntities[e] = /* @__PURE__ */ new Map());
788
788
  this.addBatchToQuery(e, r, n, t);
789
789
  });
790
790
  }
791
791
  addBatchToQuery(e, t, n, r) {
792
792
  let i = this.getQueryDelta(e);
793
- j(r, (e) => this.matchesComponents(e, n), (e) => {
793
+ T(r, (e) => this.matchesComponents(e, n), (e) => {
794
794
  e.components.entity.dead || n.filter && !n.filter(e) || (t.set(e.eid, e), this.markAdded(i, e));
795
795
  });
796
796
  }
797
797
  removeEntity(e) {
798
- this.updateEntityList(I, this.entities, e, !1), Object.entries(this.queryEntities).forEach(([t, n]) => {
798
+ this.updateEntityList(A, this.entities, e, !1), Object.entries(this.queryEntities).forEach(([t, n]) => {
799
799
  this.updateEntityList(t, n, e, !1);
800
800
  });
801
801
  }
@@ -810,7 +810,7 @@ var M = class extends A {
810
810
  destroy() {
811
811
  super.destroy(), this.pendingEffects?.discard(), "terminate" in this.worker && this.worker.terminate();
812
812
  }
813
- }, R = class extends k.default {
813
+ }, M = class extends C.default {
814
814
  eid;
815
815
  config;
816
816
  world;
@@ -911,7 +911,7 @@ var M = class extends A {
911
911
  assertComponentPropertyMutable(e, t) {
912
912
  if (e === "entity" && (t === "type" || t === "class")) throw Error(`Entity ${t} is immutable`);
913
913
  }
914
- }, z = class e {
914
+ }, N = class e {
915
915
  world;
916
916
  configs;
917
917
  classes;
@@ -928,7 +928,7 @@ var M = class extends A {
928
928
  this.world = e, this.forbiddenProperties.clear();
929
929
  for (let t of Object.keys(this.classes)) {
930
930
  let n = this.classes[t].entity;
931
- if (n !== R && !(n.prototype instanceof R)) throw Error(`Entity class ${t} must extend BaseEntity`);
931
+ if (n !== M && !(n.prototype instanceof M)) throw Error(`Entity class ${t} must extend BaseEntity`);
932
932
  for (let n of this.classes[t].components) if (n === "entity" || !(n in e.registry)) throw Error(`Entity class ${t} contains unknown or reserved component ${n}`);
933
933
  }
934
934
  for (let e of Object.keys(this.configs)) this.validateTemplate(e, this.configs[e]);
@@ -954,7 +954,7 @@ var M = class extends A {
954
954
  createAdoptedEntity(e, t, n) {
955
955
  if (!t) {
956
956
  if (this.hasClasses) throw Error(`Entity type ${e} has no class`);
957
- return new R(this.world, void 0, n);
957
+ return new M(this.world, void 0, n);
958
958
  }
959
959
  let r = this.classes[t];
960
960
  if (!r) throw Error(`Unknown entity class: ${t}`);
@@ -980,7 +980,7 @@ var M = class extends A {
980
980
  return e ? this.getAllowedComponents(e) : void 0;
981
981
  }
982
982
  createEntity(e) {
983
- return new R(this.world, e);
983
+ return new M(this.world, e);
984
984
  }
985
985
  get hasClasses() {
986
986
  return this.allowedComponents.size > 0;
@@ -1045,7 +1045,160 @@ var M = class extends A {
1045
1045
  }
1046
1046
  throw Error(`Entity type ${e} class ${t} loads a component outside its class`);
1047
1047
  }
1048
- }, B = class {
1048
+ }, P = 45, F = "!", I = "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO", L = "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}", R = (/* @__PURE__ */ new Int8Array(128)).fill(-1);
1049
+ for (let e = 0; e < P; e++) R[I.charCodeAt(e)] = e, R[L.charCodeAt(e)] = e + P;
1050
+ function z(e) {
1051
+ let t = "";
1052
+ for (; e >= P;) t += L[e % P], e = Math.floor(e / P);
1053
+ return t + I[e];
1054
+ }
1055
+ var B = /* @__PURE__ */ new Float32Array(1), V = new Uint32Array(B.buffer);
1056
+ function oe(e, t) {
1057
+ switch (e.type) {
1058
+ case "boolean": return typeof t == "boolean" ? I[Number(t)] : void 0;
1059
+ case "string": return t === null ? I[0] : typeof t == "string" && t.length ? z(t.length) + t : void 0;
1060
+ case "float32": return typeof t != "number" || !Number.isFinite(t) || Math.fround(t) !== t ? void 0 : (B[0] = t, z(V[0]));
1061
+ default: {
1062
+ let n = se(e, t);
1063
+ return n === void 0 ? void 0 : z(n);
1064
+ }
1065
+ }
1066
+ }
1067
+ function se(e, t) {
1068
+ if (typeof t != "number") return;
1069
+ let n = Math.round((t - (e.offset ?? 0)) * 10 ** (e.decimals ?? 0) / (e.step ?? 1));
1070
+ if (!Number.isSafeInteger(n) || H(e, n) !== t) return;
1071
+ if (e.type === "uint") return n >= 0 ? n : void 0;
1072
+ let r = n >= 0 ? n * 2 : -n * 2 - 1;
1073
+ return Number.isSafeInteger(r) ? r : void 0;
1074
+ }
1075
+ function H(e, t) {
1076
+ return t * (e.step ?? 1) / 10 ** (e.decimals ?? 0) + (e.offset ?? 0);
1077
+ }
1078
+ function U(e, t) {
1079
+ switch (e.type) {
1080
+ case "boolean": return t !== 0;
1081
+ case "float32": return V[0] = t, B[0];
1082
+ case "uint": return H(e, t);
1083
+ default: return H(e, t % 2 == 0 ? t / 2 : -(t + 1) / 2);
1084
+ }
1085
+ }
1086
+ function W(e) {
1087
+ return e.types === void 0 ? [e.type] : e.types;
1088
+ }
1089
+ var G = class {
1090
+ encoders = /* @__PURE__ */ new Map();
1091
+ used = /* @__PURE__ */ new Set();
1092
+ constructor(e) {
1093
+ let t = 0;
1094
+ for (let n of e) {
1095
+ let e = {
1096
+ key: t,
1097
+ definition: n,
1098
+ indices: new Map(n.properties.map((e, t) => [e.name, t]))
1099
+ };
1100
+ for (let r of W(n)) {
1101
+ if (this.encoders.has(r)) throw Error(`Duplicate compressed entity definition for ${r}`);
1102
+ this.encoders.set(r, {
1103
+ prefix: z(t++),
1104
+ group: e
1105
+ });
1106
+ }
1107
+ }
1108
+ }
1109
+ get entityDefinitions() {
1110
+ let e = {};
1111
+ for (let t of this.used) e[t.key] = t.definition;
1112
+ return e;
1113
+ }
1114
+ compress(e) {
1115
+ let t = e.type === void 0 ? void 0 : this.encoders.get(e.type), n = t && this.encode(t, e);
1116
+ return !t || n === void 0 ? e : (this.used.add(t.group), n);
1117
+ }
1118
+ compressAll(e) {
1119
+ let t = e.map((e) => this.compress(e));
1120
+ return {
1121
+ entityDefinitions: this.entityDefinitions,
1122
+ entities: t
1123
+ };
1124
+ }
1125
+ encode(e, t) {
1126
+ let n = [];
1127
+ for (let [r, i] of Object.entries(t)) {
1128
+ if (r === "type" || i === void 0) continue;
1129
+ let t = e.group.indices.get(r);
1130
+ if (t === void 0) return;
1131
+ let a = oe(e.group.definition.properties[t], i);
1132
+ if (a === void 0) return;
1133
+ n[t] = a;
1134
+ }
1135
+ let r = e.prefix;
1136
+ for (let e = 0; e < n.length; e++) r += n[e] ?? F;
1137
+ return r;
1138
+ }
1139
+ };
1140
+ function ce(e, t) {
1141
+ return new G(t).compressAll(e);
1142
+ }
1143
+ var K = /* @__PURE__ */ new WeakMap();
1144
+ function le(e) {
1145
+ let t = K.get(e);
1146
+ if (t) return t;
1147
+ t = /* @__PURE__ */ new Map();
1148
+ for (let [n, r] of Object.entries(e)) {
1149
+ let e = W(r);
1150
+ for (let i = 0; i < e.length; i++) {
1151
+ if (t.has(Number(n) + i)) throw Error(`Compressed entity definitions overlap at key ${Number(n) + i}`);
1152
+ t.set(Number(n) + i, {
1153
+ type: e[i],
1154
+ properties: r.properties
1155
+ });
1156
+ }
1157
+ }
1158
+ return K.set(e, t), t;
1159
+ }
1160
+ function q(e, t) {
1161
+ let n = 0, r = () => {
1162
+ if (e[n] === F) {
1163
+ n++;
1164
+ return;
1165
+ }
1166
+ let t = 0, r = 1;
1167
+ for (; n < e.length;) {
1168
+ let i = e.charCodeAt(n++), a = i < 128 ? R[i] : -1;
1169
+ if (a < 0) throw Error(`Invalid compressed entity ${e}`);
1170
+ if (a < P) return t + a * r;
1171
+ t += (a - P) * r, r *= P;
1172
+ }
1173
+ throw Error(`Truncated compressed entity ${e}`);
1174
+ }, i = r(), a = i === void 0 ? void 0 : le(t).get(i);
1175
+ if (!a) throw Error(`No compressed entity definition for ${e}`);
1176
+ let o = { type: a.type };
1177
+ for (let t = 0; n < e.length; t++) {
1178
+ let i = a.properties[t];
1179
+ if (!i) throw Error(`Compressed entity ${e} has more values than ${a.type} defines`);
1180
+ let s = r();
1181
+ if (s !== void 0) {
1182
+ if (i.type !== "string") o[i.name] = U(i, s);
1183
+ else if (s === 0) o[i.name] = null;
1184
+ else {
1185
+ if (n + s > e.length) throw Error(`Truncated compressed entity ${e}`);
1186
+ o[i.name] = e.slice(n, n += s);
1187
+ }
1188
+ }
1189
+ }
1190
+ return o;
1191
+ }
1192
+ function J(e, t) {
1193
+ return e.map((e) => {
1194
+ if (typeof e != "string") return e;
1195
+ if (!t) throw Error("Compressed entities need entityDefinitions to load");
1196
+ return q(e, t);
1197
+ });
1198
+ }
1199
+ //#endregion
1200
+ //#region src/scheduling/default-scheduler.ts
1201
+ var Y = class {
1049
1202
  update(e, t) {
1050
1203
  let n = null;
1051
1204
  return e.systems.forEach((r) => {
@@ -1068,7 +1221,7 @@ var M = class extends A {
1068
1221
  });
1069
1222
  }), { lastSystemError: n };
1070
1223
  }
1071
- }, V = b, H = 1e4, U = class extends k.default {
1224
+ }, ue = _, X = 1e4, de = class extends C.default {
1072
1225
  heap;
1073
1226
  constantStrings;
1074
1227
  eidCounter;
@@ -1096,7 +1249,7 @@ var M = class extends A {
1096
1249
  };
1097
1250
  clearing = !1;
1098
1251
  constructor(e, t = {}) {
1099
- super(), this.scheduler = t.scheduler ?? new B(), this.heap = new y({ bufferSize: t.heapSize ?? V }), this.constantStrings = new _(this.heap), this.eidCounter = this.heap.allocUI32(1), this.heap.addOnGrowBufferHandlers((e) => this.emit("grow-buffer", e));
1252
+ super(), this.scheduler = t.scheduler ?? new Y(), this.heap = new ne({ bufferSize: t.heapSize ?? ue }), this.constantStrings = new h(this.heap), this.eidCounter = this.heap.allocUI32(1), this.heap.addOnGrowBufferHandlers((e) => this.emit("grow-buffer", e));
1100
1253
  let n = {
1101
1254
  ...e,
1102
1255
  entity: i
@@ -1105,10 +1258,10 @@ var M = class extends A {
1105
1258
  let t = n[e];
1106
1259
  r[e] = {
1107
1260
  ...t,
1108
- memoryComponent: new v(this.heap, t.type, t.size)
1261
+ memoryComponent: new g(this.heap, t.type, t.size)
1109
1262
  };
1110
1263
  }
1111
- this.registry = r, this.factory = t.factory ?? new z(), this.factory.setWorld(this);
1264
+ this.registry = r, this.factory = t.factory ?? new N(), this.factory.setWorld(this);
1112
1265
  }
1113
1266
  allocateEid() {
1114
1267
  return Atomics.add(this.eidCounter.data, 0, 1) + 1;
@@ -1125,7 +1278,7 @@ var M = class extends A {
1125
1278
  this.heap.buffers[e.bufferPosition] === void 0 && this.heap.addSharedBuffer(e), this.emit("grow-buffer", e);
1126
1279
  }
1127
1280
  get needsSpareBuffer() {
1128
- return this.systems.some((e) => e instanceof L && e.isWorkerThread && (!!e.options.createsEntities || !!e.options.addsComponents));
1281
+ return this.systems.some((e) => e instanceof j && e.isWorkerThread && (!!e.options.createsEntities || !!e.options.addsComponents));
1129
1282
  }
1130
1283
  async init() {
1131
1284
  await Promise.all(this.systems.map((e) => e.init()).filter((e) => e instanceof Promise));
@@ -1174,14 +1327,14 @@ var M = class extends A {
1174
1327
  for (let e of Object.keys(this.factory.classes)) this.constantStrings.getOrCreate(e);
1175
1328
  this.isBulkLoading = !0;
1176
1329
  try {
1177
- let t = e.entities.map((e) => this.loadEntity(e, !1));
1330
+ let t = ("entityDefinitions" in e ? J(e.entities, e.entityDefinitions) : e.entities).map((e) => this.loadEntity(e, !1));
1178
1331
  for (let e of t) e.finishLoading(), this.emit("entity-added", e), e.on("death", () => {
1179
1332
  this.onEntityDied(e);
1180
1333
  });
1181
1334
  } finally {
1182
1335
  this.isBulkLoading = !1;
1183
1336
  }
1184
- let t = W(this.entities.values());
1337
+ let t = fe(this.entities.values());
1185
1338
  return this.systems.forEach((e) => e.addEntities(t)), this.gameTime = e.gameTime ?? 0, this.playerTime = e.playerTime ?? 0, this.timeScale = e.timeScale ?? 1, this.finishLoadingSystems();
1186
1339
  }
1187
1340
  async clear() {
@@ -1253,9 +1406,9 @@ var M = class extends A {
1253
1406
  }
1254
1407
  checkFreeBufferTimeout(e) {
1255
1408
  let t = this.activeFreeBuffer;
1256
- if (t.waitingSystems.size !== 0 && (t.waitElapsed += e, t.waitElapsed >= H)) {
1409
+ if (t.waitingSystems.size !== 0 && (t.waitElapsed += e, t.waitElapsed >= X)) {
1257
1410
  let e = Array.from(t.waitingSystems).map((e) => e.name).join(", ");
1258
- console.warn(`shared-memory-ecs: deferred component free waited over ${H}ms on system(s): ${e}; freeing anyway`), t.waitingSystems.clear(), this.processFreeBuffers();
1411
+ console.warn(`shared-memory-ecs: deferred component free waited over ${X}ms on system(s): ${e}; freeing anyway`), t.waitingSystems.clear(), this.processFreeBuffers();
1259
1412
  }
1260
1413
  }
1261
1414
  addSystem(e) {
@@ -1303,12 +1456,12 @@ var M = class extends A {
1303
1456
  }
1304
1457
  addEntityToEntityWorkerSystem(e, t) {
1305
1458
  this.isBulkLoading || this.systems.forEach((n) => {
1306
- (n instanceof N && n.options.components?.includes(t) || n instanceof L && this.componentAffectsEntityWorkerSystem(n, t)) && n.checkAddEntity(e);
1459
+ (n instanceof D && n.options.components?.includes(t) || n instanceof j && this.componentAffectsEntityWorkerSystem(n, t)) && n.checkAddEntity(e);
1307
1460
  });
1308
1461
  }
1309
1462
  removeEntityFromEntityWorkerSystem(e, t) {
1310
1463
  this.isBulkLoading || this.systems.forEach((n) => {
1311
- n instanceof N && n.options.components?.includes(t) ? n.removeEntity(e) : n instanceof L && this.componentAffectsEntityWorkerSystem(n, t) && n.checkAddEntity(e);
1464
+ n instanceof D && n.options.components?.includes(t) ? n.removeEntity(e) : n instanceof j && this.componentAffectsEntityWorkerSystem(n, t) && n.checkAddEntity(e);
1312
1465
  });
1313
1466
  }
1314
1467
  componentAffectsEntityWorkerSystem(e, t) {
@@ -1321,7 +1474,7 @@ var M = class extends A {
1321
1474
  }), this.scheduler.destroy?.(this), !0);
1322
1475
  }
1323
1476
  };
1324
- function W(e) {
1477
+ function fe(e) {
1325
1478
  let t = {
1326
1479
  entities: [],
1327
1480
  groupIndexes: [],
@@ -1335,7 +1488,7 @@ function W(e) {
1335
1488
  }
1336
1489
  //#endregion
1337
1490
  //#region src/scheduling/conflict-scheduler.ts
1338
- var G = class {
1491
+ var pe = class {
1339
1492
  compiled = Object.freeze({
1340
1493
  order: Object.freeze([]),
1341
1494
  batches: Object.freeze([])
@@ -1418,7 +1571,7 @@ var G = class {
1418
1571
  }, 0);
1419
1572
  }
1420
1573
  isSliced(e) {
1421
- return e.system instanceof M && e.system.remainingInstancesToRun.length > 0;
1574
+ return e.system instanceof E && e.system.remainingInstancesToRun.length > 0;
1422
1575
  }
1423
1576
  reset() {
1424
1577
  this.continuationTimer !== void 0 && (clearTimeout(this.continuationTimer), this.continuationTimer = void 0);
@@ -1586,27 +1739,27 @@ var G = class {
1586
1739
  };
1587
1740
  //#endregion
1588
1741
  //#region src/entity-class.ts
1589
- function K(e, t) {
1742
+ function me(e, t) {
1590
1743
  return t;
1591
1744
  }
1592
- function q(e, t) {
1745
+ function Z(e, t) {
1593
1746
  return t;
1594
1747
  }
1595
1748
  //#endregion
1596
1749
  //#region src/actions/kill-entity.ts
1597
- function J(e) {
1750
+ function he(e) {
1598
1751
  e.components.entity.dead = !0, e.emit("death");
1599
1752
  }
1600
1753
  //#endregion
1601
1754
  //#region src/performance-timing.ts
1602
- var Y = 1e3, X = {
1755
+ var ge = 1e3, Q = {
1603
1756
  avg: 0,
1604
1757
  min: 0,
1605
1758
  max: 0,
1606
1759
  samples: 0
1607
1760
  };
1608
- function Z(e) {
1609
- if (!e.length) return { ...X };
1761
+ function $(e) {
1762
+ if (!e.length) return { ...Q };
1610
1763
  let t = 0, n = Infinity, r = 0;
1611
1764
  for (let i of e) t += i, i < n && (n = i), i > r && (r = i);
1612
1765
  return {
@@ -1616,13 +1769,13 @@ function Z(e) {
1616
1769
  samples: e.length
1617
1770
  };
1618
1771
  }
1619
- var Q = class extends k.default {
1772
+ var _e = class extends C.default {
1620
1773
  world;
1621
1774
  ticksBetweenUpdates;
1622
1775
  stats = {
1623
- update: { ...X },
1776
+ update: { ...Q },
1624
1777
  systems: [],
1625
- events: { ...X }
1778
+ events: { ...Q }
1626
1779
  };
1627
1780
  autoUpdate;
1628
1781
  ticks = 0;
@@ -1640,9 +1793,9 @@ var Q = class extends k.default {
1640
1793
  this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
1641
1794
  e.run = [], e.events = [], e.eventStart = -1, e.pendingRun = 0, e.pendingEvents = 0;
1642
1795
  }), this.stats = {
1643
- update: { ...X },
1796
+ update: { ...Q },
1644
1797
  systems: [],
1645
- events: { ...X }
1798
+ events: { ...Q }
1646
1799
  };
1647
1800
  }
1648
1801
  destroy() {
@@ -1687,21 +1840,21 @@ var Q = class extends k.default {
1687
1840
  let t = this.systemTimings.get(e.name);
1688
1841
  return {
1689
1842
  name: e.name,
1690
- run: Z(t?.run ?? []),
1691
- events: Z(t?.events ?? [])
1843
+ run: $(t?.run ?? []),
1844
+ events: $(t?.events ?? [])
1692
1845
  };
1693
- }), t = { ...X };
1846
+ }), t = { ...Q };
1694
1847
  return e.forEach((e) => {
1695
1848
  t.avg += e.events.avg, t.min += e.events.min, t.max += e.events.max, t.samples += e.events.samples;
1696
1849
  }), this.stats = {
1697
- update: Z(this.updateTimes),
1850
+ update: $(this.updateTimes),
1698
1851
  systems: e,
1699
1852
  events: t
1700
1853
  }, this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
1701
1854
  e.run = [], e.events = [];
1702
1855
  }), this.emit("stats-updated", this.stats), this.stats;
1703
1856
  }
1704
- }, $ = class extends L {
1857
+ }, ve = class extends j {
1705
1858
  constructor(e, t) {
1706
1859
  super(e, {
1707
1860
  ...t,
@@ -1717,6 +1870,6 @@ var Q = class extends k.default {
1717
1870
  }
1718
1871
  };
1719
1872
  //#endregion
1720
- export { R as BaseEntity, U as BaseWorld, n as CLASS_INDEX, f as Component, G as ConflictScheduler, _ as ConstantStringCache, c as DEAD_INDEX, Y as DEFAULT_TICKS_BETWEEN_UPDATES, B as DefaultScheduler, z as EntityFactory, N as EntitySystem, F as EntitySystemWebWorker, L as EntityWorkerSystem, M as IterableSystem, v as MemoryComponent, Q as PerformanceTiming, g as STATIC_INDEX, A as System, r as TYPE_INDEX, P as WebWorker, $ as WorkerSystem, t as addComponentWorker, p as createEntitySystemWorker, d as createEntityWorker, h as createSystemWorker, K as defineEntityClasses, q as defineEntityConfigs, i as entityDefinition, J as killEntity, m as killEntityWorker, s as removeComponentWorker };
1873
+ export { M as BaseEntity, de as BaseWorld, n as CLASS_INDEX, f as Component, pe as ConflictScheduler, h as ConstantStringCache, c as DEAD_INDEX, ge as DEFAULT_TICKS_BETWEEN_UPDATES, Y as DefaultScheduler, G as EntityCompressor, N as EntityFactory, D as EntitySystem, k as EntitySystemWebWorker, j as EntityWorkerSystem, E as IterableSystem, g as MemoryComponent, _e as PerformanceTiming, te as STATIC_INDEX, w as System, r as TYPE_INDEX, O as WebWorker, ve as WorkerSystem, t as addComponentWorker, ce as compressEntities, p as createEntitySystemWorker, d as createEntityWorker, ee as createSystemWorker, J as decompressEntities, q as decompressEntity, me as defineEntityClasses, Z as defineEntityConfigs, i as entityDefinition, he as killEntity, m as killEntityWorker, s as removeComponentWorker };
1721
1874
 
1722
1875
  //# sourceMappingURL=index.js.map