@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.
Files changed (141) hide show
  1. package/README.md +3 -2
  2. package/dist/Clock.d.ts +19 -4
  3. package/dist/Clock.d.ts.map +1 -1
  4. package/dist/Clock.js +18 -2
  5. package/dist/Clock.js.map +1 -1
  6. package/dist/Command.d.ts +181 -40
  7. package/dist/Command.d.ts.map +1 -1
  8. package/dist/Command.js +31 -11
  9. package/dist/Command.js.map +1 -1
  10. package/dist/Condition.d.ts +12 -1
  11. package/dist/Condition.d.ts.map +1 -1
  12. package/dist/Condition.js.map +1 -1
  13. package/dist/Debug.d.ts +127 -13
  14. package/dist/Debug.d.ts.map +1 -1
  15. package/dist/Descriptor.d.ts +61 -10
  16. package/dist/Descriptor.d.ts.map +1 -1
  17. package/dist/Descriptor.js +22 -10
  18. package/dist/Descriptor.js.map +1 -1
  19. package/dist/Entity.d.ts +22 -7
  20. package/dist/Entity.d.ts.map +1 -1
  21. package/dist/Entity.js.map +1 -1
  22. package/dist/EntityScope.d.ts +20 -1
  23. package/dist/EntityScope.d.ts.map +1 -1
  24. package/dist/EntityScope.js +8 -2
  25. package/dist/EntityScope.js.map +1 -1
  26. package/dist/FixedLoop.d.ts +106 -0
  27. package/dist/FixedLoop.d.ts.map +1 -0
  28. package/dist/FixedLoop.js +97 -0
  29. package/dist/FixedLoop.js.map +1 -0
  30. package/dist/HostClock.d.ts +1 -1
  31. package/dist/HostClock.d.ts.map +1 -1
  32. package/dist/HostClock.js +2 -1
  33. package/dist/HostClock.js.map +1 -1
  34. package/dist/Machine.d.ts +59 -34
  35. package/dist/Machine.d.ts.map +1 -1
  36. package/dist/Machine.js +10 -3
  37. package/dist/Machine.js.map +1 -1
  38. package/dist/Query.d.ts +100 -14
  39. package/dist/Query.d.ts.map +1 -1
  40. package/dist/Query.js +34 -5
  41. package/dist/Query.js.map +1 -1
  42. package/dist/Relation.d.ts +5 -14
  43. package/dist/Relation.d.ts.map +1 -1
  44. package/dist/Relation.js +0 -32
  45. package/dist/Relation.js.map +1 -1
  46. package/dist/Runtime.d.ts +61 -15
  47. package/dist/Runtime.d.ts.map +1 -1
  48. package/dist/Runtime.js +594 -70
  49. package/dist/Runtime.js.map +1 -1
  50. package/dist/Schedule.d.ts +24 -15
  51. package/dist/Schedule.d.ts.map +1 -1
  52. package/dist/Schedule.js +2 -1
  53. package/dist/Schedule.js.map +1 -1
  54. package/dist/Schema.d.ts +233 -48
  55. package/dist/Schema.d.ts.map +1 -1
  56. package/dist/Schema.js +33 -7
  57. package/dist/Schema.js.map +1 -1
  58. package/dist/Snapshot.d.ts +90 -1
  59. package/dist/Snapshot.d.ts.map +1 -1
  60. package/dist/Snapshot.js +42 -1
  61. package/dist/Snapshot.js.map +1 -1
  62. package/dist/System.d.ts +132 -31
  63. package/dist/System.d.ts.map +1 -1
  64. package/dist/System.js +32 -0
  65. package/dist/System.js.map +1 -1
  66. package/dist/index.d.ts +4 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +4 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/internal/cells.d.ts +2 -0
  71. package/dist/internal/cells.d.ts.map +1 -1
  72. package/dist/internal/cells.js +34 -8
  73. package/dist/internal/cells.js.map +1 -1
  74. package/dist/internal/debug.d.ts +10 -0
  75. package/dist/internal/debug.d.ts.map +1 -1
  76. package/dist/internal/debug.js +171 -12
  77. package/dist/internal/debug.js.map +1 -1
  78. package/dist/internal/equal.d.ts +8 -0
  79. package/dist/internal/equal.d.ts.map +1 -0
  80. package/dist/internal/equal.js +38 -0
  81. package/dist/internal/equal.js.map +1 -0
  82. package/dist/internal/fragments.d.ts +2 -6
  83. package/dist/internal/fragments.d.ts.map +1 -1
  84. package/dist/internal/fragments.js +36 -3
  85. package/dist/internal/fragments.js.map +1 -1
  86. package/dist/internal/game.d.ts +2 -0
  87. package/dist/internal/game.d.ts.map +1 -1
  88. package/dist/internal/game.js +48 -7
  89. package/dist/internal/game.js.map +1 -1
  90. package/dist/internal/order.d.ts.map +1 -1
  91. package/dist/internal/order.js +4 -2
  92. package/dist/internal/order.js.map +1 -1
  93. package/dist/internal/queries.d.ts.map +1 -1
  94. package/dist/internal/queries.js +57 -26
  95. package/dist/internal/queries.js.map +1 -1
  96. package/dist/internal/relations.d.ts +10 -0
  97. package/dist/internal/relations.d.ts.map +1 -0
  98. package/dist/internal/relations.js +32 -0
  99. package/dist/internal/relations.js.map +1 -0
  100. package/dist/internal/requirements.d.ts +26 -0
  101. package/dist/internal/requirements.d.ts.map +1 -0
  102. package/dist/internal/requirements.js +46 -0
  103. package/dist/internal/requirements.js.map +1 -0
  104. package/dist/internal/streams.d.ts +2 -0
  105. package/dist/internal/streams.d.ts.map +1 -1
  106. package/dist/internal/streams.js +10 -0
  107. package/dist/internal/streams.js.map +1 -1
  108. package/dist/internal/world.d.ts +7 -1
  109. package/dist/internal/world.d.ts.map +1 -1
  110. package/dist/internal/world.js +53 -3
  111. package/dist/internal/world.js.map +1 -1
  112. package/package.json +1 -1
  113. package/src/Clock.ts +29 -4
  114. package/src/Command.ts +281 -67
  115. package/src/Condition.ts +17 -1
  116. package/src/Debug.ts +124 -15
  117. package/src/Descriptor.ts +92 -21
  118. package/src/Entity.ts +23 -7
  119. package/src/EntityScope.ts +21 -2
  120. package/src/FixedLoop.ts +218 -0
  121. package/src/HostClock.ts +2 -1
  122. package/src/Machine.ts +72 -35
  123. package/src/Query.ts +118 -17
  124. package/src/Relation.ts +5 -67
  125. package/src/Runtime.ts +659 -85
  126. package/src/Schedule.ts +31 -19
  127. package/src/Schema.ts +297 -57
  128. package/src/Snapshot.ts +94 -2
  129. package/src/System.ts +151 -29
  130. package/src/index.ts +4 -0
  131. package/src/internal/cells.ts +42 -10
  132. package/src/internal/debug.ts +179 -14
  133. package/src/internal/equal.ts +31 -0
  134. package/src/internal/fragments.ts +35 -5
  135. package/src/internal/game.ts +69 -7
  136. package/src/internal/order.ts +8 -4
  137. package/src/internal/queries.ts +62 -12
  138. package/src/internal/relations.ts +52 -0
  139. package/src/internal/requirements.ts +71 -0
  140. package/src/internal/streams.ts +11 -0
  141. package/src/internal/world.ts +60 -4
package/dist/Schema.d.ts CHANGED
@@ -53,6 +53,7 @@ import type * as Command from "./Command.ts";
53
53
  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
+ import { type exitApplyDeferredMessage } from "./internal/game.ts";
56
57
  import type * as Condition from "./Condition.ts";
57
58
  import type * as Inspector from "./Inspector.ts";
58
59
  import type * as Machine from "./Machine.ts";
@@ -64,21 +65,89 @@ import type * as Result from "./Result.ts";
64
65
  import type * as Debug from "./Debug.ts";
65
66
  import type * as Runtime from "./Runtime.ts";
66
67
  import type * as Schedule from "./Schedule.ts";
68
+ import type * as Snapshot from "./Snapshot.ts";
67
69
  import type * as System from "./System.ts";
68
70
  /**
69
71
  * A mapping from schema keys to nominal descriptors.
70
72
  */
71
73
  export type Registry = Record<string, Descriptor.Any>;
74
+ /** At least one: a permission that names nothing allows nothing. */
75
+ type NonEmpty<T> = readonly [T, ...ReadonlyArray<T>];
76
+ type Article<Kind extends string> = Kind extends "event" ? "an" : "a";
77
+ /**
78
+ * Rejects descriptors of another kind in a fragment's `components`,
79
+ * `resources`, or `events`, naming where each belongs.
80
+ */
81
+ type RegistryOfKind<R, Expected extends string> = {
82
+ readonly [K in keyof R]: R[K] extends {
83
+ readonly kind: Expected;
84
+ } ? unknown : R[K] extends {
85
+ readonly kind: infer Actual extends string;
86
+ } ? {
87
+ readonly __fixSchema__: Actual extends "service" ? `${K & string} is a service, not ${Article<Expected>} ${Expected}: provide services to Game.Runtime.make({ services }) instead of registering them` : `${K & string} is ${Article<Actual>} ${Actual}, not ${Article<Expected>} ${Expected}: move it to ${Actual}s: { ... }`;
88
+ } : unknown;
89
+ };
72
90
  /**
73
91
  * A closed schema: the components, resources, events, and relations a world
74
- * may contain.
92
+ * may contain, and the component requirements (`Schema.requires`) every
93
+ * entity of it keeps.
75
94
  */
76
- export interface SchemaDefinition<out Components extends Registry = {}, out Resources extends Registry = {}, out Events extends Registry = {}, out Relations extends Record<string, Relation.Relation.Any> = {}> {
95
+ export interface SchemaDefinition<out Components extends Registry = {}, out Resources extends Registry = {}, out Events extends Registry = {}, out Relations extends Record<string, Relation.Relation.Any> = {}, out Requires extends RequirementPair = never> {
77
96
  readonly components: Components;
78
97
  readonly resources: Resources;
79
98
  readonly events: Events;
80
99
  readonly relations: Relations;
100
+ /** Component requirements declared with `Schema.requires(...)`. */
101
+ readonly requires: ReadonlyArray<ComponentRequirement<Requires>>;
102
+ }
103
+ /**
104
+ * One requirement carried in a schema type, by component name:
105
+ * `[requirer, required]`. One pair per required component, so lookups by
106
+ * either end stay exact.
107
+ */
108
+ export type RequirementPair = readonly [string, string];
109
+ /**
110
+ * One `Schema.requires(...)` declaration: every entity holding `component`
111
+ * also holds each of `required`.
112
+ */
113
+ export interface ComponentRequirement<out Pairs extends RequirementPair = RequirementPair> {
114
+ readonly kind: "requires";
115
+ readonly component: Descriptor<"component", string, any>;
116
+ readonly required: ReadonlyArray<Descriptor<"component", string, any>>;
117
+ readonly __pairs?: (_: never) => Pairs;
81
118
  }
119
+ type AnyComponentDescriptor = Descriptor<"component", string, any>;
120
+ /** One `[from, to]` pair per required name. */
121
+ type RequirementPairs<From extends string, To extends string> = To extends string ? readonly [From, To] : never;
122
+ type PairsOf<R> = R extends ComponentRequirement<infer Pairs> ? Pairs : never;
123
+ /**
124
+ * Declares that every entity holding `component` also holds each of
125
+ * `required`. List it in a fragment's `requires`.
126
+ *
127
+ * The compiler then rejects every command that would break it:
128
+ * `commands.spawn` / `spawnIn` of a draft missing a required entry,
129
+ * `commands.insert` of `component` on an entity not proven to hold the
130
+ * rest, and `commands.remove` of a required component while a requirer may
131
+ * stay. `Game.System.spawns(component)` also allows spawning what it
132
+ * requires. Nothing is ever filled in with a default: the draft must carry
133
+ * every value.
134
+ *
135
+ * Requirements chain (`A` requires `B`, `B` requires `C`) and may name
136
+ * components of other fragments of the same `Schema.bind`.
137
+ *
138
+ * A saved component cannot require a transient one (`Schema.bind` rejects
139
+ * it): a restore would bring the requirer back without it. A transient
140
+ * requirer may require a transient component.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * const Gameplay = Schema.fragment({
145
+ * components: { Player, Position, Velocity },
146
+ * requires: [Schema.requires(Player, Position, Velocity)]
147
+ * })
148
+ * ```
149
+ */
150
+ export declare const requires: <D extends AnyComponentDescriptor, const Required extends readonly [AnyComponentDescriptor, ...Array<AnyComponentDescriptor>]>(component: D, ...required: Required) => ComponentRequirement<RequirementPairs<D["name"], Required[number]["name"]>>;
82
151
  declare const schemaRootTypeId: "~ritmo/SchemaRoot";
83
152
  export type RootToken<Name extends string = string> = {
84
153
  readonly kind: "SchemaRoot";
@@ -87,7 +156,7 @@ export type RootToken<Name extends string = string> = {
87
156
  readonly _Name: (_: never) => Name;
88
157
  };
89
158
  };
90
- export type MergeSchemaDefinitions<A extends Schema.Any, B extends Schema.Any> = SchemaDefinition<Schema.Components<A> & Schema.Components<B>, Schema.Resources<A> & Schema.Resources<B>, Schema.Events<A> & Schema.Events<B>, Schema.Relations<A> & Schema.Relations<B>>;
159
+ export type MergeSchemaDefinitions<A extends Schema.Any, B extends Schema.Any> = SchemaDefinition<Schema.Components<A> & Schema.Components<B>, Schema.Resources<A> & Schema.Resources<B>, Schema.Events<A> & Schema.Events<B>, Schema.Relations<A> & Schema.Relations<B>, Schema.Requires<A> | Schema.Requires<B>>;
91
160
  /**
92
161
  * Type-level fold for fragment composition.
93
162
  */
@@ -135,6 +204,24 @@ export type ValidateFragments<Fragments extends ReadonlyArray<Schema.Any>> = [
135
204
  ] extends [never] ? unknown : {
136
205
  readonly __schemaConflicts__: FragmentConflicts<Fragments>;
137
206
  };
207
+ type UnregisteredRequirements<S extends Schema.Any> = Exclude<Schema.Requires<S>[0] | Schema.Requires<S>[1], Schema.ComponentDescriptor<S>["name"]>;
208
+ type TransientComponentName<S extends Schema.Any> = Extract<Schema.ComponentDescriptor<S>, {
209
+ readonly transient: true;
210
+ }>["name"];
211
+ /** One message per saved requirer that requires a transient component. */
212
+ type TransientRequirements<S extends Schema.Any, Pairs = Schema.Requires<S>> = Pairs extends readonly [infer From extends string, infer To extends string] ? To extends TransientComponentName<S> ? From extends TransientComponentName<S> ? never : `${From} requires ${To}, which is transient and not saved: make ${From} transient too, or give ${To} a constructor` : never : never;
213
+ /**
214
+ * Rejects requirements naming a component the bound schema does not
215
+ * register. Checked at `bind`, so a fragment may require a component another
216
+ * fragment registers. Also rejects a saved component requiring a transient
217
+ * one (a restore would bring the requirer back without it). Erased schemas
218
+ * (`Schema.Any`) are checked by `bind` at runtime instead.
219
+ */
220
+ export type ValidateRequires<S extends Schema.Any> = string extends Schema.Requires<S>[1] ? unknown : [UnregisteredRequirements<S>] extends [never] ? [TransientRequirements<S>] extends [never] ? unknown : {
221
+ readonly __schemaRequires__: TransientRequirements<S>;
222
+ } : {
223
+ readonly __schemaRequires__: `${UnregisteredRequirements<S>} is named in Schema.requires(...) but no fragment registers it: add it to a fragment's components`;
224
+ };
138
225
  /**
139
226
  * Creates one explicit root token for schema-bound long-lived references.
140
227
  *
@@ -151,10 +238,6 @@ export type ValidateFragments<Fragments extends ReadonlyArray<Schema.Any>> = [
151
238
  * ```
152
239
  */
153
240
  export declare const defineRoot: <const Name extends string>(name: Name) => RootToken<Name>;
154
- /**
155
- * Creates an empty schema.
156
- */
157
- export declare const empty: () => SchemaDefinition;
158
241
  /**
159
242
  * Creates a schema fragment.
160
243
  *
@@ -165,17 +248,19 @@ export declare const empty: () => SchemaDefinition;
165
248
  * @example
166
249
  * ```ts
167
250
  * const Combat = Schema.fragment({
168
- * components: { Health, Damage },
169
- * events: { Hit }
251
+ * components: { Health, Damage, Enemy },
252
+ * events: { Hit },
253
+ * requires: [Schema.requires(Enemy, Health)]
170
254
  * })
171
255
  * ```
172
256
  */
173
- export declare const fragment: <const Components extends Registry = {}, const Resources extends Registry = {}, const Events extends Registry = {}, const Relations extends Record<string, Relation.Relation.Any> = {}>(definition: {
174
- readonly components?: Components;
175
- readonly resources?: Resources;
176
- readonly events?: Events;
257
+ export declare const fragment: <const Components extends Registry = {}, const Resources extends Registry = {}, const Events extends Registry = {}, const Relations extends Record<string, Relation.Relation.Any> = {}, const Requires extends ReadonlyArray<ComponentRequirement> = readonly []>(definition: {
258
+ readonly components?: Components & RegistryOfKind<Components, "component">;
259
+ readonly resources?: Resources & RegistryOfKind<Resources, "resource">;
260
+ readonly events?: Events & RegistryOfKind<Events, "event">;
177
261
  readonly relations?: Relations;
178
- } & ValidateFragments<[SchemaDefinition<Components, Resources, Events, Relations>]>) => SchemaDefinition<Components, Resources, Events, Relations>;
262
+ readonly requires?: Requires;
263
+ } & ValidateFragments<[SchemaDefinition<Components, Resources, Events, Relations>]>) => SchemaDefinition<Components, Resources, Events, Relations, PairsOf<Requires[number]>>;
179
264
  /**
180
265
  * Composes one or more fragments and returns one bound `Game` surface.
181
266
  *
@@ -189,10 +274,10 @@ export declare const fragment: <const Components extends Registry = {}, const Re
189
274
  * const Game = Schema.bind(Core, Combat, Root)
190
275
  * ```
191
276
  */
192
- export declare function bind<S extends Schema.Any>(schema: S & ValidateFragments<[S]>): Schema.Game<S, S>;
193
- export declare function bind<S extends Schema.Any, const Name extends string>(schema: S & ValidateFragments<[S]>, root: RootToken<Name>): Schema.Game<S, RootToken<Name>>;
194
- export declare function bind<const Fragments extends readonly [Schema.Any, Schema.Any, ...Array<Schema.Any>]>(...fragments: Fragments & ValidateFragments<Fragments>): Schema.Game<BuildFragments<Fragments>, BuildFragments<Fragments>>;
195
- export declare function bind<const Fragments extends readonly [Schema.Any, Schema.Any, ...Array<Schema.Any>], const Name extends string>(...args: [...Fragments, RootToken<Name>] & ValidateFragments<Fragments>): Schema.Game<BuildFragments<Fragments>, RootToken<Name>>;
277
+ export declare function bind<S extends Schema.Any>(schema: S & ValidateFragments<[S]> & ValidateRequires<S>): Schema.Game<S, S>;
278
+ export declare function bind<S extends Schema.Any, const Name extends string>(schema: S & ValidateFragments<[S]> & ValidateRequires<S>, root: RootToken<Name>): Schema.Game<S, RootToken<Name>>;
279
+ export declare function bind<const Fragments extends readonly [Schema.Any, Schema.Any, ...Array<Schema.Any>]>(...fragments: Fragments & ValidateFragments<Fragments> & ValidateRequires<BuildFragments<Fragments>>): Schema.Game<BuildFragments<Fragments>, BuildFragments<Fragments>>;
280
+ export declare function bind<const Fragments extends readonly [Schema.Any, Schema.Any, ...Array<Schema.Any>], const Name extends string>(...args: [...Fragments, RootToken<Name>] & ValidateFragments<Fragments> & ValidateRequires<BuildFragments<Fragments>>): Schema.Game<BuildFragments<Fragments>, RootToken<Name>>;
196
281
  type RuntimeServicesOf<Provided extends Runtime.RuntimeServices<any>> = [
197
282
  Provided
198
283
  ] extends [Runtime.RuntimeServices<infer Services>] ? Services : never;
@@ -206,7 +291,7 @@ type RelationDescriptor<S extends Schema.Any> = Schema.RelationDescriptor<S>;
206
291
  type QuerySelectionAccess<S extends Schema.Any, Root> = QueryModule.Access<ComponentDescriptor<S>> | Relation.SelectionAccess<S, Root>;
207
292
  interface BoundSystemAccess<S extends Schema.Any, Root> extends System.SystemAccessInput {
208
293
  readonly queries?: Record<string, Query.Any<Root>>;
209
- readonly resources?: Record<string, System.ResourceRead<ResourceDescriptor<S>> | System.ResourceWrite<ResourceDescriptor<S>>>;
294
+ readonly resources?: Record<string, System.ResourceRead<ResourceDescriptor<S>> | System.ResourceChanged<ResourceDescriptor<S>> | System.ResourceWrite<ResourceDescriptor<S>>>;
210
295
  readonly events?: Record<string, System.EventRead<EventDescriptor<S>> | System.EventWrite<EventDescriptor<S>>>;
211
296
  readonly machines?: Record<string, Machine.MachineRead<Schema.BoundStateMachine<Root>>>;
212
297
  readonly nextMachines?: Record<string, Machine.NextMachineWrite<Schema.BoundStateMachine<Root>>>;
@@ -221,7 +306,7 @@ interface BoundSystemAccess<S extends Schema.Any, Root> extends System.SystemAcc
221
306
  }
222
307
  interface BoundCheckAccess<S extends Schema.Any, Root> extends Condition.CheckAccessInput {
223
308
  readonly queries?: Record<string, Query.Any<Root>>;
224
- readonly resources?: Record<string, System.ResourceRead<ResourceDescriptor<S>>>;
309
+ readonly resources?: Record<string, System.ResourceRead<ResourceDescriptor<S>> | System.ResourceChanged<ResourceDescriptor<S>> | System.ResourceWrite<ResourceDescriptor<S>>>;
225
310
  readonly machines?: Record<string, Machine.MachineRead<Schema.BoundStateMachine<Root>>>;
226
311
  }
227
312
  interface BoundInspectorAccess<S extends Schema.Any, Root> extends Inspector.InspectorAccessInput {
@@ -235,7 +320,17 @@ interface BoundInspectorAccess<S extends Schema.Any, Root> extends Inspector.Ins
235
320
  }
236
321
  type BoundScheduleEntry<S extends Schema.Any, Root> = Schema.BoundSystem<S, Root, any, any> | Schedule.ApplyDeferredStep | Schedule.ApplyStateTransitionsStep<any, Root> | Schedule.ScheduleDefinition<S, any, Root, any, any, Schedule.AnyScheduleOrder>;
237
322
  type BoundTransitionEntry<S extends Schema.Any, Root> = Exclude<BoundScheduleEntry<S, Root>, Schedule.ApplyStateTransitionsStep<any, Root>>;
238
- type BoundTransitionScheduleResult<S extends Schema.Any, Root, M extends Schema.BoundStateMachine<Root>, Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>> = Machine.TransitionScheduleDefinition<S, M, Schedule.CompositionExactRequirements<Entries>, Root, Schedule.CompositionFailure<Entries>, Schedule.CompositionOrder<Entries>>;
323
+ /**
324
+ * Rejects `applyDeferred()` in an exit phase (`onExit`, `onTransition`): the
325
+ * phase rolls back as one when a system in it fails, which applied commands
326
+ * could not. Nested schedules are checked when the schedule is built.
327
+ */
328
+ type NoApplyDeferredInExit<Entries extends ReadonlyArray<unknown>> = [
329
+ Extract<Entries[number], Schedule.ApplyDeferredStep>
330
+ ] extends [never] ? unknown : {
331
+ readonly __fixTransition__: typeof exitApplyDeferredMessage;
332
+ };
333
+ type BoundTransitionScheduleResult<S extends Schema.Any, Root, M extends Schema.BoundStateMachine<Root>, Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>> = Machine.TransitionScheduleDefinition<S, M, Schedule.CompositionExactRequirements<Entries> | M, Root, Schedule.CompositionFailure<Entries>, Schedule.CompositionOrder<Entries>>;
239
334
  type BoundTransitionBundleInput<S extends Schema.Any, Root> = Schema.BoundTransitionSchedule<S, Root, any, any, any> | Schema.BoundTransitionBundle<S, Root, any, any, any>;
240
335
  type BoundTransitionBundleResult<S extends Schema.Any, Root, Entries extends ReadonlyArray<BoundTransitionBundleInput<S, Root>>> = Schedule.TransitionBundleDefinition<S, ReadonlyArray<Schedule.FlattenTransitionEntries<Entries>[number]>, Schedule.TransitionBundleRequirements<Schedule.FlattenTransitionEntries<Entries>>, Root, Schedule.TransitionBundleRequirements<Schedule.FlattenTransitionEntries<Entries>>, Schedule.TransitionBundleFailure<Schedule.FlattenTransitionEntries<Entries>>, Schedule.CompositionOrder<Entries>>;
241
336
  /**
@@ -245,11 +340,13 @@ export declare namespace Schema {
245
340
  /**
246
341
  * Any complete schema definition.
247
342
  */
248
- type Any = SchemaDefinition<Registry, Registry, Registry, Record<string, Relation.Relation.Any>>;
343
+ type Any = SchemaDefinition<Registry, Registry, Registry, Record<string, Relation.Relation.Any>, RequirementPair>;
249
344
  type Components<T extends Any> = T["components"];
250
345
  type Resources<T extends Any> = T["resources"];
251
346
  type Events<T extends Any> = T["events"];
252
347
  type Relations<T extends Any> = T["relations"];
348
+ /** The component requirements of a schema, as `[requirer, required]` name pairs (`Schema.requires`). */
349
+ type Requires<T extends Any> = T extends SchemaDefinition<any, any, any, any, infer Pairs> ? Pairs : never;
253
350
  type ComponentValue<T extends Any, K extends keyof Components<T>> = Descriptor.Value<Components<T>[K]>;
254
351
  type ResourceValue<T extends Any, K extends keyof Resources<T>> = Descriptor.Value<Resources<T>[K]>;
255
352
  type EventValue<T extends Any, K extends keyof Events<T>> = Descriptor.Value<Events<T>[K]>;
@@ -278,7 +375,7 @@ export declare namespace Schema {
278
375
  /**
279
376
  * A schema-bound finite-state machine.
280
377
  */
281
- type BoundStateMachine<Root, Name extends string = string, Values extends readonly [Machine.StateValue, ...Machine.StateValue[]] = readonly [Machine.StateValue, ...Machine.StateValue[]]> = Machine.StateMachineDefinition<Name, Values, Root>;
378
+ type BoundStateMachine<Root, Name extends string = string, Values extends readonly [Machine.StateValue, ...Machine.StateValue[]] = readonly [Machine.StateValue, ...Machine.StateValue[]], Parent = unknown> = Machine.StateMachineDefinition<Name, Values, Root, Parent>;
282
379
  type BoundTransitionSchedule<S extends Any, Root, M extends BoundStateMachine<Root> = BoundStateMachine<Root>, Needs extends Requirement.Requirement = Requirement.Requirement, Failure extends System.SystemFailure = never, Order extends Schedule.AnyScheduleOrder = Schedule.AnyScheduleOrder> = Machine.TransitionScheduleDefinition<S, M, Needs, Root, Failure, Order>;
283
380
  type BoundTransitionBundle<S extends Any, Root, Entries extends ReadonlyArray<BoundTransitionSchedule<S, Root, any, any, any>> = ReadonlyArray<BoundTransitionSchedule<S, Root, any, any, any>>, Needs extends Requirement.Requirement = Requirement.Requirement, Failure extends System.SystemFailure = never, Order extends Schedule.AnyScheduleOrder = Schedule.AnyScheduleOrder> = Schedule.TransitionBundleDefinition<S, Entries, Needs, Root, Needs, Failure, Order>;
284
381
  /**
@@ -292,11 +389,31 @@ export declare namespace Schema {
292
389
  readonly schema: S;
293
390
  /**
294
391
  * Creates a typed ownership scope for scene or level entities: a flat
295
- * group despawned together with `commands.despawnScope(...)`. Use
296
- * `Descriptor.Hierarchy` instead for a parent-child tree with ordered
297
- * children, traversal, and recursive despawn.
392
+ * group whose members are spawned with `commands.spawnIn(...)` and
393
+ * despawned together. Use `Descriptor.Hierarchy` instead for a
394
+ * parent-child tree with ordered children, traversal, and recursive
395
+ * despawn.
396
+ *
397
+ * When the group lives exactly as long as a state, name the state change
398
+ * that ends it: `despawnOnExit: [Flow, "Playing"]` despawns every member
399
+ * when `applyStateTransitions(...)` commits leaving `Playing` (after its
400
+ * `onExit` schedules, which still see the members), and
401
+ * `despawnOnEnter: [Flow, "Playing"]` when it commits entering it (before
402
+ * its `onEnter` schedules, so what they spawn survives). Use
403
+ * `commands.despawnScope(...)` instead when the wipe is not tied to a
404
+ * state change. Scope names are unique per game.
405
+ *
406
+ * @example
407
+ * ```ts
408
+ * const RunScope = Game.EntityScope("Shooter/Run", { despawnOnExit: [Flow, "Playing"] })
409
+ * ```
298
410
  */
299
- readonly EntityScope: <const Name extends string>(name: Name) => EntityScope.EntityScope<Name, Root>;
411
+ readonly EntityScope: <const Name extends string, Enter extends Machine.StateMachine.Any = never, Exit extends Machine.StateMachine.Any = never>(name: Name, options?: {
412
+ /** Despawns every member when the machine enters this state, before its `onEnter` schedules run. */
413
+ readonly despawnOnEnter?: readonly [Enter & Machine.SameGame<Enter, Root>, Machine.StateMachine.Value<Enter>];
414
+ /** Despawns every member when the machine leaves this state, after its `onExit` schedules run. */
415
+ readonly despawnOnExit?: readonly [Exit & Machine.SameGame<Exit, Root>, Machine.StateMachine.Value<Exit>];
416
+ }) => EntityScope.EntityScope<Name, Root>;
300
417
  /** Declares a reusable, requirement-checked read-only world projection. */
301
418
  readonly Inspector: <const Name extends string, const Access extends BoundInspectorAccess<S, Root>, Value>(name: Name, spec: Inspector.ExactInspectorAccess<Access>, read: (context: Inspector.InspectorContext<System.SystemSpec<S, Access, Root>>) => Value) => BoundInspector<S, Root, System.SystemSpec<S, Access, Root>, Value, Name, System.SystemAccessNeeds<Access>>;
302
419
  readonly Entity: {
@@ -305,12 +422,19 @@ export declare namespace Schema {
305
422
  * with an intent component that later resolution must prove.
306
423
  */
307
424
  handle: <const D extends ComponentDescriptor<S> | undefined = undefined>(target: Entity.HandleTarget<S, Root>, intent?: D) => Entity.Handle<Root, D>;
425
+ /**
426
+ * The entity id a handle names, to compare with ids or pass where an id
427
+ * is expected (`queries.x.get(id)`), instead of storing the id beside
428
+ * the handle. Like the handle, it proves nothing about liveness:
429
+ * resolve it through a query. Two handles of the same entity are `===`.
430
+ */
431
+ id: (handle: Entity.Handle<Root, ComponentDescriptor<S> | undefined>) => Entity.EntityId<S, Root>;
308
432
  };
309
433
  readonly Query: {
310
434
  <const Selection extends Record<string, QuerySelectionAccess<S, Root>>, const With extends ReadonlyArray<ComponentDescriptor<S>> = [], const Without extends ReadonlyArray<ComponentDescriptor<S>> = [], const Filters extends ReadonlyArray<QueryModule.Filter<ComponentDescriptor<S>>> = [], const WithRelations extends ReadonlyArray<RelationDescriptor<S>> = [], const WithoutRelations extends ReadonlyArray<RelationDescriptor<S>> = [], const WithRelated extends ReadonlyArray<RelationDescriptor<S>> = [], const WithoutRelated extends ReadonlyArray<RelationDescriptor<S>> = []>(spec: {
311
435
  readonly selection: Selection;
312
436
  readonly with?: With;
313
- readonly without?: Without;
437
+ readonly without?: Without & QueryModule.ExclusionsPossible<Selection, With, Without, Filters>;
314
438
  readonly filters?: Filters;
315
439
  readonly withRelations?: WithRelations;
316
440
  readonly withoutRelations?: WithoutRelations;
@@ -318,10 +442,15 @@ export declare namespace Schema {
318
442
  readonly withoutRelated?: WithoutRelated;
319
443
  }): 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>;
320
444
  read: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.ReadAccess<D>;
321
- write: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.WriteAccess<D>;
445
+ write: <D extends ComponentDescriptor<S>>(descriptor: D & QueryModule.Writable<D>) => QueryModule.WriteAccess<D>;
322
446
  optional: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.OptionalReadAccess<D>;
323
447
  added: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.AddedFilter<D>;
324
448
  changed: <D extends ComponentDescriptor<S>>(descriptor: D) => QueryModule.ChangedFilter<D>;
449
+ anyOf: <const Filters extends readonly [
450
+ QueryModule.LifecycleFilter<ComponentDescriptor<S>>,
451
+ QueryModule.LifecycleFilter<ComponentDescriptor<S>>,
452
+ ...ReadonlyArray<QueryModule.LifecycleFilter<ComponentDescriptor<S>>>
453
+ ]>(...filters: Filters) => QueryModule.AnyOfFilter<Filters[number]["descriptor"]>;
325
454
  readRelation: <R extends RelationDescriptor<S>>(descriptor: R) => Relation.RelationReadAccess<R, S, Root>;
326
455
  optionalRelation: <R extends RelationDescriptor<S>>(descriptor: R) => Relation.OptionalRelationReadAccess<R, S, Root>;
327
456
  readRelated: <R extends RelationDescriptor<S>>(descriptor: R) => Relation.RelatedReadAccess<R, S, Root>;
@@ -334,10 +463,15 @@ export declare namespace Schema {
334
463
  * Adds entries to a draft (a value not yet spawned). Use
335
464
  * `commands.insert` for an entity that already exists.
336
465
  */
337
- extend: <P extends Entity.ComponentProof, const Entries extends ReadonlyArray<Command.SpawnEntry<S>>>(draft: Entity.EntityDraft<S, P, Root>, ...entries: Entries) => Command.DraftFor<S, Entries, P, Root>;
338
- entry: <D extends ComponentDescriptor<S>>(descriptor: D, value: Descriptor.Value<D>) => Command.Entry<D>;
466
+ extend: <P extends Entity.ComponentProof, const Entries extends ReadonlyArray<Command.SpawnEntry<S>>, Relates = never>(draft: Entity.EntityDraft<S, P, Root, Relates>, ...entries: Entries) => Command.DraftFor<S, Entries, P, Root, Relates>;
467
+ entry: <D extends ComponentDescriptor<S>>(descriptor: D, value: QueryModule.ReadonlyValue<Descriptor.Value<D>>) => Command.Entry<D>;
339
468
  entryRaw: <D extends Extract<ComponentDescriptor<S>, ConstructedDescriptor<"component", string, any, any, any>>>(descriptor: D, raw: Descriptor.Raw<D>) => Result.Result<Command.Entry<D>, Descriptor.ConstructionError<D>>;
340
- relate: <P extends Entity.ComponentProof, R extends RelationDescriptor<S>>(draft: Entity.EntityDraft<S, P, Root>, relation: R, target: Entity.EntityId<S, Root>) => Entity.EntityDraft<S, P, Root>;
469
+ /**
470
+ * Stages a relation on a draft, created with the spawn. Spawning the
471
+ * draft needs the relation in `Game.System.relates(...)`, like
472
+ * `commands.relate`.
473
+ */
474
+ relate: <P extends Entity.ComponentProof, R extends RelationDescriptor<S>, Relates = never>(draft: Entity.EntityDraft<S, P, Root, Relates>, relation: R, target: Entity.EntityId<S, Root>) => Entity.EntityDraft<S, P, Root, Relates | R>;
341
475
  };
342
476
  /**
343
477
  * Declares one game-wide mode (menu, playing, paused): queued with
@@ -347,10 +481,43 @@ export declare namespace Schema {
347
481
  */
348
482
  readonly StateMachine: {
349
483
  <const Name extends string, const Values extends readonly [Machine.StateValue, ...Machine.StateValue[]]>(name: Name, values: Values): Schema.BoundStateMachine<Root, Name, Values>;
484
+ /**
485
+ * Declares a sub-state: a machine that exists only while `within[0]` is
486
+ * in state `within[1]` (a battle phase that only means something while
487
+ * playing). Whenever the parent enters that state, the sub-state enters
488
+ * the value given to `Game.Runtime.machine(...)`; when the parent leaves
489
+ * it, the sub-state exits and has no value: `get()` is `undefined`,
490
+ * `Game.Condition.inState(Sub, x)` is false, and `nextMachines.sub.set(...)`
491
+ * returns a `SubStateInactive` failure. So `inState(Sub, x)` alone
492
+ * implies the parent's state.
493
+ *
494
+ * The sub-state enters together with the parent's commit, before any
495
+ * `onEnter` schedule runs: the parent's `onEnter` systems already see its
496
+ * value, its `despawnOnEnter` scopes are cleared before they spawn, and
497
+ * a failing `onEnter` leaves it entered. Its own `onEnter` schedules
498
+ * run after the parent's.
499
+ *
500
+ * Use a second top-level machine instead when the two modes are
501
+ * independent (each keeps its value whatever the other does).
502
+ *
503
+ * @example
504
+ * ```ts
505
+ * const Phase = Game.StateMachine("Phase", ["Setup", "Battle"], { within: [Session, "Playing"] })
506
+ * ```
507
+ */
508
+ <const Name extends string, const Values extends readonly [Machine.StateValue, ...Machine.StateValue[]], Parent extends Machine.StateMachine.Any>(name: Name, values: Values, options: {
509
+ readonly within: readonly [Parent & Machine.SameGame<Parent, Root>, Machine.StateMachine.Value<Parent>];
510
+ }): Schema.BoundStateMachine<Root, Name, Values, Parent>;
350
511
  };
351
512
  readonly Condition: {
352
- inState: typeof Machine.inState;
353
- stateChanged: typeof Machine.stateChanged;
513
+ /**
514
+ * Passes while the machine's committed value is `value`. For a
515
+ * sub-state it fails while the parent is in another state. A machine
516
+ * of another game fails to compile with a message naming the fix.
517
+ */
518
+ inState: <M extends Machine.StateMachine.Any>(machine: M & Machine.SameGame<M, Root>, value: Machine.StateMachine.Value<M>) => Machine.InStateCondition<M>;
519
+ /** Passes in the schedule run where `applyStateTransitions(...)` changed the machine. */
520
+ stateChanged: <M extends Machine.StateMachine.Any>(machine: M & Machine.SameGame<M, Root>) => Machine.StateChangedCondition<M>;
354
521
  not: typeof Machine.not;
355
522
  and: typeof Machine.and;
356
523
  or: typeof Machine.or;
@@ -365,6 +532,7 @@ export declare namespace Schema {
365
532
  <const Name extends string, const Access extends BoundSystemAccess<S, Root>, E = never>(name: Name, spec: System.ExactAccess<Access>, run: System.SystemRun<System.SystemSpec<S, Access, Root>, E>): BoundSystem<S, Root, System.SystemSpec<S, Access, Root>, E, Name, System.SystemAccessNeeds<Access>>;
366
533
  readResource: <D extends ResourceDescriptor<S>>(descriptor: D) => System.ResourceRead<D>;
367
534
  writeResource: <D extends ResourceDescriptor<S>>(descriptor: D) => System.ResourceWrite<D>;
535
+ changedResource: <D extends ResourceDescriptor<S>>(descriptor: D) => System.ResourceChanged<D>;
368
536
  readEvent: <D extends EventDescriptor<S>>(descriptor: D) => System.EventRead<D>;
369
537
  writeEvent: <D extends EventDescriptor<S>>(descriptor: D) => System.EventWrite<D>;
370
538
  /**
@@ -372,7 +540,7 @@ export declare namespace Schema {
372
540
  * same `runtime.tick(...)` call; checked at compile time by `tick`.
373
541
  * Accepts `readEvent(...)`, `readResource(...)`, or a query.
374
542
  */
375
- thisTick: <Read extends System.EventRead<EventDescriptor<S>> | System.ResourceRead<ResourceDescriptor<S>> | Query.Any<Root>>(read: Read) => Read & System.ThisTick;
543
+ thisTick: <Read extends System.EventRead<EventDescriptor<S>> | System.ResourceRead<ResourceDescriptor<S>> | System.ResourceChanged<ResourceDescriptor<S>> | Query.Any<Root>>(read: Read) => Read & System.ThisTick;
376
544
  service: typeof System.service;
377
545
  machine: <M extends BoundStateMachine<Root>>(machine: M) => Machine.MachineRead<M>;
378
546
  nextState: <M extends BoundStateMachine<Root>>(machine: M) => Machine.NextMachineWrite<M>;
@@ -386,18 +554,21 @@ export declare namespace Schema {
386
554
  * `Game.System.commands(Game.System.spawns(Enemy, Position), Game.System.despawns(Enemy))`.
387
555
  */
388
556
  commands: typeof Command.commands;
389
- /** Allows spawning drafts whose components are all among these; see `Command.spawns`. */
390
- spawns: <const Components extends ReadonlyArray<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"spawns", Components[number]>;
557
+ /** Allows spawning drafts whose components are all among these and what they require (`Schema.requires`); see `Command.spawns`. */
558
+ spawns: <const Components extends NonEmpty<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"spawns", Components[number] | Command.RequiredDescriptors<S, Components[number]["name"]>>;
391
559
  /** Allows `insert` (add or replace at the next `applyDeferred()`) of these; see `Command.inserts`. */
392
- inserts: <const Components extends ReadonlyArray<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"inserts", Components[number]>;
560
+ inserts: <const Components extends NonEmpty<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"inserts", Components[number]>;
393
561
  /** Allows `remove` of these. */
394
- removes: <const Components extends ReadonlyArray<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"removes", Components[number]>;
562
+ removes: <const Components extends NonEmpty<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"removes", Components[number]>;
395
563
  /** Allows `despawn` of entities a query proves have one of these; see `Command.despawns`. */
396
- despawns: <const Components extends ReadonlyArray<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"despawns", Components[number]>;
564
+ despawns: <const Components extends NonEmpty<ComponentDescriptor<S>>>(...components: Components) => Command.Permission<"despawns", Components[number]>;
397
565
  /** Allows `despawnScope` of this scope. */
398
566
  despawnsScope: <const Scope extends EntityScope.EntityScope<string, Root>>(scope: Scope) => Command.Permission<"despawnsScope", Scope>;
399
- /** Allows `relate`, `unrelate`, and `reorderChildren` of these relations. */
400
- relates: <const Relations extends ReadonlyArray<RelationDescriptor<S>>>(...relations: Relations) => Command.Permission<"relates", Relations[number]>;
567
+ /**
568
+ * Allows `relate`, `unrelate`, and `reorderChildren` of these relations,
569
+ * and spawning drafts that stage them with `Game.Command.relate(...)`.
570
+ */
571
+ relates: <const Relations extends NonEmpty<RelationDescriptor<S>>>(...relations: Relations) => Command.Permission<"relates", Relations[number]>;
401
572
  };
402
573
  readonly Schedule: {
403
574
  /**
@@ -407,12 +578,23 @@ export declare namespace Schema {
407
578
  <const Entries extends ReadonlyArray<BoundScheduleEntry<S, Root>>>(...entries: Entries): Schedule.AnonymousScheduleBuildFor<S, Entries, Root>;
408
579
  transitions: <const Entries extends ReadonlyArray<BoundTransitionBundleInput<S, Root>>>(...entries: Entries) => BoundTransitionBundleResult<S, Root, Entries>;
409
580
  onEnter: <M extends BoundStateMachine<Root>, const Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>>(machine: M, state: Machine.StateMachine.Value<M>, plan: readonly [...Entries]) => BoundTransitionScheduleResult<S, Root, M, Entries>;
410
- onExit: <M extends BoundStateMachine<Root>, const Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>>(machine: M, state: Machine.StateMachine.Value<M>, plan: readonly [...Entries]) => BoundTransitionScheduleResult<S, Root, M, Entries>;
411
- onTransition: <M extends BoundStateMachine<Root>, const Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>>(machine: M, transition: readonly [Machine.StateMachine.Value<M>, Machine.StateMachine.Value<M>], plan: readonly [...Entries]) => BoundTransitionScheduleResult<S, Root, M, Entries>;
581
+ /**
582
+ * Systems run when `machine` leaves `state`. The exit phase of one
583
+ * transition (the exit schedules of the sub-states it ends, then of
584
+ * `state`, then `onTransition`) is one transaction: when a system in it
585
+ * fails, everything the phase did is undone (except `local`) and the
586
+ * transition stays queued, so the next attempt starts from the same
587
+ * state. Its commands are applied at the next `applyDeferred()` after
588
+ * the marker, so it cannot contain `applyDeferred()` itself.
589
+ */
590
+ onExit: <M extends BoundStateMachine<Root>, const Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>>(machine: M, state: Machine.StateMachine.Value<M>, plan: readonly [...Entries] & NoApplyDeferredInExit<Entries>) => BoundTransitionScheduleResult<S, Root, M, Entries>;
591
+ /** Systems run on one `[from, to]` transition, last in its exit phase (see `onExit`). */
592
+ onTransition: <M extends BoundStateMachine<Root>, const Entries extends ReadonlyArray<BoundTransitionEntry<S, Root>>>(machine: M, transition: readonly [Machine.StateMachine.Value<M>, Machine.StateMachine.Value<M>], plan: readonly [...Entries] & NoApplyDeferredInExit<Entries>) => BoundTransitionScheduleResult<S, Root, M, Entries>;
412
593
  /**
413
594
  * Builds a schedule whose systems run only while every condition
414
595
  * passes (in addition to their own `when`). Nested schedules are
415
- * gated too; marker steps still run. Gated systems drop the events
596
+ * gated too; marker steps still run, and so do the transition schedules
597
+ * an `applyStateTransitions(bundle)` in the group runs. Gated systems drop the events
416
598
  * published while gated; use `pauseWhen` to keep them. For one system,
417
599
  * use `when` in its spec.
418
600
  */
@@ -430,15 +612,18 @@ export declare namespace Schema {
430
612
  };
431
613
  readonly Runtime: {
432
614
  /**
433
- * Builds a runtime. Returns a `Result` exactly when a provided resource
434
- * goes through a constructed descriptor and can fail validation.
615
+ * Builds a runtime. Always returns a `Result`: a `Success` (read
616
+ * `.value`) when nothing provided can fail, and a `Result` to check
617
+ * when a provided resource goes through a constructed descriptor.
435
618
  */
436
619
  make: <const ProvidedServices extends Runtime.RuntimeServices<any>, const Resources extends Runtime.RuntimeResources<S> = {}, const ProvidedMachines extends Runtime.RuntimeMachines<any> = Runtime.RuntimeMachines<{}>, const Enabled extends Debug.Option | undefined = undefined>(options: {
437
620
  readonly services: ProvidedServices;
438
- readonly resources?: Resources;
621
+ readonly resources?: Resources & Runtime.ExactResources<S, Resources>;
439
622
  readonly machines?: ProvidedMachines;
440
623
  /** Attaches a `debug` handle to the runtime; see the `Debug` module. */
441
624
  readonly debug?: Enabled;
625
+ /** The game's save migrations (`Snapshot.migrations`): `restore` upgrades older saves with them. */
626
+ readonly saves?: Snapshot.Migrations;
442
627
  }) => Runtime.MakeRuntimeResult<S, RuntimeServicesOf<ProvidedServices>, Resources, Root, RuntimeMachinesOf<ProvidedMachines>, Enabled>;
443
628
  service: typeof Runtime.service;
444
629
  services: typeof Runtime.services;