mrrogge / rude

An ECS game engine built for LÖVE2D.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

EventEmitterMixin and determinism

mrrogge opened this issue · comments

The EventEmitterMixin allows a class to be extended with an implementation of the observer pattern. There are a few things about this I'd like to discuss.

First, let's talk about determinism. When I originally started building rude, I thought it would be nice to have scenes be deterministic, or at least effectively deterministic. What I mean is, for a given scene, if you load a given set of entities and components and call update() with a given dt, then the result should always be the same and not depend on any "hidden" state (e.g. globals, internal system data). This would open up a lot of possibilities for testing, both in development and maybe even in production builds.

With EventEmitterMixin, you are essentially allowing behavior to be modified at runtime. If a system registers a new handler in an update() call, future update() calls may result in different data manipulations, thus making that scene non-deterministic. I don't think this is something rude should rely on heavily. Furthermore, having a dedicated mixin for this behavior implies that a user should be applying it to their own classes, and for now there's really no reason anything but the Scene class should be using this.

It's worth noting that it's impossible for us to completely prevent a user from breaking a scene's determinism, due to Lua being such an open language. For example, one could do this:

function Scene:onUpdate(dt)
    if aBadActorAppears then
        Scene.onUpdate = function(dt) print("say goodbye to your updates!") end
    end
end

With all that said, here is what I'm proposing:

  1. EventEmitterMixin goes away. It should no longer be a dedicated mixin class.
  2. Engine should no longer have anything to do with events. For now, I don't see a benefit in having "engine events", however this may change in the future.
  3. Scene should add an emit() method. This should call an onEvent() method that is intended to be overridden by the user. This still gives full control over deciding what happens during certain scene events, and in which order things happen, but it dissuades against changing this behavior at runtime.
  4. Scene can still have the registerEventHandler() method in the class definition. However, it should be clarified in the documentation that this mechanism should be avoided unless absolutely necessary, since it makes testing the scene much harder.