@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 +46 -0
- package/dist/entity-compression.d.ts +40 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +214 -61
- package/dist/index.js.map +1 -1
- package/dist/world.d.ts +3 -1
- package/package.json +3 -1
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
|
|
2
|
-
import
|
|
3
|
-
import { MAX_BYTE_OFFSET_LENGTH as
|
|
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
|
|
6
|
-
if (t && typeof t == "object" || typeof t == "function") for (var i =
|
|
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 =
|
|
8
|
+
enumerable: !(r = re(t, s)) || r.enumerable
|
|
9
9
|
});
|
|
10
10
|
return e;
|
|
11
|
-
},
|
|
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__ */
|
|
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),
|
|
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
|
|
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
|
|
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
|
-
},
|
|
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
|
-
|
|
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
|
-
},
|
|
303
|
+
}, O = class {
|
|
304
304
|
onmessage(e, t = []) {}
|
|
305
|
-
},
|
|
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
|
-
},
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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 !==
|
|
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
|
|
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
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
|
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
|
|
1261
|
+
memoryComponent: new g(this.heap, t.type, t.size)
|
|
1109
1262
|
};
|
|
1110
1263
|
}
|
|
1111
|
-
this.registry = r, this.factory = t.factory ?? new
|
|
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
|
|
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 =
|
|
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 >=
|
|
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 ${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1742
|
+
function me(e, t) {
|
|
1590
1743
|
return t;
|
|
1591
1744
|
}
|
|
1592
|
-
function
|
|
1745
|
+
function Z(e, t) {
|
|
1593
1746
|
return t;
|
|
1594
1747
|
}
|
|
1595
1748
|
//#endregion
|
|
1596
1749
|
//#region src/actions/kill-entity.ts
|
|
1597
|
-
function
|
|
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
|
|
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
|
|
1609
|
-
if (!e.length) return { ...
|
|
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
|
|
1772
|
+
var _e = class extends C.default {
|
|
1620
1773
|
world;
|
|
1621
1774
|
ticksBetweenUpdates;
|
|
1622
1775
|
stats = {
|
|
1623
|
-
update: { ...
|
|
1776
|
+
update: { ...Q },
|
|
1624
1777
|
systems: [],
|
|
1625
|
-
events: { ...
|
|
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: { ...
|
|
1796
|
+
update: { ...Q },
|
|
1644
1797
|
systems: [],
|
|
1645
|
-
events: { ...
|
|
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:
|
|
1691
|
-
events:
|
|
1843
|
+
run: $(t?.run ?? []),
|
|
1844
|
+
events: $(t?.events ?? [])
|
|
1692
1845
|
};
|
|
1693
|
-
}), t = { ...
|
|
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:
|
|
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
|
-
},
|
|
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 {
|
|
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
|