Sanable Engine

A proof-of-concept framework centered on plugins and seamless hot-reloading in C++. Cross-platform thanks to SDL, including building to web using Emscripten.

This was originally a pair of class projects. The framework for Game Engines & Implementation is the foundation that forms most of Sanable. It uses custom memory pools to track objects, allowing for cache-friendly update and render calls, as well as enabling the hot-reload feature. I used the Game Architecture project significantly less, but did reuse the asset management system.

Memory pooling makes almost every advanced feature of this project possible. The framework is oriented around game objects owning components, which can mark themselves as receivers for render and update calls. Each receiver class is then called in one big batch to better optimize for the CPU cache.

The hot-reload system wouldn’t be possible at all without a way to track all existing objects, which memory pooling handily provides. Plugins are written in pure C++ and compile to DLLs (or .so on linux/web), which makes the problem more difficult. When unloading and reloading a DLL, addresses may change, invalidating any pointers–which most importantly includes virtual function tables. However, almost every compiler stores vtable pointers at the start of the object. Even if we don’t know the type of a vtable, we know all pointers have the same width, so we can overwrite vtable pointers obtained from fresh instances.

This approach won’t work if classes change in size, however. To fix that, we’d have to write reflection information detailing the members of every class, which could easily get tedious and fragile. I’m in the process of implementing a custom build step using Clang’s AST to generate those data structures automatically.

Such data structures would also make serialization easy. I previously had an implementation of saving and loading full levels, but the branch had diverged to the point where merging it in would be more work than re-implementing.

Framework for Game Architecture

The class for this framework was just aimed at building the systems needed to support a game, and was built on Allegro (and later transitioned to SDL). I built it with support for multiple programming styles and a focus on quality of life. For example, the logging system includes timestamps and color coded log levels for easier debugging.

The framework accomplishes two forms of resource streaming through RAII. Reference counting wrappers load assets such as texture sheets and sounds when needed, and can unload them as soon as all objects using that resource release it. Almost every referenceable asset is a descriptor file, which also specifies any other assets it may depend on, such as a sprite needing the texture sheet it is contained in. Allegro’s addons are also handled through RAII, initializing and cleaning up modules like sound and fonts.

The input system receives events from Allegro’s buffer and supports polling for key presses as well as pushing events using both functional hooks and inheritance-based listeners.

To field-test, I implemented a game in the style of Snake with colored console graphics, and a target practice game with full image graphics.

Both the powerups and the snake body segments are treated as their own Unit. Tilemap can be edited through image editing tools.
Dynamic resource loading and unloading is logged to the console. Audio takes a while to load, so it is set to always stay loaded.