import type { GameFeatures } from "./defineGame.js"; import type { GameContext } from "../runtime/gameContext.js"; import type { SnapshotModule } from "../runtime/worldSnapshot.js"; /** * How a system is scheduled. Omit `tick` (or use only `events`) for event-driven systems. * Multiple systems may share the same channel; order within a channel is deterministic by stage * then optional `before`/`after` constraints — never import order. */ export type SystemTick = { type: "fixed"; /** Steps per game-second. Default 60. */ rate?: number; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { type: "frame"; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { type: "interval"; /** Period in game-seconds between runs. */ every: number; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { type: "manual"; }; /** Event name → handler. Payload is the engine event shape for that name. */ export type SystemEventHandlers = { readonly [eventName: string]: (ctx: GameContext, event: unknown) => void; }; /** * A reusable game capability — lifecycle, timing, events, and optional save / replication / * reset / disposal. Pass instances via `defineGame({ systems })`. Prefer one system per meaningful * capability (`combat`, `quests`), not per micro-tick. * * @capability game-system declare a composable capability with its own schedule and lifecycle */ export interface SystemDefinition { readonly id: string; /** * Timing channel. Omit for event-only systems (handlers in {@link events} still run). * `manual` systems install but never auto-tick — call them yourself or leave as infrastructure. */ tick?: SystemTick; /** Other system ids that must also be installed; validated when the schedule compiles. */ dependsOn?: readonly string[]; /** * Opt-in `ctx.game.*` feature(s) this system needs. Installing the system enables them — no * separate `features: { quest: true }` flag required (you may still set flags for systems-free games). */ feature?: keyof GameFeatures | readonly (keyof GameFeatures)[]; /** Once per world boot, before {@link start}. */ create?(ctx: GameContext): void; /** Once per world boot, after every system's `create`. */ start?(ctx: GameContext): void; /** Per schedule fire — `dt` is game-seconds for the step (fixed/frame/interval). */ update?(ctx: GameContext, dt: number): void; events?: SystemEventHandlers; /** * Whole-world save contribution. A factory form runs after `create` so closures can close over * system state. Registered into `ctx.game.save` coverage. */ save?: SnapshotModule | ((ctx: GameContext) => SnapshotModule | undefined); /** * Host→client replication contribution. Same factory form as {@link save}; registered into * `ctx.snapshot` / `ctx.hydrate`. */ replicate?: SnapshotModule | ((ctx: GameContext) => SnapshotModule | undefined); /** Run on scenario/run reset — clear run-scoped state while meta may survive. */ reset?(ctx: GameContext): void; /** Run when the world is torn down (mode switch, unmount). */ dispose?(ctx: GameContext): void; } /** * Declare a composable game system. Pure data + hooks — the engine compiles the schedule and * installs lifecycle when the game boots. * * @capability define-system composable game behavior — pure data + hooks the engine schedules; pass via `defineGame({ systems })` */ export declare function defineSystem(definition: SystemDefinition): SystemDefinition; /** Collect feature flags implied by a system list (OR-merge; installing a system activates its capability). * @internal */ export declare function featuresFromSystems(systems: readonly SystemDefinition[] | undefined): GameFeatures; /** OR-merge explicit `features` with flags implied by installed systems. * @internal */ export declare function mergeSystemFeatures(explicit: GameFeatures | undefined, systems: readonly SystemDefinition[] | undefined): GameFeatures | undefined;