support for non toplevel event handlers (#360)

this change replaces the `_G` event handler lookup with a lua snippet
that fetches whatever the user has set, which could be a module's
function, a builtin global, or even a function defined in the
`RegisterEvent `call
This commit is contained in:
Lion authored and GitHub committed 2024-08-31 20:30:02 +02:00
commit e076197ab2
2 files changed
+34 -17

No files matched your search

+4 -4
View File
@@ -167,7 +167,7 @@ public:
void ReportErrors(const std::vector<std::shared_ptr<TLuaResult>>& Results); void ReportErrors(const std::vector<std::shared_ptr<TLuaResult>>& Results);
bool HasState(TLuaStateId StateId); bool HasState(TLuaStateId StateId);
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); [[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script);
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector<TLuaValue>& Args); [[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector<TLuaValue>& Args, const std::string& EventName);
void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false);
void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName);
/** /**
@@ -192,7 +192,7 @@ public:
for (const auto& Event : mLuaEvents.at(EventName)) { for (const auto& Event : mLuaEvents.at(EventName)) {
for (const auto& Function : Event.second) { for (const auto& Function : Event.second) {
if (Event.first != IgnoreId) { if (Event.first != IgnoreId) {
auto Result = EnqueueFunctionCall(Event.first, Function, Arguments); auto Result = EnqueueFunctionCall(Event.first, Function, Arguments, EventName);
Results.push_back(Result); Results.push_back(Result);
AddResultToCheck(Result); AddResultToCheck(Result);
} }
@@ -211,7 +211,7 @@ public:
std::vector<TLuaValue> Arguments { TLuaValue { std::forward<ArgsT>(Args) }... }; std::vector<TLuaValue> Arguments { TLuaValue { std::forward<ArgsT>(Args) }... };
const auto Handlers = GetEventHandlersForState(EventName, StateId); const auto Handlers = GetEventHandlersForState(EventName, StateId);
for (const auto& Handler : Handlers) { for (const auto& Handler : Handlers) {
Results.push_back(EnqueueFunctionCall(StateId, Handler, Arguments)); Results.push_back(EnqueueFunctionCall(StateId, Handler, Arguments, EventName));
} }
return Results; return Results;
} }
@@ -245,7 +245,7 @@ private:
StateThreadData(const StateThreadData&) = delete; StateThreadData(const StateThreadData&) = delete;
virtual ~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); } virtual ~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); }
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(const TLuaChunk& Script); [[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(const TLuaChunk& Script);
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(const std::string& FunctionName, const std::vector<TLuaValue>& Args); [[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(const std::string& FunctionName, const std::vector<TLuaValue>& Args, const std::string& EventName);
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCallFromCustomEvent(const std::string& FunctionName, const std::vector<TLuaValue>& Args, const std::string& EventName, CallStrategy Strategy); [[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCallFromCustomEvent(const std::string& FunctionName, const std::vector<TLuaValue>& Args, const std::string& EventName, CallStrategy Strategy);
void RegisterEvent(const std::string& EventName, const std::string& FunctionName); void RegisterEvent(const std::string& EventName, const std::string& FunctionName);
void AddPath(const fs::path& Path); // to be added to path and cpath void AddPath(const fs::path& Path); // to be added to path and cpath
+30 -13
View File
@@ -40,6 +40,18 @@ TLuaEngine* LuaAPI::MP::Engine;
static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn); static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn);
static std::optional<sol::function> GetLuaHandler(sol::state_view StateView, const std::string Handler, const std::string EventName);
static std::optional<sol::function> GetLuaHandler(sol::state_view StateView, const std::string Handler, const std::string EventName) {
auto Res = StateView.safe_script("return " + Handler, sol::script_pass_on_error);
if (!Res.valid()) {
beammp_errorf("invalid handler for event \"{}\". handler: \"{}\"", EventName, Handler);
} else if (Res.get_type() == sol::type::function) {
return Res.get<sol::function>();
}
return std::nullopt;
}
TLuaEngine::TLuaEngine() TLuaEngine::TLuaEngine()
: mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") { : mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") {
Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting); Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting);
@@ -358,9 +370,9 @@ std::shared_ptr<TLuaResult> TLuaEngine::EnqueueScript(TLuaStateId StateID, const
return mLuaStates.at(StateID)->EnqueueScript(Script); return mLuaStates.at(StateID)->EnqueueScript(Script);
} }
std::shared_ptr<TLuaResult> TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector<TLuaValue>& Args) { std::shared_ptr<TLuaResult> TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector<TLuaValue>& Args, const std::string& EventName) {
std::unique_lock Lock(mLuaStatesMutex); std::unique_lock Lock(mLuaStatesMutex);
return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName, Args); return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName, Args, EventName);
} }
void TLuaEngine::CollectAndInitPlugins() { void TLuaEngine::CollectAndInitPlugins() {
@@ -433,7 +445,7 @@ void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name,
mLuaStates[StateId] = std::move(DataPtr); mLuaStates[StateId] = std::move(DataPtr);
RegisterEvent("onInit", StateId, "onInit"); RegisterEvent("onInit", StateId, "onInit");
if (!DontCallOnInit) { if (!DontCallOnInit) {
auto Res = EnqueueFunctionCall(StateId, "onInit", {}); auto Res = EnqueueFunctionCall(StateId, "onInit", {}, "onInit");
Res->WaitUntilReady(); Res->WaitUntilReady();
if (Res->Error && Res->ErrorMessage != TLuaEngine::BeamMPFnNotFoundError) { if (Res->Error && Res->ErrorMessage != TLuaEngine::BeamMPFnNotFoundError) {
beammp_lua_error("Calling \"onInit\" on \"" + StateId + "\" failed: " + Res->ErrorMessage); beammp_lua_error("Calling \"onInit\" on \"" + StateId + "\" failed: " + Res->ErrorMessage);
@@ -494,9 +506,11 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string
sol::variadic_results LocalArgs = JsonStringToArray(Str); sol::variadic_results LocalArgs = JsonStringToArray(Str);
for (const auto& Handler : MyHandlers) { for (const auto& Handler : MyHandlers) {
auto Fn = mStateView[Handler]; auto Res = GetLuaHandler(mStateView, Handler, EventName);
Fn = AddTraceback(mStateView, Fn); if (Res.has_value()) {
if (Fn.valid()) { sol::function Fn = Res.value();
Fn = AddTraceback(mStateView, Fn);
auto LuaResult = Fn(LocalArgs); auto LuaResult = Fn(LocalArgs);
auto Result = std::make_shared<TLuaResult>(); auto Result = std::make_shared<TLuaResult>();
if (LuaResult.valid()) { if (LuaResult.valid()) {
@@ -548,8 +562,9 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string&
sol::table Result = mStateView.create_table(); sol::table Result = mStateView.create_table();
int i = 1; int i = 1;
for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) { for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) {
auto Fn = mStateView[Handler]; auto Res = GetLuaHandler(mStateView, Handler, EventName);
if (Fn.valid() && Fn.get_type() == sol::type::function) { if (Res.has_value()) {
sol::function Fn = Res.value();
auto FnRet = Fn(EventArgs); auto FnRet = Fn(EventArgs);
if (FnRet.valid()) { if (FnRet.valid()) {
Result.set(i, FnRet); Result.set(i, FnRet);
@@ -1042,12 +1057,12 @@ std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCallFrom
} }
} }
std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName, const std::vector<TLuaValue>& Args) { std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName, const std::vector<TLuaValue>& Args, const std::string& EventName) {
auto Result = std::make_shared<TLuaResult>(); auto Result = std::make_shared<TLuaResult>();
Result->StateId = mStateId; Result->StateId = mStateId;
Result->Function = FunctionName; Result->Function = FunctionName;
std::unique_lock Lock(mStateFunctionQueueMutex); std::unique_lock Lock(mStateFunctionQueueMutex);
mStateFunctionQueue.push_back({ FunctionName, Result, Args, "" }); mStateFunctionQueue.push_back({ FunctionName, Result, Args, EventName });
mStateFunctionQueueCond.notify_all(); mStateFunctionQueueCond.notify_all();
return Result; return Result;
} }
@@ -1135,8 +1150,10 @@ void TLuaEngine::StateThreadData::operator()() {
// TODO: Use TheQueuedFunction.EventName for errors, warnings, etc // TODO: Use TheQueuedFunction.EventName for errors, warnings, etc
Result->StateId = mStateId; Result->StateId = mStateId;
sol::state_view StateView(mState); sol::state_view StateView(mState);
auto RawFn = StateView[FnName];
if (RawFn.valid() && RawFn.get_type() == sol::type::function) { auto Res = GetLuaHandler(StateView, FnName, TheQueuedFunction.EventName);
if (Res.has_value()) {
sol::function Fn = Res.value();
std::vector<sol::object> LuaArgs; std::vector<sol::object> LuaArgs;
for (const auto& Arg : Args) { for (const auto& Arg : Args) {
if (Arg.valueless_by_exception()) { if (Arg.valueless_by_exception()) {
@@ -1171,7 +1188,7 @@ void TLuaEngine::StateThreadData::operator()() {
break; break;
} }
} }
auto Fn = AddTraceback(StateView, RawFn); Fn = AddTraceback(StateView, Fn);
auto Res = Fn(sol::as_args(LuaArgs)); auto Res = Fn(sol::as_args(LuaArgs));
if (Res.valid()) { if (Res.valid()) {
Result->Error = false; Result->Error = false;