ecspresso
Version:
A minimal Entity-Component-System library for typescript and javascript.
160 lines (159 loc) • 7.87 kB
TypeScript
import type ECSpresso from './ecspresso';
import type { SystemPhase } from './types';
import type { WorldConfig, EmptyConfig, MergeConfigs, WithComponents, WithEvents, WithResources, WithAssets, WithScreens } from './type-utils';
/**
* Registrar passed as the second argument to a plugin's `install` function.
* Each registered disposer runs (in reverse order) when the plugin is
* uninstalled via `world.uninstallPlugin(id)` or when `world.dispose()` is called.
*/
export type PluginCleanupRegistrar = (fn: () => void) => void;
/**
* Defaults applied to every system created via `world.addSystem(...)` inside
* a plugin's install function. Per-system builder calls (`.inPhase(...)`,
* `.inScreens([...])`, `.setPriority(...)`) always override the default.
*/
export interface SystemDefaults<Cfg extends WorldConfig = EmptyConfig> {
inScreens?: ReadonlyArray<keyof Cfg['screens'] & string>;
excludeScreens?: ReadonlyArray<keyof Cfg['screens'] & string>;
phase?: SystemPhase;
priority?: number;
}
/**
* Plugin interface for ECSpresso. A plugin is a plain object with an `install`
* function that configures a world directly, plus phantom properties for
* compile-time type extraction.
*
* @typeParam Cfg - The WorldConfig this plugin provides (components, events, resources, etc.)
* @typeParam Requires - The WorldConfig this plugin requires from other plugins
*/
export interface Plugin<Cfg extends WorldConfig = EmptyConfig, Requires extends WorldConfig = EmptyConfig, Labels extends string = never, Groups extends string = never, AssetGroupNames extends string = never, ReactiveQueryNames extends string = never> {
readonly id: string;
readonly install: (world: ECSpresso<MergeConfigs<Cfg, Requires>>, onCleanup: PluginCleanupRegistrar) => void;
/**
* Default system configuration applied to every `world.addSystem(...)` call
* made inside the plugin's install function. Explicit per-system calls
* override. Set via `PluginBuilder.setSystemDefaults(...)`.
*/
readonly systemDefaults?: SystemDefaults<MergeConfigs<Cfg, Requires>>;
readonly _cfg?: Cfg;
readonly _requires?: Requires;
readonly _labels?: Labels;
readonly _groups?: Groups;
readonly _assetGroupNames?: AssetGroupNames;
readonly _reactiveQueryNames?: ReactiveQueryNames;
}
/**
* Common configuration options shared by most plugins.
* Plugin-specific options interfaces extend this with additional fields.
*/
export interface BasePluginOptions<G extends string = string> {
/** System group name for all systems registered by this plugin */
systemGroup?: G;
/** Priority for the plugin's primary system (default varies per plugin) */
priority?: number;
/** Execution phase for the plugin's primary system */
phase?: SystemPhase;
}
/**
* Fluent builder for defining plugins. Mirrors `ECSpressoBuilder`'s
* type-accumulator pattern: each `.withXxx<T>()` call threads `T` into the
* appropriate WorldConfig slot at the type level, with no runtime cost.
*
* Terminal call is `.install(fn)` which returns the finalized `Plugin<...>`.
*
* @example
* ```typescript
* const myPlugin = definePlugin('my-plugin')
* .withComponentTypes<MyComponents>()
* .withEventTypes<MyEvents>()
* .withResourceTypes<MyResources>()
* .install((world) => {
* world.addSystem('foo').setProcess(() => {});
* });
* ```
*/
export declare class PluginBuilder<Cfg extends WorldConfig = EmptyConfig, Requires extends WorldConfig = EmptyConfig, Labels extends string = never, Groups extends string = never, AssetGroupNames extends string = never, ReactiveQueryNames extends string = never> {
private readonly _id;
constructor(_id: string);
private _systemDefaults?;
/**
* Set defaults applied to every system created via `world.addSystem(...)`
* inside this plugin's install function. Calling again replaces the
* previous defaults wholesale (not merge). Per-system builder calls
* override defaults.
*/
setSystemDefaults(defaults: SystemDefaults<MergeConfigs<Cfg, Requires>>): this;
/**
* Declare component types this plugin provides.
* Pure type-level operation with no runtime cost.
*/
withComponentTypes<T extends Record<string, any>>(): PluginBuilder<WithComponents<Cfg, T>, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
/**
* Declare event types this plugin provides.
* Pure type-level operation with no runtime cost.
*/
withEventTypes<T extends Record<string, any>>(): PluginBuilder<WithEvents<Cfg, T>, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
/**
* Declare resource types this plugin provides.
* Pure type-level operation with no runtime cost.
*/
withResourceTypes<T extends Record<string, any>>(): PluginBuilder<WithResources<Cfg, T>, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
/**
* Declare asset types this plugin provides.
* Pure type-level operation with no runtime cost.
*/
withAssetTypes<T extends Record<string, unknown>>(): PluginBuilder<WithAssets<Cfg, T>, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
/**
* Declare screen types this plugin provides.
* Pure type-level operation with no runtime cost.
*/
withScreenTypes<T extends Record<string, any>>(): PluginBuilder<WithScreens<Cfg, T>, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
/**
* Declare system labels this plugin registers.
* Pure type-level operation with no runtime cost.
*/
withLabels<L extends string>(): PluginBuilder<Cfg, Requires, Labels | L, Groups, AssetGroupNames, ReactiveQueryNames>;
/**
* Declare system groups this plugin uses.
* Pure type-level operation with no runtime cost.
*/
withGroups<G extends string>(): PluginBuilder<Cfg, Requires, Labels, Groups | G, AssetGroupNames, ReactiveQueryNames>;
/**
* Declare asset group names this plugin uses.
* Pure type-level operation with no runtime cost.
*/
withAssetGroupNames<N extends string>(): PluginBuilder<Cfg, Requires, Labels, Groups, AssetGroupNames | N, ReactiveQueryNames>;
/**
* Declare reactive query names this plugin registers.
* Pure type-level operation with no runtime cost.
*/
withReactiveQueryNames<N extends string>(): PluginBuilder<Cfg, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames | N>;
/**
* Declare dependencies this plugin requires from other plugins.
* Accepts a pre-built `WorldConfig` type (typically a named alias like
* `TransformWorldConfig`). The install callback will see these types
* merged into its world parameter.
* Pure type-level operation with no runtime cost.
*/
requires<R extends WorldConfig>(): PluginBuilder<Cfg, R, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
/**
* Terminal method. Provide the install function and receive the finalized
* `Plugin<...>` object. The install function receives a world typed as
* `ECSpresso<MergeConfigs<Cfg, Requires>>` — meaning it can use both the
* types this plugin provides and the types it declared via `.requires<>()`.
*/
install(install: (world: ECSpresso<MergeConfigs<Cfg, Requires>>, onCleanup: PluginCleanupRegistrar) => void): Plugin<Cfg, Requires, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
}
/**
* Entry point for the fluent plugin builder. Pass the plugin id and chain
* type-accumulator methods, terminating with `.install(fn)`.
*
* @example
* ```typescript
* const myPlugin = definePlugin('my-plugin')
* .withComponentTypes<MyComponents>()
* .withResourceTypes<MyResources>()
* .install((world) => { ... });
* ```
*/
export declare function definePlugin(id: string): PluginBuilder;