Sanable Engine

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

This was originally a class project, but it has since evolved. The hot-reload feature the engine is named for is made possible by memory pools and a custom, detailed reflection system in the style of C#. Pooling also enables cache-friendly update and render calls. I’ve gradually grafted in systems from my other projects, such as an asset management system similar to Unity’s Addressables.

Memory pooling makes almost every advanced feature of this project possible. 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 and objects may resize, invalidating any pointers.

Solving hot-reloading proved quite challenging and required me to research memory layouts, compiler design, and code generation. I’ve split it into a separate post to keep this as an overview. Click here for more information.

Components inherit interfaces to mark themselves as receivers for render and update calls. While memory pools already keep the data cache-friendly, Sanable also optimizes code for the CPU cache by batching calls per-class. For example, all RectangleColliders might be told to update, then all PlayerControllers, regardless of initialization order. This is made possible by the reflection system originally built for hot reloading.

Sanable is capable of code and resource streaming, inspired by smart pointers. Assets such as texture sheets and sounds are loaded only when needed, and can be unloaded soon as all objects release them. Almost every referenceable asset is a descriptor file, which also specifies any dependencies, such as a sprite needing the texture sheet it is contained in. SDL’s modules (video, image io, input) are also handled this way.

An precursor to Sanable included a number of features I am still working to graft. It had a logging system with timestamps and color coded log levels for easier debugging, an input system supporting polling and two kinds of push architectures, and a similar resource streaming system. To field-test it, I implemented 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.