Hot Constants allows you to create hot-reloadable constants in your C++ code. Here's how it works:
- Declare a hot constant with the
HC()macro and assign it a value:
HC(float, playerJumpHeight) = 5.0f;- Use the value in your code like you would any other
constvariable:
playerPosY += playerJumpHeight;- While debugging, change the value in your source file and save it.
[std::cout]
Hot Constants: Reloading file "main.cpp".
Hot Constants: "playerJumpHeight" sucessfully reloaded!
- The value will immediately update in your running program.
In release builds, the HC() macro evaluates to a simple constant declaration, eliminating the reload mechanism in shipping code. This makes it perfectly safe to leave in your project long-term, as there will be zero overhead in shipped code.
[Source file]
HC(float, playerJumpHeight) = 5.0f;
[Preprocessor output in Debug]
const HotConsts::HC_Atomic<float>& playerJumpHeight = HotConsts::_registerHotConst<float>("path/to/source/file", "playerJumpHeight", "float") = 5.0f;
[Preprocessor output in Release]
const float playerJumpHeight = 5.0f;Hot Constants was designed with game development in mind, but it is suitable in any situation where hard-coded values are subject to change. With Hot Constants, you can painlessly test new values on a whim, knowing that they will revert to hard-coded constants in release builds.
- No refactoring needed. You can convert constants into hot constants (and back again) just by changing their declaration*.
- Expression reloading. Hot Constants will automatically evaluate and reload any expression containing literals (e.g.
HC(double, frameDelta) = 1.0 / 60.0is valid code). - Externs. The
HCEX()macro allows you to declare extern hot constants, so you can reload constants across translation units. - Mac and Windows support. HotConsts has been tested on MSVC and Clang on macOS and Windows.
* The one exception to this is template deduction, which will not deduce the base constant type. Manual casting is required in these cases.
When HC_RELOADING_ON is defined, HC() does the following:
- A thread-safe variable is created, and a const reference to it is returned.
- A thread is launched to monitor changes to the source file (if it doesn't already exist).
- When you save changes to the source file, the watcher thread parses the new value and updates the corresponding variable.
On Windows, one thread is used per source file, and on Mac, one is used per source directory. The threads sleep until the OS notifies them of a change: they don't "busy wait".
Hot Constants is powered by CMake. To include it in your CMake project:
- Clone this repository to a subdirectory of your project root.
- Add the HotConsts directory to CMakeLists.txt using
add_subdirectory(). - Link
HotConsts::HotConststo your executable usingtarget_link_libraries(). - Define
HC_RELOADING_ONin your debug builds. - Include
<HotConsts/HotConsts.h>in files where you wish to use hot constants.
Non-CMake users can simply add the source files to their projects directly:
- Add every file in 'src' to your source files, except for "HC_FileWatch_macOS.cpp" on Windows and "HC_FileWatch_Win32.cpp" on Mac.
- Add 'include' to your include path.
- (macOS only) Link to the CoreServices framework.
- (Windows only) Define
UNICODEand_UNICODE(Visual Studio usually does this for you). - Define
HC_RELOADING_ONin your debug builds. - Include
<HotConsts/HotConsts.h>in files where you wish to use hot constants.
- At present, only C++17 projects are supported. Support for C++11 and C++20 will be added if people find it useful.
- Only arithmetic types (integer, char, or floating-point) can be reloaded.
- Hot Constants cannot reload expressions containing other constant names or macros.
- Hot constants declared in explicitly-linked DLL/SO modules have not been tested. Unloading a module containing the
HC()macro may cause unexpected behavior. - The reload mechanism is locking. I can look at reducing locks if it becomes a problem.
- The library is currently static only: I have no plans for a shared/DLL version.
- Character literals containing a space (
' ') are not parsed correctly, and will not reload. - If you accidentally remove a semicolon while tweaking a file, Hot Constants will fail to reload any
HC()macros on the following line. - If an
HC()macro is preceded by a string literal broken across multiple lines with a backslash, it may not reload correctly.
If you wish to work on Hot Constants yourself, a basic test runner is available in 'tests'. In CMake, simply configure a build tree from the root directory, then build and run the "HotConsts_Tester" target from the 'tests' folder.
Hot Constants was inspired by Tweakable Constants, a concept discussed in a post on gamedev.net by Joel Davis, who himself learned it from a lost thread by Casey Muratori on MollyRocket.com.