inter mod communication

This commit is contained in:
madeline
2026-04-23 04:49:21 -07:00
parent 975ab1dc54
commit 53573eb795
3 changed files with 59 additions and 1 deletions
+37 -1
View File
@@ -16,7 +16,8 @@ Mods are shared libraries packaged into a `.dusk` zip archive. The loader scans
- [Post-hooks](#post-hooks)
- [Replace hooks](#replace-hooks)
- [Reading and writing arguments](#reading-and-writing-arguments)
9. [Full Example](#full-example)
9. [Inter-Mod Communication](#inter-mod-communication)
10. [Full Example](#full-example)
---
@@ -98,6 +99,8 @@ The `api` pointer is valid for the lifetime of the mod. When using `hook.hpp`, c
| `register_tab_content` | Add a panel to the mod manager's per-mod tab |
| `register_menu_item` | Add an item to the quick-access menu |
| `hook_dispatch_pre` / `hook_dispatch_post` | Called by the trampoline, do not call directly |
| `service_publish` | Register a named pointer in the global service registry |
| `service_get` | Look up a named pointer registered by another mod |
---
@@ -248,6 +251,39 @@ dusk::hookAddPre<&daEnemy_c::takeDamage>(on_takeDamage_pre);
For reference parameters (e.g. `const cXyz& pos`), use `argRef<cXyz>` to get a direct reference.
---
## Inter-Mod Communication
Mods can expose a public API to each other through a global service registry. The convention for names is `"mod_name/service_name"`.
**Mod A — publishing:**
```cpp
struct MyModAPI {
void (*do_thing)(int value);
};
static void my_do_thing(int value) { ... }
static MyModAPI g_api = { my_do_thing };
extern "C" void mod_init(DuskModAPI* api) {
api->service_publish("my_mod/api", &g_api);
}
```
**Mod B — consuming:**
```cpp
#include "my_mod_api.h"
static MyModAPI* g_my_mod = nullptr;
extern "C" void mod_init(DuskModAPI* api) {
g_my_mod = static_cast<MyModAPI*>(api->service_get("my_mod/api"));
}
```
---
## Full Example
+3
View File
@@ -38,6 +38,9 @@ typedef struct DuskModAPI {
bool (*hook_dispatch_pre) (void* fn_addr, void* args);
void (*hook_dispatch_post)(void* fn_addr, void* args);
void (*service_publish)(const char* name, void* ptr);
void* (*service_get) (const char* name);
} DuskModAPI;
void mod_init(DuskModAPI* api);
+19
View File
@@ -6,6 +6,7 @@
#include <cstdarg>
#include <filesystem>
#include <string>
#include <unordered_map>
#include "imgui.h"
#include "miniz.h"
@@ -59,6 +60,7 @@ static constexpr const char* k_libExt = ".so";
#endif
static dusk::LoadedMod* g_currentMod = nullptr;
static std::unordered_map<std::string, void*> g_services;
namespace dusk {
void* g_dusk_hook_current_mod = nullptr;
@@ -134,6 +136,20 @@ static void cb_register_tab_content(void (*draw_fn)(void*), void* userdata) {
g_currentMod->tab_content.push_back({draw_fn, userdata});
}
static void cb_service_publish(const char* name, void* ptr) {
if (name) {
g_services[name] = ptr;
}
}
static void* cb_service_get(const char* name) {
if (!name) {
return nullptr;
}
auto it = g_services.find(name);
return it != g_services.end() ? it->second : nullptr;
}
static void cb_register_menu_item(void (*draw_fn)(void*), void* userdata) {
if (g_currentMod && draw_fn)
g_currentMod->menu_items.push_back({draw_fn, userdata});
@@ -174,6 +190,8 @@ void ModLoader::buildAPI(LoadedMod& mod) {
mod.api.hook_replace = api_hook_replace;
mod.api.hook_dispatch_pre = hookDispatchPre;
mod.api.hook_dispatch_post = hookDispatchPost;
mod.api.service_publish = cb_service_publish;
mod.api.service_get = cb_service_get;
}
void ModLoader::tryLoadDusk(const std::filesystem::path& modPath) {
@@ -365,6 +383,7 @@ void ModLoader::shutdown() {
}
}
m_mods.clear();
g_services.clear();
DuskLog.info("ModLoader: all mods unloaded");
}