@aethervtt/shard-core 0.0.1

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 (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/dist/ecs/commands.d.ts +35 -0
  4. package/dist/ecs/commands.js +96 -0
  5. package/dist/ecs/entity.d.ts +11 -0
  6. package/dist/ecs/entity.js +12 -0
  7. package/dist/ecs/events.d.ts +34 -0
  8. package/dist/ecs/events.js +65 -0
  9. package/dist/ecs/hierarchy.d.ts +7 -0
  10. package/dist/ecs/hierarchy.js +29 -0
  11. package/dist/ecs/index.d.ts +8 -0
  12. package/dist/ecs/index.js +38 -0
  13. package/dist/ecs/observers.d.ts +40 -0
  14. package/dist/ecs/observers.js +27 -0
  15. package/dist/ecs/query.d.ts +44 -0
  16. package/dist/ecs/query.js +67 -0
  17. package/dist/ecs/table.d.ts +91 -0
  18. package/dist/ecs/table.js +286 -0
  19. package/dist/ecs/world.d.ts +127 -0
  20. package/dist/ecs/world.js +513 -0
  21. package/dist/error.d.ts +26 -0
  22. package/dist/error.js +29 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.js +9 -0
  25. package/dist/json.d.ts +15 -0
  26. package/dist/json.js +22 -0
  27. package/dist/math/aabb.d.ts +13 -0
  28. package/dist/math/aabb.js +78 -0
  29. package/dist/math/affine.d.ts +28 -0
  30. package/dist/math/affine.js +159 -0
  31. package/dist/math/affine64.d.ts +11 -0
  32. package/dist/math/affine64.js +58 -0
  33. package/dist/math/frustum.d.ts +11 -0
  34. package/dist/math/frustum.js +59 -0
  35. package/dist/math/hash.d.ts +14 -0
  36. package/dist/math/hash.js +38 -0
  37. package/dist/math/index.d.ts +14 -0
  38. package/dist/math/index.js +33 -0
  39. package/dist/math/mat3.d.ts +6 -0
  40. package/dist/math/mat3.js +37 -0
  41. package/dist/math/mat4.d.ts +23 -0
  42. package/dist/math/mat4.js +224 -0
  43. package/dist/math/quat.d.ts +22 -0
  44. package/dist/math/quat.js +233 -0
  45. package/dist/math/ray.d.ts +10 -0
  46. package/dist/math/ray.js +54 -0
  47. package/dist/math/rng.d.ts +41 -0
  48. package/dist/math/rng.js +102 -0
  49. package/dist/math/types.d.ts +8 -0
  50. package/dist/math/types.js +4 -0
  51. package/dist/math/vec2.d.ts +11 -0
  52. package/dist/math/vec2.js +52 -0
  53. package/dist/math/vec3.d.ts +23 -0
  54. package/dist/math/vec3.js +135 -0
  55. package/dist/math/vec4.d.ts +8 -0
  56. package/dist/math/vec4.js +47 -0
  57. package/dist/scheduler/index.d.ts +3 -0
  58. package/dist/scheduler/index.js +39 -0
  59. package/dist/scheduler/profiler.d.ts +19 -0
  60. package/dist/scheduler/profiler.js +44 -0
  61. package/dist/scheduler/schedule.d.ts +52 -0
  62. package/dist/scheduler/schedule.js +235 -0
  63. package/dist/scheduler/system.d.ts +74 -0
  64. package/dist/scheduler/system.js +106 -0
  65. package/dist/schema/color.d.ts +7 -0
  66. package/dist/schema/color.js +34 -0
  67. package/dist/schema/component.d.ts +71 -0
  68. package/dist/schema/component.js +120 -0
  69. package/dist/schema/field.d.ts +145 -0
  70. package/dist/schema/field.js +591 -0
  71. package/dist/schema/index.d.ts +6 -0
  72. package/dist/schema/index.js +40 -0
  73. package/dist/schema/names.d.ts +27 -0
  74. package/dist/schema/names.js +39 -0
  75. package/dist/schema/registry.d.ts +38 -0
  76. package/dist/schema/registry.js +58 -0
  77. package/dist/schema/resource.d.ts +48 -0
  78. package/dist/schema/resource.js +79 -0
  79. package/dist/test-env.d.ts +31 -0
  80. package/dist/test-env.js +37 -0
  81. package/package.json +38 -0
@@ -0,0 +1,11 @@
1
+ import type { Readable, Writable } from './types.js';
2
+ export declare const create: (x?: number, y?: number) => Float32Array;
3
+ export declare function set<T extends Writable>(out: T, x: number, y: number): T;
4
+ export declare function copy<T extends Writable>(out: T, a: Readable): T;
5
+ export declare function add<T extends Writable>(out: T, a: Readable, b: Readable): T;
6
+ export declare function sub<T extends Writable>(out: T, a: Readable, b: Readable): T;
7
+ export declare function scale<T extends Writable>(out: T, a: Readable, s: number): T;
8
+ export declare const dot: (a: Readable, b: Readable) => number;
9
+ export declare const length: (a: Readable) => number;
10
+ export declare function normalize<T extends Writable>(out: T, a: Readable): T;
11
+ export declare function lerp<T extends Writable>(out: T, a: Readable, b: Readable, t: number): T;
@@ -0,0 +1,52 @@
1
+ const create = (x = 0, y = 0) => new Float32Array([x, y]);
2
+ function set(out, x, y) {
3
+ out[0] = x;
4
+ out[1] = y;
5
+ return out;
6
+ }
7
+ function copy(out, a) {
8
+ out[0] = a[0];
9
+ out[1] = a[1];
10
+ return out;
11
+ }
12
+ function add(out, a, b) {
13
+ out[0] = a[0] + b[0];
14
+ out[1] = a[1] + b[1];
15
+ return out;
16
+ }
17
+ function sub(out, a, b) {
18
+ out[0] = a[0] - b[0];
19
+ out[1] = a[1] - b[1];
20
+ return out;
21
+ }
22
+ function scale(out, a, s) {
23
+ out[0] = a[0] * s;
24
+ out[1] = a[1] * s;
25
+ return out;
26
+ }
27
+ const dot = (a, b) => a[0] * b[0] + a[1] * b[1];
28
+ const length = (a) => Math.sqrt(a[0] * a[0] + a[1] * a[1]);
29
+ function normalize(out, a) {
30
+ const len = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
31
+ const inv = len > 0 ? 1 / len : 0;
32
+ out[0] = a[0] * inv;
33
+ out[1] = a[1] * inv;
34
+ return out;
35
+ }
36
+ function lerp(out, a, b, t) {
37
+ out[0] = a[0] + (b[0] - a[0]) * t;
38
+ out[1] = a[1] + (b[1] - a[1]) * t;
39
+ return out;
40
+ }
41
+ export {
42
+ add,
43
+ copy,
44
+ create,
45
+ dot,
46
+ length,
47
+ lerp,
48
+ normalize,
49
+ scale,
50
+ set,
51
+ sub
52
+ };
@@ -0,0 +1,23 @@
1
+ import { type Readable, type Writable } from './types.js';
2
+ export declare const create: (x?: number, y?: number, z?: number) => Float32Array;
3
+ export declare function set<T extends Writable>(out: T, x: number, y: number, z: number): T;
4
+ export declare function copy<T extends Writable>(out: T, a: Readable): T;
5
+ export declare function add<T extends Writable>(out: T, a: Readable, b: Readable): T;
6
+ export declare function sub<T extends Writable>(out: T, a: Readable, b: Readable): T;
7
+ export declare function mul<T extends Writable>(out: T, a: Readable, b: Readable): T;
8
+ export declare function scale<T extends Writable>(out: T, a: Readable, s: number): T;
9
+ /** out = a + b * s */
10
+ export declare function scaleAndAdd<T extends Writable>(out: T, a: Readable, b: Readable, s: number): T;
11
+ export declare function negate<T extends Writable>(out: T, a: Readable): T;
12
+ export declare const dot: (a: Readable, b: Readable) => number;
13
+ export declare function cross<T extends Writable>(out: T, a: Readable, b: Readable): T;
14
+ export declare const lengthSq: (a: Readable) => number;
15
+ export declare const length: (a: Readable) => number;
16
+ export declare function distance(a: Readable, b: Readable): number;
17
+ export declare function normalize<T extends Writable>(out: T, a: Readable): T;
18
+ export declare function lerp<T extends Writable>(out: T, a: Readable, b: Readable, t: number): T;
19
+ /** Rotates `a` by unit quaternion `q`. */
20
+ export declare function transformQuat<T extends Writable>(out: T, a: Readable, q: Readable): T;
21
+ /** Transforms a point by a column-major mat4, with perspective divide. */
22
+ export declare function transformMat4<T extends Writable>(out: T, a: Readable, m: Readable): T;
23
+ export declare function equals(a: Readable, b: Readable, epsilon?: number): boolean;
@@ -0,0 +1,135 @@
1
+ import { EPSILON } from "./types.js";
2
+ const create = (x = 0, y = 0, z = 0) => new Float32Array([x, y, z]);
3
+ function set(out, x, y, z) {
4
+ out[0] = x;
5
+ out[1] = y;
6
+ out[2] = z;
7
+ return out;
8
+ }
9
+ function copy(out, a) {
10
+ out[0] = a[0];
11
+ out[1] = a[1];
12
+ out[2] = a[2];
13
+ return out;
14
+ }
15
+ function add(out, a, b) {
16
+ out[0] = a[0] + b[0];
17
+ out[1] = a[1] + b[1];
18
+ out[2] = a[2] + b[2];
19
+ return out;
20
+ }
21
+ function sub(out, a, b) {
22
+ out[0] = a[0] - b[0];
23
+ out[1] = a[1] - b[1];
24
+ out[2] = a[2] - b[2];
25
+ return out;
26
+ }
27
+ function mul(out, a, b) {
28
+ out[0] = a[0] * b[0];
29
+ out[1] = a[1] * b[1];
30
+ out[2] = a[2] * b[2];
31
+ return out;
32
+ }
33
+ function scale(out, a, s) {
34
+ out[0] = a[0] * s;
35
+ out[1] = a[1] * s;
36
+ out[2] = a[2] * s;
37
+ return out;
38
+ }
39
+ function scaleAndAdd(out, a, b, s) {
40
+ out[0] = a[0] + b[0] * s;
41
+ out[1] = a[1] + b[1] * s;
42
+ out[2] = a[2] + b[2] * s;
43
+ return out;
44
+ }
45
+ function negate(out, a) {
46
+ out[0] = -a[0];
47
+ out[1] = -a[1];
48
+ out[2] = -a[2];
49
+ return out;
50
+ }
51
+ const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
52
+ function cross(out, a, b) {
53
+ const ax = a[0];
54
+ const ay = a[1];
55
+ const az = a[2];
56
+ const bx = b[0];
57
+ const by = b[1];
58
+ const bz = b[2];
59
+ out[0] = ay * bz - az * by;
60
+ out[1] = az * bx - ax * bz;
61
+ out[2] = ax * by - ay * bx;
62
+ return out;
63
+ }
64
+ const lengthSq = (a) => a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
65
+ const length = (a) => Math.sqrt(lengthSq(a));
66
+ function distance(a, b) {
67
+ const x = a[0] - b[0];
68
+ const y = a[1] - b[1];
69
+ const z = a[2] - b[2];
70
+ return Math.sqrt(x * x + y * y + z * z);
71
+ }
72
+ function normalize(out, a) {
73
+ const len = length(a);
74
+ const inv = len > 0 ? 1 / len : 0;
75
+ out[0] = a[0] * inv;
76
+ out[1] = a[1] * inv;
77
+ out[2] = a[2] * inv;
78
+ return out;
79
+ }
80
+ function lerp(out, a, b, t) {
81
+ out[0] = a[0] + (b[0] - a[0]) * t;
82
+ out[1] = a[1] + (b[1] - a[1]) * t;
83
+ out[2] = a[2] + (b[2] - a[2]) * t;
84
+ return out;
85
+ }
86
+ function transformQuat(out, a, q) {
87
+ const qx = q[0];
88
+ const qy = q[1];
89
+ const qz = q[2];
90
+ const qw = q[3];
91
+ const x = a[0];
92
+ const y = a[1];
93
+ const z = a[2];
94
+ const tx = 2 * (qy * z - qz * y);
95
+ const ty = 2 * (qz * x - qx * z);
96
+ const tz = 2 * (qx * y - qy * x);
97
+ out[0] = x + qw * tx + (qy * tz - qz * ty);
98
+ out[1] = y + qw * ty + (qz * tx - qx * tz);
99
+ out[2] = z + qw * tz + (qx * ty - qy * tx);
100
+ return out;
101
+ }
102
+ function transformMat4(out, a, m) {
103
+ const x = a[0];
104
+ const y = a[1];
105
+ const z = a[2];
106
+ const w = m[3] * x + m[7] * y + m[11] * z + m[15] || 1;
107
+ out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
108
+ out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
109
+ out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
110
+ return out;
111
+ }
112
+ function equals(a, b, epsilon = EPSILON) {
113
+ return Math.abs(a[0] - b[0]) <= epsilon && Math.abs(a[1] - b[1]) <= epsilon && Math.abs(a[2] - b[2]) <= epsilon;
114
+ }
115
+ export {
116
+ add,
117
+ copy,
118
+ create,
119
+ cross,
120
+ distance,
121
+ dot,
122
+ equals,
123
+ length,
124
+ lengthSq,
125
+ lerp,
126
+ mul,
127
+ negate,
128
+ normalize,
129
+ scale,
130
+ scaleAndAdd,
131
+ set,
132
+ sub,
133
+ transformMat4,
134
+ transformQuat
135
+ };
@@ -0,0 +1,8 @@
1
+ import type { Readable, Writable } from './types.js';
2
+ export declare const create: (x?: number, y?: number, z?: number, w?: number) => Float32Array;
3
+ export declare function set<T extends Writable>(out: T, x: number, y: number, z: number, w: number): T;
4
+ export declare function copy<T extends Writable>(out: T, a: Readable): T;
5
+ export declare function scale<T extends Writable>(out: T, a: Readable, s: number): T;
6
+ export declare const dot: (a: Readable, b: Readable) => number;
7
+ export declare function lerp<T extends Writable>(out: T, a: Readable, b: Readable, t: number): T;
8
+ export declare function transformMat4<T extends Writable>(out: T, a: Readable, m: Readable): T;
@@ -0,0 +1,47 @@
1
+ const create = (x = 0, y = 0, z = 0, w = 0) => new Float32Array([x, y, z, w]);
2
+ function set(out, x, y, z, w) {
3
+ out[0] = x;
4
+ out[1] = y;
5
+ out[2] = z;
6
+ out[3] = w;
7
+ return out;
8
+ }
9
+ function copy(out, a) {
10
+ out[0] = a[0];
11
+ out[1] = a[1];
12
+ out[2] = a[2];
13
+ out[3] = a[3];
14
+ return out;
15
+ }
16
+ function scale(out, a, s) {
17
+ out[0] = a[0] * s;
18
+ out[1] = a[1] * s;
19
+ out[2] = a[2] * s;
20
+ out[3] = a[3] * s;
21
+ return out;
22
+ }
23
+ const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
24
+ function lerp(out, a, b, t) {
25
+ for (let i = 0; i < 4; i++) out[i] = a[i] + (b[i] - a[i]) * t;
26
+ return out;
27
+ }
28
+ function transformMat4(out, a, m) {
29
+ const x = a[0];
30
+ const y = a[1];
31
+ const z = a[2];
32
+ const w = a[3];
33
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
34
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
35
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
36
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
37
+ return out;
38
+ }
39
+ export {
40
+ copy,
41
+ create,
42
+ dot,
43
+ lerp,
44
+ scale,
45
+ set,
46
+ transformMat4
47
+ };
@@ -0,0 +1,3 @@
1
+ export { Profiler, ProfilerResource, type SystemTiming } from './profiler.js';
2
+ export { defineSchedule, First, FixedUpdate, Last, PostUpdate, PreUpdate, Schedule, type ScheduleLabel, type ScheduleRunOptions, Startup, type SystemDescription, Update, } from './schedule.js';
3
+ export { type Condition, condition, conditionLabel, defineSystem, defineSystemSet, type Label, not, SystemConfig, type SystemContext, type SystemDef, type SystemSetConfig, type SystemSetDef, type SystemSpec, } from './system.js';
@@ -0,0 +1,39 @@
1
+ import { Profiler, ProfilerResource } from "./profiler.js";
2
+ import {
3
+ defineSchedule,
4
+ First,
5
+ FixedUpdate,
6
+ Last,
7
+ PostUpdate,
8
+ PreUpdate,
9
+ Schedule,
10
+ Startup,
11
+ Update
12
+ } from "./schedule.js";
13
+ import {
14
+ condition,
15
+ conditionLabel,
16
+ defineSystem,
17
+ defineSystemSet,
18
+ not,
19
+ SystemConfig
20
+ } from "./system.js";
21
+ export {
22
+ First,
23
+ FixedUpdate,
24
+ Last,
25
+ PostUpdate,
26
+ PreUpdate,
27
+ Profiler,
28
+ ProfilerResource,
29
+ Schedule,
30
+ Startup,
31
+ SystemConfig,
32
+ Update,
33
+ condition,
34
+ conditionLabel,
35
+ defineSchedule,
36
+ defineSystem,
37
+ defineSystemSet,
38
+ not
39
+ };
@@ -0,0 +1,19 @@
1
+ export interface SystemTiming {
2
+ /** Most recent run, in ms. */
3
+ last: number;
4
+ /** Mean over the window, in ms. */
5
+ avg: number;
6
+ max: number;
7
+ /** Number of samples in the window. */
8
+ samples: number;
9
+ }
10
+ /** Per-system CPU time over the last `window` runs, in a ring buffer. */
11
+ export declare class Profiler {
12
+ readonly window: number;
13
+ private readonly series;
14
+ constructor(window?: number);
15
+ record(name: string, ms: number): void;
16
+ timing(name: string): SystemTiming | undefined;
17
+ all(): Record<string, SystemTiming>;
18
+ }
19
+ export declare const ProfilerResource: import("..").ResourceDef<Profiler>;
@@ -0,0 +1,44 @@
1
+ import { defineResource } from "../schema/resource.js";
2
+ class Profiler {
3
+ window;
4
+ series = /* @__PURE__ */ new Map();
5
+ constructor(window = 120) {
6
+ this.window = window;
7
+ }
8
+ record(name, ms) {
9
+ let series = this.series.get(name);
10
+ if (!series) {
11
+ series = { samples: new Float64Array(this.window), cursor: 0, count: 0 };
12
+ this.series.set(name, series);
13
+ }
14
+ series.samples[series.cursor] = ms;
15
+ series.cursor = (series.cursor + 1) % this.window;
16
+ if (series.count < this.window) series.count++;
17
+ }
18
+ timing(name) {
19
+ const series = this.series.get(name);
20
+ if (!series || series.count === 0) return void 0;
21
+ let sum = 0;
22
+ let max = 0;
23
+ for (let i = 0; i < series.count; i++) {
24
+ const v = series.samples[i];
25
+ sum += v;
26
+ if (v > max) max = v;
27
+ }
28
+ const last = series.samples[(series.cursor - 1 + this.window) % this.window];
29
+ return { last, avg: sum / series.count, max, samples: series.count };
30
+ }
31
+ all() {
32
+ const out = {};
33
+ for (const name of this.series.keys()) out[name] = this.timing(name);
34
+ return out;
35
+ }
36
+ }
37
+ const ProfilerResource = defineResource("core/Profiler", {
38
+ description: "Per-system CPU timings over recent frames.",
39
+ init: () => new Profiler()
40
+ });
41
+ export {
42
+ Profiler,
43
+ ProfilerResource
44
+ };
@@ -0,0 +1,52 @@
1
+ import type { World } from '../ecs/world.js';
2
+ import type { Profiler } from './profiler.js';
3
+ import { SystemConfig, type SystemDef, type SystemSetConfig } from './system.js';
4
+ export interface ScheduleLabel {
5
+ readonly kind: 'schedule';
6
+ readonly name: string;
7
+ }
8
+ export declare function defineSchedule(name: string): ScheduleLabel;
9
+ /** Runs once, before the first frame. */
10
+ export declare const Startup: ScheduleLabel;
11
+ export declare const First: ScheduleLabel;
12
+ export declare const PreUpdate: ScheduleLabel;
13
+ /** Runs 0..N times per frame at a fixed rate. */
14
+ export declare const FixedUpdate: ScheduleLabel;
15
+ export declare const Update: ScheduleLabel;
16
+ export declare const PostUpdate: ScheduleLabel;
17
+ export declare const Last: ScheduleLabel;
18
+ export interface ScheduleRunOptions {
19
+ now: () => number;
20
+ profiler?: Profiler | undefined;
21
+ }
22
+ export interface SystemDescription {
23
+ name: string;
24
+ description?: string;
25
+ after: string[];
26
+ before: string[];
27
+ sets: string[];
28
+ conditions: string[];
29
+ }
30
+ /**
31
+ * An ordered set of systems. Order comes from `after`/`before` constraints (on systems and
32
+ * sets); systems with no relation keep registration order, so runs are deterministic.
33
+ */
34
+ export declare class Schedule {
35
+ readonly label: ScheduleLabel;
36
+ private readonly entries;
37
+ private readonly setConfigs;
38
+ private order;
39
+ constructor(label: ScheduleLabel);
40
+ add(system: SystemDef<unknown> | SystemConfig): void;
41
+ /** Removes systems by name and set configs by identity (hot reload). Returns how many systems went. */
42
+ remove(systems: ReadonlySet<string>, sets?: ReadonlySet<SystemSetConfig>): number;
43
+ configureSet(config: SystemSetConfig): void;
44
+ get size(): number;
45
+ /** Systems in the order they run. Throws `app/system-cycle` if constraints form a cycle. */
46
+ ordered(): readonly SystemConfig[];
47
+ run(world: World, options: ScheduleRunOptions): void;
48
+ describe(): SystemDescription[];
49
+ private setConditionMap;
50
+ private resolve;
51
+ private cycleError;
52
+ }
@@ -0,0 +1,235 @@
1
+ import { Commands } from "../ecs/commands.js";
2
+ import { ShardError } from "../error.js";
3
+ import {
4
+ conditionLabel,
5
+ SystemConfig
6
+ } from "./system.js";
7
+ function defineSchedule(name) {
8
+ return { kind: "schedule", name };
9
+ }
10
+ const Startup = defineSchedule("Startup");
11
+ const First = defineSchedule("First");
12
+ const PreUpdate = defineSchedule("PreUpdate");
13
+ const FixedUpdate = defineSchedule("FixedUpdate");
14
+ const Update = defineSchedule("Update");
15
+ const PostUpdate = defineSchedule("PostUpdate");
16
+ const Last = defineSchedule("Last");
17
+ class Context {
18
+ lastRunTick = 0;
19
+ thisRunTick = 0;
20
+ commands;
21
+ world;
22
+ readers = /* @__PURE__ */ new Map();
23
+ constructor(world) {
24
+ this.world = world;
25
+ this.commands = new Commands(world);
26
+ }
27
+ reader(event) {
28
+ let reader = this.readers.get(event.id);
29
+ if (!reader) {
30
+ reader = this.world.reader(event);
31
+ this.readers.set(event.id, reader);
32
+ }
33
+ return reader;
34
+ }
35
+ }
36
+ class Schedule {
37
+ label;
38
+ entries = [];
39
+ setConfigs = [];
40
+ order;
41
+ constructor(label) {
42
+ this.label = label;
43
+ }
44
+ add(system) {
45
+ const config = system instanceof SystemConfig ? system : new SystemConfig(system);
46
+ this.entries.push({
47
+ config,
48
+ index: this.entries.length,
49
+ state: void 0,
50
+ ctx: void 0,
51
+ conditions: []
52
+ });
53
+ this.order = void 0;
54
+ }
55
+ /** Removes systems by name and set configs by identity (hot reload). Returns how many systems went. */
56
+ remove(systems, sets = /* @__PURE__ */ new Set()) {
57
+ const before = this.entries.length;
58
+ const kept = this.entries.filter((e) => !systems.has(e.config.system.name));
59
+ this.entries.length = 0;
60
+ for (let index = 0; index < kept.length; index++) this.entries.push({ ...kept[index], index });
61
+ const keptSets = this.setConfigs.filter((c) => !sets.has(c));
62
+ this.setConfigs.length = 0;
63
+ this.setConfigs.push(...keptSets);
64
+ this.order = void 0;
65
+ return before - this.entries.length;
66
+ }
67
+ configureSet(config) {
68
+ this.setConfigs.push(config);
69
+ this.order = void 0;
70
+ }
71
+ get size() {
72
+ return this.entries.length;
73
+ }
74
+ /** Systems in the order they run. Throws `app/system-cycle` if constraints form a cycle. */
75
+ ordered() {
76
+ return this.resolve().map((e) => e.config);
77
+ }
78
+ run(world, options) {
79
+ const order = this.resolve();
80
+ for (let i = 0; i < order.length; i++) {
81
+ const entry = order[i];
82
+ const conditions = entry.conditions;
83
+ let skip = false;
84
+ for (let c = 0; c < conditions.length; c++) {
85
+ if (!conditions[c](world)) {
86
+ skip = true;
87
+ break;
88
+ }
89
+ }
90
+ if (skip) continue;
91
+ const system = entry.config.system;
92
+ if (!entry.ctx) {
93
+ entry.ctx = new Context(world);
94
+ entry.state = system.setup ? system.setup(world) : void 0;
95
+ }
96
+ const ctx = entry.ctx;
97
+ ctx.thisRunTick = world.incrementTick();
98
+ const start = options.now();
99
+ try {
100
+ system.run(entry.state, world, ctx);
101
+ } catch (err) {
102
+ const message = err instanceof Error ? err.message : String(err);
103
+ const code = err instanceof ShardError ? ` [${err.code}]` : "";
104
+ throw new ShardError(
105
+ "app/system-failed",
106
+ `System "${system.name}" failed${code}: ${message}`,
107
+ {
108
+ cause: err,
109
+ hint: err instanceof ShardError ? err.hint : void 0
110
+ }
111
+ );
112
+ }
113
+ options.profiler?.record(system.name, options.now() - start);
114
+ ctx.lastRunTick = ctx.thisRunTick;
115
+ world.incrementTick();
116
+ if (ctx.commands.length > 0) ctx.commands.apply();
117
+ }
118
+ }
119
+ describe() {
120
+ const setConditions = this.setConditionMap();
121
+ return this.ordered().map((config) => {
122
+ const out = {
123
+ name: config.system.name,
124
+ after: config.afterLabels.map((l) => l.name),
125
+ before: config.beforeLabels.map((l) => l.name),
126
+ sets: config.sets.map((s) => s.name),
127
+ conditions: [
128
+ ...config.sets.flatMap((s) => setConditions.get(s.name) ?? []),
129
+ ...config.conditions
130
+ ].map(conditionLabel)
131
+ };
132
+ if (config.system.description) out.description = config.system.description;
133
+ return out;
134
+ });
135
+ }
136
+ setConditionMap() {
137
+ const map = /* @__PURE__ */ new Map();
138
+ for (const sc of this.setConfigs) {
139
+ map.set(sc.set.name, [...map.get(sc.set.name) ?? [], ...sc.conditions]);
140
+ }
141
+ return map;
142
+ }
143
+ resolve() {
144
+ if (this.order) return this.order;
145
+ const entries = this.entries;
146
+ const n = entries.length;
147
+ const edges = entries.map(() => /* @__PURE__ */ new Set());
148
+ const indegree = new Array(n).fill(0);
149
+ const link = (from, to) => {
150
+ if (from === to || edges[from].has(to)) return;
151
+ edges[from].add(to);
152
+ indegree[to]++;
153
+ };
154
+ const targets = (label) => entries.filter(
155
+ (e) => label.kind === "system" ? e.config.system === label : e.config.sets.includes(label)
156
+ ).map((e) => e.index);
157
+ for (const entry of entries) {
158
+ for (const label of entry.config.afterLabels) {
159
+ for (const t of targets(label)) link(t, entry.index);
160
+ }
161
+ for (const label of entry.config.beforeLabels) {
162
+ for (const t of targets(label)) link(entry.index, t);
163
+ }
164
+ }
165
+ for (const sc of this.setConfigs) {
166
+ const members = targets(sc.set);
167
+ for (const label of sc.afterLabels) {
168
+ for (const t of targets(label)) for (const m of members) link(t, m);
169
+ }
170
+ for (const label of sc.beforeLabels) {
171
+ for (const t of targets(label)) for (const m of members) link(m, t);
172
+ }
173
+ }
174
+ const order = [];
175
+ const done = new Array(n).fill(false);
176
+ for (let step = 0; step < n; step++) {
177
+ let next = -1;
178
+ for (let i = 0; i < n; i++) {
179
+ if (!done[i] && indegree[i] === 0) {
180
+ next = i;
181
+ break;
182
+ }
183
+ }
184
+ if (next === -1) throw this.cycleError(edges, done);
185
+ done[next] = true;
186
+ order.push(entries[next]);
187
+ for (const to of edges[next]) indegree[to]--;
188
+ }
189
+ const setConditions = this.setConditionMap();
190
+ for (const entry of entries) {
191
+ entry.conditions = [
192
+ ...entry.config.sets.flatMap((s) => setConditions.get(s.name) ?? []),
193
+ ...entry.config.conditions
194
+ ];
195
+ }
196
+ this.order = order;
197
+ return order;
198
+ }
199
+ cycleError(edges, done) {
200
+ const preds = edges.map(() => []);
201
+ edges.forEach((targets, from) => {
202
+ for (const to of targets) preds[to].push(from);
203
+ });
204
+ const start = done.indexOf(false);
205
+ const path = [start];
206
+ const seen = /* @__PURE__ */ new Map([[start, 0]]);
207
+ let current = start;
208
+ for (; ; ) {
209
+ const prev = preds[current].find((p) => !done[p]);
210
+ if (seen.has(prev)) {
211
+ const cycle = path.slice(seen.get(prev)).reverse();
212
+ const names = [...cycle, cycle[0]].map((i) => this.entries[i].config.system.name);
213
+ return new ShardError(
214
+ "app/system-cycle",
215
+ `Systems in ${this.label.name} form an ordering cycle: ${names.join(" \u2192 ")}`,
216
+ { hint: "Remove one of the after/before constraints in this cycle." }
217
+ );
218
+ }
219
+ seen.set(prev, path.length);
220
+ path.push(prev);
221
+ current = prev;
222
+ }
223
+ }
224
+ }
225
+ export {
226
+ First,
227
+ FixedUpdate,
228
+ Last,
229
+ PostUpdate,
230
+ PreUpdate,
231
+ Schedule,
232
+ Startup,
233
+ Update,
234
+ defineSchedule
235
+ };