diff --git a/UE4SS/src/GUI/ConsoleOutputDevice.cpp b/UE4SS/src/GUI/ConsoleOutputDevice.cpp index 7e0ac8e67..2552d0573 100644 --- a/UE4SS/src/GUI/ConsoleOutputDevice.cpp +++ b/UE4SS/src/GUI/ConsoleOutputDevice.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -27,7 +28,12 @@ namespace RC::Output fmt_copy.pop_back(); } auto color = static_cast(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 diff --git a/UE4SS/src/LuaType/LuaUObject.cpp b/UE4SS/src/LuaType/LuaUObject.cpp index adcb065b4..a0f3e3054 100644 --- a/UE4SS/src/LuaType/LuaUObject.cpp +++ b/UE4SS/src/LuaType/LuaUObject.cpp @@ -1089,6 +1089,41 @@ namespace RC::LuaType params.lua.throw_error(fmt::format("[push_textproperty] Unknown Operation ({}) not supported", static_cast(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(params.data); @@ -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; } diff --git a/UE4SS/src/Mod/LuaMod.cpp b/UE4SS/src/Mod/LuaMod.cpp index afaa46053..85c2881c8 100644 --- a/UE4SS/src/Mod/LuaMod.cpp +++ b/UE4SS/src/Mod/LuaMod.cpp @@ -1366,7 +1366,9 @@ No overload found for function 'UnregisterHook'. Unreal::UFunction* unreal_function = Unreal::UObjectGlobals::StaticFindObject(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()) @@ -1383,12 +1385,16 @@ No overload found for function 'UnregisterHook'. if (pre_id > std::numeric_limits::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::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. @@ -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(STR("Unregistering native hook with pre-id: {}\n"), native_hook_pre_id_it->first); + Output::send(STR("Unregistering native pre-hook ({}) for {}\n"), native_hook_pre_id_it->first, function_name_no_prefix); unreal_function->UnregisterHook(static_cast(native_hook_pre_id_it->second)); - Output::send(STR("Unregistering native hook with post-id: {}\n"), native_hook_post_id_it->first); + Output::send(STR("Unregistering native post-hook ({}) for {}\n"), native_hook_post_id_it->first, function_name_no_prefix); unreal_function->UnregisterHook(static_cast(native_hook_post_id_it->second)); // LuaUnrealScriptFunctionData contains the hook's lua registry references, captured in RegisterHook in two different lua states. @@ -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(STR("Unregistering script hook with id: {}\n"), post_id); + Output::send(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; @@ -3020,7 +3026,9 @@ No overload found for function 'RegisterHook'. Unreal::UFunction* unreal_function = Unreal::UObjectGlobals::StaticFindObject(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{}; @@ -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(func_ptr))); error_message.append(fmt::format("ProcessInternal: {}\n", Unreal::UObject::ProcessInternalInternal.get_function_address())); error_message.append( diff --git a/UE4SS/src/UE4SSProgram.cpp b/UE4SS/src/UE4SSProgram.cpp index f654b8fe2..c165ae402 100644 --- a/UE4SS/src/UE4SSProgram.cpp +++ b/UE4SS/src/UE4SSProgram.cpp @@ -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(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(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(STR("Was unable to install mod '{}' for unknown reasons. Mod is not installable.\n"), mod->get_name()); continue; }