From dfcd94bacf6cef4a7768164309ff1956a54b0b35 Mon Sep 17 00:00:00 2001 From: Buckminsterfullerene02 Date: Mon, 12 Aug 2024 17:47:36 +0100 Subject: [PATCH] feature: checking for latest ue4ss version if not latest ue4ss version from github, add to crash dumper messagebox use xrepo libcurl use curl redirect to avoid requiring user agent for api add setting for check chore: changelog --- UE4SS/include/SettingsManager.hpp | 1 + UE4SS/include/UE4SSProgram.hpp | 3 + UE4SS/src/CrashDumper.cpp | 13 ++- UE4SS/src/SettingsManager.cpp | 1 + UE4SS/src/UE4SSProgram.cpp | 135 +++++++++++++++++++++++++++++- UE4SS/xmake.lua | 3 + assets/Changelog.md | 5 ++ assets/UE4SS-settings.ini | 5 ++ 8 files changed, 163 insertions(+), 3 deletions(-) diff --git a/UE4SS/include/SettingsManager.hpp b/UE4SS/include/SettingsManager.hpp index 321497282..892069d79 100644 --- a/UE4SS/include/SettingsManager.hpp +++ b/UE4SS/include/SettingsManager.hpp @@ -25,6 +25,7 @@ namespace RC bool EnableDebugKeyBindings{false}; int64_t SecondsToScanBeforeGivingUp{30}; bool UseUObjectArrayCache{true}; + bool LatestVersionCheck{true}; } General; struct SectionEngineVersionOverride diff --git a/UE4SS/include/UE4SSProgram.hpp b/UE4SS/include/UE4SSProgram.hpp index e542f7e52..0c6fd1d94 100644 --- a/UE4SS/include/UE4SSProgram.hpp +++ b/UE4SS/include/UE4SSProgram.hpp @@ -219,6 +219,9 @@ namespace RC RC_UE4SS_API auto generate_uht_compatible_headers() -> void; RC_UE4SS_API auto generate_cxx_headers(const std::filesystem::path& output_dir) -> void; RC_UE4SS_API auto generate_lua_types(const std::filesystem::path& output_dir) -> void; + RC_UE4SS_API auto get_latest_version_check_setting() -> bool; + RC_UE4SS_API auto get_latest_ue4ss_version() -> StringType; + RC_UE4SS_API auto is_latest_ue4ss_version(StringType latest_ver) -> bool; auto get_debugging_ui() -> GUI::DebuggingGUI& { return m_debugging_gui; diff --git a/UE4SS/src/CrashDumper.cpp b/UE4SS/src/CrashDumper.cpp index d500eece8..9202ba9d3 100644 --- a/UE4SS/src/CrashDumper.cpp +++ b/UE4SS/src/CrashDumper.cpp @@ -58,7 +58,18 @@ namespace RC return EXCEPTION_CONTINUE_SEARCH; } - const std::wstring message = fmt::format(L"Crashdump written to: {}", dump_path); + std::wstring version_message = L""; + + if (UE4SSProgram::get_program().get_latest_version_check_setting()) + { + std::wstring latest_version = UE4SSProgram::get_program().get_latest_ue4ss_version(); + if (!UE4SSProgram::get_program().is_latest_ue4ss_version(latest_version)) + { + version_message = fmt::format(L"\n\nA newer version ({}) is available. Updating may solve your issue.", latest_version); + } + } + + const std::wstring message = fmt::format(L"Crashdump written to: {}{}", dump_path, version_message); MessageBoxW(NULL, message.c_str(), L"Fatal Error!", MB_OK); return EXCEPTION_EXECUTE_HANDLER; diff --git a/UE4SS/src/SettingsManager.cpp b/UE4SS/src/SettingsManager.cpp index 56557f7d4..325ac6850 100644 --- a/UE4SS/src/SettingsManager.cpp +++ b/UE4SS/src/SettingsManager.cpp @@ -57,6 +57,7 @@ namespace RC REGISTER_BOOL_SETTING(General.EnableDebugKeyBindings, section_general, EnableDebugKeyBindings) REGISTER_INT64_SETTING(General.SecondsToScanBeforeGivingUp, section_general, SecondsToScanBeforeGivingUp) REGISTER_BOOL_SETTING(General.UseUObjectArrayCache, section_general, bUseUObjectArrayCache) + REGISTER_BOOL_SETTING(General.LatestVersionCheck, section_general, bLatestVersionCheck) constexpr static File::CharType section_engine_version_override[] = STR("EngineVersionOverride"); REGISTER_INT64_SETTING(EngineVersionOverride.MajorVersion, section_engine_version_override, MajorVersion) diff --git a/UE4SS/src/UE4SSProgram.cpp b/UE4SS/src/UE4SSProgram.cpp index 2c613cb83..0b6aaca2c 100644 --- a/UE4SS/src/UE4SSProgram.cpp +++ b/UE4SS/src/UE4SSProgram.cpp @@ -56,6 +56,8 @@ #include #include +#include +#include namespace RC { @@ -226,6 +228,16 @@ namespace RC UE4SS_LIB_BETA_STARTED == 0 ? L"" : (UE4SS_LIB_IS_BETA == 0 ? L" Beta #?" : fmt::format(L" Beta #{}", UE4SS_LIB_VERSION_BETA))), to_wstring(UE4SS_LIB_BUILD_GITSHA)); + if (settings_manager.General.LatestVersionCheck) + { + StringType latest_version = get_latest_ue4ss_version(); + if (!is_latest_ue4ss_version(latest_version)) + { + if (latest_version != L"") + Output::send(STR("A newer version ({}) is available, please consider downloading from https://github.com/UE4SS-RE/RE-UE4SS/releases/latest\n"), latest_version); + } + } + #ifdef __clang__ #define UE4SS_COMPILER L"Clang" #else @@ -1460,6 +1472,126 @@ namespace RC Output::send(STR("SDK generated in {} seconds.\n"), generator_duration); } + auto UE4SSProgram::get_latest_version_check_setting() -> bool + { + return settings_manager.General.LatestVersionCheck; + } + + static auto write_callback(void* contents, size_t size, size_t nmemb, void* userp) -> size_t + { + ((std::string*)userp)->append((char*)contents, size * nmemb); + return size * nmemb; + } + + auto UE4SSProgram::get_latest_ue4ss_version() -> StringType + { + CURL* curl; + CURLcode response; + std::string finalUrl; + std::string tag; + + curl = curl_easy_init(); + if (curl) + { + // This is a redirect hack to avoid having to use github api, + // which would require a user agent such as a github app to be made in UE4SS org, + // and is not a good idea to use in a public project + // CI version: curl -L -s -o /dev/null -w "%{url_effective}" "https://github.com/UE4SS-RE/RE-UE4SS/releases/latest" + curl_easy_setopt(curl, CURLOPT_URL, "https://github.com/UE4SS-RE/RE-UE4SS/releases/latest"); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &finalUrl); + + response = curl_easy_perform(curl); + + if (response != CURLE_OK) + { + return L""; + } + else + { + char* effectiveUrl = nullptr; + curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effectiveUrl); + if (effectiveUrl) + { + finalUrl = std::string(effectiveUrl); + } + + std::size_t lastSlashPos = finalUrl.find_last_of('/'); + if (lastSlashPos != std::string::npos) + { + tag = finalUrl.substr(lastSlashPos + 1); + } + } + + curl_easy_cleanup(curl); + } + + if (tag.empty()) + { + return L""; + } + + return to_wstring(tag); + } + + static auto split_version(const std::string& version) -> std::vector + { + std::vector parts; + std::stringstream ss(version); + std::string item; + + while (std::getline(ss, item, '.')) + { + parts.push_back(std::stoi(item)); + } + + return parts; + } + + auto UE4SSProgram::is_latest_ue4ss_version(StringType latest_ver) -> bool + { + std::string current_version = fmt::format("{}.{}.{}", UE4SS_LIB_VERSION_MAJOR, UE4SS_LIB_VERSION_MINOR, UE4SS_LIB_VERSION_HOTFIX); + std::string latest_version = to_string(latest_ver); + if (latest_version.empty()) + { + // If we can't get the latest version, assume it's not + return false; + } + if (latest_version[0] == 'v') + { + latest_version = latest_version.substr(1); + } + + std::vector current = split_version(current_version); + std::vector latest = split_version(latest_version); + + while (current.size() < latest.size()) + { + current.push_back(0); + } + + while (latest.size() < current.size()) + { + latest.push_back(0); + } + + for (size_t i = 0; i < current.size(); ++i) + { + if (latest[i] > current[i]) + { + return false; + } + else if (latest[i] < current[i]) + { + return true; + } + } + + // If both equal + return true; + } + auto UE4SSProgram::stop_render_thread() -> void { if (m_render_thread.joinable()) @@ -1519,8 +1651,7 @@ namespace RC return m_input_handler.is_keydown_event_registered(key, modifier_keys); } - auto UE4SSProgram::find_mod_by_name_internal(std::wstring_view mod_name, IsInstalled is_installed, IsStarted is_started, FMBNI_ExtraPredicate extra_predicate) - -> Mod* + auto UE4SSProgram::find_mod_by_name_internal(std::wstring_view mod_name, IsInstalled is_installed, IsStarted is_started, FMBNI_ExtraPredicate extra_predicate) -> Mod* { auto mod_exists_with_name = std::find_if(get_program().m_mods.begin(), get_program().m_mods.end(), [&](auto& elem) -> bool { bool found = true; diff --git a/UE4SS/xmake.lua b/UE4SS/xmake.lua index aa0be80ad..28cd26cdc 100644 --- a/UE4SS/xmake.lua +++ b/UE4SS/xmake.lua @@ -7,6 +7,7 @@ add_requires("glfw 3.3.9", { debug = is_mode_debug() , configs = {runtimes = get add_requires("opengl", { debug = is_mode_debug(), configs = {runtimes = get_mode_runtimes()} }) add_requires("glaze v2.9.5", { debug = is_mode_debug(), configs = {runtimes = get_mode_runtimes()} }) add_requires("fmt 10.2.1", { debug = is_mode_debug(), configs = {runtimes = get_mode_runtimes()} }) +add_requires("libcurl 8.7.1", { debug = is_mode_debug(), configs = {runtimes = get_mode_runtimes()} }) option("ue4ssBetaIsStarted") set_default(true) @@ -66,6 +67,8 @@ target(projectName) add_packages("fmt", { public = true }) + add_packages("libcurl", { public = true }) + add_packages("imgui", "ImGuiTextEdit", "IconFontCppHeaders", "glfw", "opengl", { public = true }) add_packages("glaze", "polyhook_2", { public = true }) diff --git a/assets/Changelog.md b/assets/Changelog.md index 823a068df..f32939358 100644 --- a/assets/Changelog.md +++ b/assets/Changelog.md @@ -15,6 +15,8 @@ UE Platform support, which allows for much easier internal implementation of new Added new installation method by allowing overriding of the location of the `UE4SS.dll`, [documentation](https://docs.ue4ss.com/installation-guide.html#overriding-install-location). - ([UE4SS #506](https://github.com/UE4SS-RE/RE-UE4SS/pull/506)) - Buckminsterfullerene +Add opt-out checking for the latest version of UE4SS during load or when a crash dump is created. ([UE4SS #617](https://github.com/UE4SS-RE/RE-UE4SS/pull/617)) - Buckminsterfullerene + ### Live View Added search filter: `IncludeClassNames`. ([UE4SS #472](https://github.com/UE4SS-RE/RE-UE4SS/pull/472)) - Buckminsterfullerene @@ -127,6 +129,9 @@ Fixes mods not loading when UE4SS initializes too late ([UE4SS #454](https://git ### Added ```ini +[General] +bLatestVersionCheck = 1 + [Hooks] HookLoadMap = 1 HookAActorTick = 1 diff --git a/assets/UE4SS-settings.ini b/assets/UE4SS-settings.ini index 5280f7944..8449282c7 100644 --- a/assets/UE4SS-settings.ini +++ b/assets/UE4SS-settings.ini @@ -23,6 +23,11 @@ SecondsToScanBeforeGivingUp = 30 ; Default: true bUseUObjectArrayCache = true +; Whether to check if the user is running the latest stable version of UE4SS +; If enabled, and user is not running latest stable version, a warning will be displayed in console and crash popup box +; Default: 1 +bLatestVersionCheck = 1 + [EngineVersionOverride] MajorVersion = MinorVersion =