Skip to content

Commit

Permalink
wip add macros for exporting functions via events
Browse files Browse the repository at this point in the history
  • Loading branch information
matcool committed Feb 1, 2025
1 parent 6cb2662 commit ea35c76
Showing 1 changed file with 87 additions and 5 deletions.
92 changes: 87 additions & 5 deletions loader/include/Geode/loader/Dispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ namespace geode {
protected:
std::string m_id;
std::tuple<Args...> m_args;

public:
DispatchEvent(std::string const& id, Args... args)
: m_id(id), m_args(std::make_tuple(args...)) {}
DispatchEvent(std::string const& id, Args... args) :
m_id(id), m_args(std::make_tuple(args...)) {}

std::tuple<Args...> getArgs() const {
return m_args;
}
Expand Down Expand Up @@ -61,6 +61,88 @@ namespace geode {
}

DispatchFilter(std::string const& id) : m_id(id) {}

DispatchFilter(DispatchFilter const&) = default;
};
}
}

// - Macros for exporting functions via events -

// You can use these to easily export functions to other mods
// without being a required depedency.
// # Example Usage:
/*
```
// (In your api distributed header file)
#pragma once
#include <Geode/loader/Dispatch.hpp>
// You must **manually** declare the mod id, as macros like GEODE_MOD_ID will not
// behave correctly to other mods using your api.
#define MY_MOD_ID "dev.my-api"
namespace api {
// Important: The function must be declared inline, and return a geode::Result,
// as it can fail if the api is not available.
inline geode::Result<int> addNumbers(int a, int b) GEODE_EVENT_EXPORT(&addNumbers, (a, b));
}
```
*/
// Then, in **one** of your source files, you must define the exported functions:
/*
```
// MUST be defined before including the header.
#define GEODE_DEFINE_EVENT_EXPORTS
#include "../include/api.hpp"
Result<int> api::addNumbers(int a, int b) {
return Ok(a + b);
}
```
*/

// once this is set in stone we should not change it ever
#define GEODE_EVENT_EXPORT_ID_FOR(fnPtrStr, callArgsStr) \
(std::string(MY_MOD_ID "/") + (fnPtrStr[0] == '&' ? (fnPtrStr + 1) : fnPtrStr))

#define GEODE_EVENT_EXPORT_CALL(fnPtr, callArgs, eventID) \
{ \
static decltype(fnPtr) _functionStorage = [] { \
decltype(fnPtr) ptr = nullptr; \
geode::DispatchEvent<decltype(fnPtr)*>(eventID, &ptr).post(); \
return ptr; \
}(); \
if (!_functionStorage) return geode::Err("Unable to call method"); \
return _functionStorage callArgs; \
}

#define GEODE_EVENT_EXPORT_DEFINE(fnPtr, callArgs, eventID) \
; \
$execute { \
using Type = decltype(fnPtr); \
new geode::EventListener( \
+[](Type* ptr) { \
*ptr = fnPtr; \
return geode::ListenerResult::Stop; \
}, \
geode::DispatchFilter<Type*>(eventID) \
); \
}

#ifndef GEODE_DEFINE_EVENT_EXPORTS

#define GEODE_EVENT_EXPORT(fnPtr, callArgs) \
GEODE_EVENT_EXPORT_CALL(fnPtr, callArgs, GEODE_EVENT_EXPORT_ID_FOR(#fnPtr, #callArgs))

#define GEODE_EVENT_EXPORT_ID(fnPtr, callArgs, eventID) \
GEODE_EVENT_EXPORT_CALL(fnPtr, callArgs, eventID)

#else

#define GEODE_EVENT_EXPORT(fnPtr, callArgs) \
GEODE_EVENT_EXPORT_DEFINE(fnPtr, callArgs, GEODE_EVENT_EXPORT_ID_FOR(#fnPtr, #callArgs))

#define GEODE_EVENT_EXPORT_ID(fnPtr, callArgs, eventID) \
GEODE_EVENT_EXPORT_DEFINE(fnPtr, callArgs, eventID)

#endif

0 comments on commit ea35c76

Please sign in to comment.