From f63f0f2a9f008fc7a42b0a981855c112194a0308 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sun, 31 Dec 2023 17:07:34 -0600 Subject: [PATCH 01/24] Remove boost --- CMakeLists.txt | 3 --- README.md | 2 -- cmake/config.cmake.in | 1 - include/RE/B/BSTHashMap.h | 37 ++++++++++++++++++------------------- include/SKSE/Impl/PCH.h | 1 - vcpkg.json | 1 - 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a1852c05..1a08923da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,6 @@ if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") endif() find_package(binary_io REQUIRED CONFIG) -find_package(Boost MODULE REQUIRED) find_package(spdlog REQUIRED CONFIG) include(cmake/sourcelist.cmake) @@ -38,7 +37,6 @@ add_library("${PROJECT_NAME}::${PROJECT_NAME}" ALIAS "${PROJECT_NAME}") target_compile_definitions( "${PROJECT_NAME}" PUBLIC - BOOST_STL_INTERFACES_DISABLE_CONCEPTS WINVER=0x0601 # windows 7, minimum supported version by skyrim special edition _WIN32_WINNT=0x0601 "$<$:SKSE_SUPPORT_XBYAK=1>" @@ -95,7 +93,6 @@ target_link_libraries( "${PROJECT_NAME}" PUBLIC binary_io::binary_io - Boost::headers spdlog::spdlog Version.lib ) diff --git a/README.md b/README.md index 759cc741c..ed3755510 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,6 @@ ## Build Dependencies -* [Boost](https://www.boost.org/) - * Stl_interfaces * [spdlog](https://github.com/gabime/spdlog) * [Visual Studio Community 2019 16.10.0 Preview 3.0](https://visualstudio.microsoft.com/vs/preview/) * Desktop development with C++ diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in index 64a949649..ffecc2033 100644 --- a/cmake/config.cmake.in +++ b/cmake/config.cmake.in @@ -2,5 +2,4 @@ include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") include(CMakeFindDependencyMacro) find_dependency(binary_io CONFIG) -find_dependency(Boost MODULE) find_dependency(spdlog CONFIG) diff --git a/include/RE/B/BSTHashMap.h b/include/RE/B/BSTHashMap.h index 323317e6a..1059802ec 100644 --- a/include/RE/B/BSTHashMap.h +++ b/include/RE/B/BSTHashMap.h @@ -113,25 +113,14 @@ namespace RE }; template - class iterator_base : - public boost::stl_interfaces::iterator_interface< - iterator_base, - std::forward_iterator_tag, - U> + class iterator_base { - private: - using super = - boost::stl_interfaces::iterator_interface< - iterator_base, - std::forward_iterator_tag, - U>; - public: - using difference_type = typename super::difference_type; - using value_type = typename super::value_type; - using pointer = typename super::pointer; - using reference = typename super::reference; - using iterator_category = typename super::iterator_category; + using difference_type = std::ptrdiff_t; + using value_type = std::remove_const_t; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::forward_iterator_tag; iterator_base() = default; ~iterator_base() = default; @@ -176,7 +165,17 @@ namespace RE return *this; } - using super::operator++; + iterator_base operator++(int) noexcept + { + iterator_base result = *this; + ++result; + return result; + } + + [[nodiscard]] pointer operator->() const noexcept + { + return &**this; + } protected: friend class BSTScatterTable; @@ -740,7 +739,7 @@ namespace RE namespace detail { using _dummy_bsthashmap = BSTHashMap; - BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(_dummy_bsthashmap::iterator, std::forward_iterator); + static_assert(std::forward_iterator<_dummy_bsthashmap::iterator>); } template < diff --git a/include/SKSE/Impl/PCH.h b/include/SKSE/Impl/PCH.h index 58dbd2ba2..d38454d65 100644 --- a/include/SKSE/Impl/PCH.h +++ b/include/SKSE/Impl/PCH.h @@ -59,7 +59,6 @@ static_assert( #pragma warning(push) #include -#include #include #include #pragma warning(pop) diff --git a/vcpkg.json b/vcpkg.json index a6ee45c80..e1afdea7b 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -6,7 +6,6 @@ "license": "MIT", "supports": "windows & x64", "dependencies": [ - "boost-stl-interfaces", "fmt", "rsm-binary-io", "spdlog" From 3b7a36d485fbdff026946edcece4db7e79e7b946 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sun, 31 Dec 2023 17:09:22 -0600 Subject: [PATCH 02/24] .gitignore --- .gitignore | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 50253ac97..50a52675a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,12 @@ -/build* +# dot folders +.vs/ +.vscode/ +.xmake/ + +# folders +build/ +out/ + +# files +*.zip CMakeUserPresets.json -/out* -/.vs* From dd66203c508ecb71dc786f997e2b071fd58e3923 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Mon, 1 Jan 2024 16:14:59 -0600 Subject: [PATCH 03/24] Remove fmtlib, use std::format --- include/RE/A/ActorValueList.h | 2 ++ include/RE/E/EffectArchetypes.h | 2 ++ include/RE/F/FormTypes.h | 2 ++ include/RE/M/MaterialIDs.h | 2 ++ include/REL/Relocation.h | 16 ++++++++-------- include/SKSE/Impl/PCH.h | 4 ++-- include/SKSE/Logger.h | 4 ++-- src/RE/C/Color.cpp | 2 +- src/RE/N/NiColor.cpp | 2 +- src/SKSE/Translation.cpp | 2 +- vcpkg.json | 1 - 11 files changed, 23 insertions(+), 16 deletions(-) diff --git a/include/RE/A/ActorValueList.h b/include/RE/A/ActorValueList.h index 581a2ef03..9baf8fded 100644 --- a/include/RE/A/ActorValueList.h +++ b/include/RE/A/ActorValueList.h @@ -24,6 +24,7 @@ namespace RE }; } +#ifdef FMT_VERSION namespace fmt { template <> @@ -43,6 +44,7 @@ namespace fmt } }; } +#endif #ifdef __cpp_lib_format namespace std diff --git a/include/RE/E/EffectArchetypes.h b/include/RE/E/EffectArchetypes.h index b2b2b538e..7c7729dae 100644 --- a/include/RE/E/EffectArchetypes.h +++ b/include/RE/E/EffectArchetypes.h @@ -69,6 +69,7 @@ namespace std } } +#ifdef FMT_VERSION namespace fmt { template <> @@ -87,6 +88,7 @@ namespace fmt } }; } +#endif #ifdef __cpp_lib_format namespace std diff --git a/include/RE/F/FormTypes.h b/include/RE/F/FormTypes.h index 746faa446..55adfb1e2 100644 --- a/include/RE/F/FormTypes.h +++ b/include/RE/F/FormTypes.h @@ -291,6 +291,7 @@ namespace std } } +#ifdef FMT_VERSION namespace fmt { template <> @@ -309,6 +310,7 @@ namespace fmt } }; } +#endif #ifdef __cpp_lib_format namespace std diff --git a/include/RE/M/MaterialIDs.h b/include/RE/M/MaterialIDs.h index cd1ef9260..19289b09a 100644 --- a/include/RE/M/MaterialIDs.h +++ b/include/RE/M/MaterialIDs.h @@ -106,6 +106,7 @@ namespace std } } +#ifdef FMT_VERSION namespace fmt { template <> @@ -124,6 +125,7 @@ namespace fmt } }; } +#endif #ifdef __cpp_lib_format namespace std diff --git a/include/REL/Relocation.h b/include/REL/Relocation.h index 20b8b7d7e..b71423f5e 100644 --- a/include/REL/Relocation.h +++ b/include/REL/Relocation.h @@ -482,7 +482,7 @@ namespace REL auto handle = WinAPI::GetModuleHandle(_filename.c_str()); if (handle == nullptr) { stl::report_and_fail( - fmt::format( + std::format( "Failed to obtain module handle for: \"{0}\".\n" "You have likely renamed the executable to something unexpected. " "Renaming the executable back to \"{0}\" may resolve the issue."sv, @@ -503,7 +503,7 @@ namespace REL _version = *version; } else { stl::report_and_fail( - fmt::format( + std::format( "Failed to obtain file version info for: {}\n" "Please contact the author of this script extender plugin for further assistance."sv, stl::utf16_to_utf8(_filename).value_or(""s))); @@ -580,7 +580,7 @@ namespace REL }); if (it == _offset2id.end()) { stl::report_and_fail( - fmt::format( + std::format( "Failed to find the offset within the database: 0x{:08X}"sv, a_offset)); } @@ -624,7 +624,7 @@ namespace REL }); if (it == _id2offset.end()) { stl::report_and_fail( - fmt::format( + std::format( "Failed to find the id within the address library: {}\n" "This means this script extender plugin is incompatible with the address " "library for this version of the game, and thus does not support it."sv, @@ -649,7 +649,7 @@ namespace REL if (format != 1) { #endif stl::report_and_fail( - fmt::format( + std::format( "Unsupported address library format: {}\n" "This means this script extender plugin is incompatible with the address " "library available for this version of the game, and thus does not " @@ -695,7 +695,7 @@ namespace REL const auto version = Module::get().version(); const auto filename = stl::utf8_to_utf16( - fmt::format( + std::format( #ifdef SKYRIM_SUPPORT_AE "Data/SKSE/Plugins/versionlib-{}.bin"sv, #else @@ -735,7 +735,7 @@ namespace REL } } catch (const std::system_error&) { stl::report_and_fail( - fmt::format( + std::format( "Failed to locate an appropriate address library with the path: {}\n" "This means you are missing the address library for this specific version of " "the game. Please continue to the mod page for address library to download " @@ -1105,7 +1105,7 @@ namespace REL if (!this->match(a_address)) { const auto version = Module::get().version(); stl::report_and_fail( - fmt::format( + std::format( "A pattern has failed to match.\n" "This means the plugin is incompatible with the current version of the game ({}.{}.{}). " "Head to the mod page of this plugin to see if an update is available."sv, diff --git a/include/SKSE/Impl/PCH.h b/include/SKSE/Impl/PCH.h index d38454d65..0a4b8051d 100644 --- a/include/SKSE/Impl/PCH.h +++ b/include/SKSE/Impl/PCH.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,6 @@ static_assert( #pragma warning(push) #include -#include #include #pragma warning(pop) @@ -599,7 +599,7 @@ namespace SKSE } return utf8_to_utf16( - fmt::format( + std::format( "{}({}): {}"sv, filename, a_loc.line(), diff --git a/include/SKSE/Logger.h b/include/SKSE/Logger.h index fa7218afa..1fcc425db 100644 --- a/include/SKSE/Logger.h +++ b/include/SKSE/Logger.h @@ -11,7 +11,7 @@ a_func() = delete; \ \ explicit a_func( \ - fmt::format_string a_fmt, \ + spdlog::format_string_t a_fmt, \ Args&&... a_args, \ std::source_location a_loc = std::source_location::current()) \ { \ @@ -27,7 +27,7 @@ }; \ \ template \ - a_func(fmt::format_string, Args&&...) -> a_func; + a_func(spdlog::format_string_t, Args&&...) -> a_func; namespace SKSE::log { diff --git a/src/RE/C/Color.cpp b/src/RE/C/Color.cpp index 08cd9d9f3..cdbb51b0b 100644 --- a/src/RE/C/Color.cpp +++ b/src/RE/C/Color.cpp @@ -18,6 +18,6 @@ namespace RE std::string Color::ToHex() const { - return fmt::format("{:X}{:X}{:X}{:X}", red, green, blue, alpha); + return std::format("{:X}{:X}{:X}{:X}", red, green, blue, alpha); } } diff --git a/src/RE/N/NiColor.cpp b/src/RE/N/NiColor.cpp index b07f4351f..66d271a5d 100644 --- a/src/RE/N/NiColor.cpp +++ b/src/RE/N/NiColor.cpp @@ -25,7 +25,7 @@ namespace RE auto g = static_cast(green * 255); auto b = static_cast(blue * 255); - return fmt::format("{:X}{:X}{:X}", r, g, b); + return std::format("{:X}{:X}{:X}", r, g, b); } NiColorA::NiColorA(const Color& a_rhs) : diff --git a/src/SKSE/Translation.cpp b/src/SKSE/Translation.cpp index 3c7876db3..2a3c2b668 100644 --- a/src/SKSE/Translation.cpp +++ b/src/SKSE/Translation.cpp @@ -58,7 +58,7 @@ namespace SKSE // Construct translation filename std::string language = (setting && setting->GetType() == RE::Setting::Type::kString) ? setting->data.s : "ENGLISH"s; - std::string path = fmt::format("Interface\\Translations\\{}_{}.txt"sv, a_name, language); + std::string path = std::format("Interface\\Translations\\{}_{}.txt"sv, a_name, language); RE::BSResourceNiBinaryStream fileStream{ path }; if (!fileStream.good()) { diff --git a/vcpkg.json b/vcpkg.json index e1afdea7b..457ac1957 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -6,7 +6,6 @@ "license": "MIT", "supports": "windows & x64", "dependencies": [ - "fmt", "rsm-binary-io", "spdlog" ] From 06ed6387c22c6998954af05a0df7100136c64f8d Mon Sep 17 00:00:00 2001 From: shad0wshayd3 Date: Mon, 1 Jan 2024 15:40:39 -0700 Subject: [PATCH 04/24] Misc Blood Magic Defs I forgot to submit a PR for these a year ago --- include/RE/A/AIProcess.h | 3 +++ include/RE/A/Actor.h | 2 ++ include/RE/G/GFxValue.h | 2 ++ include/RE/H/HUDMenu.h | 7 +++++++ include/RE/M/MagicCaster.h | 1 + include/RE/M/MagicTarget.h | 13 ++++++------ include/RE/P/PlayerCharacter.h | 1 + include/RE/T/TESObjectREFR.h | 1 + include/RE/T/TutorialMenu.h | 7 +++++++ src/RE/A/AIProcess.cpp | 36 ++++++++++++++++++++++++++++++++++ src/RE/A/Actor.cpp | 15 ++++++++++++++ src/RE/G/GFxValue.cpp | 13 ++++++++++++ src/RE/M/MagicCaster.cpp | 9 ++++++++- src/RE/M/MagicSystem.cpp | 35 ++++++++++++++++++--------------- src/RE/M/MagicTarget.cpp | 10 ++++++++++ src/RE/P/PlayerCharacter.cpp | 7 +++++++ src/RE/T/TESObjectREFR.cpp | 7 +++++++ 17 files changed, 146 insertions(+), 23 deletions(-) diff --git a/include/RE/A/AIProcess.h b/include/RE/A/AIProcess.h index d7581313a..0d1c6b537 100644 --- a/include/RE/A/AIProcess.h +++ b/include/RE/A/AIProcess.h @@ -1,6 +1,7 @@ #pragma once #include "RE/A/ActorPackage.h" +#include "RE/A/ActorValues.h" #include "RE/B/BGSDefaultObjectManager.h" #include "RE/B/BSTArray.h" #include "RE/B/BSTList.h" @@ -161,6 +162,7 @@ namespace RE [[nodiscard]] bool GetIsSummonedCreature() const noexcept; NiAVObject* GetMagicNode(const BSTSmartPointer& a_biped) const; ObjectRefHandle GetOccupiedFurniture() const; + float GetRegenDelay(ActorValue a_actorvalue) const; TESPackage* GetRunningPackage() const; Actor* GetUserData() const; float GetVoiceRecoveryTime() const; @@ -181,6 +183,7 @@ namespace RE bool SetupSpecialIdle(Actor* a_actor, DEFAULT_OBJECT a_action, TESIdleForm* a_idle, bool a_arg5, bool a_arg6, TESObjectREFR* a_target); void StopCurrentIdle(Actor* a_actor, bool a_forceIdleStop); void Update3DModel(Actor* a_actor); + void UpdateRegenDelay(ActorValue a_actorValue, float a_regenDelay); // members MiddleLowProcessData* middleLow; // 000 diff --git a/include/RE/A/Actor.h b/include/RE/A/Actor.h index 38017deb7..656bc0e73 100644 --- a/include/RE/A/Actor.h +++ b/include/RE/A/Actor.h @@ -543,6 +543,7 @@ namespace RE double GetMoveDirectionRelativeToFacing(); ObjectRefHandle GetOccupiedFurniture() const; TESRace* GetRace() const; + float GetRegenDelay(ActorValue a_actorValue) const; bool GetRider(NiPointer& a_outRider); [[nodiscard]] TESObjectARMO* GetSkin() const; [[nodiscard]] TESObjectARMO* GetSkin(BGSBipedObjectForm::BipedObjectSlot a_slot, bool a_noInit = false); @@ -616,6 +617,7 @@ namespace RE void UpdateAwakeSound(NiAVObject* a_obj3D); void Update3DModel(); void UpdateHairColor(); + void UpdateRegenDelay(ActorValue a_actorValue, float a_regenDelay); void UpdateSkinColor(); void UpdateWeaponAbility(TESForm* a_weapon, ExtraDataList* a_extraData, bool a_leftHand); void VisitArmorAddon(TESObjectARMO* a_armor, TESObjectARMA* a_arma, std::function a_visitor); diff --git a/include/RE/G/GFxValue.h b/include/RE/G/GFxValue.h index fde0dd501..e9965649b 100644 --- a/include/RE/G/GFxValue.h +++ b/include/RE/G/GFxValue.h @@ -260,6 +260,7 @@ namespace RE bool SetText(void* a_data, const char* a_text, bool a_isHTML); bool AttachMovie(void* a_data, GFxValue* a_movieClip, const char* a_symbolName, const char* a_instanceName, std::int32_t a_depth, const GFxValue* a_initObj); + bool CreateEmptyMovieClip(void* a_data, GFxValue* a_movieClip, const char* a_instanceName, std::int32_t a_depth); bool GotoAndPlay(void* a_data, const char* a_frame, bool a_stop); bool IsSameContext(const ObjectInterface* a_rhs) const; @@ -399,6 +400,7 @@ namespace RE // AS MovieClip support. Valid for MovieClips. bool AttachMovie(GFxValue* a_movieClip, const char* a_symbolName, const char* a_instanceName, std::int32_t a_depth = -1, const GFxValue* a_initObj = nullptr); + bool CreateEmptyMovieClip(GFxValue* a_movieClip, const char* a_instanceName, std::int32_t a_depth = -1); bool GotoAndPlay(const char* a_frame); bool GotoAndStop(const char* a_frame); diff --git a/include/RE/H/HUDMenu.h b/include/RE/H/HUDMenu.h index 21d676b58..edfceee1f 100644 --- a/include/RE/H/HUDMenu.h +++ b/include/RE/H/HUDMenu.h @@ -40,6 +40,13 @@ namespace RE // override (BSTEventSink) BSEventNotifyControl ProcessEvent(const BSRemoteGamepadEvent* a_event, BSTEventSource* a_eventSource) override; // 01 + static void FlashMeter(ActorValue a_actorValue) + { + using func_t = decltype(&HUDMenu::FlashMeter); + REL::Relocation func{ RELOCATION_ID(51907, 52845) }; + return func(a_actorValue); + } + static void UpdateCrosshairMagicTarget(bool a_valid) { using func_t = decltype(&HUDMenu::UpdateCrosshairMagicTarget); diff --git a/include/RE/M/MagicCaster.h b/include/RE/M/MagicCaster.h index 619e73c7a..63df5cca6 100644 --- a/include/RE/M/MagicCaster.h +++ b/include/RE/M/MagicCaster.h @@ -78,6 +78,7 @@ namespace RE float GetCurrentSpellCost(); void InterruptCast(bool a_refund); void PlayReleaseSound(MagicItem* a_item); + void SetCurrentSpell(MagicItem* a_item); bool TestProjectilePlacement(const Effect& a_effect, const bhkPickData& a_pickData); void UpdateImpl(float a_delta); diff --git a/include/RE/M/MagicTarget.h b/include/RE/M/MagicTarget.h index f36dd9277..45bb4009b 100644 --- a/include/RE/M/MagicTarget.h +++ b/include/RE/M/MagicTarget.h @@ -86,12 +86,13 @@ namespace RE virtual float CheckResistance(MagicItem* a_magicItem, Effect* a_effect, TESBoundObject* a_object); // 0A - { return 1.0; } virtual bool CheckAbsorb(Actor* a_actor, MagicItem* a_magicItem, const Effect* a_effect); // 0B - { return false; } - bool DispelEffect(MagicItem* a_spell, BSPointerHandle& a_caster, ActiveEffect* a_effect = nullptr); - void DispelEffectsWithArchetype(Archetype a_type, bool a_force); - bool HasEffectWithArchetype(Archetype a_type); - bool HasMagicEffect(EffectSetting* a_effect); - bool HasMagicEffectWithKeyword(BGSKeyword* a_keyword, std::uint64_t a_arg2); - void VisitEffects(ForEachActiveEffectVisitor& visitor); + bool DispelEffect(MagicItem* a_spell, BSPointerHandle& a_caster, ActiveEffect* a_effect = nullptr); + void DispelEffectsWithArchetype(Archetype a_type, bool a_force); + Actor* GetTargetAsActor(); + bool HasEffectWithArchetype(Archetype a_type); + bool HasMagicEffect(EffectSetting* a_effect); + bool HasMagicEffectWithKeyword(BGSKeyword* a_keyword, std::uint64_t a_arg2); + void VisitEffects(ForEachActiveEffectVisitor& visitor); // members SpellDispelData* postUpdateDispelList; // 08 diff --git a/include/RE/P/PlayerCharacter.h b/include/RE/P/PlayerCharacter.h index 267d362a1..2bd604d56 100644 --- a/include/RE/P/PlayerCharacter.h +++ b/include/RE/P/PlayerCharacter.h @@ -367,6 +367,7 @@ namespace RE TintMask* GetTintMask(std::uint32_t a_tintType, std::uint32_t a_index); bool HasActorDoingCommand() const; bool IsGrabbing() const; + void PlayMagicFailureSound(MagicSystem::SpellType a_spellType); void PlayPickupEvent(TESForm* a_item, TESForm* a_containerOwner, TESObjectREFR* a_containerRef, EventType a_eventType); void SetAIDriven(bool a_enable); void SetEscaping(bool a_flag, bool a_escaped); diff --git a/include/RE/T/TESObjectREFR.h b/include/RE/T/TESObjectREFR.h index f711cf017..a26df60ae 100644 --- a/include/RE/T/TESObjectREFR.h +++ b/include/RE/T/TESObjectREFR.h @@ -366,6 +366,7 @@ namespace RE ObjectRefHandle CreateRefHandle(); void DoTrap(TrapData& a_data); void DoTrap(TrapEntry* a_trap, TargetEntry* a_target); + void Enable(bool a_resetInventory); NiAVObject* Get3D() const; NiAVObject* Get3D(bool a_firstPerson) const; TESNPC* GetActorOwner(); diff --git a/include/RE/T/TutorialMenu.h b/include/RE/T/TutorialMenu.h index 6720e4a33..6d41bd8c7 100644 --- a/include/RE/T/TutorialMenu.h +++ b/include/RE/T/TutorialMenu.h @@ -20,6 +20,13 @@ namespace RE void Accept(CallbackProcessor* a_processor) override; // 01 UI_MESSAGE_RESULTS ProcessMessage(UIMessage& a_message) override; // 04 + static void OpenTutorialMenu(DEFAULT_OBJECT a_tutorial) + { + using func_t = decltype(&TutorialMenu::OpenTutorialMenu); + REL::Relocation func{ RELOCATION_ID(51818, 52692) }; + return func(a_tutorial); + } + // members GFxValue root; // 30 - "Menu_mc" }; diff --git a/src/RE/A/AIProcess.cpp b/src/RE/A/AIProcess.cpp index 74ebd89d0..39e0f1d09 100644 --- a/src/RE/A/AIProcess.cpp +++ b/src/RE/A/AIProcess.cpp @@ -96,6 +96,23 @@ namespace RE } } + float AIProcess::GetRegenDelay(ActorValue a_actorValue) const + { + if (high) { + switch (a_actorValue) { + case ActorValue::kHealth: + return high->healthRegenDelay; + case ActorValue::kMagicka: + return high->magickaRegenDelay; + case ActorValue::kStamina: + return high->staminaRegenDelay; + default: + break; + } + } + return 0.0f; + } + TESPackage* AIProcess::GetRunningPackage() const { TESPackage* package = nullptr; @@ -254,4 +271,23 @@ namespace RE REL::Relocation func{ Offset::AIProcess::Update3DModel }; return func(this, a_actor); } + + void AIProcess::UpdateRegenDelay(ActorValue a_actorValue, float a_regenDelay) + { + if (high) { + switch (a_actorValue) { + case ActorValue::kHealth: + high->healthRegenDelay = a_regenDelay; + break; + case ActorValue::kMagicka: + high->magickaRegenDelay = a_regenDelay; + break; + case ActorValue::kStamina: + high->staminaRegenDelay = a_regenDelay; + break; + default: + break; + } + } + } } diff --git a/src/RE/A/Actor.cpp b/src/RE/A/Actor.cpp index 858bb1176..cfc81a100 100644 --- a/src/RE/A/Actor.cpp +++ b/src/RE/A/Actor.cpp @@ -527,6 +527,14 @@ namespace RE return base ? base->race : nullptr; } + float Actor::GetRegenDelay(ActorValue a_actorValue) const + { + if (currentProcess) { + return currentProcess->GetRegenDelay(a_actorValue); + } + return 0.0f; + } + bool Actor::GetRider(NiPointer& a_outRider) { using func_t = decltype(&Actor::GetRider); @@ -1088,6 +1096,13 @@ namespace RE } } + void Actor::UpdateRegenDelay(ActorValue a_actorValue, float a_regenDelay) + { + if (currentProcess) { + currentProcess->UpdateRegenDelay(a_actorValue, a_regenDelay); + } + } + void Actor::UpdateSkinColor() { const auto* npc = GetActorBase(); diff --git a/src/RE/G/GFxValue.cpp b/src/RE/G/GFxValue.cpp index 2b1ef15d9..d6970606d 100644 --- a/src/RE/G/GFxValue.cpp +++ b/src/RE/G/GFxValue.cpp @@ -424,6 +424,13 @@ namespace RE return func(this, a_data, a_movieClip, a_symbolName, a_instanceName, a_depth, a_initObj); } + bool GFxValue::ObjectInterface::CreateEmptyMovieClip(void* a_data, GFxValue* a_movieClip, const char* a_instanceName, std::int32_t a_depth) + { + using func_t = decltype(&GFxValue::ObjectInterface::CreateEmptyMovieClip); + REL::Relocation func{ RELOCATION_ID(80201, 82224) }; + return func(this, a_data, a_movieClip, a_instanceName, a_depth); + } + bool GFxValue::ObjectInterface::GotoAndPlay(void* a_data, const char* a_frame, bool a_stop) { using func_t = decltype(&GFxValue::ObjectInterface::GotoAndPlay); @@ -967,6 +974,12 @@ namespace RE return _objectInterface->AttachMovie(_value.obj, a_movieClip, a_symbolName, a_instanceName, a_depth, a_initObj); } + bool GFxValue::CreateEmptyMovieClip(GFxValue* a_movieClip, const char* a_instanceName, std::int32_t a_depth) + { + assert(IsDisplayObject()); + return _objectInterface->CreateEmptyMovieClip(_value.obj, a_movieClip, a_instanceName, a_depth); + } + bool GFxValue::GotoAndPlay(const char* a_frame) { assert(IsDisplayObject()); diff --git a/src/RE/M/MagicCaster.cpp b/src/RE/M/MagicCaster.cpp index f2c557539..b80f16ec4 100644 --- a/src/RE/M/MagicCaster.cpp +++ b/src/RE/M/MagicCaster.cpp @@ -16,7 +16,7 @@ namespace RE bool MagicCaster::FindTargets(float a_effectivenessMult, std::uint32_t& a_targetCount, TESBoundObject* a_source, bool a_loadCast, bool a_adjustOnlyHostileEffectiveness) { using func_t = decltype(&MagicCaster::FindTargets); - REL::Relocation func{ RELOCATION_ID(33676, 34456) }; + REL::Relocation func{ RELOCATION_ID(33632, 34410) }; return func(this, a_effectivenessMult, a_targetCount, a_source, a_loadCast, a_adjustOnlyHostileEffectiveness); } @@ -48,6 +48,13 @@ namespace RE return func(this, a_item); } + void MagicCaster::SetCurrentSpell(MagicItem* a_item) + { + using func_t = decltype(&MagicCaster::SetCurrentSpell); + REL::Relocation func{ RELOCATION_ID(33644, 34422) }; + return func(this, a_item); + } + bool MagicCaster::TestProjectilePlacement(const Effect& a_effect, const bhkPickData& a_pickData) { if (auto baseEffect = a_effect.baseEffect) { diff --git a/src/RE/M/MagicSystem.cpp b/src/RE/M/MagicSystem.cpp index 2d942435f..49bd0d358 100644 --- a/src/RE/M/MagicSystem.cpp +++ b/src/RE/M/MagicSystem.cpp @@ -2,24 +2,27 @@ namespace RE { - const char* GetCannotCastString(MagicSystem::CannotCastReason a_reason) + namespace MagicSystem { - using func_t = decltype(&MagicSystem::GetCannotCastString); - REL::Relocation func{ RELOCATION_ID(11295, 11423) }; - return func(a_reason); - } + const char* GetCannotCastString(MagicSystem::CannotCastReason a_reason) + { + using func_t = decltype(&MagicSystem::GetCannotCastString); + REL::Relocation func{ RELOCATION_ID(11295, 11423) }; + return func(a_reason); + } - float GetMagicCasterTargetUpdateInterval() - { - using func_t = decltype(&MagicSystem::GetMagicCasterTargetUpdateInterval); - REL::Relocation func{ RELOCATION_ID(11294, 11422) }; - return func(); - } + float GetMagicCasterTargetUpdateInterval() + { + using func_t = decltype(&MagicSystem::GetMagicCasterTargetUpdateInterval); + REL::Relocation func{ RELOCATION_ID(11294, 11422) }; + return func(); + } - BGSSoundDescriptorForm* GetMagicFailureSound(MagicSystem::SpellType a_type) - { - using func_t = decltype(&MagicSystem::GetMagicFailureSound); - REL::Relocation func{ RELOCATION_ID(11286, 11411) }; - return func(a_type); + BGSSoundDescriptorForm* GetMagicFailureSound(MagicSystem::SpellType a_type) + { + using func_t = decltype(&MagicSystem::GetMagicFailureSound); + REL::Relocation func{ RELOCATION_ID(11286, 11411) }; + return func(a_type); + } } } diff --git a/src/RE/M/MagicTarget.cpp b/src/RE/M/MagicTarget.cpp index e8939d719..e26df0608 100644 --- a/src/RE/M/MagicTarget.cpp +++ b/src/RE/M/MagicTarget.cpp @@ -1,6 +1,7 @@ #include "RE/M/MagicTarget.h" #include "RE/A/ActiveEffect.h" +#include "RE/A/Actor.h" #include "RE/B/BSTList.h" #include "RE/E/EffectSetting.h" @@ -33,6 +34,15 @@ namespace RE } } + Actor* MagicTarget::GetTargetAsActor() + { + if (MagicTargetIsActor()) { + return static_cast(this); + } + + return nullptr; + } + bool MagicTarget::HasEffectWithArchetype(Archetype a_type) { auto effects = GetActiveEffectList(); diff --git a/src/RE/P/PlayerCharacter.cpp b/src/RE/P/PlayerCharacter.cpp index 0b8e18750..bb901f52c 100644 --- a/src/RE/P/PlayerCharacter.cpp +++ b/src/RE/P/PlayerCharacter.cpp @@ -150,6 +150,13 @@ namespace RE return static_cast(grabbedObject); } + void PlayerCharacter::PlayMagicFailureSound(MagicSystem::SpellType a_spellType) + { + using func_t = decltype(&PlayerCharacter::PlayMagicFailureSound); + REL::Relocation func{ RELOCATION_ID(39486, 40565) }; + return func(this, a_spellType); + } + void PlayerCharacter::PlayPickupEvent(TESForm* a_item, TESForm* a_containerOwner, TESObjectREFR* a_containerRef, EventType a_eventType) { using func_t = decltype(&PlayerCharacter::PlayPickupEvent); diff --git a/src/RE/T/TESObjectREFR.cpp b/src/RE/T/TESObjectREFR.cpp index 0ec42cd9d..f7a782f8d 100644 --- a/src/RE/T/TESObjectREFR.cpp +++ b/src/RE/T/TESObjectREFR.cpp @@ -92,6 +92,13 @@ namespace RE return DoTrap2(a_trap, a_target); } + void TESObjectREFR::Enable(bool a_resetInventory) + { + using func_t = decltype(&TESObjectREFR::Enable); + REL::Relocation func{ RELOCATION_ID(19373, 19800) }; + return func(this, a_resetInventory); + } + NiAVObject* TESObjectREFR::Get3D() const { return Get3D2(); From 5183ce52e5a23ed51eaed45864c9f59007155131 Mon Sep 17 00:00:00 2001 From: Bobbyclue Date: Thu, 4 Jan 2024 21:56:07 -0500 Subject: [PATCH 05/24] Update MagicSystem.cpp Added missing namespace --- src/RE/M/MagicSystem.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/RE/M/MagicSystem.cpp b/src/RE/M/MagicSystem.cpp index 2d942435f..49bd0d358 100644 --- a/src/RE/M/MagicSystem.cpp +++ b/src/RE/M/MagicSystem.cpp @@ -2,24 +2,27 @@ namespace RE { - const char* GetCannotCastString(MagicSystem::CannotCastReason a_reason) + namespace MagicSystem { - using func_t = decltype(&MagicSystem::GetCannotCastString); - REL::Relocation func{ RELOCATION_ID(11295, 11423) }; - return func(a_reason); - } + const char* GetCannotCastString(MagicSystem::CannotCastReason a_reason) + { + using func_t = decltype(&MagicSystem::GetCannotCastString); + REL::Relocation func{ RELOCATION_ID(11295, 11423) }; + return func(a_reason); + } - float GetMagicCasterTargetUpdateInterval() - { - using func_t = decltype(&MagicSystem::GetMagicCasterTargetUpdateInterval); - REL::Relocation func{ RELOCATION_ID(11294, 11422) }; - return func(); - } + float GetMagicCasterTargetUpdateInterval() + { + using func_t = decltype(&MagicSystem::GetMagicCasterTargetUpdateInterval); + REL::Relocation func{ RELOCATION_ID(11294, 11422) }; + return func(); + } - BGSSoundDescriptorForm* GetMagicFailureSound(MagicSystem::SpellType a_type) - { - using func_t = decltype(&MagicSystem::GetMagicFailureSound); - REL::Relocation func{ RELOCATION_ID(11286, 11411) }; - return func(a_type); + BGSSoundDescriptorForm* GetMagicFailureSound(MagicSystem::SpellType a_type) + { + using func_t = decltype(&MagicSystem::GetMagicFailureSound); + REL::Relocation func{ RELOCATION_ID(11286, 11411) }; + return func(a_type); + } } } From 579a20bbd4da5461599207ca5a80b48432f08e1a Mon Sep 17 00:00:00 2001 From: powerof3 <32599957+powerof3@users.noreply.github.com> Date: Wed, 10 Jan 2024 02:37:11 +0530 Subject: [PATCH 06/24] Add `SendUIMessage::SendInventoryUpdateMessage` --- include/RE/A/ActorMagicCaster.h | 2 +- include/RE/I/InventoryUpdateData.h | 10 ++++++---- include/RE/M/MagicCaster.h | 2 +- include/RE/M/MagicSystem.h | 3 ++- include/RE/S/SendUIMessage.h | 17 +++++++++++++++++ 5 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 include/RE/S/SendUIMessage.h diff --git a/include/RE/A/ActorMagicCaster.h b/include/RE/A/ActorMagicCaster.h index 3318dad72..71868251c 100644 --- a/include/RE/A/ActorMagicCaster.h +++ b/include/RE/A/ActorMagicCaster.h @@ -47,7 +47,7 @@ namespace RE void FinishCastImpl() override; // 07 - { return; } void InterruptCastImpl(bool a_depleteEnergy) override; // 08 - { return; } void SpellCast(bool a_doCast, std::uint32_t a_arg2, MagicItem* a_spell) override; // 09 - { return; } - bool CheckCast(MagicItem* a_spell, bool a_dualCast, float* a_alchStrength, MagicSystem::CannotCastReason* a_reason, bool a_useBaseValueForCost) override; // 0A + bool CheckCast(MagicItem* a_spell, bool a_dualCast, float* a_effectStrength, MagicSystem::CannotCastReason* a_reason, bool a_useBaseValueForCost) override; // 0A TESObjectREFR* GetCasterStatsObject() const override; // 0B - { return actor; } Actor* GetCasterAsActor() const override; // 0C - { return actor; } NiNode* GetMagicNode() override; // 0E - { return magicNode; } diff --git a/include/RE/I/InventoryUpdateData.h b/include/RE/I/InventoryUpdateData.h index 0c1a8e769..dd96e9d7e 100644 --- a/include/RE/I/InventoryUpdateData.h +++ b/include/RE/I/InventoryUpdateData.h @@ -4,7 +4,9 @@ namespace RE { - class InventoryUpdateData : public IUIMessageData + class TESBoundObject; + + class InventoryUpdateData : public IUIMessageData { public: inline static constexpr auto RTTI = RTTI_InventoryUpdateData; @@ -12,9 +14,9 @@ namespace RE ~InventoryUpdateData() override = default; // 00 // members - RefHandle unk10; // 10 - std::uint32_t pad14; // 14 - TESForm* unk18; // 18 + RefHandle inventoryRef; // 10 + std::uint32_t pad14; // 14 + TESBoundObject* updateObj; // 18 }; static_assert(sizeof(InventoryUpdateData) == 0x20); } diff --git a/include/RE/M/MagicCaster.h b/include/RE/M/MagicCaster.h index 63df5cca6..3586862b3 100644 --- a/include/RE/M/MagicCaster.h +++ b/include/RE/M/MagicCaster.h @@ -52,7 +52,7 @@ namespace RE virtual void FinishCastImpl(); // 07 - { return; } virtual void InterruptCastImpl(bool a_depleteEnergy); // 08 - { return; } virtual void SpellCast(bool a_doCast, std::uint32_t a_arg2, MagicItem* a_spell); // 09 - { return; } - virtual bool CheckCast(MagicItem* a_spell, bool a_dualCast, float* a_alchStrength, MagicSystem::CannotCastReason* a_reason, bool a_useBaseValueForCost); // 0A + virtual bool CheckCast(MagicItem* a_spell, bool a_dualCast, float* a_effectStrength, MagicSystem::CannotCastReason* a_reason, bool a_useBaseValueForCost); // 0A virtual TESObjectREFR* GetCasterStatsObject() const; // 0B - { return 0; } virtual Actor* GetCasterAsActor() const; // 0C - { return 0; } virtual TESObjectREFR* GetCasterObjectReference(Actor** a_outCaster) const; // 0D diff --git a/include/RE/M/MagicSystem.h b/include/RE/M/MagicSystem.h index a5190684d..2dbb0f53a 100644 --- a/include/RE/M/MagicSystem.h +++ b/include/RE/M/MagicSystem.h @@ -16,7 +16,8 @@ namespace RE kItemCharge = 5, kCastWhileShouting = 6, kShoutWhileCasting = 7, - kShoutWhileRecovering = 8 + kShoutWhileRecovering = 8, + kCustomReasonNoStart = 100, }; enum class CastingSource diff --git a/include/RE/S/SendUIMessage.h b/include/RE/S/SendUIMessage.h new file mode 100644 index 000000000..12932922f --- /dev/null +++ b/include/RE/S/SendUIMessage.h @@ -0,0 +1,17 @@ +#pragma once + +namespace RE +{ + class TESBoundObject; + class TESObjectREFR; + + namespace SendUIMessage + { + void SendInventoryUpdateMessage(TESObjectREFR* a_inventoryRef, const TESBoundObject* a_updateObj) + { + using func_t = decltype(&SendUIMessage::SendInventoryUpdateMessage); + static REL::Relocation func{ RELOCATION_ID(51911, 52849) }; + return func(a_inventoryRef, a_updateObj); + } + } +} From bade6c1cfbb35c9af41d50c9607edec4883931a2 Mon Sep 17 00:00:00 2001 From: powerof3 Date: Tue, 9 Jan 2024 21:07:39 +0000 Subject: [PATCH 07/24] maintenance --- cmake/sourcelist.cmake | 1 + include/RE/A/ActorMagicCaster.h | 48 +++++++++++++++--------------- include/RE/I/InventoryUpdateData.h | 2 +- include/RE/S/SendUIMessage.h | 2 +- include/RE/Skyrim.h | 1 + 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/cmake/sourcelist.cmake b/cmake/sourcelist.cmake index f95c17a30..338c78755 100644 --- a/cmake/sourcelist.cmake +++ b/cmake/sourcelist.cmake @@ -1373,6 +1373,7 @@ set(SOURCES include/RE/S/ScriptedRefEffect.h include/RE/S/ScrollItem.h include/RE/S/SendPlayerToJailFunctor.h + include/RE/S/SendUIMessage.h include/RE/S/SetEventData.h include/RE/S/SetMotionTypeFunctor.h include/RE/S/SetPositionFunctor.h diff --git a/include/RE/A/ActorMagicCaster.h b/include/RE/A/ActorMagicCaster.h index 71868251c..23d259e31 100644 --- a/include/RE/A/ActorMagicCaster.h +++ b/include/RE/A/ActorMagicCaster.h @@ -40,31 +40,31 @@ namespace RE ~ActorMagicCaster() override; // 00 // override (MagicCaster) - void RequestCastImpl() override; // 03 - bool StartChargeImpl() override; // 04 - void StartReadyImpl() override; // 05 - void StartCastImpl() override; // 06 - void FinishCastImpl() override; // 07 - { return; } - void InterruptCastImpl(bool a_depleteEnergy) override; // 08 - { return; } - void SpellCast(bool a_doCast, std::uint32_t a_arg2, MagicItem* a_spell) override; // 09 - { return; } + void RequestCastImpl() override; // 03 + bool StartChargeImpl() override; // 04 + void StartReadyImpl() override; // 05 + void StartCastImpl() override; // 06 + void FinishCastImpl() override; // 07 - { return; } + void InterruptCastImpl(bool a_depleteEnergy) override; // 08 - { return; } + void SpellCast(bool a_doCast, std::uint32_t a_arg2, MagicItem* a_spell) override; // 09 - { return; } bool CheckCast(MagicItem* a_spell, bool a_dualCast, float* a_effectStrength, MagicSystem::CannotCastReason* a_reason, bool a_useBaseValueForCost) override; // 0A - TESObjectREFR* GetCasterStatsObject() const override; // 0B - { return actor; } - Actor* GetCasterAsActor() const override; // 0C - { return actor; } - NiNode* GetMagicNode() override; // 0E - { return magicNode; } - void ClearMagicNode() override; // 0F - { magicNode = 0; } - void SetCurrentSpellImpl(MagicItem* a_spell) override; // 10 - { return; } - void SelectSpellImpl() override; // 11 - { return; } - void DeselectSpellImpl() override; // 12 - { return; } - void SetSkipCheckCast() override; // 13 - { return; } - void SetCastingTimerForCharge() override; // 14 - MagicSystem::CastingSource GetCastingSource() const override; // 15 - { return castingSource; } - bool GetIsDualCasting() const override; // 16 - { return flags & 1; } - void SetDualCasting(bool a_set) override; // 17 - void SaveGame(BGSSaveGameBuffer* a_buf) override; // 18 - void LoadGame(BGSLoadGameBuffer* a_buf) override; // 19 - void FinishLoadGame(BGSLoadGameBuffer* a_buf) override; // 1A - void PrepareSound(MagicSystem::SoundID a_sound, MagicItem* a_spell) override; // 1B - void AdjustActiveEffect(ActiveEffect* a_activeEffect, float a_power, bool a_arg3) override; // 1C + TESObjectREFR* GetCasterStatsObject() const override; // 0B - { return actor; } + Actor* GetCasterAsActor() const override; // 0C - { return actor; } + NiNode* GetMagicNode() override; // 0E - { return magicNode; } + void ClearMagicNode() override; // 0F - { magicNode = 0; } + void SetCurrentSpellImpl(MagicItem* a_spell) override; // 10 - { return; } + void SelectSpellImpl() override; // 11 - { return; } + void DeselectSpellImpl() override; // 12 - { return; } + void SetSkipCheckCast() override; // 13 - { return; } + void SetCastingTimerForCharge() override; // 14 + MagicSystem::CastingSource GetCastingSource() const override; // 15 - { return castingSource; } + bool GetIsDualCasting() const override; // 16 - { return flags & 1; } + void SetDualCasting(bool a_set) override; // 17 + void SaveGame(BGSSaveGameBuffer* a_buf) override; // 18 + void LoadGame(BGSLoadGameBuffer* a_buf) override; // 19 + void FinishLoadGame(BGSLoadGameBuffer* a_buf) override; // 1A + void PrepareSound(MagicSystem::SoundID a_sound, MagicItem* a_spell) override; // 1B + void AdjustActiveEffect(ActiveEffect* a_activeEffect, float a_power, bool a_arg3) override; // 1C // add virtual void Update(float a_delta); // 1D diff --git a/include/RE/I/InventoryUpdateData.h b/include/RE/I/InventoryUpdateData.h index dd96e9d7e..be45849d7 100644 --- a/include/RE/I/InventoryUpdateData.h +++ b/include/RE/I/InventoryUpdateData.h @@ -6,7 +6,7 @@ namespace RE { class TESBoundObject; - class InventoryUpdateData : public IUIMessageData + class InventoryUpdateData : public IUIMessageData { public: inline static constexpr auto RTTI = RTTI_InventoryUpdateData; diff --git a/include/RE/S/SendUIMessage.h b/include/RE/S/SendUIMessage.h index 12932922f..c01a01327 100644 --- a/include/RE/S/SendUIMessage.h +++ b/include/RE/S/SendUIMessage.h @@ -4,7 +4,7 @@ namespace RE { class TESBoundObject; class TESObjectREFR; - + namespace SendUIMessage { void SendInventoryUpdateMessage(TESObjectREFR* a_inventoryRef, const TESBoundObject* a_updateObj) diff --git a/include/RE/Skyrim.h b/include/RE/Skyrim.h index 2f57d7c90..579e38545 100644 --- a/include/RE/Skyrim.h +++ b/include/RE/Skyrim.h @@ -1371,6 +1371,7 @@ #include "RE/S/ScriptedRefEffect.h" #include "RE/S/ScrollItem.h" #include "RE/S/SendPlayerToJailFunctor.h" +#include "RE/S/SendUIMessage.h" #include "RE/S/SetEventData.h" #include "RE/S/SetMotionTypeFunctor.h" #include "RE/S/SetPositionFunctor.h" From 00d54d9b6f2f03530ebfa0e9acc6419c98a64017 Mon Sep 17 00:00:00 2001 From: powerof3 <32599957+powerof3@users.noreply.github.com> Date: Wed, 10 Jan 2024 03:09:20 +0530 Subject: [PATCH 08/24] Add `TESForm::HasKeywordByEditorID` --- cmake/sourcelist.cmake | 1 + include/RE/S/SendUIMessage.h | 7 +------ include/RE/T/TESForm.h | 11 ++--------- src/RE/S/SendUIMessage.cpp | 14 ++++++++++++++ src/RE/T/TESForm.cpp | 34 +++++++++++++++++++--------------- 5 files changed, 37 insertions(+), 30 deletions(-) create mode 100644 src/RE/S/SendUIMessage.cpp diff --git a/cmake/sourcelist.cmake b/cmake/sourcelist.cmake index 338c78755..e94d783bb 100644 --- a/cmake/sourcelist.cmake +++ b/cmake/sourcelist.cmake @@ -1900,6 +1900,7 @@ set(SOURCES src/RE/S/ScrapHeap.cpp src/RE/S/Script.cpp src/RE/S/ScriptEventSourceHolder.cpp + src/RE/S/SendUIMessage.cpp src/RE/S/Setting.cpp src/RE/S/ShoutAttack.cpp src/RE/S/SkillIncrease.cpp diff --git a/include/RE/S/SendUIMessage.h b/include/RE/S/SendUIMessage.h index c01a01327..ec6ad5d1c 100644 --- a/include/RE/S/SendUIMessage.h +++ b/include/RE/S/SendUIMessage.h @@ -7,11 +7,6 @@ namespace RE namespace SendUIMessage { - void SendInventoryUpdateMessage(TESObjectREFR* a_inventoryRef, const TESBoundObject* a_updateObj) - { - using func_t = decltype(&SendUIMessage::SendInventoryUpdateMessage); - static REL::Relocation func{ RELOCATION_ID(51911, 52849) }; - return func(a_inventoryRef, a_updateObj); - } + void SendInventoryUpdateMessage(TESObjectREFR* a_inventoryRef, const TESBoundObject* a_updateObj); } } diff --git a/include/RE/T/TESForm.h b/include/RE/T/TESForm.h index 5141fd0ba..7884cb423 100644 --- a/include/RE/T/TESForm.h +++ b/include/RE/T/TESForm.h @@ -302,6 +302,7 @@ namespace RE [[nodiscard]] float GetWeight() const; [[nodiscard]] bool HasKeywordInArray(const std::vector& a_keywords, bool a_matchAll) const; [[nodiscard]] bool HasAnyKeywordByEditorID(const std::vector& editorIDs) const; + [[nodiscard]] bool HasKeywordByEditorID(std::string_view a_editorID); [[nodiscard]] bool HasKeywordInList(BGSListForm* a_keywordList, bool a_matchAll) const; [[nodiscard]] bool HasVMAD() const; [[nodiscard]] bool HasWorldModel() const noexcept; @@ -327,15 +328,6 @@ namespace RE [[nodiscard]] bool IsInitialized() const noexcept { return (GetFormFlags() & RecordFlags::kInitialized) != 0; } [[nodiscard]] bool IsKey() const noexcept { return Is(FormType::KeyMaster); } [[nodiscard]] bool IsLockpick() const noexcept { return GetFormID() == 0x0000000A; } - /** - * @brief Checks if the Form represents Skooma. - * - * Determines whether the FormID matches one of the known form IDs for Skooma. - * - * @return True if the FormID is either 0x00057A7A or 0x0201391D, indicating that it is Skooma or RedWater Skooma. - * - */ - [[nodiscard]] bool IsSkooma() const noexcept { return (GetFormID() == 0x00057A7A || GetFormID() == 0x0201391D); } [[nodiscard]] bool IsNot(FormType a_type) const noexcept { return !Is(a_type); } template @@ -348,6 +340,7 @@ namespace RE [[nodiscard]] bool IsNote() const noexcept { return Is(FormType::Note); } [[nodiscard]] bool IsPlayer() const noexcept { return GetFormID() == 0x00000007; } [[nodiscard]] bool IsPlayerRef() const noexcept { return GetFormID() == 0x00000014; } + [[nodiscard]] bool IsSkooma() const noexcept { return (GetFormID() == 0x00057A7A || GetFormID() == 0x0201391D); } [[nodiscard]] bool IsSoulGem() const noexcept { return Is(FormType::SoulGem); } [[nodiscard]] bool IsWeapon() const noexcept { return Is(FormType::Weapon); } diff --git a/src/RE/S/SendUIMessage.cpp b/src/RE/S/SendUIMessage.cpp new file mode 100644 index 000000000..66391a510 --- /dev/null +++ b/src/RE/S/SendUIMessage.cpp @@ -0,0 +1,14 @@ +#include "RE/S/SendUIMessage.h" + +namespace RE +{ + namespace SendUIMessage + { + void SendInventoryUpdateMessage(TESObjectREFR* a_inventoryRef, const TESBoundObject* a_updateObj) + { + using func_t = decltype(&SendInventoryUpdateMessage); + static REL::Relocation func{ RELOCATION_ID(51911, 52849) }; + return func(a_inventoryRef, a_updateObj); + } + } +} diff --git a/src/RE/T/TESForm.cpp b/src/RE/T/TESForm.cpp index ac034abff..41d88a701 100644 --- a/src/RE/T/TESForm.cpp +++ b/src/RE/T/TESForm.cpp @@ -67,26 +67,30 @@ namespace RE } // Iterate through the keywords - for (std::uint32_t i = 0; i < keywordForm->GetNumKeywords(); ++i) { - auto keywordOpt = keywordForm->GetKeywordAt(i); - if (keywordOpt) { - auto keyword = *keywordOpt; - if (keyword) { - const char* keywordEditorID = keyword->GetFormEditorID(); - if (keywordEditorID) { - // Check if the keywordEditorID is in the given editorIDs vector - if (std::find(editorIDs.begin(), editorIDs.end(), keywordEditorID) != editorIDs.end()) { - return true; - } - } - } + bool hasKeyword = false; + + keywordForm->ForEachKeyword([&](const BGSKeyword& a_keyword) { + if (std::ranges::find(editorIDs, a_keyword.GetFormEditorID()) != editorIDs.end()) { + hasKeyword = true; + return BSContainer::ForEachResult::kStop; } + return BSContainer::ForEachResult::kContinue; + }); + + return hasKeyword; + } + + bool TESForm::HasKeywordByEditorID(std::string_view a_editorID) + { + const auto keywordForm = As(); + if (!keywordForm) { + return false; } - return false; + return keywordForm->HasKeywordString(a_editorID); } - bool TESForm::HasKeywordInArray(const std::vector& a_keywords, bool a_matchAll) const + bool TESForm::HasKeywordInArray(const std::vector& a_keywords, bool a_matchAll) const { const auto keywordForm = As(); if (!keywordForm) { From abf5e00766ac45333868ab7fa4af56664e6129cf Mon Sep 17 00:00:00 2001 From: powerof3 Date: Tue, 9 Jan 2024 21:39:46 +0000 Subject: [PATCH 09/24] maintenance --- src/RE/T/TESForm.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/RE/T/TESForm.cpp b/src/RE/T/TESForm.cpp index 41d88a701..d280c2869 100644 --- a/src/RE/T/TESForm.cpp +++ b/src/RE/T/TESForm.cpp @@ -72,7 +72,7 @@ namespace RE keywordForm->ForEachKeyword([&](const BGSKeyword& a_keyword) { if (std::ranges::find(editorIDs, a_keyword.GetFormEditorID()) != editorIDs.end()) { hasKeyword = true; - return BSContainer::ForEachResult::kStop; + return BSContainer::ForEachResult::kStop; } return BSContainer::ForEachResult::kContinue; }); @@ -80,7 +80,7 @@ namespace RE return hasKeyword; } - bool TESForm::HasKeywordByEditorID(std::string_view a_editorID) + bool TESForm::HasKeywordByEditorID(std::string_view a_editorID) { const auto keywordForm = As(); if (!keywordForm) { @@ -90,7 +90,7 @@ namespace RE return keywordForm->HasKeywordString(a_editorID); } - bool TESForm::HasKeywordInArray(const std::vector& a_keywords, bool a_matchAll) const + bool TESForm::HasKeywordInArray(const std::vector& a_keywords, bool a_matchAll) const { const auto keywordForm = As(); if (!keywordForm) { From 0d835fd78cc268068d665eb90548183480c88bc8 Mon Sep 17 00:00:00 2001 From: Drew Warwick Date: Fri, 12 Jan 2024 02:56:59 -0800 Subject: [PATCH 10/24] Add BSSoundHandle::Pause --- include/RE/B/BSSoundHandle.h | 1 + include/RE/Offsets.h | 1 + src/RE/B/BSSoundHandle.cpp | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/include/RE/B/BSSoundHandle.h b/include/RE/B/BSSoundHandle.h index 7ac42a719..d1a6fbe06 100644 --- a/include/RE/B/BSSoundHandle.h +++ b/include/RE/B/BSSoundHandle.h @@ -42,6 +42,7 @@ namespace RE bool SetVolume(float a_volume); bool Stop(); bool Play(); + bool Pause(); // members std::uint32_t soundID; // 00 diff --git a/include/RE/Offsets.h b/include/RE/Offsets.h index 894d1d45f..a49e4fd35 100644 --- a/include/RE/Offsets.h +++ b/include/RE/Offsets.h @@ -146,6 +146,7 @@ namespace RE inline constexpr REL::ID Play(static_cast(67616)); inline constexpr REL::ID SetObjectToFollow(static_cast(67636)); inline constexpr REL::ID SetPosition(static_cast(67631)); + inline constexpr REL::ID Pause(static_cast(67618)); inline constexpr REL::ID Stop(static_cast(67619)); } diff --git a/src/RE/B/BSSoundHandle.cpp b/src/RE/B/BSSoundHandle.cpp index b7f79ee5d..212fa23db 100644 --- a/src/RE/B/BSSoundHandle.cpp +++ b/src/RE/B/BSSoundHandle.cpp @@ -81,4 +81,11 @@ namespace RE REL::Relocation func{ Offset::BSSoundHandle::Play }; return func(this); } + + bool BSSoundHandle::Pause() + { + using func_t = decltype(&BSSoundHandle::Pause); + REL::Relocation func{ Offset::BSSoundHandle::Pause }; + return func(this); + } } From c8eb6ae434f71acee175a888ff0b3b6bab0cbb44 Mon Sep 17 00:00:00 2001 From: Drew Warwick Date: Fri, 12 Jan 2024 03:15:57 -0800 Subject: [PATCH 11/24] Missed SSE ID --- include/RE/Offsets.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/RE/Offsets.h b/include/RE/Offsets.h index a49e4fd35..ad7c5ca45 100644 --- a/include/RE/Offsets.h +++ b/include/RE/Offsets.h @@ -727,6 +727,7 @@ namespace RE inline constexpr REL::ID Play(static_cast(66355)); inline constexpr REL::ID SetObjectToFollow(static_cast(66375)); inline constexpr REL::ID SetPosition(static_cast(66370)); + inline constexpr REL::ID Pause(static_cast(66357)); inline constexpr REL::ID Stop(static_cast(66358)); } From 5106e571e6606e00ea18fce70fc999e041b6e152 Mon Sep 17 00:00:00 2001 From: W-Drew Date: Fri, 12 Jan 2024 11:16:48 +0000 Subject: [PATCH 12/24] maintenance --- include/RE/B/BSSoundHandle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/RE/B/BSSoundHandle.h b/include/RE/B/BSSoundHandle.h index d1a6fbe06..7151fe358 100644 --- a/include/RE/B/BSSoundHandle.h +++ b/include/RE/B/BSSoundHandle.h @@ -42,7 +42,7 @@ namespace RE bool SetVolume(float a_volume); bool Stop(); bool Play(); - bool Pause(); + bool Pause(); // members std::uint32_t soundID; // 00 From 7c5df1bae45cde63c55a37f7ecb7e788e27b1131 Mon Sep 17 00:00:00 2001 From: Drew Warwick Date: Fri, 12 Jan 2024 03:02:21 -0800 Subject: [PATCH 13/24] RE constraints --- include/RE/H/hkpConstraintAtom.h | 26 ++--- include/RE/H/hkpConstraintMotor.h | 108 +++++++++++++++++++ include/RE/H/hkpLimitedHingeConstraintData.h | 30 ++++++ include/RE/H/hkpRagdollConstraintData.h | 31 ++++++ include/RE/H/hkpSolverResults.h | 14 +++ include/RE/Skyrim.h | 2 + 6 files changed, 199 insertions(+), 12 deletions(-) create mode 100644 include/RE/H/hkpConstraintMotor.h create mode 100644 include/RE/H/hkpSolverResults.h diff --git a/include/RE/H/hkpConstraintAtom.h b/include/RE/H/hkpConstraintAtom.h index 55c5aef08..54174c9f5 100644 --- a/include/RE/H/hkpConstraintAtom.h +++ b/include/RE/H/hkpConstraintAtom.h @@ -2,6 +2,8 @@ namespace RE { + class hkpConstraintMotor; + struct hkpConstraintAtom { public: @@ -150,23 +152,23 @@ namespace RE struct hkpAngMotorConstraintAtom : public hkpConstraintAtom { - bool enabled; // 02 - uint8_t motorAxis; // 03 - int16_t initializedOffset; // 04 - int16_t previousTargetAngleOffset; // 06 - int16_t correspondingAngLimitSolverResultOffset; // 08 - float targetAngle; // 0C - uintptr_t motor; // 10 + bool enabled; // 02 + uint8_t motorAxis; // 03 + int16_t initializedOffset; // 04 + int16_t previousTargetAngleOffset; // 06 + int16_t correspondingAngLimitSolverResultOffset; // 08 + float targetAngle; // 0C + hkpConstraintMotor* motor; // 10 }; static_assert(sizeof(hkpAngMotorConstraintAtom) == 0x18); struct hkpRagdollMotorConstraintAtom : public hkpConstraintAtom { - bool enabled; // 02 - int16_t initializedOffset; // 04 - int16_t previousTargetAnglesOffset; // 06 - hkMatrix3 target_bRca; // 10 - uintptr_t motors[3]; // 40 + bool enabled; // 02 + int16_t initializedOffset; // 04 + int16_t previousTargetAnglesOffset; // 06 + hkMatrix3 target_bRca; // 10 + hkpConstraintMotor* motors[3]; // 40 }; static_assert(sizeof(hkpRagdollMotorConstraintAtom) == 0x60); } diff --git a/include/RE/H/hkpConstraintMotor.h b/include/RE/H/hkpConstraintMotor.h new file mode 100644 index 000000000..46e87d520 --- /dev/null +++ b/include/RE/H/hkpConstraintMotor.h @@ -0,0 +1,108 @@ +#pragma once + +#include "RE/H/hkReferencedObject.h" + +namespace RE +{ + class hkpConstraintMotor : public hkReferencedObject + { + public: + enum class MotorType + { + kInvalid = 0, + + kPosition, + kVelocity, + kSpring, + kCallback, + + kNUM + }; + + inline static constexpr auto RTTI = RTTI_hkpConstraintMotor; + inline static constexpr auto VTABLE = VTABLE_hkpConstraintMotor; + + // members + stl::enumeration type; // 10 + }; + static_assert(sizeof(hkpConstraintMotor) == 0x18); + + class hkpLimitedForceConstraintMotor : public hkpConstraintMotor + { + public: + inline static constexpr auto RTTI = RTTI_hkpLimitedForceConstraintMotor; + inline static constexpr auto VTABLE = VTABLE_hkpLimitedForceConstraintMotor; + + // members + float minForce; // 18 + float maxForce; // 1C + }; + static_assert(sizeof(hkpLimitedForceConstraintMotor) == 0x20); + + class hkpPositionConstraintMotor : public hkpLimitedForceConstraintMotor + { + public: + inline static constexpr auto RTTI = RTTI_hkpPositionConstraintMotor; + inline static constexpr auto VTABLE = VTABLE_hkpPositionConstraintMotor; + + // members + float tau; // 20 + float damping; // 24 + float proportionalRecoveryVelocity; // 28 + float constantRecoveryVelocity; // 2C + }; + static_assert(sizeof(hkpPositionConstraintMotor) == 0x30); + + class hkpVelocityConstraintMotor : public hkpLimitedForceConstraintMotor + { + public: + inline static constexpr auto RTTI = RTTI_hkpVelocityConstraintMotor; + inline static constexpr auto VTABLE = VTABLE_hkpVelocityConstraintMotor; + + // members + float tau; // 20 + float targetVelocity; // 24 + bool useConstraintTarget; // 28 + }; + static_assert(sizeof(hkpVelocityConstraintMotor) == 0x30); + + class hkpSpringDamperConstraintMotor : public hkpLimitedForceConstraintMotor + { + public: + inline static constexpr auto RTTI = RTTI_hkpSpringDamperConstraintMotor; + inline static constexpr auto VTABLE = VTABLE_hkpSpringDamperConstraintMotor; + + // members + float springConstant; // 20 + float springDamping; // 24 + }; + static_assert(sizeof(hkpSpringDamperConstraintMotor) == 0x28); + + class hkpCallbackConstraintMotor : public hkpLimitedForceConstraintMotor + { + public: + enum class CallbackType + { + kUnk = 0, + + kUser0, + kUser1, + kUser2, + + kNUM + }; + + inline static constexpr auto RTTI = RTTI_hkpCallbackConstraintMotor; + inline static constexpr auto VTABLE = VTABLE_hkpCallbackConstraintMotor; + + using CallbackFunction = void(const hkpCallbackConstraintMotor& motor, const void* unk0, void* unk1); + + // members + CallbackFunction* func; // 20 + stl::enumeration callbackType; // 28 + std::uint64_t userData0; // 30 + std::uint64_t userData1; // 38 + std::uint64_t userData2; // 40 + }; + static_assert(sizeof(hkpCallbackConstraintMotor) == 0x48); +} \ No newline at end of file diff --git a/include/RE/H/hkpLimitedHingeConstraintData.h b/include/RE/H/hkpLimitedHingeConstraintData.h index 2ba81a8e0..4830a79bd 100644 --- a/include/RE/H/hkpLimitedHingeConstraintData.h +++ b/include/RE/H/hkpLimitedHingeConstraintData.h @@ -2,12 +2,29 @@ #include "RE/H/hkpConstraintAtom.h" #include "RE/H/hkpConstraintData.h" +#include "RE/H/hkpSolverResults.h" namespace RE { class hkpLimitedHingeConstraintData : public hkpConstraintData { public: + enum SolverResultType + { + kMotor = 0, + kFriction, + kLimit, + + kAngle0, + kAngle1, + + kLinear0, + kLinear1, + kLinear2, + + kNUM + }; + inline static constexpr auto RTTI = RTTI_hkpLimitedHingeConstraintData; inline static constexpr auto VTABLE = VTABLE_hkpLimitedHingeConstraintData; @@ -23,6 +40,19 @@ namespace RE }; static_assert(sizeof(Atoms) == 0xF0); + struct Runtime + { + inline float getCurrentAngle() + { + return solverResults[SolverResultType::kLimit].data * -1.f; + } + + hkpSolverResults solverResults[SolverResultType::kNUM]; // 00 + bool previousTargetInitialized; // 40 + float previousTargetAngle; // 44 + }; + static_assert(sizeof(Runtime) == 0x48); + // members Atoms atoms; // 18 }; diff --git a/include/RE/H/hkpRagdollConstraintData.h b/include/RE/H/hkpRagdollConstraintData.h index 6195f6409..8f4956ef4 100644 --- a/include/RE/H/hkpRagdollConstraintData.h +++ b/include/RE/H/hkpRagdollConstraintData.h @@ -2,12 +2,34 @@ #include "RE/H/hkpConstraintAtom.h" #include "RE/H/hkpConstraintData.h" +#include "RE/H/hkpSolverResults.h" namespace RE { class hkpRagdollConstraintData : public hkpConstraintData { public: + enum SolverResultType + { + kMotor0 = 0, + kMotor1, + kMotor2, + + kFriction0, + kFriction1, + kFriction2, + + kTwist, + kCone, + kPlane, + + kLinear0, + kLinear1, + kLinear2, + + kNUM + }; + inline static constexpr auto RTTI = RTTI_hkpRagdollConstraintData; inline static constexpr auto VTABLE = VTABLE_hkpRagdollConstraintData; @@ -24,6 +46,15 @@ namespace RE }; static_assert(sizeof(Atoms) == 0x160); + struct Runtime + { + hkpSolverResults solverResults[SolverResultType::kNUM]; // 00 + bool previousTargetInitialized[3]; // 60 + float previousTargetAngle[3]; // 64 + float coneAngle; // 70 + }; + static_assert(sizeof(Runtime) == 0x74); + // members Atoms atoms; // 18 }; diff --git a/include/RE/H/hkpSolverResults.h b/include/RE/H/hkpSolverResults.h new file mode 100644 index 000000000..52da57080 --- /dev/null +++ b/include/RE/H/hkpSolverResults.h @@ -0,0 +1,14 @@ +#pragma once + +namespace RE +{ + + class hkpSolverResults + { + public: + float impulse; // 00 + float data; // 04 + }; + static_assert(sizeof(hkpSolverResults) == 0x08); + +} \ No newline at end of file diff --git a/include/RE/Skyrim.h b/include/RE/Skyrim.h index 579e38545..9c0ca6d3f 100644 --- a/include/RE/Skyrim.h +++ b/include/RE/Skyrim.h @@ -986,6 +986,7 @@ #include "RE/H/hkpConstraintData.h" #include "RE/H/hkpConstraintInfo.h" #include "RE/H/hkpConstraintInstance.h" +#include "RE/H/hkpConstraintMotor.h" #include "RE/H/hkpConstraintOwner.h" #include "RE/H/hkpContactListener.h" #include "RE/H/hkpContactPointEvent.h" @@ -1030,6 +1031,7 @@ #include "RE/H/hkpSimulationIsland.h" #include "RE/H/hkpSingleShapeContainer.h" #include "RE/H/hkpSolverInfo.h" +#include "RE/H/hkpSolverResults.h" #include "RE/H/hkpSphereRepShape.h" #include "RE/H/hkpSphereShape.h" #include "RE/H/hkpTypedBroadPhaseHandle.h" From d8d82ef9ddb07dac50b3bf19c957d896cd653b49 Mon Sep 17 00:00:00 2001 From: W-Drew Date: Fri, 12 Jan 2024 18:56:53 +0000 Subject: [PATCH 14/24] maintenance --- cmake/sourcelist.cmake | 2 + include/RE/H/hkpConstraintMotor.h | 164 +++++++++---------- include/RE/H/hkpLimitedHingeConstraintData.h | 2 +- include/RE/H/hkpRagdollConstraintData.h | 2 +- include/RE/H/hkpSolverResults.h | 14 +- 5 files changed, 93 insertions(+), 91 deletions(-) diff --git a/cmake/sourcelist.cmake b/cmake/sourcelist.cmake index e94d783bb..10ddee0a5 100644 --- a/cmake/sourcelist.cmake +++ b/cmake/sourcelist.cmake @@ -984,6 +984,7 @@ set(SOURCES include/RE/H/hkpConstraintData.h include/RE/H/hkpConstraintInfo.h include/RE/H/hkpConstraintInstance.h + include/RE/H/hkpConstraintMotor.h include/RE/H/hkpConstraintOwner.h include/RE/H/hkpContactListener.h include/RE/H/hkpContactPointEvent.h @@ -1028,6 +1029,7 @@ set(SOURCES include/RE/H/hkpSimulationIsland.h include/RE/H/hkpSingleShapeContainer.h include/RE/H/hkpSolverInfo.h + include/RE/H/hkpSolverResults.h include/RE/H/hkpSphereRepShape.h include/RE/H/hkpSphereShape.h include/RE/H/hkpTypedBroadPhaseHandle.h diff --git a/include/RE/H/hkpConstraintMotor.h b/include/RE/H/hkpConstraintMotor.h index 46e87d520..dec9efe0a 100644 --- a/include/RE/H/hkpConstraintMotor.h +++ b/include/RE/H/hkpConstraintMotor.h @@ -4,105 +4,105 @@ namespace RE { - class hkpConstraintMotor : public hkReferencedObject - { - public: - enum class MotorType - { - kInvalid = 0, - - kPosition, - kVelocity, - kSpring, - kCallback, - - kNUM - }; - - inline static constexpr auto RTTI = RTTI_hkpConstraintMotor; + class hkpConstraintMotor : public hkReferencedObject + { + public: + enum class MotorType + { + kInvalid = 0, + + kPosition, + kVelocity, + kSpring, + kCallback, + + kNUM + }; + + inline static constexpr auto RTTI = RTTI_hkpConstraintMotor; inline static constexpr auto VTABLE = VTABLE_hkpConstraintMotor; - // members - stl::enumeration type; // 10 - }; - static_assert(sizeof(hkpConstraintMotor) == 0x18); + // members + stl::enumeration type; // 10 + }; + static_assert(sizeof(hkpConstraintMotor) == 0x18); - class hkpLimitedForceConstraintMotor : public hkpConstraintMotor - { - public: - inline static constexpr auto RTTI = RTTI_hkpLimitedForceConstraintMotor; + class hkpLimitedForceConstraintMotor : public hkpConstraintMotor + { + public: + inline static constexpr auto RTTI = RTTI_hkpLimitedForceConstraintMotor; inline static constexpr auto VTABLE = VTABLE_hkpLimitedForceConstraintMotor; - // members - float minForce; // 18 - float maxForce; // 1C - }; - static_assert(sizeof(hkpLimitedForceConstraintMotor) == 0x20); + // members + float minForce; // 18 + float maxForce; // 1C + }; + static_assert(sizeof(hkpLimitedForceConstraintMotor) == 0x20); - class hkpPositionConstraintMotor : public hkpLimitedForceConstraintMotor - { - public: - inline static constexpr auto RTTI = RTTI_hkpPositionConstraintMotor; + class hkpPositionConstraintMotor : public hkpLimitedForceConstraintMotor + { + public: + inline static constexpr auto RTTI = RTTI_hkpPositionConstraintMotor; inline static constexpr auto VTABLE = VTABLE_hkpPositionConstraintMotor; - // members - float tau; // 20 - float damping; // 24 - float proportionalRecoveryVelocity; // 28 - float constantRecoveryVelocity; // 2C - }; - static_assert(sizeof(hkpPositionConstraintMotor) == 0x30); - - class hkpVelocityConstraintMotor : public hkpLimitedForceConstraintMotor - { - public: - inline static constexpr auto RTTI = RTTI_hkpVelocityConstraintMotor; + // members + float tau; // 20 + float damping; // 24 + float proportionalRecoveryVelocity; // 28 + float constantRecoveryVelocity; // 2C + }; + static_assert(sizeof(hkpPositionConstraintMotor) == 0x30); + + class hkpVelocityConstraintMotor : public hkpLimitedForceConstraintMotor + { + public: + inline static constexpr auto RTTI = RTTI_hkpVelocityConstraintMotor; inline static constexpr auto VTABLE = VTABLE_hkpVelocityConstraintMotor; - // members - float tau; // 20 - float targetVelocity; // 24 - bool useConstraintTarget; // 28 - }; - static_assert(sizeof(hkpVelocityConstraintMotor) == 0x30); - - class hkpSpringDamperConstraintMotor : public hkpLimitedForceConstraintMotor - { - public: - inline static constexpr auto RTTI = RTTI_hkpSpringDamperConstraintMotor; + // members + float tau; // 20 + float targetVelocity; // 24 + bool useConstraintTarget; // 28 + }; + static_assert(sizeof(hkpVelocityConstraintMotor) == 0x30); + + class hkpSpringDamperConstraintMotor : public hkpLimitedForceConstraintMotor + { + public: + inline static constexpr auto RTTI = RTTI_hkpSpringDamperConstraintMotor; inline static constexpr auto VTABLE = VTABLE_hkpSpringDamperConstraintMotor; - // members - float springConstant; // 20 - float springDamping; // 24 - }; - static_assert(sizeof(hkpSpringDamperConstraintMotor) == 0x28); + // members + float springConstant; // 20 + float springDamping; // 24 + }; + static_assert(sizeof(hkpSpringDamperConstraintMotor) == 0x28); - class hkpCallbackConstraintMotor : public hkpLimitedForceConstraintMotor - { - public: - enum class CallbackType - { - kUnk = 0, + class hkpCallbackConstraintMotor : public hkpLimitedForceConstraintMotor + { + public: + enum class CallbackType + { + kUnk = 0, - kUser0, - kUser1, - kUser2, + kUser0, + kUser1, + kUser2, - kNUM - }; + kNUM + }; - inline static constexpr auto RTTI = RTTI_hkpCallbackConstraintMotor; + inline static constexpr auto RTTI = RTTI_hkpCallbackConstraintMotor; inline static constexpr auto VTABLE = VTABLE_hkpCallbackConstraintMotor; - using CallbackFunction = void(const hkpCallbackConstraintMotor& motor, const void* unk0, void* unk1); + using CallbackFunction = void(const hkpCallbackConstraintMotor& motor, const void* unk0, void* unk1); - // members - CallbackFunction* func; // 20 - stl::enumeration callbackType; // 28 - std::uint64_t userData0; // 30 - std::uint64_t userData1; // 38 - std::uint64_t userData2; // 40 - }; - static_assert(sizeof(hkpCallbackConstraintMotor) == 0x48); + // members + CallbackFunction* func; // 20 + stl::enumeration callbackType; // 28 + std::uint64_t userData0; // 30 + std::uint64_t userData1; // 38 + std::uint64_t userData2; // 40 + }; + static_assert(sizeof(hkpCallbackConstraintMotor) == 0x48); } \ No newline at end of file diff --git a/include/RE/H/hkpLimitedHingeConstraintData.h b/include/RE/H/hkpLimitedHingeConstraintData.h index 4830a79bd..13349d088 100644 --- a/include/RE/H/hkpLimitedHingeConstraintData.h +++ b/include/RE/H/hkpLimitedHingeConstraintData.h @@ -45,7 +45,7 @@ namespace RE inline float getCurrentAngle() { return solverResults[SolverResultType::kLimit].data * -1.f; - } + } hkpSolverResults solverResults[SolverResultType::kNUM]; // 00 bool previousTargetInitialized; // 40 diff --git a/include/RE/H/hkpRagdollConstraintData.h b/include/RE/H/hkpRagdollConstraintData.h index 8f4956ef4..283be4267 100644 --- a/include/RE/H/hkpRagdollConstraintData.h +++ b/include/RE/H/hkpRagdollConstraintData.h @@ -22,7 +22,7 @@ namespace RE kTwist, kCone, kPlane, - + kLinear0, kLinear1, kLinear2, diff --git a/include/RE/H/hkpSolverResults.h b/include/RE/H/hkpSolverResults.h index 52da57080..96ea565cd 100644 --- a/include/RE/H/hkpSolverResults.h +++ b/include/RE/H/hkpSolverResults.h @@ -3,12 +3,12 @@ namespace RE { - class hkpSolverResults - { - public: - float impulse; // 00 - float data; // 04 - }; - static_assert(sizeof(hkpSolverResults) == 0x08); + class hkpSolverResults + { + public: + float impulse; // 00 + float data; // 04 + }; + static_assert(sizeof(hkpSolverResults) == 0x08); } \ No newline at end of file From 78f140e3878f241b40d0004ae3bd9f30f7a2fa74 Mon Sep 17 00:00:00 2001 From: powerof3 <32599957+powerof3@users.noreply.github.com> Date: Mon, 15 Jan 2024 19:58:46 +0530 Subject: [PATCH 15/24] Standardize `BSContainer::ForEachResult` functions --- include/RE/B/BGSKeywordForm.h | 4 ++-- include/RE/B/BGSListForm.h | 2 +- include/RE/B/BGSOutfit.h | 4 ++-- include/RE/P/ProcessLists.h | 10 +++++----- include/RE/T/TES.h | 4 ++-- include/RE/T/TESObjectCELL.h | 4 ++-- src/RE/B/BGSKeywordForm.cpp | 18 +++++++++--------- src/RE/B/BGSListForm.cpp | 10 +++++----- src/RE/P/ProcessLists.cpp | 32 ++++++++++++++++---------------- src/RE/T/TES.cpp | 18 +++++++++--------- src/RE/T/TESForm.cpp | 8 ++++---- src/RE/T/TESObjectCELL.cpp | 10 +++++----- src/RE/T/TESObjectREFR.cpp | 4 ++-- 13 files changed, 64 insertions(+), 64 deletions(-) diff --git a/include/RE/B/BGSKeywordForm.h b/include/RE/B/BGSKeywordForm.h index 2ae40869c..29d23dafb 100644 --- a/include/RE/B/BGSKeywordForm.h +++ b/include/RE/B/BGSKeywordForm.h @@ -27,7 +27,7 @@ namespace RE bool AddKeyword(BGSKeyword* a_keyword); bool AddKeywords(const std::vector& a_keywords); [[nodiscard]] bool ContainsKeywordString(std::string_view a_editorID) const; - void ForEachKeyword(std::function a_callback) const; + void ForEachKeyword(std::function a_callback) const; [[nodiscard]] std::optional GetKeywordAt(std::uint32_t a_idx) const; [[nodiscard]] std::optional GetKeywordIndex(BGSKeyword* a_keyword) const; [[nodiscard]] std::uint32_t GetNumKeywords() const; @@ -35,7 +35,7 @@ namespace RE [[nodiscard]] bool HasKeywordString(std::string_view a_editorID) const; bool RemoveKeyword(std::uint32_t a_index); bool RemoveKeyword(BGSKeyword* a_keyword); - bool RemoveKeywords(const std::vector& a_keywords); + bool RemoveKeywords(const std::vector& a_keywords); // members BGSKeyword** keywords; // 08 - KWDA diff --git a/include/RE/B/BGSListForm.h b/include/RE/B/BGSListForm.h index e70fc5048..978367d95 100644 --- a/include/RE/B/BGSListForm.h +++ b/include/RE/B/BGSListForm.h @@ -43,7 +43,7 @@ namespace RE void AddForm(TESForm* a_form); [[nodiscard]] bool ContainsOnlyType(FormType a_formType) const; - void ForEachForm(std::function a_callback) const; + void ForEachForm(std::function a_callback) const; [[nodiscard]] bool HasForm(const TESForm* a_form) const; [[nodiscard]] bool HasForm(FormID a_formID) const; diff --git a/include/RE/B/BGSOutfit.h b/include/RE/B/BGSOutfit.h index 55d00a9f2..36002ad66 100644 --- a/include/RE/B/BGSOutfit.h +++ b/include/RE/B/BGSOutfit.h @@ -30,10 +30,10 @@ namespace RE bool Load(TESFile* a_mod) override; // 06 void InitItemImpl() override; // 13 - void ForEachItem(std::function a_callback) const + void ForEachItem(std::function a_callback) const { for (auto& item : outfitItems) { - if (item && a_callback(*item) == BSContainer::ForEachResult::kStop) { + if (item && a_callback(item) == BSContainer::ForEachResult::kStop) { return; } } diff --git a/include/RE/P/ProcessLists.h b/include/RE/P/ProcessLists.h index db8c8b40e..18d9d7ec1 100644 --- a/include/RE/P/ProcessLists.h +++ b/include/RE/P/ProcessLists.h @@ -36,11 +36,11 @@ namespace RE static ProcessLists* GetSingleton(); void ClearCachedFactionFightReactions() const; - void ForAllActors(std::function a_callback); - void ForEachHighActor(std::function a_callback); - void ForEachMagicTempEffect(std::function a_callback); - void ForEachModelEffect(std::function a_callback); - void ForEachShaderEffect(std::function a_callback); + void ForAllActors(std::function a_callback); + void ForEachHighActor(std::function a_callback); + void ForEachMagicTempEffect(std::function a_callback); + void ForEachModelEffect(std::function a_callback); + void ForEachShaderEffect(std::function a_callback); float GetSystemTimeClock(); std::int16_t RequestHighestDetectionLevelAgainstActor(Actor* a_actor, std::uint32_t& a_LOSCount); void StopAllMagicEffects(TESObjectREFR& a_ref); diff --git a/include/RE/T/TES.h b/include/RE/T/TES.h index 73387d824..e586f9ef1 100644 --- a/include/RE/T/TES.h +++ b/include/RE/T/TES.h @@ -66,8 +66,8 @@ namespace RE static TES* GetSingleton(); - void ForEachReference(std::function a_callback); - void ForEachReferenceInRange(TESObjectREFR* a_origin, float a_radius, std::function a_callback); + void ForEachReference(std::function a_callback); + void ForEachReferenceInRange(TESObjectREFR* a_origin, float a_radius, std::function a_callback); TESObjectCELL* GetCell(const NiPoint3& a_position) const; MATERIAL_ID GetLandMaterialType(const NiPoint3& a_position) const; diff --git a/include/RE/T/TESObjectCELL.h b/include/RE/T/TESObjectCELL.h index eb6c58399..eb5ee231b 100644 --- a/include/RE/T/TESObjectCELL.h +++ b/include/RE/T/TESObjectCELL.h @@ -194,8 +194,8 @@ namespace RE TESNPC* GetActorOwner(); bhkWorld* GetbhkWorld() const; - void ForEachReference(std::function a_callback) const; - void ForEachReferenceInRange(const NiPoint3& a_origin, float a_radius, std::function a_callback) const; + void ForEachReference(std::function a_callback) const; + void ForEachReferenceInRange(const NiPoint3& a_origin, float a_radius, std::function a_callback) const; EXTERIOR_DATA* GetCoordinates(); TESFaction* GetFactionOwner(); INTERIOR_DATA* GetLighting(); diff --git a/src/RE/B/BGSKeywordForm.cpp b/src/RE/B/BGSKeywordForm.cpp index 93154b46b..14a2c15c8 100644 --- a/src/RE/B/BGSKeywordForm.cpp +++ b/src/RE/B/BGSKeywordForm.cpp @@ -42,8 +42,8 @@ namespace RE bool BGSKeywordForm::ContainsKeywordString(std::string_view a_editorID) const { bool result = false; - ForEachKeyword([&](const BGSKeyword& a_keyword) { - if (a_keyword.formEditorID.contains(a_editorID)) { + ForEachKeyword([&](const BGSKeyword* a_keyword) { + if (a_keyword->formEditorID.contains(a_editorID)) { result = true; return BSContainer::ForEachResult::kStop; } @@ -52,11 +52,11 @@ namespace RE return result; } - void BGSKeywordForm::ForEachKeyword(std::function a_callback) const + void BGSKeywordForm::ForEachKeyword(std::function a_callback) const { if (keywords) { for (std::uint32_t idx = 0; idx < numKeywords; ++idx) { - if (keywords[idx] && a_callback(*keywords[idx]) == BSContainer::ForEachResult::kStop) { + if (keywords[idx] && a_callback(keywords[idx]) == BSContainer::ForEachResult::kStop) { return; } } @@ -92,8 +92,8 @@ namespace RE bool BGSKeywordForm::HasKeywordID(FormID a_formID) const { bool result = false; - ForEachKeyword([&](const BGSKeyword& a_keyword) { - if (a_keyword.GetFormID() == a_formID) { + ForEachKeyword([&](const BGSKeyword* a_keyword) { + if (a_keyword->GetFormID() == a_formID) { result = true; return BSContainer::ForEachResult::kStop; } @@ -105,8 +105,8 @@ namespace RE bool BGSKeywordForm::HasKeywordString(std::string_view a_editorID) const { bool result = false; - ForEachKeyword([&](const BGSKeyword& a_keyword) { - if (a_keyword.formEditorID == a_editorID) { + ForEachKeyword([&](const BGSKeyword* a_keyword) { + if (a_keyword->formEditorID == a_editorID) { result = true; return BSContainer::ForEachResult::kStop; } @@ -129,7 +129,7 @@ namespace RE return index ? RemoveKeyword(*index) : false; } - bool BGSKeywordForm::RemoveKeywords(const std::vector& a_keywords) + bool BGSKeywordForm::RemoveKeywords(const std::vector& a_keywords) { std::vector copiedData{ keywords, keywords + numKeywords }; if (std::erase_if(copiedData, [&](auto& keyword) { return std::ranges::find(a_keywords, keyword) != a_keywords.end(); }) > 0) { diff --git a/src/RE/B/BGSListForm.cpp b/src/RE/B/BGSListForm.cpp index 15361c080..5433b8c97 100644 --- a/src/RE/B/BGSListForm.cpp +++ b/src/RE/B/BGSListForm.cpp @@ -12,8 +12,8 @@ namespace RE bool BGSListForm::ContainsOnlyType(FormType a_formType) const { bool result = true; - ForEachForm([&](const TESForm& a_form) { - if (a_form.GetFormType() != a_formType) { + ForEachForm([&](const TESForm* a_form) { + if (a_form->GetFormType() != a_formType) { result = false; return BSContainer::ForEachResult::kStop; } @@ -47,17 +47,17 @@ namespace RE return HasForm(form); } - void BGSListForm::ForEachForm(std::function a_callback) const + void BGSListForm::ForEachForm(std::function a_callback) const { for (const auto& form : forms) { - if (form && a_callback(*form) == BSContainer::ForEachResult::kStop) { + if (form && a_callback(form) == BSContainer::ForEachResult::kStop) { return; } } if (scriptAddedTempForms) { for (const auto& addedFormID : *scriptAddedTempForms) { const auto addedForm = TESForm::LookupByID(addedFormID); - if (addedForm && a_callback(*addedForm) == BSContainer::ForEachResult::kStop) { + if (addedForm && a_callback(addedForm) == BSContainer::ForEachResult::kStop) { return; } } diff --git a/src/RE/P/ProcessLists.cpp b/src/RE/P/ProcessLists.cpp index cd861fd0e..acf86dfd4 100644 --- a/src/RE/P/ProcessLists.cpp +++ b/src/RE/P/ProcessLists.cpp @@ -21,13 +21,13 @@ namespace RE return func(this); } - void ProcessLists::ForAllActors(std::function a_callback) + void ProcessLists::ForAllActors(std::function a_callback) { for (auto& list : allProcesses) { if (list) { for (auto& actorHandle : *list) { const auto& actor = actorHandle.get(); - if (actor && a_callback(*actor) == BSContainer::ForEachResult::kStop) { + if (actor && a_callback(actor.get()) == BSContainer::ForEachResult::kStop) { return; } } @@ -35,44 +35,44 @@ namespace RE } } - void ProcessLists::ForEachHighActor(std::function a_callback) + void ProcessLists::ForEachHighActor(std::function a_callback) { for (auto& highActorHandle : highActorHandles) { const auto& highActor = highActorHandle.get(); - if (highActor && a_callback(*highActor) == BSContainer::ForEachResult::kStop) { + if (highActor && a_callback(highActor.get()) == BSContainer::ForEachResult::kStop) { break; } } } - void ProcessLists::ForEachMagicTempEffect(std::function a_callback) + void ProcessLists::ForEachMagicTempEffect(std::function a_callback) { BSSpinLockGuard locker(magicEffectsLock); for (auto& tempEffectPtr : magicEffects) { const auto& tempEffect = tempEffectPtr.get(); - if (tempEffect && a_callback(*tempEffect) == BSContainer::ForEachResult::kStop) { + if (tempEffect && a_callback(tempEffect) == BSContainer::ForEachResult::kStop) { break; } } } - void ProcessLists::ForEachModelEffect(std::function a_callback) + void ProcessLists::ForEachModelEffect(std::function a_callback) { - ForEachMagicTempEffect([a_callback](BSTempEffect& a_tempEffect) { - const auto modelEffect = a_tempEffect.As(); - if (modelEffect && a_callback(*modelEffect) == BSContainer::ForEachResult::kStop) { + ForEachMagicTempEffect([a_callback](BSTempEffect* a_tempEffect) { + const auto modelEffect = a_tempEffect->As(); + if (modelEffect && a_callback(modelEffect) == BSContainer::ForEachResult::kStop) { return BSContainer::ForEachResult::kStop; } return BSContainer::ForEachResult::kContinue; }); } - void ProcessLists::ForEachShaderEffect(std::function a_callback) + void ProcessLists::ForEachShaderEffect(std::function a_callback) { - ForEachMagicTempEffect([a_callback](BSTempEffect& a_tempEffect) { - const auto shaderEffect = a_tempEffect.As(); - if (shaderEffect && a_callback(*shaderEffect) == BSContainer::ForEachResult::kStop) { + ForEachMagicTempEffect([a_callback](BSTempEffect* a_tempEffect) { + const auto shaderEffect = a_tempEffect->As(); + if (shaderEffect && a_callback(shaderEffect) == BSContainer::ForEachResult::kStop) { return BSContainer::ForEachResult::kStop; } return BSContainer::ForEachResult::kContinue; @@ -96,8 +96,8 @@ namespace RE void ProcessLists::StopAllMagicEffects(TESObjectREFR& a_ref) { const auto handle = a_ref.CreateRefHandle(); - ForEachMagicTempEffect([&](BSTempEffect& a_tempEffect) { - const auto referenceEffect = a_tempEffect.As(); + ForEachMagicTempEffect([&](BSTempEffect* a_tempEffect) { + const auto referenceEffect = a_tempEffect->As(); if (referenceEffect && referenceEffect->target == handle) { referenceEffect->finished = true; } diff --git a/src/RE/T/TES.cpp b/src/RE/T/TES.cpp index 485a3620f..8e6305308 100644 --- a/src/RE/T/TES.cpp +++ b/src/RE/T/TES.cpp @@ -15,10 +15,10 @@ namespace RE return *singleton; } - void TES::ForEachReference(std::function a_callback) + void TES::ForEachReference(std::function a_callback) { if (interiorCell) { - interiorCell->ForEachReference([&](TESObjectREFR& a_ref) { + interiorCell->ForEachReference([&](TESObjectREFR* a_ref) { return a_callback(a_ref); }); } else { @@ -28,7 +28,7 @@ namespace RE std::uint32_t y = 0; do { if (const auto cell = gridCells->GetCell(x, y); cell && cell->IsAttached()) { - cell->ForEachReference([&](TESObjectREFR& a_ref) { + cell->ForEachReference([&](TESObjectREFR* a_ref) { return a_callback(a_ref); }); } @@ -39,19 +39,19 @@ namespace RE } } if (const auto skyCell = worldSpace ? worldSpace->GetSkyCell() : nullptr; skyCell) { - skyCell->ForEachReference([&](TESObjectREFR& a_ref) { + skyCell->ForEachReference([&](TESObjectREFR* a_ref) { return a_callback(a_ref); }); } } - void TES::ForEachReferenceInRange(TESObjectREFR* a_origin, float a_radius, std::function a_callback) + void TES::ForEachReferenceInRange(TESObjectREFR* a_origin, float a_radius, std::function a_callback) { if (a_origin && a_radius > 0.0f) { const auto originPos = a_origin->GetPosition(); if (interiorCell) { - interiorCell->ForEachReferenceInRange(originPos, a_radius, [&](TESObjectREFR& a_ref) { + interiorCell->ForEachReferenceInRange(originPos, a_radius, [&](TESObjectREFR* a_ref) { return a_callback(a_ref); }); } else { @@ -69,7 +69,7 @@ namespace RE if (const auto cellCoords = cell->GetCoordinates(); cellCoords) { const NiPoint2 worldPos{ cellCoords->worldX, cellCoords->worldY }; if (worldPos.x < xPlus && (worldPos.x + 4096.0f) > xMinus && worldPos.y < yPlus && (worldPos.y + 4096.0f) > yMinus) { - cell->ForEachReferenceInRange(originPos, a_radius, [&](TESObjectREFR& a_ref) { + cell->ForEachReferenceInRange(originPos, a_radius, [&](TESObjectREFR* a_ref) { return a_callback(a_ref); }); } @@ -83,12 +83,12 @@ namespace RE } if (const auto skyCell = worldSpace ? worldSpace->GetSkyCell() : nullptr; skyCell) { - skyCell->ForEachReferenceInRange(originPos, a_radius, [&](TESObjectREFR& a_ref) { + skyCell->ForEachReferenceInRange(originPos, a_radius, [&](TESObjectREFR* a_ref) { return a_callback(a_ref); }); } } else { - ForEachReference([&](TESObjectREFR& a_ref) { + ForEachReference([&](TESObjectREFR* a_ref) { return a_callback(a_ref); }); } diff --git a/src/RE/T/TESForm.cpp b/src/RE/T/TESForm.cpp index d280c2869..68b67cd00 100644 --- a/src/RE/T/TESForm.cpp +++ b/src/RE/T/TESForm.cpp @@ -69,8 +69,8 @@ namespace RE // Iterate through the keywords bool hasKeyword = false; - keywordForm->ForEachKeyword([&](const BGSKeyword& a_keyword) { - if (std::ranges::find(editorIDs, a_keyword.GetFormEditorID()) != editorIDs.end()) { + keywordForm->ForEachKeyword([&](const BGSKeyword* a_keyword) { + if (std::ranges::find(editorIDs, a_keyword->GetFormEditorID()) != editorIDs.end()) { hasKeyword = true; return BSContainer::ForEachResult::kStop; } @@ -122,8 +122,8 @@ namespace RE bool hasKeyword = false; - a_keywordList->ForEachForm([&](const TESForm& a_form) { - const auto keyword = a_form.As(); + a_keywordList->ForEachForm([&](const TESForm* a_form) { + const auto keyword = a_form->As(); hasKeyword = keyword && keywordForm->HasKeyword(keyword); if (a_matchAll && !hasKeyword || hasKeyword) { return BSContainer::ForEachResult::kStop; diff --git a/src/RE/T/TESObjectCELL.cpp b/src/RE/T/TESObjectCELL.cpp index e93c657c9..779df2405 100644 --- a/src/RE/T/TESObjectCELL.cpp +++ b/src/RE/T/TESObjectCELL.cpp @@ -10,21 +10,21 @@ namespace RE { - void TESObjectCELL::ForEachReference(std::function a_callback) const + void TESObjectCELL::ForEachReference(std::function a_callback) const { BSSpinLockGuard locker(spinLock); for (const auto& ref : references) { - if (ref && a_callback(*ref) == BSContainer::ForEachResult::kStop) { + if (ref && a_callback(ref.get()) == BSContainer::ForEachResult::kStop) { break; } } } - void TESObjectCELL::ForEachReferenceInRange(const NiPoint3& a_origin, float a_radius, std::function a_callback) const + void TESObjectCELL::ForEachReferenceInRange(const NiPoint3& a_origin, float a_radius, std::function a_callback) const { const float squaredRadius = a_radius * a_radius; - ForEachReference([&](TESObjectREFR& ref) { - const auto distance = a_origin.GetSquaredDistance(ref.GetPosition()); + ForEachReference([&](TESObjectREFR* ref) { + const auto distance = a_origin.GetSquaredDistance(ref->GetPosition()); return distance <= squaredRadius ? a_callback(ref) : BSContainer::ForEachResult::kContinue; diff --git a/src/RE/T/TESObjectREFR.cpp b/src/RE/T/TESObjectREFR.cpp index f7a782f8d..9d83840dd 100644 --- a/src/RE/T/TESObjectREFR.cpp +++ b/src/RE/T/TESObjectREFR.cpp @@ -578,8 +578,8 @@ namespace RE bool hasKeyword = false; - a_keywordList->ForEachForm([&](TESForm& a_form) { - const auto keyword = a_form.As(); + a_keywordList->ForEachForm([&](TESForm* a_form) { + const auto keyword = a_form->As(); hasKeyword = keyword && HasKeyword(keyword); if (a_matchAll && !hasKeyword || hasKeyword) { return BSContainer::ForEachResult::kStop; From 248c2d26f214aa4385f0ddeba71e8b61640af85c Mon Sep 17 00:00:00 2001 From: powerof3 <32599957+powerof3@users.noreply.github.com> Date: Thu, 18 Jan 2024 16:24:20 +0530 Subject: [PATCH 16/24] Add `MagicItem::IsHostile` --- include/RE/I/IngredientItem.h | 1 - include/RE/M/MagicItem.h | 1 + src/RE/I/IngredientItem.cpp | 5 ----- src/RE/M/MagicItem.cpp | 5 +++++ 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/RE/I/IngredientItem.h b/include/RE/I/IngredientItem.h index f159359e8..3884ff2b4 100644 --- a/include/RE/I/IngredientItem.h +++ b/include/RE/I/IngredientItem.h @@ -99,7 +99,6 @@ namespace RE // override (BGSKeywordForm) [[nodiscard]] BGSKeyword* GetDefaultKeyword() const override; // 05 - [[nodiscard]] bool IsHostile() const; bool LearnEffect(std::uint32_t a_index); bool LearnEffect(EffectSetting* a_effect); std::optional LearnNextEffect(); diff --git a/include/RE/M/MagicItem.h b/include/RE/M/MagicItem.h index 1da6b0779..fc9310bf3 100644 --- a/include/RE/M/MagicItem.h +++ b/include/RE/M/MagicItem.h @@ -118,6 +118,7 @@ namespace RE [[nodiscard]] std::int32_t GetLargestArea() const; [[nodiscard]] std::uint32_t GetLongestDuration() const; [[nodiscard]] bool HasEffect(EffectArchetype a_archetype); + [[nodiscard]] bool IsHostile() const; [[nodiscard]] bool IsPermanent() const; void Traverse(MagicItemTraversalFunctor& a_visitor) const; diff --git a/src/RE/I/IngredientItem.cpp b/src/RE/I/IngredientItem.cpp index 88f2f1339..3b31df0c4 100644 --- a/src/RE/I/IngredientItem.cpp +++ b/src/RE/I/IngredientItem.cpp @@ -4,11 +4,6 @@ namespace RE { - bool IngredientItem::IsHostile() const - { - return hostileCount > 0; - } - bool IngredientItem::LearnEffect(std::uint32_t a_index) { if (a_index < 4) { diff --git a/src/RE/M/MagicItem.cpp b/src/RE/M/MagicItem.cpp index 1bf83c274..785d9ff7e 100644 --- a/src/RE/M/MagicItem.cpp +++ b/src/RE/M/MagicItem.cpp @@ -73,6 +73,11 @@ namespace RE return func(this, a_archetype); } + bool MagicItem::IsHostile() const + { + return hostileCount > 0; + } + bool MagicItem::IsPermanent() const { using func_t = decltype(&MagicItem::IsPermanent); From 800b4e071bffd0a6527387f0d9164e35b5ae4120 Mon Sep 17 00:00:00 2001 From: powerof3 <32599957+powerof3@users.noreply.github.com> Date: Sat, 27 Jan 2024 00:02:44 +0530 Subject: [PATCH 17/24] `ReferenceEffect` RE --- include/RE/A/AttachTechniqueInput.h | 11 +++++------ include/RE/M/ModelReferenceEffect.h | 18 +++++++++--------- include/RE/R/RefAttachTechniqueInput.h | 14 +++++++------- include/RE/S/ShaderReferenceEffect.h | 8 ++++---- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/include/RE/A/AttachTechniqueInput.h b/include/RE/A/AttachTechniqueInput.h index b2236eb25..71632ce8c 100644 --- a/include/RE/A/AttachTechniqueInput.h +++ b/include/RE/A/AttachTechniqueInput.h @@ -1,6 +1,5 @@ #pragma once -#include "RE/M/MagicSystem.h" #include "RE/N/NiSmartPointer.h" namespace RE @@ -17,13 +16,13 @@ namespace RE virtual ~AttachTechniqueInput(); // 00 // add - virtual void Unk_01(void); // 01 + virtual void Clear(); // 01 // members - NiPointer current3DRoot; // 08 - smart ptr - NiPointer attachedArt; // 10 - smart ptr - MagicSystem::CastingSource castingSource; // 18 - std::uint32_t unk1C; // 1C + NiPointer current3DRoot; // 08 - smart ptr + NiPointer attachedArt; // 10 - smart ptr + std::uint32_t attachPoint; // 18 - MagicSystem::CastingSource for casting art + std::uint32_t pad18; // 18 }; static_assert(sizeof(AttachTechniqueInput) == 0x20); } diff --git a/include/RE/M/ModelReferenceEffect.h b/include/RE/M/ModelReferenceEffect.h index 3c379f203..f29e9c360 100644 --- a/include/RE/M/ModelReferenceEffect.h +++ b/include/RE/M/ModelReferenceEffect.h @@ -1,6 +1,6 @@ #pragma once -#include "RE/B/BSFixedString.h" +#include "RE/B/BGSLoadGameSubBuffer.h" #include "RE/B/BSTEvent.h" #include "RE/N/NiSmartPointer.h" #include "RE/R/RefAttachTechniqueInput.h" @@ -9,9 +9,9 @@ namespace RE { + class BGSArtObjectCloneTask; class NiAVObject; struct BSAnimationGraphEvent; - class BGSArtObjectCloneTask; class ModelReferenceEffect : public ReferenceEffect, // 00 @@ -55,13 +55,13 @@ namespace RE BSEventNotifyControl ProcessEvent(const BSAnimationGraphEvent* a_event, BSTEventSource* a_eventSource) override; // 01 // members - RefAttachTechniqueInput hitEffectArtData; // 68 - std::uint64_t unkB0; // B0 - BGSArtObject* artObject; // B8 - BSTSmartPointer cloneTask; // C0 - NiPointer artObject3D; // C8 - stl::enumeration flags; // D0 - std::uint32_t padD4; // D4 + RefAttachTechniqueInput hitEffectArtData; // 68 + BGSLoadGameSubBuffer loadGameSubBuffer; // B0 + BGSArtObject* artObject; // B8 + BSTSmartPointer cloneTask; // C0 + NiPointer artObject3D; // C8 + stl::enumeration flags; // D0 + std::uint32_t padD4; // D4 }; static_assert(sizeof(ModelReferenceEffect) == 0xD8); } diff --git a/include/RE/R/RefAttachTechniqueInput.h b/include/RE/R/RefAttachTechniqueInput.h index 887531011..53fc3be5a 100644 --- a/include/RE/R/RefAttachTechniqueInput.h +++ b/include/RE/R/RefAttachTechniqueInput.h @@ -16,15 +16,15 @@ namespace RE ~RefAttachTechniqueInput() override; // 00 // override (BSAttachTechniques::AttachTechniqueInput) - void Unk_01(void) override; // 01 + void Clear() override; // 01 // members - std::uint64_t unk20; // 20 - TESRace* actorRace; // 28 - bhkWorld* physicsWorld; // 30 - std::uint32_t collisionFilter; // 38 - std::uint32_t unk3C; // 3C - BSFixedString nodeName; // 40 + TESObjectREFR* actor; // 20 + TESRace* actorRace; // 28 + bhkWorld* physicsWorld; // 30 + std::uint32_t collisionFilter; // 38 + std::uint32_t pad3C; // 3C + BSFixedString nodeName; // 40 }; static_assert(sizeof(RefAttachTechniqueInput) == 0x48); } diff --git a/include/RE/S/ShaderReferenceEffect.h b/include/RE/S/ShaderReferenceEffect.h index dcd152f57..c3dedac2f 100644 --- a/include/RE/S/ShaderReferenceEffect.h +++ b/include/RE/S/ShaderReferenceEffect.h @@ -88,10 +88,10 @@ namespace RE TESEffectShader* effectData; // 108 BSEffectShaderData* effectShaderData; // 110 NiPointer targetRoot; // 118 - smart ptr - float unk120; // 120 - float unk124; // 124 - 1.0f - float addonModelsScaleStart; // 128 - 1.0f - std::uint32_t unk12C; // 12C + float alphaTimer; // 120 + float addonAlpha; // 124 - 1.0f + float addonScale; // 128 - 1.0f + float effectShaderAge; // 12C stl::enumeration flags; // 130 std::uint32_t pushCount; // 134 }; From 767d6ba23e776d0b40b2888696f3ae120bf5f375 Mon Sep 17 00:00:00 2001 From: powerof3 <32599957+powerof3@users.noreply.github.com> Date: Sat, 27 Jan 2024 00:03:16 +0530 Subject: [PATCH 18/24] Add `Actor::IsDualCasting` --- include/RE/A/Actor.h | 1 + src/RE/A/Actor.cpp | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/RE/A/Actor.h b/include/RE/A/Actor.h index 656bc0e73..258e2e95b 100644 --- a/include/RE/A/Actor.h +++ b/include/RE/A/Actor.h @@ -573,6 +573,7 @@ namespace RE bool IsCasting(MagicItem* a_spell) const; bool IsCommandedActor() const; bool IsCurrentShout(SpellItem* a_power); + bool IsDualCasting() const; bool IsEssential() const; bool IsFactionInCrimeGroup(const TESFaction* a_faction) const; bool IsGhost() const; diff --git a/src/RE/A/Actor.cpp b/src/RE/A/Actor.cpp index cfc81a100..1d330057a 100644 --- a/src/RE/A/Actor.cpp +++ b/src/RE/A/Actor.cpp @@ -749,14 +749,24 @@ namespace RE return boolFlags.all(BOOL_FLAGS::kIsCommandedActor); } - bool Actor::IsCurrentShout(SpellItem* a_spell) + bool Actor::IsCurrentShout(SpellItem* a_power) { using func_t = decltype(&Actor::IsCurrentShout); REL::Relocation func{ RELOCATION_ID(37858, 38812) }; - return func(this, a_spell); + return func(this, a_power); + } + + bool Actor::IsDualCasting() const + { + if (!currentProcess) { + return false; + } + + const auto highProcess = currentProcess->high; + return highProcess && highProcess->isDualCasting; } - bool Actor::IsEssential() const + bool Actor::IsEssential() const { return boolFlags.all(BOOL_FLAGS::kEssential); } From 23abe97fca24d024d5379db73307149ea4ad38fb Mon Sep 17 00:00:00 2001 From: powerof3 <32599957+powerof3@users.noreply.github.com> Date: Sat, 27 Jan 2024 00:04:10 +0530 Subject: [PATCH 19/24] Add `ExtraDataList::HasQuestObjectAlias` --- include/RE/E/ExtraDataList.h | 1 + src/RE/E/ExtraDataList.cpp | 9 ++++++++- src/RE/I/InventoryEntryData.cpp | 12 +++++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/RE/E/ExtraDataList.h b/include/RE/E/ExtraDataList.h index 98e891596..baec37472 100644 --- a/include/RE/E/ExtraDataList.h +++ b/include/RE/E/ExtraDataList.h @@ -181,6 +181,7 @@ namespace RE TESForm* GetOwner(); SOUL_LEVEL GetSoulLevel() const; ObjectRefHandle GetTeleportLinkedDoor(); + bool HasQuestObjectAlias(); void SetCount(std::uint16_t a_count); void SetEncounterZone(BGSEncounterZone* a_zone); void SetExtraFlags(ExtraFlags::Flag a_flags, bool a_enable); diff --git a/src/RE/E/ExtraDataList.cpp b/src/RE/E/ExtraDataList.cpp index bbf0b83ba..7d3b546df 100644 --- a/src/RE/E/ExtraDataList.cpp +++ b/src/RE/E/ExtraDataList.cpp @@ -282,7 +282,14 @@ namespace RE ObjectRefHandle(); } - void ExtraDataList::SetCount(std::uint16_t a_count) + bool ExtraDataList::HasQuestObjectAlias() + { + using func_t = decltype(&ExtraDataList::HasQuestObjectAlias); + REL::Relocation func{ RELOCATION_ID(11913, 12052) }; + return func(this); + } + + void ExtraDataList::SetCount(std::uint16_t a_count) { using func_t = decltype(&ExtraDataList::SetCount); REL::Relocation func{ Offset::ExtraDataList::SetCount }; diff --git a/src/RE/I/InventoryEntryData.cpp b/src/RE/I/InventoryEntryData.cpp index 18402da92..2c467664e 100644 --- a/src/RE/I/InventoryEntryData.cpp +++ b/src/RE/I/InventoryEntryData.cpp @@ -245,9 +245,15 @@ namespace RE bool InventoryEntryData::IsQuestObject() const { - using func_t = decltype(&InventoryEntryData::IsQuestObject); - REL::Relocation func{ RELOCATION_ID(15767, 16005) }; - return func(this); + if (extraLists) { + for (const auto& xList : *extraLists) { + if (xList && xList->HasQuestObjectAlias()) { + return true; + } + } + } + + return false; } void InventoryEntryData::PoisonObject(AlchemyItem* a_alchItem, std::uint32_t a_count) From b749caeee7ab8acee793c714915e34cad339642f Mon Sep 17 00:00:00 2001 From: powerof3 Date: Fri, 26 Jan 2024 18:40:16 +0000 Subject: [PATCH 20/24] maintenance --- src/RE/A/Actor.cpp | 6 +++--- src/RE/E/ExtraDataList.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/RE/A/Actor.cpp b/src/RE/A/Actor.cpp index 1d330057a..bc67a5067 100644 --- a/src/RE/A/Actor.cpp +++ b/src/RE/A/Actor.cpp @@ -756,17 +756,17 @@ namespace RE return func(this, a_power); } - bool Actor::IsDualCasting() const + bool Actor::IsDualCasting() const { if (!currentProcess) { return false; } - const auto highProcess = currentProcess->high; + const auto highProcess = currentProcess->high; return highProcess && highProcess->isDualCasting; } - bool Actor::IsEssential() const + bool Actor::IsEssential() const { return boolFlags.all(BOOL_FLAGS::kEssential); } diff --git a/src/RE/E/ExtraDataList.cpp b/src/RE/E/ExtraDataList.cpp index 7d3b546df..b14e07df9 100644 --- a/src/RE/E/ExtraDataList.cpp +++ b/src/RE/E/ExtraDataList.cpp @@ -282,14 +282,14 @@ namespace RE ObjectRefHandle(); } - bool ExtraDataList::HasQuestObjectAlias() + bool ExtraDataList::HasQuestObjectAlias() { using func_t = decltype(&ExtraDataList::HasQuestObjectAlias); REL::Relocation func{ RELOCATION_ID(11913, 12052) }; return func(this); } - void ExtraDataList::SetCount(std::uint16_t a_count) + void ExtraDataList::SetCount(std::uint16_t a_count) { using func_t = decltype(&ExtraDataList::SetCount); REL::Relocation func{ Offset::ExtraDataList::SetCount }; From 19b33364522b4a96a8828599bd3547603a278733 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sat, 27 Jan 2024 16:01:47 -0600 Subject: [PATCH 21/24] Improve WinAPI --- include/SKSE/Impl/WinAPI.h | 978 ++++++++++++++++++++++++++++------ src/SKSE/Impl/WinAPI.cpp | 1023 ++++++++++++++++++++++++++++-------- 2 files changed, 1641 insertions(+), 360 deletions(-) diff --git a/include/SKSE/Impl/WinAPI.h b/include/SKSE/Impl/WinAPI.h index ab6b84cb8..3b65100aa 100644 --- a/include/SKSE/Impl/WinAPI.h +++ b/include/SKSE/Impl/WinAPI.h @@ -1,117 +1,543 @@ #pragma once +#ifdef _INC_WINAPIFAMILY +# error Windows API detected. Please move any Windows API includes after CommonLibSSE, or remove them. +#else + namespace SKSE::WinAPI { + // general constants + inline const auto INVALID_HANDLE_VALUE{ reinterpret_cast(static_cast(-1)) }; + inline constexpr auto MAX_PATH{ 260u }; + + // standard access + inline constexpr auto STANDARD_RIGHTS_REQUIRED{ 0x000F0000 }; + inline constexpr auto STANDARD_RIGHTS_ALL{ 0x001F0000 }; + + // code page identifiers inline constexpr auto CP_UTF8{ 65001u }; + + // pe image header + inline constexpr auto IMAGE_DOS_SIGNATURE{ 0x5A4Du }; + inline constexpr auto IMAGE_NT_SIGNATURE{ 0x00004550u }; + inline constexpr auto IMAGE_NT_OPTIONAL_HDR32_MAGIC{ 0x10Bu }; + inline constexpr auto IMAGE_NT_OPTIONAL_HDR64_MAGIC{ 0x20Bu }; + + // pe image directory entries + inline constexpr auto IMAGE_DIRECTORY_ENTRY_EXPORT{ 0u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_IMPORT{ 1u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_RESOURCE{ 2u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_EXCEPTION{ 3u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_SECURITY{ 4u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_BASERELOC{ 5u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_DEBUG{ 6u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_ARCHITECTURE{ 7u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_GLOBALPTR{ 8u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_TLS{ 9u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG{ 10u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT{ 11u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_IAT{ 12u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT{ 13u }; + inline constexpr auto IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR{ 14u }; + inline constexpr auto IMAGE_NUMBEROF_DIRECTORY_ENTRIES{ 16u }; + + // pe image ordinal + inline constexpr auto IMAGE_ORDINAL_FLAG32{ 0x80000000u }; + inline constexpr auto IMAGE_ORDINAL_FLAG64{ 0x8000000000000000ull }; + + // pe image section header characteristics + inline constexpr auto IMAGE_SCN_MEM_SHARED{ 0x10000000u }; + inline constexpr auto IMAGE_SCN_MEM_EXECUTE{ 0x20000000u }; + inline constexpr auto IMAGE_SCN_MEM_READ{ 0x40000000u }; + inline constexpr auto IMAGE_SCN_MEM_WRITE{ 0x80000000u }; + inline constexpr auto IMAGE_SIZEOF_SECTION_HEADER{ 40u }; + inline constexpr auto IMAGE_SIZEOF_SHORT_NAME{ 8u }; + + // memory allocation types + inline constexpr auto MEM_COMMIT{ 0x00001000u }; + inline constexpr auto MEM_RESERVE{ 0x00002000u }; + inline constexpr auto MEM_DECOMMIT{ 0x00004000u }; + inline constexpr auto MEM_RELEASE{ 0x00008000u }; + inline constexpr auto MEM_FREE{ 0x00010000u }; + inline constexpr auto MEM_RESET{ 0x00080000u }; + inline constexpr auto MEM_RESET_UNDO{ 0x01000000u }; + + // memory page protection attributes + inline constexpr auto PAGE_NOACCESS{ 0x00000001u }; + inline constexpr auto PAGE_READONLY{ 0x00000002u }; + inline constexpr auto PAGE_READWRITE{ 0x00000004u }; + inline constexpr auto PAGE_WRITECOPY{ 0x00000008u }; + inline constexpr auto PAGE_EXECUTE{ 0x00000010u }; + inline constexpr auto PAGE_EXECUTE_READ{ 0x00000020u }; + inline constexpr auto PAGE_EXECUTE_READWRITE{ 0x00000040u }; + + // memory section + inline constexpr auto SECTION_QUERY{ 0x00000001 }; + inline constexpr auto SECTION_MAP_WRITE{ 0x00000002 }; + inline constexpr auto SECTION_MAP_READ{ 0x00000004 }; + inline constexpr auto SECTION_MAP_EXECUTE{ 0x00000008 }; + inline constexpr auto SECTION_EXTEND_SIZE{ 0x00000010 }; + inline constexpr auto SECTION_MAP_EXECUTE_EXPLICIT{ 0x00000020 }; + inline constexpr auto SECTION_ALL_ACCESS{ + STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE + }; + + // file attributes inline constexpr auto FILE_ATTRIBUTE_READONLY{ 0x00000001u }; inline constexpr auto FILE_ATTRIBUTE_HIDDEN{ 0x00000002u }; inline constexpr auto FILE_ATTRIBUTE_SYSTEM{ 0x00000004u }; inline constexpr auto FILE_ATTRIBUTE_DIRECTORY{ 0x00000010u }; inline constexpr auto FILE_ATTRIBUTE_ARCHIVE{ 0x00000020u }; - inline constexpr auto IMAGE_SCN_MEM_EXECUTE{ 0x20000000u }; - inline constexpr auto IMAGE_SCN_MEM_WRITE{ 0x80000000u }; - inline const auto INVALID_HANDLE_VALUE{ reinterpret_cast(static_cast(-1)) }; - inline constexpr auto MAX_PATH{ 260u }; - inline constexpr auto MEM_RELEASE{ 0x00008000u }; - inline constexpr auto PAGE_EXECUTE_READWRITE{ 0x40u }; + + // file mapping flags + inline constexpr auto FILE_MAP_ALL_ACCESS{ SECTION_ALL_ACCESS }; + inline constexpr auto FILE_MAP_COPY{ 0x00000001u }; + inline constexpr auto FILE_MAP_WRITE{ 0x00000002u }; + inline constexpr auto FILE_MAP_READ{ 0x00000004u }; + inline constexpr auto FILE_MAP_EXECUTE{ 0x00000020u }; + inline constexpr auto FILE_MAP_LARGE_PAGES{ 0x20000000u }; + inline constexpr auto FILE_MAP_TARGETS_INVALID{ 0x40000000u }; + inline constexpr auto FILE_MAP_RESERVE{ 0x80000000u }; + + // file open mode flags + inline constexpr auto GENERIC_READ{ 0x80000000L }; + inline constexpr auto GENERIC_WRITE{ 0x40000000L }; + inline constexpr auto GENERIC_EXECUTE{ 0x20000000L }; + inline constexpr auto GENERIC_ALL{ 0x10000000L }; + + // known folder flags + inline constexpr auto KF_FLAG_DEFAULT{ 0x00000000u }; + inline constexpr auto KF_FLAG_FORCE_APP_DATA_REDIRECTION{ 0x00080000u }; + inline constexpr auto KF_FLAG_RETURN_FILTER_REDIRECTION_TARGET{ 0x00040000u }; + inline constexpr auto KF_FLAG_FORCE_PACKAGE_REDIRECTION{ 0x00020000u }; + inline constexpr auto KF_FLAG_NO_PACKAGE_REDIRECTION{ 0x00010000u }; + inline constexpr auto KF_FLAG_FORCE_APPCONTAINER_REDIRECTION{ 0x00020000u }; + inline constexpr auto KF_FLAG_NO_APPCONTAINER_REDIRECTION{ 0x00010000u }; + inline constexpr auto KF_FLAG_CREATE{ 0x00008000u }; + inline constexpr auto KF_FLAG_DONT_VERIFY{ 0x00004000u }; + inline constexpr auto KF_FLAG_DONT_UNEXPAND{ 0x00002000u }; + inline constexpr auto KF_FLAG_NO_ALIAS{ 0x00001000u }; + inline constexpr auto KF_FLAG_INIT{ 0x00000800u }; + inline constexpr auto KF_FLAG_DEFAULT_PATH{ 0x00000400u }; + inline constexpr auto KF_FLAG_NOT_PARENT_RELATIVE{ 0x00000200u }; + inline constexpr auto KF_FLAG_SIMPLE_IDLIST{ 0x00000100u }; + inline constexpr auto KF_FLAG_ALIAS_ONLY{ 0x80000000u }; + + // string normalization forms + inline constexpr auto NORM_FORM_OTHER{ 0x0 }; + inline constexpr auto NORM_FORM_C{ 0x1 }; + inline constexpr auto NORM_FORM_D{ 0x2 }; + inline constexpr auto NORM_FORM_KC{ 0x5 }; + inline constexpr auto NORM_FORM_KD{ 0x6 }; + + // locale map flags + inline constexpr auto LCMAP_LOWERCASE{ 0x00000100u }; + inline constexpr auto LCMAP_UPPERCASE{ 0x00000200u }; + inline constexpr auto LCMAP_TITLECASE{ 0x00000300u }; + inline constexpr auto LCMAP_SORTKEY{ 0x00000400u }; + inline constexpr auto LCMAP_BYTEREV{ 0x00000800u }; + inline constexpr auto LCMAP_HIRAGANA{ 0x00100000u }; + inline constexpr auto LCMAP_KATAKANA{ 0x00200000u }; + inline constexpr auto LCMAP_HALFWIDTH{ 0x00400000u }; + inline constexpr auto LCMAP_FULLWIDTH{ 0x00800000u }; + inline constexpr auto LCMAP_LINGUISTIC_CASING{ 0x01000000u }; + inline constexpr auto LCMAP_SIMPLIFIED_CHINESE{ 0x02000000u }; + inline constexpr auto LCMAP_TRADITIONAL_CHINESE{ 0x04000000u }; + + // locale names + inline constexpr auto LOCALE_NAME_USER_DEFAULT{ nullptr }; + inline constexpr auto LOCALE_NAME_INVARIANT{ L"" }; + inline constexpr auto LOCALE_NAME_SYSTEM_DEFAULT{ L"!x-sys-default-locale" }; + + // process creation flags + inline constexpr auto DEBUG_PROCESS{ 0x00000001u }; + inline constexpr auto DEBUG_ONLY_THIS_PROCESS{ 0x00000002u }; + inline constexpr auto CREATE_SUSPENDED{ 0x00000004u }; + inline constexpr auto DETACHED_PROCESS{ 0x00000008u }; + inline constexpr auto CREATE_NEW_CONSOLE{ 0x00000010u }; + inline constexpr auto NORMAL_PRIORITY_CLASS{ 0x00000020u }; + inline constexpr auto IDLE_PRIORITY_CLASS{ 0x00000040u }; + inline constexpr auto HIGH_PRIORITY_CLASS{ 0x00000080u }; + inline constexpr auto REALTIME_PRIORITY_CLASS{ 0x00000100u }; + inline constexpr auto CREATE_NEW_PROCESS_GROUP{ 0x00000200u }; + inline constexpr auto CREATE_UNICODE_ENVIRONMENT{ 0x00000400u }; + inline constexpr auto CREATE_FORCEDOS{ 0x00002000u }; + inline constexpr auto BELOW_NORMAL_PRIORITY_CLASS{ 0x00004000u }; + inline constexpr auto ABOVE_NORMAL_PRIORITY_CLASS{ 0x00008000u }; + inline constexpr auto INHERIT_PARENT_AFFINITY{ 0x00010000u }; + inline constexpr auto CREATE_PROTECTED_PROCESS{ 0x00040000u }; + inline constexpr auto EXTENDED_STARTUPINFO_PRESENT{ 0x00080000u }; + inline constexpr auto PROCESS_MODE_BACKGROUND_BEGIN{ 0x00100000u }; + inline constexpr auto PROCESS_MODE_BACKGROUND_END{ 0x00200000u }; + inline constexpr auto CREATE_SECURE_PROCESS{ 0x00400000 }; + inline constexpr auto CREATE_BREAKAWAY_FROM_JOB{ 0x01000000u }; + inline constexpr auto CREATE_PRESERVE_CODE_AUTHZ_LEVEL{ 0x02000000u }; + inline constexpr auto CREATE_DEFAULT_ERROR_MODE{ 0x04000000u }; + inline constexpr auto CREATE_NO_WINDOW{ 0x08000000u }; + + // symbol name undecoration flags + inline constexpr auto UNDNAME_NO_MS_KEYWORDS{ 0x00000002u }; + inline constexpr auto UNDNAME_NO_FUNCTION_RETURNS{ 0x00000004u }; + inline constexpr auto UNDNAME_NO_ALLOCATION_MODEL{ 0x00000008u }; + inline constexpr auto UNDNAME_NO_ALLOCATION_LANGUAGE{ 0x00000010u }; + inline constexpr auto UNDNAME_NO_THISTYPE{ 0x00000060u }; + inline constexpr auto UNDNAME_NO_ACCESS_SPECIFIERS{ 0x00000080u }; + inline constexpr auto UNDNAME_NO_THROW_SIGNATURES{ 0x00000100u }; + inline constexpr auto UNDNAME_NO_RETURN_UDT_MODEL{ 0x00000400u }; + inline constexpr auto UNDNAME_NAME_ONLY{ 0x00001000u }; + inline constexpr auto UNDNAME_NO_ARGUMENTS{ 0x00002000u }; + + using THREAD_START_ROUTINE = std::uint32_t(void* a_param); struct CRITICAL_SECTION { public: - // members - void* DebugInfo; // 00 - std::int32_t LockCount; // 08 - std::int32_t RecursionCount; // 0C - void* OwningThread; // 10 - void* LockSemaphore; // 18 - std::uint64_t* SpinCount; // 20 + void* debugInfo; // 00 + std::int32_t lockCount; // 08 + std::int32_t recursionCount; // 0C + void* owningThread; // 10 + void* lockSemaphore; // 18 + std::uint64_t* spinCount; // 20 }; static_assert(sizeof(CRITICAL_SECTION) == 0x28); - struct _FILETIME + struct FILETIME { - public: - // members - std::uint32_t dwLowDateTime; // 00 - std::uint32_t dwHighDateTime; // 04 + std::uint32_t lo; // 00 + std::uint32_t hi; // 04 }; - static_assert(sizeof(_FILETIME) == 0x8); - using FILETIME = _FILETIME; + static_assert(sizeof(FILETIME) == 0x8); - struct _GUID + struct GUID { - std::uint32_t Data1; - std::uint16_t Data2; - std::uint16_t Data3; - std::uint8_t Data4[8]; + std::uint32_t data1; + std::uint16_t data2; + std::uint16_t data3; + std::uint8_t data4[8]; }; - static_assert(sizeof(_GUID) == 0x10); - using GUID = _GUID; + static_assert(sizeof(GUID) == 0x10); + + // known folder ids + inline constexpr GUID FOLDERID_DOCUMENTS{ 0xFDD39AD0u, 0x238Fu, 0x46AFu, 0xADu, 0xB4u, 0x6Cu, 0x85u, 0x48u, 0x03u, 0x69u, 0xC7u }; + inline constexpr GUID FOLDERID_PICTURES{ 0x33E28130u, 0x4E1Eu, 0x4676u, 0x83u, 0x5Au, 0x98u, 0x39u, 0x5Cu, 0x3Bu, 0xC3u, 0xBBu }; + inline constexpr GUID FOLDERID_PROGRAMDATA{ 0x62AB5D82u, 0xFDC1u, 0x4DC3u, 0xA9u, 0xDDu, 0x07u, 0x0Du, 0x1Du, 0x49u, 0x5Du, 0x97u }; + + using HRESULT = std::uint32_t; struct HWND__; using HWND = HWND__*; - struct HINSTANCE__; - using HINSTANCE = HINSTANCE__*; + using WNDPROC = std::int32_t(__stdcall*)(HWND, std::uint32_t, std::uint64_t, std::int64_t); struct HICON__; using HICON = HICON__*; - using WNDPROC = std::int32_t(__stdcall*)(HWND, std::uint32_t, std::uint64_t, std::int64_t); + struct HINSTANCE__; + using HINSTANCE = HINSTANCE__*; + using HMODULE = HINSTANCE; + + struct HKEY__; + using HKEY = HKEY__*; + + inline auto HKEY_CLASSES_ROOT{ reinterpret_cast(0x80000000ull) }; + inline auto HKEY_CURRENT_USER{ reinterpret_cast(0x80000001ull) }; + inline auto HKEY_LOCAL_MACHINE{ reinterpret_cast(0x80000002ull) }; - struct _WIN32_FIND_DATAA + struct IMAGE_DATA_DIRECTORY { - public: - // members - std::uint32_t dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - std::uint32_t nFileSizeHigh; - std::uint32_t nFileSizeLow; - std::uint32_t dwReserved0; - std::uint32_t dwReserved1; - char cFileName[MAX_PATH]; - char cAlternateFileName[14]; + std::uint32_t virtualAddress; + std::uint32_t size; }; - static_assert(sizeof(_WIN32_FIND_DATAA) == 0x140); - using WIN32_FIND_DATAA = _WIN32_FIND_DATAA; + static_assert(sizeof(IMAGE_DATA_DIRECTORY) == 0x8); - struct _WIN32_FIND_DATAW + struct IMAGE_DOS_HEADER { - public: - // members - std::uint32_t dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - std::uint32_t nFileSizeHigh; - std::uint32_t nFileSizeLow; - std::uint32_t dwReserved0; - std::uint32_t dwReserved1; - wchar_t cFileName[MAX_PATH]; - wchar_t cAlternateFileName[14]; + std::uint16_t magic; + std::uint16_t cblp; + std::uint16_t cp; + std::uint16_t crlc; + std::uint16_t cparhdr; + std::uint16_t minalloc; + std::uint16_t maxalloc; + std::uint16_t ss; + std::uint16_t sp; + std::uint16_t csum; + std::uint16_t ip; + std::uint16_t cs; + std::uint16_t lfarlc; + std::uint16_t ovno; + std::uint16_t res[4]; + std::uint16_t oemid; + std::uint16_t oeminfo; + std::uint16_t res2[10]; + std::int32_t lfanew; + }; + static_assert(sizeof(IMAGE_DOS_HEADER) == 0x40); + + struct IMAGE_FILE_HEADER + { + std::uint16_t machine; + std::uint16_t sectionCount; + std::uint32_t timeDateStamp; + std::uint32_t symbolTablePtr; + std::uint32_t symbolCount; + std::uint16_t optionalHeaderSize; + std::uint16_t characteristics; + }; + static_assert(sizeof(IMAGE_FILE_HEADER) == 0x14); + + struct IMAGE_IMPORT_BY_NAME + { + std::uint16_t hint; + char name[1]; + }; + static_assert(sizeof(IMAGE_IMPORT_BY_NAME) == 0x4); + + struct IMAGE_IMPORT_DESCRIPTOR + { + union + { + std::uint32_t characteristics; + std::uint32_t firstThunkOriginal; + }; + + std::uint32_t timeDateStamp; + std::uint32_t forwarderChain; + std::uint32_t name; + std::uint32_t firstThunk; }; - static_assert(sizeof(_WIN32_FIND_DATAW) == 0x250); - using WIN32_FIND_DATAW = _WIN32_FIND_DATAW; + static_assert(sizeof(IMAGE_IMPORT_DESCRIPTOR) == 0x14); - struct tagRECT + struct IMAGE_OPTIONAL_HEADER64 + { + std::uint16_t magic; + std::uint8_t linkerVersionMajor; + std::uint8_t linkerVersionMinor; + std::uint32_t codeSize; + std::uint32_t initializedDataSize; + std::uint32_t uninitializedDataSize; + std::uint32_t entryPointAddress; + std::uint32_t codeBase; + std::uint64_t imageBase; + std::uint32_t sectionAlignment; + std::uint32_t fileAlignment; + std::uint16_t osVersionMajor; + std::uint16_t osVersionMinor; + std::uint16_t imageVersionMajor; + std::uint16_t imageVersionMinor; + std::uint16_t subsystemVersionMajor; + std::uint16_t subsystemVersionMinor; + std::uint32_t win32Version; + std::uint32_t imageSize; + std::uint32_t headersSize; + std::uint32_t checksum; + std::uint16_t subsystem; + std::uint16_t dllCharacteristics; + std::uint64_t stackReserveSize; + std::uint64_t stackCommitSize; + std::uint64_t heapReserveSize; + std::uint64_t heapCommitSize; + std::uint32_t loaderFlags; + std::uint32_t rvaAndSizesCount; + IMAGE_DATA_DIRECTORY dataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + }; + static_assert(sizeof(IMAGE_OPTIONAL_HEADER64) == 0xF0); + + struct IMAGE_NT_HEADERS64 + { + std::uint32_t signature; + IMAGE_FILE_HEADER fileHeader; + IMAGE_OPTIONAL_HEADER64 optionalHeader; + }; + static_assert(sizeof(IMAGE_NT_HEADERS64) == 0x108); + + struct IMAGE_SECTION_HEADER + { + std::uint8_t name[IMAGE_SIZEOF_SHORT_NAME]; + union + { + std::uint32_t physicalAddress; + std::uint32_t virtualSize; + }; + std::uint32_t virtualAddress; + std::uint32_t rawDataSize; + std::uint32_t rawDataPtr; + std::uint32_t relocationsPtr; + std::uint32_t lineNumbersPtr; + std::uint16_t relocationsCount; + std::uint16_t lineNumbersCount; + std::uint32_t characteristics; + }; + static_assert(sizeof(IMAGE_SECTION_HEADER) == 0x28); + + struct IMAGE_THUNK_DATA64 + { + union + { + std::uint64_t forwarderString; // PBYTE + std::uint64_t function; // PDWORD + std::uint64_t ordinal; + std::uint64_t address; // PIMAGE_IMPORT_BY_NAME + }; + }; + static_assert(sizeof(IMAGE_THUNK_DATA64) == 0x8); + + struct MEMORY_BASIC_INFORMATION + { + void* baseAddress; + void* allocationBase; + std::uint32_t allocationProtect; + std::uint16_t partitionID; + std::size_t regionSize; + std::uint32_t state; + std::uint32_t protect; + std::uint32_t type; + }; + static_assert(sizeof(MEMORY_BASIC_INFORMATION) == 0x30); + + struct NLSVERSIONINFO; + + struct POINT + { + std::int32_t x; + std::int32_t y; + }; + + struct PROCESS_INFORMATION + { + void* process; + void* thread; + std::uint32_t processID; + std::uint32_t threadID; + }; + static_assert(sizeof(PROCESS_INFORMATION) == 0x18); + + struct RECT { std::int32_t left; std::int32_t top; std::int32_t right; std::int32_t bottom; }; - using RECT = tagRECT; - struct tagPOINT + struct SECURITY_ATTRIBUTES { - std::int32_t x; - std::int32_t y; + std::uint32_t length; + void* securityDescriptor; + bool inheritHandle; }; - using POINT = tagPOINT; + static_assert(sizeof(SECURITY_ATTRIBUTES) == 0x18); - using HRESULT = std::int32_t; + struct STARTUPINFOA + { + std::uint32_t size; + char* reserved0; + char* desktop; + char* title; + std::uint32_t x; + std::uint32_t y; + std::uint32_t xSize; + std::uint32_t ySize; + std::uint32_t xCountChars; + std::uint32_t yCountChars; + std::uint32_t fillAttribute; + std::uint32_t flags; + std::uint16_t showWindow; + std::uint16_t reserved1; + std::uint8_t* reserved2; + void* stdIn; + void* stdOut; + void* stdErr; + }; + static_assert(sizeof(STARTUPINFOA) == 0x68); + + struct STARTUPINFOW + { + std::uint32_t size; + wchar_t* reserved0; + wchar_t* desktop; + wchar_t* title; + std::uint32_t x; + std::uint32_t y; + std::uint32_t xSize; + std::uint32_t ySize; + std::uint32_t xCountChars; + std::uint32_t yCountChars; + std::uint32_t fillAttribute; + std::uint32_t flags; + std::uint16_t showWindow; + std::uint16_t reserved1; + std::uint8_t* reserved2; + void* stdIn; + void* stdOut; + void* stdErr; + }; + static_assert(sizeof(STARTUPINFOW) == 0x68); + + struct SYSTEM_INFO + { + union + { + std::uint32_t oemID; + struct + { + std::uint16_t processorArch; + std::uint16_t reserved; + }; + }; + std::uint32_t pageSize; + void* appAddressMin; + void* appAddressMax; + std::uintptr_t processorActiveMask; + std::uint32_t processorCount; + std::uint32_t processorType; + std::uint32_t allocationGranularity; + std::uint16_t processorLevel; + std::uint16_t processorRevision; + }; + static_assert(sizeof(SYSTEM_INFO) == 0x30); + + union ULARGE_INTEGER + { + struct + { + std::uint32_t lo; + std::uint32_t hi; + }; + std::uint64_t value; + }; + + struct WIN32_FIND_DATAA + { + // members + std::uint32_t fileAttributes; + FILETIME creationTime; + FILETIME lastAccessTime; + FILETIME lastWriteTime; + std::uint32_t fileSizeHi; + std::uint32_t fileSizeLo; + std::uint32_t reserved0; + std::uint32_t reserved1; + char fileName[MAX_PATH]; + char fileNameAlt[14]; + }; + static_assert(sizeof(WIN32_FIND_DATAA) == 0x140); + + struct WIN32_FIND_DATAW + { + // members + std::uint32_t fileAttributes; + FILETIME creationTime; + FILETIME lastAccessTime; + FILETIME lastWriteTime; + std::uint32_t fileSizeHi; + std::uint32_t fileSizeLo; + std::uint32_t reserved0; + std::uint32_t reserved1; + wchar_t fileName[MAX_PATH]; + wchar_t fileNameAlt[14]; + }; + static_assert(sizeof(WIN32_FIND_DATAW) == 0x250); enum VKEnum : std::uint32_t { @@ -344,23 +770,105 @@ namespace SKSE::WinAPI VK_RESERVED_FF = 0xFF }; - [[nodiscard]] bool FindClose(void* a_findFile) noexcept; + bool CloseHandle( + void* a_handle) noexcept; + + void CoTaskMemFree( + void* a_block) noexcept; + + void* CreateFileMapping( + void* a_file, + SECURITY_ATTRIBUTES* a_attributes, + std::uint32_t a_protect, + std::uint32_t a_maxSizeHigh, + std::uint32_t a_maxSizeLow, + const char* a_name) noexcept; + + void* CreateFileMapping( + void* a_file, + SECURITY_ATTRIBUTES* a_attributes, + std::uint32_t a_protect, + std::uint32_t a_maxSizeHigh, + std::uint32_t a_maxSizeLow, + const wchar_t* a_name) noexcept; + + bool CreateProcess( + const char* a_name, + char* a_cmd, + SECURITY_ATTRIBUTES* a_procAttr, + SECURITY_ATTRIBUTES* a_threadAttr, + bool a_inherit, + std::uint32_t a_flags, + void* a_env, + const char* a_curDir, + STARTUPINFOA* a_startInfo, + PROCESS_INFORMATION* a_procInfo) noexcept; + + bool CreateProcess( + const wchar_t* a_name, + wchar_t* a_cmd, + SECURITY_ATTRIBUTES* a_procAttr, + SECURITY_ATTRIBUTES* a_threadAttr, + bool a_inherit, + std::uint32_t a_flags, + void* a_env, + const wchar_t* a_curDir, + STARTUPINFOW* a_startInfo, + PROCESS_INFORMATION* a_procInfo) noexcept; + + void* CreateRemoteThread( + void* a_process, + SECURITY_ATTRIBUTES* a_threadAttr, + std::size_t a_stackSize, + THREAD_START_ROUTINE* a_startAddr, + void* a_param, + std::uint32_t a_flags, + std::uint32_t* a_threadID) noexcept; + + void* CreateThread( + SECURITY_ATTRIBUTES* a_threadAttr, + std::size_t a_stackSize, + THREAD_START_ROUTINE* a_startAddr, + void* a_param, + std::uint32_t a_flags, + std::uint32_t* a_threadID) noexcept; + + std::uint32_t ExpandEnvironmentStrings( + const char* a_src, + char* a_dst, + std::uint32_t a_dstLen) noexcept; + + std::uint32_t ExpandEnvironmentStrings( + const wchar_t* a_src, + wchar_t* a_dst, + std::uint32_t a_dstLen) noexcept; + + [[nodiscard]] bool FindClose( + void* a_file) noexcept; [[nodiscard]] void* FindFirstFile( - const char* a_fileName, - WIN32_FIND_DATAA* a_findFileData) noexcept; + const char* a_name, + WIN32_FIND_DATAA* a_data) noexcept; [[nodiscard]] void* FindFirstFile( - const wchar_t* a_fileName, - WIN32_FIND_DATAW* a_findFileData) noexcept; + const wchar_t* a_name, + WIN32_FIND_DATAW* a_data) noexcept; [[nodiscard]] bool FindNextFile( - void* a_findFile, - WIN32_FIND_DATAA* a_findFileData) noexcept; + void* a_file, + WIN32_FIND_DATAA* a_data) noexcept; [[nodiscard]] bool FindNextFile( - void* a_findFile, - WIN32_FIND_DATAW* a_findFileData) noexcept; + void* a_file, + WIN32_FIND_DATAW* a_data) noexcept; + + bool FlushInstructionCache( + void* a_process, + const void* a_baseAddr, + std::size_t a_size) noexcept; + + bool FreeLibrary( + HMODULE a_module) noexcept; [[nodiscard]] void* GetCurrentModule() noexcept; @@ -379,152 +887,327 @@ namespace SKSE::WinAPI std::uint32_t a_size) noexcept; [[nodiscard]] bool GetFileVersionInfo( - const char* a_filename, + const char* a_name, std::uint32_t a_handle, - std::uint32_t a_len, + std::uint32_t a_dataLen, void* a_data) noexcept; [[nodiscard]] bool GetFileVersionInfo( - const wchar_t* a_filename, + const wchar_t* a_name, std::uint32_t a_handle, - std::uint32_t a_len, + std::uint32_t a_dataLen, void* a_data) noexcept; [[nodiscard]] std::uint32_t GetFileVersionInfoSize( - const char* a_filename, + const char* a_name, std::uint32_t* a_handle) noexcept; [[nodiscard]] std::uint32_t GetFileVersionInfoSize( - const wchar_t* a_filename, + const wchar_t* a_name, std::uint32_t* a_handle) noexcept; - [[nodiscard]] int GetKeyNameText( - std::int32_t a_lParam, + [[nodiscard]] std::int32_t GetKeyNameText( + std::int32_t a_param, char* a_buffer, - int a_size) noexcept; + std::int32_t a_bufferLen) noexcept; - [[nodiscard]] int GetKeyNameText( - std::int32_t a_lParam, + [[nodiscard]] std::int32_t GetKeyNameText( + std::int32_t a_param, wchar_t* a_buffer, - int a_size) noexcept; + std::int32_t a_bufferLen) noexcept; + + [[nodiscard]] std::int16_t GetKeyState( + std::int32_t a_key) noexcept; - [[nodiscard]] std::int16_t GetKeyState(int nVirtKey) noexcept; + [[nodiscard]] std::uint32_t GetLastError() noexcept; [[nodiscard]] std::size_t GetMaxPath() noexcept; [[nodiscard]] std::uint32_t GetModuleFileName( void* a_module, - char* a_filename, - std::uint32_t a_size) noexcept; + char* a_name, + std::uint32_t a_nameLen) noexcept; [[nodiscard]] std::uint32_t GetModuleFileName( void* a_module, - wchar_t* a_filename, - std::uint32_t a_size) noexcept; + wchar_t* a_name, + std::uint32_t a_nameLen) noexcept; - [[nodiscard]] void* GetModuleHandle(const char* a_moduleName) noexcept; + [[nodiscard]] HMODULE GetModuleHandle( + const char* a_name) noexcept; - [[nodiscard]] void* GetModuleHandle(const wchar_t* a_moduleName) noexcept; + [[nodiscard]] HMODULE GetModuleHandle( + const wchar_t* a_name) noexcept; [[nodiscard]] std::uint32_t GetPrivateProfileString( - const char* a_appName, - const char* a_keyName, + const char* a_app, + const char* a_key, const char* a_default, - char* a_outString, - std::uint32_t a_size, - const char* a_fileName) noexcept; + char* a_out, + std::uint32_t a_outLen, + const char* a_name) noexcept; [[nodiscard]] std::uint32_t GetPrivateProfileString( - const wchar_t* a_appName, - const wchar_t* a_keyName, + const wchar_t* a_app, + const wchar_t* a_key, const wchar_t* a_default, - wchar_t* a_outString, - std::uint32_t a_size, - const wchar_t* a_fileName) noexcept; + wchar_t* a_out, + std::uint32_t a_outLen, + const wchar_t* a_name) noexcept; [[nodiscard]] void* GetProcAddress( void* a_module, - const char* a_procName) noexcept; + const char* a_name) noexcept; + + [[nodiscard]] std::string_view GetProcPath( + HMODULE a_handle) noexcept; + + void GetSystemInfo( + SYSTEM_INFO* a_info) noexcept; + + [[nodiscard]] bool IMAGE_SNAP_BY_ORDINAL64( + std::uint64_t a_ordinal) noexcept; + + [[nodiscard]] IMAGE_SECTION_HEADER* IMAGE_FIRST_SECTION( + const IMAGE_NT_HEADERS64* a_header) noexcept; [[nodiscard]] bool IsDebuggerPresent() noexcept; + std::int32_t LCMapStringEx( + const wchar_t* a_locale, + std::uint32_t a_flags, + const wchar_t* a_src, + std::int32_t a_srcLen, + wchar_t* a_dest, + std::int32_t a_destLen, + NLSVERSIONINFO* a_info, + void* a_reserved, + std::intptr_t a_sortHandle) noexcept; + + [[nodiscard]] HMODULE LoadLibrary( + const char* a_name) noexcept; + + [[nodiscard]] HMODULE LoadLibrary( + const wchar_t* a_name) noexcept; + + [[nodiscard]] void* MapViewOfFile( + void* a_object, + std::uint32_t a_desiredAccess, + std::uint32_t a_fileOffsetHigh, + std::uint32_t a_fileOffsetLow, + std::size_t a_numBytesToMap) noexcept; + + [[nodiscard]] void* MapViewOfFileEx( + void* a_object, + std::uint32_t a_desiredAccess, + std::uint32_t a_fileOffsetHigh, + std::uint32_t a_fileOffsetLow, + std::size_t a_numBytesToMap, + void* a_baseAddress) noexcept; + std::int32_t MessageBox( - void* a_wnd, - const char* a_text, - const char* a_caption, - unsigned int a_type) noexcept; + void* a_wnd, + const char* a_text, + const char* a_caption, + std::uint32_t a_type) noexcept; std::int32_t MessageBox( void* a_wnd, const wchar_t* a_text, const wchar_t* a_caption, - unsigned int a_type) noexcept; + std::uint32_t a_type) noexcept; - [[nodiscard]] int MultiByteToWideChar( - unsigned int a_codePage, + [[nodiscard]] std::int32_t MultiByteToWideChar( + std::uint32_t a_codePage, std::uint32_t a_flags, - const char* a_multiByteStr, - int a_multiByte, - wchar_t* a_wideCharStr, - int a_wideChar); + const char* a_str, + std::int32_t a_strLen, + wchar_t* a_wstr, + std::int32_t a_wstrLen); + + [[nodiscard]] std::int32_t NormalizeString( + std::int32_t a_normForm, + const wchar_t* a_src, + std::int32_t a_srcLen, + wchar_t* a_dest, + std::int32_t a_destLen); + + [[nodiscard]] void* OpenFileMapping( + std::uint32_t a_desiredAccess, + bool a_inheritHandle, + const char* a_name) noexcept; + + [[nodiscard]] void* OpenFileMapping( + std::uint32_t a_desiredAccess, + bool a_inheritHandle, + const wchar_t* a_name) noexcept; void OutputDebugString( - const char* a_outputString) noexcept; + const char* a_outStr) noexcept; void OutputDebugString( - const wchar_t* a_outputString) noexcept; + const wchar_t* a_outStr) noexcept; - [[nodiscard]] int ShowCursor(bool bShow) noexcept; + std::int32_t RegGetValue( + HKEY a_key, + const char* a_subKey, + const char* a_value, + std::uint32_t a_flags, + std::uint32_t* a_type, + void* a_data, + std::uint32_t* a_dataLen); - [[noreturn]] void TerminateProcess( - void* a_process, - unsigned int a_exitCode) noexcept; + std::int32_t RegGetValue( + HKEY a_key, + const wchar_t* a_subKey, + const wchar_t* a_value, + std::uint32_t a_flags, + std::uint32_t* a_type, + void* a_data, + std::uint32_t* a_dataLen); - [[nodiscard]] void* TlsGetValue(std::uint32_t a_tlsIndex) noexcept; + std::uint32_t ResumeThread( + void* a_handle) noexcept; + + bool SetEnvironmentVariable( + const char* a_name, + const char* a_value) noexcept; + + bool SetEnvironmentVariable( + const wchar_t* a_name, + const wchar_t* a_value) noexcept; + + [[nodiscard]] std::int32_t SHGetKnownFolderPath( + const GUID& a_id, + std::uint32_t a_flags, + void* a_token, + wchar_t** a_path) noexcept; + + [[nodiscard]] std::int32_t ShowCursor( + bool a_show) noexcept; + + void Sleep( + std::uint32_t a_milliseconds) noexcept; + + bool TerminateProcess( + void* a_process, + std::uint32_t a_exitCode) noexcept; + + [[nodiscard]] void* TlsGetValue( + std::uint32_t a_index) noexcept; bool TlsSetValue( - std::uint32_t a_tlsIndex, - void* a_tlsValue) noexcept; + std::uint32_t a_index, + void* a_value) noexcept; - bool VirtualFree( - void* a_address, - std::size_t a_size, - std::uint32_t a_freeType) noexcept; + [[nodiscard]] std::uint32_t UnDecorateSymbolName( + const char* a_name, + char* a_out, + std::uint32_t a_outLenMax, + std::uint32_t a_flags) noexcept; + + [[nodiscard]] std::uint32_t UnDecorateSymbolName( + const wchar_t* a_name, + wchar_t* a_out, + std::uint32_t a_outLenMax, + std::uint32_t a_flags) noexcept; - [[nodiscard]] bool VerQueryValue( - const void* a_block, - const char* a_subBlock, - void** a_buffer, - unsigned int* a_len) noexcept; + bool UnmapViewOfFile( + const void* a_baseAddress) noexcept; + + bool VerQueryValue( + const void* a_block, + const char* a_subBlock, + void** a_buffer, + std::uint32_t* a_bufferLen) noexcept; - [[nodiscard]] bool VerQueryValue( + bool VerQueryValue( const void* a_block, const wchar_t* a_subBlock, void** a_buffer, - unsigned int* a_len) noexcept; + std::uint32_t* a_bufferLen) noexcept; - [[nodiscard]] bool VirtualProtect( + void* VirtualAlloc( + void* a_address, + std::size_t a_size, + std::uint32_t a_type, + std::uint32_t a_protect) noexcept; + + void* VirtualAllocEx( + void* a_process, + void* a_address, + std::size_t a_size, + std::uint32_t a_type, + std::uint32_t a_protect) noexcept; + + bool VirtualFree( + void* a_address, + std::size_t a_size, + std::uint32_t a_type) noexcept; + + bool VirtualFreeEx( + void* a_process, + void* a_address, + std::size_t a_size, + std::uint32_t a_type) noexcept; + + bool VirtualProtect( + void* a_address, + std::size_t a_size, + std::uint32_t a_newProtect, + std::uint32_t* a_oldProtect) noexcept; + + bool VirtualProtectEx( + void* a_process, void* a_address, std::size_t a_size, std::uint32_t a_newProtect, std::uint32_t* a_oldProtect) noexcept; - [[nodiscard]] int WideCharToMultiByte( - unsigned int a_codePage, + [[nodiscard]] std::size_t VirtualQuery( + const void* a_address, + MEMORY_BASIC_INFORMATION* a_buffer, + std::size_t a_bufferLen) noexcept; + + [[nodiscard]] std::size_t VirtualQueryEx( + void* a_process, + const void* a_address, + MEMORY_BASIC_INFORMATION* a_buffer, + std::size_t a_bufferLen) noexcept; + + [[nodiscard]] std::uint32_t WaitForSingleObject( + void* a_handle, + std::uint32_t a_milliseconds) noexcept; + + [[nodiscard]] std::uint32_t WaitForSingleObjectEx( + void* a_handle, + std::uint32_t a_milliseconds, + bool a_alertable) noexcept; + + [[nodiscard]] std::int32_t WideCharToMultiByte( + std::uint32_t a_codePage, std::uint32_t a_flags, - const wchar_t* a_wideCharStr, - int a_wideChar, - char* a_multiByteStr, - int a_multiByte, - const char* a_defaultChar, - int* a_usedDefaultChar); + const wchar_t* a_wstr, + std::int32_t a_wstrLen, + char* a_str, + std::int32_t a_strLen, + const char* a_default, + std::int32_t* a_defaultLen); + + bool WriteProcessMemory( + void* a_process, + void* a_address, + const void* a_buffer, + std::size_t a_bufferLen, + std::size_t* a_bufferWritten) noexcept; } +#endif // _INC_WINAPIFAMILY + namespace RE::DirectX { struct XMFLOAT4X4 { - public: // members float m[4][4]; }; @@ -532,7 +1215,6 @@ namespace RE::DirectX struct DXGI_RATIONAL { - public: // members std::uint32_t numerator; // 00 std::uint32_t denominator; // 04 diff --git a/src/SKSE/Impl/WinAPI.cpp b/src/SKSE/Impl/WinAPI.cpp index 0a7fecb9a..3a28645eb 100644 --- a/src/SKSE/Impl/WinAPI.cpp +++ b/src/SKSE/Impl/WinAPI.cpp @@ -1,7 +1,17 @@ #include "SKSE/Impl/WinAPI.h" +#define WIN32_LEAN_AND_MEAN + +// clang-format off #include +#include +#include +#include +// clang-format on +#undef CreateFileMapping +#undef CreateProcess +#undef ExpandEnvironmentStrings #undef FindFirstFile #undef FindNextFile #undef GetEnvironmentVariable @@ -11,252 +21,493 @@ #undef GetModuleFileName #undef GetModuleHandle #undef GetPrivateProfileString +#undef IMAGE_FIRST_SECTION +#undef IMAGE_SNAP_BY_ORDINAL64 +#undef LoadLibrary #undef MessageBox +#undef OpenFileMapping #undef OutputDebugString +#undef RegGetValue +#undef RegQueryValueEx +#undef SetEnvironmentVariable #undef VerQueryValue extern "C" IMAGE_DOS_HEADER __ImageBase; namespace SKSE::WinAPI { - [[nodiscard]] bool FindClose(void* a_findFile) noexcept + bool CloseHandle( + void* a_handle) noexcept { return static_cast( - ::FindClose(static_cast<::HMODULE>(a_findFile))); + ::CloseHandle( + a_handle)); + } + + void CoTaskMemFree( + void* a_block) noexcept + { + ::CoTaskMemFree( + a_block); + } + + void* CreateFileMapping( + void* a_file, + SECURITY_ATTRIBUTES* a_attributes, + std::uint32_t a_protect, + std::uint32_t a_maxSizeHigh, + std::uint32_t a_maxSizeLow, + const char* a_name) noexcept + { + return CreateFileMappingA( + a_file, + reinterpret_cast(a_attributes), + a_protect, + a_maxSizeHigh, + a_maxSizeLow, + a_name); } - [[nodiscard]] void* FindFirstFile( - const char* a_fileName, - WIN32_FIND_DATAA* a_findFileData) noexcept + void* CreateFileMapping( + void* a_file, + SECURITY_ATTRIBUTES* a_attributes, + std::uint32_t a_protect, + std::uint32_t a_maxSizeHigh, + std::uint32_t a_maxSizeLow, + const wchar_t* a_name) noexcept { - return static_cast( - ::FindFirstFileA( - static_cast<::LPCSTR>(a_fileName), - reinterpret_cast<::LPWIN32_FIND_DATAA>(a_findFileData))); + return CreateFileMappingW( + a_file, + reinterpret_cast(a_attributes), + a_protect, + a_maxSizeHigh, + a_maxSizeLow, + a_name); } - [[nodiscard]] void* FindFirstFile( - const wchar_t* a_fileName, - WIN32_FIND_DATAW* a_findFileData) noexcept + bool CreateProcess( + const char* a_name, + char* a_cmd, + SECURITY_ATTRIBUTES* a_procAttr, + SECURITY_ATTRIBUTES* a_threadAttr, + bool a_inherit, + std::uint32_t a_flags, + void* a_env, + const char* a_curDir, + STARTUPINFOA* a_startInfo, + PROCESS_INFORMATION* a_procInfo) noexcept { - return static_cast( - ::FindFirstFileW( - static_cast<::LPCWSTR>(a_fileName), - reinterpret_cast<::LPWIN32_FIND_DATAW>(a_findFileData))); + return static_cast( + CreateProcessA( + a_name, + a_cmd, + reinterpret_cast(a_procAttr), + reinterpret_cast(a_threadAttr), + a_inherit, + a_flags, + a_env, + a_curDir, + reinterpret_cast(a_startInfo), + reinterpret_cast(a_procInfo))); } - [[nodiscard]] bool FindNextFile( - void* a_findFile, - WIN32_FIND_DATAA* a_findFileData) noexcept + bool CreateProcess( + const wchar_t* a_name, + wchar_t* a_cmd, + SECURITY_ATTRIBUTES* a_procAttr, + SECURITY_ATTRIBUTES* a_threadAttr, + bool a_inherit, + std::uint32_t a_flags, + void* a_env, + const wchar_t* a_curDir, + STARTUPINFOW* a_startInfo, + PROCESS_INFORMATION* a_procInfo) noexcept { return static_cast( - ::FindNextFileA( - static_cast<::HANDLE>(a_findFile), - reinterpret_cast<::LPWIN32_FIND_DATAA>(a_findFileData))); + CreateProcessW( + a_name, + a_cmd, + reinterpret_cast(a_procAttr), + reinterpret_cast(a_threadAttr), + a_inherit, + a_flags, + a_env, + a_curDir, + reinterpret_cast(a_startInfo), + reinterpret_cast(a_procInfo))); + } + + void* CreateRemoteThread( + void* a_process, + SECURITY_ATTRIBUTES* a_threadAttr, + std::size_t a_stackSize, + THREAD_START_ROUTINE* a_startAddr, + void* a_param, + std::uint32_t a_flags, + std::uint32_t* a_threadID) noexcept + { + return ::CreateRemoteThread( + a_process, + reinterpret_cast(a_threadAttr), + a_stackSize, + reinterpret_cast(a_startAddr), + a_param, + a_flags, + reinterpret_cast(a_threadID)); + } + + void* CreateThread( + SECURITY_ATTRIBUTES* a_threadAttr, + std::size_t a_stackSize, + THREAD_START_ROUTINE* a_startAddr, + void* a_param, + std::uint32_t a_flags, + std::uint32_t* a_threadID) noexcept + { + return ::CreateThread( + reinterpret_cast(a_threadAttr), + a_stackSize, + reinterpret_cast(a_startAddr), + a_param, + a_flags, + reinterpret_cast(a_threadID)); + } + + std::uint32_t ExpandEnvironmentStrings( + const char* a_src, + char* a_dst, + std::uint32_t a_dstLen) noexcept + { + return static_cast( + ExpandEnvironmentStringsA( + a_src, + a_dst, + a_dstLen)); } - [[nodiscard]] bool FindNextFile( - void* a_findFile, - WIN32_FIND_DATAW* a_findFileData) noexcept + std::uint32_t ExpandEnvironmentStrings( + const wchar_t* a_src, + wchar_t* a_dst, + std::uint32_t a_dstLen) noexcept + { + return static_cast( + ExpandEnvironmentStringsW( + a_src, + a_dst, + a_dstLen)); + } + + bool FindClose( + void* a_file) noexcept { return static_cast( - ::FindNextFileW( - static_cast<::HANDLE>(a_findFile), - reinterpret_cast<::LPWIN32_FIND_DATAW>(a_findFileData))); + ::FindClose( + a_file)); + } + + void* FindFirstFile( + const char* a_name, + WIN32_FIND_DATAA* a_data) noexcept + { + return FindFirstFileA( + a_name, + reinterpret_cast(a_data)); + } + + void* FindFirstFile( + const wchar_t* a_name, + WIN32_FIND_DATAW* a_data) noexcept + { + return FindFirstFileW( + a_name, + reinterpret_cast(a_data)); + } + + bool FindNextFile( + void* a_file, + WIN32_FIND_DATAA* a_data) noexcept + { + return static_cast( + FindNextFileA( + a_file, + reinterpret_cast(a_data))); + } + + bool FindNextFile( + void* a_file, + WIN32_FIND_DATAW* a_data) noexcept + { + return static_cast( + FindNextFileW( + a_file, + reinterpret_cast(a_data))); + } + + bool FlushInstructionCache( + void* a_process, + const void* a_baseAddr, + std::size_t a_size) noexcept + { + return static_cast( + ::FlushInstructionCache( + a_process, + a_baseAddr, + a_size)); + } + + bool FreeLibrary( + HMODULE a_module) noexcept + { + return static_cast( + ::FreeLibrary( + reinterpret_cast<::HMODULE>(a_module))); } void* GetCurrentModule() noexcept { - return static_cast( - std::addressof(__ImageBase)); + return std::addressof(__ImageBase); } void* GetCurrentProcess() noexcept { - return static_cast( - ::GetCurrentProcess()); + return ::GetCurrentProcess(); } std::uint32_t GetCurrentThreadID() noexcept { return static_cast( - ::GetCurrentThreadId()); + GetCurrentThreadId()); } - [[nodiscard]] std::uint32_t GetEnvironmentVariable( + std::uint32_t GetEnvironmentVariable( const char* a_name, char* a_buffer, - std::uint32_t a_size) noexcept + std::uint32_t a_bufferLen) noexcept { return static_cast( - ::GetEnvironmentVariableA( - static_cast<::LPCSTR>(a_name), - static_cast<::LPSTR>(a_buffer), - static_cast<::DWORD>(a_size))); + GetEnvironmentVariableA( + a_name, + a_buffer, + a_bufferLen)); } - [[nodiscard]] std::uint32_t GetEnvironmentVariable( + std::uint32_t GetEnvironmentVariable( const wchar_t* a_name, wchar_t* a_buffer, - std::uint32_t a_size) noexcept + std::uint32_t a_bufferLen) noexcept { return static_cast( - ::GetEnvironmentVariableW( - static_cast<::LPCWSTR>(a_name), - static_cast<::LPWSTR>(a_buffer), - static_cast<::DWORD>(a_size))); + GetEnvironmentVariableW( + a_name, + a_buffer, + a_bufferLen)); } bool GetFileVersionInfo( - const char* a_filename, + const char* a_name, std::uint32_t a_handle, - std::uint32_t a_len, + std::uint32_t a_dataLen, void* a_data) noexcept { return static_cast( - ::GetFileVersionInfoA( - static_cast<::LPCSTR>(a_filename), - static_cast<::DWORD>(a_handle), - static_cast<::DWORD>(a_len), - static_cast<::LPVOID>(a_data))); + GetFileVersionInfoA( + a_name, + a_handle, + a_dataLen, + a_data)); } bool GetFileVersionInfo( - const wchar_t* a_filename, + const wchar_t* a_name, std::uint32_t a_handle, - std::uint32_t a_len, + std::uint32_t a_dataLen, void* a_data) noexcept { return static_cast( - ::GetFileVersionInfoW( - static_cast<::LPCWSTR>(a_filename), - static_cast<::DWORD>(a_handle), - static_cast<::DWORD>(a_len), - static_cast<::LPVOID>(a_data))); + GetFileVersionInfoW( + a_name, + a_handle, + a_dataLen, + a_data)); } std::uint32_t GetFileVersionInfoSize( - const char* a_filename, + const char* a_name, std::uint32_t* a_handle) noexcept { return static_cast( - ::GetFileVersionInfoSizeA( - static_cast<::LPCSTR>(a_filename), - reinterpret_cast<::LPDWORD>(a_handle))); + GetFileVersionInfoSizeA( + a_name, + reinterpret_cast(a_handle))); } std::uint32_t GetFileVersionInfoSize( - const wchar_t* a_filename, + const wchar_t* a_name, std::uint32_t* a_handle) noexcept { return static_cast( - ::GetFileVersionInfoSizeW( - static_cast<::LPCWSTR>(a_filename), - reinterpret_cast<::LPDWORD>(a_handle))); + GetFileVersionInfoSizeW( + a_name, + reinterpret_cast(a_handle))); } - int GetKeyNameText(std::int32_t a_lParam, wchar_t* a_buffer, int a_size) noexcept + std::int32_t GetKeyNameText( + std::int32_t a_param, + wchar_t* a_buffer, + std::int32_t a_bufferLen) noexcept { - return ::GetKeyNameTextW(static_cast<::LONG>(a_lParam), static_cast<::LPWSTR>(a_buffer), a_size); + return GetKeyNameTextW( + a_param, + a_buffer, + a_bufferLen); } - int GetKeyNameText(std::int32_t a_lParam, char* a_buffer, int a_size) noexcept + std::int32_t GetKeyNameText( + std::int32_t a_param, + char* a_buffer, + std::int32_t a_bufferLen) noexcept { - return ::GetKeyNameTextA(static_cast<::LONG>(a_lParam), static_cast<::LPSTR>(a_buffer), a_size); + return GetKeyNameTextA( + a_param, + a_buffer, + a_bufferLen); } - std::int16_t GetKeyState(int nVirtKey) noexcept + std::int16_t GetKeyState( + std::int32_t a_key) noexcept { - return ::GetKeyState(nVirtKey); + return ::GetKeyState(a_key); + } + + std::uint32_t GetLastError() noexcept + { + return static_cast( + ::GetLastError()); } std::size_t GetMaxPath() noexcept { - return static_cast(MAX_PATH); + return MAX_PATH; } std::uint32_t GetModuleFileName( void* a_module, - char* a_filename, - std::uint32_t a_size) noexcept + char* a_name, + std::uint32_t a_nameLen) noexcept { return static_cast( - ::GetModuleFileNameA( + GetModuleFileNameA( static_cast<::HMODULE>(a_module), - static_cast<::LPSTR>(a_filename), - static_cast<::DWORD>(a_size))); + a_name, + a_nameLen)); } std::uint32_t GetModuleFileName( void* a_module, - wchar_t* a_filename, - std::uint32_t a_size) noexcept + wchar_t* a_name, + std::uint32_t a_nameLen) noexcept { return static_cast( - ::GetModuleFileNameW( + GetModuleFileNameW( static_cast<::HMODULE>(a_module), - static_cast<::LPWSTR>(a_filename), - static_cast<::DWORD>(a_size))); + a_name, + a_nameLen)); } - void* GetModuleHandle(const char* a_moduleName) noexcept + HMODULE GetModuleHandle( + const char* a_name) noexcept { - return static_cast( - ::GetModuleHandleA( - static_cast<::LPCSTR>(a_moduleName))); + return reinterpret_cast( + GetModuleHandleA( + a_name)); } - void* GetModuleHandle(const wchar_t* a_moduleName) noexcept + HMODULE GetModuleHandle( + const wchar_t* a_name) noexcept { - return static_cast( - ::GetModuleHandleW( - static_cast<::LPCWSTR>(a_moduleName))); + return reinterpret_cast( + GetModuleHandleW(a_name)); } std::uint32_t GetPrivateProfileString( - const char* a_appName, - const char* a_keyName, + const char* a_app, + const char* a_key, const char* a_default, - char* a_outString, - std::uint32_t a_size, - const char* a_fileName) noexcept + char* a_out, + std::uint32_t a_outLen, + const char* a_name) noexcept { return static_cast( - ::GetPrivateProfileStringA( - static_cast<::LPCSTR>(a_appName), - static_cast<::LPCSTR>(a_keyName), - static_cast<::LPCSTR>(a_default), - static_cast<::LPSTR>(a_outString), - static_cast<::DWORD>(a_size), - static_cast<::LPCSTR>(a_fileName))); + GetPrivateProfileStringA( + a_app, + a_key, + a_default, + a_out, + a_outLen, + a_name)); } std::uint32_t GetPrivateProfileString( - const wchar_t* a_appName, - const wchar_t* a_keyName, + const wchar_t* a_app, + const wchar_t* a_key, const wchar_t* a_default, - wchar_t* a_outString, - std::uint32_t a_size, - const wchar_t* a_fileName) noexcept + wchar_t* a_out, + std::uint32_t a_outLen, + const wchar_t* a_name) noexcept { return static_cast( - ::GetPrivateProfileStringW( - static_cast<::LPCWSTR>(a_appName), - static_cast<::LPCWSTR>(a_keyName), - static_cast<::LPCWSTR>(a_default), - static_cast<::LPWSTR>(a_outString), - static_cast<::DWORD>(a_size), - static_cast<::LPCWSTR>(a_fileName))); + GetPrivateProfileStringW( + a_app, + a_key, + a_default, + a_out, + a_outLen, + a_name)); } void* GetProcAddress( void* a_module, - const char* a_procName) noexcept + const char* a_name) noexcept { return reinterpret_cast( ::GetProcAddress( static_cast<::HMODULE>(a_module), - static_cast<::LPCSTR>(a_procName))); + a_name)); + } + + std::string_view GetProcPath( + HMODULE a_handle) noexcept + { + static std::string fileName(MAX_PATH + 1, ' '); + auto res = GetModuleFileName(a_handle, fileName.data(), MAX_PATH + 1); + if (res == 0) { + fileName = "[ProcessHost]"; + res = 13; + } + + return { fileName.c_str(), res }; + } + + void GetSystemInfo( + SYSTEM_INFO* a_info) noexcept + { + ::GetSystemInfo( + reinterpret_cast(a_info)); + } + + bool IMAGE_SNAP_BY_ORDINAL64( + std::uint64_t a_ordinal) noexcept + { + return (a_ordinal & IMAGE_ORDINAL_FLAG64) != 0; + } + + IMAGE_SECTION_HEADER* IMAGE_FIRST_SECTION( + const IMAGE_NT_HEADERS64* a_header) noexcept + { + constexpr auto opt = __builtin_offsetof(IMAGE_NT_HEADERS64, optionalHeader); + const auto optSize = a_header->fileHeader.optionalHeaderSize; + const auto section = reinterpret_cast(a_header) + opt + optSize; + return reinterpret_cast(section); } bool IsDebuggerPresent() noexcept @@ -265,134 +516,405 @@ namespace SKSE::WinAPI ::IsDebuggerPresent()); } + std::int32_t LCMapStringEx( + const wchar_t* a_locale, + std::uint32_t a_flags, + const wchar_t* a_src, + std::int32_t a_srcLen, + wchar_t* a_dest, + std::int32_t a_destLen, + NLSVERSIONINFO* a_info, + void* a_reserved, + std::intptr_t a_sortHandle) noexcept + { + return ::LCMapStringEx( + a_locale, + a_flags, + a_src, + a_srcLen, + a_dest, + a_destLen, + reinterpret_cast(a_info), + a_reserved, + a_sortHandle); + } + + HMODULE LoadLibrary( + const char* a_name) noexcept + { + return reinterpret_cast( + LoadLibraryA( + a_name)); + } + + HMODULE LoadLibrary( + const wchar_t* a_name) noexcept + { + return reinterpret_cast( + LoadLibraryW(a_name)); + } + + void* MapViewOfFile( + void* a_object, + std::uint32_t a_desiredAccess, + std::uint32_t a_fileOffsetHigh, + std::uint32_t a_fileOffsetLow, + std::size_t a_numBytesToMap) noexcept + { + return ::MapViewOfFile( + a_object, + a_desiredAccess, + a_fileOffsetHigh, + a_fileOffsetLow, + a_numBytesToMap); + } + + void* MapViewOfFileEx( + void* a_object, + std::uint32_t a_desiredAccess, + std::uint32_t a_fileOffsetHigh, + std::uint32_t a_fileOffsetLow, + std::size_t a_numBytesToMap, + void* a_baseAddress) noexcept + { + return ::MapViewOfFileEx( + a_object, + a_desiredAccess, + a_fileOffsetHigh, + a_fileOffsetLow, + a_numBytesToMap, + a_baseAddress); + } + std::int32_t MessageBox( - void* a_wnd, - const char* a_text, - const char* a_caption, - unsigned int a_type) noexcept + void* a_wnd, + const char* a_text, + const char* a_caption, + std::uint32_t a_type) noexcept { - return static_cast( - ::MessageBoxA( - static_cast<::HWND>(a_wnd), - static_cast<::LPCSTR>(a_text), - static_cast<::LPCSTR>(a_caption), - static_cast<::UINT>(a_type))); + return MessageBoxA( + static_cast<::HWND>(a_wnd), + a_text, + a_caption, + a_type); } std::int32_t MessageBox( void* a_wnd, const wchar_t* a_text, const wchar_t* a_caption, - unsigned int a_type) noexcept + std::uint32_t a_type) noexcept { - return static_cast( - ::MessageBoxW( - static_cast<::HWND>(a_wnd), - static_cast<::LPCWSTR>(a_text), - static_cast<::LPCWSTR>(a_caption), - static_cast<::UINT>(a_type))); + return MessageBoxW( + static_cast<::HWND>(a_wnd), + a_text, + a_caption, + a_type); } - int MultiByteToWideChar( - unsigned int a_codePage, + std::int32_t MultiByteToWideChar( + std::uint32_t a_codePage, std::uint32_t a_flags, - const char* a_multiByteStr, - int a_multiByte, - wchar_t* a_wideCharStr, - int a_wideChar) + const char* a_str, + std::int32_t a_strLen, + wchar_t* a_wstr, + std::int32_t a_wstrLen) { return ::MultiByteToWideChar( - static_cast<::UINT>(a_codePage), - static_cast<::DWORD>(a_flags), - static_cast<::LPCCH>(a_multiByteStr), - a_multiByte, - static_cast<::LPWSTR>(a_wideCharStr), - a_wideChar); + a_codePage, + a_flags, + a_str, + a_strLen, + a_wstr, + a_wstrLen); + } + + std::int32_t NormalizeString( + std::int32_t a_normForm, + const wchar_t* a_src, + std::int32_t a_srcLen, + wchar_t* a_dest, + std::int32_t a_destLen) + { + return ::NormalizeString( + static_cast(a_normForm), + a_src, + a_srcLen, + a_dest, + a_destLen); + } + + void* OpenFileMapping( + std::uint32_t a_desiredAccess, + bool a_inheritHandle, + const char* a_name) noexcept + { + return OpenFileMappingA( + a_desiredAccess, + a_inheritHandle, + a_name); + } + + void* OpenFileMapping( + std::uint32_t a_desiredAccess, + bool a_inheritHandle, + const wchar_t* a_name) noexcept + { + return OpenFileMappingW( + a_desiredAccess, + a_inheritHandle, + a_name); } void OutputDebugString( - const char* a_outputString) noexcept + const char* a_out) noexcept { - ::OutputDebugStringA( - static_cast<::LPCSTR>(a_outputString)); + OutputDebugStringA( + a_out); } void OutputDebugString( - const wchar_t* a_outputString) noexcept + const wchar_t* a_out) noexcept { - ::OutputDebugStringW( - static_cast<::LPCWSTR>(a_outputString)); + OutputDebugStringW( + a_out); } - int ShowCursor(bool bShow) noexcept + std::int32_t RegGetValue( + HKEY a_key, + const char* a_subKey, + const char* a_value, + std::uint32_t a_flags, + std::uint32_t* a_type, + void* a_data, + std::uint32_t* a_dataLen) { - return ::ShowCursor(static_cast<::BOOL>(bShow)); + return RegGetValueA( + reinterpret_cast<::HKEY>(a_key), + a_subKey, + a_value, + a_flags, + reinterpret_cast(a_type), + a_data, + reinterpret_cast(a_dataLen)); } - void TerminateProcess( - void* a_process, - unsigned int a_exitCode) noexcept + std::int32_t RegGetValue( + HKEY a_key, + const wchar_t* a_subKey, + const wchar_t* a_value, + std::uint32_t a_flags, + std::uint32_t* a_type, + void* a_data, + std::uint32_t* a_dataLen) { - ::TerminateProcess( - static_cast<::HANDLE>(a_process), - static_cast<::UINT>(a_exitCode)); + return RegGetValueW( + reinterpret_cast<::HKEY>(a_key), + a_subKey, + a_value, + a_flags, + reinterpret_cast(a_type), + a_data, + reinterpret_cast(a_dataLen)); } - void* TlsGetValue(std::uint32_t a_tlsIndex) noexcept + std::uint32_t ResumeThread( + void* a_handle) noexcept { - return static_cast( - ::TlsGetValue( - static_cast<::DWORD>(a_tlsIndex))); + return static_cast( + ::ResumeThread( + a_handle)); + } + + bool SetEnvironmentVariable( + const char* a_name, + const char* a_value) noexcept + { + return static_cast( + SetEnvironmentVariableA( + a_name, + a_value)); + } + + bool SetEnvironmentVariable( + const wchar_t* a_name, + const wchar_t* a_value) noexcept + { + return static_cast( + SetEnvironmentVariableW( + a_name, + a_value)); + } + + std::int32_t SHGetKnownFolderPath( + const GUID& a_id, + std::uint32_t a_flags, + void* a_token, + wchar_t** a_path) noexcept + { + return static_cast( + ::SHGetKnownFolderPath( + reinterpret_cast(a_id), + a_flags, + a_token, + a_path)); + } + + std::int32_t ShowCursor( + bool a_show) noexcept + { + return ::ShowCursor( + a_show); + } + + void Sleep( + std::uint32_t a_milliseconds) noexcept + { + ::Sleep(a_milliseconds); + } + + bool TerminateProcess( + void* a_process, + std::uint32_t a_exitCode) noexcept + { + return static_cast( + ::TerminateProcess( + a_process, + a_exitCode)); + } + + void* TlsGetValue( + std::uint32_t a_index) noexcept + { + return ::TlsGetValue( + a_index); } bool TlsSetValue( - std::uint32_t a_tlsIndex, - void* a_tlsValue) noexcept + std::uint32_t a_index, + void* a_value) noexcept { return static_cast( ::TlsSetValue( - static_cast<::DWORD>(a_tlsIndex), - static_cast<::LPVOID>(a_tlsValue))); + a_index, + a_value)); } - bool VirtualFree( - void* a_address, - std::size_t a_size, - std::uint32_t a_freeType) noexcept + std::uint32_t UnDecorateSymbolName( + const char* a_name, + char* a_out, + std::uint32_t a_outLenMax, + std::uint32_t a_flags) noexcept + { + return static_cast( + ::UnDecorateSymbolName( + a_name, + a_out, + a_outLenMax, + a_flags)); + } + + std::uint32_t UnDecorateSymbolName( + const wchar_t* a_name, + wchar_t* a_out, + std::uint32_t a_outLenMax, + std::uint32_t a_flags) noexcept + { + return static_cast( + UnDecorateSymbolNameW( + a_name, + a_out, + a_outLenMax, + a_flags)); + } + + bool UnmapViewOfFile( + const void* a_baseAddress) noexcept { return static_cast( - ::VirtualFree( - static_cast<::LPVOID>(a_address), - static_cast<::SIZE_T>(a_size), - static_cast<::DWORD>(a_freeType))); + ::UnmapViewOfFile( + a_baseAddress)); } bool VerQueryValue( - const void* a_block, - const char* a_subBlock, - void** a_buffer, - unsigned int* a_len) noexcept + const void* a_block, + const char* a_subBlock, + void** a_buffer, + std::uint32_t* a_bufferLen) noexcept { return static_cast( - ::VerQueryValueA( - static_cast<::LPCVOID>(a_block), - static_cast<::LPCSTR>(a_subBlock), - static_cast<::LPVOID*>(a_buffer), - static_cast<::PUINT>(a_len))); + VerQueryValueA(a_block, + a_subBlock, + a_buffer, + a_bufferLen)); } bool VerQueryValue( const void* a_block, const wchar_t* a_subBlock, void** a_buffer, - unsigned int* a_len) noexcept + std::uint32_t* a_bufferLen) noexcept { return static_cast( - ::VerQueryValueW( - static_cast<::LPCVOID>(a_block), - static_cast<::LPCWSTR>(a_subBlock), - static_cast<::LPVOID*>(a_buffer), - static_cast<::PUINT>(a_len))); + VerQueryValueW( + a_block, + a_subBlock, + a_buffer, + a_bufferLen)); + } + + void* VirtualAlloc( + void* a_address, + std::size_t a_size, + std::uint32_t a_type, + std::uint32_t a_protect) noexcept + { + return ::VirtualAlloc( + a_address, + a_size, + a_type, + a_protect); + } + + void* VirtualAllocEx( + void* a_process, + void* a_address, + std::size_t a_size, + std::uint32_t a_type, + std::uint32_t a_protect) noexcept + { + return ::VirtualAllocEx( + a_process, + a_address, + a_size, + a_type, + a_protect); + } + + bool VirtualFree( + void* a_address, + std::size_t a_size, + std::uint32_t a_type) noexcept + { + return static_cast( + ::VirtualFree( + a_address, + a_size, + a_type)); + } + + bool VirtualFreeEx( + void* a_process, + void* a_address, + std::size_t a_size, + std::uint32_t a_type) noexcept + { + return static_cast( + ::VirtualFreeEx( + a_process, + a_address, + a_size, + a_type)); } bool VirtualProtect( @@ -403,31 +925,108 @@ namespace SKSE::WinAPI { return static_cast( ::VirtualProtect( - static_cast<::LPVOID>(a_address), - static_cast<::SIZE_T>(a_size), - static_cast<::DWORD>(a_newProtect), - reinterpret_cast<::PDWORD>(a_oldProtect))); + a_address, + a_size, + a_newProtect, + reinterpret_cast(a_oldProtect))); + } + + bool VirtualProtectEx( + void* a_process, + void* a_address, + std::size_t a_size, + std::uint32_t a_newProtect, + std::uint32_t* a_oldProtect) noexcept + { + return static_cast( + ::VirtualProtectEx( + a_process, + a_address, + a_size, + a_newProtect, + reinterpret_cast(a_oldProtect))); + } + + std::size_t VirtualQuery( + const void* a_address, + MEMORY_BASIC_INFORMATION* a_buffer, + std::size_t a_bufferLen) noexcept + { + return ::VirtualQuery( + a_address, + reinterpret_cast(a_buffer), + a_bufferLen); + } + + std::size_t VirtualQueryEx( + void* a_process, + const void* a_address, + MEMORY_BASIC_INFORMATION* a_buffer, + std::size_t a_bufferLen) noexcept + { + return ::VirtualQueryEx( + a_process, + a_address, + reinterpret_cast(a_buffer), + a_bufferLen); } - int WideCharToMultiByte( - unsigned int a_codePage, + std::uint32_t WaitForSingleObject( + void* a_handle, + std::uint32_t a_milliseconds) noexcept + { + return static_cast( + ::WaitForSingleObject( + a_handle, + a_milliseconds)); + } + + std::uint32_t WaitForSingleObjectEx( + void* a_handle, + std::uint32_t a_milliseconds, + bool a_alertable) noexcept + { + return static_cast( + ::WaitForSingleObjectEx( + a_handle, + a_milliseconds, + a_alertable)); + } + + std::int32_t WideCharToMultiByte( + std::uint32_t a_codePage, std::uint32_t a_flags, - const wchar_t* a_wideCharStr, - int a_wideChar, - char* a_multiByteStr, - int a_multiByte, - const char* a_defaultChar, - int* a_usedDefaultChar) + const wchar_t* a_wstr, + std::int32_t a_wstrLen, + char* a_str, + std::int32_t a_strLen, + const char* a_default, + std::int32_t* a_defaultLen) { return ::WideCharToMultiByte( - static_cast<::UINT>(a_codePage), - static_cast<::DWORD>(a_flags), - static_cast<::LPCWCH>(a_wideCharStr), - a_wideChar, - static_cast<::LPSTR>(a_multiByteStr), - a_multiByte, - static_cast<::LPCCH>(a_defaultChar), - static_cast<::LPBOOL>(a_usedDefaultChar)); + a_codePage, + a_flags, + a_wstr, + a_wstrLen, + a_str, + a_strLen, + a_default, + a_defaultLen); } + bool WriteProcessMemory( + void* a_process, + void* a_address, + const void* a_buffer, + std::size_t a_bufferLen, + std::size_t* a_bufferWritten) noexcept + { + return static_cast( + ::WriteProcessMemory( + a_process, + a_address, + a_buffer, + a_bufferLen, + a_bufferWritten)); + } } From 89bbcd3fde7b0e6b6576e6311ffd43240300ce63 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sat, 27 Jan 2024 16:02:20 -0600 Subject: [PATCH 22/24] Improve WinAPI+ --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a08923da..5bace4cb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ target_link_libraries( binary_io::binary_io spdlog::spdlog Version.lib + Dbghelp.lib ) target_precompile_headers( From 55bdb18c4b7d8395a935b6f883362d7cd9eed0b3 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sat, 27 Jan 2024 16:05:05 -0600 Subject: [PATCH 23/24] Separate Relocation.h --- cmake/sourcelist.cmake | 9 +- include/REL/ID.h | 374 ++++++++++++++++++ include/REL/Module.h | 151 +++++++ include/REL/Offset.h | 30 ++ include/REL/Pattern.h | 189 +++++++++ include/REL/REL.h | 8 + include/REL/Relocation.h | 823 --------------------------------------- include/REL/Version.h | 105 +++++ include/SKSE/Impl/PCH.h | 2 +- src/REL/ID.cpp | 87 +++++ src/REL/Module.cpp | 25 ++ src/REL/Relocation.cpp | 155 -------- 12 files changed, 978 insertions(+), 980 deletions(-) create mode 100644 include/REL/ID.h create mode 100644 include/REL/Module.h create mode 100644 include/REL/Offset.h create mode 100644 include/REL/Pattern.h create mode 100644 include/REL/REL.h create mode 100644 include/REL/Version.h create mode 100644 src/REL/ID.cpp create mode 100644 src/REL/Module.cpp delete mode 100644 src/REL/Relocation.cpp diff --git a/cmake/sourcelist.cmake b/cmake/sourcelist.cmake index 10ddee0a5..297ce72d1 100644 --- a/cmake/sourcelist.cmake +++ b/cmake/sourcelist.cmake @@ -1613,7 +1613,13 @@ set(SOURCES include/RE/W/WerewolfFeedEffect.h include/RE/Z/ZeroFunctionArguments.h include/RE/Z/ZeroOverheadHeap.h + include/REL/ID.h + include/REL/Module.h + include/REL/Offset.h + include/REL/Pattern.h + include/REL/REL.h include/REL/Relocation.h + include/REL/Version.h include/SKSE/API.h include/SKSE/Events.h include/SKSE/IAT.h @@ -1957,7 +1963,8 @@ set(SOURCES src/RE/V/Variable.cpp src/RE/V/VirtualMachine.cpp src/RE/Z/ZeroFunctionArguments.cpp - src/REL/Relocation.cpp + src/REL/ID.cpp + src/REL/Module.cpp src/SKSE/API.cpp src/SKSE/IAT.cpp src/SKSE/Impl/PCH.cpp diff --git a/include/REL/ID.h b/include/REL/ID.h new file mode 100644 index 000000000..09d5f25ee --- /dev/null +++ b/include/REL/ID.h @@ -0,0 +1,374 @@ +#pragma once + +#include "REL/Module.h" + +namespace REL +{ + namespace detail + { + class memory_map + { + public: + memory_map() noexcept = default; + memory_map(const memory_map&) = delete; + + memory_map(memory_map&& a_rhs) noexcept : + _mapping(a_rhs._mapping), + _view(a_rhs._view) + { + a_rhs._mapping = nullptr; + a_rhs._view = nullptr; + } + + ~memory_map() { close(); } + + memory_map& operator=(const memory_map&) = delete; + + memory_map& operator=(memory_map&& a_rhs) noexcept + { + if (this != std::addressof(a_rhs)) { + _mapping = a_rhs._mapping; + a_rhs._mapping = nullptr; + + _view = a_rhs._view; + a_rhs._view = nullptr; + } + return *this; + } + + [[nodiscard]] void* data() noexcept { return _view; } + + bool open(stl::zwstring a_name, std::size_t a_size); + bool create(stl::zwstring a_name, std::size_t a_size); + void close(); + + private: + void* _mapping{ nullptr }; + void* _view{ nullptr }; + }; + } + + class IDDatabase + { + private: + struct mapping_t + { + std::uint64_t id; + std::uint64_t offset; + }; + + public: + class Offset2ID + { + public: + using value_type = mapping_t; + using container_type = std::vector; + using size_type = typename container_type::size_type; + using const_iterator = typename container_type::const_iterator; + using const_reverse_iterator = typename container_type::const_reverse_iterator; + + template + explicit Offset2ID(ExecutionPolicy&& a_policy) // + requires(std::is_execution_policy_v>) + { + const std::span id2offset = IDDatabase::get()._id2offset; + _offset2id.reserve(id2offset.size()); + _offset2id.insert(_offset2id.begin(), id2offset.begin(), id2offset.end()); + std::sort(a_policy, _offset2id.begin(), _offset2id.end(), [](auto&& a_lhs, auto&& a_rhs) { + return a_lhs.offset < a_rhs.offset; + }); + } + + Offset2ID() : + Offset2ID(std::execution::sequenced_policy{}) + {} + + [[nodiscard]] std::uint64_t operator()(std::size_t a_offset) const + { + const mapping_t elem{ 0, a_offset }; + const auto it = std::lower_bound( + _offset2id.begin(), + _offset2id.end(), + elem, + [](auto&& a_lhs, auto&& a_rhs) { + return a_lhs.offset < a_rhs.offset; + }); + if (it == _offset2id.end()) { + stl::report_and_fail( + std::format( + "Failed to find the offset within the database: 0x{:08X}"sv, + a_offset)); + } + + return it->id; + } + + [[nodiscard]] const_iterator begin() const noexcept { return _offset2id.begin(); } + [[nodiscard]] const_iterator cbegin() const noexcept { return _offset2id.cbegin(); } + + [[nodiscard]] const_iterator end() const noexcept { return _offset2id.end(); } + [[nodiscard]] const_iterator cend() const noexcept { return _offset2id.cend(); } + + [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return _offset2id.rbegin(); } + [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return _offset2id.crbegin(); } + + [[nodiscard]] const_reverse_iterator rend() const noexcept { return _offset2id.rend(); } + [[nodiscard]] const_reverse_iterator crend() const noexcept { return _offset2id.crend(); } + + [[nodiscard]] size_type size() const noexcept { return _offset2id.size(); } + + private: + container_type _offset2id; + }; + + [[nodiscard]] static IDDatabase& get() + { + static IDDatabase singleton; + return singleton; + } + + [[nodiscard]] inline std::size_t id2offset(std::uint64_t a_id) const + { + mapping_t elem{ a_id, 0 }; + const auto it = std::lower_bound( + _id2offset.begin(), + _id2offset.end(), + elem, + [](auto&& a_lhs, auto&& a_rhs) { + return a_lhs.id < a_rhs.id; + }); + if (it == _id2offset.end()) { + stl::report_and_fail( + std::format( + "Failed to find the id within the address library: {}\n" + "This means this script extender plugin is incompatible with the address " + "library for this version of the game, and thus does not support it."sv, + a_id)); + } + + return static_cast(it->offset); + } + + private: + friend Offset2ID; + + class header_t + { + public: + void read(binary_io::file_istream& a_in) + { + const auto [format] = a_in.read(); +#ifdef SKYRIM_SUPPORT_AE + if (format != 2) { +#else + if (format != 1) { +#endif + stl::report_and_fail( + std::format( + "Unsupported address library format: {}\n" + "This means this script extender plugin is incompatible with the address " + "library available for this version of the game, and thus does not " + "support it."sv, + format)); + } + + const auto [major, minor, patch, revision] = + a_in.read(); + _version[0] = static_cast(major); + _version[1] = static_cast(minor); + _version[2] = static_cast(patch); + _version[3] = static_cast(revision); + + const auto [nameLen] = a_in.read(); + a_in.seek_relative(nameLen); + + a_in.read(_pointerSize, _addressCount); + } + + [[nodiscard]] std::size_t address_count() const noexcept { return static_cast(_addressCount); } + [[nodiscard]] std::uint64_t pointer_size() const noexcept { return static_cast(_pointerSize); } + [[nodiscard]] Version version() const noexcept { return _version; } + + private: + Version _version; + std::int32_t _pointerSize{ 0 }; + std::int32_t _addressCount{ 0 }; + }; + + IDDatabase() { load(); } + + IDDatabase(const IDDatabase&) = delete; + IDDatabase(IDDatabase&&) = delete; + + ~IDDatabase() = default; + + IDDatabase& operator=(const IDDatabase&) = delete; + IDDatabase& operator=(IDDatabase&&) = delete; + + void load() + { + const auto version = Module::get().version(); + const auto filename = + stl::utf8_to_utf16( + std::format( +#ifdef SKYRIM_SUPPORT_AE + "Data/SKSE/Plugins/versionlib-{}.bin"sv, +#else + "Data/SKSE/Plugins/version-{}.bin"sv, +#endif + version.string())) + .value_or(L""s); + load_file(filename, version); + } + + void load_file(stl::zwstring a_filename, Version a_version) + { + try { + binary_io::file_istream in(a_filename); + header_t header; + header.read(in); + if (header.version() != a_version) { + stl::report_and_fail("version mismatch"sv); + } + + auto mapname = L"CommonLibSSEOffsets-v2-"s; + mapname += a_version.wstring(); + const auto byteSize = static_cast(header.address_count()) * sizeof(mapping_t); + if (_mmap.open(mapname, byteSize)) { + _id2offset = { static_cast(_mmap.data()), header.address_count() }; + } else if (_mmap.create(mapname, byteSize)) { + _id2offset = { static_cast(_mmap.data()), header.address_count() }; + unpack_file(in, header); + std::sort( + _id2offset.begin(), + _id2offset.end(), + [](auto&& a_lhs, auto&& a_rhs) { + return a_lhs.id < a_rhs.id; + }); + } else { + stl::report_and_fail("failed to create shared mapping"sv); + } + } catch (const std::system_error&) { + stl::report_and_fail( + std::format( + "Failed to locate an appropriate address library with the path: {}\n" + "This means you are missing the address library for this specific version of " + "the game. Please continue to the mod page for address library to download " + "an appropriate version. If one is not available, then it is likely that " + "address library has not yet added support for this version of the game."sv, + stl::utf16_to_utf8(a_filename).value_or(""s))); + } + } + + void unpack_file(binary_io::file_istream& a_in, header_t a_header) + { + std::uint8_t type = 0; + std::uint64_t id = 0; + std::uint64_t offset = 0; + std::uint64_t prevID = 0; + std::uint64_t prevOffset = 0; + for (auto& mapping : _id2offset) { + a_in.read(type); + const auto lo = static_cast(type & 0xF); + const auto hi = static_cast(type >> 4); + + switch (lo) { + case 0: + a_in.read(id); + break; + case 1: + id = prevID + 1; + break; + case 2: + id = prevID + std::get<0>(a_in.read()); + break; + case 3: + id = prevID - std::get<0>(a_in.read()); + break; + case 4: + id = prevID + std::get<0>(a_in.read()); + break; + case 5: + id = prevID - std::get<0>(a_in.read()); + break; + case 6: + std::tie(id) = a_in.read(); + break; + case 7: + std::tie(id) = a_in.read(); + break; + default: + stl::report_and_fail("unhandled type"sv); + } + + const std::uint64_t tmp = (hi & 8) != 0 ? (prevOffset / a_header.pointer_size()) : prevOffset; + + switch (hi & 7) { + case 0: + a_in.read(offset); + break; + case 1: + offset = tmp + 1; + break; + case 2: + offset = tmp + std::get<0>(a_in.read()); + break; + case 3: + offset = tmp - std::get<0>(a_in.read()); + break; + case 4: + offset = tmp + std::get<0>(a_in.read()); + break; + case 5: + offset = tmp - std::get<0>(a_in.read()); + break; + case 6: + std::tie(offset) = a_in.read(); + break; + case 7: + std::tie(offset) = a_in.read(); + break; + default: + stl::report_and_fail("unhandled type"sv); + } + + if ((hi & 8) != 0) { + offset *= a_header.pointer_size(); + } + + mapping = { id, offset }; + + prevOffset = offset; + prevID = id; + } + } + + detail::memory_map _mmap; + std::span _id2offset; + }; + + class ID + { + public: + constexpr ID() noexcept = default; + + explicit constexpr ID(std::uint64_t a_id) noexcept : + _id(a_id) + {} + + constexpr ID& operator=(std::uint64_t a_id) noexcept + { + _id = a_id; + return *this; + } + + [[nodiscard]] std::uintptr_t address() const { return base() + offset(); } + [[nodiscard]] constexpr std::uint64_t id() const noexcept { return _id; } + [[nodiscard]] std::size_t offset() const { return IDDatabase::get().id2offset(_id); } + + private: + [[nodiscard]] static std::uintptr_t base() { return Module::get().base(); } + + std::uint64_t _id{ 0 }; + }; +} diff --git a/include/REL/Module.h b/include/REL/Module.h new file mode 100644 index 000000000..07f465e40 --- /dev/null +++ b/include/REL/Module.h @@ -0,0 +1,151 @@ +#pragma once + +#include "REL/Version.h" + +namespace REL +{ + class Segment + { + public: + enum Name : std::size_t + { + textx, + idata, + rdata, + data, + pdata, + tls, + textw, + gfids, + total + }; + + Segment() noexcept = default; + + Segment(std::uintptr_t a_proxyBase, std::uintptr_t a_address, std::uintptr_t a_size) noexcept : + _proxyBase(a_proxyBase), + _address(a_address), + _size(a_size) + {} + + [[nodiscard]] std::uintptr_t address() const noexcept { return _address; } + [[nodiscard]] std::size_t offset() const noexcept { return address() - _proxyBase; } + [[nodiscard]] std::size_t size() const noexcept { return _size; } + + [[nodiscard]] void* pointer() const noexcept { return reinterpret_cast(address()); } + + template + [[nodiscard]] T* pointer() const noexcept + { + return static_cast(pointer()); + } + + private: + std::uintptr_t _proxyBase{ 0 }; + std::uintptr_t _address{ 0 }; + std::size_t _size{ 0 }; + }; + + class Module + { + public: + [[nodiscard]] static Module& get() + { + static Module singleton; + return singleton; + } + + [[nodiscard]] std::uintptr_t base() const noexcept { return _base; } + [[nodiscard]] stl::zwstring filename() const noexcept { return _filename; } + [[nodiscard]] Version version() const noexcept { return _version; } + + [[nodiscard]] Segment segment(Segment::Name a_segment) const noexcept { return _segments[a_segment]; } + + [[nodiscard]] void* pointer() const noexcept { return reinterpret_cast(base()); } + + template + [[nodiscard]] T* pointer() const noexcept + { + return static_cast(pointer()); + } + + private: + Module() + { + const auto getFilename = [&]() { + return WinAPI::GetEnvironmentVariable( + ENVIRONMENT.data(), + _filename.data(), + static_cast(_filename.size())); + }; + + _filename.resize(getFilename()); + if (const auto result = getFilename(); + result != _filename.size() - 1 || + result == 0) { + _filename = L"SkyrimSE.exe"sv; + } + + load(); + } + + Module(const Module&) = delete; + Module(Module&&) = delete; + + ~Module() noexcept = default; + + Module& operator=(const Module&) = delete; + Module& operator=(Module&&) = delete; + + void load() + { + auto handle = WinAPI::GetModuleHandle(_filename.c_str()); + if (handle == nullptr) { + stl::report_and_fail( + std::format( + "Failed to obtain module handle for: \"{0}\".\n" + "You have likely renamed the executable to something unexpected. " + "Renaming the executable back to \"{0}\" may resolve the issue."sv, + stl::utf16_to_utf8(_filename).value_or(""s))); + } + _base = reinterpret_cast(handle); + + load_version(); + load_segments(); + } + + void load_segments(); + + void load_version() + { + const auto version = get_file_version(_filename); + if (version) { + _version = *version; + } else { + stl::report_and_fail( + std::format( + "Failed to obtain file version info for: {}\n" + "Please contact the author of this script extender plugin for further assistance."sv, + stl::utf16_to_utf8(_filename).value_or(""s))); + } + } + + static constexpr std::array SEGMENTS{ + std::make_pair(".text"sv, WinAPI::IMAGE_SCN_MEM_EXECUTE), + std::make_pair(".idata"sv, 0u), + std::make_pair(".rdata"sv, 0u), + std::make_pair(".data"sv, 0u), + std::make_pair(".pdata"sv, 0u), + std::make_pair(".tls"sv, 0u), + std::make_pair(".text"sv, WinAPI::IMAGE_SCN_MEM_WRITE), + std::make_pair(".gfids"sv, 0u) + }; + + static constexpr auto ENVIRONMENT = L"SKSE_RUNTIME"sv; + + std::wstring _filename; + std::array _segments; + Version _version; + std::uintptr_t _base{ 0 }; + }; +} diff --git a/include/REL/Offset.h b/include/REL/Offset.h new file mode 100644 index 000000000..6ed58b82d --- /dev/null +++ b/include/REL/Offset.h @@ -0,0 +1,30 @@ +#pragma once + +#include "REL/Module.h" + +namespace REL +{ + class Offset + { + public: + constexpr Offset() noexcept = default; + + explicit constexpr Offset(std::size_t a_offset) noexcept : + _offset(a_offset) + {} + + constexpr Offset& operator=(std::size_t a_offset) noexcept + { + _offset = a_offset; + return *this; + } + + [[nodiscard]] std::uintptr_t address() const { return base() + offset(); } + [[nodiscard]] constexpr std::size_t offset() const noexcept { return _offset; } + + private: + [[nodiscard]] static std::uintptr_t base() { return Module::get().base(); } + + std::size_t _offset{ 0 }; + }; +} diff --git a/include/REL/Pattern.h b/include/REL/Pattern.h new file mode 100644 index 000000000..a23631940 --- /dev/null +++ b/include/REL/Pattern.h @@ -0,0 +1,189 @@ +#pragma once + +#include "REL/Module.h" + +namespace REL +{ + namespace detail + { + namespace characters + { + [[nodiscard]] constexpr bool hexadecimal(char a_ch) noexcept + { + return ('0' <= a_ch && a_ch <= '9') || + ('A' <= a_ch && a_ch <= 'F') || + ('a' <= a_ch && a_ch <= 'f'); + } + + [[nodiscard]] constexpr bool space(char a_ch) noexcept + { + return a_ch == ' '; + } + + [[nodiscard]] constexpr bool wildcard(char a_ch) noexcept + { + return a_ch == '?'; + } + } + + namespace rules + { + namespace detail + { + [[nodiscard]] consteval std::byte hexacharacters_to_hexadecimal(char a_hi, char a_lo) noexcept + { + constexpr auto lut = []() noexcept { + std::array::max() + 1> a = {}; + + const auto iterate = [&](std::uint8_t a_iFirst, unsigned char a_cFirst, unsigned char a_cLast) noexcept { + for (; a_cFirst <= a_cLast; ++a_cFirst, ++a_iFirst) { + a[a_cFirst] = a_iFirst; + } + }; + + iterate(0, '0', '9'); + iterate(0xA, 'A', 'F'); + iterate(0xa, 'a', 'f'); + + return a; + }(); + + return static_cast( + lut[static_cast(a_hi)] * 0x10u + + lut[static_cast(a_lo)]); + } + } + + template + class Hexadecimal + { + public: + [[nodiscard]] static constexpr bool match(std::byte a_byte) noexcept + { + constexpr auto expected = detail::hexacharacters_to_hexadecimal(HI, LO); + return a_byte == expected; + } + }; + + static_assert(Hexadecimal<'5', '7'>::match(std::byte{ 0x57 })); + static_assert(Hexadecimal<'6', '5'>::match(std::byte{ 0x65 })); + static_assert(Hexadecimal<'B', 'D'>::match(std::byte{ 0xBD })); + static_assert(Hexadecimal<'1', 'C'>::match(std::byte{ 0x1C })); + static_assert(Hexadecimal<'F', '2'>::match(std::byte{ 0xF2 })); + static_assert(Hexadecimal<'9', 'f'>::match(std::byte{ 0x9f })); + + static_assert(!Hexadecimal<'D', '4'>::match(std::byte{ 0xF8 })); + static_assert(!Hexadecimal<'6', '7'>::match(std::byte{ 0xAA })); + static_assert(!Hexadecimal<'7', '8'>::match(std::byte{ 0xE3 })); + static_assert(!Hexadecimal<'6', 'E'>::match(std::byte{ 0x61 })); + + class Wildcard + { + public: + [[nodiscard]] static constexpr bool match(std::byte) noexcept + { + return true; + } + }; + + static_assert(Wildcard::match(std::byte{ 0xB9 })); + static_assert(Wildcard::match(std::byte{ 0x96 })); + static_assert(Wildcard::match(std::byte{ 0x35 })); + static_assert(Wildcard::match(std::byte{ 0xE4 })); + + template + void rule_for() noexcept; + + template + Hexadecimal rule_for() noexcept + requires(characters::hexadecimal(C1) && characters::hexadecimal(C2)); + + template + Wildcard rule_for() noexcept + requires(characters::wildcard(C1) && characters::wildcard(C2)); + } + + template + class PatternMatcher + { + public: + static_assert(sizeof...(Rules) >= 1, "must provide at least 1 rule for the pattern matcher"); + + [[nodiscard]] constexpr bool match(std::span a_bytes) const noexcept + { + std::size_t i = 0; + return (Rules::match(a_bytes[i++]) && ...); + } + + [[nodiscard]] bool match(std::uintptr_t a_address) const noexcept + { + return this->match(*reinterpret_cast(a_address)); + } + + void match_or_fail(std::uintptr_t a_address, std::source_location a_loc = std::source_location::current()) const noexcept + { + if (!this->match(a_address)) { + const auto version = Module::get().version(); + stl::report_and_fail( + std::format( + "A pattern has failed to match.\n" + "This means the plugin is incompatible with the current version of the game ({}.{}.{}). " + "Head to the mod page of this plugin to see if an update is available."sv, + version[0], + version[1], + version[2]), + a_loc); + } + } + }; + + void consteval_error(const char* a_error); + + template + [[nodiscard]] constexpr auto do_make_pattern() noexcept + { + if constexpr (S.length() == 0) { + return PatternMatcher(); + } else if constexpr (S.length() == 1) { + constexpr char c = S[0]; + if constexpr (characters::hexadecimal(c) || characters::wildcard(c)) { + consteval_error("the given pattern has an unpaired rule (rules are required to be written in pairs of 2)"); + } else { + consteval_error("the given pattern has trailing characters at the end (which is not allowed)"); + } + } else { + using rule_t = decltype(rules::rule_for()); + if constexpr (std::same_as) { + consteval_error("the given pattern failed to match any known rules"); + } else { + if constexpr (S.length() <= 3) { + return do_make_pattern(), Rules..., rule_t>(); + } else if constexpr (characters::space(S[2])) { + return do_make_pattern(), Rules..., rule_t>(); + } else { + consteval_error("a space character is required to split byte patterns"); + } + } + } + } + + template + [[nodiscard]] consteval auto make_byte_array(Bytes... a_bytes) noexcept + -> std::array + { + static_assert((std::integral && ...), "all bytes must be an integral type"); + return { static_cast(a_bytes)... }; + } + } + + template + [[nodiscard]] constexpr auto make_pattern() noexcept + { + return detail::do_make_pattern(); + } + + static_assert(make_pattern<"40 10 F2 ??">().match( + detail::make_byte_array(0x40, 0x10, 0xF2, 0x41))); + static_assert(make_pattern<"B8 D0 ?? ?? D4 6E">().match( + detail::make_byte_array(0xB8, 0xD0, 0x35, 0x2A, 0xD4, 0x6E))); +} diff --git a/include/REL/REL.h b/include/REL/REL.h new file mode 100644 index 000000000..0fab8ad1f --- /dev/null +++ b/include/REL/REL.h @@ -0,0 +1,8 @@ +#pragma once + +#include "REL/ID.h" +#include "REL/Module.h" +#include "REL/Offset.h" +#include "REL/Pattern.h" +#include "REL/Relocation.h" +#include "REL/Version.h" diff --git a/include/REL/Relocation.h b/include/REL/Relocation.h index b71423f5e..b8edfe732 100644 --- a/include/REL/Relocation.h +++ b/include/REL/Relocation.h @@ -60,47 +60,6 @@ namespace REL { namespace detail { - class memory_map - { - public: - memory_map() noexcept = default; - memory_map(const memory_map&) = delete; - - memory_map(memory_map&& a_rhs) noexcept : - _mapping(a_rhs._mapping), - _view(a_rhs._view) - { - a_rhs._mapping = nullptr; - a_rhs._view = nullptr; - } - - ~memory_map() { close(); } - - memory_map& operator=(const memory_map&) = delete; - - memory_map& operator=(memory_map&& a_rhs) noexcept - { - if (this != std::addressof(a_rhs)) { - _mapping = a_rhs._mapping; - a_rhs._mapping = nullptr; - - _view = a_rhs._view; - a_rhs._view = nullptr; - } - return *this; - } - - [[nodiscard]] void* data() noexcept { return _view; } - - bool open(stl::zwstring a_name, std::size_t a_size); - bool create(stl::zwstring a_name, std::size_t a_size); - void close(); - - private: - void* _mapping{ nullptr }; - void* _view{ nullptr }; - }; - template struct member_function_pod_type; @@ -282,605 +241,6 @@ namespace REL assert(success != 0); } - class Version - { - public: - using value_type = std::uint16_t; - using reference = value_type&; - using const_reference = const value_type&; - - constexpr Version() noexcept = default; - - explicit constexpr Version(std::array a_version) noexcept : - _impl(a_version) - {} - - constexpr Version(value_type a_v1, value_type a_v2 = 0, value_type a_v3 = 0, value_type a_v4 = 0) noexcept : - _impl{ a_v1, a_v2, a_v3, a_v4 } - {} - - [[nodiscard]] constexpr reference operator[](std::size_t a_idx) noexcept { return _impl[a_idx]; } - [[nodiscard]] constexpr const_reference operator[](std::size_t a_idx) const noexcept { return _impl[a_idx]; } - - [[nodiscard]] constexpr decltype(auto) begin() const noexcept { return _impl.begin(); } - [[nodiscard]] constexpr decltype(auto) cbegin() const noexcept { return _impl.cbegin(); } - [[nodiscard]] constexpr decltype(auto) end() const noexcept { return _impl.end(); } - [[nodiscard]] constexpr decltype(auto) cend() const noexcept { return _impl.cend(); } - - [[nodiscard]] std::strong_ordering constexpr compare(const Version& a_rhs) const noexcept - { - for (std::size_t i = 0; i < _impl.size(); ++i) { - if ((*this)[i] != a_rhs[i]) { - return (*this)[i] < a_rhs[i] ? std::strong_ordering::less : std::strong_ordering::greater; - } - } - return std::strong_ordering::equal; - } - - [[nodiscard]] constexpr std::uint32_t pack() const noexcept - { - return static_cast( - (_impl[0] & 0x0FF) << 24u | - (_impl[1] & 0x0FF) << 16u | - (_impl[2] & 0xFFF) << 4u | - (_impl[3] & 0x00F) << 0u); - } - - [[nodiscard]] std::string string() const - { - std::string result; - for (auto&& ver : _impl) { - result += std::to_string(ver); - result += '-'; - } - result.pop_back(); - return result; - } - - [[nodiscard]] std::wstring wstring() const - { - std::wstring result; - for (auto&& ver : _impl) { - result += std::to_wstring(ver); - result += L'-'; - } - result.pop_back(); - return result; - } - - private: - std::array _impl{ 0, 0, 0, 0 }; - }; - - [[nodiscard]] constexpr bool operator==(const Version& a_lhs, const Version& a_rhs) noexcept { return a_lhs.compare(a_rhs) == 0; } - [[nodiscard]] constexpr std::strong_ordering operator<=>(const Version& a_lhs, const Version& a_rhs) noexcept { return a_lhs.compare(a_rhs); } - - [[nodiscard]] inline std::optional get_file_version(stl::zwstring a_filename) - { - std::uint32_t dummy; - std::vector buf(WinAPI::GetFileVersionInfoSize(a_filename.data(), std::addressof(dummy))); - if (buf.empty()) { - return std::nullopt; - } - - if (!WinAPI::GetFileVersionInfo(a_filename.data(), 0, static_cast(buf.size()), buf.data())) { - return std::nullopt; - } - - void* verBuf{ nullptr }; - std::uint32_t verLen{ 0 }; - if (!WinAPI::VerQueryValue(buf.data(), L"\\StringFileInfo\\040904B0\\ProductVersion", std::addressof(verBuf), std::addressof(verLen))) { - return std::nullopt; - } - - Version version; - std::wistringstream ss( - std::wstring(static_cast(verBuf), verLen)); - std::wstring token; - for (std::size_t i = 0; i < 4 && std::getline(ss, token, L'.'); ++i) { - version[i] = static_cast(std::stoi(token)); - } - - return version; - } - - class Segment - { - public: - enum Name : std::size_t - { - textx, - idata, - rdata, - data, - pdata, - tls, - textw, - gfids, - total - }; - - Segment() noexcept = default; - - Segment(std::uintptr_t a_proxyBase, std::uintptr_t a_address, std::uintptr_t a_size) noexcept : - _proxyBase(a_proxyBase), - _address(a_address), - _size(a_size) - {} - - [[nodiscard]] std::uintptr_t address() const noexcept { return _address; } - [[nodiscard]] std::size_t offset() const noexcept { return address() - _proxyBase; } - [[nodiscard]] std::size_t size() const noexcept { return _size; } - - [[nodiscard]] void* pointer() const noexcept { return reinterpret_cast(address()); } - - template - [[nodiscard]] T* pointer() const noexcept - { - return static_cast(pointer()); - } - - private: - std::uintptr_t _proxyBase{ 0 }; - std::uintptr_t _address{ 0 }; - std::size_t _size{ 0 }; - }; - - class Module - { - public: - [[nodiscard]] static Module& get() - { - static Module singleton; - return singleton; - } - - [[nodiscard]] std::uintptr_t base() const noexcept { return _base; } - [[nodiscard]] stl::zwstring filename() const noexcept { return _filename; } - [[nodiscard]] Version version() const noexcept { return _version; } - - [[nodiscard]] Segment segment(Segment::Name a_segment) const noexcept { return _segments[a_segment]; } - - [[nodiscard]] void* pointer() const noexcept { return reinterpret_cast(base()); } - - template - [[nodiscard]] T* pointer() const noexcept - { - return static_cast(pointer()); - } - - private: - Module() - { - const auto getFilename = [&]() { - return WinAPI::GetEnvironmentVariable( - ENVIRONMENT.data(), - _filename.data(), - static_cast(_filename.size())); - }; - - _filename.resize(getFilename()); - if (const auto result = getFilename(); - result != _filename.size() - 1 || - result == 0) { - _filename = L"SkyrimSE.exe"sv; - } - - load(); - } - - Module(const Module&) = delete; - Module(Module&&) = delete; - - ~Module() noexcept = default; - - Module& operator=(const Module&) = delete; - Module& operator=(Module&&) = delete; - - void load() - { - auto handle = WinAPI::GetModuleHandle(_filename.c_str()); - if (handle == nullptr) { - stl::report_and_fail( - std::format( - "Failed to obtain module handle for: \"{0}\".\n" - "You have likely renamed the executable to something unexpected. " - "Renaming the executable back to \"{0}\" may resolve the issue."sv, - stl::utf16_to_utf8(_filename).value_or(""s))); - } - _base = reinterpret_cast(handle); - - load_version(); - load_segments(); - } - - void load_segments(); - - void load_version() - { - const auto version = get_file_version(_filename); - if (version) { - _version = *version; - } else { - stl::report_and_fail( - std::format( - "Failed to obtain file version info for: {}\n" - "Please contact the author of this script extender plugin for further assistance."sv, - stl::utf16_to_utf8(_filename).value_or(""s))); - } - } - - static constexpr std::array SEGMENTS{ - std::make_pair(".text"sv, WinAPI::IMAGE_SCN_MEM_EXECUTE), - std::make_pair(".idata"sv, static_cast(0)), - std::make_pair(".rdata"sv, static_cast(0)), - std::make_pair(".data"sv, static_cast(0)), - std::make_pair(".pdata"sv, static_cast(0)), - std::make_pair(".tls"sv, static_cast(0)), - std::make_pair(".text"sv, WinAPI::IMAGE_SCN_MEM_WRITE), - std::make_pair(".gfids"sv, static_cast(0)) - }; - - static constexpr auto ENVIRONMENT = L"SKSE_RUNTIME"sv; - - std::wstring _filename; - std::array _segments; - Version _version; - std::uintptr_t _base{ 0 }; - }; - - class IDDatabase - { - private: - struct mapping_t - { - std::uint64_t id; - std::uint64_t offset; - }; - - public: - class Offset2ID - { - public: - using value_type = mapping_t; - using container_type = std::vector; - using size_type = typename container_type::size_type; - using const_iterator = typename container_type::const_iterator; - using const_reverse_iterator = typename container_type::const_reverse_iterator; - - template - explicit Offset2ID(ExecutionPolicy&& a_policy) // - requires(std::is_execution_policy_v>) - { - const std::span id2offset = IDDatabase::get()._id2offset; - _offset2id.reserve(id2offset.size()); - _offset2id.insert(_offset2id.begin(), id2offset.begin(), id2offset.end()); - std::sort( - a_policy, - _offset2id.begin(), - _offset2id.end(), - [](auto&& a_lhs, auto&& a_rhs) { - return a_lhs.offset < a_rhs.offset; - }); - } - - Offset2ID() : - Offset2ID(std::execution::sequenced_policy{}) - {} - - [[nodiscard]] std::uint64_t operator()(std::size_t a_offset) const - { - const mapping_t elem{ 0, a_offset }; - const auto it = std::lower_bound( - _offset2id.begin(), - _offset2id.end(), - elem, - [](auto&& a_lhs, auto&& a_rhs) { - return a_lhs.offset < a_rhs.offset; - }); - if (it == _offset2id.end()) { - stl::report_and_fail( - std::format( - "Failed to find the offset within the database: 0x{:08X}"sv, - a_offset)); - } - - return it->id; - } - - [[nodiscard]] const_iterator begin() const noexcept { return _offset2id.begin(); } - [[nodiscard]] const_iterator cbegin() const noexcept { return _offset2id.cbegin(); } - - [[nodiscard]] const_iterator end() const noexcept { return _offset2id.end(); } - [[nodiscard]] const_iterator cend() const noexcept { return _offset2id.cend(); } - - [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return _offset2id.rbegin(); } - [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return _offset2id.crbegin(); } - - [[nodiscard]] const_reverse_iterator rend() const noexcept { return _offset2id.rend(); } - [[nodiscard]] const_reverse_iterator crend() const noexcept { return _offset2id.crend(); } - - [[nodiscard]] size_type size() const noexcept { return _offset2id.size(); } - - private: - container_type _offset2id; - }; - - [[nodiscard]] static IDDatabase& get() - { - static IDDatabase singleton; - return singleton; - } - - [[nodiscard]] inline std::size_t id2offset(std::uint64_t a_id) const - { - mapping_t elem{ a_id, 0 }; - const auto it = std::lower_bound( - _id2offset.begin(), - _id2offset.end(), - elem, - [](auto&& a_lhs, auto&& a_rhs) { - return a_lhs.id < a_rhs.id; - }); - if (it == _id2offset.end()) { - stl::report_and_fail( - std::format( - "Failed to find the id within the address library: {}\n" - "This means this script extender plugin is incompatible with the address " - "library for this version of the game, and thus does not support it."sv, - a_id)); - } - - return static_cast(it->offset); - } - - private: - friend Offset2ID; - - class header_t - { - public: - void read(binary_io::file_istream& a_in) - { - const auto [format] = a_in.read(); -#ifdef SKYRIM_SUPPORT_AE - if (format != 2) { -#else - if (format != 1) { -#endif - stl::report_and_fail( - std::format( - "Unsupported address library format: {}\n" - "This means this script extender plugin is incompatible with the address " - "library available for this version of the game, and thus does not " - "support it."sv, - format)); - } - - const auto [major, minor, patch, revision] = - a_in.read(); - _version[0] = static_cast(major); - _version[1] = static_cast(minor); - _version[2] = static_cast(patch); - _version[3] = static_cast(revision); - - const auto [nameLen] = a_in.read(); - a_in.seek_relative(nameLen); - - a_in.read(_pointerSize, _addressCount); - } - - [[nodiscard]] std::size_t address_count() const noexcept { return static_cast(_addressCount); } - [[nodiscard]] std::uint64_t pointer_size() const noexcept { return static_cast(_pointerSize); } - [[nodiscard]] Version version() const noexcept { return _version; } - - private: - Version _version; - std::int32_t _pointerSize{ 0 }; - std::int32_t _addressCount{ 0 }; - }; - - IDDatabase() { load(); } - - IDDatabase(const IDDatabase&) = delete; - IDDatabase(IDDatabase&&) = delete; - - ~IDDatabase() = default; - - IDDatabase& operator=(const IDDatabase&) = delete; - IDDatabase& operator=(IDDatabase&&) = delete; - - void load() - { - const auto version = Module::get().version(); - const auto filename = - stl::utf8_to_utf16( - std::format( -#ifdef SKYRIM_SUPPORT_AE - "Data/SKSE/Plugins/versionlib-{}.bin"sv, -#else - "Data/SKSE/Plugins/version-{}.bin"sv, -#endif - version.string())) - .value_or(L""s); - load_file(filename, version); - } - - void load_file(stl::zwstring a_filename, Version a_version) - { - try { - binary_io::file_istream in(a_filename); - header_t header; - header.read(in); - if (header.version() != a_version) { - stl::report_and_fail("version mismatch"sv); - } - - auto mapname = L"CommonLibSSEOffsets-v2-"s; - mapname += a_version.wstring(); - const auto byteSize = static_cast(header.address_count()) * sizeof(mapping_t); - if (_mmap.open(mapname, byteSize)) { - _id2offset = { static_cast(_mmap.data()), header.address_count() }; - } else if (_mmap.create(mapname, byteSize)) { - _id2offset = { static_cast(_mmap.data()), header.address_count() }; - unpack_file(in, header); - std::sort( - _id2offset.begin(), - _id2offset.end(), - [](auto&& a_lhs, auto&& a_rhs) { - return a_lhs.id < a_rhs.id; - }); - } else { - stl::report_and_fail("failed to create shared mapping"sv); - } - } catch (const std::system_error&) { - stl::report_and_fail( - std::format( - "Failed to locate an appropriate address library with the path: {}\n" - "This means you are missing the address library for this specific version of " - "the game. Please continue to the mod page for address library to download " - "an appropriate version. If one is not available, then it is likely that " - "address library has not yet added support for this version of the game."sv, - stl::utf16_to_utf8(a_filename).value_or(""s))); - } - } - - void unpack_file(binary_io::file_istream& a_in, header_t a_header) - { - std::uint8_t type = 0; - std::uint64_t id = 0; - std::uint64_t offset = 0; - std::uint64_t prevID = 0; - std::uint64_t prevOffset = 0; - for (auto& mapping : _id2offset) { - a_in.read(type); - const auto lo = static_cast(type & 0xF); - const auto hi = static_cast(type >> 4); - - switch (lo) { - case 0: - a_in.read(id); - break; - case 1: - id = prevID + 1; - break; - case 2: - id = prevID + std::get<0>(a_in.read()); - break; - case 3: - id = prevID - std::get<0>(a_in.read()); - break; - case 4: - id = prevID + std::get<0>(a_in.read()); - break; - case 5: - id = prevID - std::get<0>(a_in.read()); - break; - case 6: - std::tie(id) = a_in.read(); - break; - case 7: - std::tie(id) = a_in.read(); - break; - default: - stl::report_and_fail("unhandled type"sv); - } - - const std::uint64_t tmp = (hi & 8) != 0 ? (prevOffset / a_header.pointer_size()) : prevOffset; - - switch (hi & 7) { - case 0: - a_in.read(offset); - break; - case 1: - offset = tmp + 1; - break; - case 2: - offset = tmp + std::get<0>(a_in.read()); - break; - case 3: - offset = tmp - std::get<0>(a_in.read()); - break; - case 4: - offset = tmp + std::get<0>(a_in.read()); - break; - case 5: - offset = tmp - std::get<0>(a_in.read()); - break; - case 6: - std::tie(offset) = a_in.read(); - break; - case 7: - std::tie(offset) = a_in.read(); - break; - default: - stl::report_and_fail("unhandled type"sv); - } - - if ((hi & 8) != 0) { - offset *= a_header.pointer_size(); - } - - mapping = { id, offset }; - - prevOffset = offset; - prevID = id; - } - } - - detail::memory_map _mmap; - std::span _id2offset; - }; - - class Offset - { - public: - constexpr Offset() noexcept = default; - - explicit constexpr Offset(std::size_t a_offset) noexcept : - _offset(a_offset) - {} - - constexpr Offset& operator=(std::size_t a_offset) noexcept - { - _offset = a_offset; - return *this; - } - - [[nodiscard]] std::uintptr_t address() const { return base() + offset(); } - [[nodiscard]] constexpr std::size_t offset() const noexcept { return _offset; } - - private: - [[nodiscard]] static std::uintptr_t base() { return Module::get().base(); } - - std::size_t _offset{ 0 }; - }; - - class ID - { - public: - constexpr ID() noexcept = default; - - explicit constexpr ID(std::uint64_t a_id) noexcept : - _id(a_id) - {} - - constexpr ID& operator=(std::uint64_t a_id) noexcept - { - _id = a_id; - return *this; - } - - [[nodiscard]] std::uintptr_t address() const { return base() + offset(); } - [[nodiscard]] constexpr std::uint64_t id() const noexcept { return _id; } - [[nodiscard]] std::size_t offset() const { return IDDatabase::get().id2offset(_id); } - - private: - [[nodiscard]] static std::uintptr_t base() { return Module::get().base(); } - - std::uint64_t _id{ 0 }; - }; - template class Relocation { @@ -983,189 +343,6 @@ namespace REL std::uintptr_t _impl{ 0 }; }; - - namespace detail - { - namespace characters - { - [[nodiscard]] constexpr bool hexadecimal(char a_ch) noexcept - { - return ('0' <= a_ch && a_ch <= '9') || - ('A' <= a_ch && a_ch <= 'F') || - ('a' <= a_ch && a_ch <= 'f'); - } - - [[nodiscard]] constexpr bool space(char a_ch) noexcept - { - return a_ch == ' '; - } - - [[nodiscard]] constexpr bool wildcard(char a_ch) noexcept - { - return a_ch == '?'; - } - } - - namespace rules - { - namespace detail - { - [[nodiscard]] consteval std::byte hexacharacters_to_hexadecimal(char a_hi, char a_lo) noexcept - { - constexpr auto lut = []() noexcept { - std::array::max() + 1> a = {}; - - const auto iterate = [&](std::uint8_t a_iFirst, unsigned char a_cFirst, unsigned char a_cLast) noexcept { - for (; a_cFirst <= a_cLast; ++a_cFirst, ++a_iFirst) { - a[a_cFirst] = a_iFirst; - } - }; - - iterate(0, '0', '9'); - iterate(0xA, 'A', 'F'); - iterate(0xa, 'a', 'f'); - - return a; - }(); - - return static_cast( - lut[static_cast(a_hi)] * 0x10u + - lut[static_cast(a_lo)]); - } - } - - template - class Hexadecimal - { - public: - [[nodiscard]] static constexpr bool match(std::byte a_byte) noexcept - { - constexpr auto expected = detail::hexacharacters_to_hexadecimal(HI, LO); - return a_byte == expected; - } - }; - - static_assert(Hexadecimal<'5', '7'>::match(std::byte{ 0x57 })); - static_assert(Hexadecimal<'6', '5'>::match(std::byte{ 0x65 })); - static_assert(Hexadecimal<'B', 'D'>::match(std::byte{ 0xBD })); - static_assert(Hexadecimal<'1', 'C'>::match(std::byte{ 0x1C })); - static_assert(Hexadecimal<'F', '2'>::match(std::byte{ 0xF2 })); - static_assert(Hexadecimal<'9', 'f'>::match(std::byte{ 0x9f })); - - static_assert(!Hexadecimal<'D', '4'>::match(std::byte{ 0xF8 })); - static_assert(!Hexadecimal<'6', '7'>::match(std::byte{ 0xAA })); - static_assert(!Hexadecimal<'7', '8'>::match(std::byte{ 0xE3 })); - static_assert(!Hexadecimal<'6', 'E'>::match(std::byte{ 0x61 })); - - class Wildcard - { - public: - [[nodiscard]] static constexpr bool match(std::byte) noexcept - { - return true; - } - }; - - static_assert(Wildcard::match(std::byte{ 0xB9 })); - static_assert(Wildcard::match(std::byte{ 0x96 })); - static_assert(Wildcard::match(std::byte{ 0x35 })); - static_assert(Wildcard::match(std::byte{ 0xE4 })); - - template - void rule_for() noexcept; - - template - Hexadecimal rule_for() noexcept - requires(characters::hexadecimal(C1) && characters::hexadecimal(C2)); - - template - Wildcard rule_for() noexcept - requires(characters::wildcard(C1) && characters::wildcard(C2)); - } - - template - class PatternMatcher - { - public: - static_assert(sizeof...(Rules) >= 1, "must provide at least 1 rule for the pattern matcher"); - - [[nodiscard]] constexpr bool match(std::span a_bytes) const noexcept - { - std::size_t i = 0; - return (Rules::match(a_bytes[i++]) && ...); - } - - [[nodiscard]] bool match(std::uintptr_t a_address) const noexcept - { - return this->match(*reinterpret_cast(a_address)); - } - - void match_or_fail(std::uintptr_t a_address, std::source_location a_loc = std::source_location::current()) const noexcept - { - if (!this->match(a_address)) { - const auto version = Module::get().version(); - stl::report_and_fail( - std::format( - "A pattern has failed to match.\n" - "This means the plugin is incompatible with the current version of the game ({}.{}.{}). " - "Head to the mod page of this plugin to see if an update is available."sv, - version[0], - version[1], - version[2]), - a_loc); - } - } - }; - - void consteval_error(const char* a_error); - - template - [[nodiscard]] constexpr auto do_make_pattern() noexcept - { - if constexpr (S.length() == 0) { - return PatternMatcher(); - } else if constexpr (S.length() == 1) { - constexpr char c = S[0]; - if constexpr (characters::hexadecimal(c) || characters::wildcard(c)) { - consteval_error("the given pattern has an unpaired rule (rules are required to be written in pairs of 2)"); - } else { - consteval_error("the given pattern has trailing characters at the end (which is not allowed)"); - } - } else { - using rule_t = decltype(rules::rule_for()); - if constexpr (std::same_as) { - consteval_error("the given pattern failed to match any known rules"); - } else { - if constexpr (S.length() <= 3) { - return do_make_pattern(), Rules..., rule_t>(); - } else if constexpr (characters::space(S[2])) { - return do_make_pattern(), Rules..., rule_t>(); - } else { - consteval_error("a space character is required to split byte patterns"); - } - } - } - } - - template - [[nodiscard]] consteval auto make_byte_array(Bytes... a_bytes) noexcept - -> std::array - { - static_assert((std::integral && ...), "all bytes must be an integral type"); - return { static_cast(a_bytes)... }; - } - } - - template - [[nodiscard]] constexpr auto make_pattern() noexcept - { - return detail::do_make_pattern(); - } - - static_assert(make_pattern<"40 10 F2 ??">().match( - detail::make_byte_array(0x40, 0x10, 0xF2, 0x41))); - static_assert(make_pattern<"B8 D0 ?? ?? D4 6E">().match( - detail::make_byte_array(0xB8, 0xD0, 0x35, 0x2A, 0xD4, 0x6E))); } #undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE diff --git a/include/REL/Version.h b/include/REL/Version.h new file mode 100644 index 000000000..04b3ffca8 --- /dev/null +++ b/include/REL/Version.h @@ -0,0 +1,105 @@ +#pragma once + +namespace REL +{ + class Version + { + public: + using value_type = std::uint16_t; + using reference = value_type&; + using const_reference = const value_type&; + + constexpr Version() noexcept = default; + + explicit constexpr Version(std::array a_version) noexcept : + _impl(a_version) + {} + + constexpr Version(value_type a_v1, value_type a_v2 = 0, value_type a_v3 = 0, value_type a_v4 = 0) noexcept : + _impl{ a_v1, a_v2, a_v3, a_v4 } + {} + + [[nodiscard]] constexpr reference operator[](std::size_t a_idx) noexcept { return _impl[a_idx]; } + [[nodiscard]] constexpr const_reference operator[](std::size_t a_idx) const noexcept { return _impl[a_idx]; } + + [[nodiscard]] constexpr decltype(auto) begin() const noexcept { return _impl.begin(); } + [[nodiscard]] constexpr decltype(auto) cbegin() const noexcept { return _impl.cbegin(); } + [[nodiscard]] constexpr decltype(auto) end() const noexcept { return _impl.end(); } + [[nodiscard]] constexpr decltype(auto) cend() const noexcept { return _impl.cend(); } + + [[nodiscard]] std::strong_ordering constexpr compare(const Version& a_rhs) const noexcept + { + for (std::size_t i = 0; i < _impl.size(); ++i) { + if ((*this)[i] != a_rhs[i]) { + return (*this)[i] < a_rhs[i] ? std::strong_ordering::less : std::strong_ordering::greater; + } + } + return std::strong_ordering::equal; + } + + [[nodiscard]] constexpr std::uint32_t pack() const noexcept + { + return static_cast( + (_impl[0] & 0x0FF) << 24u | + (_impl[1] & 0x0FF) << 16u | + (_impl[2] & 0xFFF) << 4u | + (_impl[3] & 0x00F) << 0u); + } + + [[nodiscard]] std::string string() const + { + std::string result; + for (auto&& ver : _impl) { + result += std::to_string(ver); + result += '-'; + } + result.pop_back(); + return result; + } + + [[nodiscard]] std::wstring wstring() const + { + std::wstring result; + for (auto&& ver : _impl) { + result += std::to_wstring(ver); + result += L'-'; + } + result.pop_back(); + return result; + } + + private: + std::array _impl{ 0, 0, 0, 0 }; + }; + + [[nodiscard]] constexpr bool operator==(const Version& a_lhs, const Version& a_rhs) noexcept { return a_lhs.compare(a_rhs) == 0; } + [[nodiscard]] constexpr std::strong_ordering operator<=>(const Version& a_lhs, const Version& a_rhs) noexcept { return a_lhs.compare(a_rhs); } + + [[nodiscard]] inline std::optional get_file_version(stl::zwstring a_filename) + { + std::uint32_t dummy; + std::vector buf(WinAPI::GetFileVersionInfoSize(a_filename.data(), std::addressof(dummy))); + if (buf.empty()) { + return std::nullopt; + } + + if (!WinAPI::GetFileVersionInfo(a_filename.data(), 0, static_cast(buf.size()), buf.data())) { + return std::nullopt; + } + + void* verBuf{ nullptr }; + std::uint32_t verLen{ 0 }; + if (!WinAPI::VerQueryValue(buf.data(), L"\\StringFileInfo\\040904B0\\ProductVersion", std::addressof(verBuf), std::addressof(verLen))) { + return std::nullopt; + } + + Version version; + std::wistringstream ss(std::wstring(static_cast(verBuf), verLen)); + std::wstring token; + for (std::size_t i = 0; i < 4 && std::getline(ss, token, L'.'); ++i) { + version[i] = static_cast(std::stoi(token)); + } + + return version; + } +} diff --git a/include/SKSE/Impl/PCH.h b/include/SKSE/Impl/PCH.h index 0a4b8051d..e76a73124 100644 --- a/include/SKSE/Impl/PCH.h +++ b/include/SKSE/Impl/PCH.h @@ -713,7 +713,7 @@ namespace REL # define RELOCATION_ID(SE, AE) REL::ID(SE) #endif -#include "REL/Relocation.h" +#include "REL/REL.h" #include "RE/Offsets.h" #include "RE/Offsets_NiRTTI.h" diff --git a/src/REL/ID.cpp b/src/REL/ID.cpp new file mode 100644 index 000000000..86926e12a --- /dev/null +++ b/src/REL/ID.cpp @@ -0,0 +1,87 @@ +#include "REL/ID.h" + +namespace REL +{ + namespace detail + { + bool memory_map::open(stl::zwstring a_name, std::size_t a_size) + { + close(); + + WinAPI::ULARGE_INTEGER bytes; + bytes.value = a_size; + + _mapping = WinAPI::OpenFileMapping( + WinAPI::FILE_MAP_READ | WinAPI::FILE_MAP_WRITE, + false, + a_name.data()); + if (!_mapping) { + close(); + return false; + } + + _view = WinAPI::MapViewOfFile( + _mapping, + WinAPI::FILE_MAP_READ | WinAPI::FILE_MAP_WRITE, + 0, + 0, + bytes.value); + if (!_view) { + close(); + return false; + } + + return true; + } + + bool memory_map::create(stl::zwstring a_name, std::size_t a_size) + { + close(); + + WinAPI::ULARGE_INTEGER bytes; + bytes.value = a_size; + + _mapping = WinAPI::OpenFileMapping( + WinAPI::FILE_MAP_READ | WinAPI::FILE_MAP_WRITE, + false, + a_name.data()); + if (!_mapping) { + _mapping = WinAPI::CreateFileMapping( + WinAPI::INVALID_HANDLE_VALUE, + nullptr, + WinAPI::PAGE_READWRITE, + bytes.hi, + bytes.lo, + a_name.data()); + if (!_mapping) { + return false; + } + } + + _view = WinAPI::MapViewOfFile( + _mapping, + WinAPI::FILE_MAP_READ | WinAPI::FILE_MAP_WRITE, + 0, + 0, + bytes.value); + if (!_view) { + return false; + } + + return true; + } + + void memory_map::close() + { + if (_view) { + WinAPI::UnmapViewOfFile(static_cast(_view)); + _view = nullptr; + } + + if (_mapping) { + WinAPI::CloseHandle(_mapping); + _mapping = nullptr; + } + } + } +} diff --git a/src/REL/Module.cpp b/src/REL/Module.cpp new file mode 100644 index 000000000..1e70aea3e --- /dev/null +++ b/src/REL/Module.cpp @@ -0,0 +1,25 @@ +#include "REL/Module.h" + +namespace REL +{ + void Module::load_segments() + { + const auto dosHeader = reinterpret_cast(_base); + const auto ntHeader = stl::adjust_pointer(dosHeader, dosHeader->lfanew); + const auto sections = WinAPI::IMAGE_FIRST_SECTION(ntHeader); + const auto size = std::min(ntHeader->fileHeader.sectionCount, _segments.size()); + for (std::size_t i = 0; i < size; ++i) { + const auto& section = sections[i]; + const auto it = std::find_if(SEGMENTS.begin(), SEGMENTS.end(), [&](auto&& a_elem) { + constexpr auto size = std::extent_v; + const auto len = std::min(a_elem.first.size(), size); + return std::memcmp(a_elem.first.data(), section.name, len) == 0 && + (section.characteristics & a_elem.second) == a_elem.second; + }); + if (it != SEGMENTS.end()) { + const auto idx = static_cast(std::distance(SEGMENTS.begin(), it)); + _segments[idx] = Segment{ _base, _base + section.virtualAddress, section.virtualSize }; + } + } + } +} diff --git a/src/REL/Relocation.cpp b/src/REL/Relocation.cpp deleted file mode 100644 index 940ed6a2c..000000000 --- a/src/REL/Relocation.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "REL/Relocation.h" - -#define WIN32_LEAN_AND_MEAN - -#define NOGDICAPMASKS -#define NOVIRTUALKEYCODES -//#define NOWINMESSAGES -#define NOWINSTYLES -#define NOSYSMETRICS -#define NOMENUS -#define NOICONS -#define NOKEYSTATES -#define NOSYSCOMMANDS -#define NORASTEROPS -#define NOSHOWWINDOW -#define OEMRESOURCE -#define NOATOM -#define NOCLIPBOARD -#define NOCOLOR -//#define NOCTLMGR -#define NODRAWTEXT -#define NOGDI -#define NOKERNEL -//#define NOUSER -#define NONLS -//#define NOMB -#define NOMEMMGR -#define NOMETAFILE -#define NOMINMAX -//#define NOMSG -#define NOOPENFILE -#define NOSCROLL -#define NOSERVICE -#define NOSOUND -#define NOTEXTMETRIC -#define NOWH -#define NOWINOFFSETS -#define NOCOMM -#define NOKANJI -#define NOHELP -#define NOPROFILER -#define NODEFERWINDOWPOS -#define NOMCX - -#include - -namespace REL -{ - namespace detail - { - bool memory_map::open(stl::zwstring a_name, std::size_t a_size) - { - close(); - - ::ULARGE_INTEGER bytes; - bytes.QuadPart = a_size; - - _mapping = ::OpenFileMappingW( - FILE_MAP_READ | FILE_MAP_WRITE, - false, - a_name.data()); - if (!_mapping) { - close(); - return false; - } - - _view = ::MapViewOfFile( - _mapping, - FILE_MAP_READ | FILE_MAP_WRITE, - 0, - 0, - bytes.QuadPart); - if (!_view) { - close(); - return false; - } - - return true; - } - - bool memory_map::create(stl::zwstring a_name, std::size_t a_size) - { - close(); - - ::ULARGE_INTEGER bytes; - bytes.QuadPart = a_size; - - _mapping = ::OpenFileMappingW( - FILE_MAP_READ | FILE_MAP_WRITE, - false, - a_name.data()); - if (!_mapping) { - _mapping = ::CreateFileMappingW( - INVALID_HANDLE_VALUE, - nullptr, - PAGE_READWRITE, - bytes.HighPart, - bytes.LowPart, - a_name.data()); - if (!_mapping) { - return false; - } - } - - _view = ::MapViewOfFile( - _mapping, - FILE_MAP_READ | FILE_MAP_WRITE, - 0, - 0, - bytes.QuadPart); - if (!_view) { - return false; - } - - return true; - } - - void memory_map::close() - { - if (_view) { - ::UnmapViewOfFile(static_cast(_view)); - _view = nullptr; - } - - if (_mapping) { - ::CloseHandle(_mapping); - _mapping = nullptr; - } - } - } - - void Module::load_segments() - { - auto dosHeader = reinterpret_cast(_base); - auto ntHeader = stl::adjust_pointer(dosHeader, dosHeader->e_lfanew); - const auto* sections = IMAGE_FIRST_SECTION(ntHeader); - const auto size = std::min(ntHeader->FileHeader.NumberOfSections, _segments.size()); - for (std::size_t i = 0; i < size; ++i) { - const auto& section = sections[i]; - const auto it = std::find_if( - SEGMENTS.begin(), - SEGMENTS.end(), - [&](auto&& a_elem) { - constexpr auto size = std::extent_v; - const auto len = std::min(a_elem.first.size(), size); - return std::memcmp(a_elem.first.data(), section.Name, len) == 0 && - (section.Characteristics & a_elem.second) == a_elem.second; - }); - if (it != SEGMENTS.end()) { - const auto idx = static_cast(std::distance(SEGMENTS.begin(), it)); - _segments[idx] = Segment{ _base, _base + section.VirtualAddress, section.Misc.VirtualSize }; - } - } - } -} From 9e9e2daaa132bb0cc64fe809402761e38a4752e0 Mon Sep 17 00:00:00 2001 From: powerof3 Date: Sun, 28 Jan 2024 00:28:19 +0000 Subject: [PATCH 24/24] maintenance --- include/REL/ID.h | 2 +- include/REL/Version.h | 4 ++-- src/REL/Module.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/REL/ID.h b/include/REL/ID.h index 09d5f25ee..a6214a429 100644 --- a/include/REL/ID.h +++ b/include/REL/ID.h @@ -46,7 +46,7 @@ namespace REL void* _mapping{ nullptr }; void* _view{ nullptr }; }; - } + } class IDDatabase { diff --git a/include/REL/Version.h b/include/REL/Version.h index 04b3ffca8..b6f4ddd91 100644 --- a/include/REL/Version.h +++ b/include/REL/Version.h @@ -2,7 +2,7 @@ namespace REL { - class Version + class Version { public: using value_type = std::uint16_t; @@ -95,7 +95,7 @@ namespace REL Version version; std::wistringstream ss(std::wstring(static_cast(verBuf), verLen)); - std::wstring token; + std::wstring token; for (std::size_t i = 0; i < 4 && std::getline(ss, token, L'.'); ++i) { version[i] = static_cast(std::stoi(token)); } diff --git a/src/REL/Module.cpp b/src/REL/Module.cpp index 1e70aea3e..3a590cf74 100644 --- a/src/REL/Module.cpp +++ b/src/REL/Module.cpp @@ -14,7 +14,7 @@ namespace REL constexpr auto size = std::extent_v; const auto len = std::min(a_elem.first.size(), size); return std::memcmp(a_elem.first.data(), section.name, len) == 0 && - (section.characteristics & a_elem.second) == a_elem.second; + (section.characteristics & a_elem.second) == a_elem.second; }); if (it != SEGMENTS.end()) { const auto idx = static_cast(std::distance(SEGMENTS.begin(), it));