Skip to content

Commit

Permalink
#9 prepare eventing and implement it for resource adding and PDA
Browse files Browse the repository at this point in the history
  • Loading branch information
minecrawler committed Jul 4, 2023
1 parent afc4169 commit ae28821
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 68 deletions.
6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,19 @@
"@types/chai": "~4.3.5",
"@types/mocha": "~10.0.1",
"chai": "~4.3.7",
"esbuild": "~0.17.18",
"madge": "~6.0.0",
"mocha": "~10.2.0",
"nyc": "~15.1.0",
"ts-node": "~10.9.1",
"typedoc": "~0.24.7",
"typescript": "~5.0.4",
"esbuild": "~0.17.18"
"typescript": "^5.0.4"
},
"files": [
"dist"
],
"scripts": {
"prebuild": "npm run loop-test-ts && npm run test",

"bench": "cd examples/bench && npm run bench",
"build": "npm run esmbuild && npm run dtsbuild && npm run doc",
"build-examples": "cd examples && tsc --project .",
Expand All @@ -90,7 +89,6 @@
"prepare": "npm run build",
"test": "echo 'Testing disabled until Mocha can handle TS ESM!'",
"test-original": "mocha --experimental-specifier-resolution=node --loader=ts-node/esm src/**/*.test.ts",

"postbuild": "npm run loop-test-js"
}
}
36 changes: 27 additions & 9 deletions src/events/internal-events.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,52 @@
import type {ISystem} from "../system/system.spec.ts";
import type {TObjectProto} from "../_.spec.ts";
import type {IIStateProto} from "../state/state.spec.ts";
import type {IIStateProto, IState} from "../state/state.spec.ts";


class SimECSPDAEvent {
export class SimECSEvent {}

class SimECSPDAEvent extends SimECSEvent {
constructor(
public readonly state: Readonly<IState> | undefined,
) { super() }
}

export class SimECSPDAPopStateEvent extends SimECSPDAEvent {
constructor(
public readonly state: Readonly<IIStateProto>
) {}
public readonly oldState: Readonly<IState> | undefined,
public readonly newState: Readonly<IState> | undefined,
) {
super(newState);
}
}

export class SimECSPDAPushStateEvent extends SimECSPDAEvent {}
export class SimECSPDAPushStateEvent extends SimECSPDAEvent {
constructor(
public readonly oldState: Readonly<IState> | undefined,
public readonly newState: Readonly<IState>,
) {
super(newState);
}
}


class SimECSResourceEvent<T extends TObjectProto> {
class SimECSResourceEvent<T extends TObjectProto> extends SimECSEvent {
constructor(
public resourceType: T,
public resourceObject: InstanceType<T>,
) {}
) { super() }
}

export class SimECSAddResourceEvent<T extends TObjectProto> extends SimECSResourceEvent<T> {}
export class SimECSReplaceResourceEvent<T extends TObjectProto> extends SimECSResourceEvent<T> {}


class SimECSSystemResourceEvent {
class SimECSSystemResourceEvent extends SimECSEvent{
constructor(
public readonly system: Readonly<ISystem>,
public readonly paramName: string,
public readonly resource: Readonly<TObjectProto>,
) {}
) { super() }
}

export class SimECSSystemAddResource extends SimECSSystemResourceEvent {}
Expand Down
13 changes: 10 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// Polyfills

// @ts-ignore
Symbol.dispose ??= Symbol('Symbol.dispose');
// @ts-ignore
Symbol.asyncDispose ??= Symbol('Symbol.asyncDispose');


// Import all

export * from './ecs/ecs-entity.ts';
export * from './ecs/ecs-query.ts';
export * from './ecs/ecs-sync-point.ts';
Expand All @@ -7,13 +17,10 @@ export * from './entity/entity-builder.ts';
export * from './query/query.ts';
export * from './events/event-bus.ts';
export * from './pda/sim-ecs-pda.ts';

// Scheduler exports
export * from './scheduler/scheduler.ts';
export * from './scheduler/pipeline/pipeline.ts';
export * from './scheduler/pipeline/stage.ts';
export * from './scheduler/pipeline/sync-point.ts';

export * from './serde/serde.ts';
export * from './serde/serial-format.ts';
export * from './state/state.ts';
Expand Down
15 changes: 14 additions & 1 deletion src/pda/pda.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,22 @@ import type {TTypeProto} from "../_.spec.ts";

export interface IPushDownAutomaton<T> {
readonly state?: T

/**
* Clear the PDA by GC-ing all entries
*/
clear(): void

/**
* Remove the current state from the stack and return it
*/
pop(): T | undefined
push<P extends TTypeProto<T>>(state: P): void

/**
* Put a new state on the stack and return a ref to the created instance
* @param state
*/
push<P extends TTypeProto<T>>(state: P): T
}

export type TPushDownAutomatonProto<T> = { new(): IPushDownAutomaton<T> };
Expand Down
4 changes: 3 additions & 1 deletion src/pda/pda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ export class PushDownAutomaton<T> implements IPushDownAutomaton<T> {
return oldTail.state;
}

push<P extends TTypeProto<T>>(State: P): void {
push<P extends TTypeProto<T>>(State: P): T {
this.currentState = new State();
this.statesTail = {
prevNode: this.statesTail,
state: this.currentState,
};

return this.currentState;
}
}
35 changes: 28 additions & 7 deletions src/pda/sim-ecs-pda.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
import {PushDownAutomaton} from "./pda.ts";
import type {IRuntimeWorld} from "../world/runtime/runtime-world.spec.ts";
import type {TTypeProto} from "../_.spec.ts";
import {SimECSPDAPushStateEvent} from "../events/internal-events.ts";
import {SimECSPDAPopStateEvent, SimECSPDAPushStateEvent} from "../events/internal-events.ts";
import type {IState} from "../state/state.spec.ts";
import type {ITransitionActions} from "../world/actions.spec.ts";

export * from "./pda.ts";

export class SimECSPushDownAutomaton<T extends IState> extends PushDownAutomaton<T> {
export class SimECSPushDownAutomaton<T extends IState> {
#pda = new PushDownAutomaton<T>();

constructor(
protected world: IRuntimeWorld
) {
super();
) {}

get state(): T | undefined {
return this.#pda.state;
}

clear(actions: Readonly<ITransitionActions>): void {
while (this.#pda.state !== undefined) {
this.#pda.pop()!.destroy(actions);
}

this.#pda.clear();
}

async pop(): Promise<T | undefined> {
const oldState = this.#pda.pop();
await this.world.eventBus.publish(new SimECSPDAPopStateEvent(oldState, this.#pda.state))
return oldState as T | undefined;
}

push<P extends TTypeProto<T>>(State: P): Promise<void> {
super.push(State);
return this.world.eventBus.publish(new SimECSPDAPushStateEvent(State));
async push<P extends TTypeProto<T>>(State: P): Promise<T> {
const oldState = this.state;
const newState = this.#pda.push(State);
await this.world.eventBus.publish(new SimECSPDAPushStateEvent(oldState, newState));
return newState;
}
}
20 changes: 19 additions & 1 deletion src/system/system-builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type {ISystemBuilder} from "./system-builder.spec.ts";
import type {ISystem, TSystemFunction, TSystemParameterDesc} from "./system.spec.ts";
import {setRuntimeContext, unsetRuntimeContext} from "./system_context.ts";
import {IRuntimeWorld} from "../world/runtime/runtime-world.spec.ts";
import {RuntimeWorld} from "../world/runtime/runtime-world.ts";
import {ISystemContext} from "./system_context.spec.ts";

export * from "./system-builder.spec.ts";

Expand All @@ -16,11 +20,25 @@ export class SystemBuilder<PARAMDESC extends TSystemParameterDesc> implements IS

build(): Readonly<ISystem<Readonly<PARAMDESC>>> {
const self = this;
const System = class implements Readonly<ISystem<Readonly<PARAMDESC>>> {
const System = class implements Readonly<ISystem<Readonly<PARAMDESC>>>, ISystemContext {
/** @internal */
_context = undefined;
/** @internal */
_handlers = new Map();

readonly name = self.systemName;
readonly parameterDesc = self.parameterDesc;
readonly runFunction = self.runFunction;
readonly setupFunction = self.setupFunction;

get runtimeContext(): IRuntimeWorld | undefined {
return this._context;
}

/** @internal */
setRuntimeContext = setRuntimeContext;
/** @internal */
unsetRuntimeContext = unsetRuntimeContext;
};

Object.defineProperty(System, 'name', {
Expand Down
22 changes: 21 additions & 1 deletion src/system/system.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type {ISystemActions} from "../world/actions.spec.ts";
import {systemEventReaderSym, systemEventWriterSym, systemResourceTypeSym, systemRunParamSym} from "./_.ts";
import type {IEventReader} from "../events/event-reader.spec.ts";
import type {IEventWriter} from "../events/event-writer.spec.ts";
import type {IRuntimeWorld} from "../world/runtime/runtime-world.spec.ts";
import {type RuntimeWorld} from "../world/runtime/runtime-world.ts";

export type TSystemParameter =
IEntitiesQuery
Expand All @@ -18,10 +20,28 @@ export type TSystemFunction<PDESC extends TSystemParameterDesc> = (params: Reado
export interface ISystem<PDESC extends TSystemParameterDesc = TSystemParameterDesc> {
/** @internal */
[systemRunParamSym]?: Readonly<PDESC>

readonly name: string
readonly parameterDesc: Readonly<PDESC>
readonly parameterDesc: PDESC
readonly runFunction: TSystemFunction<Readonly<PDESC>>
readonly runtimeContext: IRuntimeWorld | undefined
readonly setupFunction: TSystemFunction<Readonly<PDESC>>

/**
* Set world in which the System will be executed.
* This will be used to register event readers for speedy cache-syncs
*
* @internal
* @param world
*/
setRuntimeContext(world: IRuntimeWorld): void

/**
* Unset the world in which the system was executed.
*
* @internal
*/
unsetRuntimeContext(world: IRuntimeWorld): void
}

export interface ISystemResource<T extends object> {
Expand Down
12 changes: 12 additions & 0 deletions src/system/system_context.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type {IRuntimeWorld} from "../world/runtime/runtime-world.spec";
import type {SimECSEvent} from "../events/internal-events.ts";
import type {TTypeProto} from "../_.spec.ts";
import type {TSubscriber} from "../events/_.ts";

/** @internal */
export interface ISystemContext {
/** @internal */
_context: IRuntimeWorld | undefined
/** @internal */
_handlers: Map<TTypeProto<SimECSEvent>, TSubscriber<TTypeProto<SimECSEvent>>>
}
35 changes: 35 additions & 0 deletions src/system/system_context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {ISystem} from "./system.spec";
import {
SimECSReplaceResourceEvent,
} from "../events/internal-events.ts";
import {RuntimeWorld} from "../world/runtime/runtime-world.ts";
import {TObjectProto, TTypeProto} from "../_.spec.ts";
import {ISystemContext} from "./system_context.spec.ts";
import {TSubscriber} from "../events/_.ts";


export function setRuntimeContext(this: ISystem & ISystemContext, context: RuntimeWorld): void {
{
const handler: TSubscriber<TTypeProto<SimECSReplaceResourceEvent<TObjectProto>>> = handleSimECSReplaceResourceEvent.bind(this);
this._handlers.set(SimECSReplaceResourceEvent, handler);
context.eventBus.subscribe(SimECSReplaceResourceEvent, handler);
}

this._context = context;
}

export function unsetRuntimeContext(this: ISystem & ISystemContext, context: RuntimeWorld): void {
let handler;
for (handler of this._handlers) {
context.eventBus.unsubscribe(handler[0], handler[1]);
}

this._context = undefined;
}


function handleSimECSReplaceResourceEvent(this: ISystem, event: Readonly<SimECSReplaceResourceEvent<TObjectProto>>) {
Object.entries(this.parameterDesc)
.filter(param => param[1] instanceof event.resourceType)
.forEach(param => this.parameterDesc[param[0]] = event.resourceObject);
}

0 comments on commit ae28821

Please sign in to comment.