diff --git a/examples/example_plugin/Plugin.cpp b/examples/example_plugin/Plugin.cpp index 73aaec17..c6fffee6 100644 --- a/examples/example_plugin/Plugin.cpp +++ b/examples/example_plugin/Plugin.cpp @@ -24,6 +24,8 @@ SOFTWARE. #include #include #include +#include +#include #include @@ -179,6 +181,38 @@ class ExamplePlugin : public uevr::Plugin { API::get()->log_info("Running once on pre engine tick"); API::get()->execute_command(L"stat fps"); + // Log the UEngine name. + const auto uengine_fname = engine->get_fname(); + const auto uengine_name = uengine_fname->to_string(); + + // Convert from wide to narrow string (we do not have utility::narrow in this context). + std::string uengine_name_narrow{std::wstring_convert>{}.to_bytes(uengine_name)}; + + API::get()->log_info("Engine name: %s", uengine_name_narrow.c_str()); + + // Go through all of engine's fields and log their names. + const auto engine_class_ours = (API::UStruct*)engine->get_class(); + for (auto super = engine_class_ours; super != nullptr; super = super->get_super()) { + for (auto field = super->get_child_properties(); field != nullptr; field = field->get_next()) { + const auto field_fname = field->get_fname(); + const auto field_name = field_fname->to_string(); + const auto field_class = field->get_class(); + + std::wstring prepend{}; + + if (field_class != nullptr) { + const auto field_class_fname = field_class->get_fname(); + const auto field_class_name = field_class_fname->to_string(); + + prepend = field_class_name + L" "; + } + + // Convert from wide to narrow string (we do not have utility::narrow in this context). + std::string field_name_narrow{std::wstring_convert>{}.to_bytes(prepend + field_name)}; + API::get()->log_info(" Field name: %s", field_name_narrow.c_str()); + } + } + // Check if we can find the GameInstance and call is_a() on it. const auto game_instance = engine->get_property(L"GameInstance"); diff --git a/include/uevr/API.h b/include/uevr/API.h index 415ed28d..74fbe032 100644 --- a/include/uevr/API.h +++ b/include/uevr/API.h @@ -36,7 +36,7 @@ SOFTWARE. #define UEVR_OUT #define UEVR_PLUGIN_VERSION_MAJOR 2 -#define UEVR_PLUGIN_VERSION_MINOR 6 +#define UEVR_PLUGIN_VERSION_MINOR 7 #define UEVR_PLUGIN_VERSION_PATCH 0 #define UEVR_RENDERER_D3D11 0 @@ -66,6 +66,8 @@ DECLARE_UEVR_HANDLE(UEVR_FPropertyHandle); DECLARE_UEVR_HANDLE(UEVR_UStructHandle); DECLARE_UEVR_HANDLE(UEVR_UClassHandle); DECLARE_UEVR_HANDLE(UEVR_UFunctionHandle); +DECLARE_UEVR_HANDLE(UEVR_FNameHandle); +DECLARE_UEVR_HANDLE(UEVR_FFieldClassHandle); // OpenXR stuff DECLARE_UEVR_HANDLE(UEVR_XrInstance); @@ -233,6 +235,8 @@ typedef struct { typedef struct { UEVR_FFieldHandle (*get_next)(UEVR_FFieldHandle field); + UEVR_FFieldClassHandle (*get_class)(UEVR_FFieldHandle field); + UEVR_FNameHandle (*get_fname)(UEVR_FFieldHandle field); } UEVR_FFieldFunctions; typedef struct { @@ -263,6 +267,8 @@ typedef struct { void (*process_event)(UEVR_UObjectHandle object, UEVR_UFunctionHandle function, void* params); void (*call_function)(UEVR_UObjectHandle object, const wchar_t* name, void* params); + + UEVR_FNameHandle (*get_fname)(UEVR_UObjectHandle object); } UEVR_UObjectFunctions; typedef struct { @@ -278,6 +284,14 @@ typedef struct { UEVR_UObjectHandle (*get_first_object_by_class_name)(const wchar_t* class_name, bool allow_default); } UEVR_UObjectHookFunctions; +typedef struct { + UEVR_FNameHandle (*get_fname)(UEVR_FFieldClassHandle field_class); +} UEVR_FFieldClassFunctions; + +typedef struct { + unsigned int (*to_string)(UEVR_FNameHandle name, wchar_t* buffer, unsigned int buffer_size); +} UEVR_FNameFunctions; + typedef struct { const UEVR_SDKFunctions* functions; const UEVR_SDKCallbacks* callbacks; @@ -289,6 +303,8 @@ typedef struct { const UEVR_UClassFunctions* uclass; const UEVR_UFunctionFunctions* ufunction; const UEVR_UObjectHookFunctions* uobject_hook; + const UEVR_FFieldClassFunctions* ffield_class; + const UEVR_FNameFunctions* fname; } UEVR_SDKData; DECLARE_UEVR_HANDLE(UEVR_IVRSystem); diff --git a/include/uevr/API.hpp b/include/uevr/API.hpp index 74fcc6d5..fd097fd1 100644 --- a/include/uevr/API.hpp +++ b/include/uevr/API.hpp @@ -102,6 +102,7 @@ class API { struct FProperty; struct FFieldClass; struct FUObjectArray; + struct FName; template T* find_uobject(std::wstring_view name) { @@ -144,6 +145,33 @@ class API { return (FUObjectArray*)fn(); } + struct FName { + inline UEVR_FNameHandle to_handle() { return (UEVR_FNameHandle)this; } + inline UEVR_FNameHandle to_handle() const { return (UEVR_FNameHandle)this; } + + std::wstring to_string() const { + static const auto fn = initialize()->to_string; + const auto size = fn(to_handle(), nullptr, 0); + if (size == 0) { + return L""; + } + + std::wstring result(size, L'\0'); + fn(to_handle(), result.data(), size + 1); + return result; + } + + private: + static inline const UEVR_FNameFunctions* s_functions{nullptr}; + static inline const UEVR_FNameFunctions* initialize() { + if (s_functions == nullptr) { + s_functions = API::get()->sdk()->fname; + } + + return s_functions; + } + }; + struct UObject { inline UEVR_UObjectHandle to_handle() { return (UEVR_UObjectHandle)this; } inline UEVR_UObjectHandle to_handle() const { return (UEVR_UObjectHandle)this; } @@ -202,6 +230,11 @@ class API { return *get_property_data(name); } + FName* get_fname() const { + static const auto fn = initialize()->get_fname; + return (FName*)fn(to_handle()); + } + private: static inline const UEVR_UObjectFunctions* s_functions{nullptr}; inline static const UEVR_UObjectFunctions* initialize() { @@ -355,17 +388,16 @@ class API { static const auto fn = initialize()->get_next; return (FField*)fn(to_handle()); } - - // TODO: stubbed out for now - /* - inline std::wstring get_name() const { + + FName* get_fname() const { + static const auto fn = initialize()->get_fname; + return (FName*)fn(to_handle()); } FFieldClass* get_class() const { static const auto fn = initialize()->get_class; return (FFieldClass*)fn(to_handle()); } - */ private: static inline const UEVR_FFieldFunctions* s_functions{nullptr}; @@ -401,24 +433,27 @@ class API { struct FFieldClass { // TODO: stubbed out for now - /*inline UEVR_FFieldClassHandle to_handle() { return (UEVR_FFieldClassHandle)this; } + inline UEVR_FFieldClassHandle to_handle() { return (UEVR_FFieldClassHandle)this; } inline UEVR_FFieldClassHandle to_handle() const { return (UEVR_FFieldClassHandle)this; } + FName* get_fname() const { + static const auto fn = initialize()->get_fname; + return (FName*)fn(to_handle()); + } + std::wstring get_name() const { - static const auto fn = initialize()->get_name; - return fn(to_handle()); + return get_fname()->to_string(); } private: static inline const UEVR_FFieldClassFunctions* s_functions{nullptr}; static inline const UEVR_FFieldClassFunctions* initialize() { if (s_functions == nullptr) { - s_functions = API::get()->sdk()->ffieldclass; + s_functions = API::get()->sdk()->ffield_class; } return s_functions; } - */ }; // TODO diff --git a/src/CommitHash.hpp b/src/CommitHash.hpp index 04e6e408..c2af0a4e 100644 --- a/src/CommitHash.hpp +++ b/src/CommitHash.hpp @@ -1,4 +1,4 @@ #pragma once -#define UEVR_COMMIT_HASH "efd4c133d1ab679f1b72cea18d17f53e91869821" +#define UEVR_COMMIT_HASH "81e77749037bd11ab11d84c9598901fc36e6b9b7" #define UEVR_BUILD_DATE "17.02.2024" #define UEVR_BUILD_TIME "00:00" diff --git a/src/mods/PluginLoader.cpp b/src/mods/PluginLoader.cpp index 7a5f5f57..4d0a0077 100644 --- a/src/mods/PluginLoader.cpp +++ b/src/mods/PluginLoader.cpp @@ -339,6 +339,10 @@ UEVR_UObjectFunctions g_uobject_functions { [](UEVR_UObjectHandle obj, const wchar_t* name, void* params) { UOBJECT(obj)->call_function(name, params); }, + // get_fname + [](UEVR_UObjectHandle obj) { + return (UEVR_FNameHandle)&UOBJECT(obj)->get_fname(); + }, }; UEVR_UObjectArrayFunctions g_uobject_array_functions { @@ -355,6 +359,14 @@ UEVR_FFieldFunctions g_ffield_functions { [](UEVR_FFieldHandle field) { return (UEVR_FFieldHandle)FFIELD(field)->get_next(); }, + // get_class + [](UEVR_FFieldHandle field) { + return (UEVR_FFieldClassHandle)FFIELD(field)->get_class(); + }, + // get_fname + [](UEVR_FFieldHandle field) { + return (UEVR_FNameHandle)&FFIELD(field)->get_field_name(); + }, }; #define FPROPERTY(x) ((sdk::FProperty*)x) @@ -489,6 +501,35 @@ UEVR_UObjectHookFunctions g_uobjecthook_functions { uevr::uobjecthook::get_first_object_by_class_name }; +#define FFIELDCLASS(x) ((sdk::FFieldClass*)x) + +UEVR_FFieldClassFunctions g_ffield_class_functions { + // get_fname + [](UEVR_FFieldClassHandle field) { + return (UEVR_FNameHandle)&FFIELDCLASS(field)->get_name(); + }, +}; + +#define FNAME(x) ((sdk::FName*)x) + +UEVR_FNameFunctions g_fname_functions { + // to_string + [](UEVR_FNameHandle name, wchar_t* buffer, unsigned int buffer_size) -> unsigned int { + const auto result = FNAME(name)->to_string(); + + if (buffer == nullptr || buffer_size == 0) { + return (unsigned int)result.size(); + } + + const auto size = std::min(result.size(), (size_t)buffer_size - 1); + + memcpy(buffer, result.c_str(), size * sizeof(wchar_t)); + buffer[size] = L'\0'; + + return (unsigned int)size; + }, +}; + UEVR_SDKData g_sdk_data { &g_sdk_functions, &g_sdk_callbacks, @@ -499,7 +540,9 @@ UEVR_SDKData g_sdk_data { &g_ustruct_functions, &g_uclass_functions, &g_ufunction_functions, - &g_uobjecthook_functions + &g_uobjecthook_functions, + &g_ffield_class_functions, + &g_fname_functions, }; namespace uevr { @@ -922,11 +965,11 @@ void PluginLoader::early_init() try { namespace fs = std::filesystem; std::scoped_lock _{m_mux}; - std::string module_path{}; + std::wstring module_path{}; module_path.resize(1024, 0); - module_path.resize(GetModuleFileName(nullptr, module_path.data(), module_path.size())); - spdlog::info("[PluginLoader] Module path {}", module_path); + module_path.resize(GetModuleFileNameW(nullptr, module_path.data(), module_path.size())); + spdlog::info("[PluginLoader] Module path {}", utility::narrow(module_path)); const auto plugin_path = Framework::get_persistent_dir() / "plugins";