diff --git a/Source/utils/lua.cpp b/Source/utils/lua.cpp index 043fca442c83..694e16c4c687 100644 --- a/Source/utils/lua.cpp +++ b/Source/utils/lua.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include @@ -73,6 +75,48 @@ void LuaPanic(sol::optional maybe_msg) maybe_msg.value_or("unknown error")); } +void LuaLog(LogPriority priority, std::string_view fmt, sol::variadic_args args) +{ + std::string formatted; + FMT_TRY + { + fmt::dynamic_format_arg_store store; + for (sol::stack_proxy arg : args) { + switch (arg.get_type()) { + case sol::type::boolean: + store.push_back(arg.as()); + break; + case sol::type::number: + if (lua_isinteger(arg.lua_state(), arg.stack_index())) { + store.push_back(arg.as()); + } else { + store.push_back(arg.as()); + } + break; + case sol::type::string: + store.push_back(arg.as()); + break; + default: + store.push_back(sol::utility::to_string(sol::stack_object(arg))); + break; + } + } + formatted = fmt::vformat(fmt, store); + } + FMT_CATCH(const fmt::format_error &e) + { +#if FMT_EXCEPTIONS + // e.what() is undefined if exceptions are disabled, so we wrap the whole block + // with an `FMT_EXCEPTIONS` check. + std::string error = StrCat("Format error, fmt: ", fmt, " error: ", e.what()); + SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "%s", error.c_str()); + return; +#endif + } + SDL_LogMessage(static_cast(LogCategory::Application), static_cast(priority), + "%s", formatted.c_str()); +} + } // namespace void Sol2DebugPrintStack(lua_State *state) @@ -110,10 +154,14 @@ void LuaInitialize() // Registering devilutionx object table lua.create_named_table( "devilutionx", - "message", [](std::string_view text) { EventPlrMsg(text, UiFlags::ColorRed); } + "message", [](std::string_view text) { EventPlrMsg(text, UiFlags::ColorRed); }, // TODO: Re-enable once https://github.com/bebbo/amiga-gcc/issues/363 is fixed. // "drawString", [](std::string_view text, int x, int y) { DrawString(GlobalBackBuffer(), text, { x, y }); } - ); + "log", [](std::string_view fmt, sol::variadic_args args) { LuaLog(LogPriority::Info, fmt, std::move(args)); }, + "logVerbose", [](std::string_view fmt, sol::variadic_args args) { LuaLog(LogPriority::Verbose, fmt, std::move(args)); }, + "logDebug", [](std::string_view fmt, sol::variadic_args args) { LuaLog(LogPriority::Debug, fmt, std::move(args)); }, + "logWarn", [](std::string_view fmt, sol::variadic_args args) { LuaLog(LogPriority::Warn, fmt, std::move(args)); }, + "logError", [](std::string_view fmt, sol::variadic_args args) { LuaLog(LogPriority::Error, fmt, std::move(args)); }); RunScript("lua/init.lua"); RunScript("lua/user.lua"); @@ -150,7 +198,7 @@ tl::expected RunLua(std::string_view code) return tl::make_unexpected("Unknown Lua error"); } - return sol::utility::to_string(sol::object(result)); + return sol::utility::to_string(sol::stack_object(result)); } } // namespace devilution