C++ modules and hot reload
A Vilanel project does not need any C++: gameplay is built with visual scripting
and everything else is data. Projects that need native code can add a source
folder containing a C++ module. The editor builds it into a library and reloads
it while the editor keeps running.
C++ is used instead of an embedded scripting language because the engine itself is written in C++. One language means one debugger, and nothing extra to keep in sync between the engine and the game code.
Building a module
A project's source/CMakeLists.txt finds the engine as a CMake package and
declares a game module. The engine provides a helper that makes the module match
the engine's build settings: the C++ runtime library, the C++ standard, and
runtime type information being disabled.
The editor and the packager each build the module for their own configuration.
What a module can contain
A module can define actor classes in C++, with begin play, tick, fixed tick and
end play functions, and .vactor assets can use them as their parent class. It
can also define its own components and systems, which are functions that run on
every matching object each tick, in a defined order.
A module cannot keep function pointers or callbacks across a reload, because they would point into the old library after it is unloaded. For the same reason, modules cannot add anything to the editor's user interface.
How reloading works
When a module is reloaded, the engine saves the values of every object the module created, unloads the old library, loads the new one, and rebuilds the objects with their saved values. The rebuilt objects use the new code.
- Fields that still exist with the same name and type keep their values.
- New fields start with their default values.
- Removed fields are dropped, and fields whose type has changed are reset.
- Strings, lists and nested structures are carried over correctly.
Components and classes registered by the module are removed automatically before the old library is unloaded, and registered again by the new one.
Types are identified by a hash of their name rather than by the compiler's type information, which becomes invalid once the old library is unloaded.
Undo history
The undo history is cleared when a module reloads and when a level is loaded, because it may refer to types or objects that no longer exist.
Version checks
When a module loads, the engine checks that it was built for the same engine interface version and with the same standard library, since Debug and Release builds use different ones. A mismatch is reported as a clear error instead of causing a crash later. The Hub makes sure each project opens with the engine version it was made for.
Limitations
A crash in C++ module code also takes down the editor. Visual scripts are safer: an error in a graph stops that graph and reports the problem, and the editor keeps running.