Closed smallka closed 2 years ago
I wanted to get events into sim-ecs for quiet a while, and I have been thinking about ways to make them a reality. sim-ecs is not built the same way bevy_ecs works (for a number of reasons), so there are some design concerns I have and I can't find a good solution. So, let me just brainstorm:
Option 1 ReadEvent and WriteEvent are part of the regular IAccessQuery interface, but Read only triggers the query when there is an event / the query only has data when there is an event
class MyEvent {
constructor(
public message: string,
) {}
}
const query = new Query({
event: ReadEvent(MyEvent),
eventWriter: WriteEvent(MyEvent),
});
for (const {eventReader, eventWriter} of query.iter()) {
console.log(event.message); // <- ref is constant for all items in query
setTimeout(eventWriter.send(new MyEvent('Hello World')), 100); // <- ref is constant for all items in query
}
Option 2 Expose a new interface IEventSystem, which is a special System interface for handling events without touching the current Query APIs
class MyEvent {
constructor(
public message: string,
) {}
}
class MyEventSystem<T extends MyEvent> extends EventSystem<T> {
readonly query = new Query({ counterObj: Write(Counter) });
run(actions: ISystemActions, event: T) {
console.log(event.message);
actions.sendEvent(new MyEvent('Hello World'));
}
}
Option 3 Implement an API on the world interfaces which allows manually polling events at any point
class MyEvent {
constructor(
public message: string,
) {}
}
class MySystem extends System {
readonly query = new Query({ counterObj: Write(Counter) });
run(actions: ISystemActions) {
for (const event of actions.getEvents(MyEvent)) {
console.log(event.message);
}
actions.sendEvent(new MyEvent('Hello World'));
}
}
Option 4 We go ahead with stageless, centralized pipeline planning, PLUS implement a system builder, which gets rid of the class boilerplate and makes systems look like a configurable function - which would work more like bevy_ecs.
// this is fantasy code!
class MyEvent {
constructor(
public message: string,
) {}
}
const MySystem = System
.withParams([
new Query({
counterObj: Read(Counter),
}),
EventWriter(MyEvent),
EventReader(MyEvent),
ReadResource(GlobalStore),
WriteResource(SomethingEelse),
// ...
])
.build((query, eventWriter, eventReader, globalStore, somethingElse) => {
if (eventReader.empty()) return;
for (const event of eventReader.events()) {
console.log(event.message);
}
eventWriter.send(new MyEvent('Hello World'));
query.execute(({counterObj}) => {
// ...
});
});
After creating a PoC with option 4, it seems to be a good move forward, so I will implement centralized pipelines, now, and after that work on stageless, System builder and finally events. Might take a while, but I'll try to work on it quickly and release it as a package in 0.5.0
Merged in #43 and will be part of v0.5
refer to bevy: https://github.com/bevyengine/bevy/blob/latest/examples/ecs/event.rs