One of the side effects of adding mod support into the game engine is that we had to build a cross-platform dynamic/shared library loader. This is enabled by the UntitledRuntimeLibraryLoader which we developed. To include it use:
#include <urll/urll.h>
All the functions under the URLL
namespace named and work like in Unix, so they can feel familiar to use. There are also 2 utility functions for ease of use.
dlopen
- returns a void*
handle given a path to the library*dlerror
- returns a char*
with the latest errordlclose
- closes the library given the handle**dlsym
- retrieves a symbol from the library given a name* Due to Windows restrictions dlopen
cannot receive a flag and will always default to lazy loading
** dlclose
closes the library handle, which makes all the memory acquired from dlsym
null
There are currently 3 definitions of dlsym
, all of them take a handle and a name
dlsym
that returns a void*
and only takes a handle and a namestd::function
variant that assigns the void*
from dlsym
to an std::function
void*
to the specified template typeHere are some examples:
dlsym
with std::function
std::function<void(void)> func;
// We check against nullptr or the handle for errors
if (URLL::dlsym(handle, "func", func) == nullptr)
{
return -1;
}
func();
dlsym
with a templated type
void(*func)(void);
// We check against nullptr or the handle for errors
if (URLL::dlsym(handle, "func", func) == nullptr)
{
return -1;
}
func();
regular dlsym
int* a = (int*)URLL::dlsym(handle, "func", func);
// We check against nullptr or the handle for errors
if (a == nullptr)
{
return -1;
}
std::cout << *a << std::endl;
This is an extract from the auto-generated main file for the modded executable
#ifdef _WIN32
void* handle = URLL::dlopen("Modlib.dll");
#else
// That ./ is required on unix systems
void* handle = URLL::dlopen("./libModlib.so");
#endif
bool bCanClose = false;
if (handle != nullptr)
{
bCanClose = true;
if (URLL::dlsym(handle, "modlibbegin", UVK::global.modbegin) == handle && URLL::dlsym(handle, "modlibend", UVK::global.modend) == handle && URLL::dlsym(handle, "modlibtick", UVK::global.modtick) == handle)
logger.consoleLog("Loaded all mods!", UVK_LOG_TYPE_SUCCESS);
else
logger.consoleLog("Failed to load some or all of the initial mod library functions, mod events will not be loaded! Error: ", UVK_LOG_TYPE_WARNING, URLL::dlerror());
}
else
logger.consoleLog("Failed to load the mod library!", UVK_LOG_TYPE_WARNING);
...
dlclose(handle);