From 464212564d8290366a822713d6f8989d20333fa5 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sat, 19 Oct 2024 06:31:42 -0500 Subject: [PATCH 1/5] feat: `REX` --- CommonLibF4/include/REX/REX.h | 65 +++++++++++++++++++++ CommonLibF4/include/REX/W32.h | 1 + CommonLibF4/include/REX/W32/BASE.h | 10 ++++ CommonLibF4/include/REX/W32/NT.h | 92 ++++++++++++++++++++++++++++++ CommonLibF4/src/REX/W32.cpp | 11 ++++ 5 files changed, 179 insertions(+) create mode 100644 CommonLibF4/include/REX/W32/NT.h diff --git a/CommonLibF4/include/REX/REX.h b/CommonLibF4/include/REX/REX.h index b7b8aa04..e16baae6 100644 --- a/CommonLibF4/include/REX/REX.h +++ b/CommonLibF4/include/REX/REX.h @@ -1,5 +1,70 @@ #pragma once +namespace REX +{ + template < + class E, + class U = std::underlying_type_t> + class Enum + { + public: + using enum_type = E; + using underlying_type = U; + + static_assert(std::is_enum_v, "Enum must be an enum"); + static_assert(std::is_integral_v, "Enum<..., U> must be an integral"); + + constexpr Enum() noexcept = default; + constexpr Enum(const Enum&) noexcept = default; + constexpr Enum(Enum&&) noexcept = default; + + template // NOLINTNEXTLINE(google-explicit-constructor) + constexpr Enum(Enum a_rhs) noexcept : + _impl(static_cast(a_rhs.get())) + {} + + constexpr Enum(E a_value) noexcept : + _impl(static_cast(a_value)) + {} + + ~Enum() noexcept = default; + + constexpr Enum& operator=(const Enum&) noexcept = default; + constexpr Enum& operator=(Enum&&) noexcept = default; + + template + constexpr Enum& operator=(Enum a_rhs) noexcept + { + _impl = static_cast(a_rhs.get()); + } + + constexpr Enum& operator=(E a_value) noexcept + { + _impl = static_cast(a_value); + return *this; + } + + public: + [[nodiscard]] explicit constexpr operator bool() const noexcept { return _impl != static_cast(0); } + [[nodiscard]] constexpr E operator*() const noexcept { return get(); } + [[nodiscard]] constexpr E get() const noexcept { return static_cast(_impl); } + [[nodiscard]] constexpr U underlying() const noexcept { return _impl; } + + public: + friend constexpr bool operator==(Enum a_lhs, Enum a_rhs) noexcept { return a_lhs.underlying() == a_rhs.underlying(); } + friend constexpr bool operator==(Enum a_lhs, E a_rhs) noexcept { return a_lhs.underlying() == static_cast(a_rhs); } + friend constexpr bool operator==(E a_lhs, Enum a_rhs) noexcept { return static_cast(a_lhs) == a_rhs.underlying(); } + + private: + U _impl{ 0 }; + }; + template + Enum(Args...) -> Enum< + std::common_type_t, + std::underlying_type_t< + std::common_type_t>>; +} + namespace REX { template < diff --git a/CommonLibF4/include/REX/W32.h b/CommonLibF4/include/REX/W32.h index 6deadaa1..b11a7f6e 100644 --- a/CommonLibF4/include/REX/W32.h +++ b/CommonLibF4/include/REX/W32.h @@ -21,6 +21,7 @@ #include "REX/W32/DXGI_5.h" #include "REX/W32/DXGI_6.h" #include "REX/W32/KERNEL32.h" +#include "REX/W32/NT.h" #include "REX/W32/OLE32.h" #include "REX/W32/USER32.h" #include "REX/W32/VERSION.h" diff --git a/CommonLibF4/include/REX/W32/BASE.h b/CommonLibF4/include/REX/W32/BASE.h index 13cce382..1196560a 100644 --- a/CommonLibF4/include/REX/W32/BASE.h +++ b/CommonLibF4/include/REX/W32/BASE.h @@ -162,6 +162,7 @@ namespace REX::W32 }; std::int64_t value; }; + static_assert(sizeof(LARGE_INTEGER) == 0x8); union ULARGE_INTEGER { @@ -172,6 +173,15 @@ namespace REX::W32 }; std::uint64_t value; }; + static_assert(sizeof(ULARGE_INTEGER) == 0x8); + + struct UNICODE_STRING + { + std::uint16_t length; + std::uint16_t maxLength; + wchar_t* buffer; + }; + static_assert(sizeof(UNICODE_STRING) == 0x10); } namespace REX::W32 diff --git a/CommonLibF4/include/REX/W32/NT.h b/CommonLibF4/include/REX/W32/NT.h new file mode 100644 index 00000000..9a410f64 --- /dev/null +++ b/CommonLibF4/include/REX/W32/NT.h @@ -0,0 +1,92 @@ +#pragma once + +#include "REX/W32/BASE.h" + +namespace REX::W32 +{ + struct EXCEPTION_REGISTRATION_RECORD; + struct PEB_LDR_DATA; + struct RTL_USER_PROCESS_PARAMETERS; + struct UNICODE_STRING; + + using PS_POST_PROCESS_INIT_ROUTINE = void (*)(); + + struct LIST_ENTRY + { + struct LIST_ENTRY* fLink; + struct LIST_ENTRY* bLink; + }; + + struct NT_TIB + { + EXCEPTION_REGISTRATION_RECORD* exceptionList; + void* stackBase; + void* stackLimit; + void* subSystemTib; + union + { + void* fiberData; + std::uint32_t version; + }; + void* arbitraryUserPointer; + struct NT_TIB* self; + }; + + struct PEB + { + std::byte reserved1[2]; + std::byte beingDebugged; + std::byte reserved2[1]; + void* reserved3[2]; + PEB_LDR_DATA* ldr; + RTL_USER_PROCESS_PARAMETERS* processParameters; + void* reserved4[3]; + void* atlThunkSListPtr; + void* reserved5; + std::uint32_t reserved6; + void* reserved7; + std::uint32_t reserved8; + std::uint32_t atlThunkSListPtr32; + void* reserved9[45]; + std::byte reserved10[96]; + PS_POST_PROCESS_INIT_ROUTINE postProcessInitRoutine; + std::byte reserved11[128]; + void* reserved12[1]; + std::uint32_t sessionID; + }; + + struct PEB_LDR_DATA + { + std::byte reserved1[8]; + void* reserved2[3]; + LIST_ENTRY inMemoryOrderModuleList; + }; + + struct RTL_USER_PROCESS_PARAMETERS + { + std::byte reserved1[16]; + void* reserved2[10]; + UNICODE_STRING imagePathName; + UNICODE_STRING commandLine; + }; + + struct TEB + { + void* reserved1[11]; + void* threadLocalStoragePointer; + PEB* processEnvironmentBlock; + void* reserved2[399]; + std::byte reserved3[1952]; + void* tlsSlots[64]; + std::byte reserved4[8]; + void* reserved5[26]; + void* reservedForOle; + void* reserved6[4]; + void* tlsExpansionSlots; + }; +} + +namespace REX::W32 +{ + TEB* NtCurrentTeb() noexcept; +} diff --git a/CommonLibF4/src/REX/W32.cpp b/CommonLibF4/src/REX/W32.cpp index 27d40a73..7249caba 100644 --- a/CommonLibF4/src/REX/W32.cpp +++ b/CommonLibF4/src/REX/W32.cpp @@ -5,6 +5,7 @@ #include "REX/W32/DBGHELP.h" #include "REX/W32/DXGI.h" #include "REX/W32/KERNEL32.h" +#include "REX/W32/NT.h" #include "REX/W32/OLE32.h" #include "REX/W32/SHELL32.h" #include "REX/W32/USER32.h" @@ -796,6 +797,16 @@ namespace REX::W32 } } +// NT + +namespace REX::W32 +{ + TEB* NtCurrentTeb() noexcept + { + return reinterpret_cast(__readgsqword(offsetof(NT_TIB, self))); + } +} + // OLE32 REX_W32_IMPORT(void, CoTaskMemFree, void*); From 57329624e3c3885d01260c9c5c9b9b95bff5ac4d Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sat, 19 Oct 2024 06:32:22 -0500 Subject: [PATCH 2/5] feat: `TLS` --- CommonLibF4/include/RE/Bethesda/TLS.h | 18 ++++++++++++++++++ CommonLibF4/include/RE/Fallout.h | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 CommonLibF4/include/RE/Bethesda/TLS.h diff --git a/CommonLibF4/include/RE/Bethesda/TLS.h b/CommonLibF4/include/RE/Bethesda/TLS.h new file mode 100644 index 00000000..fc90e1ab --- /dev/null +++ b/CommonLibF4/include/RE/Bethesda/TLS.h @@ -0,0 +1,18 @@ +#pragma once + +#include "REX/W32/NT.h" + +namespace RE +{ + struct TLS + { + [[nodiscard]] static TLS* GetSingleton() + { + return *static_cast(REX::W32::NtCurrentTeb()->threadLocalStoragePointer); + } + + // members + std::byte pad000[0x830]; // 000 + bool consoleMode; // 830 + }; +} diff --git a/CommonLibF4/include/RE/Fallout.h b/CommonLibF4/include/RE/Fallout.h index 2cbac517..f156fb4a 100644 --- a/CommonLibF4/include/RE/Fallout.h +++ b/CommonLibF4/include/RE/Fallout.h @@ -211,6 +211,7 @@ #include "RE/Bethesda/Settings.h" #include "RE/Bethesda/Sky.h" #include "RE/Bethesda/SplineUtils.h" +#include "RE/Bethesda/TaskQueueInterface.h" #include "RE/Bethesda/TESBoundAnimObjects.h" #include "RE/Bethesda/TESBoundObjects.h" #include "RE/Bethesda/TESCamera.h" @@ -225,7 +226,7 @@ #include "RE/Bethesda/TESRace.h" #include "RE/Bethesda/TESWaterForm.h" #include "RE/Bethesda/TESWorldSpace.h" -#include "RE/Bethesda/TaskQueueInterface.h" +#include "RE/Bethesda/TLS.h" #include "RE/Bethesda/UI.h" #include "RE/Bethesda/UIMessage.h" #include "RE/Bethesda/UIMessageQueue.h" From 503330d96a439a3967653cd3f01865d8d1ce07e3 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sat, 19 Oct 2024 06:35:58 -0500 Subject: [PATCH 3/5] fix: cmake sourcelist --- CommonLibF4/cmake/sourcelist.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CommonLibF4/cmake/sourcelist.cmake b/CommonLibF4/cmake/sourcelist.cmake index 77c1ccfc..a8a558f9 100644 --- a/CommonLibF4/cmake/sourcelist.cmake +++ b/CommonLibF4/cmake/sourcelist.cmake @@ -216,6 +216,7 @@ set(SOURCES include/RE/Bethesda/Settings.h include/RE/Bethesda/Sky.h include/RE/Bethesda/SplineUtils.h + include/RE/Bethesda/TaskQueueInterface.h include/RE/Bethesda/TESBoundAnimObjects.h include/RE/Bethesda/TESBoundObjects.h include/RE/Bethesda/TESCamera.h @@ -230,7 +231,7 @@ set(SOURCES include/RE/Bethesda/TESRace.h include/RE/Bethesda/TESWaterForm.h include/RE/Bethesda/TESWorldSpace.h - include/RE/Bethesda/TaskQueueInterface.h + include/RE/Bethesda/TLS.h include/RE/Bethesda/UI.h include/RE/Bethesda/UIMessage.h include/RE/Bethesda/UIMessageQueue.h @@ -390,6 +391,7 @@ set(SOURCES include/REX/W32/DXGI_5.h include/REX/W32/DXGI_6.h include/REX/W32/KERNEL32.h + include/REX/W32/NT.h include/REX/W32/OLE32.h include/REX/W32/SHELL32.h include/REX/W32/USER32.h From 6a7750222db944788d48a3c15bd772e6cc8bb7df Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sat, 19 Oct 2024 07:58:11 -0500 Subject: [PATCH 4/5] feat: `TESConditionItem` --- CommonLibF4/include/RE/Bethesda/TESCondition.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CommonLibF4/include/RE/Bethesda/TESCondition.h b/CommonLibF4/include/RE/Bethesda/TESCondition.h index 013ea95b..5cbe8b6a 100644 --- a/CommonLibF4/include/RE/Bethesda/TESCondition.h +++ b/CommonLibF4/include/RE/Bethesda/TESCondition.h @@ -80,11 +80,18 @@ namespace RE [[nodiscard]] bool IsTrue(TESObjectREFR* a_actionRef, TESObjectREFR* a_targetRef) { - using func_t = decltype(&TESConditionItem::IsTrue); + using func_t = bool(*)(TESConditionItem*, TESObjectREFR*, TESObjectREFR*); static REL::Relocation func{ REL::ID(2212008) }; return func(this, a_actionRef, a_targetRef); } + [[nodiscard]] bool IsTrue(ConditionCheckParams& a_params) + { + using func_t = bool(*)(TESConditionItem*, ConditionCheckParams&); + static REL::Relocation func{ REL::ID(2212009) }; + return func(this, a_params); + } + // members TESConditionItem* next; // 00 CONDITION_ITEM_DATA data; // 08 From 9dbb466c05f81adfbab02eaef77ab286cc8eb9af Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Sat, 19 Oct 2024 08:18:51 -0500 Subject: [PATCH 5/5] feat: `Relocation` --- CommonLibF4/include/REL/Relocation.h | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/CommonLibF4/include/REL/Relocation.h b/CommonLibF4/include/REL/Relocation.h index 2a3bf789..65aa44ce 100644 --- a/CommonLibF4/include/REL/Relocation.h +++ b/CommonLibF4/include/REL/Relocation.h @@ -300,28 +300,32 @@ namespace REL safe_write(address(), a_data.data(), a_data.size_bytes()); } - template - std::uintptr_t write_branch(const std::uintptr_t a_dst) requires(std::same_as) + template + std::uintptr_t write_branch(const std::uintptr_t a_dst) + requires(std::same_as) { - return F4SE::GetTrampoline().write_branch(address(), a_dst); + return F4SE::GetTrampoline().write_branch(address() + O, a_dst); } - template - std::uintptr_t write_branch(const F a_dst) requires(std::same_as) + template + std::uintptr_t write_branch(const F a_dst) + requires(std::same_as) { - return F4SE::GetTrampoline().write_branch(address(), stl::unrestricted_cast(a_dst)); + return F4SE::GetTrampoline().write_branch(address() + O, stl::unrestricted_cast(a_dst)); } - template - std::uintptr_t write_call(const std::uintptr_t a_dst) requires(std::same_as) + template + std::uintptr_t write_call(const std::uintptr_t a_dst) + requires(std::same_as) { - return F4SE::GetTrampoline().write_call(address(), a_dst); + return F4SE::GetTrampoline().write_call(address() + O , a_dst); } - template - std::uintptr_t write_call(const F a_dst) requires(std::same_as) + template + std::uintptr_t write_call(const F a_dst) + requires(std::same_as) { - return F4SE::GetTrampoline().write_call(address(), stl::unrestricted_cast(a_dst)); + return F4SE::GetTrampoline().write_call(address() + O, stl::unrestricted_cast(a_dst)); } void write_fill(const std::uint8_t a_value, const std::size_t a_count) requires(std::same_as)