Skip to content

Commit 9fee6fb

Browse files
committed
feat: callback manager
1 parent 093492a commit 9fee6fb

3 files changed

Lines changed: 153 additions & 3 deletions

File tree

src/callback/CallbackManager.hpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#include <algorithm>
2+
#include <any>
3+
#include <functional>
4+
#include <iostream>
5+
#include <map>
6+
#include <mutex>
7+
#include <shared_mutex>
8+
#include <string>
9+
#include <tuple>
10+
#include <type_traits>
11+
#include <vector>
12+
13+
namespace primordial_core {
14+
15+
template <typename T>
16+
struct function_traits;
17+
18+
template <typename R, typename... Args>
19+
struct function_traits<R (*)(Args...)> {
20+
using args_type = std::tuple<Args...>;
21+
};
22+
23+
template <typename R, typename... Args>
24+
struct function_traits<std::function<R(Args...)>> {
25+
using args_type = std::tuple<Args...>;
26+
};
27+
28+
template <typename C, typename R, typename... Args>
29+
struct function_traits<R (C::*)(Args...) const> {
30+
using args_type = std::tuple<Args...>;
31+
};
32+
33+
template <typename T>
34+
struct function_traits : public function_traits<decltype(&T::operator())> {};
35+
36+
class CallbackManager {
37+
template <typename... Args>
38+
struct CallbackList {
39+
struct Entry {
40+
int priority;
41+
std::function<void(Args...)> func;
42+
uint64_t id;
43+
44+
static bool compare(const Entry& a, const Entry& b) {
45+
return a.priority > b.priority;
46+
}
47+
};
48+
std::vector<Entry> list;
49+
50+
void add(int p, std::function<void(Args...)> f, uint64_t id) {
51+
list.push_back({p, std::move(f), id});
52+
std::stable_sort(list.begin(), list.end(), Entry::compare);
53+
}
54+
55+
void invoke(Args... args) const {
56+
for (const auto& e : list) {
57+
e.func(args...);
58+
}
59+
}
60+
};
61+
62+
std::map<std::string, std::any> events;
63+
mutable std::shared_mutex mutex;
64+
uint64_t next_id = 0;
65+
66+
template <typename... Args>
67+
void register_impl(const std::string& name, std::function<void(Args...)> f, int p) {
68+
std::unique_lock lock(mutex);
69+
using ListT = CallbackList<Args...>;
70+
71+
if (events.find(name) == events.end()) {
72+
events[name] = ListT{};
73+
}
74+
75+
try {
76+
auto& container = std::any_cast<ListT&>(events[name]);
77+
container.add(p, std::move(f), ++next_id);
78+
} catch (const std::bad_any_cast&) {
79+
throw std::runtime_error("Signature mismatch for event: " + name);
80+
}
81+
}
82+
83+
template <typename Callable, typename... Args>
84+
void deduce_and_register(const std::string& name, Callable&& c, int p, std::tuple<Args...>) {
85+
std::function<void(Args...)> f = std::forward<Callable>(c);
86+
register_impl<Args...>(name, std::move(f), p);
87+
}
88+
89+
public:
90+
template <typename Callable>
91+
void addCallback(const std::string& name, Callable&& cb, int priority = 0) {
92+
using traits = function_traits<std::decay_t<Callable>>;
93+
using ArgsT = typename traits::args_type;
94+
deduce_and_register(name, std::forward<Callable>(cb), priority, ArgsT{});
95+
}
96+
97+
template <typename... Args>
98+
void invokeCallback(const std::string& name, Args&&... args) {
99+
std::shared_lock lock(mutex);
100+
auto it = events.find(name);
101+
if (it == events.end()) {
102+
std::cerr << "Warning: Event '" << name << "' not found\n";
103+
return;
104+
}
105+
106+
using ListT = CallbackList<std::decay_t<Args>...>;
107+
108+
try {
109+
const auto& container = std::any_cast<const ListT&>(it->second);
110+
container.invoke(std::forward<Args>(args)...);
111+
} catch (const std::bad_any_cast&) {
112+
std::cerr << "Error: Invoke arguments do not match stored signature for '" << name << "'\n";
113+
}
114+
}
115+
};
116+
117+
} // namespace primordial_core

src/mod/PrimordialCore.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "mod/PrimordialCore.h"
2+
#include "callback/CallbackManager.hpp"
23

34
#include "ll/api/mod/RegisterHelper.h"
45

@@ -12,6 +13,33 @@ PrimordialCore& PrimordialCore::getInstance() {
1213
bool PrimordialCore::load() {
1314
getSelf().getLogger().debug("Loading...");
1415
// Code for loading the mod goes here.
16+
17+
CallbackManager mgr;
18+
19+
// 添加不同签名的事件
20+
mgr.addCallback(
21+
"OnLogin",
22+
[](std::string user, int age) { std::cout << "[User] " << user << " logged in. Age: " << age << "\n"; },
23+
10
24+
);
25+
26+
mgr.addCallback("OnSystem", [](int code) { std::cout << "Code: " << code << "\n"; });
27+
28+
// 高优先级测试
29+
mgr.addCallback(
30+
"OnLogin",
31+
[](std::string user, int) { std::cout << "[Admin] Priority check for " << user << "\n"; },
32+
100
33+
);
34+
35+
// 调用
36+
std::cout << "--- Triggering Login ---\n";
37+
// 注意:必须显式构造std::string,否则推导为const char*导致类型不匹配
38+
mgr.invokeCallback("OnLogin", std::string("Alice"), 25);
39+
40+
std::cout << "\n--- Triggering System ---\n";
41+
mgr.invokeCallback("OnSystem", 404);
42+
1543
return true;
1644
}
1745

@@ -27,6 +55,12 @@ bool PrimordialCore::disable() {
2755
return true;
2856
}
2957

58+
bool PrimordialCore::unload() {
59+
getSelf().getLogger().debug("Unloading...");
60+
// Code for unloading the mod goes here.
61+
return true;
62+
}
63+
3064
} // namespace primordial_core
3165

3266
LL_REGISTER_MOD(primordial_core::PrimordialCore, primordial_core::PrimordialCore::getInstance());

src/mod/PrimordialCore.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ class PrimordialCore {
2222
/// @return True if the mod is disabled successfully.
2323
bool disable();
2424

25-
// TODO: Implement this method if you need to unload the mod.
26-
// /// @return True if the mod is unloaded successfully.
27-
// bool unload();
25+
// @return True if the mod is unloaded successfully.
26+
bool unload();
2827

2928
private:
3029
ll::mod::NativeMod& mSelf;

0 commit comments

Comments
 (0)