Skip to content

Commit

Permalink
feature: checking for latest ue4ss version
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Buckminsterfullerene02 committed Aug 12, 2024
1 parent 07bb2dd commit dfcd94b
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 3 deletions.
1 change: 1 addition & 0 deletions UE4SS/include/SettingsManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace RC
bool EnableDebugKeyBindings{false};
int64_t SecondsToScanBeforeGivingUp{30};
bool UseUObjectArrayCache{true};
bool LatestVersionCheck{true};
} General;

struct SectionEngineVersionOverride
Expand Down
3 changes: 3 additions & 0 deletions UE4SS/include/UE4SSProgram.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
13 changes: 12 additions & 1 deletion UE4SS/src/CrashDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions UE4SS/src/SettingsManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
135 changes: 133 additions & 2 deletions UE4SS/src/UE4SSProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
#include <UnrealDef.hpp>

#include <polyhook2/PE/IatHook.hpp>
#include <curl/curl.h>
#include <glaze/glaze.hpp>

namespace RC
{
Expand Down Expand Up @@ -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<LogLevel::Warning>(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
Expand Down Expand Up @@ -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<int>
{
std::vector<int> 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<int> current = split_version(current_version);
std::vector<int> 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())
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions UE4SS/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 })
Expand Down
5 changes: 5 additions & 0 deletions assets/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions assets/UE4SS-settings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down

0 comments on commit dfcd94b

Please sign in to comment.