Sharing Resources Between Addons
Updated 21 October, 2026
Shared resources, called DataLink in the API, are named blocks of memory that Nexus allocates and any addon can look up by name. Nexus uses them to share the game's MumbleLink data and its own state, and addons use them to publish data or functions to other addons. This guide shows how to read the built-in resources, how to share your own, and how to do it without crashing other addons when yours is unloaded.
Reading a shared resource
DataLink_Get returns a pointer to the resource with the given name, or nullptr if nobody has shared it yet:
static NexusLinkData_t* s_NexusLink = nullptr;
static Mumble::Data* s_MumbleLink = nullptr;
void AddonLoad(AddonAPI_t* aApi)
{
APIDefs = aApi;
s_NexusLink = (NexusLinkData_t*)APIDefs->DataLink_Get(DL_NEXUS_LINK);
s_MumbleLink = (Mumble::Data*)APIDefs->DataLink_Get(DL_MUMBLE_LINK);
}
The pointer stays valid until the game closes, so you only need to look it up once. The memory behind it is updated in place.
Resources shared by Nexus
| Name | Type | Contains |
|---|---|---|
DL_NEXUS_LINK |
NexusLinkData_t |
Screen size, interface scaling, whether the player or camera is moving, whether the player is in gameplay (not in a loading screen or character select), and the game's fonts. |
DL_MUMBLE_LINK |
Mumble::Data |
The game's MumbleLink data: avatar and camera position, map, combat state, mount, compass and more. |
DL_MUMBLE_LINK_IDENTITY |
Mumble::Identity |
The MumbleLink identity, already parsed from its JSON string: character name, profession, specialization, map, commander tag, field of view and interface size. |
NexusLinkData_t is defined in Nexus.h. The Mumble types come from the RCGG-lib-mumble-api header. Nexus also supports multiboxing setups where the game is started with a custom -mumble name, so reading MumbleLink through Nexus is more reliable than opening the shared memory yourself.
The game updates MumbleLink continuously, and the identity changes rarely. Instead of comparing it every frame, subscribe to EV_MUMBLE_IDENTITY_UPDATED, see Event Handling.
Sharing your own data
DataLink_Share allocates a resource of the given size and returns a pointer you can write to. The memory starts zeroed.
#define DL_MYADDON_STATE "DL_MYADDON_STATE"
struct MyAddonState_t
{
uint32_t Version; /* Increase when the layout changes. */
uint32_t ActiveTimers;
float NextTimerIn;
};
static MyAddonState_t* s_State = nullptr;
void AddonLoad(AddonAPI_t* aApi)
{
APIDefs = aApi;
s_State = (MyAddonState_t*)APIDefs->DataLink_Share(DL_MYADDON_STATE, sizeof(MyAddonState_t));
if (s_State)
{
s_State->Version = 1;
}
}
- If a resource with that name already exists with the same size, you get the existing pointer, including its current contents. This is what happens when your addon is reloaded.
- If it exists with a different size, you get
nullptrand a warning in the log. Always check the result. - Resources cannot be freed. They stay allocated until the game closes, which is what keeps pointers held by other addons valid.
Since resources survive reloads, they are also a convenient place to keep runtime state that should outlive a reload during development, see Understanding the Nexus Addon Lifecycle.
Keeping the layout stable
Other addons are compiled against your struct definition. If you change it, they read garbage. Follow the same rules as for any binary interface:
- Use plain, fixed-size types. No C++ classes, STL containers or pointers to memory that may be freed.
- Start with a version field, and only ever append new members at the end.
- Publish the struct in a small header for other developers.
Reading and writing safely
Nexus does not lock shared resources. Your addon may write while another one reads, on a different thread. Keep it simple: let only the owning addon write, use single values that are read and written in one piece (such as aligned 32-bit integers or std::atomic types) for data that changes often, and accept that readers may see a mix of old and new values in larger structs. If consistency matters, add a sequence counter that the writer increments before and after each update, and have readers retry when it changed.
Sharing functions
A shared struct can contain function pointers, which lets other addons call into yours directly. This is powerful, but function pointers point into your DLL, and they become invalid the moment your addon is unloaded. A caller that uses one after that crashes the game.
struct MyAddonApi_t
{
uint32_t Version;
void (*StartTimer)(uint32_t aSeconds);
};
static MyAddonApi_t* s_Api = nullptr;
void StartTimer(uint32_t aSeconds) { /* ... */ }
void AddonLoad(AddonAPI_t* aApi)
{
APIDefs = aApi;
s_Api = (MyAddonApi_t*)APIDefs->DataLink_Share("DL_MYADDON_API", sizeof(MyAddonApi_t));
if (s_Api)
{
s_Api->Version = 1;
s_Api->StartTimer = StartTimer;
}
}
void AddonUnload()
{
if (s_Api)
{
s_Api->StartTimer = nullptr; /* Must happen before the DLL goes away. */
}
}
Callers have to read the pointer fresh and check it every time they use it, never cache it:
MyAddonApi_t* api = (MyAddonApi_t*)APIDefs->DataLink_Get("DL_MYADDON_API");
if (api && api->Version >= 1 && api->StartTimer)
{
api->StartTimer(30);
}
Even then, a call that is already in progress while the provider unloads can crash. For anything that is not called very frequently, events are the safer way to offer actions to other addons: Nexus removes the handlers of an unloaded addon itself, so an event to an addon that is gone simply does nothing. Another option is to expose actions as keybinds, which other addons can trigger with InputBinds_Invoke.
Access from other programs
Shared resources are backed by named shared memory, so tools outside the game can read them too. The name is the resource name followed by an underscore and the game's process ID, for example DL_MYADDON_STATE_12345. Open it with OpenFileMappingA and MapViewOfFile. This lets you pair an addon with an external companion app, such as a stream overlay, without any networking.