@lite-fsm/entities 0.1.0-alpha.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/PERFORMANCE.md +537 -0
- package/README.md +395 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -0
- package/dist/internal.d.cts +5 -0
- package/dist/internal.d.ts +5 -0
- package/dist/machine-extension.d.cts +153 -0
- package/dist/machine-extension.d.ts +153 -0
- package/dist/plugin.d.cts +32 -0
- package/dist/plugin.d.ts +32 -0
- package/dist/react/index.d.cts +11 -0
- package/dist/react/index.d.ts +11 -0
- package/dist/react.cjs +1 -0
- package/dist/react.js +1 -0
- package/dist/runtime/access.d.cts +72 -0
- package/dist/runtime/access.d.ts +72 -0
- package/dist/runtime/columns.d.cts +11 -0
- package/dist/runtime/columns.d.ts +11 -0
- package/dist/runtime/compile.d.cts +68 -0
- package/dist/runtime/compile.d.ts +68 -0
- package/dist/runtime/effects.d.cts +26 -0
- package/dist/runtime/effects.d.ts +26 -0
- package/dist/runtime/lifecycle.d.cts +10 -0
- package/dist/runtime/lifecycle.d.ts +10 -0
- package/dist/runtime/mutation-snapshot.d.cts +41 -0
- package/dist/runtime/mutation-snapshot.d.ts +41 -0
- package/dist/runtime/react.d.cts +29 -0
- package/dist/runtime/react.d.ts +29 -0
- package/dist/runtime/reactions.d.cts +15 -0
- package/dist/runtime/reactions.d.ts +15 -0
- package/dist/runtime/reduce-batch.d.cts +6 -0
- package/dist/runtime/reduce-batch.d.ts +6 -0
- package/dist/runtime/reduce-despawn.d.cts +7 -0
- package/dist/runtime/reduce-despawn.d.ts +7 -0
- package/dist/runtime/reduce-post-process.d.cts +35 -0
- package/dist/runtime/reduce-post-process.d.ts +35 -0
- package/dist/runtime/reduce-shared.d.cts +34 -0
- package/dist/runtime/reduce-shared.d.ts +34 -0
- package/dist/runtime/reduce-spawn.d.cts +5 -0
- package/dist/runtime/reduce-spawn.d.ts +5 -0
- package/dist/runtime/reduce-transitions.d.cts +11 -0
- package/dist/runtime/reduce-transitions.d.ts +11 -0
- package/dist/runtime/reduce.d.cts +5 -0
- package/dist/runtime/reduce.d.ts +5 -0
- package/dist/runtime/routing.d.cts +11 -0
- package/dist/runtime/routing.d.ts +11 -0
- package/dist/runtime/runtime-index.d.cts +23 -0
- package/dist/runtime/runtime-index.d.ts +23 -0
- package/dist/runtime/snapshot-export.d.cts +12 -0
- package/dist/runtime/snapshot-export.d.ts +12 -0
- package/dist/runtime/snapshot-import.d.cts +5 -0
- package/dist/runtime/snapshot-import.d.ts +5 -0
- package/dist/runtime/snapshot-types.d.cts +56 -0
- package/dist/runtime/snapshot-types.d.ts +56 -0
- package/dist/runtime/snapshot.d.cts +15 -0
- package/dist/runtime/snapshot.d.ts +15 -0
- package/dist/runtime/spawn-commit.d.cts +10 -0
- package/dist/runtime/spawn-commit.d.ts +10 -0
- package/dist/runtime/state.d.cts +15 -0
- package/dist/runtime/state.d.ts +15 -0
- package/dist/runtime/storage.d.cts +19 -0
- package/dist/runtime/storage.d.ts +19 -0
- package/dist/runtime/store-types.d.cts +81 -0
- package/dist/runtime/store-types.d.ts +81 -0
- package/dist/runtime/transaction.d.cts +104 -0
- package/dist/runtime/transaction.d.ts +104 -0
- package/dist/runtime/transitionTrace.d.cts +19 -0
- package/dist/runtime/transitionTrace.d.ts +19 -0
- package/dist/schema.d.cts +90 -0
- package/dist/schema.d.ts +90 -0
- package/dist/spawn.d.cts +56 -0
- package/dist/spawn.d.ts +56 -0
- package/package.json +90 -0
package/README.md
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# @lite-fsm/entities
|
|
2
|
+
|
|
3
|
+
Alpha-плагин для `lite-fsm`, который добавляет колоночное (SoA) хранилище сущностей поверх обычных машин. Одна машина описывает шаблон сущности, а её состояние и контекст хранятся в типизированных массивах для тысяч строк сразу. Подход близок к ECS: данные лежат в колонках, переходы выполняются батчами по всем живым строкам.
|
|
4
|
+
|
|
5
|
+
> Статус: alpha. Публичный API и формат снимков могут меняться. Текущие замеры производительности см. в [`PERFORMANCE.md`](./PERFORMANCE.md).
|
|
6
|
+
|
|
7
|
+
## Возможности
|
|
8
|
+
|
|
9
|
+
- Колоночное хранилище: каждое поле контекста — отдельный `TypedArray` (`f32`/`i16`/`i32`/`u8`) или массив строк.
|
|
10
|
+
- Машина-шаблон с `storage: "entity"`: один `config`/`reducer` обслуживает все строки сразу.
|
|
11
|
+
- Декларативный спавн: события спавна и рецепты, которые создают одну или несколько сущностей из одного payload.
|
|
12
|
+
- Управляемый жизненный цикл: внутренние события `ENTITY_SPAWNED`/`ENTITY_DESPAWNED` и авто-удаление по `despawnOn`.
|
|
13
|
+
- Runtime resources через `resource(...)`: общий объект шаблона на один manager instance для spatial grid, flow field, physics world, pathfinding cache и scratch buffers.
|
|
14
|
+
- `effects` для диспатча новых событий и `reactions` для синхронизации с внешним миром (рендер, звук) без диспатча.
|
|
15
|
+
- Маршрутизация по `entityId`, `groupId`, `groupTag` через `meta`.
|
|
16
|
+
- Типобезопасный доступ к колонкам через `manager.entities()` и React-хуки.
|
|
17
|
+
|
|
18
|
+
## Установка
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @lite-fsm/core @lite-fsm/entities
|
|
22
|
+
# React-хуки (опционально)
|
|
23
|
+
pnpm add @lite-fsm/react react
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Быстрый старт
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import {
|
|
30
|
+
createMachine as createLiteFsmMachine,
|
|
31
|
+
MachineManager,
|
|
32
|
+
type MachinesState,
|
|
33
|
+
type TypedCreateMachineFn,
|
|
34
|
+
} from "@lite-fsm/core";
|
|
35
|
+
import {
|
|
36
|
+
defineEntitySpawn,
|
|
37
|
+
defineSpawnEvents,
|
|
38
|
+
entitiesPlugin,
|
|
39
|
+
f32,
|
|
40
|
+
spawnEvent,
|
|
41
|
+
type EntitiesPlugin,
|
|
42
|
+
type EntityAccess,
|
|
43
|
+
type EntityIndex,
|
|
44
|
+
} from "@lite-fsm/entities";
|
|
45
|
+
|
|
46
|
+
type AppEvent = { readonly type: "TICK" };
|
|
47
|
+
type Deps = { readonly entities: () => EntityAccess<AppMachines> };
|
|
48
|
+
|
|
49
|
+
// Типизированный createMachine, который знает про storage: "entity".
|
|
50
|
+
const createMachine: TypedCreateMachineFn<AppEvent, Deps, EntitiesPlugin<Deps>> = createLiteFsmMachine;
|
|
51
|
+
|
|
52
|
+
const movement = createMachine({
|
|
53
|
+
storage: "entity",
|
|
54
|
+
initialState: "__INIT",
|
|
55
|
+
// Колонки строки: значение по умолчанию задаёт тип столбца.
|
|
56
|
+
initialContext: { x: f32({ default: 0 }), dx: f32({ default: 0 }) },
|
|
57
|
+
// Поля, которые приходят при спавне (без default).
|
|
58
|
+
spawnSchema: { x: f32(), dx: f32() },
|
|
59
|
+
config: {
|
|
60
|
+
__INIT: { ENTITY_SPAWNED: "active" },
|
|
61
|
+
active: { TICK: "active", ENTITY_DESPAWNED: "removed" },
|
|
62
|
+
removed: {},
|
|
63
|
+
},
|
|
64
|
+
reducer(_state, action, { self, payloadFor }) {
|
|
65
|
+
for (const entity of self.indices) {
|
|
66
|
+
if (action.type === "ENTITY_SPAWNED") {
|
|
67
|
+
const payload = payloadFor(entity);
|
|
68
|
+
self.x[entity] = payload.x;
|
|
69
|
+
self.dx[entity] = payload.dx;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (action.type === "TICK") self.x[entity] += self.dx[entity];
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const machines = { movement };
|
|
78
|
+
type AppMachines = typeof machines;
|
|
79
|
+
type AppState = MachinesState<AppMachines>;
|
|
80
|
+
|
|
81
|
+
// События спавна и их payload.
|
|
82
|
+
const spawnEvents = defineSpawnEvents({
|
|
83
|
+
SPAWN_UNIT: spawnEvent<{ id: string; x: number; dx: number }>(),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Рецепт превращает payload события в одну или несколько сущностей.
|
|
87
|
+
const spawn = defineEntitySpawn(
|
|
88
|
+
machines,
|
|
89
|
+
spawnEvents,
|
|
90
|
+
)({
|
|
91
|
+
SPAWN_UNIT: (p) => ({
|
|
92
|
+
id: `unit/${p.id}`,
|
|
93
|
+
groupTag: "unit",
|
|
94
|
+
actors: { movement: { x: p.x, dx: p.dx } },
|
|
95
|
+
}),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const manager = MachineManager(machines, {
|
|
99
|
+
plugins: [entitiesPlugin({ spawn })],
|
|
100
|
+
});
|
|
101
|
+
manager.setDependencies({ entities: manager.entities });
|
|
102
|
+
|
|
103
|
+
manager.transition({ type: "SPAWN_UNIT", payload: { id: "a", x: 0, dx: 2 } });
|
|
104
|
+
manager.transition({ type: "TICK" });
|
|
105
|
+
|
|
106
|
+
const view = manager.entities().get("movement");
|
|
107
|
+
view.count; // 1
|
|
108
|
+
const entity = 0 as EntityIndex;
|
|
109
|
+
if (view.has(entity)) {
|
|
110
|
+
view.x[entity]; // 2 — колонки индексируются по EntityIndex
|
|
111
|
+
view.state(entity); // "active"
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Модель данных: схемы, колонки и resources
|
|
116
|
+
|
|
117
|
+
Авторитативные данные строки хранятся в колонках. Поле колонки описывается дескриптором, который задаёт тип столбца и значение по умолчанию.
|
|
118
|
+
|
|
119
|
+
| Дескриптор | Колонка | Значение |
|
|
120
|
+
| ------------- | -------------- | ---------------------------------------- |
|
|
121
|
+
| `f32()` | `Float32Array` | `number` |
|
|
122
|
+
| `i32()` | `Int32Array` | `number` |
|
|
123
|
+
| `i16()` | `Int16Array` | `number` |
|
|
124
|
+
| `u8()` | `Uint8Array` | `number` |
|
|
125
|
+
| `string()` | `string[]` | `string` |
|
|
126
|
+
| `optional(d)` | — | `value \| null` (только в `spawnSchema`) |
|
|
127
|
+
|
|
128
|
+
Две схемы решают разные задачи:
|
|
129
|
+
|
|
130
|
+
- `initialContext` — постоянные колонки строки и template-level runtime resources. Дескрипторы колонок требуют `default`, `optional(...)` запрещён.
|
|
131
|
+
- `spawnSchema` — данные, приходящие при спавне. `default` запрещён, `optional(...)` разрешён (значение может быть `null`), `resource(...)` запрещён.
|
|
132
|
+
|
|
133
|
+
Часть имён зарезервирована рантаймом (`count`, `capacity`, `ids`, `version`, `presence`, `stateCode` и др.) и не может использоваться как имя колонки или resource.
|
|
134
|
+
|
|
135
|
+
### Runtime resources
|
|
136
|
+
|
|
137
|
+
`resource(...)` объявляет template-level shared runtime field. Значение создаётся один раз при создании actor store внутри конкретного `MachineManager` instance и принадлежит шаблону, а не строке. Если передан `expose`, exposed view тоже создаётся один раз; owner object и exposed view сохраняют identity на время жизни менеджера. Resource не требует единственной активной строки, доступен как runtime ресурс шаблона и не индексируется по `EntityIndex`.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
type SpatialGrid = {
|
|
141
|
+
clear(): void;
|
|
142
|
+
insert(entity: EntityIndex, x: number, y: number): void;
|
|
143
|
+
queryRadius(x: number, y: number, radius: number): readonly EntityIndex[];
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
type SpatialGridView = {
|
|
147
|
+
queryRadius(x: number, y: number, radius: number): readonly EntityIndex[];
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
declare function createSpatialGrid(): SpatialGrid;
|
|
151
|
+
|
|
152
|
+
const movement = createMachine({
|
|
153
|
+
storage: "entity",
|
|
154
|
+
initialState: "__INIT",
|
|
155
|
+
initialContext: {
|
|
156
|
+
x: f32({ default: 0 }),
|
|
157
|
+
y: f32({ default: 0 }),
|
|
158
|
+
unitGrid: resource(
|
|
159
|
+
createSpatialGrid,
|
|
160
|
+
(grid): SpatialGridView => ({
|
|
161
|
+
queryRadius: grid.queryRadius.bind(grid),
|
|
162
|
+
}),
|
|
163
|
+
),
|
|
164
|
+
scratch: resource(() => new Int32Array(256)),
|
|
165
|
+
},
|
|
166
|
+
spawnSchema: {
|
|
167
|
+
x: f32(),
|
|
168
|
+
y: f32(),
|
|
169
|
+
},
|
|
170
|
+
config: {
|
|
171
|
+
__INIT: { ENTITY_SPAWNED: "active" },
|
|
172
|
+
active: { TICK: "active" },
|
|
173
|
+
},
|
|
174
|
+
reducer(_state, action, { self }) {
|
|
175
|
+
if (action.type !== "TICK") return;
|
|
176
|
+
|
|
177
|
+
self.unitGrid.clear();
|
|
178
|
+
self.scratch.fill(-1);
|
|
179
|
+
|
|
180
|
+
for (const entity of self.indices) {
|
|
181
|
+
self.unitGrid.insert(entity, self.x[entity], self.y[entity]);
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Правила доступа:
|
|
188
|
+
|
|
189
|
+
- `resource(factory)` создаёт private owner-only resource. Он доступен владельцу как `self.<resource>` в reducer, effect и reaction этого же шаблона, но отсутствует в `EntityAccess`.
|
|
190
|
+
- `resource(factory, expose)` создаёт owner resource и публикует значение, возвращённое `expose`, в `entities().get(key)`. Consumer видит ровно exposed view, а не owner object.
|
|
191
|
+
- Owner `self` получает mutable owner object. Например, `self.unitGrid.clear()` и `self.scratch.fill(...)` разрешены; `self.unitGrid` не является колонкой и не читается по индексу строки.
|
|
192
|
+
- Exposed view доступен через `manager.entities()` и `entities()` даже при `0` active rows у шаблона. Без `expose` поле не публикуется.
|
|
193
|
+
- `expose` отвечает за форму и безопасность consumer surface. Runtime не анализирует mutating methods и не создаёт proxy, freeze или deep-freeze для owner object или exposed view.
|
|
194
|
+
|
|
195
|
+
Resource не является источником авторитативного состояния домена. Не используйте resource для `hp`, `command`, `selected`, `ownership` и других авторитативных фактов домена; колонки и spawn payload остаются источником данных строки. Resource подходит для детерминированных cache и рабочих структур, которые owner reducer пересобирает из колонок в порядке шаблонов: spatial grid, flow field, physics world, pathfinding cache, scratch buffers.
|
|
196
|
+
|
|
197
|
+
Для большого числа временных объектов, например снарядов, предпочтителен system actor с SoA-пулом внутри `resource(...)`, если каждый объект живет недолго и не требует отдельного entity lifecycle. Такой owner reducer обновляет пул батчем, переиспользует typed buffers, выполняет bounded spatial query для попаданий или AoE, удаляет элементы через swap и публикует только узкий read view или handoff buffer. Авторитативный эффект попадания все равно должен применяться владельцем доменной колонки, например `health` читает damage buffer и меняет `hp`.
|
|
198
|
+
|
|
199
|
+
Resource не входит в public state: `dehydrate()`, `hydrate()` payload, persistence, `MachinesState`, `manager.getSnapshot()`, selectors, `useEntitySnapshot` и `useEntityList` содержат только строки, состояния и колонки. `hydrate()` существующего manager не заменяет resource values и exposed views.
|
|
200
|
+
|
|
201
|
+
Rollback для resource в v1 не реализован. Staged spawn rollback откатывает строки, колонки и индексы, но не восстанавливает мутации resource. Owner reducer должен сначала валидировать и читать входные данные, затем мутировать или пересобирать resource и не бросать ошибку после начала мутации. Для RTS-сценариев rebuild выполняется штатным событием, например `TICK`, без отдельного механизма восстановления resource.
|
|
202
|
+
|
|
203
|
+
## Жизненный цикл сущности
|
|
204
|
+
|
|
205
|
+
Машина-шаблон стартует из служебного состояния `__INIT`. Единственный разрешённый переход из него — по внутреннему событию `ENTITY_SPAWNED`.
|
|
206
|
+
|
|
207
|
+
- `ENTITY_SPAWNED` — рантайм диспатчит автоматически при создании строки. В этот момент доступен `payloadFor(entity)`.
|
|
208
|
+
- `ENTITY_DESPAWNED` — локальный hook для строк актёра, которые удаляются в текущем `transition`. Reducer и `reactions.ENTITY_DESPAWNED` видят колонки до физического удаления строки.
|
|
209
|
+
- `despawnOn: "state"` (или массив состояний) — как только строка переходит в указанное состояние, рантайм автоматически удаляет её.
|
|
210
|
+
|
|
211
|
+
Прямой публичный диспатч `ENTITY_SPAWNED`/`ENTITY_DESPAWNED` запрещён. Сущности создаются только через события спавна, а удаляются через `despawnOn` или `transition.despawn(...)` в эффекте.
|
|
212
|
+
|
|
213
|
+
Финальную синхронизацию с внешними системами выполняйте в `reactions.ENTITY_DESPAWNED`. `effects`, связанные с целевым состоянием перехода по `ENTITY_DESPAWNED`, не являются контрактом cleanup.
|
|
214
|
+
|
|
215
|
+
## Reducer
|
|
216
|
+
|
|
217
|
+
`storage: "entity"` reducer является entity system reducer: он выполняется один раз для батча затронутых строк, читает root entity runtime через `entities()` и мутирует только `self` текущей машины. Первый аргумент (`state`) не используется в entity-машинах.
|
|
218
|
+
|
|
219
|
+
`self` даёт доступ к колонкам, owner resources и метаданным строк текущего батча:
|
|
220
|
+
|
|
221
|
+
- `self.indices` — индексы (`EntityIndex`) строк текущего reducer batch.
|
|
222
|
+
- `self.<column>[entity]` — чтение и запись значения колонки текущей машины.
|
|
223
|
+
- `self.<resource>` — mutable owner resource текущего шаблона; значение общее для всех строк и не индексируется по `EntityIndex`.
|
|
224
|
+
- `self.states.<STATE>` — числовой код состояния; запись `self.stateCode[entity] = self.states.expired` планирует переход строки.
|
|
225
|
+
- `self.has(entity)`, `self.entityId(entity)` — проверка наличия и строковый id строки.
|
|
226
|
+
- `payloadFor(entity)` — данные спавна для строки (валидно на `ENTITY_SPAWNED`).
|
|
227
|
+
- `entities()` — live read view всего entity runtime, доступный на `ENTITY_SPAWNED`, public events и routed events.
|
|
228
|
+
|
|
229
|
+
`entities()` в reducer — live view, а не snapshot на начало события. Reducer видит записи entity reducers, которые уже выполнились раньше в текущем `transition`, и не видит будущие записи reducers, которые стоят позже. Порядок entity machines в объекте `machines` является simulation contract для одного event.
|
|
230
|
+
|
|
231
|
+
`self.indices` ограничивает строки текущего батча, а `entities()` читает все entity stores без scoped validation по этому батчу. Перед чтением optional row другого store проверяйте `view.has(entity)`. Представления, полученные через `entities().get(...)`, типизированы только для чтения: писать можно только в `self`. Runtime не добавляет proxy или freeze для защиты от обхода типов через `as any`.
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
reducer(_state, action, { self, entities, payloadFor }) {
|
|
235
|
+
if (action.type === "ENTITY_SPAWNED") {
|
|
236
|
+
for (const entity of self.indices) {
|
|
237
|
+
const payload = payloadFor(entity);
|
|
238
|
+
self.x[entity] = payload.x;
|
|
239
|
+
self.y[entity] = payload.y;
|
|
240
|
+
self.vx[entity] = payload.vx;
|
|
241
|
+
self.vy[entity] = payload.vy;
|
|
242
|
+
}
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (action.type !== "TICK") return;
|
|
247
|
+
|
|
248
|
+
const health = entities().get("health");
|
|
249
|
+
|
|
250
|
+
for (const entity of self.indices) {
|
|
251
|
+
if (!health.has(entity) || health.hp[entity] <= 0) continue;
|
|
252
|
+
self.x[entity] += self.vx[entity];
|
|
253
|
+
self.y[entity] += self.vy[entity];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Reducer должен быть синхронным и детерминированным: в контекст не передаются deps или `transition`, нельзя возвращать Promise, запускать async work, IO или внешние side effects. `self`, `entities()` и store views действуют только во время текущего вызова reducer; не сохраняйте их для последующего использования.
|
|
259
|
+
|
|
260
|
+
Для hot-path entity state не используйте цепочку `reaction -> orchestrator -> scratch -> flush events`. Переносите расчёт в entity system reducer, оставляя `reactions` для внешней синхронизации, а `effects` — для редких событий, удаления сущностей и async/IO.
|
|
261
|
+
|
|
262
|
+
## Effects
|
|
263
|
+
|
|
264
|
+
`effects` объявляются по имени состояния и выполняются при входе строк в это состояние. Эффект может диспатчить новые события и удалять сущности. В аргументах: прикладные зависимости плюс `action`, `self`, `entities()` и `transition`.
|
|
265
|
+
|
|
266
|
+
`transition` — это функция и набор адресных методов:
|
|
267
|
+
|
|
268
|
+
- `transition(action)` — обычный диспатч.
|
|
269
|
+
- `transition.entity(id, action)` — только указанным сущностям.
|
|
270
|
+
- `transition.actor(actorId, action)` / `transition.group(...)` / `transition.tag(groupTag, action)` — по адресу.
|
|
271
|
+
- `transition.unscoped(action)` — без маршрутизации.
|
|
272
|
+
- `transition.despawn(ids | self.indices)` — удалить сущности.
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
effects: {
|
|
276
|
+
EXPIRED: ({ self, transition }) => {
|
|
277
|
+
transition.despawn(self.indices);
|
|
278
|
+
},
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Reactions
|
|
283
|
+
|
|
284
|
+
`reactions` объявляются по типу события и выполняются после коммита транзакции. Они предназначены для синхронного обновления внешних систем и не могут диспатчить события. В аргументах: прикладные зависимости плюс `action` и `self`. Кросс-машинные колонки читаются через `entities()` (если он передан в зависимости).
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
reactions: {
|
|
288
|
+
TICK: ({ self, entities, sprites }) => {
|
|
289
|
+
const move = entities().get("movement");
|
|
290
|
+
for (const entity of self.indices) {
|
|
291
|
+
sprites.sync(self.spriteId[entity], { x: move.x[entity] });
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`self.indices` в reaction — настоящий `readonly EntityIndex[]` для текущего синхронного вызова. `self`, `self.indices`, `deps` и представления из `entities()` нельзя мутировать и нельзя сохранять для использования после завершения reaction.
|
|
298
|
+
|
|
299
|
+
`effects` меняют состояние (диспатчат), `reactions` только читают и вызывают побочные эффекты.
|
|
300
|
+
|
|
301
|
+
## Спавн сущностей
|
|
302
|
+
|
|
303
|
+
Спавн описывается в три шага и подключается через `entitiesPlugin({ spawn })`:
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
// 1. События спавна и их payload.
|
|
307
|
+
const spawnEvents = defineSpawnEvents({
|
|
308
|
+
SPAWN_UNIT: spawnEvent<{ id: string; x: number }>(),
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// 2. Рецепты: payload -> одна сущность или массив сущностей.
|
|
312
|
+
const spawn = defineEntitySpawn(
|
|
313
|
+
machines,
|
|
314
|
+
spawnEvents,
|
|
315
|
+
)({
|
|
316
|
+
SPAWN_UNIT: (p) => ({
|
|
317
|
+
id: `unit/${p.id}`, // уникальный id сущности
|
|
318
|
+
groupTag: "unit", // тег для группового адреса и фильтрации
|
|
319
|
+
actors: {
|
|
320
|
+
// какие машины-шаблоны получают строку
|
|
321
|
+
movement: { x: p.x, dx: 0 },
|
|
322
|
+
},
|
|
323
|
+
}),
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Одна сущность может состоять из нескольких актёров (`movement`, `sprite`, ...), которые делят общий `id` и `groupTag`. Поля каждого актёра проверяются по его `spawnSchema`.
|
|
328
|
+
|
|
329
|
+
## Чтение состояния
|
|
330
|
+
|
|
331
|
+
`manager.entities()` возвращает корневой доступ ко всем entity stores:
|
|
332
|
+
|
|
333
|
+
- `entities().get(key)` — представление шаблона: `count`, `version`, `has(entity)`, `state(entity)` и колонки только для чтения. Строки индексируются по `EntityIndex` (`view.x[entity]`).
|
|
334
|
+
- `entities().maybe(key)` — на root access возвращает такой же read-only view; отличие от `get` по scoped validation относится к effects/reactions.
|
|
335
|
+
|
|
336
|
+
Значение колонки является публичным состоянием только для живой строки: сначала проверяйте `view.has(entity) === true`. После `has(entity) === false` значения `view.<column>[entity]` могут оставаться устаревшими до повторного использования слота и не являются частью публичного контракта. `dehydrate()` не публикует runtime values удалённых слотов: в JSON для них записываются defaults из `initialContext`.
|
|
337
|
+
|
|
338
|
+
`version` у entity store и actor store — монотонный invalidation token. Он меняется при видимом изменении хранилища, но точная величина инкремента не является счетчиком строк, событий или мутаций.
|
|
339
|
+
|
|
340
|
+
В reducer поле `entities()` предоставляет тот же root access object через storage runtime и не выполняет scoped validation. Для строгих ключей и колонок в reducer объявите `AppDeps.entities: () => EntityAccess<AppMachines>` в типе, который передаётся в `EntitiesPlugin<AppDeps>`; runtime reducer не читает это поле из deps. В effects и reactions runtime создает scoped access: там `get` проверяет текущий scope в dev, а `maybe` возвращает view без этой проверки. Для effects и reactions передавайте `manager.entities` через `manager.setDependencies(...)`.
|
|
341
|
+
|
|
342
|
+
## React
|
|
343
|
+
|
|
344
|
+
Хуки доступны из `@lite-fsm/entities/react` и подписываются на менеджер через `@lite-fsm/react`. Корректно работают с SSR и hydration preview.
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
import { useEntityList, useEntitySnapshot } from "@lite-fsm/entities/react";
|
|
348
|
+
|
|
349
|
+
function Units() {
|
|
350
|
+
const ids = useEntityList<AppMachines>("movement", { groupTag: "unit" });
|
|
351
|
+
return (
|
|
352
|
+
<ul>
|
|
353
|
+
{ids.map((id) => (
|
|
354
|
+
<Unit key={id} id={id} />
|
|
355
|
+
))}
|
|
356
|
+
</ul>
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function Unit({ id }: { id: string }) {
|
|
361
|
+
const row = useEntitySnapshot<AppMachines>("movement", id);
|
|
362
|
+
if (!row) return null;
|
|
363
|
+
// row: { entityId, groupTag, state, context: { x, dx } }
|
|
364
|
+
return <div>{row.context.x}</div>;
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
| Хук | Возвращает |
|
|
369
|
+
| ------------------------------- | -------------------------------------------------------- |
|
|
370
|
+
| `useEntitySnapshot(key, id)` | `{ entityId, groupTag, state, context }` или `undefined` |
|
|
371
|
+
| `useEntityCount(key, options?)` | число живых строк |
|
|
372
|
+
| `useEntityList(key, options?)` | список `id` живых строк |
|
|
373
|
+
|
|
374
|
+
`options.groupTag` фильтрует строки по тегу группы.
|
|
375
|
+
|
|
376
|
+
## Маршрутизация
|
|
377
|
+
|
|
378
|
+
Плагин регистрирует ключ маршрутизации `entityId`. События можно адресовать конкретным целям через `meta` или адресные методы `transition`:
|
|
379
|
+
|
|
380
|
+
- `entityId` — конкретные сущности;
|
|
381
|
+
- `groupId` — все актёры одной сущности;
|
|
382
|
+
- `groupTag` — все сущности с заданным тегом.
|
|
383
|
+
|
|
384
|
+
В одном событии может быть только один активный ключ маршрутизации.
|
|
385
|
+
|
|
386
|
+
## Ограничения
|
|
387
|
+
|
|
388
|
+
- Alpha: API и формат снимков нестабильны.
|
|
389
|
+
- `condition()` в entity-эффектах не поддерживается.
|
|
390
|
+
- Производительность пока не проходит целевые бюджеты относительно ручного SoA ECS (см. [`PERFORMANCE.md`](./PERFORMANCE.md)).
|
|
391
|
+
|
|
392
|
+
## Экспорты
|
|
393
|
+
|
|
394
|
+
- Корень: `entitiesPlugin`, `defineEntitySpawn`, `defineSpawnEvents`, `spawnEvent`, дескрипторы `f32`/`i16`/`i32`/`u8`/`string`/`optional`/`resource`, типы `EntitiesPlugin`, `EntityAccess`, `EntityId`, `EntityIndex` и др.
|
|
395
|
+
- `@lite-fsm/entities/react`: `useEntitySnapshot`, `useEntityCount`, `useEntityList`.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var Vt=Object.defineProperty;var jo=Object.getOwnPropertyDescriptor;var Fo=Object.getOwnPropertyNames;var Ko=Object.prototype.hasOwnProperty;var Uo=(t,e)=>{for(var n in e)Vt(t,n,{get:e[n],enumerable:!0})},Go=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Fo(e))!Ko.call(t,r)&&r!==n&&Vt(t,r,{get:()=>e[r],enumerable:!(o=jo(e,r))||o.enumerable});return t};var Ho=t=>Go(Vt({},"__esModule",{value:!0}),t);var qa={};Uo(qa,{defineEntitySpawn:()=>an,defineSpawnEvents:()=>rn,entitiesPlugin:()=>Vo,f32:()=>Pe,i16:()=>Me,i32:()=>De,optional:()=>$e,resource:()=>Le,spawnEvent:()=>on,string:()=>_e,u8:()=>Oe});module.exports=Ho(qa);var ft=require("@lite-fsm/core");var jt=require("@lite-fsm/core");var Te=require("@lite-fsm/core"),m=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),I=t=>t!==null&&typeof t=="object"&&!Array.isArray(t)&&Object.getPrototypeOf(t)===Object.prototype,Y=()=>globalThis.process?.env?.NODE_ENV!=="production",g=t=>new Te.LiteFsmError("LITE_FSM_INVALID_STORAGE_RUNTIME",`[lite-fsm/entities] ${t}.`);var O="ENTITY_SPAWNED",L="ENTITY_DESPAWNED",Yo=new Set([O,L]),be=t=>Object.prototype.toString.call(t)==="[object Object]",St=(t,e)=>new jt.LiteFsmError("LITE_FSM_INVALID_STORAGE_CONFIG",`[lite-fsm/entities] machine '${t}' has invalid storage: "entity" config: ${e}.`),Ft=t=>Yo.has(t),Et=t=>{if(Ft(t))throw new jt.LiteFsmError("LITE_FSM_INVALID_STORAGE_RUNTIME",`[lite-fsm/entities] public dispatch of internal entity lifecycle event '${t}' is not allowed.`)},ke=(t,e)=>{if(!be(e))throw St(t,"config must be a plain object");if(!m(e,"__INIT"))throw St(t,"config.__INIT must be a transition map");let n=e.__INIT;if(!be(n))throw St(t,"config.__INIT must be a transition map");for(let o of Object.keys(n))if(o!==O)throw St(t,`custom event edge '${o}' from __INIT is not allowed; use '${O}'`)};var Z=require("@lite-fsm/core");var Be=require("@lite-fsm/core");var mt=Symbol.for("lite-fsm.entities.schema-descriptor"),Kt=Symbol.for("lite-fsm.entities.resource-descriptor"),qo=new Set(["count","capacity","ids","indexById","alive","generation","freeList","stateCode","version","columns","presence","rowVersion","indices","states"]),Wo=new Set(["acceptedScratch","acceptStateBucketsByEventCode","entityId","entitiesByGroupTag","groupTagByIndex","groupTagPosition","has","metadata","pendingPrevStateCodeSync","pendingPrevStateCodeSyncMark","pendingPrevStateCodeSyncToken","prevStateCode","publicSlice","reducerSelf","resources","resourceViews","routingScratchVersion","state","stateBuckets","statePosition","templateKey"]),zo=t=>qo.has(t),nt=(t,e)=>{let n=e&&m(e,"default")?{[mt]:!0,kind:t,default:e.default}:{[mt]:!0,kind:t};return Object.freeze(n)},Pe=t=>nt("f32",t),Me=t=>nt("i16",t),De=t=>nt("i32",t),Oe=t=>nt("u8",t),_e=t=>nt("string",t),$e=t=>Object.freeze({[mt]:!0,kind:"optional",inner:t});function Le(t,e){let n=e===void 0?{[Kt]:!0,kind:"resource",factory:t,exposed:!1}:{[Kt]:!0,kind:"resource",factory:t,expose:e,exposed:!0};return Object.freeze(n)}var Jo=t=>I(t)&&Reflect.get(t,mt)===!0,wt=t=>I(t)&&Reflect.get(t,Kt)===!0,Qo=t=>t.kind==="f32"||t.kind==="i16"||t.kind==="i32"||t.kind==="u8"||t.kind==="string",v=(t,e,n)=>new Be.LiteFsmError("LITE_FSM_INVALID_STORAGE_CONFIG",`[lite-fsm/entities] machine '${t}' has invalid ${e}: ${n}.`),Ne=t=>Array.isArray(t)?"arrays are not supported in entity schemas":t instanceof Map?"Map is not supported in entity schemas":t instanceof Set?"Set is not supported in entity schemas":Object.getPrototypeOf(t)!==Object.prototype?"custom prototype objects are not supported in entity schemas":"unknown descriptor shape",Xo=(t,e,n)=>{for(let o of Object.keys(n))if(o!=="kind"&&o!=="default"&&o!=="inner")throw v(t,e,`unknown descriptor property '${o}'`)},Zo=(t,e,n)=>{for(let o of Object.keys(n))if(o!=="kind"&&o!=="factory"&&o!=="expose"&&o!=="exposed")throw v(t,e,`unknown descriptor property '${o}'`)},tr=(t,e,n,o)=>{if(!m(n,"default"))return;if(!o)throw v(t,e,"default values are not allowed in spawnSchema");let r=n.default;if(n.kind==="string"?typeof r!="string":typeof r!="number")throw v(t,e,"default value does not match descriptor kind")},Ve=(t,e,n,o,r)=>{if(wt(n)){if(o)throw v(t,e,"resource(...) is not allowed in spawnSchema");Zo(t,e,n);return}if(!Jo(n))throw n!==null&&typeof n=="object"?v(t,e,Ne(n)):v(t,e,"schema field must be a descriptor");if(Xo(t,e,n),n.kind==="optional"){if(!o)throw v(t,e,"optional(...) is not allowed in initialContext");Ve(t,`${e}.inner`,n.inner,!1,r);return}if(!Qo(n))throw v(t,e,"unknown descriptor kind");tr(t,e,n,r)},Ut=(t,e,n)=>{if(!I(n))throw n!==null&&typeof n=="object"?v(t,e,Ne(n)):v(t,e,"schema must be a plain object");let o=e==="spawnSchema",r=e==="initialContext";for(let[i,a]of Object.entries(n)){let s=wt(a);if(zo(i)||e==="initialContext"&&s&&Wo.has(i))throw v(t,`${e}.${i}`,"field name is reserved");Ve(t,`${e}.${i}`,a,o,r)}};var ot=require("@lite-fsm/core");var er=t=>new ot.LiteFsmError("LITE_FSM_INVALID_STORAGE_RUNTIME",`[lite-fsm/entities] unknown entity actor template '${t}'.`),Fe=(t,e)=>{let n=t.actorStores[e];if(n)return n;throw er(e)},je=(t,e,n,o)=>new ot.LiteFsmError("LITE_FSM_INVALID_STORAGE_RUNTIME",`[lite-fsm/entities] scoped entities().get('${e}') failed for source actor '${t.sourceActor}' while handling '${t.eventType}' on entity '${n}': ${o}.`),Ke=(t,e)=>t.entityStore.alive[e.entity]===1&&t.entityStore.generation[e.entity]===e.generation,nr=(t,e,n,o)=>{if(Y())for(let r of e.entries){if(!Ke(t,r))throw je(e,n,r.id,"captured entity scope is stale");if(o.presence[r.entity]!==1)throw je(e,n,r.id,"requested actor row is missing")}},Ue=(t,e)=>{for(let n of Object.keys(e.columns))Object.defineProperty(t,n,{enumerable:!0,configurable:!0,writable:!1,value:e.columns[n]})},Ge=(t,e)=>{for(let[n,o]of Object.entries(e.resourceViews))Object.defineProperty(t,n,{enumerable:!0,configurable:!0,writable:!1,value:o})},He=new WeakMap,q=t=>{let e=He.get(t);e&&(Ue(e,t),Ge(e,t))},or=(t,e)=>{let n=Fe(t,e),o={get count(){return n.count},get version(){return n.version},has(r){return n.presence[r]===1},state(r){if(n.presence[r]===1){let i=n.stateCode[r];return n.metadata.publicStates[i]}}};return Ue(o,n),Ge(o,n),He.set(n,o),o},Ye=t=>{let e=new Map,n=o=>{let r=e.get(o);if(r)return r;let i=or(t,o);return e.set(o,i),i};return{get(o){return n(o)},maybe(o){return n(o)}}},qe=(t,e)=>new ot.LiteFsmError("LITE_FSM_INVALID_STORAGE_RUNTIME",`[lite-fsm/entities] entity index ${e} is outside current entity ${t} scope.`),gt=(t,e)=>new ot.LiteFsmError("LITE_FSM_INVALID_STORAGE_RUNTIME",`[lite-fsm/entities] entity index ${t} is stale in current entity reaction scope: ${e}.`),Gt=(t,e)=>{t.presence=e.presence,t.stateCode=e.stateCode,t.prevStateCode=e.prevStateCode,t.rowVersion=e.rowVersion;for(let[n,o]of Object.entries(e.columns))t[n]=o;for(let[n,o]of Object.entries(e.resources))t[n]=o},ht=(t,e)=>{let n={indices:e.indices,states:t.metadata.stateCodeByName,has:e.has,entityId:e.entityId};return Gt(n,t),n},We=(t,e,n)=>{let o,r=()=>{if(o)return o;let i=new Map;for(let a of n.entries)i.set(a.entity,a);return o=i,i};return ht(e,{indices:n.indices,has(i){let a=r().get(i);return a?Ke(t,a)&&e.presence[i]===1:!1},entityId(i){let a=r().get(i);if(a)return a.id;throw qe(n.scopeName,i)}})},ze=(t,e,n)=>{let o=a=>n.lifetime.token===n.token&&n.markers[a]===n.token,r=a=>t.entityStore.generation[a]===n.generation[a],i=a=>{let s=t.entityStore.ids[a];return s!==void 0&&s.length>0};return ht(e,{indices:n.indices,has(a){return o(a)&&r(a)&&t.entityStore.alive[a]===1&&e.presence[a]===1&&i(a)},entityId(a){if(!o(a))throw qe("reaction",a);if(!r(a))throw gt(a,"generation changed");if(t.entityStore.alive[a]!==1)throw gt(a,"entity is not live");if(e.presence[a]!==1)throw gt(a,"actor row is missing");let s=t.entityStore.ids[a];if(s!==void 0&&s.length>0)return s;throw gt(a,"entity id is missing")}})},Je=t=>t.access,Qe=(t,e)=>{let n=t.access;return{get(o){let r=Fe(t,o),i=n.get(o);return nr(t,e,o,r),i},maybe(o){return n.maybe(o)}}};var Xe=require("@lite-fsm/core");var Ze=Symbol.for("lite-fsm.entities.spawn-event"),tn=Symbol.for("lite-fsm.entities.spawn-descriptor"),N=t=>new Xe.LiteFsmError("LITE_FSM_INVALID_OPTIONS",`[lite-fsm/entities] invalid entity spawn config: ${t}.`),rr=t=>I(t)&&Reflect.get(t,Ze)===!0,en=(t,e)=>{if(Ft(e))throw N(`${t} cannot use internal lifecycle event '${e}'`)};function Ht(t){if(!I(t))throw N("spawnEvents must be a plain object");for(let[e,n]of Object.entries(t))if(en("spawnEvents",e),!rr(n))throw N(`spawnEvents.${e} must be created by spawnEvent()`)}function nn(t,e){if(!I(e))throw N("recipes must be a plain object");let n=Object.keys(t),o=new Set(n);for(let r of Object.keys(e)){if(en("recipes",r),!o.has(r))throw N(`unknown recipe key '${r}'`);if(typeof e[r]!="function")throw N(`recipe '${r}' must be a function`)}for(let r of n)if(!m(e,r))throw N(`missing recipe for spawn event '${r}'`)}var on=()=>Object.freeze({[Ze]:!0}),rn=t=>(Ht(t),Object.freeze({...t})),an=(t,e)=>n=>(Ht(e),nn(e,n),Object.freeze({[tn]:!0,spawnEvents:e,recipes:n})),ir=t=>I(t)&&Reflect.get(t,tn)===!0;function sn(t){if(!ir(t))throw N("entitiesPlugin({ spawn }) expects a value returned by defineEntitySpawn(...)");Ht(t.spawnEvents),nn(t.spawnEvents,t.recipes)}var cn=(t,e)=>m(t.recipes,e),dn=(t,e)=>{let n=t.recipes[e.type];return n(e.payload)};var ar="@lite-fsm/core/transition-trace",V=t=>{let e=t.runtime.get(ar);if(!e||typeof e!="object")return;let n=e;if(!(typeof n.depth!="number"||typeof n.now!="function"||typeof n.record!="function"||typeof n.count!="function"||typeof n.finish!="function"))return n},h=(t,e,n)=>{!t||n===void 0||t.record(e,n)},G=(t,e,n)=>{t&&t.count(e,n)},x=(t,e,n)=>{if(!t)return n();let o=t.now();try{return n()}finally{t.record(e,o)}},W=(t,e,n)=>x(V(t),e,n);var En="@lite-fsm/entities/transaction",mn=Symbol.for("@lite-fsm/entities/despawn-options"),Yt="LITE_FSM_ENTITY_DESPAWN",sr=new Uint8Array,yn=new WeakMap,un=16,pn=16,A=t=>g(`invalid entity spawn: ${t}`),cr=t=>{if(!(t===null||typeof t!="object"))return t[mn]},qt=t=>({[mn]:t}),dr=(t,e)=>{let n=t.runtime.entityStore.indexById[e];return n===void 0?!1:rt(t,n)},yr=(t,e)=>{let n=t.runtime.entityStore;if(!(n.alive[e.entity]!==1||n.generation[e.entity]!==e.generation))return rt(t,e.entity);if(Y())throw g(`stale entity effect scope cannot despawn entity '${e.id}' at index ${e.entity}`);return!1},ur=(t,e,n)=>{let o=cr(e);if(!o)return;let r=0;if(o.mode==="ids"){G(n,"entities.prepare.explicitDespawn.ids",o.ids.length);for(let i of o.ids)dr(t,i)&&(r+=1);G(n,"entities.prepare.explicitDespawn.scheduled",r);return}G(n,"entities.prepare.explicitDespawn.scopeEntries",o.entries.length);for(let i of o.entries)yr(t,i)&&(r+=1);G(n,"entities.prepare.explicitDespawn.scheduled",r)},M=t=>{let e=yn.get(t);if(e)return e;let n={despawnScheduled:sr,despawnScheduledMarks:[],despawnRowHintMarksByStoreId:[],despawnRowHintBucketStateCodeByStoreId:[],despawnRowHintMarks:[],cleanupScratchPool:[],cleanupScratchPoolCursor:0,reactionIndexPool:[],reactionIndexPoolCursor:0};return yn.set(t,n),n},pr=t=>{for(let e of t.despawnScheduledMarks)t.despawnScheduled[e]=0;t.despawnScheduledMarks.length=0},wn=t=>{for(let e of t.despawnRowHintMarks)t.despawnRowHintMarksByStoreId[e.storeId][e.entity]=0;t.despawnRowHintMarks.length=0},lr=t=>{for(let e=0;e<t.reactionIndexPoolCursor;e+=1)t.reactionIndexPool[e].length=0;t.reactionIndexPoolCursor=0},fr=()=>({entities:[],removalBatchesByStoreId:[],removalTouchedStoreIds:[],lifecycleBatchesByStoreId:[],lifecycleTouchedStoreIds:[]}),Wt=t=>{for(let e of t.removalTouchedStoreIds){let n=t.removalBatchesByStoreId[e];n&&(n.rows.length=0,n.bucketStateCodes.length=0,n.bucketStateCodesActive=!1)}t.removalTouchedStoreIds.length=0;for(let e of t.lifecycleTouchedStoreIds){let n=t.lifecycleBatchesByStoreId[e];n&&(n.indices.length=0)}t.lifecycleTouchedStoreIds.length=0,t.entities.length=0},Sr=t=>{if(t.cleanupScratchPoolCursor===0)for(let e of t.cleanupScratchPool)Wt(e)},gn=(t,e)=>{let n=M(e);pr(n),wn(n),Sr(n),lr(n);let o={runtime:e,stagedSpawns:[],scheduledDespawns:[],despawnScheduled:n.despawnScheduled,despawnRowHints:[],terminalRows:[],effectBatches:[],reactionBatches:[]};t.runtime.set(En,o);let r=V(t);return x(r,"entities.prepare.explicitDespawn",()=>ur(o,t.options,r)),o},j=t=>t.runtime.get(En),ln=(t,e)=>{if(typeof e=="string"&&e.length>0)return e;throw A(`${t} must be a non-empty string`)},fn=t=>t===void 0?"undefined":t===null?"null":typeof t,Sn=(t,e,n)=>{if(e==="string"){if(typeof n=="string")return;throw A(`${t} must be a string, got ${fn(n)}`)}if(!(typeof n=="number"&&Number.isFinite(n)))throw A(`${t} must be a finite number, got ${fn(n)}`)},Er=(t,e,n)=>{if(e.kind!=="optional"){Sn(t,String(e.kind),n);return}if(n!==null){if(n===void 0)throw A(`${t} is required and cannot be undefined`);Sn(t,String(e.inner.kind),n)}},mr=(t,e,n)=>{if(!I(n))throw A(`actor '${t}' payload must be a plain object`);for(let o in n)if(m(n,o)&&!m(e,o))throw A(`actor '${t}' payload has unknown key '${o}'`);for(let o in e){if(!m(e,o))continue;if(!m(n,o))throw A(`actor '${t}' payload is missing required key '${o}'`);let r=e[o];Er(`actor '${t}' payload.${o}`,r,n[o])}return n},wr=t=>{if(Array.isArray(t))return t;if(I(t))return[t];throw A("recipe must return an EntitySpawnSpec or an array of EntitySpawnSpec")},gr=(t,e,n)=>{if(!I(e))throw A("EntitySpawnSpec must be a plain object");let o=ln("EntitySpawnSpec.id",e.id),r=ln("EntitySpawnSpec.groupTag",e.groupTag),i=t.entityStore.indexById[o];if(i!==void 0&&t.entityStore.alive[i]===1)throw A(`duplicate entity id '${o}'`);if(n.has(o))throw A(`duplicate entity id '${o}' in one recipe result`);if(n.add(o),!I(e.actors))throw A(`EntitySpawnSpec '${o}' actors must be a plain object`);let a=[];for(let s in e.actors){if(!m(e.actors,s))continue;let c=e.actors[s],d=t.actorStores[s];if(!d)throw A(`unknown entity actor template '${s}'`);a.push({templateKey:s,payload:mr(s,d.metadata.spawnSchema,c)})}if(a.length===0)throw A(`EntitySpawnSpec '${o}' must contain at least one actor`);return{id:o,groupTag:r,actors:a}},hn=(t,e)=>{let n=V(t),o=n?.now();try{if(t.skipDelivery||!cn(e,t.action.type))return;let r=j(t);if(!r)throw A("entity transaction slot was not prepared before spawn staging");let i=x(n,"entities.spawn.stage.recipe",()=>dn(e,t.action)),a=x(n,"entities.spawn.stage.normalize",()=>wr(i));if(a.length===0){r.stagedSpawns=[];return}r.stagedSpawns=x(n,"entities.spawn.stage.validate",()=>{let s=new Set;return a.map(c=>gr(r.runtime,c,s))})}finally{h(n,"entities.spawn.stage",o)}},Rn=t=>{let e=j(t);return e?e.stagedSpawns:[]},hr=(t,e)=>{let n=t.despawnScheduled.length;if(n>=e)return;let o=Math.max(e,t.runtime.entityStore.capacity,un),r=Math.max(n,un);for(;r<o;)r*=2;let i=new Uint8Array(r);i.set(t.despawnScheduled),M(t.runtime).despawnScheduled=i,t.despawnScheduled=i},rt=(t,e)=>t.runtime.entityStore.alive[e]!==1||(hr(t,e+1),t.despawnScheduled[e]===1)?!1:(t.despawnScheduled[e]=1,t.scheduledDespawns.push(e),M(t.runtime).despawnScheduledMarks.push(e),!0),Rr=(t,e,n,o)=>{let r=t.despawnRowHintMarksByStoreId[e],i=t.despawnRowHintBucketStateCodeByStoreId[e];if(r&&i&&r.length>=n&&i.length>=n)return;let a=Math.min(r?.length??0,i?.length??0),s=Math.max(n,o,pn),c=Math.max(a,pn);for(;c<s;)c*=2;let d=new Uint8Array(c);r&&d.set(r),t.despawnRowHintMarksByStoreId[e]=d;let y=new Int16Array(c);i&&y.set(i),t.despawnRowHintBucketStateCodeByStoreId[e]=y},zt=(t,e,n,o)=>{let r=M(t.runtime);Rr(r,e.storeId,n+1,e.capacity);let i=r.despawnRowHintMarksByStoreId[e.storeId];if(i[n]===1)return!1;i[n]=1,r.despawnRowHintBucketStateCodeByStoreId[e.storeId][n]=o;let a={storeId:e.storeId,entity:n,bucketStateCode:o};return t.despawnRowHints.push(a),r.despawnRowHintMarks.push(a),!0},Cn=(t,e,n)=>{let o=M(t.runtime),r=o.despawnRowHintMarksByStoreId[e];if(!(!r||r[n]!==1))return o.despawnRowHintBucketStateCodeByStoreId[e][n]},xn=t=>{wn(M(t.runtime)),t.despawnRowHints=[]},An=t=>{let e=t.scheduledDespawns;t.scheduledDespawns=[];for(let n of e)t.despawnScheduled[n]=0;return M(t.runtime).despawnScheduledMarks.length=0,e},Jt=t=>{let e=M(t.runtime),n=e.cleanupScratchPoolCursor,o=e.cleanupScratchPool[n]??fr();return e.cleanupScratchPool[n]=o,e.cleanupScratchPoolCursor+=1,Wt(o),o},Qt=(t,e)=>{Wt(e);let n=M(t.runtime),o=n.cleanupScratchPoolCursor-1;o>=0&&n.cleanupScratchPool[o]===e&&(n.cleanupScratchPoolCursor=o)},In=(t,e,n,o)=>{let r=t.removalBatchesByStoreId[e.storeId];r||(r={store:e,rows:[],bucketStateCodes:[],bucketStateCodesActive:!1},t.removalBatchesByStoreId[e.storeId]=r),r.rows.length===0&&t.removalTouchedStoreIds.push(e.storeId),(o!==void 0||r.bucketStateCodesActive)&&(r.bucketStateCodesActive||(r.bucketStateCodes.length=r.rows.length,r.bucketStateCodesActive=!0),r.bucketStateCodes.push(o)),r.rows.push(n)},vn=(t,e,n)=>{let o=t.lifecycleBatchesByStoreId[e.storeId];o||(o={store:e,indices:[]},t.lifecycleBatchesByStoreId[e.storeId]=o),o.indices.length===0&&t.lifecycleTouchedStoreIds.push(e.storeId),o.indices.push(n)},Tn=(t,e,n,o,r)=>{if(!t||o.length===0||!e.metadata.effectsByStateCode[n])return;let i=t.runtime.entityStore;t.effectBatches.push({store:e,stateCode:n,indices:o,capturedEntries:r,storeVersion:e.version,entityStoreVersion:i.version})},Cr=(t,e)=>{let n=M(t.runtime),o=n.reactionIndexPoolCursor,r=n.reactionIndexPool[o]??[];n.reactionIndexPool[o]=r,n.reactionIndexPoolCursor+=1,r.length=e.length;for(let i=0;i<e.length;i+=1)r[i]=e[i];return r},Xt=(t,e,n,o,r={})=>{if(!t||n===void 0||o.length===0||!e.metadata.reactionsByEventCode[n])return;let i=r.ownership??"owned";return{store:e,eventCode:n,ownership:i,indices:i==="borrowed"?o:Cr(t,o)}},bn=(t,e,n,o,r)=>{if(!t)return;let i=Xt(t,e,n,o,r);i&&t.reactionBatches.push(i)};var Rt=(t,e)=>({...t,meta:{...t.meta??{},...e}}),xt=(t,e)=>{if(typeof e=="string")return[e];if(!Array.isArray(e)||e.some(n=>typeof n!="string"))throw g(`${t} target must be a string or an array of strings`);return e},xr=t=>{let e=new Set,n=[];for(let o of t)e.has(o)||(e.add(o),n.push(o));return n},Ct=t=>t.length===1?t[0]:t,Ar=(t,e)=>{let n=t.entityStore.indexById[e];return n!==void 0&&t.entityStore.alive[n]===1},kn=(t,e)=>xr(xt("entity",e)).filter(n=>Ar(t,n)),Ir=t=>g(`stale entity effect scope cannot despawn entity '${t.id}' at index ${t.entity}`),vr=(t,e)=>{let n=[],o=t.entityStore.alive,r=t.entityStore.generation;for(let i of e){if(o[i.entity]===1&&r[i.entity]===i.generation){n.push(i);continue}if(Y())throw Ir(i)}return n},Tr=(t,e,n)=>{let o=(r=>e.transition(r));return o.unscoped=r=>e.transition(r,{routingMode:"unscoped"}),o.actor=(r,i)=>e.transition(Rt(i,{actorId:Ct(xt("actor",r))})),o.group=(r,i)=>e.transition(Rt(i,{groupId:Ct(xt("group",r))})),o.tag=(r,i)=>e.transition(Rt(i,{groupTag:Ct(xt("tag",r))})),o.entity=(r,i)=>{let a=kn(t,r);return a.length===0?i:e.transition(Rt(i,{entityId:Ct(a)}))},o.despawn=r=>{if(typeof r=="string"||Array.isArray(r)&&r.every(i=>typeof i=="string")){let i=kn(t,r);if(i.length===0)return;e.transition({type:Yt},qt({mode:"ids",ids:i}));return}if(Array.isArray(r)&&r.every(i=>typeof i=="number")){if(r!==n.indices)throw g("transition.despawn(EntityIndex[]) only accepts self.indices from current entity effect scope");let i=vr(t,n.scope.entries);if(i.length===0)return;e.transition({type:Yt},qt({mode:"scope",entries:i}));return}throw g("transition.despawn(...) expects an entity id, entity id array or self.indices")},o},br=()=>{throw g('condition() is not supported in storage: "entity" effects')},kr=(t,e,n)=>n.capturedEntries!==void 0&&n.storeVersion===e.version&&n.entityStoreVersion===t.entityStore.version,Br=(t,e)=>({storeKey:t.store.templateKey,stateCode:t.stateCode,indices:t.indices,scope:{sourceActor:t.store.templateKey,eventType:e,entries:t.capturedEntries}}),Pr=(t,e,n)=>{let o=e.store,r=e.stateCode,i=e.indices,a=o.presence,s=o.stateCode,c=t.entityStore.alive,d=t.entityStore.ids,y=t.entityStore.generation,u=[],p,w=()=>{if(p)return p;p=[];for(let E=0;E<u.length;E+=1)p.push(u[E].entity);return p};for(let E=0;E<i.length;E+=1){let l=i[E];if(a[l]!==1||s[l]!==r||c[l]!==1){w();continue}let f=d[l];if(f===void 0||f.length===0){w();continue}u.push({entity:l,generation:y[l],id:f}),p?.push(l)}if(u.length!==0)return{storeKey:o.templateKey,stateCode:r,indices:p??i,scope:{sourceActor:o.templateKey,eventType:n,entries:u}}},Bn=(t,e)=>{let n=j(e.dispatch);if(!n||n.effectBatches.length===0)return[];let o=e.action.type,r=[];for(let i of n.effectBatches){if(!i.store.metadata.effectsByStateCode[i.stateCode])continue;if(kr(t,i.store,i)){r.push(Br(i,o));continue}let a=Pr(t,i,o);a&&r.push(a)}return r},Pn=(t,e,n)=>{let o=t.actorStores[e.storeKey],r=o?.metadata.effectsByStateCode[e.stateCode];if(!o||!r)return;let i=Qe(t,e.scope),a=Object.create(n.manager.getDependencies());a.action=n.action,a.self=We(t,o,{scopeName:"effect",indices:e.indices,entries:e.scope.entries}),a.entities=()=>i,a.transition=Tr(t,n.manager,e),a.condition=br;try{let s=r(a);s instanceof Promise&&s.catch(c=>{n.dispatch.reportError(c)})}catch(s){n.dispatch.reportError(s)}};var Mn=require("@lite-fsm/core");var At="__INIT",R=-1,it=-2,at=-3,st=-4,F=-32768,It=-32767,Mr=new Set(["__INIT","__RESOLVED","__REJECTED","__CANCELLED","*"]),Dr=new Set(["__INIT","__RESOLVED","__REJECTED","__CANCELLED"]),Or={__RESOLVED:it,__REJECTED:at,__CANCELLED:st},_r={[it]:"__RESOLVED",[at]:"__REJECTED",[st]:"__CANCELLED"},B=(t,e)=>new Mn.LiteFsmError("LITE_FSM_INVALID_STORAGE_CONFIG",`[lite-fsm/entities] machine '${t}' has invalid storage: "entity" config: ${e}.`),$r=t=>{let e=Object.create(null),n=Object.create(null);for(let[o,r]of Object.entries(t)){if(wt(r)){n[o]=r;continue}e[o]=r}return{initialContext:e,resourceSchema:n}},Lr=(t,e)=>e===At?R:t.stateCodeByName[e],Nr=(t,e)=>e===At?R:Or[e]??t.stateCodeByName[e],Dn=t=>t+1,P=t=>t===it||t===at||t===st,vt=t=>{for(let e=0;e<t.length;e+=1)if(t[e]===1)return!0;return!1},Vr=t=>{let e=[],n=new Set;for(let o of Object.values(t))if(o)for(let r of Object.keys(o))n.has(r)||(n.add(r),e.push(r));return e},jr=(t,e)=>{if(e===void 0)return[];if(typeof e=="string")return[e];if(Array.isArray(e)&&e.every(n=>typeof n=="string"))return e;throw B(t,"despawnOn must be a state name or a readonly array of state names")},Fr=(t,e,n,o)=>{let r=new Uint8Array(Object.keys(n).length);for(let i of jr(t,o)){if(Dr.has(i))throw B(t,`despawnOn cannot reference special state '${i}'`);if(!m(e,i))throw B(t,`despawnOn references unknown state '${i}'`);let a=n[i];if(a===void 0)throw B(t,`despawnOn references non-public state '${i}'`);r[a]=1}return r},Kr=(t,e,n)=>{let o=Array.from({length:Object.keys(e).length});if(n===void 0)return o;if(n===null||typeof n!="object"||Array.isArray(n))throw B(t,"effects must be a plain object keyed by public state names");for(let[r,i]of Object.entries(n)){if(r==="*")throw B(t,'wildcard "*" effects are not supported for storage: "entity"');if(!m(e,r))throw B(t,`effects references unknown public state '${r}'`);if(typeof i!="function")throw B(t,`effect for state '${r}' must be a function`);o[e[r]]=i}return o},Ur=(t,e,n)=>{let o=Object.create(null);if(n===void 0)return o;if(n===null||typeof n!="object"||Array.isArray(n))throw B(t,"reactions must be a plain object keyed by event names");let r=new Set(e);for(let[i,a]of Object.entries(n)){if(!r.has(i))throw B(t,`reactions references event '${i}' that is not accepted by config`);if(typeof a!="function")throw B(t,`reaction for event '${i}' must be a function`);o[i]=a}return o},Zt=(t,e)=>{let n=e.config,o=Object.keys(n).filter(s=>!Mr.has(s)),r=Object.fromEntries(o.map((s,c)=>[s,c])),i=Vr(n),a=$r(e.initialContext);return{templateKey:t,config:n,initialContext:a.initialContext,resourceSchema:a.resourceSchema,spawnSchema:e.spawnSchema,publicStates:o,stateCodeByName:r,eventTypes:i,eventAcceptMask:new Uint8Array(0),transitionTable:new Int16Array(0),transitionTargetByCell:Object.create(null),acceptStateCodesByEventCode:[],stateSlotCount:o.length+1,despawnStateMask:Fr(t,n,r,e.despawnOn),despawnLifecycleStateMask:new Uint8Array(o.length+1),effectsByStateCode:Kr(t,r,e.effects),reactionsByEventType:Ur(t,i,e.reactions),reactionsByEventCode:[],reducePlansByEventCode:[],...typeof e.reducer=="function"?{reducer:e.reducer}:{}}},Gr=(t,e,n)=>{let o=new Uint8Array(t.stateSlotCount),r=e[L];if(r===void 0||!t.reducer&&!m(t.reactionsByEventType,L))return o;let i=r*t.stateSlotCount;for(let a=0;a<t.stateSlotCount;a+=1)n[i+a]!==F&&(o[a]=1);return o},Hr=(t,e,n,o,r,i)=>{let a=!0,s=!1,c=!1,d=!1,y=e*t.stateSlotCount;for(let u of o){let p=n[y+Dn(u)];p!==u&&(a=!1,s=!0),p>=0&&p!==u&&t.effectsByStateCode[p]&&(c=!0),P(p)&&(d=!0)}return{eventCode:e,acceptStateCodes:o,allDefaultTransitionsIdentity:a,hasNonIdentityDefaultTransition:s,mayEnterEffectState:c,hasDespawnOnStates:i,hasReaction:r,mayEnterTerminalState:d,requiresReducerCall:t.reducer!==void 0}},Yr=(t,e,n,o,r)=>{let i=vt(t.despawnStateMask),a=[];for(let s=0;s<e;s+=1)a[s]=Hr(t,s,n,o[s],r[s]!==void 0,i);return a},qr=(t,e,n)=>{let o=new Uint8Array(n),r=new Int16Array(n*t.stateSlotCount);r.fill(F);let i=Object.create(null),a=Array.from({length:n},()=>[]),s=Array.from({length:n});for(let[c,d]of Object.entries(t.config)){if(!d)continue;let y=Lr(t,c);if(y!==void 0)for(let[u,p]of Object.entries(d)){let w=e[u];if(w===void 0)continue;let E=p??c,l=Nr(t,E),f=w*t.stateSlotCount+Dn(y);if(o[w]=1,a[w].push(y),l===void 0){r[f]=It,i[f]=E;continue}r[f]=l}}for(let[c,d]of Object.entries(t.reactionsByEventType)){let y=e[c];y!==void 0&&(s[y]=d)}return{...t,eventAcceptMask:o,transitionTable:r,transitionTargetByCell:i,acceptStateCodesByEventCode:a,despawnLifecycleStateMask:Gr(t,e,r),reactionsByEventCode:s,reducePlansByEventCode:Yr(t,n,r,a,s)}},On=t=>{let e=Object.create(null),n=[];for(let r of t)for(let i of r.eventTypes)m(e,i)||(e[i]=n.length,n.push(i));let o=Object.create(null);for(let r of t)o[r.templateKey]=qr(r,e,n.length);return{eventCodeByType:e,eventTypesByCode:n,metadataByKey:o}},z=(t,e)=>e===R?At:e<R?_r[e]:t.publicStates[e];var Tt=(t,e,n,o,r)=>{let i=Xt(t,n,o,r,{ownership:"owned"});i&&e.push(i)};var Yn=require("@lite-fsm/core");var _n={f32:()=>new Float32Array(0),i16:()=>new Int16Array(0),i32:()=>new Int32Array(0),u8:()=>new Uint8Array(0),string:()=>[]},$n=t=>_n[t.kind](),Ln=(t,e,n)=>{if(t.length>=n)return t;if(e.kind==="string"){let i=t.slice();i.length=n;for(let a=t.length;a<n;a+=1)i[a]="";return i}let o=_n[e.kind](),r=new o.constructor(n);return r.set(t),r},te=(t,e,n=0)=>{if(t.length>=e)return t;let o=new Int16Array(e);return o.fill(n),o.set(t),o},ee=(t,e,n=0)=>{if(t.length>=e)return t;let o=new Int32Array(e);return o.fill(n),o.set(t),o},ne=(t,e)=>{if(t.length>=e)return t;let n=new Uint8Array(e);return n.set(t),n},bt=(t,e)=>{if(t.length>=e)return t;let n=new Uint32Array(e);return n.set(t),n},ct=t=>t.default!==void 0?t.default:t.kind==="string"?"":0;var oe=t=>t.map(()=>[]),Nn=t=>({storage:"entity",version:t.version,count:t.count,capacity:t.capacity}),_=t=>{t.publicSlice=Nn(t)},kt=t=>{t.pendingPrevStateCodeSync.length=0,t.pendingPrevStateCodeSyncToken+=1,t.pendingPrevStateCodeSyncToken>=4294967295&&(t.pendingPrevStateCodeSyncMark.fill(0),t.pendingPrevStateCodeSyncToken=1)},re=(t,e)=>{for(let n=0;n<e.length;n+=1)Bt(t,e[n])},Bt=(t,e)=>{let n=t.pendingPrevStateCodeSyncMark,o=t.pendingPrevStateCodeSyncToken;n[e]!==o&&(n[e]=o,t.pendingPrevStateCodeSync.push(e))},ie=t=>{let e=t.pendingPrevStateCodeSync,n=t.pendingPrevStateCodeSyncMark,o=t.pendingPrevStateCodeSyncToken,r=t.presence;for(let i=0;i<r.length;i+=1)r[i]!==1||n[i]===o||(n[i]=o,e.push(i))},ae=t=>{let e=t.pendingPrevStateCodeSync;if(e.length===0)return;let n=t.presence,o=t.prevStateCode,r=t.stateCode;for(let i=0;i<e.length;i+=1){let a=e[i];n[a]===1&&(o[a]=r[a])}kt(t)},dt=t=>{t.acceptStateBucketsByEventCode=t.metadata.acceptStateCodesByEventCode.map(e=>e.flatMap(n=>n>=0?[t.stateBuckets[n]]:[]))},Pt=(t,e,n)=>{let o=t.entitiesByGroupTag[n]??[];o.length===0&&(t.entitiesByGroupTag[n]=o),t.groupTagPosition[e]=o.length,o.push(e)},Wr=(t,e)=>{let n=t.groupTagByIndex[e],o=t.entitiesByGroupTag[n],r=t.groupTagPosition[e];if(!o||r<0)return;let i=o.pop();i!==void 0&&i!==e&&(o[r]=i,t.groupTagPosition[i]=r),o.length===0&&delete t.entitiesByGroupTag[n],t.groupTagPosition[e]=-1},Vn=(t,e,n,o)=>{let r=t.actorRowsByEntity[n]??[];r.length===0&&(t.actorRowsByEntity[n]=r);let i=t.actorRowsByGroupTag[o]??[];i.length===0&&(t.actorRowsByGroupTag[o]=i);let a={store:e,entity:n,groupTag:o,entityRowsPosition:r.length,groupRowsPosition:i.length};r.push(a),i.push(a)},jn=(t,e,n,o)=>{if(!t||n<0||t[n]!==e)return!1;let r=t.pop();return r!==void 0&&r!==e&&(t[n]=r,o(r,n)),!0},zr=(t,e)=>{let n=t.actorRowsByEntity[e.entity];jn(n,e,e.entityRowsPosition,(o,r)=>{o.entityRowsPosition=r}),e.entityRowsPosition=-1},Fn=(t,e)=>{let n=t.actorRowsByGroupTag[e.groupTag];jn(n,e,e.groupRowsPosition,(o,r)=>{o.groupRowsPosition=r}),e.groupRowsPosition=-1,n&&n.length===0&&delete t.actorRowsByGroupTag[e.groupTag]},Jr=(t,e)=>{zr(t,e),Fn(t,e)},Kn=(t,e,n)=>{if(n<0)return;let o=t.stateBuckets[n],r=t.statePosition[e];if(!o||r<0)return;let i=o.pop();i!==void 0&&i!==e&&(o[r]=i,t.statePosition[i]=r),t.statePosition[e]=-1},Un=(t,e,n)=>{if(n<0)return;let o=t.stateBuckets[n];o&&(t.statePosition[e]=o.length,o.push(e))},se=(t,e,n,o)=>{n!==o&&(Kn(t,e,n),Un(t,e,o))},ce=(t,e,n,o)=>{if(e===n||e<0||n<0)return!1;let r=t.stateBuckets[e],i=t.stateBuckets[n];return r!==o||!i||i.length!==0?!1:(t.stateBuckets[e]=i,t.stateBuckets[n]=r,dt(t),!0)},de=(t,e,n,o,r="row")=>{let i=0;for(let a=0;a<n.length;a+=1){let s=n[a],c=s.entity;s.store!==e||e.presence[c]!==1||(Kn(e,c,o?.[a]??e.stateCode[c]),r==="fullEntity"?(s.entityRowsPosition=-1,Fn(t,s)):Jr(t,s),e.presence[c]=0,e.stateCode[c]=R,e.prevStateCode[c]=R,e.rowVersion[c]=0,i+=1)}return i===0?0:(e.count-=i,e.version+=1,_(e),i)},Mt=(t,e)=>{let n=t.entityStore,o=0;for(let r of e){if(n.alive[r]!==1)continue;let i=n.ids[r];Wr(n,r),delete n.indexById[i],n.ids[r]="",n.alive[r]=0,n.groupTagByIndex[r]="",n.freeList.push(r),t.actorRowsByEntity[r]=[],o+=1}return o===0?0:(n.count-=o,n.version+=1,o)},ye=(t,e)=>{let n=t.actorStores[e.key];if(!n)throw new Error(`[lite-fsm/entities] missing actor store for entity template '${e.key}'.`);return n.publicSlice=Nn(n),n.publicSlice},J=(t,e)=>{let n=e;for(let o of Object.values(t.actorStores))n[o.templateKey]!==o.publicSlice&&(n===e&&(n={...e}),n[o.templateKey]=o.publicSlice);return n},ue=t=>{let e=t.entityStore;e.indexById=Object.create(null),e.entitiesByGroupTag=Object.create(null),e.groupTagPosition=new Int32Array(e.capacity),e.groupTagPosition.fill(-1),e.count=0,t.actorRowsByEntity=Array.from({length:e.capacity},()=>[]),t.actorRowsByGroupTag=Object.create(null),t.routingScratchVersion=0;for(let n of Object.values(t.actorStores))n.count=0,n.stateBuckets=oe(n.metadata.publicStates),n.statePosition=new Int32Array(n.capacity),n.statePosition.fill(-1),n.acceptedScratch=[],n.routingScratchVersion=0,dt(n);for(let n=0;n<e.capacity;n+=1){if(e.alive[n]!==1)continue;let o=n;e.indexById[e.ids[n]]=o,Pt(e,o,e.groupTagByIndex[n]),e.count+=1}for(let n of Object.values(t.actorStores)){for(let o=0;o<n.capacity;o+=1){if(n.presence[o]!==1)continue;let r=o;Un(n,r,n.stateCode[o]),Vn(t,n,r,e.groupTagByIndex[o]),n.count+=1}_(n)}};var pe=new WeakMap,Gn=(t,e,n)=>new Yn.LiteFsmError("LITE_FSM_INVALID_STORAGE_CONFIG",`[lite-fsm/entities] machine '${t}' resource '${e}' ${n}.`),Hn=t=>t instanceof Promise,Qr=(t,e)=>ht(e,{indices:[],has(n){return e.presence[n]===1},entityId(n){let o=t.ids[n];if(o!==void 0)return o;throw g(`unknown entity index ${n}`)}}),yt=t=>{Gt(t.reducerSelf,t)},qn=(t,e)=>(t.reducerSelf.indices=e,t.reducerSelf),Xr=t=>{let e=Object.create(null),n=Object.create(null);for(let[o,r]of Object.entries(t.resourceSchema)){let i=r.factory();if(Hn(i))throw Gn(t.templateKey,o,"factory returned a Promise; resource factories are sync-only");if(e[o]=i,!r.exposed)continue;let a=r.expose,s=a(i);if(Hn(s))throw Gn(t.templateKey,o,"expose returned a Promise; resource expose functions are sync-only");n[o]=s}return{resources:e,resourceViews:n}},Zr=()=>({count:0,capacity:0,ids:[],indexById:Object.create(null),alive:new Uint8Array(0),generation:new Uint32Array(0),groupTagByIndex:[],entitiesByGroupTag:Object.create(null),groupTagPosition:new Int32Array(0),freeList:[],version:0}),ti=(t,e,n)=>{let o=Object.fromEntries(Object.entries(t.initialContext).map(([a,s])=>[a,$n(s)])),r=Xr(t),i={storeId:n,templateKey:t.templateKey,metadata:t,capacity:0,count:0,version:0,presence:new Uint8Array(0),stateCode:new Int16Array(0),prevStateCode:new Int16Array(0),rowVersion:new Uint32Array(0),stateBuckets:oe(t.publicStates),statePosition:new Int32Array(0),acceptedScratch:[],defaultTransitionSourceStateScratch:[],pendingPrevStateCodeSync:[],pendingPrevStateCodeSyncMark:new Uint32Array(0),pendingPrevStateCodeSyncToken:1,routingScratchVersion:0,acceptStateBucketsByEventCode:[],columns:o,resources:r.resources,resourceViews:r.resourceViews,reducerSelf:void 0,publicSlice:{storage:"entity",version:0,count:0,capacity:0}};return i.reducerSelf=Qr(e,i),i.acceptStateBucketsByEventCode=t.acceptStateCodesByEventCode.map(a=>a.flatMap(s=>s>=0?[i.stateBuckets[s]]:[])),_(i),i},Wn=(t,e)=>{let n=On(t.map(r=>r.data)),o={entityStore:Zr(),actorStores:Object.create(null),actorStoresById:[],eventCodeByType:n.eventCodeByType,eventTypesByCode:n.eventTypesByCode,templatesByEventCode:n.eventTypesByCode.map(()=>[]),actorRowsByEntity:[],actorRowsByGroupTag:Object.create(null),routingScratchVersion:0,access:void 0};for(let r=0;r<t.length;r+=1){let i=t[r],a=n.metadataByKey[i.key],s=ti(a,o.entityStore,r);o.actorStores[i.key]=s,o.actorStoresById[r]=s;for(let c=0;c<a.eventAcceptMask.length;c+=1)a.eventAcceptMask[c]===1&&o.templatesByEventCode[c].push(s)}return o.access=Ye(o),pe.set(e,o),pe.set(o.access,o),o},zn=t=>{let e=pe.get(t);if(!e)throw new Error("[lite-fsm/entities] entity runtime state is not initialized for this manager.");return e},D=t=>t,Jn=(t,e)=>{t.capacity>=e||(t.capacity=e,t.alive=ne(t.alive,e),t.generation=bt(t.generation,e),t.groupTagPosition=ee(t.groupTagPosition,e,-1))},Qn=(t,e)=>{if(!(t.capacity>=e)){t.capacity=e,t.presence=ne(t.presence,e),t.stateCode=te(t.stateCode,e,R),t.prevStateCode=te(t.prevStateCode,e,R),t.rowVersion=bt(t.rowVersion,e),t.statePosition=ee(t.statePosition,e,-1),t.pendingPrevStateCodeSyncMark=bt(t.pendingPrevStateCodeSyncMark,e);for(let[n,o]of Object.entries(t.metadata.initialContext))t.columns[n]=Ln(t.columns[n],o,e);yt(t),q(t)}};var le=(t,e,n)=>{if(!(n===R||t.metadata.publicStates[n]!==void 0||P(n)))throw g(`actor '${t.templateKey}' reducer wrote invalid stateCode ${n} for entity ${e}`)},ei=t=>{for(let e of t.metadata.effectsByStateCode)if(e)return!0;return!1},Xn=(t,e,n)=>{let o=t.metadata.reducer!==void 0;return{scheduleDespawnOn:(n.scheduleDespawnOn??!0)&&vt(t.metadata.despawnStateMask),scheduleEffects:(n.scheduleEffects??!0)&&(e?.mayEnterEffectState===!0||o&&ei(t)),collectReactionSurvivors:n.scheduleReactions===!0&&e?.hasReaction===!0&&(n.scheduleDespawnOn??!0)&&vt(t.metadata.despawnStateMask),scheduleTerminal:(n.scheduleTerminal??!0)&&(e?.mayEnterTerminalState===!0||o)}},ni=(t,e,n,o,r)=>{let i=t??new Map,a={entity:o,generation:e.generation[o],id:e.ids[o]},s=i.get(n);return s?(s.indices!==r&&s.indices.push(o),s.entries.push(a),i):(i.set(n,{indices:i.size===0?r:[o],entries:[a]}),i)},Zn=t=>{if(t.indices.length===t.entries.length)return t.indices;let e=new Array(t.entries.length);for(let n=0;n<t.entries.length;n+=1)e[n]=t.entries[n].entity;return e},oi=(t,e,n,o,r)=>{let i=e.stateCode,a=e.rowVersion,s,c=!1;for(let d=0;d<n.length;d+=1){let y=n[d],u=i[y];a[y]+=1,u!==r&&(le(e,y,u),s||(s=[]),s.push(y),o.scheduleTerminal&&P(u)&&(c=!0,t&&t.terminalRows.push({store:e,entity:y})))}return{dirtyRows:s,dirtyRowsPreviousStateCode:s?r:void 0,dirtyRowsPreviousStateCodes:void 0,bulkStateTransition:void 0,enteredByState:void 0,cleanupRemovesAcceptedRows:c,despawnOnRemovesAcceptedRows:!1,acceptedRowsHaveFinalRemoval:!1,reactionSurvivorRows:void 0}},ri=(t,e,n,o,r,i)=>{let a=e.stateCode,s=e.rowVersion,c=e.metadata.despawnStateMask,d,y=!1,u=!1,p=!1;for(let w=0;w<n.length;w+=1){let E=n[w],l=a[E];if(l===r){s[E]+=1;continue}if(l!==i&&le(e,E,l),s[E]+=1,l>=0&&c[l]===1&&(y=!0,u=!0,t&&rt(t,E),!to(e,l))){p=!0,t&&zt(t,e,E,r);continue}d||(d=[]),d.push(E),o.scheduleTerminal&&P(l)&&(y=!0,t&&t.terminalRows.push({store:e,entity:E}))}return{dirtyRows:d,dirtyRowsPreviousStateCode:d?r:void 0,dirtyRowsPreviousStateCodes:void 0,bulkStateTransition:void 0,enteredByState:void 0,cleanupRemovesAcceptedRows:y,despawnOnRemovesAcceptedRows:u,acceptedRowsHaveFinalRemoval:p,reactionSurvivorRows:void 0}},ii=(t,e)=>{for(let n of t.acceptStateCodes)if(n===e)return!0;return!1},ai=(t,e,n,o,r,i)=>{if(o?.hasNonIdentityDefaultTransition&&!(r===void 0||i===void 0)&&r!==i&&!(r<0||i<0)&&ii(o,r)&&t.stateBuckets[r]===e&&t.stateBuckets[i]?.length===0&&!(n.scheduleDespawnOn&&t.metadata.despawnStateMask[i]===1))return{indices:e,previousStateCode:r,stateCode:i}},si=(t,e)=>{let n=t.runtime.entityStore,o=new Array(e.length);for(let r=0;r<e.length;r+=1){let i=e[r];o[r]={entity:i,generation:n.generation[i],id:n.ids[i]}}return{indices:e,entries:o}},to=(t,e)=>{let n=e+1;return n>=0&&t.metadata.despawnLifecycleStateMask[n]===1},ci=(t,e,n,o,r)=>n!==void 0?n:o===void 0?r[t]:o[e],di=(t,e,n,o,r,i,a)=>{let s=ai(e,n,o,r,i,a);if(!s)return;let c=e.stateCode;for(let u=0;u<n.length;u+=1)if(c[n[u]]!==s.stateCode)return;let d=e.rowVersion;for(let u=0;u<n.length;u+=1){let p=n[u];d[p]+=1,Bt(e,p)}let y;return o.scheduleEffects&&t&&e.metadata.effectsByStateCode[s.stateCode]&&(y=new Map,y.set(s.stateCode,si(t,n))),{dirtyRows:void 0,dirtyRowsPreviousStateCode:void 0,dirtyRowsPreviousStateCodes:void 0,bulkStateTransition:s,enteredByState:y,cleanupRemovesAcceptedRows:!1,despawnOnRemovesAcceptedRows:!1,acceptedRowsHaveFinalRemoval:!1,reactionSurvivorRows:void 0}},eo=(t,e,n,o,r,i,a,s)=>{let c=di(t,e,n,o,r,i,a);if(c)return c;if(i!==void 0&&!o.scheduleDespawnOn&&!o.scheduleEffects)return oi(t,e,n,o,i);if(i!==void 0&&o.scheduleDespawnOn&&!o.scheduleEffects&&!o.collectReactionSurvivors&&(i<0||e.metadata.despawnStateMask[i]!==1))return ri(t,e,n,o,i,a);let d,y,u,p=!1,w=!1,E=!1,l,f=i!==void 0,U=e.stateCode,$=e.prevStateCode,tt=e.rowVersion,et=e.metadata.despawnStateMask,$t=e.metadata.effectsByStateCode;for(let C=0;C<n.length;C+=1){let b=n[C],k=U[b],Lt=ci(b,C,i,s,$),Ie=k!==Lt;(Ie||!f)&&!(i!==void 0&&(k===i||k===a))&&le(e,b,k),tt[b]+=1;let ve=!1;if(o.scheduleDespawnOn&&k>=0&&et[k]===1){if(p=!0,w=!0,ve=!0,o.collectReactionSurvivors&&!l){l=[];for(let Nt=0;Nt<C;Nt+=1)l.push(n[Nt])}if(t&&rt(t,b),!to(e,k)){E=!0,t&&zt(t,e,b,Lt);continue}}else l?.push(b);if(Ie){if(d||(d=[],i===void 0&&(y=[])),d.push(b),y?.push(Lt),o.scheduleTerminal&&P(k)){p=!0,t&&t.terminalRows.push({store:e,entity:b});continue}o.scheduleEffects&&t&&!ve&&k>=0&&$t[k]&&(u=ni(u,t.runtime.entityStore,k,b,d))}}return{dirtyRows:d,dirtyRowsPreviousStateCode:d?i:void 0,dirtyRowsPreviousStateCodes:y,bulkStateTransition:void 0,enteredByState:u,cleanupRemovesAcceptedRows:p,despawnOnRemovesAcceptedRows:w,acceptedRowsHaveFinalRemoval:E,reactionSurvivorRows:l}};var no=(t,e,n,o)=>{if(n===void 0)return{accepted:!1,nextState:void 0,sourceStateCode:F};let r=t.stateCode[e],i=r+1;if(i<0||i>=t.metadata.stateSlotCount)throw g(`actor '${t.templateKey}' has invalid stateCode ${r} for entity ${e}`);let a=n*t.metadata.stateSlotCount+i,s=t.metadata.transitionTable[a];if(s===F)return{accepted:!1,nextState:void 0,sourceStateCode:r};if(s===It)throw g(`actor '${t.templateKey}' transition '${o}' targets unknown state '${t.metadata.transitionTargetByCell[a]}'`);return t.prevStateCode[e]=r,t.stateCode[e]=s,{accepted:!0,nextState:z(t.metadata,s),sourceStateCode:r}},oo=t=>{if(t.accepted)return t.indices;let e=t.store.acceptedScratch;e.length=0;for(let n=0;n<t.indices.length;n+=1){let o=t.indices[n];no(t.store,o,t.eventCode,t.action.type).accepted&&e.push(o)}return e},yi=(t,e)=>{if(!t.accepted||t.eventCode===void 0)return;let n=t.store.metadata.reducePlansByEventCode[t.eventCode];if(n){for(let o of n.acceptStateCodes)if(o>=0&&t.store.stateBuckets[o]===e)return o}},ui=(t,e)=>{let n=yi(t,e);if(n===void 0)return;let o=t.store,i=t.eventCode*o.metadata.stateSlotCount+n+1,a=o.metadata.transitionTable[i];if(a===F)return;if(a===It)throw g(`actor '${o.templateKey}' transition '${t.action.type}' targets unknown state '${o.metadata.transitionTargetByCell[i]}'`);if(a===n)return ae(o),{firstNextState:z(o.metadata,n),previousStateCodeForAccepted:n,knownValidStateCodeForAccepted:n};let s=o.prevStateCode,c=o.stateCode;for(let d=0;d<e.length;d+=1){let y=e[d];if(c[y]!==n)throw g(`actor '${o.templateKey}' has invalid stateCode ${c[y]} for entity ${y}`);s[y]=n,c[y]=a}return{firstNextState:z(o.metadata,a),previousStateCodeForAccepted:n,knownValidStateCodeForAccepted:a}},ro=(t,e)=>{let n=ui(t,e);if(n!==void 0)return n;let o;if(!t.accepted){let i=t.store.stateCode,a=t.store.prevStateCode,s=t.store.defaultTransitionSourceStateScratch;s.length=e.length;for(let c=0;c<e.length;c+=1){let d=e[c];s[c]=a[d],o??(o=z(t.store.metadata,i[d]))}return{firstNextState:o,previousStateCodeForAccepted:void 0,sourceStateCodesByAccepted:s}}let r=t.store.defaultTransitionSourceStateScratch;r.length=e.length;for(let i=0;i<e.length;i+=1){let a=e[i],s=no(t.store,a,t.eventCode,t.action.type);r[i]=s.sourceStateCode,o??(o=s.nextState)}return{firstNextState:o,previousStateCodeForAccepted:void 0,sourceStateCodesByAccepted:r}};var pi=t=>{t.version+=1,_(t)},io=(t,e,n,o)=>{let r=t.prevStateCode,i=t.stateCode;for(let a=e.length-1;a>=0;a-=1){let s=e[a],c=n;c===void 0&&o!==void 0&&(c=o[a]),c===void 0&&(c=r[s]),se(t,s,c,i[s])}},li=(t,e,n)=>{if(!(!t||!n))for(let[o,r]of n)Tn(t,e,o,Zn(r),r.entries)},ao=(t,e,n)=>{let o=t.acceptStateBucketsByEventCode[e];return o!==void 0&&o.length===1&&o[0]===n},fi=(t,e,n)=>!n.allowBorrowedReactionBatch||t?.allDefaultTransitionsIdentity!==!0||e.dirtyRows&&e.dirtyRows.length>0||e.cleanupRemovesAcceptedRows?"owned":"borrowed",Si=(t,e)=>e.despawnOnRemovesAcceptedRows?e.reactionSurvivorRows??[]:t,Ei=(t,e)=>e?n=>{let o=n-e.firstEntity;if(o>=0&&o<e.indices.length&&e.indices[o]===n)return e.payloads[o];let r=e.positionsByEntity?.[n];if(r!==void 0&&e.indices[r]===n)return e.payloads[r];throw g(`payloadFor(entity) for actor '${t.templateKey}' only accepts EntityIndex values from current spawn scope`)}:()=>{throw g(`payloadFor(entity) is only available while reducing ${O}`)},mi=t=>{if(t.eventCode!==void 0)return t.store.metadata.reducePlansByEventCode[t.eventCode]},Q=(t,e,n,o={})=>{let r=o.traceBatchPrefix??"entities.reduce.publicBatch",i=o.tracePublicBatch||o.traceBatchPrefix?o.trace:void 0,a=i?.now();try{let s=[],c,d,y,u,p=i?.now();try{if(s=oo(e),s.length===0)return!1;let C=ro(e,s);c=C.firstNextState,d=C.previousStateCodeForAccepted,y=C.sourceStateCodesByAccepted,u=C.knownValidStateCodeForAccepted}finally{h(i,`${r}.defaultTransitions`,p)}let w=e.store.metadata.reducer,E=i?.now();try{if(w){let C=c;if(w({state:C,context:{}},e.action,{nextState:C,config:e.store.metadata.config,self:qn(e.store,s),entities:()=>t.access,payloadFor:Ei(e.store,e.payloadScope)})instanceof Promise)throw g(`reducer for actor '${e.store.templateKey}' and event '${e.action.type}' returned a Promise; entity reducers are sync-only`)}}finally{h(i,`${r}.userReducer`,E)}let l=mi(e),f,U=i?.now();try{f=eo(n,e.store,s,Xn(e.store,l,o),l,d,u,y)}finally{h(i,`${r}.postProcess`,U)}let $=i?.now();try{pi(e.store)}finally{h(i,`${r}.markTouched`,$)}let tt=i?.now();try{li(n,e.store,f.enteredByState)}finally{h(i,`${r}.scheduleEffects`,tt)}let et=i?.now();try{if(o.scheduleReactions&&e.eventCode!==void 0){let C=Si(s,f);C.length>0&&bn(n,e.store,e.eventCode,C,{ownership:fi(l,f,o)})}}finally{h(i,`${r}.scheduleReactions`,et)}let $t=i?.now();try{f.bulkStateTransition&&(ce(e.store,f.bulkStateTransition.previousStateCode,f.bulkStateTransition.stateCode,f.bulkStateTransition.indices)||io(e.store,f.bulkStateTransition.indices,f.bulkStateTransition.previousStateCode)),f.dirtyRows&&(io(e.store,f.dirtyRows,f.dirtyRowsPreviousStateCode,f.dirtyRowsPreviousStateCodes),re(e.store,f.dirtyRows))}finally{h(i,`${r}.updateStateBuckets`,$t)}return o.onAccepted?.(s),!0}finally{h(i,`${r}.total`,a)}};var so=new WeakMap,wi=()=>({markers:new Uint32Array(0),generation:new Uint32Array(0),compactIndices:[],lifetime:{token:0},token:0}),gi=t=>{let e=so.get(t);if(e)return e;let n=wi();return so.set(t,n),n},hi=(t,e)=>{if(t.markers.length>=e)return;let n=new Uint32Array(e);n.set(t.markers),t.markers=n;let o=new Uint32Array(e);o.set(t.generation),t.generation=o},Ri=t=>(t.token+=1,t.token>=4294967295&&(t.markers.fill(0),t.generation.fill(0),t.token=1),t.token),Ci=(t,e,n)=>{if(e.presence[n]!==1||t.entityStore.alive[n]!==1)return!1;let o=t.entityStore.ids[n];return o!==void 0&&o.length>0},fe=t=>{t.lifetime.token=0,t.compactIndices.length=0},xi=(t,e,n,o)=>{let r=gi(t);fe(r),hi(r,Math.max(t.entityStore.generation.length,e.presence.length));let i=Ri(r),a;if(o==="borrowed")for(let c=0;c<n.length;c+=1){let d=n[c];r.markers[d]=i,r.generation[d]=t.entityStore.generation[d]}else for(let c=0;c<n.length;c+=1){let d=n[c];if(!Ci(t,e,d)){if(!a){a=r.compactIndices,a.length=0;for(let y=0;y<c;y+=1)a.push(n[y])}continue}r.markers[d]=i,r.generation[d]=t.entityStore.generation[d],a?.push(d)}let s=a??n;if(s.length===0){fe(r);return}return r.lifetime.token=i,{scratch:r,scope:{indices:s,markers:r.markers,generation:r.generation,lifetime:r.lifetime,token:i}}},Ai=(t,e,n,o)=>{let r=Je(t),i=Object.create(o.manager.getDependencies());return i.action=o.action,i.self=ze(t,e,n),i.entities=()=>r,i.transition=void 0,i.condition=void 0,i},Ii=(t,e)=>g(`reaction for actor '${t.templateKey}' and event '${e}' returned a Promise; entity reactions are sync-only`),co=(t,e,n,o,r="entities.reactions")=>{let i=e.store.metadata.reactionsByEventCode[e.eventCode];if(!i)return;let a=o?.now(),s=xi(t,e.store,e.indices,e.ownership);if(h(o,`${r}.captureScope`,a),!s)return;let c=o?.now(),d=Ai(t,e.store,s.scope,n);h(o,`${r}.createDeps`,c);let y=o?.now();try{i(d)instanceof Promise&&n.dispatch.reportError(Ii(e.store,n.action.type))}catch(u){n.dispatch.reportError(u)}finally{h(o,`${r}.user`,y),fe(s.scratch)}},Dt=(t,e,n,o,r)=>{for(let i of e)co(t,i,n,o,r)},yo=(t,e)=>{let n=j(e.dispatch);if(!n||n.reactionBatches.length===0)return;let o=V(e.dispatch);for(let r of n.reactionBatches)co(t,r,e,o)};var uo={type:L},T=(t,e,n,o)=>{G(t,`entities.cleanup.${e}.${n}`,o)},vi=t=>{if(!t)return 0;let e=0;for(let n of t.lifecycleTouchedStoreIds)e+=t.lifecycleBatchesByStoreId[n]?.indices.length??0;return e},Ti=(t,e)=>{let n=t.stateCode[e]+1;return n>=0&&t.metadata.despawnLifecycleStateMask[n]===1},po=(t,e,n)=>{let o=t?Cn(t,n.store.storeId,n.entity):void 0;In(e,n.store,n,o)},bi=(t,e,n,o)=>{let r=t.eventCodeByType[L];for(let i of n){if(t.entityStore.alive[i]!==1)continue;o.entities.push(i);let a=t.actorRowsByEntity[i];if(a)for(let s of a){let{store:c}=s;c.presence[i]===1&&(po(e,o,s),r!==void 0&&Ti(c,i)&&vn(o,c,i))}}},ki=(t,e,n)=>{let o=t.actorRowsByEntity[n];if(o){for(let r of o)if(r.store===e)return r}},lo=(t,e,n="row")=>{let o=0;for(let r of e.removalTouchedStoreIds){let i=e.removalBatchesByStoreId[r];if(!i)continue;let a=de(t,i.store,i.rows,i.bucketStateCodesActive?i.bucketStateCodes:void 0,n);o+=a}return o},Bi=(t,e)=>{let n=0;for(let o=0;o<e.length;o+=1){let r=e[o],i=t.actorRowsByEntity[r];i&&i.length>0||(e[n]=r,n+=1)}return e.length=n,Mt(t,e)},Pi=(t,e,n,o)=>{if(e.terminalRows.length===0)return T(n,o,"terminalRows",0),!1;let r=Jt(e);try{let i=n?.now();try{let y=e.terminalRows;e.terminalRows=[],T(n,o,"terminalRows",y.length);for(let u of y){if(!P(u.store.stateCode[u.entity]))continue;let p=ki(t,u.store,u.entity);p&&(po(void 0,r,p),r.entities.push(u.entity))}}finally{h(n,`entities.cleanup.${o}.collectPlan`,i)}let a=!1,s=0,c=n?.now();try{s=lo(t,r)}finally{T(n,o,"removedActorRows",s),h(n,`entities.cleanup.${o}.removeActorRows`,c)}a=s>0;let d=n?.now();try{let y=Bi(t,r.entities);T(n,o,"removedEntityRecords",y),a=y>0||a}finally{h(n,`entities.cleanup.${o}.removeEntityRecords`,d)}return a}finally{Qt(e,r)}},Se=(t,e,n,o,r)=>{if(!e)return!1;let i=!1,a=An(e);T(r,o,"scheduledDespawns",a.length);let s;try{let d=r?.now();try{a.length>0&&(s=Jt(e),bi(t,e,a,s))}finally{h(r,`entities.cleanup.${o}.collectPlan`,d)}if(T(r,o,"despawnedEntities",s?.entities.length??0),T(r,o,"touchedTemplates",s?.removalTouchedStoreIds.length??0),T(r,o,"lifecycleBatches",s?.lifecycleTouchedStoreIds.length??0),T(r,o,"lifecycleRows",vi(s)),T(r,o,"removalBatches",s?.removalTouchedStoreIds.length??0),s){let y=t.eventCodeByType[L],u=[],p=r?.now();try{for(let U of s.lifecycleTouchedStoreIds){let $=s.lifecycleBatchesByStoreId[U];if(!$)continue;let tt=Q(t,{store:$.store,indices:$.indices,action:uo,eventCode:y,accepted:!0},e,{scheduleDespawnOn:!1,scheduleEffects:!1,scheduleReactions:!1,scheduleTerminal:!1,onAccepted(et){Tt(e,u,$.store,y,et)}});i=i||tt}Dt(t,u,{action:uo,manager:n.manager,dispatch:n.dispatch})}finally{h(r,`entities.cleanup.${o}.lifecycle`,p)}let w=0,E=r?.now();try{w=lo(t,s,"fullEntity")}finally{T(r,o,"removedActorRows",w),h(r,`entities.cleanup.${o}.removeActorRows`,E)}let l=0,f=r?.now();try{l=Mt(t,s.entities)}finally{T(r,o,"removedEntityRecords",l),h(r,`entities.cleanup.${o}.removeEntityRecords`,f)}w>0&&(i=!0),l>0&&(i=!0)}}finally{xn(e),s&&Qt(e,s)}let c=Pi(t,e,r,o);return i=i||c,i};var Mi=t=>t,Di=t=>Object.entries(t.metadata.initialContext).map(([e,n])=>({name:e,value:ct(n)})),Oi=(t,e)=>{let n=t.get(e.templateKey);if(n)return n;let o={store:e,defaultEntries:Di(e),requiredCapacity:e.capacity,addedRows:0};return t.set(e.templateKey,o),o},_i=(t,e)=>{let n=t.get(e.templateKey);if(n)return n;let o={store:e,indices:[],payloads:[]};return t.set(e.templateKey,o),o},$i=(t,e)=>{let n=t[0],o=!0;for(let i=1;i<t.length;i+=1)if(t[i]!==n+i){o=!1;break}if(o)return{indices:t,payloads:e,firstEntity:n};let r=Object.create(null);for(let i=0;i<t.length;i+=1)r[t[i]]=i;return{indices:t,payloads:e,firstEntity:n,positionsByEntity:r}},Li=t=>t.map(e=>({store:e.store,indices:e.indices,payloadScope:$i(e.indices,e.payloads)})),Ni=(t,e)=>{let n=t.entityStore,o=n.freeList.length,r=Math.min(o,e.length),i=new Array(e.length),a=new Map,s=new Map,c=n.capacity;for(let d=0;d<e.length;d+=1){let y=d<o?n.freeList[o-1-d]:Mi(n.ids.length+(d-o));i[d]=y,c=Math.max(c,y+1);let u=e[d];for(let p of u.actors){let w=t.actorStores[p.templateKey],E=Oi(a,w);E.requiredCapacity=Math.max(E.requiredCapacity,y+1),E.addedRows+=1;let l=_i(s,w);l.indices.push(y),l.payloads.push(p.payload)}}return{assignedEntities:i,batches:[...s.values()],actorPlans:a,requiredEntityCapacity:c,usedFreeListCount:r}},Vi=(t,e)=>{e.requiredEntityCapacity>t.entityStore.capacity&&Jn(t.entityStore,e.requiredEntityCapacity);for(let n of e.actorPlans.values())n.requiredCapacity>n.store.capacity&&Qn(n.store,n.requiredCapacity)},ji=(t,e,n)=>{for(let o=0;o<n.length;o+=1){let r=n[o];t.columns[r.name][e]=r.value}},Fi=(t,e,n,o)=>{let r=t.actorRowsByEntity[n]??[];r.length===0&&(t.actorRowsByEntity[n]=r);let i=t.actorRowsByGroupTag[o]??[];i.length===0&&(t.actorRowsByGroupTag[o]=i);let a={store:e,entity:n,groupTag:o,entityRowsPosition:r.length,groupRowsPosition:i.length};r.push(a),i.push(a)},Ki=(t,e,n)=>{let o=t.entityStore;n.usedFreeListCount>0&&(o.freeList.length-=n.usedFreeListCount);for(let r=0;r<e.length;r+=1){let i=e[r],a=n.assignedEntities[r];o.ids[a]=i.id,o.indexById[i.id]=a,o.alive[a]=1,o.generation[a]+=1,o.groupTagByIndex[a]=i.groupTag,Pt(o,a,i.groupTag)}e.length!==0&&(o.count+=e.length,o.version+=1)},Ui=(t,e,n)=>{for(let o=0;o<e.length;o+=1){let r=e[o],i=n.assignedEntities[o];for(let a of r.actors){let s=n.actorPlans.get(a.templateKey),c=s.store;c.presence[i]=1,c.stateCode[i]=R,c.prevStateCode[i]=R,c.rowVersion[i]=0,ji(c,i,s.defaultEntries),Fi(t,c,i,r.groupTag)}}for(let o of n.actorPlans.values())o.store.count+=o.addedRows,o.store.version+=1,_(o.store)},fo=(t,e)=>{let n=Ni(t,e);return Vi(t,n),Ki(t,e,n),Ui(t,e,n),Li(n.batches)};var So={type:O},Eo=(t,e,n,o,r)=>{if(e.length===0)return!1;let i=x(r,"entities.reduce.spawnLifecycle.applyStagedSpawns",()=>fo(t,e)),a=[];return x(r,"entities.reduce.spawnLifecycle.reduceBatches",()=>{for(let s of i)Q(t,{store:s.store,indices:s.indices,action:So,eventCode:t.eventCodeByType[O],payloadScope:s.payloadScope},n,{scheduleReactions:!1,trace:r,traceBatchPrefix:"entities.reduce.spawnLifecycle.batch",onAccepted(c){Tt(n,a,s.store,t.eventCodeByType[O],c)}})}),x(r,"entities.reduce.spawnLifecycle.reactions",()=>{Dt(t,a,{action:So,manager:o.manager,dispatch:o.dispatch},r,"entities.reduce.spawnLifecycle.reactions")}),!0};var Gi=t=>Object.assign(Object.create(null),t),Hi=t=>Object.assign(Object.create(null),Object.fromEntries(Object.entries(t).map(([e,n])=>[e,n.slice()]))),Yi=t=>t.map(e=>e.slice()),mo=(t,e)=>{let n=e.get(t);if(n)return n;let o={...t};return e.set(t,o),o},qi=(t,e)=>t.map(n=>n.map(o=>mo(o,e))),Wi=(t,e)=>Object.assign(Object.create(null),Object.fromEntries(Object.entries(t).map(([n,o])=>[n,o.map(r=>mo(r,e))]))),zi=t=>(Array.isArray(t),t.slice()),Ji=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,zi(n)])),Qi=t=>({count:t.count,capacity:t.capacity,ids:t.ids.slice(),indexById:Gi(t.indexById),alive:t.alive.slice(),generation:t.generation.slice(),groupTagByIndex:t.groupTagByIndex.slice(),entitiesByGroupTag:Hi(t.entitiesByGroupTag),groupTagPosition:t.groupTagPosition.slice(),freeList:t.freeList.slice(),version:t.version}),Xi=t=>({capacity:t.capacity,count:t.count,version:t.version,presence:t.presence.slice(),stateCode:t.stateCode.slice(),prevStateCode:t.prevStateCode.slice(),rowVersion:t.rowVersion.slice(),stateBuckets:Yi(t.stateBuckets),statePosition:t.statePosition.slice(),acceptedScratch:t.acceptedScratch.slice(),pendingPrevStateCodeSync:t.pendingPrevStateCodeSync.slice(),pendingPrevStateCodeSyncMark:t.pendingPrevStateCodeSyncMark.slice(),pendingPrevStateCodeSyncToken:t.pendingPrevStateCodeSyncToken,columns:Ji(t.columns),publicSlice:t.publicSlice}),wo=t=>{let e=new Map;return{entityStore:Qi(t.entityStore),actorStores:Object.fromEntries(Object.entries(t.actorStores).map(([n,o])=>[n,Xi(o)])),actorRowsByEntity:qi(t.actorRowsByEntity,e),actorRowsByGroupTag:Wi(t.actorRowsByGroupTag,e)}},Zi=(t,e)=>{t.count=e.count,t.capacity=e.capacity,t.ids=e.ids,t.indexById=e.indexById,t.alive=e.alive,t.generation=e.generation,t.groupTagByIndex=e.groupTagByIndex,t.entitiesByGroupTag=e.entitiesByGroupTag,t.groupTagPosition=e.groupTagPosition,t.freeList=e.freeList,t.version=e.version},ta=(t,e)=>{t.capacity=e.capacity,t.count=e.count,t.version=e.version,t.presence=e.presence,t.stateCode=e.stateCode,t.prevStateCode=e.prevStateCode,t.rowVersion=e.rowVersion,t.stateBuckets=e.stateBuckets,t.statePosition=e.statePosition,t.acceptedScratch=e.acceptedScratch,t.pendingPrevStateCodeSync=e.pendingPrevStateCodeSync,t.pendingPrevStateCodeSyncMark=e.pendingPrevStateCodeSyncMark,t.pendingPrevStateCodeSyncToken=e.pendingPrevStateCodeSyncToken,dt(t),t.columns=e.columns,yt(t),q(t),t.publicSlice=e.publicSlice},go=(t,e)=>{Zi(t.entityStore,e.entityStore);for(let[n,o]of Object.entries(e.actorStores))ta(t.actorStores[n],o);t.actorRowsByEntity=e.actorRowsByEntity,t.actorRowsByGroupTag=e.actorRowsByGroupTag};var ea=(t,e,n)=>{let o=n+1;return o<0||o>=t.stateSlotCount?-1:e*t.stateSlotCount+o},na=(t,e,n)=>{let o=t.stateCode[e],r=ea(t.metadata,n,o);if(r<0)throw g(`actor '${t.templateKey}' has invalid stateCode ${o} for entity ${e}`);return t.metadata.transitionTable[r]!==F},oa=(t,e,n,o)=>t.entityStore.alive[o]!==1||e.presence[o]!==1?!1:na(e,o,n),ra=(t,e)=>{let n=t.acceptStateBucketsByEventCode[e];if(!n||n.length===0)return;if(n.length===1)return n[0].length===0?void 0:n[0];let o,r=t.acceptedScratch;r.length=0;for(let i of n)if(i.length!==0){if(!o){o=i;continue}if(r.length===0)for(let a=0;a<o.length;a+=1)r.push(o[a]);for(let a=0;a<i.length;a+=1)r.push(i[a])}return r.length>0?r:o},ho=t=>(t.routingScratchVersion+=1,t.routingScratchVersion),Ro=(t,e,n,o,r)=>{let{store:i,entity:a}=o;oa(t,i,e,a)&&(i.routingScratchVersion!==n&&(i.routingScratchVersion=n,i.acceptedScratch.length=0),i.acceptedScratch.length===0&&r.push({store:i,indices:i.acceptedScratch,accepted:!0}),i.acceptedScratch.push(a))},ia=(t,e,n)=>{let o=[],r=ho(t);for(let i of n){let a=t.entityStore.indexById[i];if(a===void 0)continue;let s=t.actorRowsByEntity[a];if(s)for(let c=0;c<s.length;c+=1)Ro(t,e,r,s[c],o)}return o},aa=(t,e,n)=>{let o=[],r=ho(t);for(let i of n){let a=t.actorRowsByGroupTag[i];if(a)for(let s=0;s<a.length;s+=1)Ro(t,e,r,a[s],o)}return o},Co=(t,e,n)=>{if(n.scope==="plugin"&&n.key==="entityId")return ia(t,e,n.targetSet);if(n.scope==="tag")return aa(t,e,n.targetSet);if(n.scope!=="unscoped")return[];let o=t.templatesByEventCode[e];if(!o||o.length===0)return[];let r=[];for(let i of o){let a=ra(i,e);!a||a.length===0||r.push({store:i,indices:a,accepted:!0})}return r};var xo=(t,e)=>{let n=V(e.dispatch),o=Rn(e.dispatch),r=j(e.dispatch),i=o.length>0?wo(t):void 0,a=t.eventCodeByType[e.action.type];return x(n,"entities.reduce.total",()=>{try{let s=x(n,"entities.reduce.spawnLifecycle",()=>Eo(t,o,r,e,n)),c=x(n,"entities.reduce.spawnCleanup",()=>Se(t,r,e,"spawn",n)),d=s||c;if(a===void 0)return d?void 0:{type:"skip"};let y=x(n,"entities.reduce.collectPublicBatches",()=>Co(t,a,e.dispatch.route));for(let p of y)Q(t,{store:p.store,indices:p.indices,action:e.action,eventCode:a,accepted:p.accepted},r,{allowBorrowedReactionBatch:e.dispatch.route.scope==="unscoped"&&ao(p.store,a,p.indices),scheduleReactions:!0,trace:n,tracePublicBatch:!0})&&(d=!0);let u=x(n,"entities.reduce.publicCleanup",()=>Se(t,r,e,"public",n));return d=d||u,d?void 0:{type:"skip"}}catch(s){throw i&&go(t,i),s}})};var _o=require("@lite-fsm/core");var vo=require("@lite-fsm/core");var sa=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),S=t=>new vo.LiteFsmError("LITE_FSM_INVALID_HYDRATION_ENVELOPE",`[lite-fsm/entities] hydrate: invalid snapshot.storage.entity: ${t}.`),H=(t,e)=>{if(sa(e))return e;throw S(`${t} must be an object`)},X=(t,e)=>{if(Array.isArray(e))return e;throw S(`${t} must be an array`)},ut=(t,e,n)=>{if(e.length!==n)throw S(`${t} length ${e.length} does not match capacity ${n}`)},me=(t,e)=>{if(typeof e=="number"&&Number.isInteger(e))return e;throw S(`${t} must be an integer`)},K=(t,e)=>{let n=me(t,e);if(n>=0)return n;throw S(`${t} must be a non-negative integer`)},pt=(t,e)=>{if(e<=4294967295)return e;throw S(`${t} must fit Uint32`)},To=(t,e,n)=>{let o=X(t,e);ut(t,o,n);let r=new Uint32Array(n);for(let i=0;i<n;i+=1)r[i]=pt(`${t}[${i}]`,K(`${t}[${i}]`,o[i]));return r},bo=(t,e,n)=>{let o=X(t,e);ut(t,o,n);let r=new Uint8Array(n);for(let i=0;i<n;i+=1){let a=me(`${t}[${i}]`,o[i]);if(a!==0&&a!==1)throw S(`${t}[${i}] must be 0 or 1`);r[i]=a}return r},Ao=(t,e,n)=>{let o=X(t,e);ut(t,o,n);let r=new Int16Array(n);for(let i=0;i<n;i+=1){let a=me(`${t}[${i}]`,o[i]);if(a<-32768||a>32767)throw S(`${t}[${i}] must fit Int16`);r[i]=a}return r},Ee=(t,e,n)=>{let o=X(t,e);return ut(t,o,n),o.map((r,i)=>{if(typeof r=="string")return r;throw S(`${t}[${i}] must be a string`)})},ca=(t,e)=>{let n=X("entityStore.freeList",t),o=new Set,r=[];for(let i=0;i<n.length;i+=1){let a=K(`entityStore.freeList[${i}]`,n[i]);if(a>=e.length)throw S(`entityStore.freeList[${i}] is out of range`);if(e[a]===1)throw S(`entityStore.freeList[${i}] points to a live entity`);if(o.has(a))throw S(`entityStore.freeList contains duplicate entity index ${a}`);o.add(a),r.push(a)}for(let i=0;i<e.length;i+=1)if(e[i]===0&&!o.has(i))throw S(`entityStore.freeList is missing dead entity index ${i}`);return r},da=t=>{let e=[];for(let n=0;n<t.length;n+=1)t[n]===0&&e.push(n);return e},ya=(t,e,n,o)=>{let r=new Set,i=0;for(let a=0;a<n.length;a+=1){if(n[a]!==1)continue;let s=e[a],c=o[a];if(s.length===0)throw S(`entityStore.ids[${a}] must be non-empty for a live entity`);if(c.length===0)throw S(`entityStore.groupTagByIndex[${a}] must be non-empty for a live entity`);if(r.has(s))throw S(`entityStore.ids contains duplicate live id '${s}'`);r.add(s),i+=1}if(t!==i)throw S(`entityStore.count ${t} does not match live entity count ${i}`)},ua=(t,e)=>pt("entityStore.version",Math.max(t,e)+1),pa=(t,e)=>{let n=H("entityStore",t.entityStore),o=K("entityStore.capacity",n.capacity),r=K("entityStore.count",n.count);if(r>o)throw S("entityStore.count cannot exceed capacity");let i=Ee("entityStore.ids",n.ids,o),a=bo("entityStore.alive",n.alive,o),s=Ee("entityStore.groupTagByIndex",n.groupTagByIndex,o),c=m(n,"generation")&&n.generation!==void 0,d=c?To("entityStore.generation",n.generation,o):new Uint32Array(o),y=c?ca(n.freeList,a):da(a),u=ua(e.version,pt("entityStore.version",K("entityStore.version",n.version)));return ya(r,i,a,s),{count:r,capacity:o,ids:i,alive:a,generation:d,groupTagByIndex:s,freeList:y,version:u}},la=t=>t.kind,Ot=t=>Object.fromEntries(Object.entries(t.metadata.initialContext).map(([e,n])=>[e,la(n)])),we=(t,e,n)=>{let o=[...e].sort(),r=[...n].sort();if(o.length!==r.length)throw S(`${t} keys do not match current entity schema`);for(let i=0;i<o.length;i+=1)if(o[i]!==r[i])throw S(`${t} keys do not match current entity schema`)},fa=(t,e)=>{let n=H(`actors.${t.templateKey}.schema`,e.schema),o=Ee(`actors.${t.templateKey}.schema.states`,n.states,t.metadata.publicStates.length);for(let a=0;a<o.length;a+=1)if(o[a]!==t.metadata.publicStates[a])throw S(`actors.${t.templateKey}.schema.states do not match current entity schema`);let r=H(`actors.${t.templateKey}.schema.columns`,n.columns),i=Ot(t);we(`actors.${t.templateKey}.schema.columns`,Object.keys(r),Object.keys(i));for(let[a,s]of Object.entries(i))if(r[a]!==s)throw S(`actors.${t.templateKey}.schema.columns.${a} does not match current entity schema`)},Sa=(t,e)=>e===R||e===it||e===at||e===st||e>=0&&e<t.metadata.publicStates.length,Io=(t,e,n)=>{for(let o=0;o<n.length;o+=1)if(!Sa(t,n[o]))throw S(`actors.${t.templateKey}.${e}[${o}] has unknown stateCode ${n[o]}`)},Ea=(t,e,n)=>{for(let o=0;o<e.length;o+=1)if(!(e[o]!==1||!P(n[o])))throw S(`actors.${t.templateKey}.stateCode[${o}] cannot be a terminal stateCode for a present row`)},ma=(t,e,n)=>{if(typeof n!="number"||!Number.isFinite(n))throw S(`${t} must be a finite number`);if(e==="f32")return n;if(!Number.isInteger(n))throw S(`${t} must be an integer`);if(e==="i16"&&(n<-32768||n>32767))throw S(`${t} must fit Int16`);if(e==="i32"&&(n<-2147483648||n>2147483647))throw S(`${t} must fit Int32`);if(e==="u8"&&(n<0||n>255))throw S(`${t} must fit Uint8`);return n},wa=(t,e)=>t==="f32"?Float32Array.from(e):t==="i16"?Int16Array.from(e):t==="i32"?Int32Array.from(e):Uint8Array.from(e),ga=(t,e,n,o)=>{let r=X(t,n);return ut(t,r,o),e==="string"?r.map((i,a)=>{if(typeof i=="string")return i;throw S(`${t}[${a}] must be a string`)}):wa(e,r.map((i,a)=>ma(`${t}[${a}]`,e,i)))},ha=(t,e,n)=>{let o=0;for(let r=0;r<n.length;r+=1)if(n[r]===1){if(e.alive[r]!==1)throw S(`actors.${t.templateKey}.presence[${r}] points to a missing entity`);o+=1}return o},Ra=(t,e,n)=>{let o=Math.max(t,e);if(n)for(let r=0;r<n.length;r+=1)n[r]>o&&(o=n[r]);return pt("actor.version",o+1)},Ca=(t,e,n)=>{let o=H(`actors.${t.templateKey}`,e);fa(t,o);let r=K(`actors.${t.templateKey}.capacity`,o.capacity);if(r>n.capacity)throw S(`actors.${t.templateKey}.capacity cannot exceed entityStore.capacity`);let i=K(`actors.${t.templateKey}.count`,o.count);if(i>r)throw S(`actors.${t.templateKey}.count cannot exceed capacity`);let a=bo(`actors.${t.templateKey}.presence`,o.presence,r),s=ha(t,n,a);if(i!==s)throw S(`actors.${t.templateKey}.count ${i} does not match present row count ${s}`);let c=Ao(`actors.${t.templateKey}.stateCode`,o.stateCode,r),d=Ao(`actors.${t.templateKey}.prevStateCode`,o.prevStateCode,r);Io(t,"stateCode",c),Io(t,"prevStateCode",d),Ea(t,a,c);let y=m(o,"rowVersion")&&o.rowVersion!==void 0?To(`actors.${t.templateKey}.rowVersion`,o.rowVersion,r):void 0,u=Ra(t.version,pt(`actors.${t.templateKey}.version`,K(`actors.${t.templateKey}.version`,o.version)),y),p=new Uint32Array(r);for(let f=0;f<r;f+=1)a[f]===1&&(p[f]=u);let w=H(`actors.${t.templateKey}.columns`,o.columns),E=Ot(t);we(`actors.${t.templateKey}.columns`,Object.keys(w),Object.keys(E));let l=Object.create(null);for(let[f,U]of Object.entries(E))l[f]=ga(`actors.${t.templateKey}.columns.${f}`,U,w[f],r);return{capacity:r,count:i,version:u,presence:a,stateCode:c,prevStateCode:d,rowVersion:p,columns:l}},xa=t=>{let e=new Uint8Array(t.entityStore.capacity);for(let n of Object.values(t.actorStores))for(let o=0;o<n.capacity;o+=1)n.presence[o]===1&&(e[o]=1);for(let n=0;n<t.entityStore.capacity;n+=1)if(t.entityStore.alive[n]===1&&e[n]!==1)throw S(`entity '${t.entityStore.ids[n]}' has no actor rows`)},ge=(t,e)=>{let n=H("storage.entity",e);if(n.formatVersion!==1)throw S("formatVersion must be 1");let o=pa(n,t.entityStore),r=H("actors",n.actors),i=Object.keys(t.actorStores);we("actors",Object.keys(r),i);let a=Object.create(null);for(let c of i)a[c]=Ca(t.actorStores[c],r[c],o);let s={entityStore:o,actorStores:a};return xa(s),s},_t=(t,e)=>ge(t,e);var ko=(t,e)=>Array.from({length:e},(n,o)=>t[o]??""),Aa=t=>({count:t.count,capacity:t.capacity,ids:ko(t.ids,t.capacity),alive:Array.from(t.alive),generation:Array.from(t.generation),groupTagByIndex:ko(t.groupTagByIndex,t.capacity),freeList:t.freeList.slice(),version:t.version}),Ia=(t,e,n,o)=>Array.from({length:e},(i,a)=>n[a]!==1?o:t[a]??o),va=t=>{let e=Ot(t);return{schema:{states:t.metadata.publicStates.slice(),columns:e},count:t.count,capacity:t.capacity,version:t.version,presence:Array.from(t.presence),stateCode:Array.from(t.stateCode),prevStateCode:Array.from(t.prevStateCode),rowVersion:Array.from(t.rowVersion),columns:Object.fromEntries(Object.entries(t.columns).map(([n,o])=>[n,Ia(o,t.capacity,t.presence,ct(t.metadata.initialContext[n]))]))}},he=(t,e)=>{let o=e.options?.machines??Object.keys(t.actorStores),r=Object.create(null);for(let i of o)r[i]=t.actorStores[i].publicSlice;return{machines:r,snapshot:{formatVersion:1,entityStore:Aa(t.entityStore),actors:Object.fromEntries(Object.entries(t.actorStores).map(([i,a])=>[i,va(a)]))}}};var Ta=(t,e)=>{let n=e;for(let[o,r]of Object.entries(t)){let i={storage:"entity",version:r.version,count:r.count,capacity:r.capacity};n===e&&(n={...e}),n[o]=i}return n},ba=(t,e)=>{t.count=e.count,t.capacity=e.capacity,t.ids=e.ids,t.indexById=Object.create(null),t.alive=e.alive,t.generation=e.generation,t.groupTagByIndex=e.groupTagByIndex,t.entitiesByGroupTag=Object.create(null),t.groupTagPosition=new Int32Array(e.capacity),t.groupTagPosition.fill(-1),t.freeList=e.freeList,t.version=e.version},ka=(t,e)=>{t.capacity=e.capacity,t.count=e.count,t.version=e.version,t.presence=e.presence,t.stateCode=e.stateCode,t.prevStateCode=e.prevStateCode,t.rowVersion=e.rowVersion,t.pendingPrevStateCodeSync=[],t.pendingPrevStateCodeSyncMark=new Uint32Array(e.capacity),t.pendingPrevStateCodeSyncToken=1,kt(t),ie(t),t.columns=e.columns,yt(t),q(t)},Ba=(t,e)=>{ba(t.entityStore,e.entityStore);for(let[n,o]of Object.entries(e.actorStores))ka(t.actorStores[n],o);ue(t)},Bo=(t,e)=>{if(e.snapshot===void 0){let r=J(t,e.baseState);return{nextState:r,changed:r!==e.baseState}}let n=ge(t,e.snapshot),o=e.mode==="preview"?Ta(n.actorStores,e.baseState):(Ba(t,n),J(t,e.baseState));return{nextState:o,changed:e.mode!=="preview"||o!==e.baseState}};var Po=Object.freeze([]),Re=()=>({rows:new Map,lists:new Map}),xe=t=>new _o.LiteFsmError("LITE_FSM_INVALID_STORAGE_RUNTIME",`[lite-fsm/entities/react] ${t}.`),Ce=(t,e)=>{let n=t.actorStores[e];if(n)return n;throw xe(`unknown entity actor template '${e}'`)},Mo=t=>{let e=t?.groupTag;if(e!==void 0){if(typeof e=="string")return e;throw xe("EntityListOptions.groupTag must be a string")}},Do=t=>{let e=Object.create(null);for(let n=0;n<t.alive.length;n+=1)t.alive[n]===1&&(e[t.ids[n]]=n);return e},Pa=(t,e)=>`${t}\0${e}`,Ma=(t,e)=>e===void 0?t:`${t}\0${e}`,Da=(t,e)=>{if(t.length!==e.length)return!1;for(let n=0;n<t.length;n+=1)if(t[n]!==e[n])return!1;return!0},Oa=(t,e)=>t[e],_a=(t,e,n)=>{let o={};for(let r of Object.keys(t.metadata.initialContext))o[r]=Oa(e.columns[r],n);return o},$a=(t,e,n)=>{let o=t.metadata.publicStates[e.stateCode[n]];if(o!==void 0)return o;throw xe(`actor '${t.templateKey}' row for entity '${n}' has no public state snapshot`)},La=(t,e,n,o)=>{if(Ce(t,n),o==null)return;let r=e.indexById[o];if(r===void 0)return;let i=e.actorStores[n];if(i.presence[r]!==1)return;let a=e.entityStore.generation[r],s=i.rowVersion[r],c=Pa(n,o),d=e.cache.rows.get(c);if(d?.entity===r&&d.generation===a&&d.rowVersion===s)return d.snapshot;let y=Ce(t,n),u={entityId:o,groupTag:e.entityStore.groupTagByIndex[r],state:$a(y,i,r),context:_a(y,i,r)};return e.cache.rows.set(c,{entity:r,generation:a,rowVersion:s,snapshot:u}),u},Oo=(t,e,n,o)=>{Ce(t,n);let r=e.actorStores[n];if(r.count===0)return Po;let i=[];for(let c=0;c<r.presence.length;c+=1)r.presence[c]===1&&(o!==void 0&&e.entityStore.groupTagByIndex[c]!==o||i.push(e.entityStore.ids[c]));if(i.length===0)return Po;let a=Ma(n,o),s=e.cache.lists.get(a);return s&&Da(s.ids,i)?s.ids:(e.cache.lists.set(a,{ids:i}),i)},$o=t=>{let e=Re(),n=new WeakMap,o=i=>{if(i!==null&&(typeof i=="object"||typeof i=="function")){let s=n.get(i);if(s)return s;let c=_t(t,i),d={imported:c,indexById:Do(c.entityStore),cache:Re()};return n.set(i,d),d}let a=_t(t,i);return{imported:a,indexById:Do(a.entityStore),cache:Re()}},r=i=>{if(i.mode==="commit")return{entityStore:t.entityStore,actorStores:t.actorStores,indexById:t.entityStore.indexById,cache:e};let a=o(i.snapshot);return{entityStore:a.imported.entityStore,actorStores:a.imported.actorStores,indexById:a.indexById,cache:a.cache}};return{readRow(i,a,s){return La(t,r(s),i,a)},readCount(i,a,s){let c=Mo(a);return Oo(t,r(s),i,c).length},readList(i,a,s){let c=Mo(a);return Oo(t,r(s),i,c)}}};var Ae="entity",lt=(t,e)=>new Z.LiteFsmError("LITE_FSM_INVALID_STORAGE_CONFIG",`[lite-fsm/entities] machine '${t}' has invalid storage: "entity" config: ${e}.`),Na=t=>new Z.LiteFsmError("LITE_FSM_INVALID_STORAGE_CONFIG",`[lite-fsm/entities] machine '${t}' uses despawnOn, but despawnOn is only supported with storage: "entity".`),Va=t=>new Z.LiteFsmError("LITE_FSM_INVALID_STORAGE_CONFIG",`[lite-fsm/entities] machine '${t}' uses reactions, but reactions are only supported with storage: "entity".`),ja=t=>{for(let[e,n]of Object.entries(t)){if(n===null||typeof n!="object")continue;let o=n;if(!(!m(o,"despawnOn")||o.despawnOn===void 0)&&o.storage!==Ae)throw Na(e)}},Fa=t=>{for(let[e,n]of Object.entries(t)){if(n===null||typeof n!="object")continue;let o=n;if(!(!m(o,"reactions")||o.reactions===void 0)&&o.storage!==Ae)throw Va(e)}},Ka=(t,e)=>{if(!m(e,"initialState")||e.initialState===void 0)throw lt(t,'missing required field "initialState"');if(e.initialState!=="__INIT")throw lt(t,'initialState must be "__INIT"');if(!m(e,"initialContext")||e.initialContext===void 0)throw lt(t,'missing required field "initialContext"');if(!m(e,"spawnSchema")||e.spawnSchema===void 0)throw lt(t,'missing required field "spawnSchema"');if(m(e,"groupTag")&&e.groupTag!==void 0)throw lt(t,"groupTag is defined by EntitySpawnSpec, not by actor template");Ut(t,"initialContext",e.initialContext),Ut(t,"spawnSchema",e.spawnSchema),ke(t,e.config)},Lo=(t,e)=>{let n=Wn(t,e);return n.react=$o(n),n},No=(0,Z.defineStorageRuntime)().create({kind:Ae,routeMetaKeys:["entityId"],reduceScope:"bucket",validateTemplate({key:t,machine:e}){Ka(t,e)},compileTemplate({key:t,machine:e}){return{data:Zt(t,e)}},createRuntimeState({templates:t,manager:e}){let n=e.config;return n===null||typeof n!="object"||(ja(n),Fa(n)),Lo(t,e)},createPublicInitialState({template:t,state:e}){return ye(D(e),t)},prepareAction({action:t,dispatch:e,state:n}){W(e,"entities.prepare.transaction",()=>{Et(t.type),gn(e,D(n))})},reduceBucket(t){return xo(D(t.state),t)},commit({state:t,dispatch:e}){W(e,"entities.commit.restorePublicSlices",()=>{e.nextState=J(D(t),e.nextState)})},effects:{resolveInvocations(t){return W(t.dispatch,"entities.effects.resolve",()=>Bn(D(t.state),t))},invoke(t){W(t.dispatch,"entities.effects.invoke",()=>{Pn(D(t.state),t.invocation,t)})}},reactions:{run(t){W(t.dispatch,"entities.reactions.total",()=>{yo(D(t.state),t)})}},snapshot:{dehydrate(t){return he(D(t.state),t)},hydrate(t){return Bo(D(t.state),t)}}});var Ua="@lite-fsm/entities",Ga=t=>{if(typeof t=="string"||Array.isArray(t)&&t.every(e=>typeof e=="string"))return t;throw new ft.LiteFsmError("LITE_FSM_INVALID_ROUTE_RESOLVER_RESULT","[lite-fsm/entities] routeMeta.entityId must be a string or an array of strings.")},Ha=t=>(0,ft.definePlugin)().create({name:Ua,storage:[No],routeMeta:{entityId:Ga},hooks:{beforeReduce(e){let{action:n}=e;Et(n.type),t&&hn(e,t)}},manager:{entities(e){let n=zn(e).access;return()=>n}}}),Ya=t=>{if(t!==void 0){if(t!==null&&typeof t=="object"&&"spawn"in t){let e=t.spawn;return sn(e),e}throw new ft.LiteFsmError("LITE_FSM_INVALID_OPTIONS","[lite-fsm/entities] entitiesPlugin options must be { spawn } with a defineEntitySpawn(...) descriptor.")}};function Vo(t){let e=Ya(t);return Ha(e)}0&&(module.exports={defineEntitySpawn,defineSpawnEvents,entitiesPlugin,f32,i16,i32,optional,resource,spawnEvent,string,u8});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { entitiesPlugin } from "./plugin";
|
|
2
|
+
export { f32, i16, i32, optional, resource, string, u8 } from "./schema";
|
|
3
|
+
export { defineEntitySpawn, defineSpawnEvents, spawnEvent } from "./spawn";
|
|
4
|
+
export type { EntityMachineExtension, EntityReducerContext, EntityReducerSelf } from "./machine-extension";
|
|
5
|
+
export type { EntitiesPlugin, EntityId, EntityIndex } from "./plugin";
|
|
6
|
+
export type { EntityAccess } from "./runtime/access";
|
|
7
|
+
export type { LiteFsmEntityLifecycleEvents } from "./runtime/lifecycle";
|
|
8
|
+
export type { SpawnEventsFrom } from "./spawn";
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { entitiesPlugin } from "./plugin";
|
|
2
|
+
export { f32, i16, i32, optional, resource, string, u8 } from "./schema";
|
|
3
|
+
export { defineEntitySpawn, defineSpawnEvents, spawnEvent } from "./spawn";
|
|
4
|
+
export type { EntityMachineExtension, EntityReducerContext, EntityReducerSelf } from "./machine-extension";
|
|
5
|
+
export type { EntitiesPlugin, EntityId, EntityIndex } from "./plugin";
|
|
6
|
+
export type { EntityAccess } from "./runtime/access";
|
|
7
|
+
export type { LiteFsmEntityLifecycleEvents } from "./runtime/lifecycle";
|
|
8
|
+
export type { SpawnEventsFrom } from "./spawn";
|