@typeonce/ritmo 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/Clock.d.ts +19 -4
- package/dist/Clock.d.ts.map +1 -1
- package/dist/Clock.js +18 -2
- package/dist/Clock.js.map +1 -1
- package/dist/Command.d.ts +181 -40
- package/dist/Command.d.ts.map +1 -1
- package/dist/Command.js +31 -11
- package/dist/Command.js.map +1 -1
- package/dist/Condition.d.ts +12 -1
- package/dist/Condition.d.ts.map +1 -1
- package/dist/Condition.js.map +1 -1
- package/dist/Debug.d.ts +127 -13
- package/dist/Debug.d.ts.map +1 -1
- package/dist/Descriptor.d.ts +61 -10
- package/dist/Descriptor.d.ts.map +1 -1
- package/dist/Descriptor.js +22 -10
- package/dist/Descriptor.js.map +1 -1
- package/dist/Entity.d.ts +22 -7
- package/dist/Entity.d.ts.map +1 -1
- package/dist/Entity.js.map +1 -1
- package/dist/EntityScope.d.ts +20 -1
- package/dist/EntityScope.d.ts.map +1 -1
- package/dist/EntityScope.js +8 -2
- package/dist/EntityScope.js.map +1 -1
- package/dist/FixedLoop.d.ts +106 -0
- package/dist/FixedLoop.d.ts.map +1 -0
- package/dist/FixedLoop.js +97 -0
- package/dist/FixedLoop.js.map +1 -0
- package/dist/HostClock.d.ts +1 -1
- package/dist/HostClock.d.ts.map +1 -1
- package/dist/HostClock.js +2 -1
- package/dist/HostClock.js.map +1 -1
- package/dist/Machine.d.ts +59 -34
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +10 -3
- package/dist/Machine.js.map +1 -1
- package/dist/Query.d.ts +100 -14
- package/dist/Query.d.ts.map +1 -1
- package/dist/Query.js +34 -5
- package/dist/Query.js.map +1 -1
- package/dist/Relation.d.ts +5 -14
- package/dist/Relation.d.ts.map +1 -1
- package/dist/Relation.js +0 -32
- package/dist/Relation.js.map +1 -1
- package/dist/Runtime.d.ts +61 -15
- package/dist/Runtime.d.ts.map +1 -1
- package/dist/Runtime.js +594 -70
- package/dist/Runtime.js.map +1 -1
- package/dist/Schedule.d.ts +24 -15
- package/dist/Schedule.d.ts.map +1 -1
- package/dist/Schedule.js +2 -1
- package/dist/Schedule.js.map +1 -1
- package/dist/Schema.d.ts +233 -48
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +33 -7
- package/dist/Schema.js.map +1 -1
- package/dist/Snapshot.d.ts +90 -1
- package/dist/Snapshot.d.ts.map +1 -1
- package/dist/Snapshot.js +42 -1
- package/dist/Snapshot.js.map +1 -1
- package/dist/System.d.ts +132 -31
- package/dist/System.d.ts.map +1 -1
- package/dist/System.js +32 -0
- package/dist/System.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/cells.d.ts +2 -0
- package/dist/internal/cells.d.ts.map +1 -1
- package/dist/internal/cells.js +34 -8
- package/dist/internal/cells.js.map +1 -1
- package/dist/internal/debug.d.ts +10 -0
- package/dist/internal/debug.d.ts.map +1 -1
- package/dist/internal/debug.js +171 -12
- package/dist/internal/debug.js.map +1 -1
- package/dist/internal/equal.d.ts +8 -0
- package/dist/internal/equal.d.ts.map +1 -0
- package/dist/internal/equal.js +38 -0
- package/dist/internal/equal.js.map +1 -0
- package/dist/internal/fragments.d.ts +2 -6
- package/dist/internal/fragments.d.ts.map +1 -1
- package/dist/internal/fragments.js +36 -3
- package/dist/internal/fragments.js.map +1 -1
- package/dist/internal/game.d.ts +2 -0
- package/dist/internal/game.d.ts.map +1 -1
- package/dist/internal/game.js +48 -7
- package/dist/internal/game.js.map +1 -1
- package/dist/internal/order.d.ts.map +1 -1
- package/dist/internal/order.js +4 -2
- package/dist/internal/order.js.map +1 -1
- package/dist/internal/queries.d.ts.map +1 -1
- package/dist/internal/queries.js +57 -26
- package/dist/internal/queries.js.map +1 -1
- package/dist/internal/relations.d.ts +10 -0
- package/dist/internal/relations.d.ts.map +1 -0
- package/dist/internal/relations.js +32 -0
- package/dist/internal/relations.js.map +1 -0
- package/dist/internal/requirements.d.ts +26 -0
- package/dist/internal/requirements.d.ts.map +1 -0
- package/dist/internal/requirements.js +46 -0
- package/dist/internal/requirements.js.map +1 -0
- package/dist/internal/streams.d.ts +2 -0
- package/dist/internal/streams.d.ts.map +1 -1
- package/dist/internal/streams.js +10 -0
- package/dist/internal/streams.js.map +1 -1
- package/dist/internal/world.d.ts +7 -1
- package/dist/internal/world.d.ts.map +1 -1
- package/dist/internal/world.js +53 -3
- package/dist/internal/world.js.map +1 -1
- package/package.json +1 -1
- package/src/Clock.ts +29 -4
- package/src/Command.ts +281 -67
- package/src/Condition.ts +17 -1
- package/src/Debug.ts +124 -15
- package/src/Descriptor.ts +92 -21
- package/src/Entity.ts +23 -7
- package/src/EntityScope.ts +21 -2
- package/src/FixedLoop.ts +218 -0
- package/src/HostClock.ts +2 -1
- package/src/Machine.ts +72 -35
- package/src/Query.ts +118 -17
- package/src/Relation.ts +5 -67
- package/src/Runtime.ts +659 -85
- package/src/Schedule.ts +31 -19
- package/src/Schema.ts +297 -57
- package/src/Snapshot.ts +94 -2
- package/src/System.ts +151 -29
- package/src/index.ts +4 -0
- package/src/internal/cells.ts +42 -10
- package/src/internal/debug.ts +179 -14
- package/src/internal/equal.ts +31 -0
- package/src/internal/fragments.ts +35 -5
- package/src/internal/game.ts +69 -7
- package/src/internal/order.ts +8 -4
- package/src/internal/queries.ts +62 -12
- package/src/internal/relations.ts +52 -0
- package/src/internal/requirements.ts +71 -0
- package/src/internal/streams.ts +11 -0
- package/src/internal/world.ts +60 -4
package/src/Schema.ts
CHANGED
|
@@ -54,7 +54,7 @@ import type { ConstructedDescriptor, Descriptor } from "./Descriptor.ts"
|
|
|
54
54
|
import type * as Entity from "./Entity.ts"
|
|
55
55
|
import type * as EntityScope from "./EntityScope.ts"
|
|
56
56
|
import { buildSchema, emptySchema, mergeSchemas } from "./internal/fragments.ts"
|
|
57
|
-
import { makeGame } from "./internal/game.ts"
|
|
57
|
+
import { type exitApplyDeferredMessage, makeGame } from "./internal/game.ts"
|
|
58
58
|
import type * as Condition from "./Condition.ts"
|
|
59
59
|
import type * as Inspector from "./Inspector.ts"
|
|
60
60
|
import type * as Machine from "./Machine.ts"
|
|
@@ -66,6 +66,7 @@ import type * as Result from "./Result.ts"
|
|
|
66
66
|
import type * as Debug from "./Debug.ts"
|
|
67
67
|
import type * as Runtime from "./Runtime.ts"
|
|
68
68
|
import type * as Schedule from "./Schedule.ts"
|
|
69
|
+
import type * as Snapshot from "./Snapshot.ts"
|
|
69
70
|
import type * as System from "./System.ts"
|
|
70
71
|
|
|
71
72
|
/**
|
|
@@ -73,22 +74,107 @@ import type * as System from "./System.ts"
|
|
|
73
74
|
*/
|
|
74
75
|
export type Registry = Record<string, Descriptor.Any>
|
|
75
76
|
|
|
77
|
+
/** At least one: a permission that names nothing allows nothing. */
|
|
78
|
+
type NonEmpty<T> = readonly [T, ...ReadonlyArray<T>]
|
|
79
|
+
|
|
80
|
+
type Article<Kind extends string> = Kind extends "event" ? "an" : "a"
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Rejects descriptors of another kind in a fragment's `components`,
|
|
84
|
+
* `resources`, or `events`, naming where each belongs.
|
|
85
|
+
*/
|
|
86
|
+
type RegistryOfKind<R, Expected extends string> = {
|
|
87
|
+
readonly [K in keyof R]: R[K] extends { readonly kind: Expected }
|
|
88
|
+
? unknown
|
|
89
|
+
: R[K] extends { readonly kind: infer Actual extends string }
|
|
90
|
+
? {
|
|
91
|
+
readonly __fixSchema__: Actual extends "service"
|
|
92
|
+
? `${K & string} is a service, not ${Article<Expected>} ${Expected}: provide services to Game.Runtime.make({ services }) instead of registering them`
|
|
93
|
+
: `${K & string} is ${Article<Actual>} ${Actual}, not ${Article<Expected>} ${Expected}: move it to ${Actual}s: { ... }`
|
|
94
|
+
}
|
|
95
|
+
: unknown
|
|
96
|
+
}
|
|
97
|
+
|
|
76
98
|
/**
|
|
77
99
|
* A closed schema: the components, resources, events, and relations a world
|
|
78
|
-
* may contain.
|
|
100
|
+
* may contain, and the component requirements (`Schema.requires`) every
|
|
101
|
+
* entity of it keeps.
|
|
79
102
|
*/
|
|
80
103
|
export interface SchemaDefinition<
|
|
81
104
|
out Components extends Registry = {},
|
|
82
105
|
out Resources extends Registry = {},
|
|
83
106
|
out Events extends Registry = {},
|
|
84
|
-
out Relations extends Record<string, Relation.Relation.Any> = {}
|
|
107
|
+
out Relations extends Record<string, Relation.Relation.Any> = {},
|
|
108
|
+
out Requires extends RequirementPair = never
|
|
85
109
|
> {
|
|
86
110
|
readonly components: Components
|
|
87
111
|
readonly resources: Resources
|
|
88
112
|
readonly events: Events
|
|
89
113
|
readonly relations: Relations
|
|
114
|
+
/** Component requirements declared with `Schema.requires(...)`. */
|
|
115
|
+
readonly requires: ReadonlyArray<ComponentRequirement<Requires>>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* One requirement carried in a schema type, by component name:
|
|
120
|
+
* `[requirer, required]`. One pair per required component, so lookups by
|
|
121
|
+
* either end stay exact.
|
|
122
|
+
*/
|
|
123
|
+
export type RequirementPair = readonly [string, string]
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* One `Schema.requires(...)` declaration: every entity holding `component`
|
|
127
|
+
* also holds each of `required`.
|
|
128
|
+
*/
|
|
129
|
+
export interface ComponentRequirement<out Pairs extends RequirementPair = RequirementPair> {
|
|
130
|
+
readonly kind: "requires"
|
|
131
|
+
readonly component: Descriptor<"component", string, any>
|
|
132
|
+
readonly required: ReadonlyArray<Descriptor<"component", string, any>>
|
|
133
|
+
readonly __pairs?: (_: never) => Pairs
|
|
90
134
|
}
|
|
91
135
|
|
|
136
|
+
type AnyComponentDescriptor = Descriptor<"component", string, any>
|
|
137
|
+
|
|
138
|
+
/** One `[from, to]` pair per required name. */
|
|
139
|
+
type RequirementPairs<From extends string, To extends string> = To extends string ? readonly [From, To] : never
|
|
140
|
+
|
|
141
|
+
type PairsOf<R> = R extends ComponentRequirement<infer Pairs> ? Pairs : never
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Declares that every entity holding `component` also holds each of
|
|
145
|
+
* `required`. List it in a fragment's `requires`.
|
|
146
|
+
*
|
|
147
|
+
* The compiler then rejects every command that would break it:
|
|
148
|
+
* `commands.spawn` / `spawnIn` of a draft missing a required entry,
|
|
149
|
+
* `commands.insert` of `component` on an entity not proven to hold the
|
|
150
|
+
* rest, and `commands.remove` of a required component while a requirer may
|
|
151
|
+
* stay. `Game.System.spawns(component)` also allows spawning what it
|
|
152
|
+
* requires. Nothing is ever filled in with a default: the draft must carry
|
|
153
|
+
* every value.
|
|
154
|
+
*
|
|
155
|
+
* Requirements chain (`A` requires `B`, `B` requires `C`) and may name
|
|
156
|
+
* components of other fragments of the same `Schema.bind`.
|
|
157
|
+
*
|
|
158
|
+
* A saved component cannot require a transient one (`Schema.bind` rejects
|
|
159
|
+
* it): a restore would bring the requirer back without it. A transient
|
|
160
|
+
* requirer may require a transient component.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* const Gameplay = Schema.fragment({
|
|
165
|
+
* components: { Player, Position, Velocity },
|
|
166
|
+
* requires: [Schema.requires(Player, Position, Velocity)]
|
|
167
|
+
* })
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
export const requires = <
|
|
171
|
+
D extends AnyComponentDescriptor,
|
|
172
|
+
const Required extends readonly [AnyComponentDescriptor, ...Array<AnyComponentDescriptor>]
|
|
173
|
+
>(
|
|
174
|
+
component: D,
|
|
175
|
+
...required: Required
|
|
176
|
+
): ComponentRequirement<RequirementPairs<D["name"], Required[number]["name"]>> => ({ kind: "requires", component, required })
|
|
177
|
+
|
|
92
178
|
const schemaRootTypeId = "~ritmo/SchemaRoot" as const
|
|
93
179
|
|
|
94
180
|
export type RootToken<Name extends string = string> = {
|
|
@@ -112,7 +198,8 @@ export type MergeSchemaDefinitions<
|
|
|
112
198
|
Schema.Components<A> & Schema.Components<B>,
|
|
113
199
|
Schema.Resources<A> & Schema.Resources<B>,
|
|
114
200
|
Schema.Events<A> & Schema.Events<B>,
|
|
115
|
-
Schema.Relations<A> & Schema.Relations<B
|
|
201
|
+
Schema.Relations<A> & Schema.Relations<B>,
|
|
202
|
+
Schema.Requires<A> | Schema.Requires<B>
|
|
116
203
|
>
|
|
117
204
|
|
|
118
205
|
/**
|
|
@@ -186,6 +273,40 @@ export type ValidateFragments<Fragments extends ReadonlyArray<Schema.Any>> =
|
|
|
186
273
|
readonly __schemaConflicts__: FragmentConflicts<Fragments>
|
|
187
274
|
}
|
|
188
275
|
|
|
276
|
+
type UnregisteredRequirements<S extends Schema.Any> =
|
|
277
|
+
Exclude<Schema.Requires<S>[0] | Schema.Requires<S>[1], Schema.ComponentDescriptor<S>["name"]>
|
|
278
|
+
|
|
279
|
+
type TransientComponentName<S extends Schema.Any> = Extract<Schema.ComponentDescriptor<S>, { readonly transient: true }>["name"]
|
|
280
|
+
|
|
281
|
+
/** One message per saved requirer that requires a transient component. */
|
|
282
|
+
type TransientRequirements<S extends Schema.Any, Pairs = Schema.Requires<S>> =
|
|
283
|
+
Pairs extends readonly [infer From extends string, infer To extends string]
|
|
284
|
+
? To extends TransientComponentName<S>
|
|
285
|
+
? From extends TransientComponentName<S> ? never
|
|
286
|
+
: `${From} requires ${To}, which is transient and not saved: make ${From} transient too, or give ${To} a constructor`
|
|
287
|
+
: never
|
|
288
|
+
: never
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Rejects requirements naming a component the bound schema does not
|
|
292
|
+
* register. Checked at `bind`, so a fragment may require a component another
|
|
293
|
+
* fragment registers. Also rejects a saved component requiring a transient
|
|
294
|
+
* one (a restore would bring the requirer back without it). Erased schemas
|
|
295
|
+
* (`Schema.Any`) are checked by `bind` at runtime instead.
|
|
296
|
+
*/
|
|
297
|
+
export type ValidateRequires<S extends Schema.Any> =
|
|
298
|
+
string extends Schema.Requires<S>[1]
|
|
299
|
+
? unknown
|
|
300
|
+
: [UnregisteredRequirements<S>] extends [never]
|
|
301
|
+
? [TransientRequirements<S>] extends [never]
|
|
302
|
+
? unknown
|
|
303
|
+
: {
|
|
304
|
+
readonly __schemaRequires__: TransientRequirements<S>
|
|
305
|
+
}
|
|
306
|
+
: {
|
|
307
|
+
readonly __schemaRequires__: `${UnregisteredRequirements<S>} is named in Schema.requires(...) but no fragment registers it: add it to a fragment's components`
|
|
308
|
+
}
|
|
309
|
+
|
|
189
310
|
/**
|
|
190
311
|
* Creates one explicit root token for schema-bound long-lived references.
|
|
191
312
|
*
|
|
@@ -209,11 +330,6 @@ export const defineRoot = <const Name extends string>(name: Name): RootToken<Nam
|
|
|
209
330
|
}
|
|
210
331
|
}) as RootToken<Name>
|
|
211
332
|
|
|
212
|
-
/**
|
|
213
|
-
* Creates an empty schema.
|
|
214
|
-
*/
|
|
215
|
-
export const empty = (): SchemaDefinition => emptySchema()
|
|
216
|
-
|
|
217
333
|
/**
|
|
218
334
|
* Creates a schema fragment.
|
|
219
335
|
*
|
|
@@ -224,8 +340,9 @@ export const empty = (): SchemaDefinition => emptySchema()
|
|
|
224
340
|
* @example
|
|
225
341
|
* ```ts
|
|
226
342
|
* const Combat = Schema.fragment({
|
|
227
|
-
* components: { Health, Damage },
|
|
228
|
-
* events: { Hit }
|
|
343
|
+
* components: { Health, Damage, Enemy },
|
|
344
|
+
* events: { Hit },
|
|
345
|
+
* requires: [Schema.requires(Enemy, Health)]
|
|
229
346
|
* })
|
|
230
347
|
* ```
|
|
231
348
|
*/
|
|
@@ -233,19 +350,22 @@ export const fragment = <
|
|
|
233
350
|
const Components extends Registry = {},
|
|
234
351
|
const Resources extends Registry = {},
|
|
235
352
|
const Events extends Registry = {},
|
|
236
|
-
const Relations extends Record<string, Relation.Relation.Any> = {}
|
|
353
|
+
const Relations extends Record<string, Relation.Relation.Any> = {},
|
|
354
|
+
const Requires extends ReadonlyArray<ComponentRequirement> = readonly []
|
|
237
355
|
>(definition: {
|
|
238
|
-
readonly components?: Components
|
|
239
|
-
readonly resources?: Resources
|
|
240
|
-
readonly events?: Events
|
|
356
|
+
readonly components?: Components & RegistryOfKind<Components, "component">
|
|
357
|
+
readonly resources?: Resources & RegistryOfKind<Resources, "resource">
|
|
358
|
+
readonly events?: Events & RegistryOfKind<Events, "event">
|
|
241
359
|
readonly relations?: Relations
|
|
242
|
-
|
|
360
|
+
readonly requires?: Requires
|
|
361
|
+
} & ValidateFragments<[SchemaDefinition<Components, Resources, Events, Relations>]>): SchemaDefinition<Components, Resources, Events, Relations, PairsOf<Requires[number]>> =>
|
|
243
362
|
mergeSchemas(emptySchema(), {
|
|
244
363
|
components: definition.components ?? {},
|
|
245
364
|
resources: definition.resources ?? {},
|
|
246
365
|
events: definition.events ?? {},
|
|
247
|
-
relations: definition.relations ?? {}
|
|
248
|
-
|
|
366
|
+
relations: definition.relations ?? {},
|
|
367
|
+
requires: definition.requires ?? []
|
|
368
|
+
}) as SchemaDefinition<Components, Resources, Events, Relations, PairsOf<Requires[number]>>
|
|
249
369
|
|
|
250
370
|
/**
|
|
251
371
|
* Composes one or more fragments and returns one bound `Game` surface.
|
|
@@ -262,18 +382,18 @@ export const fragment = <
|
|
|
262
382
|
*/
|
|
263
383
|
export function bind<
|
|
264
384
|
S extends Schema.Any
|
|
265
|
-
>(schema: S & ValidateFragments<[S]>): Schema.Game<S, S>
|
|
385
|
+
>(schema: S & ValidateFragments<[S]> & ValidateRequires<S>): Schema.Game<S, S>
|
|
266
386
|
export function bind<
|
|
267
387
|
S extends Schema.Any,
|
|
268
388
|
const Name extends string
|
|
269
|
-
>(schema: S & ValidateFragments<[S]>, root: RootToken<Name>): Schema.Game<S, RootToken<Name>>
|
|
389
|
+
>(schema: S & ValidateFragments<[S]> & ValidateRequires<S>, root: RootToken<Name>): Schema.Game<S, RootToken<Name>>
|
|
270
390
|
export function bind<
|
|
271
391
|
const Fragments extends readonly [Schema.Any, Schema.Any, ...Array<Schema.Any>]
|
|
272
|
-
>(...fragments: Fragments & ValidateFragments<Fragments>): Schema.Game<BuildFragments<Fragments>, BuildFragments<Fragments>>
|
|
392
|
+
>(...fragments: Fragments & ValidateFragments<Fragments> & ValidateRequires<BuildFragments<Fragments>>): Schema.Game<BuildFragments<Fragments>, BuildFragments<Fragments>>
|
|
273
393
|
export function bind<
|
|
274
394
|
const Fragments extends readonly [Schema.Any, Schema.Any, ...Array<Schema.Any>],
|
|
275
395
|
const Name extends string
|
|
276
|
-
>(...args: [...Fragments, RootToken<Name>] & ValidateFragments<Fragments>): Schema.Game<BuildFragments<Fragments>, RootToken<Name>>
|
|
396
|
+
>(...args: [...Fragments, RootToken<Name>] & ValidateFragments<Fragments> & ValidateRequires<BuildFragments<Fragments>>): Schema.Game<BuildFragments<Fragments>, RootToken<Name>>
|
|
277
397
|
export function bind(...args: ReadonlyArray<Schema.Any | RootToken>) {
|
|
278
398
|
const maybeRoot = args[args.length - 1]
|
|
279
399
|
const fragments = (isRootToken(maybeRoot) ? args.slice(0, -1) : args) as Array<Schema.Any>
|
|
@@ -298,7 +418,7 @@ type QuerySelectionAccess<S extends Schema.Any, Root> =
|
|
|
298
418
|
|
|
299
419
|
interface BoundSystemAccess<S extends Schema.Any, Root> extends System.SystemAccessInput {
|
|
300
420
|
readonly queries?: Record<string, Query.Any<Root>>
|
|
301
|
-
readonly resources?: Record<string, System.ResourceRead<ResourceDescriptor<S>> | System.ResourceWrite<ResourceDescriptor<S>>>
|
|
421
|
+
readonly resources?: Record<string, System.ResourceRead<ResourceDescriptor<S>> | System.ResourceChanged<ResourceDescriptor<S>> | System.ResourceWrite<ResourceDescriptor<S>>>
|
|
302
422
|
readonly events?: Record<string, System.EventRead<EventDescriptor<S>> | System.EventWrite<EventDescriptor<S>>>
|
|
303
423
|
readonly machines?: Record<string, Machine.MachineRead<Schema.BoundStateMachine<Root>>>
|
|
304
424
|
readonly nextMachines?: Record<string, Machine.NextMachineWrite<Schema.BoundStateMachine<Root>>>
|
|
@@ -314,7 +434,7 @@ interface BoundSystemAccess<S extends Schema.Any, Root> extends System.SystemAcc
|
|
|
314
434
|
|
|
315
435
|
interface BoundCheckAccess<S extends Schema.Any, Root> extends Condition.CheckAccessInput {
|
|
316
436
|
readonly queries?: Record<string, Query.Any<Root>>
|
|
317
|
-
readonly resources?: Record<string, System.ResourceRead<ResourceDescriptor<S>>>
|
|
437
|
+
readonly resources?: Record<string, System.ResourceRead<ResourceDescriptor<S>> | System.ResourceChanged<ResourceDescriptor<S>> | System.ResourceWrite<ResourceDescriptor<S>>>
|
|
318
438
|
readonly machines?: Record<string, Machine.MachineRead<Schema.BoundStateMachine<Root>>>
|
|
319
439
|
}
|
|
320
440
|
|
|
@@ -337,6 +457,16 @@ type BoundScheduleEntry<S extends Schema.Any, Root> =
|
|
|
337
457
|
type BoundTransitionEntry<S extends Schema.Any, Root> =
|
|
338
458
|
Exclude<BoundScheduleEntry<S, Root>, Schedule.ApplyStateTransitionsStep<any, Root>>
|
|
339
459
|
|
|
460
|
+
/**
|
|
461
|
+
* Rejects `applyDeferred()` in an exit phase (`onExit`, `onTransition`): the
|
|
462
|
+
* phase rolls back as one when a system in it fails, which applied commands
|
|
463
|
+
* could not. Nested schedules are checked when the schedule is built.
|
|
464
|
+
*/
|
|
465
|
+
type NoApplyDeferredInExit<Entries extends ReadonlyArray<unknown>> =
|
|
466
|
+
[Extract<Entries[number], Schedule.ApplyDeferredStep>] extends [never]
|
|
467
|
+
? unknown
|
|
468
|
+
: { readonly __fixTransition__: typeof exitApplyDeferredMessage }
|
|
469
|
+
|
|
340
470
|
type BoundTransitionScheduleResult<
|
|
341
471
|
S extends Schema.Any,
|
|
342
472
|
Root,
|
|
@@ -345,7 +475,8 @@ type BoundTransitionScheduleResult<
|
|
|
345
475
|
> = Machine.TransitionScheduleDefinition<
|
|
346
476
|
S,
|
|
347
477
|
M,
|
|
348
|
-
|
|
478
|
+
// The machine itself: a transition schedule on a machine the runtime does not provide could never run.
|
|
479
|
+
Schedule.CompositionExactRequirements<Entries> | M,
|
|
349
480
|
Root,
|
|
350
481
|
Schedule.CompositionFailure<Entries>,
|
|
351
482
|
Schedule.CompositionOrder<Entries>
|
|
@@ -376,12 +507,14 @@ export namespace Schema {
|
|
|
376
507
|
/**
|
|
377
508
|
* Any complete schema definition.
|
|
378
509
|
*/
|
|
379
|
-
export type Any = SchemaDefinition<Registry, Registry, Registry, Record<string, Relation.Relation.Any
|
|
510
|
+
export type Any = SchemaDefinition<Registry, Registry, Registry, Record<string, Relation.Relation.Any>, RequirementPair>
|
|
380
511
|
|
|
381
512
|
export type Components<T extends Any> = T["components"]
|
|
382
513
|
export type Resources<T extends Any> = T["resources"]
|
|
383
514
|
export type Events<T extends Any> = T["events"]
|
|
384
515
|
export type Relations<T extends Any> = T["relations"]
|
|
516
|
+
/** The component requirements of a schema, as `[requirer, required]` name pairs (`Schema.requires`). */
|
|
517
|
+
export type Requires<T extends Any> = T extends SchemaDefinition<any, any, any, any, infer Pairs> ? Pairs : never
|
|
385
518
|
|
|
386
519
|
export type ComponentValue<T extends Any, K extends keyof Components<T>> = Descriptor.Value<Components<T>[K]>
|
|
387
520
|
export type ResourceValue<T extends Any, K extends keyof Resources<T>> = Descriptor.Value<Resources<T>[K]>
|
|
@@ -434,8 +567,9 @@ export namespace Schema {
|
|
|
434
567
|
export type BoundStateMachine<
|
|
435
568
|
Root,
|
|
436
569
|
Name extends string = string,
|
|
437
|
-
Values extends readonly [Machine.StateValue, ...Machine.StateValue[]] = readonly [Machine.StateValue, ...Machine.StateValue[]]
|
|
438
|
-
|
|
570
|
+
Values extends readonly [Machine.StateValue, ...Machine.StateValue[]] = readonly [Machine.StateValue, ...Machine.StateValue[]],
|
|
571
|
+
Parent = unknown
|
|
572
|
+
> = Machine.StateMachineDefinition<Name, Values, Root, Parent>
|
|
439
573
|
|
|
440
574
|
export type BoundTransitionSchedule<
|
|
441
575
|
S extends Any,
|
|
@@ -473,11 +607,38 @@ export namespace Schema {
|
|
|
473
607
|
readonly schema: S
|
|
474
608
|
/**
|
|
475
609
|
* Creates a typed ownership scope for scene or level entities: a flat
|
|
476
|
-
* group
|
|
477
|
-
* `Descriptor.Hierarchy` instead for a
|
|
478
|
-
* children, traversal, and recursive
|
|
610
|
+
* group whose members are spawned with `commands.spawnIn(...)` and
|
|
611
|
+
* despawned together. Use `Descriptor.Hierarchy` instead for a
|
|
612
|
+
* parent-child tree with ordered children, traversal, and recursive
|
|
613
|
+
* despawn.
|
|
614
|
+
*
|
|
615
|
+
* When the group lives exactly as long as a state, name the state change
|
|
616
|
+
* that ends it: `despawnOnExit: [Flow, "Playing"]` despawns every member
|
|
617
|
+
* when `applyStateTransitions(...)` commits leaving `Playing` (after its
|
|
618
|
+
* `onExit` schedules, which still see the members), and
|
|
619
|
+
* `despawnOnEnter: [Flow, "Playing"]` when it commits entering it (before
|
|
620
|
+
* its `onEnter` schedules, so what they spawn survives). Use
|
|
621
|
+
* `commands.despawnScope(...)` instead when the wipe is not tied to a
|
|
622
|
+
* state change. Scope names are unique per game.
|
|
623
|
+
*
|
|
624
|
+
* @example
|
|
625
|
+
* ```ts
|
|
626
|
+
* const RunScope = Game.EntityScope("Shooter/Run", { despawnOnExit: [Flow, "Playing"] })
|
|
627
|
+
* ```
|
|
479
628
|
*/
|
|
480
|
-
readonly EntityScope: <
|
|
629
|
+
readonly EntityScope: <
|
|
630
|
+
const Name extends string,
|
|
631
|
+
Enter extends Machine.StateMachine.Any = never,
|
|
632
|
+
Exit extends Machine.StateMachine.Any = never
|
|
633
|
+
>(
|
|
634
|
+
name: Name,
|
|
635
|
+
options?: {
|
|
636
|
+
/** Despawns every member when the machine enters this state, before its `onEnter` schedules run. */
|
|
637
|
+
readonly despawnOnEnter?: readonly [Enter & Machine.SameGame<Enter, Root>, Machine.StateMachine.Value<Enter>]
|
|
638
|
+
/** Despawns every member when the machine leaves this state, after its `onExit` schedules run. */
|
|
639
|
+
readonly despawnOnExit?: readonly [Exit & Machine.SameGame<Exit, Root>, Machine.StateMachine.Value<Exit>]
|
|
640
|
+
}
|
|
641
|
+
) => EntityScope.EntityScope<Name, Root>
|
|
481
642
|
/** Declares a reusable, requirement-checked read-only world projection. */
|
|
482
643
|
readonly Inspector: <
|
|
483
644
|
const Name extends string,
|
|
@@ -497,6 +658,13 @@ export namespace Schema {
|
|
|
497
658
|
target: Entity.HandleTarget<S, Root>,
|
|
498
659
|
intent?: D
|
|
499
660
|
) => Entity.Handle<Root, D>
|
|
661
|
+
/**
|
|
662
|
+
* The entity id a handle names, to compare with ids or pass where an id
|
|
663
|
+
* is expected (`queries.x.get(id)`), instead of storing the id beside
|
|
664
|
+
* the handle. Like the handle, it proves nothing about liveness:
|
|
665
|
+
* resolve it through a query. Two handles of the same entity are `===`.
|
|
666
|
+
*/
|
|
667
|
+
id: (handle: Entity.Handle<Root, ComponentDescriptor<S> | undefined>) => Entity.EntityId<S, Root>
|
|
500
668
|
}
|
|
501
669
|
readonly Query: {
|
|
502
670
|
<
|
|
@@ -511,7 +679,7 @@ export namespace Schema {
|
|
|
511
679
|
>(spec: {
|
|
512
680
|
readonly selection: Selection
|
|
513
681
|
readonly with?: With
|
|
514
|
-
readonly without?: Without
|
|
682
|
+
readonly without?: Without & QueryModule.ExclusionsPossible<Selection, With, Without, Filters>
|
|
515
683
|
readonly filters?: Filters
|
|
516
684
|
readonly withRelations?: WithRelations
|
|
517
685
|
readonly withoutRelations?: WithoutRelations
|
|
@@ -520,10 +688,17 @@ export namespace Schema {
|
|
|
520
688
|
// Uninferred: an omitted list is `[]`, never inferred from the spec it is written in (`queries: { ... }`).
|
|
521
689
|
}): QueryModule.QuerySpec<Selection, QueryModule.Uninferred<With, ReadonlyArray<ComponentDescriptor<S>>>, QueryModule.Uninferred<Without, ReadonlyArray<ComponentDescriptor<S>>>, QueryModule.Uninferred<Filters, ReadonlyArray<QueryModule.Filter<ComponentDescriptor<S>>>>, QueryModule.Uninferred<WithRelations, ReadonlyArray<Relation.Relation.Any>>, QueryModule.Uninferred<WithoutRelations, ReadonlyArray<Relation.Relation.Any>>, QueryModule.Uninferred<WithRelated, ReadonlyArray<Relation.Relation.Any>>, QueryModule.Uninferred<WithoutRelated, ReadonlyArray<Relation.Relation.Any>>, Root>
|
|
522
690
|
read: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.ReadAccess<D>
|
|
523
|
-
write: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.WriteAccess<D>
|
|
691
|
+
write: <D extends ComponentDescriptor<S>>(descriptor: D & QueryModule.Writable<D>) => QueryModule.WriteAccess<D>
|
|
524
692
|
optional: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.OptionalReadAccess<D>
|
|
525
693
|
added: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.AddedFilter<D>
|
|
526
694
|
changed: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.ChangedFilter<D>
|
|
695
|
+
anyOf: <
|
|
696
|
+
const Filters extends readonly [
|
|
697
|
+
QueryModule.LifecycleFilter<ComponentDescriptor<S>>,
|
|
698
|
+
QueryModule.LifecycleFilter<ComponentDescriptor<S>>,
|
|
699
|
+
...ReadonlyArray<QueryModule.LifecycleFilter<ComponentDescriptor<S>>>
|
|
700
|
+
]
|
|
701
|
+
>(...filters: Filters) => QueryModule.AnyOfFilter<Filters[number]["descriptor"]>
|
|
527
702
|
readRelation: <R extends RelationDescriptor<S>>(descriptor: R) => Relation.RelationReadAccess<R, S, Root>
|
|
528
703
|
optionalRelation: <R extends RelationDescriptor<S>>(descriptor: R) => Relation.OptionalRelationReadAccess<R, S, Root>
|
|
529
704
|
readRelated: <R extends RelationDescriptor<S>>(descriptor: R) => Relation.RelatedReadAccess<R, S, Root>
|
|
@@ -538,20 +713,25 @@ export namespace Schema {
|
|
|
538
713
|
* Adds entries to a draft (a value not yet spawned). Use
|
|
539
714
|
* `commands.insert` for an entity that already exists.
|
|
540
715
|
*/
|
|
541
|
-
extend: <P extends Entity.ComponentProof, const Entries extends ReadonlyArray<Command.SpawnEntry<S
|
|
542
|
-
draft: Entity.EntityDraft<S, P, Root>,
|
|
716
|
+
extend: <P extends Entity.ComponentProof, const Entries extends ReadonlyArray<Command.SpawnEntry<S>>, Relates = never>(
|
|
717
|
+
draft: Entity.EntityDraft<S, P, Root, Relates>,
|
|
543
718
|
...entries: Entries
|
|
544
|
-
) => Command.DraftFor<S, Entries, P, Root>
|
|
545
|
-
entry: <D extends ComponentDescriptor<S>>(descriptor: D, value: Descriptor.Value<D
|
|
719
|
+
) => Command.DraftFor<S, Entries, P, Root, Relates>
|
|
720
|
+
entry: <D extends ComponentDescriptor<S>>(descriptor: D, value: QueryModule.ReadonlyValue<Descriptor.Value<D>>) => Command.Entry<D>
|
|
546
721
|
entryRaw: <D extends Extract<ComponentDescriptor<S>, ConstructedDescriptor<"component", string, any, any, any>>>(
|
|
547
722
|
descriptor: D,
|
|
548
723
|
raw: Descriptor.Raw<D>
|
|
549
724
|
) => Result.Result<Command.Entry<D>, Descriptor.ConstructionError<D>>
|
|
550
|
-
|
|
551
|
-
|
|
725
|
+
/**
|
|
726
|
+
* Stages a relation on a draft, created with the spawn. Spawning the
|
|
727
|
+
* draft needs the relation in `Game.System.relates(...)`, like
|
|
728
|
+
* `commands.relate`.
|
|
729
|
+
*/
|
|
730
|
+
relate: <P extends Entity.ComponentProof, R extends RelationDescriptor<S>, Relates = never>(
|
|
731
|
+
draft: Entity.EntityDraft<S, P, Root, Relates>,
|
|
552
732
|
relation: R,
|
|
553
733
|
target: Entity.EntityId<S, Root>
|
|
554
|
-
) => Entity.EntityDraft<S, P, Root>
|
|
734
|
+
) => Entity.EntityDraft<S, P, Root, Relates | R>
|
|
555
735
|
}
|
|
556
736
|
/**
|
|
557
737
|
* Declares one game-wide mode (menu, playing, paused): queued with
|
|
@@ -564,10 +744,52 @@ export namespace Schema {
|
|
|
564
744
|
const Name extends string,
|
|
565
745
|
const Values extends readonly [Machine.StateValue, ...Machine.StateValue[]]
|
|
566
746
|
>(name: Name, values: Values): Schema.BoundStateMachine<Root, Name, Values>
|
|
747
|
+
/**
|
|
748
|
+
* Declares a sub-state: a machine that exists only while `within[0]` is
|
|
749
|
+
* in state `within[1]` (a battle phase that only means something while
|
|
750
|
+
* playing). Whenever the parent enters that state, the sub-state enters
|
|
751
|
+
* the value given to `Game.Runtime.machine(...)`; when the parent leaves
|
|
752
|
+
* it, the sub-state exits and has no value: `get()` is `undefined`,
|
|
753
|
+
* `Game.Condition.inState(Sub, x)` is false, and `nextMachines.sub.set(...)`
|
|
754
|
+
* returns a `SubStateInactive` failure. So `inState(Sub, x)` alone
|
|
755
|
+
* implies the parent's state.
|
|
756
|
+
*
|
|
757
|
+
* The sub-state enters together with the parent's commit, before any
|
|
758
|
+
* `onEnter` schedule runs: the parent's `onEnter` systems already see its
|
|
759
|
+
* value, its `despawnOnEnter` scopes are cleared before they spawn, and
|
|
760
|
+
* a failing `onEnter` leaves it entered. Its own `onEnter` schedules
|
|
761
|
+
* run after the parent's.
|
|
762
|
+
*
|
|
763
|
+
* Use a second top-level machine instead when the two modes are
|
|
764
|
+
* independent (each keeps its value whatever the other does).
|
|
765
|
+
*
|
|
766
|
+
* @example
|
|
767
|
+
* ```ts
|
|
768
|
+
* const Phase = Game.StateMachine("Phase", ["Setup", "Battle"], { within: [Session, "Playing"] })
|
|
769
|
+
* ```
|
|
770
|
+
*/
|
|
771
|
+
<
|
|
772
|
+
const Name extends string,
|
|
773
|
+
const Values extends readonly [Machine.StateValue, ...Machine.StateValue[]],
|
|
774
|
+
Parent extends Machine.StateMachine.Any
|
|
775
|
+
>(
|
|
776
|
+
name: Name,
|
|
777
|
+
values: Values,
|
|
778
|
+
options: { readonly within: readonly [Parent & Machine.SameGame<Parent, Root>, Machine.StateMachine.Value<Parent>] }
|
|
779
|
+
): Schema.BoundStateMachine<Root, Name, Values, Parent>
|
|
567
780
|
}
|
|
568
781
|
readonly Condition: {
|
|
569
|
-
|
|
570
|
-
|
|
782
|
+
/**
|
|
783
|
+
* Passes while the machine's committed value is `value`. For a
|
|
784
|
+
* sub-state it fails while the parent is in another state. A machine
|
|
785
|
+
* of another game fails to compile with a message naming the fix.
|
|
786
|
+
*/
|
|
787
|
+
inState: <M extends Machine.StateMachine.Any>(
|
|
788
|
+
machine: M & Machine.SameGame<M, Root>,
|
|
789
|
+
value: Machine.StateMachine.Value<M>
|
|
790
|
+
) => Machine.InStateCondition<M>
|
|
791
|
+
/** Passes in the schedule run where `applyStateTransitions(...)` changed the machine. */
|
|
792
|
+
stateChanged: <M extends Machine.StateMachine.Any>(machine: M & Machine.SameGame<M, Root>) => Machine.StateChangedCondition<M>
|
|
571
793
|
not: typeof Machine.not
|
|
572
794
|
and: typeof Machine.and
|
|
573
795
|
or: typeof Machine.or
|
|
@@ -594,6 +816,7 @@ export namespace Schema {
|
|
|
594
816
|
): BoundSystem<S, Root, System.SystemSpec<S, Access, Root>, E, Name, System.SystemAccessNeeds<Access>>
|
|
595
817
|
readResource: <D extends ResourceDescriptor<S>>(descriptor: D) => System.ResourceRead<D>
|
|
596
818
|
writeResource: <D extends ResourceDescriptor<S>>(descriptor: D) => System.ResourceWrite<D>
|
|
819
|
+
changedResource: <D extends ResourceDescriptor<S>>(descriptor: D) => System.ResourceChanged<D>
|
|
597
820
|
readEvent: <D extends EventDescriptor<S>>(descriptor: D) => System.EventRead<D>
|
|
598
821
|
writeEvent: <D extends EventDescriptor<S>>(descriptor: D) => System.EventWrite<D>
|
|
599
822
|
/**
|
|
@@ -601,7 +824,7 @@ export namespace Schema {
|
|
|
601
824
|
* same `runtime.tick(...)` call; checked at compile time by `tick`.
|
|
602
825
|
* Accepts `readEvent(...)`, `readResource(...)`, or a query.
|
|
603
826
|
*/
|
|
604
|
-
thisTick: <Read extends System.EventRead<EventDescriptor<S>> | System.ResourceRead<ResourceDescriptor<S>> | Query.Any<Root>>(
|
|
827
|
+
thisTick: <Read extends System.EventRead<EventDescriptor<S>> | System.ResourceRead<ResourceDescriptor<S>> | System.ResourceChanged<ResourceDescriptor<S>> | Query.Any<Root>>(
|
|
605
828
|
read: Read
|
|
606
829
|
) => Read & System.ThisTick
|
|
607
830
|
service: typeof System.service
|
|
@@ -617,18 +840,21 @@ export namespace Schema {
|
|
|
617
840
|
* `Game.System.commands(Game.System.spawns(Enemy, Position), Game.System.despawns(Enemy))`.
|
|
618
841
|
*/
|
|
619
842
|
commands: typeof Command.commands
|
|
620
|
-
/** Allows spawning drafts whose components are all among these; see `Command.spawns`. */
|
|
621
|
-
spawns: <const Components extends
|
|
843
|
+
/** Allows spawning drafts whose components are all among these and what they require (`Schema.requires`); see `Command.spawns`. */
|
|
844
|
+
spawns: <const Components extends NonEmpty<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"spawns", Components[number] | Command.RequiredDescriptors<S, Components[number]["name"]>>
|
|
622
845
|
/** Allows `insert` (add or replace at the next `applyDeferred()`) of these; see `Command.inserts`. */
|
|
623
|
-
inserts: <const Components extends
|
|
846
|
+
inserts: <const Components extends NonEmpty<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"inserts", Components[number]>
|
|
624
847
|
/** Allows `remove` of these. */
|
|
625
|
-
removes: <const Components extends
|
|
848
|
+
removes: <const Components extends NonEmpty<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"removes", Components[number]>
|
|
626
849
|
/** Allows `despawn` of entities a query proves have one of these; see `Command.despawns`. */
|
|
627
|
-
despawns: <const Components extends
|
|
850
|
+
despawns: <const Components extends NonEmpty<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"despawns", Components[number]>
|
|
628
851
|
/** Allows `despawnScope` of this scope. */
|
|
629
852
|
despawnsScope: <const Scope extends EntityScope.EntityScope<string, Root>>(scope: Scope) => Command.Permission<"despawnsScope", Scope>
|
|
630
|
-
/**
|
|
631
|
-
|
|
853
|
+
/**
|
|
854
|
+
* Allows `relate`, `unrelate`, and `reorderChildren` of these relations,
|
|
855
|
+
* and spawning drafts that stage them with `Game.Command.relate(...)`.
|
|
856
|
+
*/
|
|
857
|
+
relates: <const Relations extends NonEmpty<RelationDescriptor<S>>>(...relations: Relations) => Command.Permission<"relates", Relations[number]>
|
|
632
858
|
}
|
|
633
859
|
readonly Schedule: {
|
|
634
860
|
/**
|
|
@@ -646,20 +872,31 @@ export namespace Schema {
|
|
|
646
872
|
state: Machine.StateMachine.Value<M>,
|
|
647
873
|
plan: readonly [...Entries]
|
|
648
874
|
) => BoundTransitionScheduleResult<S, Root, M, Entries>
|
|
875
|
+
/**
|
|
876
|
+
* Systems run when `machine` leaves `state`. The exit phase of one
|
|
877
|
+
* transition (the exit schedules of the sub-states it ends, then of
|
|
878
|
+
* `state`, then `onTransition`) is one transaction: when a system in it
|
|
879
|
+
* fails, everything the phase did is undone (except `local`) and the
|
|
880
|
+
* transition stays queued, so the next attempt starts from the same
|
|
881
|
+
* state. Its commands are applied at the next `applyDeferred()` after
|
|
882
|
+
* the marker, so it cannot contain `applyDeferred()` itself.
|
|
883
|
+
*/
|
|
649
884
|
onExit: <M extends BoundStateMachine<Root>, const Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>>(
|
|
650
885
|
machine: M,
|
|
651
886
|
state: Machine.StateMachine.Value<M>,
|
|
652
|
-
plan: readonly [...Entries]
|
|
887
|
+
plan: readonly [...Entries] & NoApplyDeferredInExit<Entries>
|
|
653
888
|
) => BoundTransitionScheduleResult<S, Root, M, Entries>
|
|
889
|
+
/** Systems run on one `[from, to]` transition, last in its exit phase (see `onExit`). */
|
|
654
890
|
onTransition: <M extends BoundStateMachine<Root>, const Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>>(
|
|
655
891
|
machine: M,
|
|
656
892
|
transition: readonly [Machine.StateMachine.Value<M>, Machine.StateMachine.Value<M>],
|
|
657
|
-
plan: readonly [...Entries]
|
|
893
|
+
plan: readonly [...Entries] & NoApplyDeferredInExit<Entries>
|
|
658
894
|
) => BoundTransitionScheduleResult<S, Root, M, Entries>
|
|
659
895
|
/**
|
|
660
896
|
* Builds a schedule whose systems run only while every condition
|
|
661
897
|
* passes (in addition to their own `when`). Nested schedules are
|
|
662
|
-
* gated too; marker steps still run
|
|
898
|
+
* gated too; marker steps still run, and so do the transition schedules
|
|
899
|
+
* an `applyStateTransitions(bundle)` in the group runs. Gated systems drop the events
|
|
663
900
|
* published while gated; use `pauseWhen` to keep them. For one system,
|
|
664
901
|
* use `when` in its spec.
|
|
665
902
|
*/
|
|
@@ -691,8 +928,9 @@ export namespace Schema {
|
|
|
691
928
|
}
|
|
692
929
|
readonly Runtime: {
|
|
693
930
|
/**
|
|
694
|
-
* Builds a runtime.
|
|
695
|
-
*
|
|
931
|
+
* Builds a runtime. Always returns a `Result`: a `Success` (read
|
|
932
|
+
* `.value`) when nothing provided can fail, and a `Result` to check
|
|
933
|
+
* when a provided resource goes through a constructed descriptor.
|
|
696
934
|
*/
|
|
697
935
|
make: <
|
|
698
936
|
const ProvidedServices extends Runtime.RuntimeServices<any>,
|
|
@@ -701,10 +939,12 @@ export namespace Schema {
|
|
|
701
939
|
const Enabled extends Debug.Option | undefined = undefined
|
|
702
940
|
>(options: {
|
|
703
941
|
readonly services: ProvidedServices
|
|
704
|
-
readonly resources?: Resources
|
|
942
|
+
readonly resources?: Resources & Runtime.ExactResources<S, Resources>
|
|
705
943
|
readonly machines?: ProvidedMachines
|
|
706
944
|
/** Attaches a `debug` handle to the runtime; see the `Debug` module. */
|
|
707
945
|
readonly debug?: Enabled
|
|
946
|
+
/** The game's save migrations (`Snapshot.migrations`): `restore` upgrades older saves with them. */
|
|
947
|
+
readonly saves?: Snapshot.Migrations
|
|
708
948
|
}) => Runtime.MakeRuntimeResult<S, RuntimeServicesOf<ProvidedServices>, Resources, Root, RuntimeMachinesOf<ProvidedMachines>, Enabled>
|
|
709
949
|
service: typeof Runtime.service
|
|
710
950
|
services: typeof Runtime.services
|