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.

Functions

  1. dlopen - returns a void* handle given a path to the library*
  2. dlerror - returns a char* with the latest error
  3. dlclose - closes the library given the handle**
  4. 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

dlsym

There are currently 3 definitions of dlsym, all of them take a handle and a name

  1. Standard dlsym that returns a void* and only takes a handle and a name
  2. std::function variant that assigns the void* from dlsym to an std::function
  3. The templated variant, which casts the void* to the specified template type

Here 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;

Example of full URLL usage

This is an extract from the auto-generated main file for the modded executable

#ifdef _WIN32
    void* handle = URLL::dlopen("Modlib.dll");
#else
    // That https://madladsquad.com/ is required on unix systems
    void* handle = URLL::dlopen("https://madladsquad.com/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);