Disclaimer: I'm not 100% sure about any of this, any suggestions or requirements on how to improve it are totally welcome.
https://github.com/jewalky/gzdoom/commi ... eisnospoon — source
http://www.mediafire.com/file/3zxaib4r4f6my96/REL.zip — build + example
0. Technically, this implements the OOP Observer pattern in relation to the engine and not exactly hierarchical 'events' as we know them by various GUI or DOM systems.
0.1. The observers are not planned to be able to interact with each other right now.
1. Subset of Render events was implemented, if this is to be accepted we will have to think about other virtuals that should be there (and do some performance tests, for example I'd want to implement something like "RenderActor" so that it's possible to know what actors were actually rendered during last frame (use-case: "a picture of an angel becomes an angel"), but not sure if calling the VM for every drawn actor won't bring it to a crawl; maybe replace virtual methods with abstract, if possible, so that unimplemented methods aren't called excessively).
1.1. Current implementation allows for sub-gametic and sub-renderframe precision in scripts.
1.2. The generic point is: any EventHandler can override any virtual method (and it will be called), but event-specific handlers have additional data.
2. To run the example, use the GZDoom version from the archive and load EventDemo.pk3,
3. Some things are not done even though planned. For example, MAPINFO-based handler instantiation and addition.
4. Sound doesn't work in my build, make sure that you don't overwrite your normal GZDoom! I don't have FMOD libraries on my PC, and their new website is retarded and requires registration, so I'm too lazy to do it.
5. There are no checks for registering one handler twice, I know about that. And will fix if we agree on this. (and if not, it doesn't matter)
6. By the current architecture, if you want your handler to be gone on map unload, you have to do it manually: MapUnloading + Destroy();. This is because in the future, if we use this for UI, we will need to be disconnected from the map.
6.1. Note that this is not yet implemented ;P The event handlers are destroyed by the GC right now it seems.
7. Statusbar suggestion: permanent class StatusBar : UiEventHandler object that gets created by MAPINFO/GameInfo on engine start, doesn't get removed by map unload and checks for gameaction/gamestate in order to decide current state.
(yes I've seen it in the GZDoom commit history that there are preparations in the repo to move sbar out )
7.1. This raises another problem: serialization of event handlers. We don't want our old statusbar to restore from the savegame, and we don't want our statusbar to be gone if someone loads a savegame that doesn't have it.
(note: read 'statusbar', understand 'anything that has to be global');
What I have in mind right now:
7.2. There should be two kinds of handlers (this is changed dynamically throughout map lifecycle): those defined in MAPINFO, and those created with EventHandler.Create.
7.3. Handlers that are defined in MAPINFO can be only only one per map, trying to EventHandler.Create an instance of a handler that already is loaded using MAPINFO should result in an exception.
7.3.1. Subvariant: I don't see when we might want to have same handler both dynamically and statically, so we can have these "inherit" from StaticEventHandler instead, and somehow make this translate into isStatic boolean in EventHandler structure.
7.4. Handlers that are defined in MAPINFO are implicitly transient: they are not serialized, instead null is written. If one wants to refer to a global handler, they should use EventHandler.Find.
7.5. When the save game is loaded, MAPINFO handlers are recreated based on their settings for the particular map.
7.6. Based on exact place of MAPINFO where handlers were defined (GameInfo or Map section) they will or will not be deleted/recreated on map unload/load.
7.7. Handlers that were temporarily created from the map, on the other side, are serialized along with normal objects and with their references and state fully preserved.
Side note: I needed to provide it an Actor in order to call A_Log.
We desperately need something like Console or System in order to call Printf static method from it.