@skewedaspect/sage-core 0.10.0-beta.2 → 0.10.0-rc.2
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/dist/behavior.d.ts +7 -4
- package/dist/computedState.d.ts +11 -0
- package/dist/eventBus.d.ts +9 -1
- package/dist/events.d.ts +6 -1
- package/dist/gameEntity.d.ts +24 -8
- package/dist/index.d.ts +17 -15
- package/dist/namedBehavior.d.ts +1 -1
- package/dist/sage-core.js +308 -103
- package/dist/sage-core.js.map +1 -1
- package/dist/simulation.d.ts +48 -11
- package/dist/simulationBus.d.ts +13 -0
- package/dist/simulationContext.d.ts +2 -2
- package/dist/stateMachineBehavior.d.ts +3 -2
- package/package.json +5 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christopher Case
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/behavior.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { Computation } from "./computedState.js";
|
|
2
|
+
import { EventSubscription, GameEvent } from "./events.js";
|
|
3
|
+
import { GameEntity } from "./gameEntity.js";
|
|
4
|
+
export declare abstract class Behavior<State extends object, Requires extends object = object, Entity extends GameEntity = GameEntity> {
|
|
4
5
|
readonly state: State;
|
|
5
6
|
readonly ops: Requires;
|
|
6
|
-
readonly entity:
|
|
7
|
+
readonly entity: Entity;
|
|
7
8
|
abstract readonly defaults: State;
|
|
9
|
+
onStateReady?(): void;
|
|
8
10
|
onCreate?(): void;
|
|
9
11
|
onUpdate?(dt: number): void;
|
|
10
12
|
onEvent?(event: GameEvent): boolean | undefined;
|
|
13
|
+
protected computed<Field extends keyof State & string>(field: Field, computation: Computation<State[Field]>): void;
|
|
11
14
|
}
|
|
12
15
|
export interface BehaviorClass {
|
|
13
16
|
new (): Behavior<object, object>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** What a computed field is read and written through (design/entities.md#computed-state). */
|
|
2
|
+
export interface Computation<Value> {
|
|
3
|
+
get: () => Value;
|
|
4
|
+
set: (value: Value) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function defineComputed<Value>(state: object, field: string, computation: Computation<Value>): void;
|
|
7
|
+
/**
|
|
8
|
+
* Take every computation off a state bag, newest first, so a computation over a computation leaves the one beneath
|
|
9
|
+
* it answering and the field ends as the plain value the last one answered with.
|
|
10
|
+
*/
|
|
11
|
+
export declare function removeComputed(state: object): void;
|
package/dist/eventBus.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import { EventSubscription, GameEvent, Subscriber, Unsubscribe } from "./events.
|
|
1
|
+
import { EventSubscription, EventsMatching, GameEvent, RawGameEvent, Subscriber, Unsubscribe } from "./events.js";
|
|
2
|
+
export type EventCallback<Subscription extends EventSubscription = EventSubscription> = (event: EventsMatching<Subscription>) => void;
|
|
2
3
|
export declare class EventBus {
|
|
3
4
|
#private;
|
|
4
5
|
register(subscriber: Subscriber, subscriptions: readonly EventSubscription[]): Unsubscribe;
|
|
6
|
+
on<Subscription extends EventSubscription>(subscription: Subscription, callback: EventCallback<Subscription>): Unsubscribe;
|
|
7
|
+
/**
|
|
8
|
+
* The ID the n-th subscriber `on` makes registers under (design/events.md#registration).
|
|
9
|
+
*/
|
|
10
|
+
protected mintSubscriberID(ordinal: number): string;
|
|
5
11
|
emit(event: GameEvent): void;
|
|
6
12
|
drain(): void;
|
|
13
|
+
protected takeQueuedEvents(): GameEvent[];
|
|
14
|
+
protected static reclaimQueuedEvents(bus: EventBus, events: readonly RawGameEvent[]): GameEvent[];
|
|
7
15
|
}
|
package/dist/events.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EventMap } from "./index.
|
|
1
|
+
import { EventMap } from "./index.js";
|
|
2
2
|
export type { EventMap };
|
|
3
3
|
export type GameEvent = {
|
|
4
4
|
[Type in keyof EventMap & string]: {
|
|
@@ -10,6 +10,11 @@ export type GameEvent = {
|
|
|
10
10
|
}[keyof EventMap & string];
|
|
11
11
|
type EventPrefix<Type extends string> = Type extends `${infer Prefix}:${infer Rest}` ? Prefix | `${Prefix}:${EventPrefix<Rest>}` : never;
|
|
12
12
|
export type EventSubscription = (keyof EventMap & string) | `${EventPrefix<keyof EventMap & string>}:*`;
|
|
13
|
+
export type EventsMatching<Subscription extends EventSubscription> = Subscription extends `${infer Prefix}:*` ? Extract<GameEvent, {
|
|
14
|
+
type: `${Prefix}:${string}`;
|
|
15
|
+
}> : Extract<GameEvent, {
|
|
16
|
+
type: Subscription;
|
|
17
|
+
}>;
|
|
13
18
|
export type Unsubscribe = () => void;
|
|
14
19
|
export interface Subscriber {
|
|
15
20
|
readonly id: string;
|
package/dist/gameEntity.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Computation } from "./computedState.js";
|
|
2
|
+
import { EventMap, GameEvent, Subscriber } from "./events.js";
|
|
3
|
+
import { Behavior, BehaviorClass } from "./behavior.js";
|
|
4
|
+
import { GameSimulationContext } from "./simulationContext.js";
|
|
4
5
|
export type StateValue = null | boolean | number | string | StateValue[] | {
|
|
5
6
|
[key: string]: StateValue;
|
|
6
7
|
};
|
|
@@ -27,6 +28,9 @@ export type StateFor<Behaviors extends readonly BehaviorClass[]> = GameEntitySta
|
|
|
27
28
|
export type OpsFor<Behaviors extends readonly BehaviorClass[]> = UnionToIntersection<OpsFrom<Behaviors[number]>> & object;
|
|
28
29
|
export type OpsOf<Class extends BehaviorClass> = OpsFrom<Class>;
|
|
29
30
|
export type StateSliceOf<Class extends BehaviorClass> = StateOf<Class>;
|
|
31
|
+
type EntityOf<Class> = Class extends new () => {
|
|
32
|
+
entity: infer Entity;
|
|
33
|
+
} ? Entity : GameEntity;
|
|
30
34
|
interface Unsatisfied<Missing> {
|
|
31
35
|
'ERROR: a behavior requires operations the entity does not provide': Missing;
|
|
32
36
|
}
|
|
@@ -36,6 +40,12 @@ interface DuplicateOperation<Name> {
|
|
|
36
40
|
interface IncompatibleState<Name> {
|
|
37
41
|
'ERROR: two behaviors declare one state field with incompatible types': Name;
|
|
38
42
|
}
|
|
43
|
+
interface WrongEntity<Class> {
|
|
44
|
+
'ERROR: a behavior attaches to an entity of another class': Class;
|
|
45
|
+
}
|
|
46
|
+
type ValidateEntity<Behaviors extends readonly BehaviorClass[], Entity> = {
|
|
47
|
+
[Index in keyof Behaviors]: Entity extends EntityOf<Behaviors[Index]> ? Behaviors[Index] : WrongEntity<Behaviors[Index]>;
|
|
48
|
+
};
|
|
39
49
|
type ValidateRequires<Behaviors extends readonly BehaviorClass[]> = {
|
|
40
50
|
[Index in keyof Behaviors]: OpsFor<Behaviors> extends RequiresOf<Behaviors[Index]> ? Behaviors[Index] : Unsatisfied<Exclude<keyof RequiresOf<Behaviors[Index]>, keyof OpsFor<Behaviors>>>;
|
|
41
51
|
};
|
|
@@ -44,13 +54,17 @@ type IncompatibleKeys<First, Second> = {
|
|
|
44
54
|
[Key in keyof First & keyof Second]: [First[Key]] extends [Second[Key]] ? [Second[Key]] extends [First[Key]] ? never : Key : Key;
|
|
45
55
|
}[keyof First & keyof Second];
|
|
46
56
|
type IncompatibleStateKeys<Behaviors extends readonly unknown[], SeenState extends object = object> = Behaviors extends readonly [infer Head, ...infer Tail] ? IncompatibleKeys<SeenState, StateOf<Head>> | IncompatibleStateKeys<Tail, SeenState & StateOf<Head>> : never;
|
|
47
|
-
export type ValidTuple<Behaviors extends readonly BehaviorClass[]> = [DuplicateNames<Behaviors>] extends [never] ? [IncompatibleStateKeys<Behaviors>] extends [never] ? Behaviors extends ValidateRequires<Behaviors> ? Behaviors : ValidateRequires<Behaviors> : readonly IncompatibleState<IncompatibleStateKeys<Behaviors>>[] : readonly DuplicateOperation<DuplicateNames<Behaviors>>[];
|
|
57
|
+
export type ValidTuple<Behaviors extends readonly BehaviorClass[], Entity = GameEntity> = [DuplicateNames<Behaviors>] extends [never] ? [IncompatibleStateKeys<Behaviors>] extends [never] ? Behaviors extends ValidateRequires<Behaviors> ? Behaviors extends ValidateEntity<Behaviors, Entity> ? Behaviors : ValidateEntity<Behaviors, Entity> : ValidateRequires<Behaviors> : readonly IncompatibleState<IncompatibleStateKeys<Behaviors>>[] : readonly DuplicateOperation<DuplicateNames<Behaviors>>[];
|
|
48
58
|
export interface GameEntityType {
|
|
49
59
|
readonly behaviors: readonly BehaviorClass[];
|
|
50
60
|
readonly prototype: GameEntity;
|
|
51
61
|
}
|
|
62
|
+
export interface GameEntityClass<Context extends GameSimulationContext = GameSimulationContext> extends GameEntityType {
|
|
63
|
+
readonly create: (id: string, context: Context, state?: object, name?: string) => GameEntity;
|
|
64
|
+
readonly restore: (id: string, context: Context, state: GameEntityState, name?: string) => GameEntity;
|
|
65
|
+
}
|
|
52
66
|
export type ComposedOf<Type extends GameEntityType> = Type['prototype'] & {
|
|
53
|
-
readonly state: StateFor<Type['behaviors']
|
|
67
|
+
readonly state: DeepReadonly<StateFor<Type['behaviors']>>;
|
|
54
68
|
readonly ops: OpsFor<Type['behaviors']>;
|
|
55
69
|
};
|
|
56
70
|
export type NarrowedTo<Class extends BehaviorClass> = GameEntity & {
|
|
@@ -65,13 +79,12 @@ export declare abstract class GameEntity implements Subscriber {
|
|
|
65
79
|
protected readonly context: GameSimulationContext;
|
|
66
80
|
readonly state: object;
|
|
67
81
|
readonly ops: object;
|
|
68
|
-
readonly eventSubscriptions: readonly EventSubscription[];
|
|
69
82
|
static readonly behaviors: readonly BehaviorClass[];
|
|
70
83
|
static create<Type extends GameEntityType>(this: Type & {
|
|
71
|
-
behaviors: ValidTuple<Type['behaviors']>;
|
|
84
|
+
behaviors: ValidTuple<Type['behaviors'], Type['prototype']>;
|
|
72
85
|
}, id: string, context: GameSimulationContext, state?: Partial<StateFor<Type['behaviors']>>, name?: string): ComposedOf<Type>;
|
|
73
86
|
static restore<Type extends GameEntityType>(this: Type & {
|
|
74
|
-
behaviors: ValidTuple<Type['behaviors']>;
|
|
87
|
+
behaviors: ValidTuple<Type['behaviors'], Type['prototype']>;
|
|
75
88
|
}, id: string, context: GameSimulationContext, state: StateFor<Type['behaviors']>, name?: string): ComposedOf<Type>;
|
|
76
89
|
protected constructor(id: string, context: GameSimulationContext, providedState: object, runCreateHooks: boolean, name?: string);
|
|
77
90
|
hasBehavior<Class extends BehaviorClass>(behaviorClass: Class): this is NarrowedTo<Class>;
|
|
@@ -80,6 +93,9 @@ export declare abstract class GameEntity implements Subscriber {
|
|
|
80
93
|
update(dt: number): void;
|
|
81
94
|
receive(event: GameEvent): boolean;
|
|
82
95
|
destroy(): void;
|
|
96
|
+
protected declareComputedState(suppliedState: object): void;
|
|
97
|
+
protected computed<OwnState extends object, Field extends keyof OwnState & string>(field: Field, computation: Computation<OwnState[Field]>): void;
|
|
98
|
+
protected removeComputedState(): void;
|
|
83
99
|
protected attachedBehaviors(): readonly BehaviorInstance[];
|
|
84
100
|
}
|
|
85
101
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
export interface EventMap {
|
|
2
2
|
}
|
|
3
|
-
export type { Action, AnalogAction, DigitalAction } from "./action.
|
|
4
|
-
export { Behavior } from "./behavior.
|
|
5
|
-
export type { BehaviorClass } from "./behavior.
|
|
6
|
-
export {
|
|
7
|
-
export
|
|
8
|
-
export {
|
|
9
|
-
export
|
|
10
|
-
export {
|
|
11
|
-
export
|
|
12
|
-
export {
|
|
13
|
-
export {
|
|
14
|
-
export type {
|
|
15
|
-
export {
|
|
16
|
-
export type {
|
|
17
|
-
export
|
|
3
|
+
export type { Action, AnalogAction, DigitalAction } from "./action.js";
|
|
4
|
+
export { Behavior } from "./behavior.js";
|
|
5
|
+
export type { BehaviorClass } from "./behavior.js";
|
|
6
|
+
export type { Computation } from "./computedState.js";
|
|
7
|
+
export { NamedBehavior } from "./namedBehavior.js";
|
|
8
|
+
export type { NamedState } from "./namedBehavior.js";
|
|
9
|
+
export { defineStates, StateMachineBehavior } from "./stateMachineBehavior.js";
|
|
10
|
+
export type { StateDefinition } from "./stateMachineBehavior.js";
|
|
11
|
+
export { dilationLimit, drainPassLimit, operationCallDepthLimit } from "./constants.js";
|
|
12
|
+
export type { EventSubscription, EventsMatching, GameEvent, Subscriber, Unsubscribe } from "./events.js";
|
|
13
|
+
export { EventBus } from "./eventBus.js";
|
|
14
|
+
export type { EventCallback } from "./eventBus.js";
|
|
15
|
+
export { GameEntity } from "./gameEntity.js";
|
|
16
|
+
export type { ComposedOf, DeepReadonly, GameEntityClass, GameEntityState, GameEntityType, NarrowedTo, OpsFor, OpsOf, StateBag, StateFor, StateSliceOf, StateValue, ValidTuple, } from "./gameEntity.js";
|
|
17
|
+
export { GameSimulationManager } from "./simulation.js";
|
|
18
|
+
export type { GameEntityRegistry, GameEntitySnapshot, IDAllocator, GameSimulationOptions, GameSimulationSnapshot, ValidEntityRegistry, } from "./simulation.js";
|
|
19
|
+
export type { GameSimulationContext } from "./simulationContext.js";
|
package/dist/namedBehavior.d.ts
CHANGED