@sadhaka/loom-engine 0.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/LICENSE +21 -0
- package/README.md +344 -0
- package/dist/animation/animation-clip.d.ts +12 -0
- package/dist/animation/animation-clip.d.ts.map +1 -0
- package/dist/animation/animation-clip.js +85 -0
- package/dist/animation/animation-clip.js.map +1 -0
- package/dist/animation/animation-state-pool.d.ts +25 -0
- package/dist/animation/animation-state-pool.d.ts.map +1 -0
- package/dist/animation/animation-state-pool.js +113 -0
- package/dist/animation/animation-state-pool.js.map +1 -0
- package/dist/asset/sprite-sheet-loader.d.ts +41 -0
- package/dist/asset/sprite-sheet-loader.d.ts.map +1 -0
- package/dist/asset/sprite-sheet-loader.js +313 -0
- package/dist/asset/sprite-sheet-loader.js.map +1 -0
- package/dist/audio/audio-bus.d.ts +43 -0
- package/dist/audio/audio-bus.d.ts.map +1 -0
- package/dist/audio/audio-bus.js +258 -0
- package/dist/audio/audio-bus.js.map +1 -0
- package/dist/combat/mob-catalog.d.ts +29 -0
- package/dist/combat/mob-catalog.d.ts.map +1 -0
- package/dist/combat/mob-catalog.js +104 -0
- package/dist/combat/mob-catalog.js.map +1 -0
- package/dist/components/health.d.ts +28 -0
- package/dist/components/health.d.ts.map +1 -0
- package/dist/components/health.js +150 -0
- package/dist/components/health.js.map +1 -0
- package/dist/components/interactable.d.ts +30 -0
- package/dist/components/interactable.d.ts.map +1 -0
- package/dist/components/interactable.js +94 -0
- package/dist/components/interactable.js.map +1 -0
- package/dist/components/particle-emitter.d.ts +62 -0
- package/dist/components/particle-emitter.d.ts.map +1 -0
- package/dist/components/particle-emitter.js +193 -0
- package/dist/components/particle-emitter.js.map +1 -0
- package/dist/components/pursue.d.ts +23 -0
- package/dist/components/pursue.d.ts.map +1 -0
- package/dist/components/pursue.js +96 -0
- package/dist/components/pursue.js.map +1 -0
- package/dist/components/ranged-attack.d.ts +44 -0
- package/dist/components/ranged-attack.d.ts.map +1 -0
- package/dist/components/ranged-attack.js +120 -0
- package/dist/components/ranged-attack.js.map +1 -0
- package/dist/components/sprite.d.ts +27 -0
- package/dist/components/sprite.d.ts.map +1 -0
- package/dist/components/sprite.js +122 -0
- package/dist/components/sprite.js.map +1 -0
- package/dist/components/transform.d.ts +30 -0
- package/dist/components/transform.d.ts.map +1 -0
- package/dist/components/transform.js +150 -0
- package/dist/components/transform.js.map +1 -0
- package/dist/director/director-bridge.d.ts +22 -0
- package/dist/director/director-bridge.d.ts.map +1 -0
- package/dist/director/director-bridge.js +23 -0
- package/dist/director/director-bridge.js.map +1 -0
- package/dist/director/director-encounter-system.d.ts +21 -0
- package/dist/director/director-encounter-system.d.ts.map +1 -0
- package/dist/director/director-encounter-system.js +128 -0
- package/dist/director/director-encounter-system.js.map +1 -0
- package/dist/director/director-system.d.ts +19 -0
- package/dist/director/director-system.d.ts.map +1 -0
- package/dist/director/director-system.js +179 -0
- package/dist/director/director-system.js.map +1 -0
- package/dist/director/event-envelope.d.ts +144 -0
- package/dist/director/event-envelope.d.ts.map +1 -0
- package/dist/director/event-envelope.js +108 -0
- package/dist/director/event-envelope.js.map +1 -0
- package/dist/director/knot-context-resource.d.ts +25 -0
- package/dist/director/knot-context-resource.d.ts.map +1 -0
- package/dist/director/knot-context-resource.js +152 -0
- package/dist/director/knot-context-resource.js.map +1 -0
- package/dist/director/mock-director-bridge.d.ts +18 -0
- package/dist/director/mock-director-bridge.d.ts.map +1 -0
- package/dist/director/mock-director-bridge.js +75 -0
- package/dist/director/mock-director-bridge.js.map +1 -0
- package/dist/director/snapshot-recovery.d.ts +37 -0
- package/dist/director/snapshot-recovery.d.ts.map +1 -0
- package/dist/director/snapshot-recovery.js +180 -0
- package/dist/director/snapshot-recovery.js.map +1 -0
- package/dist/director/sse-director-bridge.d.ts +42 -0
- package/dist/director/sse-director-bridge.d.ts.map +1 -0
- package/dist/director/sse-director-bridge.js +280 -0
- package/dist/director/sse-director-bridge.js.map +1 -0
- package/dist/engine.d.ts +25 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +166 -0
- package/dist/engine.js.map +1 -0
- package/dist/entity.d.ts +17 -0
- package/dist/entity.d.ts.map +1 -0
- package/dist/entity.js +77 -0
- package/dist/entity.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/input/input-manager.d.ts +91 -0
- package/dist/input/input-manager.d.ts.map +1 -0
- package/dist/input/input-manager.js +349 -0
- package/dist/input/input-manager.js.map +1 -0
- package/dist/input/tap-to-walk.d.ts +27 -0
- package/dist/input/tap-to-walk.d.ts.map +1 -0
- package/dist/input/tap-to-walk.js +118 -0
- package/dist/input/tap-to-walk.js.map +1 -0
- package/dist/input/virtual-dpad.d.ts +34 -0
- package/dist/input/virtual-dpad.d.ts.map +1 -0
- package/dist/input/virtual-dpad.js +267 -0
- package/dist/input/virtual-dpad.js.map +1 -0
- package/dist/renderer/camera.d.ts +26 -0
- package/dist/renderer/camera.d.ts.map +1 -0
- package/dist/renderer/camera.js +39 -0
- package/dist/renderer/camera.js.map +1 -0
- package/dist/renderer/canvas2d-device.d.ts +26 -0
- package/dist/renderer/canvas2d-device.d.ts.map +1 -0
- package/dist/renderer/canvas2d-device.js +252 -0
- package/dist/renderer/canvas2d-device.js.map +1 -0
- package/dist/renderer/graphics-device.d.ts +36 -0
- package/dist/renderer/graphics-device.d.ts.map +1 -0
- package/dist/renderer/graphics-device.js +12 -0
- package/dist/renderer/graphics-device.js.map +1 -0
- package/dist/renderer/iso-projection.d.ts +11 -0
- package/dist/renderer/iso-projection.d.ts.map +1 -0
- package/dist/renderer/iso-projection.js +59 -0
- package/dist/renderer/iso-projection.js.map +1 -0
- package/dist/resources.d.ts +28 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +53 -0
- package/dist/resources.js.map +1 -0
- package/dist/system.d.ts +14 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +25 -0
- package/dist/system.js.map +1 -0
- package/dist/systems/animation-system.d.ts +8 -0
- package/dist/systems/animation-system.d.ts.map +1 -0
- package/dist/systems/animation-system.js +77 -0
- package/dist/systems/animation-system.js.map +1 -0
- package/dist/systems/attack-system.d.ts +17 -0
- package/dist/systems/attack-system.d.ts.map +1 -0
- package/dist/systems/attack-system.js +94 -0
- package/dist/systems/attack-system.js.map +1 -0
- package/dist/systems/damage-system.d.ts +18 -0
- package/dist/systems/damage-system.d.ts.map +1 -0
- package/dist/systems/damage-system.js +77 -0
- package/dist/systems/damage-system.js.map +1 -0
- package/dist/systems/input-system.d.ts +7 -0
- package/dist/systems/input-system.d.ts.map +1 -0
- package/dist/systems/input-system.js +27 -0
- package/dist/systems/input-system.js.map +1 -0
- package/dist/systems/interaction-system.d.ts +23 -0
- package/dist/systems/interaction-system.d.ts.map +1 -0
- package/dist/systems/interaction-system.js +120 -0
- package/dist/systems/interaction-system.js.map +1 -0
- package/dist/systems/particle-emitter-system.d.ts +8 -0
- package/dist/systems/particle-emitter-system.d.ts.map +1 -0
- package/dist/systems/particle-emitter-system.js +161 -0
- package/dist/systems/particle-emitter-system.js.map +1 -0
- package/dist/systems/particle-render-system.d.ts +7 -0
- package/dist/systems/particle-render-system.d.ts.map +1 -0
- package/dist/systems/particle-render-system.js +53 -0
- package/dist/systems/particle-render-system.js.map +1 -0
- package/dist/systems/particle-simulation-system.d.ts +8 -0
- package/dist/systems/particle-simulation-system.d.ts.map +1 -0
- package/dist/systems/particle-simulation-system.js +45 -0
- package/dist/systems/particle-simulation-system.js.map +1 -0
- package/dist/systems/projectile-render-system.d.ts +7 -0
- package/dist/systems/projectile-render-system.d.ts.map +1 -0
- package/dist/systems/projectile-render-system.js +35 -0
- package/dist/systems/projectile-render-system.js.map +1 -0
- package/dist/systems/projectile-system.d.ts +7 -0
- package/dist/systems/projectile-system.d.ts.map +1 -0
- package/dist/systems/projectile-system.js +114 -0
- package/dist/systems/projectile-system.js.map +1 -0
- package/dist/systems/pursue-system.d.ts +7 -0
- package/dist/systems/pursue-system.d.ts.map +1 -0
- package/dist/systems/pursue-system.js +83 -0
- package/dist/systems/pursue-system.js.map +1 -0
- package/dist/systems/ranged-attack-system.d.ts +7 -0
- package/dist/systems/ranged-attack-system.d.ts.map +1 -0
- package/dist/systems/ranged-attack-system.js +98 -0
- package/dist/systems/ranged-attack-system.js.map +1 -0
- package/dist/systems/sprite-render-system.d.ts +9 -0
- package/dist/systems/sprite-render-system.d.ts.map +1 -0
- package/dist/systems/sprite-render-system.js +108 -0
- package/dist/systems/sprite-render-system.js.map +1 -0
- package/dist/systems/veil-budget-system.d.ts +7 -0
- package/dist/systems/veil-budget-system.d.ts.map +1 -0
- package/dist/systems/veil-budget-system.js +37 -0
- package/dist/systems/veil-budget-system.js.map +1 -0
- package/dist/util/color.d.ts +19 -0
- package/dist/util/color.d.ts.map +1 -0
- package/dist/util/color.js +45 -0
- package/dist/util/color.js.map +1 -0
- package/dist/util/math.d.ts +26 -0
- package/dist/util/math.d.ts.map +1 -0
- package/dist/util/math.js +47 -0
- package/dist/util/math.js.map +1 -0
- package/dist/util/typed-arrays.d.ts +7 -0
- package/dist/util/typed-arrays.d.ts.map +1 -0
- package/dist/util/typed-arrays.js +42 -0
- package/dist/util/typed-arrays.js.map +1 -0
- package/dist/vfx/particle-pool.d.ts +61 -0
- package/dist/vfx/particle-pool.d.ts.map +1 -0
- package/dist/vfx/particle-pool.js +204 -0
- package/dist/vfx/particle-pool.js.map +1 -0
- package/dist/vfx/projectile-pool.d.ts +56 -0
- package/dist/vfx/projectile-pool.d.ts.map +1 -0
- package/dist/vfx/projectile-pool.js +157 -0
- package/dist/vfx/projectile-pool.js.map +1 -0
- package/dist/world.d.ts +23 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +101 -0
- package/dist/world.js.map +1 -0
- package/dist/zone/zone-catalog.d.ts +17 -0
- package/dist/zone/zone-catalog.d.ts.map +1 -0
- package/dist/zone/zone-catalog.js +116 -0
- package/dist/zone/zone-catalog.js.map +1 -0
- package/dist/zone/zone-state.d.ts +18 -0
- package/dist/zone/zone-state.d.ts.map +1 -0
- package/dist/zone/zone-state.js +52 -0
- package/dist/zone/zone-state.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// SpritePool - per-entity sprite appearance data.
|
|
2
|
+
//
|
|
3
|
+
// Companion to TransformPool: an entity that has both Transform
|
|
4
|
+
// (position) and Sprite (atlas + frame + tint) gets rendered by
|
|
5
|
+
// the SpriteRenderSystem.
|
|
6
|
+
//
|
|
7
|
+
// Stored as parallel arrays indexed by entity index, mirroring
|
|
8
|
+
// TransformPool's structure-of-arrays layout. Atlas + frame are
|
|
9
|
+
// tightly packed. Tint is split into rgba arrays so iteration
|
|
10
|
+
// stays cache-friendly.
|
|
11
|
+
import { growF32, growI32, growU8, nextPow2 } from '../util/typed-arrays.js';
|
|
12
|
+
import { entityIndex } from '../entity.js';
|
|
13
|
+
export const SPRITE_FLAG_ACTIVE = 1 << 0;
|
|
14
|
+
export const SPRITE_FLAG_TINTED = 1 << 1;
|
|
15
|
+
export class SpritePool {
|
|
16
|
+
// Hot data
|
|
17
|
+
atlas; // -1 = no sprite assigned (pair with flags ACTIVE bit)
|
|
18
|
+
frame;
|
|
19
|
+
tintR;
|
|
20
|
+
tintG;
|
|
21
|
+
tintB;
|
|
22
|
+
tintA;
|
|
23
|
+
// Cold data
|
|
24
|
+
flags;
|
|
25
|
+
highWaterMark = 0;
|
|
26
|
+
capacity = 0;
|
|
27
|
+
constructor(initialCapacity = 64) {
|
|
28
|
+
this.capacity = nextPow2(initialCapacity);
|
|
29
|
+
this.atlas = new Int32Array(this.capacity).fill(-1);
|
|
30
|
+
this.frame = new Int32Array(this.capacity);
|
|
31
|
+
this.tintR = new Float32Array(this.capacity);
|
|
32
|
+
this.tintG = new Float32Array(this.capacity);
|
|
33
|
+
this.tintB = new Float32Array(this.capacity);
|
|
34
|
+
this.tintA = new Float32Array(this.capacity);
|
|
35
|
+
this.flags = new Uint8Array(this.capacity);
|
|
36
|
+
}
|
|
37
|
+
ensureCapacity(neededIndex) {
|
|
38
|
+
if (neededIndex < this.capacity)
|
|
39
|
+
return;
|
|
40
|
+
const next = nextPow2(neededIndex + 1);
|
|
41
|
+
const newAtlas = new Int32Array(next).fill(-1);
|
|
42
|
+
newAtlas.set(this.atlas);
|
|
43
|
+
this.atlas = newAtlas;
|
|
44
|
+
this.frame = growI32(this.frame, next);
|
|
45
|
+
this.tintR = growF32(this.tintR, next);
|
|
46
|
+
this.tintG = growF32(this.tintG, next);
|
|
47
|
+
this.tintB = growF32(this.tintB, next);
|
|
48
|
+
this.tintA = growF32(this.tintA, next);
|
|
49
|
+
this.flags = growU8(this.flags, next);
|
|
50
|
+
this.capacity = next;
|
|
51
|
+
}
|
|
52
|
+
attach(e, atlas, frame = 0, tint) {
|
|
53
|
+
const i = entityIndex(e);
|
|
54
|
+
this.ensureCapacity(i);
|
|
55
|
+
this.atlas[i] = atlas;
|
|
56
|
+
this.frame[i] = frame;
|
|
57
|
+
if (tint) {
|
|
58
|
+
this.tintR[i] = tint.r;
|
|
59
|
+
this.tintG[i] = tint.g;
|
|
60
|
+
this.tintB[i] = tint.b;
|
|
61
|
+
this.tintA[i] = tint.a;
|
|
62
|
+
this.flags[i] = SPRITE_FLAG_ACTIVE | SPRITE_FLAG_TINTED;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
this.tintR[i] = 1;
|
|
66
|
+
this.tintG[i] = 1;
|
|
67
|
+
this.tintB[i] = 1;
|
|
68
|
+
this.tintA[i] = 1;
|
|
69
|
+
this.flags[i] = SPRITE_FLAG_ACTIVE;
|
|
70
|
+
}
|
|
71
|
+
if (i >= this.highWaterMark)
|
|
72
|
+
this.highWaterMark = i + 1;
|
|
73
|
+
}
|
|
74
|
+
detach(e) {
|
|
75
|
+
const i = entityIndex(e);
|
|
76
|
+
if (i >= this.capacity)
|
|
77
|
+
return;
|
|
78
|
+
this.atlas[i] = -1;
|
|
79
|
+
this.flags[i] = 0;
|
|
80
|
+
}
|
|
81
|
+
setFrame(e, frame) {
|
|
82
|
+
const i = entityIndex(e);
|
|
83
|
+
if (i >= this.capacity)
|
|
84
|
+
return;
|
|
85
|
+
this.frame[i] = frame;
|
|
86
|
+
}
|
|
87
|
+
setTint(e, tint) {
|
|
88
|
+
const i = entityIndex(e);
|
|
89
|
+
if (i >= this.capacity)
|
|
90
|
+
return;
|
|
91
|
+
this.tintR[i] = tint.r;
|
|
92
|
+
this.tintG[i] = tint.g;
|
|
93
|
+
this.tintB[i] = tint.b;
|
|
94
|
+
this.tintA[i] = tint.a;
|
|
95
|
+
const f = this.flags[i] ?? 0;
|
|
96
|
+
this.flags[i] = f | SPRITE_FLAG_TINTED;
|
|
97
|
+
}
|
|
98
|
+
clearTint(e) {
|
|
99
|
+
const i = entityIndex(e);
|
|
100
|
+
if (i >= this.capacity)
|
|
101
|
+
return;
|
|
102
|
+
this.tintR[i] = 1;
|
|
103
|
+
this.tintG[i] = 1;
|
|
104
|
+
this.tintB[i] = 1;
|
|
105
|
+
this.tintA[i] = 1;
|
|
106
|
+
const f = this.flags[i] ?? 0;
|
|
107
|
+
this.flags[i] = f & ~SPRITE_FLAG_TINTED;
|
|
108
|
+
}
|
|
109
|
+
isActive(e) {
|
|
110
|
+
const i = entityIndex(e);
|
|
111
|
+
if (i >= this.capacity)
|
|
112
|
+
return false;
|
|
113
|
+
return ((this.flags[i] ?? 0) & SPRITE_FLAG_ACTIVE) !== 0;
|
|
114
|
+
}
|
|
115
|
+
getHighWaterMark() {
|
|
116
|
+
return this.highWaterMark;
|
|
117
|
+
}
|
|
118
|
+
getCapacity() {
|
|
119
|
+
return this.capacity;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=sprite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprite.js","sourceRoot":"","sources":["../../src/components/sprite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type EntityId } from '../entity.js';
|
|
2
|
+
export declare const TRANSFORM_FLAG_DIRTY: number;
|
|
3
|
+
export declare const TRANSFORM_FLAG_VISIBLE: number;
|
|
4
|
+
export declare const TRANSFORM_FLAG_STATIC: number;
|
|
5
|
+
export declare const TRANSFORM_FLAG_HAS_PARENT: number;
|
|
6
|
+
export declare class TransformPool {
|
|
7
|
+
x: Float32Array;
|
|
8
|
+
y: Float32Array;
|
|
9
|
+
z: Float32Array;
|
|
10
|
+
rotation: Float32Array;
|
|
11
|
+
scaleX: Float32Array;
|
|
12
|
+
scaleY: Float32Array;
|
|
13
|
+
parent: Int32Array;
|
|
14
|
+
flags: Uint8Array;
|
|
15
|
+
private highWaterMark;
|
|
16
|
+
private capacity;
|
|
17
|
+
constructor(initialCapacity?: number);
|
|
18
|
+
ensureCapacity(neededIndex: number): void;
|
|
19
|
+
attach(e: EntityId, x?: number, y?: number, z?: number): void;
|
|
20
|
+
detach(e: EntityId): void;
|
|
21
|
+
setPosition(e: EntityId, x: number, y: number, z?: number): void;
|
|
22
|
+
setScale(e: EntityId, sx: number, sy: number): void;
|
|
23
|
+
setRotation(e: EntityId, radians: number): void;
|
|
24
|
+
isVisible(e: EntityId): boolean;
|
|
25
|
+
setVisible(e: EntityId, visible: boolean): void;
|
|
26
|
+
getHighWaterMark(): number;
|
|
27
|
+
getCapacity(): number;
|
|
28
|
+
clearDirtyAt(index: number): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/components/transform.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,QAAQ,EAAe,MAAM,cAAc,CAAC;AAG1D,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAC3C,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAC7C,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD,qBAAa,aAAa;IAExB,CAAC,EAAE,YAAY,CAAC;IAChB,CAAC,EAAE,YAAY,CAAC;IAChB,CAAC,EAAE,YAAY,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IAGrB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAKlB,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAa;gBAEjB,eAAe,GAAE,MAAW;IAYxC,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAsBzC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAE,MAAU,EAAE,CAAC,GAAE,MAAU,EAAE,CAAC,GAAE,MAAU,GAAG,IAAI;IActE,MAAM,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI;IASzB,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,GAAE,MAAU,GAAG,IAAI;IAUnE,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IASnD,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ/C,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO;IAM/B,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAO/C,gBAAgB,IAAI,MAAM;IAI1B,WAAW,IAAI,MAAM;IAOrB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAKlC"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// TransformPool - the hot component for the Loom Engine ECS.
|
|
2
|
+
//
|
|
3
|
+
// Structure-of-arrays storage: x, y, z, rotation, scaleX, scaleY in
|
|
4
|
+
// separate Float32Arrays so iteration sweeps a contiguous block.
|
|
5
|
+
// Cold metadata (parent, flags) in their own arrays.
|
|
6
|
+
//
|
|
7
|
+
// Inspired by Mike Acton's CppCon 2014 "Data-Oriented Design" talk
|
|
8
|
+
// (see PRIOR-ART.md). The premise: a 10k-entity sort step iterates
|
|
9
|
+
// through ~80kB of contiguous Float32Array memory rather than
|
|
10
|
+
// chasing 10k object pointers.
|
|
11
|
+
//
|
|
12
|
+
// Capacity grows by 2x on demand. Initial capacity is small to
|
|
13
|
+
// keep startup cost tiny; first scene with > 64 entities pays for
|
|
14
|
+
// one grow, after that pow-2 sizing absorbs further growth cheaply.
|
|
15
|
+
import { growF32, growU8, nextPow2 } from '../util/typed-arrays.js';
|
|
16
|
+
import { entityIndex } from '../entity.js';
|
|
17
|
+
// Bitflags packed into the cold flags array.
|
|
18
|
+
export const TRANSFORM_FLAG_DIRTY = 1 << 0; // world matrix needs recompute
|
|
19
|
+
export const TRANSFORM_FLAG_VISIBLE = 1 << 1; // skip render if cleared
|
|
20
|
+
export const TRANSFORM_FLAG_STATIC = 1 << 2; // never moves; cache aggressively
|
|
21
|
+
export const TRANSFORM_FLAG_HAS_PARENT = 1 << 3; // parent slot is meaningful
|
|
22
|
+
export class TransformPool {
|
|
23
|
+
// Hot data - touched every frame by render + sort systems.
|
|
24
|
+
x;
|
|
25
|
+
y;
|
|
26
|
+
z;
|
|
27
|
+
rotation;
|
|
28
|
+
scaleX;
|
|
29
|
+
scaleY;
|
|
30
|
+
// Cold data - rarely touched per-frame.
|
|
31
|
+
parent; // -1 for root, otherwise parent entity index
|
|
32
|
+
flags;
|
|
33
|
+
// High-water mark of active indices. Iteration goes up to this,
|
|
34
|
+
// not capacity, so a sparsely-populated pool doesn't waste cycles
|
|
35
|
+
// on empty slots above the live set.
|
|
36
|
+
highWaterMark = 0;
|
|
37
|
+
capacity = 0;
|
|
38
|
+
constructor(initialCapacity = 64) {
|
|
39
|
+
this.capacity = nextPow2(initialCapacity);
|
|
40
|
+
this.x = new Float32Array(this.capacity);
|
|
41
|
+
this.y = new Float32Array(this.capacity);
|
|
42
|
+
this.z = new Float32Array(this.capacity);
|
|
43
|
+
this.rotation = new Float32Array(this.capacity);
|
|
44
|
+
this.scaleX = new Float32Array(this.capacity);
|
|
45
|
+
this.scaleY = new Float32Array(this.capacity);
|
|
46
|
+
this.parent = new Int32Array(this.capacity).fill(-1);
|
|
47
|
+
this.flags = new Uint8Array(this.capacity);
|
|
48
|
+
}
|
|
49
|
+
ensureCapacity(neededIndex) {
|
|
50
|
+
if (neededIndex < this.capacity)
|
|
51
|
+
return;
|
|
52
|
+
const next = nextPow2(neededIndex + 1);
|
|
53
|
+
this.x = growF32(this.x, next);
|
|
54
|
+
this.y = growF32(this.y, next);
|
|
55
|
+
this.z = growF32(this.z, next);
|
|
56
|
+
this.rotation = growF32(this.rotation, next);
|
|
57
|
+
this.scaleX = growF32(this.scaleX, next);
|
|
58
|
+
this.scaleY = growF32(this.scaleY, next);
|
|
59
|
+
// -1 is the parent sentinel for "no parent" - new slots default
|
|
60
|
+
// to that.
|
|
61
|
+
const oldParent = this.parent;
|
|
62
|
+
const newParent = new Int32Array(next).fill(-1);
|
|
63
|
+
newParent.set(oldParent);
|
|
64
|
+
this.parent = newParent;
|
|
65
|
+
this.flags = growU8(this.flags, next);
|
|
66
|
+
this.capacity = next;
|
|
67
|
+
}
|
|
68
|
+
// Attach a transform to an entity. Sets sane defaults: scale = 1,
|
|
69
|
+
// visible = true, dirty = true. The dirty flag tells the transform
|
|
70
|
+
// system to recompute any cached world matrix on the next commit.
|
|
71
|
+
attach(e, x = 0, y = 0, z = 0) {
|
|
72
|
+
const i = entityIndex(e);
|
|
73
|
+
this.ensureCapacity(i);
|
|
74
|
+
this.x[i] = x;
|
|
75
|
+
this.y[i] = y;
|
|
76
|
+
this.z[i] = z;
|
|
77
|
+
this.rotation[i] = 0;
|
|
78
|
+
this.scaleX[i] = 1;
|
|
79
|
+
this.scaleY[i] = 1;
|
|
80
|
+
this.parent[i] = -1;
|
|
81
|
+
this.flags[i] = TRANSFORM_FLAG_DIRTY | TRANSFORM_FLAG_VISIBLE;
|
|
82
|
+
if (i >= this.highWaterMark)
|
|
83
|
+
this.highWaterMark = i + 1;
|
|
84
|
+
}
|
|
85
|
+
detach(e) {
|
|
86
|
+
const i = entityIndex(e);
|
|
87
|
+
if (i >= this.capacity)
|
|
88
|
+
return;
|
|
89
|
+
this.flags[i] = 0;
|
|
90
|
+
// We don't shrink highWaterMark on detach - the slot is just
|
|
91
|
+
// marked invisible. A future tighten() pass could compact, but
|
|
92
|
+
// v1 keeps it simple.
|
|
93
|
+
}
|
|
94
|
+
setPosition(e, x, y, z = 0) {
|
|
95
|
+
const i = entityIndex(e);
|
|
96
|
+
if (i >= this.capacity)
|
|
97
|
+
return;
|
|
98
|
+
this.x[i] = x;
|
|
99
|
+
this.y[i] = y;
|
|
100
|
+
this.z[i] = z;
|
|
101
|
+
const f = this.flags[i] ?? 0;
|
|
102
|
+
this.flags[i] = f | TRANSFORM_FLAG_DIRTY;
|
|
103
|
+
}
|
|
104
|
+
setScale(e, sx, sy) {
|
|
105
|
+
const i = entityIndex(e);
|
|
106
|
+
if (i >= this.capacity)
|
|
107
|
+
return;
|
|
108
|
+
this.scaleX[i] = sx;
|
|
109
|
+
this.scaleY[i] = sy;
|
|
110
|
+
const f = this.flags[i] ?? 0;
|
|
111
|
+
this.flags[i] = f | TRANSFORM_FLAG_DIRTY;
|
|
112
|
+
}
|
|
113
|
+
setRotation(e, radians) {
|
|
114
|
+
const i = entityIndex(e);
|
|
115
|
+
if (i >= this.capacity)
|
|
116
|
+
return;
|
|
117
|
+
this.rotation[i] = radians;
|
|
118
|
+
const f = this.flags[i] ?? 0;
|
|
119
|
+
this.flags[i] = f | TRANSFORM_FLAG_DIRTY;
|
|
120
|
+
}
|
|
121
|
+
isVisible(e) {
|
|
122
|
+
const i = entityIndex(e);
|
|
123
|
+
if (i >= this.capacity)
|
|
124
|
+
return false;
|
|
125
|
+
return ((this.flags[i] ?? 0) & TRANSFORM_FLAG_VISIBLE) !== 0;
|
|
126
|
+
}
|
|
127
|
+
setVisible(e, visible) {
|
|
128
|
+
const i = entityIndex(e);
|
|
129
|
+
if (i >= this.capacity)
|
|
130
|
+
return;
|
|
131
|
+
const f = this.flags[i] ?? 0;
|
|
132
|
+
this.flags[i] = visible ? f | TRANSFORM_FLAG_VISIBLE : f & ~TRANSFORM_FLAG_VISIBLE;
|
|
133
|
+
}
|
|
134
|
+
getHighWaterMark() {
|
|
135
|
+
return this.highWaterMark;
|
|
136
|
+
}
|
|
137
|
+
getCapacity() {
|
|
138
|
+
return this.capacity;
|
|
139
|
+
}
|
|
140
|
+
// Clear the dirty bit after the transform-system commit pass. The
|
|
141
|
+
// commit pass walks all dirty entries, recomputes derived state,
|
|
142
|
+
// then calls this.
|
|
143
|
+
clearDirtyAt(index) {
|
|
144
|
+
if (index >= this.capacity)
|
|
145
|
+
return;
|
|
146
|
+
const f = this.flags[index] ?? 0;
|
|
147
|
+
this.flags[index] = f & ~TRANSFORM_FLAG_DIRTY;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/components/transform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DirectorEvent } from './event-envelope.js';
|
|
2
|
+
export type DirectorBridgeStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'snapshot-required' | 'closed';
|
|
3
|
+
export interface DirectorBridgeStats {
|
|
4
|
+
eventsReceived: number;
|
|
5
|
+
reconnects: number;
|
|
6
|
+
lastEventId: number;
|
|
7
|
+
outOfOrderEvents: number;
|
|
8
|
+
serverDropsP1: number;
|
|
9
|
+
serverDropsP2: number;
|
|
10
|
+
}
|
|
11
|
+
export interface IDirectorBridge {
|
|
12
|
+
start(): void;
|
|
13
|
+
stop(): void;
|
|
14
|
+
status(): DirectorBridgeStatus;
|
|
15
|
+
isConnected(): boolean;
|
|
16
|
+
getLastEventId(): number;
|
|
17
|
+
pollEvents(): DirectorEvent[];
|
|
18
|
+
stats(): Readonly<DirectorBridgeStats>;
|
|
19
|
+
}
|
|
20
|
+
export declare const RESOURCE_DIRECTOR_BRIDGE = "director_bridge";
|
|
21
|
+
export declare const RESOURCE_KNOT_CONTEXT = "knot_context";
|
|
22
|
+
//# sourceMappingURL=director-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"director-bridge.d.ts","sourceRoot":"","sources":["../../src/director/director-bridge.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,MAAM,oBAAoB,GAC5B,MAAM,GACN,YAAY,GACZ,WAAW,GACX,cAAc,GACd,mBAAmB,GACnB,QAAQ,CAAC;AAEb,MAAM,WAAW,mBAAmB;IAElC,cAAc,EAAE,MAAM,CAAC;IAEvB,UAAU,EAAE,MAAM,CAAC;IAEnB,WAAW,EAAE,MAAM,CAAC;IAEpB,gBAAgB,EAAE,MAAM,CAAC;IAEzB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;IACb,MAAM,IAAI,oBAAoB,CAAC;IAC/B,WAAW,IAAI,OAAO,CAAC;IACvB,cAAc,IAAI,MAAM,CAAC;IACzB,UAAU,IAAI,aAAa,EAAE,CAAC;IAC9B,KAAK,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC;CACxC;AAGD,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAC1D,eAAO,MAAM,qBAAqB,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// IDirectorBridge - abstraction over the event source.
|
|
2
|
+
//
|
|
3
|
+
// Concrete implementations:
|
|
4
|
+
// MockDirectorBridge - synthetic event injection. Used in tests +
|
|
5
|
+
// offline demo. Does not touch the network.
|
|
6
|
+
// SSEDirectorBridge - real EventSource subscription against the
|
|
7
|
+
// backend's /api/v1/loom/director/events route.
|
|
8
|
+
// Browser-only; throws in Node test runs.
|
|
9
|
+
//
|
|
10
|
+
// The DirectorSystem (PHASE_INPUT) calls pollEvents() once per tick
|
|
11
|
+
// to drain queued events. Bridges buffer events between polls so the
|
|
12
|
+
// system's per-tick read is bounded.
|
|
13
|
+
//
|
|
14
|
+
// Connection lifecycle:
|
|
15
|
+
// start() - begin subscription / open EventSource
|
|
16
|
+
// stop() - close and stop reconnecting
|
|
17
|
+
// isConnected() - true when the underlying transport is open
|
|
18
|
+
// getLastEventId() - highest id observed; used for reconnect Last-Event-ID
|
|
19
|
+
// pollEvents() - drain and return all queued events since last poll
|
|
20
|
+
// Resource keys.
|
|
21
|
+
export const RESOURCE_DIRECTOR_BRIDGE = 'director_bridge';
|
|
22
|
+
export const RESOURCE_KNOT_CONTEXT = 'knot_context';
|
|
23
|
+
//# sourceMappingURL=director-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"director-bridge.js","sourceRoot":"","sources":["../../src/director/director-bridge.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,EAAE;AACF,4BAA4B;AAC5B,qEAAqE;AACrE,oEAAoE;AACpE,oEAAoE;AACpE,wEAAwE;AACxE,kEAAkE;AAClE,EAAE;AACF,oEAAoE;AACpE,qEAAqE;AACrE,qCAAqC;AACrC,EAAE;AACF,wBAAwB;AACxB,+DAA+D;AAC/D,qDAAqD;AACrD,oEAAoE;AACpE,+EAA+E;AAC/E,4EAA4E;AAoC5E,iBAAiB;AACjB,MAAM,CAAC,MAAM,wBAAwB,GAAG,iBAAiB,CAAC;AAC1D,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { System } from '../system.js';
|
|
2
|
+
import type { World } from '../world.js';
|
|
3
|
+
import type { AtlasHandle } from '../renderer/graphics-device.js';
|
|
4
|
+
import type { EntityId } from '../entity.js';
|
|
5
|
+
export interface DirectorEncounterSystemOptions {
|
|
6
|
+
player: EntityId;
|
|
7
|
+
mobAtlas: AtlasHandle;
|
|
8
|
+
onEncounterStarted?: (encounterId: string, mobCount: number, narratorLine: string | null) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare class DirectorEncounterSystem implements System {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
private handled;
|
|
13
|
+
private opts;
|
|
14
|
+
constructor(opts: DirectorEncounterSystemOptions);
|
|
15
|
+
update(world: World, _dt: number): void;
|
|
16
|
+
private spawnEncounter;
|
|
17
|
+
private spawnOne;
|
|
18
|
+
clearHandled(): void;
|
|
19
|
+
hasHandled(encounterId: string): boolean;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=director-encounter-system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"director-encounter-system.d.ts","sourceRoot":"","sources":["../../src/director/director-encounter-system.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAWzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAsB7C,MAAM,WAAW,8BAA8B;IAE7C,MAAM,EAAE,QAAQ,CAAC;IAKjB,QAAQ,EAAE,WAAW,CAAC;IAItB,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACnG;AAED,qBAAa,uBAAwB,YAAW,MAAM;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAwB;IAI7C,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,IAAI,CAAiC;gBAEjC,IAAI,EAAE,8BAA8B;IAIhD,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IA2BvC,OAAO,CAAC,cAAc;IA6BtB,OAAO,CAAC,QAAQ;IAyBhB,YAAY,IAAI,IAAI;IAIpB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;CAGzC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// DirectorEncounterSystem - subscribes to encounter.spawn events
|
|
2
|
+
// from the DirectorEventLog and spawns mobs into the world.
|
|
3
|
+
//
|
|
4
|
+
// Works in tandem with DirectorSystem:
|
|
5
|
+
// 1. DirectorSystem (PHASE_INPUT) drains the bridge and applies
|
|
6
|
+
// events to KnotContext / VeilBudget / DirectorEventLog
|
|
7
|
+
// 2. DirectorEncounterSystem (PHASE_LOGIC) re-reads the most
|
|
8
|
+
// recent events from the log, spawns mobs from any new
|
|
9
|
+
// encounter.spawn event, and tracks handled encounter ids so
|
|
10
|
+
// replay / duplicate events don't double-spawn
|
|
11
|
+
//
|
|
12
|
+
// Per spec §3.1 the encounter.spawn payload includes:
|
|
13
|
+
// - mobs: ReadonlyArray<MobSpec> with type, position_hint, etc.
|
|
14
|
+
// - boss: BossSpec | null
|
|
15
|
+
// - knot, level, zone_id, narrator_line
|
|
16
|
+
//
|
|
17
|
+
// The renderer never decides composition (spec §5.1, §6.5). It just
|
|
18
|
+
// applies what the Director said.
|
|
19
|
+
//
|
|
20
|
+
// Mob type mapping: the spec's `type` field is a string the Director
|
|
21
|
+
// chose. We map known strings to MobArchetype values; unknown strings
|
|
22
|
+
// fall back to 'skel_warrior' so the encounter still produces
|
|
23
|
+
// something visible.
|
|
24
|
+
import { RESOURCE_DIRECTOR_LOG, } from './director-system.js';
|
|
25
|
+
import { spawnMob, MOB_CATALOG, } from '../combat/mob-catalog.js';
|
|
26
|
+
// String -> MobArchetype map. The Director can emit any string in
|
|
27
|
+
// the type field (spec doesn't enumerate); the engine validates +
|
|
28
|
+
// falls back. New mob types added in subsequent phases just extend
|
|
29
|
+
// this map.
|
|
30
|
+
const TYPE_MAP = {
|
|
31
|
+
skel_warrior: 'skel_warrior',
|
|
32
|
+
skel_archer: 'skel_archer',
|
|
33
|
+
skel_caster: 'skel_caster',
|
|
34
|
+
// Aliases / legacy names from the existing Survivor that map to
|
|
35
|
+
// catalog archetypes.
|
|
36
|
+
skeleton_iron: 'skel_warrior',
|
|
37
|
+
skeleton_warrior: 'skel_warrior',
|
|
38
|
+
skeleton_archer: 'skel_archer',
|
|
39
|
+
skeleton_caster: 'skel_caster',
|
|
40
|
+
};
|
|
41
|
+
function resolveMobArchetype(typeStr) {
|
|
42
|
+
return TYPE_MAP[typeStr] ?? 'skel_warrior';
|
|
43
|
+
}
|
|
44
|
+
export class DirectorEncounterSystem {
|
|
45
|
+
name = 'director-encounter';
|
|
46
|
+
// Set of encounter_ids we've already spawned. Prevents duplicate
|
|
47
|
+
// spawn on event replay (spec §9.3 dual-delivery dedupe).
|
|
48
|
+
handled = new Set();
|
|
49
|
+
opts;
|
|
50
|
+
constructor(opts) {
|
|
51
|
+
this.opts = opts;
|
|
52
|
+
}
|
|
53
|
+
update(world, _dt) {
|
|
54
|
+
const log = world.resources.get(RESOURCE_DIRECTOR_LOG);
|
|
55
|
+
if (!log)
|
|
56
|
+
return;
|
|
57
|
+
// Walk recent events from the log. recent is newest-first and
|
|
58
|
+
// capped at 32 (per DirectorSystem ring buffer). Iterate from
|
|
59
|
+
// oldest-to-newest so multi-encounter ticks spawn in order.
|
|
60
|
+
for (let i = log.recent.length - 1; i >= 0; i--) {
|
|
61
|
+
const ev = log.recent[i];
|
|
62
|
+
if (!ev || ev.type !== 'encounter.spawn')
|
|
63
|
+
continue;
|
|
64
|
+
const spawn = ev;
|
|
65
|
+
const id = spawn.data.encounter_id;
|
|
66
|
+
if (!id || this.handled.has(id))
|
|
67
|
+
continue;
|
|
68
|
+
this.spawnEncounter(world, spawn.data);
|
|
69
|
+
this.handled.add(id);
|
|
70
|
+
}
|
|
71
|
+
// On encounter.end events, free up the encounter id so a future
|
|
72
|
+
// re-emission (e.g. retry) can spawn again.
|
|
73
|
+
for (let i = log.recent.length - 1; i >= 0; i--) {
|
|
74
|
+
const ev = log.recent[i];
|
|
75
|
+
if (!ev || ev.type !== 'encounter.end')
|
|
76
|
+
continue;
|
|
77
|
+
const id = ev.encounter_id;
|
|
78
|
+
if (id)
|
|
79
|
+
this.handled.delete(id);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
spawnEncounter(world, data) {
|
|
83
|
+
let totalSpawned = 0;
|
|
84
|
+
for (const mob of data.mobs) {
|
|
85
|
+
totalSpawned += this.spawnOne(world, mob);
|
|
86
|
+
}
|
|
87
|
+
// Boss spawn (if present).
|
|
88
|
+
if (data.boss) {
|
|
89
|
+
// Bosses use the same spawnMob factory in v1; future work
|
|
90
|
+
// adds a spawnBoss with bigger HP / unique behaviour.
|
|
91
|
+
const archetype = resolveMobArchetype(data.boss.type);
|
|
92
|
+
// Verify the catalog has the entry before spawning - prevents
|
|
93
|
+
// a typo on the Director side from crashing the renderer.
|
|
94
|
+
if (MOB_CATALOG[archetype]) {
|
|
95
|
+
spawnMob(world, archetype, data.boss.position_hint.x, data.boss.position_hint.y, this.opts.player, this.opts.mobAtlas);
|
|
96
|
+
totalSpawned++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (this.opts.onEncounterStarted) {
|
|
100
|
+
this.opts.onEncounterStarted(data.encounter_id, totalSpawned, data.narrator_line);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
spawnOne(world, mob) {
|
|
104
|
+
const archetype = resolveMobArchetype(mob.type);
|
|
105
|
+
if (!MOB_CATALOG[archetype])
|
|
106
|
+
return 0;
|
|
107
|
+
const baseX = mob.position_hint.x;
|
|
108
|
+
const baseY = mob.position_hint.y;
|
|
109
|
+
// count > 1 spawns multiple instances at slightly varied
|
|
110
|
+
// positions (small radius around the position_hint).
|
|
111
|
+
for (let i = 0; i < mob.count; i++) {
|
|
112
|
+
const angle = (i / Math.max(1, mob.count)) * Math.PI * 2;
|
|
113
|
+
const spread = mob.count > 1 ? 0.5 : 0;
|
|
114
|
+
spawnMob(world, archetype, baseX + Math.cos(angle) * spread, baseY + Math.sin(angle) * spread, this.opts.player, this.opts.mobAtlas);
|
|
115
|
+
}
|
|
116
|
+
return mob.count;
|
|
117
|
+
}
|
|
118
|
+
// Test / debug helper: clear the handled-id cache. Used by demo
|
|
119
|
+
// code when transitioning zones so a fresh encounter.spawn for a
|
|
120
|
+
// re-entered zone re-spawns mobs.
|
|
121
|
+
clearHandled() {
|
|
122
|
+
this.handled.clear();
|
|
123
|
+
}
|
|
124
|
+
hasHandled(encounterId) {
|
|
125
|
+
return this.handled.has(encounterId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=director-encounter-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"director-encounter-system.js","sourceRoot":"","sources":["../../src/director/director-encounter-system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { System } from '../system.js';
|
|
2
|
+
import type { World } from '../world.js';
|
|
3
|
+
import type { DirectorEvent, VeilTier } from './event-envelope.js';
|
|
4
|
+
export interface DirectorEventLog {
|
|
5
|
+
recent: DirectorEvent[];
|
|
6
|
+
lastNarratorLine: string | null;
|
|
7
|
+
lastNarratorTtlMs: number;
|
|
8
|
+
lastKnot: string | null;
|
|
9
|
+
activeEncounterId: string | null;
|
|
10
|
+
lastTier: VeilTier;
|
|
11
|
+
eventsApplied: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const RESOURCE_DIRECTOR_LOG = "director_log";
|
|
14
|
+
export declare function createDirectorEventLog(): DirectorEventLog;
|
|
15
|
+
export declare class DirectorSystem implements System {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
update(world: World, _dt: number): void;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=director-system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"director-system.d.ts","sourceRoot":"","sources":["../../src/director/director-system.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAazC,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACT,MAAM,qBAAqB,CAAC;AAG7B,MAAM,WAAW,gBAAgB;IAE/B,MAAM,EAAE,aAAa,EAAE,CAAC;IAExB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAG1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjC,QAAQ,EAAE,QAAQ,CAAC;IAEnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AAIpD,wBAAgB,sBAAsB,IAAI,gBAAgB,CAUzD;AAwBD,qBAAa,cAAe,YAAW,MAAM;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAc;IAEnC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CAwBxC"}
|