Skip to content

Commit c60ee60

Browse files
committed
feat: implement the internal support for event cancellation #285
1 parent 565011c commit c60ee60

File tree

2 files changed

+59
-23
lines changed

2 files changed

+59
-23
lines changed

src/legacy/api/EventAPI.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "api/EventAPI.h"
1+
#include "EventAPI.h"
22

33
#include "BaseAPI.h"
44
#include "BlockAPI.h"
@@ -71,7 +71,7 @@
7171
//////////////////// Listeners ////////////////////
7272

7373
// 监听器表
74-
std::list<ListenerListType> listenerList[int(EVENT_TYPES::EVENT_COUNT)];
74+
std::list<EventListener> listenerList[int(EVENT_TYPES::EVENT_COUNT)];
7575

7676
// 监听器历史
7777
bool hasListened[int(EVENT_TYPES::EVENT_COUNT)] = {false};
@@ -84,31 +84,32 @@ Local<Value> McClass::listen(const Arguments& args) {
8484
CHECK_ARG_TYPE(args[1], ValueKind::kFunction);
8585

8686
try {
87-
return Boolean::newBoolean(
88-
LLSEAddEventListener(EngineScope::currentEngine(), args[0].asString().toString(), args[1].asFunction())
89-
);
87+
auto eventName = args[0].asString().toString();
88+
auto listener = LLSEAddEventListener(EngineScope::currentEngine(), eventName, args[1].asFunction());
89+
return Boolean::newBoolean(listener.has_value());
9090
}
9191
CATCH("Fail to Bind Listener!");
9292
}
9393

9494
//////////////////// Funcs ////////////////////
9595

96-
bool LLSEAddEventListener(ScriptEngine* engine, const string& eventName, const Local<Function>& func) {
96+
optional_ref<EventListener>
97+
LLSEAddEventListener(ScriptEngine* engine, const string& eventName, const Local<Function>& func) {
9798
try {
98-
auto event_enum = magic_enum::enum_cast<EVENT_TYPES>(eventName);
99-
auto eventId = int(event_enum.value());
100-
listenerList[eventId].push_back({engine, script::Global<Function>(func)});
99+
auto event_enum = magic_enum::enum_cast<EVENT_TYPES>(eventName);
100+
auto eventId = int(event_enum.value());
101+
auto& listener = listenerList[eventId].emplace_back(engine, script::Global<Function>(func), *event_enum);
101102
if (!hasListened[eventId]) {
102103
hasListened[eventId] = true;
103104
EnableEventListener(eventId);
104105
}
105-
return true;
106+
return {listener};
106107
} catch (...) {
107108
lse::LegacyScriptEngine::getInstance().getSelf().getLogger().error("Event {} not found!"_tr(eventName));
108109
lse::LegacyScriptEngine::getInstance().getSelf().getLogger().error(
109110
"In Plugin: " + getEngineData(engine)->pluginName
110111
);
111-
return false;
112+
return std::nullopt;
112113
}
113114
}
114115

@@ -878,7 +879,17 @@ void InitBasicEventListeners() {
878879
ll::coro::keepThis([]() -> ll::coro::CoroTask<> {
879880
while (true) {
880881
co_await 1_tick;
881-
882+
for (auto& type : dirtyEventTypes) {
883+
auto& list = listenerList[int(type)];
884+
for (auto iter = list.begin(); iter != list.end();) {
885+
if (iter->removed) {
886+
EngineScope scope(iter->engine);
887+
iter = list.erase(iter);
888+
} else {
889+
iter++;
890+
}
891+
}
892+
}
882893
#ifndef LEGACY_SCRIPT_ENGINE_BACKEND_NODEJS
883894
try {
884895
std::list<ScriptEngine*> tmpList;

src/legacy/api/EventAPI.h

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
//////////////////// Funcs ////////////////////
66

7+
struct EventListener;
8+
79
void InitBasicEventListeners();
810
void EnableEventListener(int eventId);
9-
10-
bool LLSEAddEventListener(ScriptEngine* engine, const std::string& eventName, const Local<Function>& func);
11+
optional_ref<EventListener>
12+
LLSEAddEventListener(ScriptEngine* engine, const std::string& eventName, const Local<Function>& func);
1113
bool LLSERemoveAllEventListeners(ScriptEngine* engine);
1214
bool LLSECallEventsOnHotLoad(ScriptEngine* engine);
1315
bool LLSECallEventsOnUnload(ScriptEngine* engine);
@@ -118,13 +120,36 @@ enum class EVENT_TYPES : int {
118120

119121
//////////////////// Listeners ////////////////////
120122

121-
struct ListenerListType {
123+
inline std::set<EVENT_TYPES> dirtyEventTypes{};
124+
125+
struct EventListener {
122126
ScriptEngine* engine;
123127
script::Global<Function> func;
128+
// mark as removed and remove at next tick
129+
using RemovedRef = std::shared_ptr<std::reference_wrapper<bool>>;
130+
EVENT_TYPES type;
131+
bool removed = false;
132+
RemovedRef removedRef{std::make_shared<RemovedRef::element_type>(std::ref(removed))};
133+
134+
[[nodiscard]] inline auto remover() const {
135+
return [ref{RemovedRef::weak_type{removedRef}}, type{type}]() -> bool {
136+
auto removed = ref.lock();
137+
if (removed) {
138+
removed->get() = true;
139+
dirtyEventTypes.emplace(type);
140+
}
141+
return !!removed;
142+
};
143+
}
144+
EventListener(ScriptEngine* engine, script::Global<Function> func, EVENT_TYPES type)
145+
: engine(engine),
146+
func(std::move(func)),
147+
type(type) {};
148+
EventListener(const EventListener&) = delete;
124149
};
125150

126151
// 监听器表
127-
extern std::list<ListenerListType> listenerList[int(EVENT_TYPES::EVENT_COUNT)];
152+
extern std::list<EventListener> listenerList[int(EVENT_TYPES::EVENT_COUNT)];
128153

129154
// 监听器历史
130155
extern bool hasListened[int(EVENT_TYPES::EVENT_COUNT)];
@@ -134,17 +159,17 @@ inline std::string EventTypeToString(EVENT_TYPES e) { return std::string(magic_e
134159

135160
#define CallEvent(type, ...) \
136161
[&]() { \
137-
std::list<ListenerListType>& nowList = listenerList[(int)type]; \
138-
bool returnValue = true; \
139-
for (auto& listener : nowList) { \
162+
std::list<EventListener>& nowList = listenerList[(int)type]; \
163+
bool returnValue = true; \
164+
for (auto& listener : nowList | std::views::filter([](auto& l) { return !l.removed; })) { \
140165
EngineScope enter(listener.engine); \
141166
CallEventImpl(listener, returnValue, type, __VA_ARGS__); \
142167
} \
143168
return returnValue; \
144169
}()
145170

146171
template <typename... T>
147-
void CallEventImpl(ListenerListType& listener, bool& returnValue, EVENT_TYPES type, T&&... args) {
172+
void CallEventImpl(EventListener& listener, bool& returnValue, EVENT_TYPES type, T&&... args) {
148173
try {
149174
auto result = listener.func.get().call({}, args...);
150175
if (result.isBoolean() && result.asBoolean().value() == false) {
@@ -168,14 +193,14 @@ void CallEventImpl(ListenerListType& listener, bool& returnValue, EVENT_TYPES ty
168193
}
169194

170195
#define FakeCallEvent(engine, type, ...) \
171-
std::list<ListenerListType>& nowList = listenerList[(int)type]; \
172-
for (auto& listener : nowList) { \
196+
std::list<EventListener>& nowList = listenerList[(int)type]; \
197+
for (auto& listener : nowList | std::views::filter([](auto& l) { return !l.removed; })) { \
173198
EngineScope enter(listener.engine); \
174199
FakeCallEventImpl(listener, engine, type, __VA_ARGS__); \
175200
}
176201

177202
template <typename... T>
178-
void FakeCallEventImpl(ListenerListType& listener, ScriptEngine* engine, EVENT_TYPES type, T&&... args) {
203+
void FakeCallEventImpl(EventListener& listener, ScriptEngine* engine, EVENT_TYPES type, T&&... args) {
179204
if (listener.engine == engine) {
180205
try {
181206
listener.func.get().call({}, args...);

0 commit comments

Comments
 (0)