C/C++ plugin SDK
Native plugins build against the Plugin SDK only: a plain C ABI with versioned function tables and a header-only C++ layer, with any compiler, C runtime and configuration.
The C ABI
Kroys Plugin SDK - C ABI (version 2.2).
The only header a native plugin needs. Plain C: fixed-width integers, floats, UTF-8 strings, plain structs, opaque handles and C function pointers. No STL, Dear ImGui or CRT objects cross the boundary, so a plugin builds with any compiler, C runtime and configuration (Docs/Architecture/PluginSDK.md).
A module exports two functions (KROYS_PLUGIN_EXPORT, C linkage):
int32_t KroysPlugin_GetModuleInfo(KroysModuleInfo* info); KroysResult KroysPlugin_Start(const KroysHost* host, KroysPluginCallbacks* callbacks);
The host calls Start once per target the module serves (editor, runtime). Start registers extensions through the host tables and fills callbacks.
Versioning: minor versions only append members to tables and structs. Every table and struct that crosses the boundary starts with structSize; KROYS_API_HAS checks an optional member. Memory: the host copies every input during the call; host strings stay valid until the next host call on the same thread; nothing is freed across the boundary. Threads: main thread unless a function or callback says otherwise. Errors: functions return KroysResult (0 = success) and set core->LastError. Never let an exception leave a callback.
HelloPlugin.c
static const KroysHost* gHost = 0; static void KROYS_CALL Greet(void* userData) { (void)userData; gHost->core->Log(gHost->context, KROYS_SEVERITY_INFO, "Hello from C."); } KROYS_PLUGIN_EXPORT int32_t KROYS_CALL KroysPlugin_GetModuleInfo(KroysModuleInfo* info) { if (info == 0) return 0; info->structSize = (uint32_t)sizeof(KroysModuleInfo); info->targets = KROYS_TARGET_EDITOR; info->sdkVersion.major = KROYS_SDK_VERSION_MAJOR; info->sdkVersion.minor = KROYS_SDK_VERSION_MINOR; info->sdkVersion.patch = KROYS_SDK_VERSION_PATCH; info->pluginId = "HelloC"; info->pluginVersion = "1.0.0"; return 1; } KROYS_PLUGIN_EXPORT KroysResult KROYS_CALL KroysPlugin_Start(const KroysHost* host, KroysPluginCallbacks* callbacks) { KroysCommandDesc command; KroysCommandCallbacks commandCallbacks; KroysHandle handle = 0u; (void)callbacks; if (host == 0 || host->editor == 0) return KROYS_E_UNSUPPORTED; gHost = host; memset(&command, 0, sizeof(command)); command.structSize = (uint32_t)sizeof(command); /* lets newer engines read older plugins */ command.id = "Greet"; command.label = "Say Hello (C)"; memset(&commandCallbacks, 0, sizeof(commandCallbacks)); commandCallbacks.structSize = (uint32_t)sizeof(commandCallbacks); commandCallbacks.Execute = &Greet; return host->editor->RegisterCommand(host->context, &command, &commandCallbacks, &handle); }
Conventions
| Member | Meaning |
|---|---|
structSize | Size of this struct as the writer compiled it (sizeof); the reader uses it to detect members appended by later minor versions. |
reserved | Padding reserved for later use; leave it 0. |
userData | Plugin-owned pointer passed back unchanged to every callback of this table; the host never dereferences it. |
jobContext | Host-owned job pointer; pass it unchanged to the job's functions. |
sinkContext | Host-owned sink pointer; pass it unchanged to Write. |
Members marked since 2.1 were appended in that minor version: check them with KROYS_API_HAS(Type, pointer, Member) when the plugin may run on an older engine.
The C++ layer
Kroys Plugin SDK - C++ convenience layer (header-only, C++17 or newer).
Compiled into the plugin, so it may use the standard library freely; it only calls the C ABI tables of kroys_plugin.h and never changes the ABI. It offers:
kroys::Plugin base class (OnLoad / OnUnload / OnWorldStarted / OnWorldStopping) kroys::Host typed registration with lambdas, std::string results, kroys::Result kroys::Ui the editor UI API with RAII scopes (Section, Table, Tree, Id, Disabled) kroys::World scene access on a world (editor document or a running game) KROYS_PLUGIN(Class, "id", "version", targets) the two module exports
Every callback trampoline catches exceptions and reports them to the host (core->ReportFailure), which disables the plugin for the session: exceptions never cross the boundary. Closures registered through a Host live until that Host (one per plugin instance and target) is destroyed, after the host has removed every registration and called OnUnload.
KROYS_PLUGIN
Declares the module exports for a kroys::Plugin subclass with a default constructor:
KROYS_PLUGIN(MyPlugin, "MyCompany.MyPlugin", "1.0.0", KROYS_TARGET_EDITOR)
targets: KROYS_TARGET_EDITOR, KROYS_TARGET_RUNTIME or both (|).
HelloPlugin.cpp
class Hello final : public kroys::Plugin { public: bool OnLoad(kroys::Host& host) override { host_ = &host; kroys::CommandOptions greet{ "Greet", "Say Hello" }; greet.toolbar = true; kroys::PanelOptions panel{ "Panel", "Hello" }; return host.AddCommand(greet, [this] { host_->Notify(KROYS_SEVERITY_INFO, "Hello", text_); }) != 0u && host.AddPanel(panel, [this](const kroys::Ui& ui, const KroysDrawArgs&) { if (kroys::Ui::Section section{ ui, "Greeting" }) { ui.InputText("Text", text_); if (ui.Button("Say Hello", KROYS_UI_BUTTON_PRIMARY)) host_->Execute("Hello.Greet"); } }) != 0u; } private: kroys::Host* host_ = nullptr; std::string text_ = "Hello!"; }; KROYS_PLUGIN(Hello, "Hello", "1.0.0", KROYS_TARGET_EDITOR | KROYS_TARGET_RUNTIME)
C: Basics
C: Basic types
C: Values
C: Module entry
C: Core (all targets)
C: Scene (all targets; permission scene.read / scene.write)
C: Tasks (editor)
C: UI (editor; valid only inside draw callbacks)
C: Editor
C: Viewport (editor, 2.1; capability viewport-tools)
C: Runtime (system graph)
C: Assets
C: Loopback networking (editor; permission network.loopback)
C: Host
C++ classes
Generated from the comments of kroys/kroys_plugin.h and kroys/plugin.hpp by Tools/BuildDocsSite.py. Every struct member, function pointer, enum value and public C++ member is documented.