Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Lua): Better error messages #639

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion UE4SS/src/GUI/ConsoleOutputDevice.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <chrono>
#include <locale>
#include <sstream>

#include <GUI/ConsoleOutputDevice.hpp>
#include <UE4SSProgram.hpp>
Expand Down Expand Up @@ -27,7 +28,12 @@ namespace RC::Output
fmt_copy.pop_back();
}
auto color = static_cast<Color::Color>(optional_arg);
UE4SSProgram::get_program().get_debugging_ui().get_console().add_line(m_formatter(fmt_copy), color);
auto formatted_message = m_formatter(fmt_copy);
std::wstringstream stream{formatted_message};
for (File::StringType line; std::getline(stream, line);)
{
UE4SSProgram::get_program().get_debugging_ui().get_console().add_line(line, color);
}
#endif
}
} // namespace RC::Output
39 changes: 38 additions & 1 deletion UE4SS/src/LuaType/LuaUObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,41 @@ namespace RC::LuaType
params.lua.throw_error(fmt::format("[push_textproperty] Unknown Operation ({}) not supported", static_cast<int32_t>(params.operation)));
}

static auto get_stack_dump(const LuaMadeSimple::Lua& lua, const char* message = "") -> std::string
{
auto lua_state = lua.get_lua_state();
auto out_message = fmt::format("\n\nLUA Stack dump -> START------------------------------\n{}\n", message);
int top = lua_gettop(lua_state);
for (int i = 1; i <= top; i++)
{
out_message.append(fmt::format("{}\t{}\t", i, luaL_typename(lua_state, i)));
switch (lua_type(lua_state, i))
{
case LUA_TNUMBER:
out_message.append(fmt::format("{}", lua_tonumber(lua_state, i)));
break;
case LUA_TSTRING:
out_message.append(fmt::format("{}", lua_tostring(lua_state, i)));
break;
case LUA_TBOOLEAN:
out_message.append(fmt::format("{}", (lua_toboolean(lua_state, i) ? "true" : "false")));
break;
case LUA_TNIL:
out_message.append("nil");
break;
case LUA_TFUNCTION:
out_message.append("function");
break;
default:
out_message.append(fmt::format("{}", lua_topointer(lua_state, i)));
break;
}
out_message.append("\n");
}
out_message.append("\nLUA Stack dump -> END----------------------------\n\n");
return out_message;
}

auto push_strproperty(const PusherParams& params) -> void
{
Unreal::FString* string = static_cast<Unreal::FString*>(params.data);
Expand Down Expand Up @@ -1117,7 +1152,9 @@ namespace RC::LuaType
}
else
{
params.lua.throw_error("[push_strproperty] StrProperty can only be set to a string or FString");
auto error = to_string(fmt::format(STR("[push_strproperty] StrProperty ({}) can only be set to a string or FString"), params.property ? params.property->GetFullName() : STR("N/A")));
error.append(get_stack_dump(params.lua));
params.lua.throw_error(error);
}
return;
}
Expand Down
23 changes: 16 additions & 7 deletions UE4SS/src/Mod/LuaMod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,7 +1366,9 @@ No overload found for function 'UnregisterHook'.
Unreal::UFunction* unreal_function = Unreal::UObjectGlobals::StaticFindObject<Unreal::UFunction*>(nullptr, nullptr, function_name_no_prefix);
if (!unreal_function)
{
lua.throw_error("Tried to unregister a hook with Lua function 'UnregisterHook' but no UFunction with the specified name was found.");
lua.throw_error(std::format("Tried to unregister a hook with Lua function 'UnregisterHook' but no UFunction with the specified name "
"was found.\n>FunctionName: {}",
to_string(function_name_no_prefix)));
}

if (!lua.is_integer())
Expand All @@ -1383,12 +1385,16 @@ No overload found for function 'UnregisterHook'.

if (pre_id > std::numeric_limits<int32_t>::max())
{
lua.throw_error("Tried to unregister a hook with Lua function 'UnregisterHook' but the PreCallbackId supplied was too large (>int32)");
lua.throw_error(std::format("Tried to unregister a hook with Lua function 'UnregisterHook' but the PreCallbackId supplied was too "
"large (>int32)\n>FunctionName: {}",
to_string(function_name_no_prefix)));
}

if (post_id > std::numeric_limits<int32_t>::max())
{
lua.throw_error("Tried to unregister a hook with Lua function 'UnregisterHook' but the PostCallbackId supplied was too large (>int32)");
lua.throw_error(std::format("Tried to unregister a hook with Lua function 'UnregisterHook' but the PostCallbackId supplied was too "
"large (>int32)\n>FunctionName: {}",
to_string(function_name_no_prefix)));
}

// Hooks on native UFunctions will have both of these IDs.
Expand All @@ -1397,9 +1403,9 @@ No overload found for function 'UnregisterHook'.
if (native_hook_pre_id_it != LuaMod::m_generic_hook_id_to_native_hook_id.end() &&
native_hook_post_id_it != LuaMod::m_generic_hook_id_to_native_hook_id.end())
{
Output::send<LogLevel::Verbose>(STR("Unregistering native hook with pre-id: {}\n"), native_hook_pre_id_it->first);
Output::send<LogLevel::Verbose>(STR("Unregistering native pre-hook ({}) for {}\n"), native_hook_pre_id_it->first, function_name_no_prefix);
unreal_function->UnregisterHook(static_cast<int32_t>(native_hook_pre_id_it->second));
Output::send<LogLevel::Verbose>(STR("Unregistering native hook with post-id: {}\n"), native_hook_post_id_it->first);
Output::send<LogLevel::Verbose>(STR("Unregistering native post-hook ({}) for {}\n"), native_hook_post_id_it->first, function_name_no_prefix);
unreal_function->UnregisterHook(static_cast<int32_t>(native_hook_post_id_it->second));

// LuaUnrealScriptFunctionData contains the hook's lua registry references, captured in RegisterHook in two different lua states.
Expand All @@ -1425,7 +1431,7 @@ No overload found for function 'UnregisterHook'.
if (auto callback_data_it = LuaMod::m_script_hook_callbacks.find(unreal_function->GetFullName());
callback_data_it != LuaMod::m_script_hook_callbacks.end())
{
Output::send<LogLevel::Verbose>(STR("Unregistering script hook with id: {}\n"), post_id);
Output::send<LogLevel::Verbose>(STR("Unregistering script hook with id: {}, FunctionName: {}\n"), post_id, function_name_no_prefix);
auto& registry_indexes = callback_data_it->second.registry_indexes;
std::erase_if(registry_indexes, [&](const auto& pair) -> bool {
return post_id == pair.second.identifier;
Expand Down Expand Up @@ -3020,7 +3026,9 @@ No overload found for function 'RegisterHook'.
Unreal::UFunction* unreal_function = Unreal::UObjectGlobals::StaticFindObject<Unreal::UFunction*>(nullptr, nullptr, function_name_no_prefix);
if (!unreal_function)
{
lua.throw_error("Tried to register a hook with Lua function 'RegisterHook' but no UFunction with the specified name was found.");
lua.throw_error(std::format(
"Tried to register a hook with Lua function 'RegisterHook' but no UFunction with the specified name was found.\nFunction Name: {}",
to_string(function_name_no_prefix)));
}

int32_t generic_pre_id{};
Expand Down Expand Up @@ -3062,6 +3070,7 @@ No overload found for function 'RegisterHook'.
else
{
std::string error_message{"Was unable to register a hook with Lua function 'RegisterHook', information:\n"};
error_message.append(fmt::format("FunctionName: {}\n", to_string(function_name_no_prefix)));
error_message.append(fmt::format("UFunction::Func: {}\n", std::bit_cast<void*>(func_ptr)));
error_message.append(fmt::format("ProcessInternal: {}\n", Unreal::UObject::ProcessInternalInternal.get_function_address()));
error_message.append(
Expand Down
6 changes: 3 additions & 3 deletions UE4SS/src/UE4SSProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,19 +1050,19 @@ namespace RC
if (mod_name_is_taken)
{
mod->set_installable(false);
Output::send(STR("Mod name '{}' is already in use.\n"), mod->get_name());
Output::send<LogLevel::Warning>(STR("Mod name '{}' is already in use.\n"), mod->get_name());
continue;
}

if (mod->is_installed())
{
Output::send(STR("Tried to install a mod that was already installed, Mod: '{}'\n"), mod->get_name());
Output::send<LogLevel::Warning>(STR("Tried to install a mod that was already installed, Mod: '{}'\n"), mod->get_name());
continue;
}

if (!mod->is_installable())
{
Output::send(STR("Was unable to install mod '{}' for unknown reasons. Mod is not installable.\n"), mod->get_name());
Output::send<LogLevel::Warning>(STR("Was unable to install mod '{}' for unknown reasons. Mod is not installable.\n"), mod->get_name());
continue;
}

Expand Down
Loading