diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 3d74483..658d753 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -192,7 +192,9 @@ public: for (const auto& Event : mLuaEvents.at(EventName)) { for (const auto& Function : Event.second) { if (Event.first != IgnoreId) { - Results.push_back(EnqueueFunctionCall(Event.first, Function, Arguments)); + auto Result = EnqueueFunctionCall(Event.first, Function, Arguments); + Results.push_back(Result); + AddResultToCheck(Result); } } } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index a48c848..d423c69 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -30,12 +30,16 @@ #include #include #include +#include #include +#include #include #include TLuaEngine* LuaAPI::MP::Engine; +static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn); + TLuaEngine::TLuaEngine() : mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") { Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting); @@ -491,6 +495,7 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string sol::variadic_results LocalArgs = JsonStringToArray(Str); for (const auto& Handler : MyHandlers) { auto Fn = mStateView[Handler]; + Fn = AddTraceback(mStateView, Fn); if (Fn.valid()) { auto LuaResult = Fn(LocalArgs); auto Result = std::make_shared(); @@ -499,7 +504,9 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string Result->Result = LuaResult; } else { Result->Error = true; - Result->ErrorMessage = "Function result in TriggerGlobalEvent was invalid"; + sol::error Err = LuaResult; + Result->ErrorMessage = Err.what(); + beammp_errorf("An error occured while executing local event handler \"{}\" for event \"{}\": {}", Handler, EventName, Result->ErrorMessage); } Result->MarkAsReady(); Return.push_back(Result); @@ -1049,6 +1056,21 @@ void TLuaEngine::StateThreadData::RegisterEvent(const std::string& EventName, co mEngine->RegisterEvent(EventName, mStateId, FunctionName); } +static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn) { + StateView["INTERNAL_ERROR_HANDLER"] = [](lua_State *L) { + auto Error = sol::stack::get>(L); + std::string ErrorString = ""; + if (Error.has_value()) { + ErrorString = Error.value(); + } + auto DebugTracebackFn = sol::state_view(L).globals().get("debug").get("traceback"); + // 2 = start collecting the trace one above the current function (1=current function) + std::string Traceback = DebugTracebackFn(ErrorString, 2); + return sol::stack::push(L, Traceback); + }; + return sol::protected_function(RawFn, StateView["INTERNAL_ERROR_HANDLER"]); +} + void TLuaEngine::StateThreadData::operator()() { RegisterThread("Lua:" + mStateId); while (!Application::IsShuttingDown()) { @@ -1113,8 +1135,8 @@ void TLuaEngine::StateThreadData::operator()() { // TODO: Use TheQueuedFunction.EventName for errors, warnings, etc Result->StateId = mStateId; sol::state_view StateView(mState); - auto Fn = StateView[FnName]; - if (Fn.valid() && Fn.get_type() == sol::type::function) { + auto RawFn = StateView[FnName]; + if (RawFn.valid() && RawFn.get_type() == sol::type::function) { std::vector LuaArgs; for (const auto& Arg : Args) { if (Arg.valueless_by_exception()) { @@ -1149,6 +1171,7 @@ void TLuaEngine::StateThreadData::operator()() { break; } } + auto Fn = AddTraceback(StateView, RawFn); auto Res = Fn(sol::as_args(LuaArgs)); if (Res.valid()) { Result->Error = false;