diff --git a/lua-api/lib/include/ScriptContext.hpp b/lua-api/lib/include/ScriptContext.hpp index 440fb4bd..b6dc46b5 100644 --- a/lua-api/lib/include/ScriptContext.hpp +++ b/lua-api/lib/include/ScriptContext.hpp @@ -54,6 +54,13 @@ class ScriptContext : public std::enable_shared_from_this { } static void log(const std::string& message); + void log_error(const std::string& message) { + log(message); + + std::unique_lock _{m_script_error_mutex}; + m_last_script_error_state.e = message; + m_last_script_error_state.t = std::chrono::system_clock::now(); + } template void add_callback(T1&& adder, T2&& cb) { @@ -75,7 +82,7 @@ class ScriptContext : public std::enable_shared_from_this { for (auto& cb : m_on_script_reset_callbacks) try { handle_protected_result(cb()); } catch (const std::exception& e) { - log("Exception in on_script_reset: " + std::string(e.what())); + log_error("Exception in on_script_reset: " + std::string(e.what())); } catch (...) { log("Unknown exception in on_script_reset"); } @@ -87,9 +94,9 @@ class ScriptContext : public std::enable_shared_from_this { for (auto& cb : m_on_frame_callbacks) try { handle_protected_result(cb()); } catch (const std::exception& e) { - log("Exception in on_frame: " + std::string(e.what())); + log_error("Exception in on_frame: " + std::string(e.what())); } catch (...) { - log("Unknown exception in on_frame"); + log_error("Unknown exception in on_frame"); } } @@ -99,9 +106,9 @@ class ScriptContext : public std::enable_shared_from_this { for (auto& cb : m_on_draw_ui_callbacks) try { handle_protected_result(cb()); } catch (const std::exception& e) { - log("Exception in on_draw_ui: " + std::string(e.what())); + log_error("Exception in on_draw_ui: " + std::string(e.what())); } catch (...) { - log("Unknown exception in on_draw_ui"); + log_error("Unknown exception in on_draw_ui"); } } @@ -111,12 +118,22 @@ class ScriptContext : public std::enable_shared_from_this { for (auto& cb : m_on_lua_event_callbacks) try { handle_protected_result(cb(event_name, event_data)); } catch (const std::exception& e) { - log("Exception in on_lua_event: " + std::string(e.what())); + log_error("Exception in on_lua_event: " + std::string(e.what())); } catch (...) { - log("Unknown exception in on_lua_event"); + log_error("Unknown exception in on_lua_event"); } } + struct ScriptErrorState { + std::string e{}; + std::chrono::system_clock::time_point t{}; + }; + + auto get_last_script_error() const { + std::shared_lock _{m_script_error_mutex}; + return m_last_script_error_state; + } + private: // Private constructor to prevent direct instantiation ScriptContext(lua_State* l, UEVR_PluginInitializeParam* param = nullptr); @@ -127,6 +144,9 @@ class ScriptContext : public std::enable_shared_from_this { sol::state_view m_lua; std::shared_ptr m_lua_shared{}; // This allows us to keep the state alive (if it was created by ScriptState) + ScriptErrorState m_last_script_error_state{}; + mutable std::shared_mutex m_script_error_mutex{}; + std::recursive_mutex m_mtx{}; UEVR_PluginInitializeParam* m_plugin_initialize_param{nullptr}; std::vector m_on_xinput_get_state_callbacks{}; diff --git a/lua-api/lib/include/ScriptState.hpp b/lua-api/lib/include/ScriptState.hpp index 0af9fc29..26b82f4e 100644 --- a/lua-api/lib/include/ScriptState.hpp +++ b/lua-api/lib/include/ScriptState.hpp @@ -58,6 +58,14 @@ class ScriptState { return m_context; } + std::optional get_last_script_error() const { + if (m_context != nullptr) { + return m_context->get_last_script_error(); + } + + return std::nullopt; + } + auto& lua() { return m_lua; } private: diff --git a/lua-api/lib/src/ScriptContext.cpp b/lua-api/lib/src/ScriptContext.cpp index 23a2c4eb..09858e87 100644 --- a/lua-api/lib/src/ScriptContext.cpp +++ b/lua-api/lib/src/ScriptContext.cpp @@ -87,8 +87,10 @@ ScriptContext::~ScriptContext() { } void ScriptContext::log(const std::string& message) { - std::cout << "[LuaVR] " << message << std::endl; - API::get()->log_info("[LuaVR] %s", message.c_str()); + auto msg = std::format("[LuaVR] {}", message); + OutputDebugStringA((msg + "\n").c_str()); + fprintf(stderr, "%s\n", msg.c_str()); + API::get()->log_info("%s", msg.c_str()); } void ScriptContext::setup_callback_bindings() { @@ -830,9 +832,9 @@ bool ScriptContext::global_ufunction_pre_handler(uevr::API::UFunction* fn, uevr: any_false = true; } } catch (const std::exception& e) { - ScriptContext::log("Exception in global_ufunction_pre_handler: " + std::string(e.what())); + ctx->log_error("Exception in global_ufunction_pre_handler: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in global_ufunction_pre_handler"); + ctx->log_error("Unknown exception in global_ufunction_pre_handler"); } } }); @@ -855,9 +857,9 @@ void ScriptContext::global_ufunction_post_handler(uevr::API::UFunction* fn, uevr for (auto& cb : it->second->post_hooks) try { ctx->handle_protected_result(cb(fn, obj, locals_obj, result)); } catch (const std::exception& e) { - ScriptContext::log("Exception in global_ufunction_post_handler: " + std::string(e.what())); + ctx->log_error("Exception in global_ufunction_post_handler: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in global_ufunction_post_handler"); + ctx->log_error("Unknown exception in global_ufunction_post_handler"); } } }); @@ -870,9 +872,9 @@ void ScriptContext::on_xinput_get_state(uint32_t* retval, uint32_t user_index, v for (auto& fn : ctx->m_on_xinput_get_state_callbacks) try { ctx->handle_protected_result(fn(retval, user_index, (XINPUT_STATE*)state)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_xinput_get_state: " + std::string(e.what())); + ctx->log_error("Exception in on_xinput_get_state: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_xinput_get_state"); + ctx->log_error("Unknown exception in on_xinput_get_state"); } }); } @@ -884,9 +886,9 @@ void ScriptContext::on_xinput_set_state(uint32_t* retval, uint32_t user_index, v for (auto& fn : ctx->m_on_xinput_set_state_callbacks) try { ctx->handle_protected_result(fn(retval, user_index, (XINPUT_VIBRATION*)vibration)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_xinput_set_state: " + std::string(e.what())); + ctx->log_error("Exception in on_xinput_set_state: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_xinput_set_state"); + ctx->log_error("Unknown exception in on_xinput_set_state"); } }); } @@ -898,9 +900,9 @@ void ScriptContext::on_pre_engine_tick(UEVR_UGameEngineHandle engine, float delt for (auto& fn : ctx->m_on_pre_engine_tick_callbacks) try { ctx->handle_protected_result(fn(engine, delta_seconds)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_pre_engine_tick: " + std::string(e.what())); + ctx->log_error("Exception in on_pre_engine_tick: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_pre_engine_tick"); + ctx->log_error("Unknown exception in on_pre_engine_tick"); } }); } @@ -912,9 +914,9 @@ void ScriptContext::on_post_engine_tick(UEVR_UGameEngineHandle engine, float del for (auto& fn : ctx->m_on_post_engine_tick_callbacks) try { ctx->handle_protected_result(fn(engine, delta_seconds)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_post_engine_tick: " + std::string(e.what())); + ctx->log_error("Exception in on_post_engine_tick: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_post_engine_tick"); + ctx->log_error("Unknown exception in on_post_engine_tick"); } }); } @@ -926,9 +928,9 @@ void ScriptContext::on_pre_slate_draw_window_render_thread(UEVR_FSlateRHIRendere for (auto& fn : ctx->m_on_pre_slate_draw_window_render_thread_callbacks) try { ctx->handle_protected_result(fn(renderer, viewport_info)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_pre_slate_draw_window_render_thread: " + std::string(e.what())); + ctx->log_error("Exception in on_pre_slate_draw_window_render_thread: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_pre_slate_draw_window_render_thread"); + ctx->log_error("Unknown exception in on_pre_slate_draw_window_render_thread"); } }); } @@ -940,9 +942,9 @@ void ScriptContext::on_post_slate_draw_window_render_thread(UEVR_FSlateRHIRender for (auto& fn : ctx->m_on_post_slate_draw_window_render_thread_callbacks) try { ctx->handle_protected_result(fn(renderer, viewport_info)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_post_slate_draw_window_render_thread: " + std::string(e.what())); + ctx->log_error("Exception in on_post_slate_draw_window_render_thread: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_post_slate_draw_window_render_thread"); + ctx->log_error("Unknown exception in on_post_slate_draw_window_render_thread"); } }); } @@ -970,9 +972,9 @@ void ScriptContext::on_early_calculate_stereo_view_offset(UEVR_StereoRenderingDe ctx->handle_protected_result(fn(device, view_index, world_to_meters, ue4_position, ue4_rotation, is_double)); } } catch (const std::exception& e) { - ScriptContext::log("Exception in on_early_calculate_stereo_view_offset: " + std::string(e.what())); + ctx->log_error("Exception in on_early_calculate_stereo_view_offset: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_early_calculate_stereo_view_offset"); + ctx->log_error("Unknown exception in on_early_calculate_stereo_view_offset"); } }); } @@ -1000,9 +1002,9 @@ void ScriptContext::on_pre_calculate_stereo_view_offset(UEVR_StereoRenderingDevi ctx->handle_protected_result(fn(device, view_index, world_to_meters, ue4_position, ue4_rotation, is_double)); } } catch (const std::exception& e) { - ScriptContext::log("Exception in on_pre_calculate_stereo_view_offset: " + std::string(e.what())); + ctx->log_error("Exception in on_pre_calculate_stereo_view_offset: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_pre_calculate_stereo_view_offset"); + ctx->log_error("Unknown exception in on_pre_calculate_stereo_view_offset"); } }); } @@ -1030,9 +1032,9 @@ void ScriptContext::on_post_calculate_stereo_view_offset(UEVR_StereoRenderingDev ctx->handle_protected_result(fn(device, view_index, world_to_meters, ue4_position, ue4_rotation, is_double)); } } catch (const std::exception& e) { - ScriptContext::log("Exception in on_post_calculate_stereo_view_offset: " + std::string(e.what())); + ctx->log_error("Exception in on_post_calculate_stereo_view_offset: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_post_calculate_stereo_view_offset"); + ctx->log_error("Unknown exception in on_post_calculate_stereo_view_offset"); } }); } @@ -1044,9 +1046,9 @@ void ScriptContext::on_pre_viewport_client_draw(UEVR_UGameViewportClientHandle v for (auto& fn : ctx->m_on_pre_viewport_client_draw_callbacks) try { ctx->handle_protected_result(fn(viewport_client, viewport, canvas)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_pre_viewport_client_draw: " + std::string(e.what())); + ctx->log_error("Exception in on_pre_viewport_client_draw: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_pre_viewport_client_draw"); + ctx->log_error("Unknown exception in on_pre_viewport_client_draw"); } }); } @@ -1058,9 +1060,9 @@ void ScriptContext::on_post_viewport_client_draw(UEVR_UGameViewportClientHandle for (auto& fn : ctx->m_on_post_viewport_client_draw_callbacks) try { ctx->handle_protected_result(fn(viewport_client, viewport, canvas)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_post_viewport_client_draw: " + std::string(e.what())); + ctx->log_error("Exception in on_post_viewport_client_draw: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_post_viewport_client_draw"); + ctx->log_error("Unknown exception in on_post_viewport_client_draw"); } }); } @@ -1072,9 +1074,9 @@ void ScriptContext::on_frame() { for (auto& fn : ctx->m_on_frame_callbacks) try { ctx->handle_protected_result(fn()); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_frame: " + std::string(e.what())); + ctx->log_error("Exception in on_frame: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_frame"); + ctx->log_error("Unknown exception in on_frame"); } }); } @@ -1086,9 +1088,9 @@ void ScriptContext::on_draw_ui() { for (auto& fn : ctx->m_on_draw_ui_callbacks) try { ctx->handle_protected_result(fn()); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_draw_ui: " + std::string(e.what())); + ctx->log_error("Exception in on_draw_ui: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_draw_ui"); + ctx->log_error("Unknown exception in on_draw_ui"); } }); } @@ -1100,9 +1102,9 @@ void ScriptContext::on_script_reset() { for (auto& fn : ctx->m_on_script_reset_callbacks) try { ctx->handle_protected_result(fn()); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_script_reset: " + std::string(e.what())); + ctx->log_error("Exception in on_script_reset: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_script_reset"); + ctx->log_error("Unknown exception in on_script_reset"); } }); } @@ -1117,9 +1119,9 @@ void ScriptContext::on_lua_event(std::string_view event_name, std::string_view e for (auto& fn : ctx->m_on_lua_event_callbacks) try { ctx->handle_protected_result(fn(event_name_data, event_data_data)); } catch (const std::exception& e) { - ScriptContext::log("Exception in on_lua_event: " + std::string(e.what())); + ctx->log_error("Exception in on_lua_event: " + std::string(e.what())); } catch (...) { - ScriptContext::log("Unknown exception in on_lua_event"); + ctx->log_error("Unknown exception in on_lua_event"); } }); } diff --git a/src/mods/LuaLoader.cpp b/src/mods/LuaLoader.cpp index 16011b1a..5ff495ca 100644 --- a/src/mods/LuaLoader.cpp +++ b/src/mods/LuaLoader.cpp @@ -171,17 +171,17 @@ void LuaLoader::on_draw_sidebar_entry(std::string_view in_entry) { m_log_to_disk->draw("Log Lua Errors to Disk"); - if (!m_last_script_error.empty()) { - std::shared_lock _{m_script_error_mutex}; + auto last_script_error = m_main_state != nullptr ? m_main_state->get_last_script_error() : std::nullopt; + if (last_script_error.has_value() && !last_script_error->e.empty()) { const auto now = std::chrono::system_clock::now(); - const auto diff = now - m_last_script_error_time; + const auto diff = now - last_script_error->t; const auto sec = std::chrono::duration(diff).count(); ImGui::TextWrapped("Last Error Time: %.2f seconds ago", sec); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); - ImGui::TextWrapped("Last Script Error: %s", m_last_script_error.data()); + ImGui::TextWrapped("Last Script Error: %s", last_script_error->e.c_str()); ImGui::PopStyleColor(); } else { ImGui::TextWrapped("No Script Errors... yet!"); @@ -224,11 +224,6 @@ void LuaLoader::reset_scripts() { std::scoped_lock _{ m_access_mutex }; - { - std::unique_lock _{ m_script_error_mutex }; - m_last_script_error.clear(); - } - if (m_main_state != nullptr) { /*auto& mods = g_framework->get_mods()->get_mods(); diff --git a/src/mods/LuaLoader.hpp b/src/mods/LuaLoader.hpp index 5514fe69..c54c8e70 100644 --- a/src/mods/LuaLoader.hpp +++ b/src/mods/LuaLoader.hpp @@ -72,9 +72,6 @@ class LuaLoader : public Mod { std::vector m_known_scripts{}; std::unordered_map m_loaded_scripts_map{}; std::vector m_states_to_delete{}; - std::string m_last_script_error{}; - std::shared_mutex m_script_error_mutex{}; - std::chrono::system_clock::time_point m_last_script_error_time{}; bool m_console_spawned{false}; bool m_needs_first_reset{true};