mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-10 12:54:50 -04:00
97 lines
3.7 KiB
C++
97 lines
3.7 KiB
C++
#pragma once
|
|
|
|
#include "mods/api.h"
|
|
|
|
/*
|
|
* The host service: the calling mod's identity and its runtime interface to the loader.
|
|
* Always available; every other service can be reached from it.
|
|
*/
|
|
|
|
#define HOST_SERVICE_ID "dev.twilitrealm.dusklight.host"
|
|
#define HOST_SERVICE_MAJOR 1u
|
|
#define HOST_SERVICE_MINOR 1u
|
|
|
|
/*
|
|
* Ignore unknown values: later service minors may add events.
|
|
*/
|
|
typedef enum ModLifecycleEvent {
|
|
/*
|
|
* The subject mod is gone: its mod_shutdown has run (when it initialized at all) and
|
|
* every service has already dropped the state it held for it. The subject's library is
|
|
* still mapped, so pointers into it are valid to compare against, but they must not be
|
|
* called or dereferenced after the callback returns. Drop everything keyed to the
|
|
* mod: callbacks it registered, its ModContext*, state indexed by it.
|
|
*/
|
|
MOD_LIFECYCLE_DETACHED = 0,
|
|
} ModLifecycleEvent;
|
|
|
|
/*
|
|
* ctx is the watching mod's own context; subject identifies the mod the event is about.
|
|
* subject_id is valid only for the duration of the call.
|
|
*/
|
|
typedef void (*ModLifecycleFn)(ModContext* ctx, ModContext* subject, const char* subject_id,
|
|
ModLifecycleEvent event, void* user_data);
|
|
|
|
typedef struct HostService {
|
|
ServiceHeader header;
|
|
|
|
/*
|
|
* Look up a service by id at call time. Unlike a manifest import, this sees whatever is
|
|
* currently published and carries no initialization-order guarantee (see mods/api.h).
|
|
* MOD_UNAVAILABLE if no matching service is published; *out_service is null on failure.
|
|
*/
|
|
ModResult (*get_service)(ModContext* ctx, const char* service_id, uint16_t major_version,
|
|
uint16_t min_minor_version, const void** out_service);
|
|
|
|
/*
|
|
* Publish a service the calling mod declared as a deferred export in its manifest.
|
|
* Must happen during mod_initialize so importers can resolve it; `service` must stay
|
|
* valid until the mod shuts down.
|
|
*/
|
|
ModResult (*publish_service)(
|
|
ModContext* ctx, const char* service_id, uint16_t major_version, const void* service);
|
|
|
|
/*
|
|
* Report an unrecoverable failure. The calling mod's services stop resolving immediately
|
|
* and the loader fully disables it at the next safe point; `message` is shown to the user.
|
|
* Safe to call from any mod callback.
|
|
*/
|
|
void (*fail)(ModContext* ctx, ModResult code, const char* message);
|
|
|
|
/*
|
|
* The calling mod's manifest metadata. Returned strings remain valid while the mod is
|
|
* loaded.
|
|
*/
|
|
const char* (*mod_id)(ModContext* ctx);
|
|
const char* (*mod_name)(ModContext* ctx);
|
|
const char* (*mod_version)(ModContext* ctx);
|
|
|
|
/*
|
|
* A writable scratch directory reserved for the calling mod. Contents survive disable
|
|
* and reload within a session, but the directory is wiped at game startup.
|
|
*/
|
|
const char* (*mod_dir)(ModContext* ctx);
|
|
|
|
/*
|
|
* Observe other mods' lifecycle events. Any mod whose service hands out per-caller state
|
|
* (registrations, callbacks, handles) should watch for MOD_LIFECYCLE_DETACHED and drop what it
|
|
* holds for the subject.
|
|
*
|
|
* Callbacks fire on the game thread at a lifecycle safe point (never mid-frame), for
|
|
* every mod but the watcher itself (use mod_shutdown for self-cleanup).
|
|
*/
|
|
ModResult (*watch_mod_lifecycle)(
|
|
ModContext* ctx, ModLifecycleFn fn, void* user_data, uint64_t* out_handle);
|
|
ModResult (*unwatch_mod_lifecycle)(ModContext* ctx, uint64_t handle);
|
|
} HostService;
|
|
|
|
#ifdef __cplusplus
|
|
#include "mods/service.hpp"
|
|
|
|
template <>
|
|
struct dusk::mods::ServiceTraits<HostService> {
|
|
static constexpr const char* id = HOST_SERVICE_ID;
|
|
static constexpr uint16_t major_version = HOST_SERVICE_MAJOR;
|
|
};
|
|
#endif
|