Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

event system? #34

Closed
smallka opened this issue Oct 7, 2021 · 3 comments
Closed

event system? #34

smallka opened this issue Oct 7, 2021 · 3 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@smallka
Copy link

smallka commented Oct 7, 2021

refer to bevy: https://github.com/bevyengine/bevy/blob/latest/examples/ecs/event.rs

@minecrawler minecrawler added the enhancement New feature or request label Oct 7, 2021
@minecrawler minecrawler added this to the 1.0 milestone Oct 7, 2021
@minecrawler minecrawler added this to To do in New Features via automation Oct 7, 2021
@minecrawler
Copy link
Collaborator

minecrawler commented Nov 22, 2021

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

  • does every data-instance of varying components get the same reference to the event data struct?
  • how do we handle multiple events?
  • sounds inconsistent with regular way queries work
  • might need looping system execution to handle all events
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

  • can only handle one event per system
  • may need looping systems for multiple events
  • extra interface with generics
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

  • forgetting to poll events may lead to constant memory consumption
  • cannot be prepared before the main loop starts
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.

  • I like this approach the most, because it makes systems very flexible
  • also it makes it easier to prepare systems under the hood (resources included!)
  • I got a lot of feedback that people want functions as systems, this is rather close :)
  • (as soon as decorators land, this could be decorated nicely)
// 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}) => {
            // ...
        });
    });

@minecrawler minecrawler self-assigned this Nov 25, 2021
@minecrawler minecrawler moved this from To do to In progress in New Features Nov 25, 2021
@minecrawler
Copy link
Collaborator

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

@minecrawler minecrawler modified the milestones: 1.0, 0.5.0 Nov 25, 2021
@minecrawler
Copy link
Collaborator

Merged in #43 and will be part of v0.5

New Features automation moved this from In progress to Done Jan 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

No branches or pull requests

2 participants