UNPKG

@game-vir/entity

Version:

Entity system for game development.

162 lines (161 loc) 7.48 kB
import { type AnyObject, type ArrayElement, type Values } from '@augment-vir/common'; import { type ShapeDefinition } from 'object-shape-tester'; import { type Constructor } from 'type-fest'; import { BaseEntity, type EntityDestroyEvent, EntityStore, type EntityStoreConstructorParams, type ParamsMap, type ReverseParamsMap, ViewEntity } from './entity.js'; /** * Params for both {@link EntitySuite.defineEntity} and {@link EntitySuite.defineLogicEntity}. * * @category Internal */ export type DefineEntityParams<EntityKey extends string, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends ReadonlyArray<Constructor<Event>> = never> = { /** * This key is used for deserialization of entities to track which class needs to be * constructed. Do not use duplicate key strings across multiple entity classes. */ key: EntityKey; /** * This should contain all parameters necessary to reconstruct this entity from scratch so it * can be serialized, sent across the network in JSON format, then reconstructed on another * device (for multiplayer support). * * Make sure to include {@link entityPositionParamsShape} if you want to include the base entity * position parameters. */ paramsShape: Shape; /** * All events that this entity can emit, in addition to the default {@link EntityDestroyEvent} * event. */ events?: Events | undefined; /** * A mapping of the entity's params object (defined by {@link DefineEntityParams.paramsShape}) * keys to hitbox and/or view properties. * * @default undefined // no mapping */ paramsMap?: ParamsMap<Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined> | undefined; }; /** * Static members of both view and logic entity constructors. * * @category Internal */ export type StaticEntity<EntityKey, Shape extends ShapeDefinition<AnyObject, any> | undefined> = { /** * This key is used for deserialization of entities to track which class needs to be * constructed. You cannot have duplicate keys loaded at the same time. */ entityKey: EntityKey; /** Shape definition of this entity's parameters. */ paramsShape: Shape; /** * Defines which properties from {@link BaseEntity.params} will be mapped to hitbox and/or view * properties. */ paramsMap: ParamsMap<Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined>; /** Parses the serialized params generated by {@link BaseEntity.serialize}. */ deserialize(serialized: string | undefined): AnyObject | undefined; }; /** * ======================== * * # View Entity * * Types for entity definitions that have a view. * * ======================== */ /** * The constructor output of {@link DefinedViewEntityConstructor}. * * @category Internal */ export type DefinedViewEntityInstance<Context, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends Readonly<Event>> = ViewEntity<Context, Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined, Events>; /** * Output of {@link DefineViewEntity}. * * @category Internal */ export type DefinedViewEntityConstructor<EntityKey, Context, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends Readonly<Event>> = Constructor<DefinedViewEntityInstance<Context, Shape, Events>, ConstructorParameters<typeof ViewEntity<Context, Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined>>> & StaticEntity<EntityKey, Shape>; /** * Type for {@link EntitySuite.defineEntity}. * * @category Internal */ export type DefineViewEntity<Context> = <const EntityKey extends string, const Shape extends ShapeDefinition<AnyObject, any> | undefined, const Events extends ReadonlyArray<Constructor<Event>> = never>(params: DefineEntityParams<EntityKey, Shape, Events>) => DefinedViewEntityConstructor<EntityKey, Context, Shape, InstanceType<ArrayElement<NoInfer<Events>>> | EntityDestroyEvent>; /** * ======================== * * # Logic Entity * * Types for entity definitions that don't have a view. The only difference between these types and * the view types are that this uses `BaseEntity` instead of `ViewEntity. * * ======================== */ /** * The constructor output of {@link DefinedLogicEntityConstructor}. * * @category Internal */ export type DefinedLogicEntityInstance<Context, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends Readonly<Event>> = BaseEntity<Context, Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined, Events>; /** * Output of {@link DefineLogicEntity}. * * @category Internal */ export type DefinedLogicEntityConstructor<EntityKey, Context, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends Readonly<Event>> = Constructor<DefinedLogicEntityInstance<Context, Shape, Events>, ConstructorParameters<typeof BaseEntity<Context, Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined>>> & StaticEntity<EntityKey, Shape>; /** * Type for {@link EntitySuite.defineEntity}. * * @category Internal */ export type DefineLogicEntity<Context> = <const EntityKey extends string, const Shape extends ShapeDefinition<AnyObject, any> | undefined, const Events extends ReadonlyArray<Constructor<Event>> = never>(params: DefineEntityParams<EntityKey, Shape, Events>) => DefinedLogicEntityConstructor<EntityKey, Context, Shape, InstanceType<ArrayElement<NoInfer<Events>>> | EntityDestroyEvent>; /** * ======================== * * # Entity Suite * * ======================== */ /** * Output of {@link defineEntitySuite}, used to defining and creating entities. * * @category Internal */ export type EntitySuite<Context> = { /** * The suite's entity store constructor. Instantiate this and to add your first entities. * * All defined entities will also have a reference to this store so they can add additional * entities by themselves. */ EntityStore: new <const RegisteredEntities extends Values<EntityStore['entityKeyConstructorMap']>>(params: Readonly<EntityStoreConstructorParams<Context, RegisteredEntities>>) => EntityStore<Context, RegisteredEntities>; /** * Define a standard entity (with a view). This is intended to be extended from your entity * class. */ defineEntity: DefineViewEntity<Context>; /** Define an entity that doesn't have an attached view. These are likely to be rare. */ defineLogicEntity: DefineLogicEntity<Context>; /** * A set of entity keys used within this entity suite. This will only be populated by all * classes that are defined with `defineEntity` or `defineLogicEntity` (so this will miss any * not-yet-resolved dynamic imports). This will be populated even before the classes are ever * instantiated. */ entityKeys: Set<string>; }; /** * This is the starting point of the @game-vir/entity package. Call this to produce the function * needed to define new entities and the store needed to add entity instances. * * @category Main */ export declare function defineEntitySuite<Context = undefined>(): EntitySuite<Context>; /** * Converts {@link ParamsMap} to {@link ReverseParamsMap}. * * @category Internal */ export declare function reverseParamsMap(paramsMap: ParamsMap | undefined): ReverseParamsMap | undefined;