From 0823d2b145973d9d72d1698995caddf50222f35b Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:17:35 -0500 Subject: [PATCH 01/20] chore!: move `emplace_vtable` to `REL` --- include/RE/S/Setting.h | 2 +- include/REL/Relocation.h | 12 ++++++++++++ include/SFSE/Impl/PCH.h | 11 ----------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/RE/S/Setting.h b/include/RE/S/Setting.h index b991b35c..2fde9417 100644 --- a/include/RE/S/Setting.h +++ b/include/RE/S/Setting.h @@ -66,7 +66,7 @@ namespace RE _value.s = _defaultValue.s = _strdup(a_value); } - virtual ~Setting() { stl::emplace_vtable(this); } // 00 + virtual ~Setting() { REL::EmplaceVTable(this); } // 00 // add [[nodiscard]] virtual bool IsPrefSetting() { return false; } // 01 diff --git a/include/REL/Relocation.h b/include/REL/Relocation.h index dc2ab8c7..09ba7c0d 100644 --- a/include/REL/Relocation.h +++ b/include/REL/Relocation.h @@ -149,6 +149,18 @@ namespace REL } } + template + bool EmplaceVTable(T* a_ptr) + { + auto address = T::VTABLE[0].address(); + if (address) { + reinterpret_cast(a_ptr)[0] = address; + return true; + } + + return true; + } + template constexpr std::invoke_result_t invoke(F&& a_func, Args&&... a_args) // noexcept(std::is_nothrow_invocable_v) diff --git a/include/SFSE/Impl/PCH.h b/include/SFSE/Impl/PCH.h index 7f8b1109..bf471d9a 100644 --- a/include/SFSE/Impl/PCH.h +++ b/include/SFSE/Impl/PCH.h @@ -297,17 +297,6 @@ namespace SFSE::stl } } - template - bool emplace_vtable(T* a_ptr) - { - auto address = T::VTABLE[0].address(); - if (!address) { - return false; - } - reinterpret_cast(a_ptr)[0] = address; - return true; - } - template void memzero(volatile T* a_ptr, const std::size_t a_size = sizeof(T)) { From c51f97dba3d8450a5bd59b6cb472b430c2b46e49 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:26:58 -0500 Subject: [PATCH 02/20] feat!: move `ID`s and `GetDefaultObjectData` --- include/RE/B/BGSDefaultObjectManager.h | 16 +++---- include/RE/B/BGSStoryTeller.h | 2 +- include/RE/B/BSInputEnableLayer.h | 48 ++++++++++---------- include/RE/B/BSInputEnableManager.h | 4 +- include/RE/B/BSInputEventUser.h | 4 +- include/RE/F/FORM_ENUM_STRING.h | 2 +- include/RE/G/GameMenuBase.h | 2 +- include/RE/I/INIPrefSettingCollection.h | 2 +- include/RE/I/INISettingCollection.h | 2 +- include/RE/IDs.h | 58 +++++++++++++++++++++++++ include/RE/S/SWFToCodeFunctionHandler.h | 6 +-- include/RE/S/ScaleformMemoryHeap.h | 4 +- include/RE/T/TESContainer.h | 2 +- 13 files changed, 107 insertions(+), 45 deletions(-) diff --git a/include/RE/B/BGSDefaultObjectManager.h b/include/RE/B/BGSDefaultObjectManager.h index a9d04dd4..f77f4c9b 100644 --- a/include/RE/B/BGSDefaultObjectManager.h +++ b/include/RE/B/BGSDefaultObjectManager.h @@ -402,12 +402,6 @@ namespace RE }; static_assert(sizeof(DEFAULT_OBJECT_DATA) == 0x20); - [[nodiscard]] inline std::span GetDefaultObjectData() - { - static REL::Relocation data{ REL::ID(761776) }; - return { *data }; - } - class BGSDefaultObjectManager : public TESForm, // 00 public BSTSingletonImplicit // 30 @@ -416,6 +410,8 @@ namespace RE SF_RTTI_VTABLE(BGSDefaultObjectManager); SF_FORMTYPE(DOBJ); + ~BGSDefaultObjectManager() override; // 00 + [[nodiscard]] static BGSDefaultObjectManager* GetSingleton() { using func_t = decltype(&BGSDefaultObjectManager::GetSingleton); @@ -423,7 +419,11 @@ namespace RE return func(); } - ~BGSDefaultObjectManager() override; // 00 + [[nodiscard]] static std::span GetDefaultObjectData() + { + static REL::Relocation data{ ID::BGSDefaultObjectManager::DefaultObjectData }; + return { *data }; + } [[nodiscard]] TESForm* GetDefaultObject(DEFAULT_OBJECT a_obj) const noexcept { @@ -432,7 +432,7 @@ namespace RE } template - [[nodiscard]] T* GetDefaultObject(DEFAULT_OBJECT a_obj) const // + [[nodiscard]] T* GetDefaultObject(DEFAULT_OBJECT a_obj) const requires(std::derived_from && !std::is_pointer_v && !std::is_reference_v) diff --git a/include/RE/B/BGSStoryTeller.h b/include/RE/B/BGSStoryTeller.h index 5dc06a84..874e2059 100644 --- a/include/RE/B/BGSStoryTeller.h +++ b/include/RE/B/BGSStoryTeller.h @@ -13,7 +13,7 @@ namespace RE [[nodiscard]] static BGSStoryTeller* GetSingleton() { - static REL::Relocation singleton{ REL::ID(878850) }; + static REL::Relocation singleton{ ID::BGSStoryTeller::Singleton }; return *singleton; } diff --git a/include/RE/B/BSInputEnableLayer.h b/include/RE/B/BSInputEnableLayer.h index bc1afa49..a967beac 100644 --- a/include/RE/B/BSInputEnableLayer.h +++ b/include/RE/B/BSInputEnableLayer.h @@ -44,35 +44,36 @@ namespace RE Others = HandScanner | Takeoff | Inventory | Gravjump | FarTravel, }; - uint32_t index; - uint32_t state; - uint64_t unk08; - uint64_t unk10; - uint64_t unk18; - - uint64_t SetUserFlags(uint64_t flags, bool enabled) + std::uint64_t SetUserFlags(std::uint64_t a_flags, bool a_enabled) { using func_t = decltype(&BSInputEnableLayer::SetUserFlags); - static REL::Relocation func(REL::ID(106486)); - return func(this, flags, enabled); + static REL::Relocation func{ ID::BSInputEnableLayer::SetUserFlags }; + return func(this, a_flags, a_enabled); } - uint64_t SetOtherFlags(uint64_t flags, bool enabled) + std::uint64_t SetOtherFlags(std::uint64_t a_flags, bool a_enabled) { using func_t = decltype(&BSInputEnableLayer::SetOtherFlags); - static REL::Relocation func(REL::ID(109447)); - return func(this, flags, enabled); + static REL::Relocation func{ ID::BSInputEnableLayer::SetOtherFlags }; + return func(this, a_flags, a_enabled); } + + // members + std::uint32_t index; + std::uint32_t state; + std::uint64_t unk08; + std::uint64_t unk10; + std::uint64_t unk18; }; class InputEnableLayer { public: - InputEnableLayer() {} + InputEnableLayer() = default; - InputEnableLayer(const char* layerName) + InputEnableLayer(const char* a_layerName) { - Create(layerName); + Create(a_layerName); } ~InputEnableLayer() @@ -80,14 +81,15 @@ namespace RE Free(); } - bool Create(const char* layerName) + bool Create(const char* a_layerName) { bool result = true; if (!data) { - result = BSInputEnableManager::GetSingleton()->CreateLayer(this, layerName); + result = BSInputEnableManager::GetSingleton()->CreateLayer(this, a_layerName); if (!result) data = nullptr; } + return result; } @@ -96,25 +98,27 @@ namespace RE bool result = true; if (data) { using func_t = decltype(&InputEnableLayer::Free); - static REL::Relocation func(REL::ID(36626)); + static REL::Relocation func{ ID::InputEnableLayer::Free }; result = func(this); data = nullptr; } + return result; } - void SetUserFlags(uint64_t flags, bool enabled) + void SetUserFlags(std::uint64_t a_flags, bool a_enabled) { if (data) - data->SetUserFlags(flags, enabled); + data->SetUserFlags(a_flags, a_enabled); } - void SetOtherFlags(uint64_t flags, bool enabled) + void SetOtherFlags(std::uint64_t a_flags, bool a_enabled) { if (data) - data->SetOtherFlags(flags, enabled); + data->SetOtherFlags(a_flags, a_enabled); } + // members BSInputEnableLayer* data{ nullptr }; }; } diff --git a/include/RE/B/BSInputEnableManager.h b/include/RE/B/BSInputEnableManager.h index 4a4abd5a..47f4abfe 100644 --- a/include/RE/B/BSInputEnableManager.h +++ b/include/RE/B/BSInputEnableManager.h @@ -11,14 +11,14 @@ namespace RE static BSInputEnableManager* GetSingleton() { - static REL::Relocation singleton{ REL::ID(878792) }; + static REL::Relocation singleton{ ID::BSInputEnableManager::Singleton }; return *singleton; } bool CreateLayer(InputEnableLayer* a_layer, const char* a_layerName) { using func_t = decltype(&BSInputEnableManager::CreateLayer); - static REL::Relocation func(REL::ID(179101)); + static REL::Relocation func{ ID::BSInputEnableManager::CreateLayer }; return func(this, a_layer, a_layerName); } }; diff --git a/include/RE/B/BSInputEventUser.h b/include/RE/B/BSInputEventUser.h index 8d156f39..22ee45b4 100644 --- a/include/RE/B/BSInputEventUser.h +++ b/include/RE/B/BSInputEventUser.h @@ -141,9 +141,9 @@ namespace RE virtual void OnCharacterEvent(const CharacterEvent*) { return; } // 07 virtual void OnButtonEvent(const ButtonEvent*) { return; } // 08 - virtual void InputEventUser_Unk_09(const InputEvent* a_event) // 09 + virtual void InputEventUser_Unk09(const InputEvent* a_event) // 09 { - using func_t = decltype(&BSInputEventUser::InputEventUser_Unk_09); + using func_t = decltype(&BSInputEventUser::InputEventUser_Unk09); static REL::Relocation func(REL::ID(178899)); return func(this, a_event); } diff --git a/include/RE/F/FORM_ENUM_STRING.h b/include/RE/F/FORM_ENUM_STRING.h index 7e1e0d8f..8204e6ad 100644 --- a/include/RE/F/FORM_ENUM_STRING.h +++ b/include/RE/F/FORM_ENUM_STRING.h @@ -9,7 +9,7 @@ namespace RE public: [[nodiscard]] static std::span GetFormEnumString() { - static REL::Relocation formEnumString{ REL::ID(761416) }; + static REL::Relocation formEnumString{ ID::FORM_ENUM_STRING::FormEnumString }; return { *formEnumString }; } diff --git a/include/RE/G/GameMenuBase.h b/include/RE/G/GameMenuBase.h index c6b41c05..c0281444 100644 --- a/include/RE/G/GameMenuBase.h +++ b/include/RE/G/GameMenuBase.h @@ -28,7 +28,7 @@ namespace RE GameMenuBase() { using func_t = GameMenuBase* (*)(GameMenuBase*); - static REL::Relocation func(REL::ID(130577)); + static REL::Relocation func{ ID::GameMenuBase::Ctor }; func(this); } diff --git a/include/RE/I/INIPrefSettingCollection.h b/include/RE/I/INIPrefSettingCollection.h index 75f58d9b..e2f3ba68 100644 --- a/include/RE/I/INIPrefSettingCollection.h +++ b/include/RE/I/INIPrefSettingCollection.h @@ -14,7 +14,7 @@ namespace RE [[nodiscard]] static INIPrefSettingCollection* GetSingleton() { - static REL::Relocation singleton{ REL::ID(885866) }; + static REL::Relocation singleton{ ID::INIPrefSettingCollection::Singleton }; return *singleton; } }; diff --git a/include/RE/I/INISettingCollection.h b/include/RE/I/INISettingCollection.h index c21806f8..6ad4bc5e 100644 --- a/include/RE/I/INISettingCollection.h +++ b/include/RE/I/INISettingCollection.h @@ -15,7 +15,7 @@ namespace RE [[nodiscard]] static INISettingCollection* GetSingleton() { - static REL::Relocation singleton{ REL::ID(885862) }; + static REL::Relocation singleton{ ID::INISettingCollection::Singleton }; return *singleton; } diff --git a/include/RE/IDs.h b/include/RE/IDs.h index 519ea393..c69a3740 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -39,6 +39,7 @@ namespace RE::ID namespace BGSDefaultObjectManager { + inline constexpr REL::ID DefaultObjectData{ 761776 }; inline constexpr REL::ID GetSingleton{ 82283 }; } @@ -75,6 +76,23 @@ namespace RE::ID inline constexpr REL::ID DeleteSaveFile{ 147844 }; } + namespace BGSStoryTeller + { + inline constexpr REL::ID Singleton{ 878850 }; + } + + namespace BSInputEnableLayer + { + inline constexpr REL::ID SetUserFlags{ 106486 }; + inline constexpr REL::ID SetOtherFlags{ 109447 }; + } + + namespace BSInputEnableManager + { + inline constexpr REL::ID CreateLayer{ 179101 }; + inline constexpr REL::ID Singleton{ 878792 }; + } + namespace BSLog { inline constexpr REL::ID ctor{ 184813 }; @@ -233,6 +251,16 @@ namespace RE::ID inline constexpr REL::ID HasType{ 83208 }; } + namespace FORM_ENUM_STRING + { + inline constexpr REL::ID FormEnumString{ 761416 }; + } + + namespace GameMenuBase + { + inline constexpr REL::ID Ctor{ 130577 }; + } + namespace GameScript { namespace RemoteDebugger @@ -275,6 +303,21 @@ namespace RE::ID inline constexpr REL::ID Write{ 211266 }; } + namespace INIPrefSettingCollection + { + inline constexpr REL::ID Singleton{ 885866 }; + } + + namespace INISettingCollection + { + inline constexpr REL::ID Singleton{ 885862 }; + } + + namespace InputEnableLayer + { + inline constexpr REL::ID Free{ 36626 }; + } + namespace LockPickedEvent { inline constexpr REL::ID GetEventSource{ 107115 }; @@ -385,6 +428,11 @@ namespace RE::ID } } } + + namespace MemoryHeapPT + { + inline constexpr REL::ID Singleton{ 820297 }; + } } namespace ScrapHeap @@ -399,6 +447,11 @@ namespace RE::ID inline constexpr REL::ID GetScriptCommands{ 841467 }; } + namespace SWFToCodeFunctionHandler + { + inline constexpr REL::ID RegisterNativeFunction{ 187274 }; + } + namespace TESActorBaseData { inline constexpr REL::ID GetLevel{ 85868 }; @@ -420,6 +473,11 @@ namespace RE::ID inline constexpr REL::ID IsTrue{ 116127 }; } + namespace TESContainer + { + inline constexpr REL::ID AddObjectToContainer{ 85991 }; + } + namespace TESContainerChangedEvent { inline constexpr REL::ID GetEventSource{ 107155 }; diff --git a/include/RE/S/SWFToCodeFunctionHandler.h b/include/RE/S/SWFToCodeFunctionHandler.h index e6575561..08722e23 100644 --- a/include/RE/S/SWFToCodeFunctionHandler.h +++ b/include/RE/S/SWFToCodeFunctionHandler.h @@ -18,11 +18,11 @@ namespace RE // add virtual void MapCodeObjectFunctions() { return; } // 02 - void RegisterNativeFunction(const char* name, uint64_t idx) + void RegisterNativeFunction(const char* a_name, std::uint64_t a_idx) { using func_t = decltype(&SWFToCodeFunctionHandler::RegisterNativeFunction); - static REL::Relocation func(REL::ID(187274)); - func(this, name, idx); + static REL::Relocation func{ ID::SWFToCodeFunctionHandler::RegisterNativeFunction }; + func(this, a_name, a_idx); } }; static_assert(sizeof(SWFToCodeFunctionHandler) == 0x10); diff --git a/include/RE/S/ScaleformMemoryHeap.h b/include/RE/S/ScaleformMemoryHeap.h index 7209fbe1..504c6016 100644 --- a/include/RE/S/ScaleformMemoryHeap.h +++ b/include/RE/S/ScaleformMemoryHeap.h @@ -56,8 +56,8 @@ namespace RE::Scaleform public: static MemoryHeapPT* GetSingleton() { - static REL::Relocation memoryHeapPT(REL::ID(820297)); - return *memoryHeapPT; + static REL::Relocation singleton{ ID::Scaleform::MemoryHeapPT::Singleton }; + return *singleton; } }; } diff --git a/include/RE/T/TESContainer.h b/include/RE/T/TESContainer.h index f3b8f8d5..0e181484 100644 --- a/include/RE/T/TESContainer.h +++ b/include/RE/T/TESContainer.h @@ -34,7 +34,7 @@ namespace RE void AddObjectToContainer(TESForm* a_owner, TESBoundObject* a_obj, std::int32_t a_count, ContainerItemExtra* a_itemExtra) { using func_t = decltype(&TESContainer::AddObjectToContainer); - static REL::Relocation func{ REL::ID(85991) }; + static REL::Relocation func{ ID::TESContainer::AddObjectToContainer }; return func(this, a_owner, a_obj, a_count, a_itemExtra); } From e4d5facab51bfd3fab3bf3883b1b835fee3978c4 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:28:07 -0500 Subject: [PATCH 03/20] feat: `TES` --- include/RE/IDs.h | 5 +++++ include/RE/T/TES.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 include/RE/T/TES.h diff --git a/include/RE/IDs.h b/include/RE/IDs.h index c69a3740..c0a60bc5 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -452,6 +452,11 @@ namespace RE::ID inline constexpr REL::ID RegisterNativeFunction{ 187274 }; } + namespace TES + { + inline constexpr REL::ID Singleton{ 881024 }; + } + namespace TESActorBaseData { inline constexpr REL::ID GetLevel{ 85868 }; diff --git a/include/RE/T/TES.h b/include/RE/T/TES.h new file mode 100644 index 00000000..7731b41d --- /dev/null +++ b/include/RE/T/TES.h @@ -0,0 +1,42 @@ +#pragma once + +#include "RE/B/BSTEvent.h" + +namespace RE +{ + namespace BSResource::Archive2 + { + class StreamOpenedEvent; + } + + class TESObjectCELL; + + struct PositionPlayerEvent; + + class TES : + public BSTEventSink, // 000 + public BSTEventSink // 008 + { + public: + SF_RTTI_VTABLE(TES); + + virtual ~TES(); // 00 + + // override (BSTEventSink) + BSEventNotifyControl ProcessEvent(const BSResource::Archive2::StreamOpenedEvent& a_event, BSTEventSource* a_eventSource) override; // 01 - { return BSEventNotifyControl::kContinue; } + + // override (BSTEventSink) + BSEventNotifyControl ProcessEvent(const PositionPlayerEvent& a_event, BSTEventSource* a_eventSource) override; // 01 + + [[nodiscard]] static TES* GetSingleton() + { + static REL::Relocation singleton{ ID::TES::Singleton }; + return *singleton; + } + + // members + std::byte pad[0xD8]; // 010 + TESObjectCELL* interiorCell; // 0E8 + }; + static_assert(offsetof(TES, interiorCell) == 0xE8); +} From 6c4cd026bd905e6a1b29a769818a6594f88c5574 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:29:16 -0500 Subject: [PATCH 04/20] feat!: `Main` --- include/RE/IDs.h | 6 ++++++ include/RE/M/Main.h | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/RE/IDs.h b/include/RE/IDs.h index c0a60bc5..8da56734 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -324,6 +324,12 @@ namespace RE::ID inline constexpr REL::ID Notify{ 107339 }; } + namespace Main + { + inline constexpr REL::ID Singleton{ 881027 }; + inline constexpr REL::ID WorldRoot{ 887308 }; + } + namespace msvc { namespace type_info diff --git a/include/RE/M/Main.h b/include/RE/M/Main.h index 85dbc505..afcbb97f 100644 --- a/include/RE/M/Main.h +++ b/include/RE/M/Main.h @@ -31,19 +31,24 @@ namespace RE [[nodiscard]] static Main* GetSingleton() { - static REL::Relocation singleton{ REL::ID(881027) }; + static REL::Relocation singleton{ ID::Main::Singleton }; return *singleton; } - [[nodiscard]] static SceneGraphRoot* WorldRoot() + [[nodiscard]] static SceneGraphRoot* GetWorldRoot() { - static REL::Relocation worldRoot{ REL::ID(887308) }; + static REL::Relocation worldRoot{ ID::Main::WorldRoot }; return *worldRoot; } - [[nodiscard]] static NiCamera* WorldRootCamera() + [[nodiscard]] static NiCamera* GetWorldRootCamera() { - return WorldRoot()->worldCamera; + return GetWorldRoot()->worldCamera; } + + // members + std::byte pad008[0x440]; // 008 + bool isGameMenuPaused; // 448 }; + static_assert(offsetof(Main, isGameMenuPaused) == 0x448); } From 680c17951e9f4aa7c56650a08dfb816361764514 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:32:34 -0500 Subject: [PATCH 05/20] feat: `UIMessageQueue` --- include/RE/U/UIMessageQueue.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/RE/U/UIMessageQueue.h b/include/RE/U/UIMessageQueue.h index bf43c28f..c031916b 100644 --- a/include/RE/U/UIMessageQueue.h +++ b/include/RE/U/UIMessageQueue.h @@ -4,9 +4,10 @@ namespace RE { - enum UIMessage : std::uint32_t + enum class UI_MESSAGE_TYPE : std::uint32_t { kShow = 0, + kUpdate = 1, kHide = 2 }; @@ -14,6 +15,7 @@ namespace RE { public: virtual ~IUIMessageData() = default; + virtual void* GetRTTI() = 0; }; @@ -22,8 +24,8 @@ namespace RE public: virtual ~UIMessageData() = default; - UIMessage type; //08 - //...more? + UI_MESSAGE_TYPE type; // 08 + //...more? }; enum UI_MESSAGE_RESULT : std::int64_t @@ -42,11 +44,11 @@ namespace RE return *singleton; } - std::int64_t AddMessage(const BSFixedString& a_menuName, UIMessage a_message) + std::int64_t AddMessage(const BSFixedString& a_menuName, UI_MESSAGE_TYPE a_type) { using func_t = decltype(&UIMessageQueue::AddMessage); static REL::Relocation func{ ID::UIMessageQueue::AddMessage }; - return func(this, a_menuName, a_message); + return func(this, a_menuName, a_type); } }; } From cd51bfe1267d1564b3ad9c913da68a67f670daa7 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:34:05 -0500 Subject: [PATCH 06/20] feat: `NiRefObject` --- include/RE/N/NiRefObject.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 include/RE/N/NiRefObject.h diff --git a/include/RE/N/NiRefObject.h b/include/RE/N/NiRefObject.h new file mode 100644 index 00000000..d145a0ff --- /dev/null +++ b/include/RE/N/NiRefObject.h @@ -0,0 +1,15 @@ +#pragma once + +namespace RE +{ + class NiRefObject + { + public: + SF_RTTI_VTABLE(NiRefObject); + + virtual ~NiRefObject(); + + // members + std::uint32_t refCount; // 08 + }; +} From 049d2012c8ede8e009aadcdbc80ff0fcb87f9825 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:40:21 -0500 Subject: [PATCH 07/20] feat!: `BSPointerHandle` --- include/RE/B/BSPointerHandle.h | 155 +++++++++++++++++++++++++++++++++ include/RE/C/CombatGroup.h | 2 +- include/RE/E/Events.h | 9 +- include/RE/IDs.h | 5 ++ include/RE/M/Misc.h | 7 -- include/RE/Starfield.h | 3 + include/RE/T/TESObjectREFR.h | 20 ++--- src/RE/T/TESObjectREFR.cpp | 13 --- 8 files changed, 178 insertions(+), 36 deletions(-) create mode 100644 include/RE/B/BSPointerHandle.h diff --git a/include/RE/B/BSPointerHandle.h b/include/RE/B/BSPointerHandle.h new file mode 100644 index 00000000..4791ff04 --- /dev/null +++ b/include/RE/B/BSPointerHandle.h @@ -0,0 +1,155 @@ +#pragma once + +#include "RE/N/NiSmartPointer.h" + +namespace RE +{ + class Actor; + class HandleManager; + class Projectile; + class TESObjectREFR; + + template + class BSUntypedPointerHandle; + + template > + class BSPointerHandle; + + template + class BSPointerHandleManagerInterface; + + template + class BSUntypedPointerHandle + { + public: + using HandleType = std::uint32_t; + + enum : std::uint32_t + { + kFreeListBits = FREE_LIST_BITS, + kAgeShift = AGE_SHIFT, + }; + + BSUntypedPointerHandle() noexcept = default; + BSUntypedPointerHandle(const BSUntypedPointerHandle&) noexcept = default; + + explicit BSUntypedPointerHandle(HandleType a_handle) noexcept : + _handle(a_handle) + {} + + ~BSUntypedPointerHandle() noexcept { reset(); } + + BSUntypedPointerHandle& operator=(const BSUntypedPointerHandle&) noexcept = default; + + BSUntypedPointerHandle& operator=(HandleType a_rhs) noexcept + { + _handle = a_rhs; + return *this; + } + + [[nodiscard]] explicit operator bool() const noexcept { return has_value(); } + [[nodiscard]] bool has_value() const noexcept { return _handle != 0; } + + [[nodiscard]] HandleType value() const noexcept { return _handle; } + + void reset() noexcept { _handle = 0; } + + [[nodiscard]] friend bool operator==(const BSUntypedPointerHandle& a_lhs, const BSUntypedPointerHandle& a_rhs) noexcept + { + return a_lhs.value() == a_rhs.value(); + } + + private: + + HandleType _handle{ 0 }; // 00 + }; + + extern template class BSUntypedPointerHandle<>; + + template + class BSPointerHandle + { + public: + BSPointerHandle() noexcept = default; + + template + BSPointerHandle(BSPointerHandle a_rhs) noexcept + requires(std::convertible_to) : + _handle(a_rhs._handle) + {} + + ~BSPointerHandle() noexcept = default; + + template + BSPointerHandle& operator=(BSPointerHandle a_rhs) noexcept + requires(std::convertible_to) + { + _handle = a_rhs._handle; + return *this; + } + + void reset() noexcept { _handle.reset(); } + + [[nodiscard]] NiPointer get() const + { + return BSPointerHandleManagerInterface::GetSmartPointer(*this); + } + + [[nodiscard]] Handle::HandleType get_handle() noexcept + { + return _handle.value(); + } + + [[nodiscard]] explicit operator bool() const noexcept { return _handle.has_value(); } + + [[nodiscard]] friend bool operator==(const BSPointerHandle& a_lhs, const BSPointerHandle& a_rhs) noexcept + { + return a_lhs._handle == a_rhs._handle; + } + + [[nodiscard]] NiPointer operator*() const noexcept + { + assert(static_cast(*this)); + return get(); + } + + [[nodiscard]] NiPointer operator->() const noexcept + { + assert(static_cast(*this)); + return get(); + } + + private: + template + friend class BSPointerHandle; + + Handle _handle; // 00 + }; + + extern template class BSPointerHandle; + extern template class BSPointerHandle; + extern template class BSPointerHandle; + + template + class BSPointerHandleManagerInterface + { + public: + static bool GetSmartPointer(const BSPointerHandle& a_in, NiPointer& a_out) + { + using func_t = bool(*)(const BSPointerHandle& a_in, NiPointer& a_out); + static REL::Relocation func{ ID::BSPointerHandleManagerInterface::GetSmartPointer }; + return func(a_in, a_out); + } + + static NiPointer GetSmartPointer(const BSPointerHandle& a_in) + { + NiPointer out; + GetSmartPointer(a_in, out); + return out; + } + }; + + extern template class BSPointerHandleManagerInterface; + extern template class BSPointerHandleManagerInterface; + extern template class BSPointerHandleManagerInterface; +} diff --git a/include/RE/C/CombatGroup.h b/include/RE/C/CombatGroup.h index 11bff87f..2cec074c 100644 --- a/include/RE/C/CombatGroup.h +++ b/include/RE/C/CombatGroup.h @@ -29,7 +29,7 @@ namespace RE AITimer searchUpdateTimer; // 0E8 AITimer searchAreaUpdateTimer; // 0F0 AITimeStamp unkF8; // 0F8 - ActorHandle targetToSearchFor; // 0FC + BSPointerHandle targetToSearchFor; // 0FC BGSWorldLocation searchTargetLoc; // 100 float searchRadius; // 118 std::uint32_t unk11C; // 11C diff --git a/include/RE/E/Events.h b/include/RE/E/Events.h index f7b2bbee..92e3d679 100644 --- a/include/RE/E/Events.h +++ b/include/RE/E/Events.h @@ -1,6 +1,7 @@ #pragma once #include "RE/B/BSCoreTypes.h" +#include "RE/B/BSPointerHandle.h" #include "RE/B/BSTEvent.h" #include "RE/N/NiSmartPointer.h" @@ -198,7 +199,7 @@ namespace RE struct BGSActorEvent { // members - ActorHandle actor; // 00 + BSPointerHandle actor; // 00 }; static_assert(sizeof(BGSActorEvent) == 0x4); @@ -3773,9 +3774,9 @@ namespace RE public: // members DamageImpactData impactData; // 00 - std::uint32_t aggressor; // 40 - ActorHandle - std::uint32_t target; // 44 - ActorHandle - std::uint32_t sourceRef; // 48 - ObjectRefHandle + BSPointerHandle aggressor; // 40 + BSPointerHandle target; // 44 + BSPointerHandle sourceRef; // 48 std::uint64_t attackData; // 50 - NiPointer BGSObjectInstanceT weapon; // 58 SpellItem* criticalEffect; // 68 diff --git a/include/RE/IDs.h b/include/RE/IDs.h index 8da56734..37c07819 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -113,6 +113,11 @@ namespace RE::ID inline constexpr REL::ID unlock{ 73895 }; } + namespace BSPointerHandleManagerInterface + { + inline constexpr REL::ID GetSmartPointer{ 72432 }; + } + namespace BSReadWriteLock { inline constexpr REL::ID lock_read{ 178605 }; diff --git a/include/RE/M/Misc.h b/include/RE/M/Misc.h index a721de42..4039df5a 100644 --- a/include/RE/M/Misc.h +++ b/include/RE/M/Misc.h @@ -28,13 +28,6 @@ namespace RE return setting; } - inline bool LookupReferenceByHandle(const RefHandle& a_handle, NiPointer& a_refrOut) - { - using func_t = decltype(&LookupReferenceByHandle); - static REL::Relocation func{ ID::Misc::LookupReferenceByHandle }; - return func(a_handle, a_refrOut); - } - inline void PlayMenuSound(const char* a_editorID, const char* a_arg3 = nullptr, float a_arg4 = 0.0f) { std::uint32_t arg1 = 0; diff --git a/include/RE/Starfield.h b/include/RE/Starfield.h index 1cc99c74..1123b036 100644 --- a/include/RE/Starfield.h +++ b/include/RE/Starfield.h @@ -195,6 +195,7 @@ #include "RE/B/BSIntrusiveRefCounted.h" #include "RE/B/BSLock.h" #include "RE/B/BSLog.h" +#include "RE/B/BSPointerHandle.h" #include "RE/B/BSReflection.h" #include "RE/B/BSResourceEnums.h" #include "RE/B/BSScriptUtil.h" @@ -316,6 +317,7 @@ #include "RE/N/NiPoint3.h" #include "RE/N/NiPoint4.h" #include "RE/N/NiQuaternion.h" +#include "RE/N/NiRefObject.h" #include "RE/N/NiSmartPointer.h" #include "RE/N/NiTransform.h" #include "RE/O/Object.h" @@ -365,6 +367,7 @@ #include "RE/S/StructTypeInfo.h" #include "RE/S/SuspendedStack.h" #include "RE/T/TBO_InstanceData.h" +#include "RE/T/TES.h" #include "RE/T/TESAIForm.h" #include "RE/T/TESActorBase.h" #include "RE/T/TESActorBaseData.h" diff --git a/include/RE/T/TESObjectREFR.h b/include/RE/T/TESObjectREFR.h index 84bc3685..ac9008a7 100644 --- a/include/RE/T/TESObjectREFR.h +++ b/include/RE/T/TESObjectREFR.h @@ -5,6 +5,7 @@ #include "RE/B/BGSLocalizedString.h" #include "RE/B/BSContainer.h" #include "RE/B/BSLock.h" +#include "RE/B/BSPointerHandle.h" #include "RE/B/BSTEvent.h" #include "RE/B/BSTSmartPointer.h" #include "RE/E/ExtraDataList.h" @@ -357,9 +358,6 @@ namespace RE virtual void Unk_12E(); // 12E virtual void Unk_12F(); // 12F - static NiPointer LookupByHandle(RefHandle a_refHandle); - static bool LookupByHandle(RefHandle a_refHandle, NiPointer& a_refrOut); - void ForEachEquippedItem(std::function a_callback) const; void ForEachInventoryItem(std::function a_callback) const; @@ -396,14 +394,14 @@ namespace RE [[nodiscard]] bool WornHasKeyword(BGSKeyword* a_keyword); // members - OBJ_REFR data; // 78 - BSGuarded inventoryList; // 98 - TESObjectCELL* parentCell; // A8 - BSGuarded loadedData; // B0 - BSTSmartPointer extraDataList; // C0 - std::uint16_t scale; // C8 - std::uint8_t unkE2; // CA - std::uint8_t flags; // CB + OBJ_REFR data; // 80 + BSGuarded inventoryList; // A0 + TESObjectCELL* parentCell; // B0 + BSGuarded loadedData; // B8 + BSTSmartPointer extraDataList; // C8 + std::uint16_t scale; // D0 + std::uint8_t unkE2; // D2 + std::uint8_t flags; // D3 private: void AddLockChange(); diff --git a/src/RE/T/TESObjectREFR.cpp b/src/RE/T/TESObjectREFR.cpp index fc767951..d87051ce 100644 --- a/src/RE/T/TESObjectREFR.cpp +++ b/src/RE/T/TESObjectREFR.cpp @@ -2,22 +2,9 @@ #include "RE/B/BGSInventoryItem.h" #include "RE/E/ExtraLock.h" -#include "RE/M/Misc.h" namespace RE { - NiPointer TESObjectREFR::LookupByHandle(RefHandle a_refHandle) - { - NiPointer ref; - LookupReferenceByHandle(a_refHandle, ref); - return ref; - } - - bool TESObjectREFR::LookupByHandle(RefHandle a_refHandle, NiPointer& a_refrOut) - { - return LookupReferenceByHandle(a_refHandle, a_refrOut); - } - void TESObjectREFR::ForEachEquippedItem(std::function a_callback) const { ForEachInventoryItem([&](const BGSInventoryItem& a_invItem) { From 33e27dc7a3a241345584c8db712b1c0a46898a52 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:40:58 -0500 Subject: [PATCH 08/20] feat: `MenuTopicManager` --- include/RE/IDs.h | 5 +++++ include/RE/M/MenuTopicManager.h | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 include/RE/M/MenuTopicManager.h diff --git a/include/RE/IDs.h b/include/RE/IDs.h index 37c07819..ebd15f1b 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -359,6 +359,11 @@ namespace RE::ID inline constexpr REL::ID GetThreadScrapHeap{ 36848 }; } + namespace MenuTopicManager + { + inline constexpr REL::ID Singleton{ 879316 }; + } + namespace Misc { inline constexpr REL::ID DebugNotification{ 138728 }; diff --git a/include/RE/M/MenuTopicManager.h b/include/RE/M/MenuTopicManager.h new file mode 100644 index 00000000..8bbee121 --- /dev/null +++ b/include/RE/M/MenuTopicManager.h @@ -0,0 +1,26 @@ +#pragma once + +#include "RE/B/BSTEvent.h" +#include "RE/B/BSTSingleton.h" + +namespace RE +{ + struct MenuOpenCloseEvent; + struct PositionPlayerEvent; + + class MenuTopicManager : + public BSTSingletonSDM, // 00 + public BSTEventSink, // 08 + public BSTEventSink // 10 + { + public: + [[nodiscard]] static MenuTopicManager* GetSingleton() + { + static REL::Relocation singleton{ ID::MenuTopicManager::Singleton }; + return *singleton; + } + + // members + BSPointerHandle speaker; // 14 + }; +} From 812a5b67f3976e65f2cd5a826c79fc28eb87ccd5 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:43:12 -0500 Subject: [PATCH 09/20] feat: `TESNPC` --- include/RE/T/TESActorBase.h | 8 +++++++- include/RE/T/TESNPC.h | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/include/RE/T/TESActorBase.h b/include/RE/T/TESActorBase.h index d1dd40b0..3247ca2b 100644 --- a/include/RE/T/TESActorBase.h +++ b/include/RE/T/TESActorBase.h @@ -7,6 +7,7 @@ #include "RE/B/BGSPerkRankArray.h" #include "RE/B/BGSPropertySheet.h" #include "RE/B/BGSSkinForm.h" +#include "RE/S/Sexes.h" #include "RE/T/TESAIForm.h" #include "RE/T/TESActorBaseData.h" #include "RE/T/TESBoundAnimObject.h" @@ -18,7 +19,7 @@ namespace RE { class TESCombatStyle; - class TESActorBase : + class __declspec(novtable) TESActorBase : public TESBoundAnimObject, // 000 public TESActorBaseData, // 0E0 public TESContainer, // 168 @@ -43,6 +44,11 @@ namespace RE virtual TESCombatStyle* GetCombatStyle(); // 83 virtual void SetCombatStyle(TESCombatStyle*); // 84 virtual TESForm* GetAsForm(); // 85 + + [[nodiscard]] SEX GetSex() const + { + return IsFemale() ? SEX::kFemale : SEX::kMale; + } }; static_assert(sizeof(TESActorBase) == 0x270); } diff --git a/include/RE/T/TESNPC.h b/include/RE/T/TESNPC.h index c9a5862d..a66eba4d 100644 --- a/include/RE/T/TESNPC.h +++ b/include/RE/T/TESNPC.h @@ -10,7 +10,6 @@ #include "RE/B/BSTEvent.h" #include "RE/B/BSTScatterTable.h" #include "RE/N/NiPoint3.h" -#include "RE/S/Sexes.h" #include "RE/T/TESActorBase.h" #include "RE/T/TESRace.h" #include "RE/T/TESRaceForm.h" @@ -27,7 +26,7 @@ namespace RE class TESFaction; class TESFurniture; - class TESNPC : + class __declspec(novtable) TESNPC : public TESActorBase, // 000 public TESRaceForm, // 278 public BGSOverridePackCollection, // 288 @@ -56,9 +55,6 @@ namespace RE ~TESNPC() override; // 00 - [[nodiscard]] TESClass* GetClass() const { return npcClass; } - [[nodiscard]] TESRace* GetRace() const { return formRace; } - [[nodiscard]] bool ContainsKeyword(std::string_view a_editorID) { if (ContainsKeywordString(a_editorID)) @@ -84,9 +80,36 @@ namespace RE return func(this, a_source); } - [[nodiscard]] SEX GetSex() const + [[nodiscard]] TESClass* GetClass() const + { + return npcClass; + } + + [[nodiscard]] TESRace* GetRace() const { - return IsFemale() ? SEX::kFemale : SEX::kMale; + return formRace; + } + + [[nodiscard]] TESNPC* GetRootFaceNPC() noexcept + { + return const_cast(static_cast(this)->GetRootFaceNPC()); + } + + [[nodiscard]] const TESNPC* GetRootFaceNPC() const noexcept + { + auto root = this; + while (root->faceNPC) + root = root->faceNPC; + + return root; + } + + [[nodiscard]] TESObjectARMO* GetSkin() const + { + if (formSkin) + return formSkin; + + return formRace ? formRace->formSkin : nullptr; } [[nodiscard]] bool HasKeyword(std::string_view a_editorID) From 89792018eefb284a267c275dff3b26f8d93f6ea3 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:43:31 -0500 Subject: [PATCH 10/20] feat: `ConsoleLog` --- include/RE/C/ConsoleLog.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/RE/C/ConsoleLog.h b/include/RE/C/ConsoleLog.h index d50b8dfc..36434bc3 100644 --- a/include/RE/C/ConsoleLog.h +++ b/include/RE/C/ConsoleLog.h @@ -30,6 +30,15 @@ namespace RE func(this, a_str); } + // std::format rules, has compile time checking + template + void Log(const std::format_string a_fmt, Args&&... a_args) + { + auto str = std::vformat(a_fmt.get(), std::make_format_args(a_args...)); + str += '\n'; + AddString(str.c_str()); + } + void Print(const char* a_fmt, std::va_list a_args) { using func_t = decltype(&ConsoleLog::Print); @@ -46,13 +55,6 @@ namespace RE va_end(args); } - // std::format rules, has compile time checking - template - void Log(const std::format_string a_fmt, Args&&... a_args) - { - AddString(std::vformat(a_fmt.get(), std::make_format_args(a_args...)).c_str()); - } - void SetUseConsoleOverlay(bool a_value) { useConsoleOverlay = a_value; From 03e821676689573039228fca8786e2493b8b254d Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:45:00 -0500 Subject: [PATCH 11/20] feat: `TESFaction` --- include/RE/T/TESFaction.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/include/RE/T/TESFaction.h b/include/RE/T/TESFaction.h index 8086335c..380c9f5d 100644 --- a/include/RE/T/TESFaction.h +++ b/include/RE/T/TESFaction.h @@ -5,9 +5,17 @@ namespace RE { - class TESFaction : - public TESForm, // 000 - public TESFullName // 030 + class TESReactionForm : + public BaseFormComponent // 00 + { + public: + SF_RTTI(TESReactionForm); + }; + + class __declspec(novtable) TESFaction : + public TESForm, // 000 + public TESFullName, // 038 + public TESReactionForm // 040 { public: SF_RTTI_VTABLE(TESFaction); From 420f705ed479fe7dd35c4d3c701ca9b8fa2faf70 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:45:44 -0500 Subject: [PATCH 12/20] feat: `TESPackage` --- include/RE/T/TESPackage.h | 42 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/include/RE/T/TESPackage.h b/include/RE/T/TESPackage.h index e50cbad6..b4cce708 100644 --- a/include/RE/T/TESPackage.h +++ b/include/RE/T/TESPackage.h @@ -4,13 +4,51 @@ namespace RE { - class TESPackage : public TESForm + class TESPackageData; + + struct PACKAGE_DATA + { + // members + std::uint32_t packageFlags; // 0 + std::int8_t packageType; // 4 + std::int8_t interruptOverrideType; // 5 + std::int8_t maxSpeed; // 6 + std::uint16_t foBehaviorFlags; // 8 + std::uint16_t packageSpecificFlags; // A + }; + static_assert(sizeof(PACKAGE_DATA) == 0xC); + + struct PackageLocation + { + + }; + + struct PackageTarget + { + std::uint8_t type; + union + { + BSPointerHandle refHandle; + TESForm* object; + }; + std::int32_t value; + }; + static_assert(sizeof(PackageTarget) == 0x18); + + class __declspec(novtable) TESPackage : + public TESForm // 00 { public: SF_RTTI_VTABLE(TESPackage); SF_FORMTYPE(PACK); ~TESPackage() override; // 00 + + // members + PACKAGE_DATA packageData; // 38 + TESPackageData* packageData2; // 48 + PackageLocation* packageLocation; // 50 + PackageTarget* packageTarget; // 58 }; - //static_assert(sizeof(TESPackage) == 0xE8); + static_assert(offsetof(TESPackage, packageData2) == 0x48); } From 21bc57ecf2049b286c2746e463c576ef58b5efbc Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:47:40 -0500 Subject: [PATCH 13/20] feat: `TESQuest` --- include/RE/T/TESQuest.h | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/include/RE/T/TESQuest.h b/include/RE/T/TESQuest.h index cc73db77..833ea0ad 100644 --- a/include/RE/T/TESQuest.h +++ b/include/RE/T/TESQuest.h @@ -4,6 +4,18 @@ namespace RE { + class BGSStoryEvent; + + struct QUEST_DATA + { + // members + float questDelayTime; // 0 + std::uint16_t flags; // 4 + std::int8_t priority; // 6 + std::uint8_t questType; // 7 + }; + static_assert(sizeof(QUEST_DATA) == 0x8); + class __declspec(novtable) TESQuest : public BGSStoryManagerTreeForm { @@ -11,17 +23,6 @@ namespace RE SF_RTTI_VTABLE(TESQuest); SF_FORMTYPE(QUST); - // DNAM - struct QUEST_DATA - { - // members - float questDelayTime; // 0 - std::uint16_t flags; // 4 - std::int8_t priority; // 6 - std::uint8_t questType; // 7 - }; - static_assert(sizeof(QUEST_DATA) == 0x8); - ~TESQuest() override; // 00 [[nodiscard]] bool IsStageDone(std::uint16_t a_stage) const @@ -32,7 +33,10 @@ namespace RE } // members - std::byte pad38[0xD6]; // 038 - QUEST_DATA data; // 108 + std::byte pad038[0xD0]; // 038 + QUEST_DATA data; // 108 + std::byte pad110[0x220]; // 110 + BGSStoryEvent* startEventData; // 330 }; + static_assert(offsetof(TESQuest, startEventData) == 0x330); } From 8ab0fa7fad24db65eff205428c25d7fd8d88f12f Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:48:27 -0500 Subject: [PATCH 14/20] feat: `Events` --- include/RE/E/Events.h | 106 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/include/RE/E/Events.h b/include/RE/E/Events.h index 92e3d679..e8e5914f 100644 --- a/include/RE/E/Events.h +++ b/include/RE/E/Events.h @@ -12,6 +12,7 @@ namespace RE class BGSLocation; class bhkNPCollisionObject; class HUDModeType; + class SpellItem; class TESBoundObject; class TESObjectBOOK; class TESObjectCELL; @@ -1226,6 +1227,23 @@ namespace RE } }; + struct DaysPassed + { + struct Event + { + [[nodiscard]] static BSTEventSource* GetEventSource() + { + using func_t = decltype(&DaysPassed::Event::GetEventSource); + static REL::Relocation func{ REL::ID(148411) }; + return func(); + } + + // members + std::int32_t days; // 00 + }; + static_assert(sizeof(DaysPassed::Event) == 0x4); + }; + struct DialogueMenu_OnDialogueSelect { [[nodiscard]] static BSTEventSource* GetEventSource() @@ -1359,6 +1377,32 @@ namespace RE }; }; + struct HourPassed + { + struct Event + { + [[nodiscard]] static BSTEventSource* GetEventSource() + { + using func_t = decltype(&HourPassed::Event::GetEventSource); + static REL::Relocation func{ REL::ID(148412) }; + return func(); + } + }; + }; + + struct HoursPassed + { + struct Event + { + [[nodiscard]] static BSTEventSource* GetEventSource() + { + using func_t = decltype(&HoursPassed::Event::GetEventSource); + static REL::Relocation func{ REL::ID(167218) }; + return func(); + } + }; + }; + struct HUDModeEvent { [[nodiscard]] static BSTEventSource* GetEventSource() @@ -3220,6 +3264,23 @@ namespace RE }; }; + struct SpellsLearned + { + struct Event + { + [[nodiscard]] static BSTEventSource* GetEventSource() + { + using func_t = decltype(&SpellsLearned::Event::GetEventSource); + static REL::Relocation func{ REL::ID(151932) }; + return func(); + } + + // members + SpellItem* spell; // 00 + }; + static_assert(sizeof(SpellsLearned::Event) == 0x8); + }; + struct StarMap { struct PlanetTraitKnownEvent @@ -3819,6 +3880,20 @@ namespace RE } }; + struct TESLockChangedEvent + { + [[nodiscard]] static BSTEventSource* GetEventSource() + { + using func_t = decltype(&TESLockChangedEvent::GetEventSource); + static REL::Relocation func{ REL::ID(107174) }; + return func(); + } + + // members + const NiPointer ref; + }; + static_assert(sizeof(TESLockChangedEvent) == 0x8); + struct TESMissionAcceptedEvent { [[nodiscard]] static BSTEventSource* GetEventSource() @@ -3908,6 +3983,37 @@ namespace RE }; static_assert(sizeof(TESResolveNPCTemplatesEvent) == 0x4); + struct TESSleepStartEvent + { + [[nodiscard]] static BSTEventSource* GetEventSource() + { + using func_t = decltype(&TESSleepStartEvent::GetEventSource); + static REL::Relocation func{ REL::ID(107199) }; + return func(); + } + + // members + float timeStart; // 00 + float timeEnd; // 04 + NiPointer bed; // 08 + }; + static_assert(sizeof(TESSleepStartEvent) == 0x10); + + struct TESSleepStopEvent + { + [[nodiscard]] static BSTEventSource* GetEventSource() + { + using func_t = decltype(&TESSleepStopEvent::GetEventSource); + static REL::Relocation func{ REL::ID(107200) }; + return func(); + } + + // members + bool interrupted; // 00 + NiPointer bed; // 01 + }; + static_assert(sizeof(TESSleepStopEvent) == 0x10); + struct TraitDiscoveryTextEvent { struct Event From 1149801af48ee7eee87e81562fd24bd3fd6a5b68 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:48:56 -0500 Subject: [PATCH 15/20] feat: `AITimeStamp` --- include/RE/A/AITimeStamp.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 include/RE/A/AITimeStamp.h diff --git a/include/RE/A/AITimeStamp.h b/include/RE/A/AITimeStamp.h new file mode 100644 index 00000000..c8e1e802 --- /dev/null +++ b/include/RE/A/AITimeStamp.h @@ -0,0 +1,12 @@ +#pragma once + +namespace RE +{ + class AITimeStamp + { + public: + // members + float timeStamp{ -3.4028235e38f }; // 00 + }; + static_assert(sizeof(AITimeStamp) == 0x4); +} From 6a32f969d05f2be53fabb4e59791ed9116b58ed6 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:50:05 -0500 Subject: [PATCH 16/20] feat: `DetectionState` --- include/RE/D/DetectionState.h | 26 ++++++++++++++++++++++++++ include/RE/Starfield.h | 3 +++ 2 files changed, 29 insertions(+) create mode 100644 include/RE/D/DetectionState.h diff --git a/include/RE/D/DetectionState.h b/include/RE/D/DetectionState.h new file mode 100644 index 00000000..b783e3e2 --- /dev/null +++ b/include/RE/D/DetectionState.h @@ -0,0 +1,26 @@ +#pragma once + +#include "RE/A/AITimeStamp.h" +#include "RE/N/NiPoint3.h" +#include "RE/N/NiRefObject.h" + +namespace RE +{ + struct DetectionLevels + { + std::int16_t visual; + std::int16_t sound; + }; + + class __declspec(novtable) DetectionState : + public NiRefObject + { + public: + SF_RTTI_VTABLE(DetectionState); + + // members + std::byte pad10[0x6C]; // 10 + DetectionLevels detectionLevel; // 7C + }; + static_assert(offsetof(DetectionState, detectionLevel) == 0x7C); +} diff --git a/include/RE/Starfield.h b/include/RE/Starfield.h index 1123b036..bd1f5dbf 100644 --- a/include/RE/Starfield.h +++ b/include/RE/Starfield.h @@ -3,6 +3,7 @@ #include "SFSE/Impl/PCH.h" #include "RE/A/AIProcess.h" +#include "RE/A/AITimeStamp.h" #include "RE/A/AVMData.h" #include "RE/A/Actor.h" #include "RE/A/ActorEquipManager.h" @@ -229,6 +230,7 @@ #include "RE/C/ConsoleLog.h" #include "RE/D/DebuggerMessages.h" #include "RE/D/DecalData.h" +#include "RE/D/DetectionState.h" #include "RE/E/EffectArchetypes.h" #include "RE/E/EffectItem.h" #include "RE/E/EffectSetting.h" @@ -304,6 +306,7 @@ #include "RE/M/MemoryManager.h" #include "RE/M/MenuOpenCloseEvent.h" #include "RE/M/MenuPaperDoll.h" +#include "RE/M/MenuTopicManager.h" #include "RE/M/Misc.h" #include "RE/M/MissileProjectile.h" #include "RE/M/msvc.h" From b6b7ed93c0c415ed46d95c7c3b875cc16f72a940 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:50:46 -0500 Subject: [PATCH 17/20] feat: `ActorKnowledge` --- include/RE/A/ActorKnowledge.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 include/RE/A/ActorKnowledge.h diff --git a/include/RE/A/ActorKnowledge.h b/include/RE/A/ActorKnowledge.h new file mode 100644 index 00000000..a07b28d8 --- /dev/null +++ b/include/RE/A/ActorKnowledge.h @@ -0,0 +1,27 @@ +#pragma once + +#include "RE/A/AITimeStamp.h" +#include "RE/B/BSPointerHandle.h" +#include "RE/N/NiRefObject.h" +#include "RE/N/NiSmartPointer.h" + +namespace RE +{ + class Actor; + class DetectionState; + + class __declspec(novtable) ActorKnowledge : + public NiRefObject + { + public: + SF_RTTI_VTABLE(ActorKnowledge); + + // members + BSPointerHandle owner; // 10 + BSPointerHandle target; // 14 + AITimeStamp factionFightReaction; // 18 + float shouldAttackTargetTimeStamp; // 1C + float damagePerSecond; // 20 + NiPointer detectionState; // 28 + }; +} From 8d6a17c4f9a385b9fedd1ebb72ef015fa0a30e1e Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:52:04 -0500 Subject: [PATCH 18/20] feat: `ProcessLists` --- include/RE/B/BSCoreTypes.h | 2 -- include/RE/IDs.h | 1 + include/RE/P/ProcessLists.h | 44 +++++++++++++++++++++++++++---------- include/RE/Starfield.h | 1 + 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/include/RE/B/BSCoreTypes.h b/include/RE/B/BSCoreTypes.h index ffc97fb9..29c9f638 100644 --- a/include/RE/B/BSCoreTypes.h +++ b/include/RE/B/BSCoreTypes.h @@ -3,6 +3,4 @@ namespace RE { using TESFormID = std::uint32_t; - using RefHandle = std::uint32_t; - using ActorHandle = std::uint32_t; } diff --git a/include/RE/IDs.h b/include/RE/IDs.h index ebd15f1b..474763c7 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -399,6 +399,7 @@ namespace RE::ID { inline constexpr REL::ID AreHostileActorsNear{ 154040 }; inline constexpr REL::ID Singleton{ 878338 }; + inline constexpr REL::ID ToggleAI{ 154056 }; } namespace REFR_LOCK diff --git a/include/RE/P/ProcessLists.h b/include/RE/P/ProcessLists.h index b39f8ea2..a10b5116 100644 --- a/include/RE/P/ProcessLists.h +++ b/include/RE/P/ProcessLists.h @@ -1,5 +1,6 @@ #pragma once +#include "RE/B/BSPointerHandle.h" #include "RE/B/BSTArray.h" #include "RE/B/BSTEvent.h" #include "RE/B/BSTSingleton.h" @@ -26,25 +27,46 @@ namespace RE return *singleton; } - [[nodiscard]] bool AreHostileActorsNear(BSScrapArray* a_hostileActors = nullptr) + [[nodiscard]] bool AreHostileActorsNear(BSScrapArray>* a_hostileActors = nullptr) { using func_t = decltype(&ProcessLists::AreHostileActorsNear); static REL::Relocation func{ ID::ProcessLists::AreHostileActorsNear }; return func(this, a_hostileActors); } + void EnableAI(bool a_enable) + { + using func_t = decltype(&ProcessLists::EnableAI); + static REL::Relocation func{ ID::ProcessLists::ToggleAI }; + func(this, a_enable); + } + // members - std::byte pad10[0x3B]; // 010 - bool runDetection; // 044 - std::byte pad45[0x13]; // 045 - BSTArray highActorHandles; // 058 - BSTArray lowActorHandles; // 068 - BSTArray middleHighActorHandles; // 078 - BSTArray middleLowActorHandles; // 088 + std::byte pad010[0x14]; // 010 + std::int32_t numberHighActors; // 020 + std::int32_t numberFullyEnabledHighActors; // 024 + std::byte pad028[0x1C]; // 028 + bool runDetection; // 044 + std::byte unk045; // 045 + bool processHigh; // 046 + bool processLow; // 047 + bool processMiddleHigh; // 048 + bool processMiddleLow; // 049 + bool processSchedules; // 04A + bool showSubtitles; // 04B + std::byte pad04C[0x6]; // 04C + BSTArray> highActorHandles; // 058 + BSTArray> lowActorHandles; // 068 + BSTArray> middleHighActorHandles; // 078 + BSTArray> middleLowActorHandles; // 088 + std::byte pad098[0x154]; // 098 + bool runSchedules; // 1EC + bool runMovement; // 1ED + bool runAnimations; // 1EE }; + static_assert(offsetof(ProcessLists, numberHighActors) == 0x20); static_assert(offsetof(ProcessLists, runDetection) == 0x44); + static_assert(offsetof(ProcessLists, showSubtitles) == 0x4B); static_assert(offsetof(ProcessLists, highActorHandles) == 0x58); - static_assert(offsetof(ProcessLists, lowActorHandles) == 0x68); - static_assert(offsetof(ProcessLists, middleHighActorHandles) == 0x78); - static_assert(offsetof(ProcessLists, middleLowActorHandles) == 0x88); + static_assert(offsetof(ProcessLists, runSchedules) == 0x1EC); } diff --git a/include/RE/Starfield.h b/include/RE/Starfield.h index bd1f5dbf..8711f2b6 100644 --- a/include/RE/Starfield.h +++ b/include/RE/Starfield.h @@ -7,6 +7,7 @@ #include "RE/A/AVMData.h" #include "RE/A/Actor.h" #include "RE/A/ActorEquipManager.h" +#include "RE/A/ActorKnowledge.h" #include "RE/A/ActorPackage.h" #include "RE/A/ActorState.h" #include "RE/A/ActorUtils.h" From ddeba6fb7331fc7c679c308d166031638439a02c Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:53:39 -0500 Subject: [PATCH 19/20] feat: `AIProcess` --- include/RE/A/AIProcess.h | 286 ++++++++++++++++++++++++++++++++++----- 1 file changed, 254 insertions(+), 32 deletions(-) diff --git a/include/RE/A/AIProcess.h b/include/RE/A/AIProcess.h index 0e7e2f99..82763a9d 100644 --- a/include/RE/A/AIProcess.h +++ b/include/RE/A/AIProcess.h @@ -1,44 +1,266 @@ #pragma once -#include "ActorPackage.h" +#include "RE/A/ActorPackage.h" +#include "RE/B/BSFixedString.h" +#include "RE/B/BSLock.h" +#include "RE/B/BSPointerHandle.h" +#include "RE/B/BSTArray.h" +#include "RE/B/BSTList.h" +#include "RE/N/NiPoint3.h" +#include "RE/N/NiSmartPointer.h" namespace RE { - struct MiddleLowProcessData; - struct MiddleHighProcessData; - struct HighProcessData; + class ActorKnowledge; + class bhkCharacterController; + class DialogueItem; + class MagicItem; + class ObjectsToAcquire; + class TESBoundObject; + class TESIdleForm; + class TESObjectREFR; + class TESObjectWEAP; + + enum class COMMAND_TYPE : std::int32_t + { + kNone = 0, + kCall = 1, + kFollow = 2, + kMove = 3, + kAttack = 4, + kInspect = 5, + kRetrieve = 6, + kStay = 7, + kRelease = 8, + kHeal = 9, + kAssign = 10, + kRide = 11, + kEnter = 12, + }; + + struct HighProcessData + { + enum class FADE_STATE : std::int32_t + { + kNormal = 0, + kIn = 1, + kOut = 2, + kTeleportIn = 3, + kTeleportOut = 4, + kOutDisable = 5, + kOutDelete = 6 + }; + + // members + std::byte pad000[0x13C]; // 000 + FADE_STATE fadeState; // 13C + std::byte pad140[0x1B8]; // 140 + BSFixedStringCS strVoiceSubtitle; // 2F8 + std::byte pad300[0x14]; // 300 + BSReadWriteLock knowledgeLock; // 314 + std::byte pad31C[0x2E]; // 31C + NiPoint3 deathForceDirection; // 34C + float deathForce; // 358 + std::byte pad35C[0x28]; // 35C + float packageEvalTimer; // 384 + float useItemTimer; // 388 + float procedureEvalTimer; // 38C + std::byte pad390[0x40]; // 390 + float greetingTimer; // 3D0 + std::byte pad3D4[0x4]; // 3D4 + float idleTimer; // 3D8 + std::byte pad3DC[0x2C]; // 3DC + TESIdleForm* idleToPlay; // 408 + std::byte pad410[0x8]; // 410 + TESPackage* commandPackage; // 418 + std::byte pad420[0x18]; // 420 + BSPointerHandle idleTarget; // 438 + std::byte pad43C[0x4]; // 43C + DialogueItem* greetTopic; // 440 + std::byte pad448[0x30]; // 448 + float lightLevel; // 478 + std::byte pad47C[0x84]; // 47C + float tryTalkIdleTimer; // 500 + std::uint16_t tryTalk; // 504 + std::byte pad506[0xA]; // 506 + COMMAND_TYPE commandType; // 510 + std::byte pad514[0x47]; // 514 + bool greetingFlag; // 55B + bool pickNewIdle; // 55C + bool skipVoiceEndIdleStop; // 55D + bool weaponAlertDrawn; // 55E + bool dialoguewithPlayer; // 55F + bool inCommandState; // 560 + bool inWorkshopCommandState; // 561 + bool continuingPackageForPC; // 562 + bool activateAnim; // 563 + bool stop; // 564 + std::byte pad562[0x18]; // 562 + bool playerActivated; // 57D + bool itemEquipQueued; // 57E + bool doingCommand; // 57F + bool capLineFired; // 580 + std::byte pad581[0x2]; // 581 + bool processingForceEquip; // 583 + bool capLinePlaying; // 584 + }; + static_assert(offsetof(HighProcessData, fadeState) == 0x13C); + static_assert(offsetof(HighProcessData, strVoiceSubtitle) == 0x2F8); + static_assert(offsetof(HighProcessData, knowledgeLock) == 0x314); + static_assert(offsetof(HighProcessData, deathForceDirection) == 0x34C); + static_assert(offsetof(HighProcessData, packageEvalTimer) == 0x384); + static_assert(offsetof(HighProcessData, idleTimer) == 0x3D8); + static_assert(offsetof(HighProcessData, idleToPlay) == 0x408); + static_assert(offsetof(HighProcessData, greetTopic) == 0x440); + static_assert(offsetof(HighProcessData, lightLevel) == 0x478); + static_assert(offsetof(HighProcessData, tryTalkIdleTimer) == 0x500); + static_assert(offsetof(HighProcessData, commandType) == 0x510); + static_assert(offsetof(HighProcessData, pickNewIdle) == 0x55C); + static_assert(offsetof(HighProcessData, inCommandState) == 0x560); + static_assert(offsetof(HighProcessData, stop) == 0x564); + static_assert(offsetof(HighProcessData, playerActivated) == 0x57D); + static_assert(offsetof(HighProcessData, capLineFired) == 0x580); + static_assert(offsetof(HighProcessData, capLinePlaying) == 0x584); + + struct MiddleLowProcessData + { + // members + std::int32_t hourPackageEvaluated; // 00 + }; + + struct MiddleHighProcessData + { + // members + std::byte pad000[0x38]; // 000 + ActorPackage runOncePackage; // 038 + std::byte pad068[0x200]; // 068 + BSReadWriteLock equippedItemsLock; // 268 + std::byte pad270[0x1B4]; // 270 + BSPointerHandle currentFurniture; // 424 + BSPointerHandle occupiedFurniture; // 428 + std::byte pad42C[0x1C]; // 42C + MagicItem* currentPackageSpell; // 448 + TESObjectWEAP* lastBoundWeapon; // 450 + NiPointer charController; // 458 + std::byte pad460[0xA8]; // 460 + std::uint32_t deferredKill; // 508 + std::byte pad50C[0x74]; // 50C + std::int16_t animActionSuccess; // 580 + std::byte pad582[0x7]; // 582 + bool aimingTarget; // 589 + bool doneClothesChange; // 58A + std::byte pad58B[0x6]; // 58B + bool playedBeginIdles; // 591 + std::byte pad592[0x7]; // 592 + bool eating; // 599 + bool calcLight; // 59A + std::byte pad59B[0x6]; // 59B + bool killQueued; // 5A1 + bool ragdollInstant; // 5A2 + bool scriptDeferredKill; // 5A3 + bool furnitureEntryLeftFootFirst; // 5A4 + bool furnitureAnimationPlayed; // 5A5 + bool queuedInstantInteractionAnimation; // 5A6 + bool queuedModifyInitialAnimationPose; // 5A7 + bool avoidPlayer; // 5A8 + }; + static_assert(offsetof(MiddleHighProcessData, runOncePackage) == 0x38); + static_assert(offsetof(MiddleHighProcessData, equippedItemsLock) == 0x268); + static_assert(offsetof(MiddleHighProcessData, currentFurniture) == 0x424); + static_assert(offsetof(MiddleHighProcessData, occupiedFurniture) == 0x428); + static_assert(offsetof(MiddleHighProcessData, currentPackageSpell) == 0x448); + static_assert(offsetof(MiddleHighProcessData, charController) == 0x458); + static_assert(offsetof(MiddleHighProcessData, deferredKill) == 0x508); + static_assert(offsetof(MiddleHighProcessData, animActionSuccess) == 0x580); + static_assert(offsetof(MiddleHighProcessData, doneClothesChange) == 0x58A); + static_assert(offsetof(MiddleHighProcessData, playedBeginIdles) == 0x591); + static_assert(offsetof(MiddleHighProcessData, calcLight) == 0x59A); + static_assert(offsetof(MiddleHighProcessData, killQueued) == 0x5A1); + static_assert(offsetof(MiddleHighProcessData, avoidPlayer) == 0x5A8); - // F8 class AIProcess { public: - MiddleLowProcessData* middleLow; // 00 - MiddleHighProcessData* middleHigh; // 08 - HighProcessData* high; // 10 - ActorPackage currentPackage; // 18 - float hourLastProcessed; // 48 - std::uint32_t unk4C; // 4C - std::uint64_t unk50; // 50 - std::uint64_t unk58; // 58 - std::uint64_t unk60; // 60 - std::uint64_t unk68; // 68 - std::uint64_t unk70; // 70 - std::uint64_t unk78; // 78 - std::uint64_t unk80; // 80 - std::uint64_t unk88; // 88 - std::uint64_t unk90; // 90 - std::uint64_t unk98; // 98 - std::uint64_t unkA0; // A0 - std::uint64_t unkA8; // A8 - std::uint64_t unkB0; // B0 - std::uint64_t unkB8; // B8 - std::uint64_t unkC0; // C0 - std::uint64_t unkC8; // C8 - std::uint64_t unkD0; // D0 - std::uint64_t unkD8; // D8 - std::uint64_t unkE0; // E0 - std::uint64_t unkE8; // E8 - std::uint64_t unkF0; // F0 + float GetActorLightLevel() const + { + return high ? high->lightLevel : 0.0f; + } + + ActorPackage* GetActorPackage() + { + return std::addressof(currentPackage); + } + + ActorPackage* GetActorPackageRunning() + { + if (middleHigh && middleHigh->runOncePackage.package) + return std::addressof(middleHigh->runOncePackage); + + return std::addressof(currentPackage); + } + + bool GetCommandState() const + { + return high && high->inCommandState; + } + + bool GetCommandWorkshopState() const + { + return high && high->inWorkshopCommandState; + } + + COMMAND_TYPE GetCommandType() const + { + return high ? high->commandType : COMMAND_TYPE::kNone; + } + + bool IsPlayingPCap() const + { + return high && high->capLinePlaying; + } + + bool IsRunningRunOnce() const + { + return middleHigh && middleHigh->runOncePackage.package; + } + + // members + MiddleLowProcessData* middleLow; // 00 + MiddleHighProcessData* middleHigh; // 08 + HighProcessData* high; // 10 + ActorPackage currentPackage; // 18 + float hourLastProcessed; // 48 + float timeAdjustmentsMade; // 4C + std::uint64_t unk50; // 50 + std::uint64_t unk58; // 58 + std::uint64_t unk60; // 60 + BSSimpleList objectList; // 68 + BSSimpleList genericLocationsList; // 78 + ObjectsToAcquire* acquireObject; // 88 + ObjectsToAcquire* savedAcquireObject; // 90 + std::uint64_t unk98; // 98 + std::uint64_t unkA0; // A0 + std::uint64_t unkA8; // A8 + std::uint64_t unkB0; // B0 + TESBoundObject* itemBeingUsed; // B8 + BSPointerHandle followTarget; // C0 + BSPointerHandle target; // C4 + std::uint64_t unkC8; // C8 + std::uint64_t unkD0; // D0 + std::uint64_t unkD8; // D8 + std::byte unkE0[0x6]; // E0 + std::uint8_t lowProcessFlags; // E6 + std::uint8_t unkE7; // E7 + std::byte padE8[0x3]; // E8 + bool ignoringCombat; // EB + std::byte padEC[0x5]; // EC + bool escortingPlayer; // F1 + std::byte padF2[0x6]; // F2 }; static_assert(sizeof(AIProcess) == 0xF8); + static_assert(offsetof(AIProcess, objectList) == 0x68); + static_assert(offsetof(AIProcess, acquireObject) == 0x88); + static_assert(offsetof(AIProcess, lowProcessFlags) == 0xE6); + static_assert(offsetof(AIProcess, ignoringCombat) == 0xEB); + static_assert(offsetof(AIProcess, escortingPlayer) == 0xF1); } From 5efcaa99c6601b9489510058f34c7f97a0a18316 Mon Sep 17 00:00:00 2001 From: Qudix <17361645+Qudix@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:54:51 -0500 Subject: [PATCH 20/20] feat: `Actor` --- include/RE/A/Actor.h | 80 ++++++++++++++++++++++++++++---------------- include/RE/IDs.h | 1 + 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/include/RE/A/Actor.h b/include/RE/A/Actor.h index 3acf3eb4..81612ff9 100644 --- a/include/RE/A/Actor.h +++ b/include/RE/A/Actor.h @@ -290,6 +290,13 @@ namespace RE func(this, a_immediate, a_resetAI); } + [[nodiscard]] ActorKnowledge* GetActorKnowledge(Actor* a_actor) + { + using func_t = decltype(&Actor::GetActorKnowledge); + static REL::Relocation func{ ID::Actor::GetActorKnowledge }; + return func(this, a_actor); + } + [[nodiscard]] TESNPC* GetNPC() { return GetBaseObject()->As(); @@ -300,6 +307,11 @@ namespace RE return GetBaseObject()->As(); } + [[nodiscard]] bool IsDead() const + { + return boolBits.all(RE::Actor::BOOL_BITS::kDead); + } + [[nodiscard]] bool IsHostileToActor(Actor* a_actor) { using func_t = decltype(&Actor::IsHostileToActor); @@ -324,6 +336,11 @@ namespace RE return func(this); } + [[nodiscard]] bool IsMurderAlarmed() const + { + return boolBits.all(RE::Actor::BOOL_BITS::kMurderAlarm); + } + [[nodiscard]] bool IsOverEncumbered() { using func_t = decltype(&Actor::IsOverEncumbered); @@ -331,6 +348,11 @@ namespace RE return func(this); } + [[nodiscard]] bool IsParalyzed() const + { + return boolBits.all(RE::Actor::BOOL_BITS::kParalyzed); + } + [[nodiscard]] bool IsSneaking() { using func_t = decltype(&Actor::IsSneaking); @@ -360,30 +382,29 @@ namespace RE } // members - REX::EnumSet boolBits; // 200 - float unk204; // 204 - BSGuarded, BSSpinLock> unk208; // 208 - BGSBody? - AIProcess* currentProcess; // 220 - std::uint64_t unk228; // 228 + REX::EnumSet boolBits; // 208 + float unk20C; // 20C + BSGuarded, BSSpinLock> unk210; // 210 - BGSBody? + AIProcess* currentProcess; // 228 std::uint64_t unk230; // 230 std::uint64_t unk238; // 238 std::uint64_t unk240; // 240 - CombatController* combatController; // 248 - std::uint64_t unk250; // 250 - ActorValueStorage avStorage; // 258 - std::uint64_t unk280; // 280 - REX::EnumSet criticalStage; // 288 - std::uint32_t dialogueItemTarget; // 28C - TESPointerHandle - std::uint32_t currentCombatTarget; // 290 - TESPointerHandle - std::uint32_t myKiller; // 294 - TESPointerHandle - std::uint64_t unk298; // 298 + std::uint64_t unk248; // 248 + CombatController* combatController; // 250 + std::uint64_t unk258; // 258 + ActorValueStorage avStorage; // 260 + std::uint64_t unk288; // 288 + REX::EnumSet criticalStage; // 290 + std::uint32_t dialogueItemTarget; // 294 - TESPointerHandle + std::uint32_t currentCombatTarget; // 298 - TESPointerHandle + std::uint32_t myKiller; // 29C - TESPointerHandle std::uint64_t unk2A0; // 2A0 - std::uint32_t actionValue; // 2A8 - float timerOnAction; // 2AC - std::uint64_t unk2B0; // 2B0 - std::uint32_t intimidateBribeDayStamp; // 2B8 - std::uint32_t unk2BC; // 2BC - std::uint64_t unk2C0; // 2C0 + std::uint64_t unk2A8; // 2A8 + std::uint32_t actionValue; // 2B0 + float timerOnAction; // 2B4 + std::uint64_t unk2B8; // 2B8 + std::uint32_t intimidateBribeDayStamp; // 2C0 + std::uint32_t unk2C4; // 2C4 std::uint64_t unk2C8; // 2C8 std::uint64_t unk2D0; // 2D0 std::uint64_t unk2D8; // 2D8 @@ -401,14 +422,14 @@ namespace RE std::uint64_t unk338; // 338 std::uint64_t unk340; // 340 std::uint64_t unk348; // 348 - TESRace* race; // 350 - Perks* perks; // 358 - std::uint32_t unk360; // 360 - mutable BSReadWriteLock perkArrayLock; // 364 - std::uint32_t unk35C; // 35C - REX::EnumSet boolFlags; // 370 - REX::EnumSet boolFlags2; // 374 - std::uint64_t unk378; // 378 + std::uint64_t unk350; // 350 + TESRace* race; // 358 + Perks* perks; // 360 + std::uint32_t unk368; // 368 + mutable BSReadWriteLock perkArrayLock; // 36C + std::uint32_t unk374; // 374 + REX::EnumSet boolFlags; // 378 + REX::EnumSet boolFlags2; // 37C std::uint64_t unk380; // 380 std::uint64_t unk388; // 388 std::uint64_t unk390; // 390 @@ -460,7 +481,8 @@ namespace RE std::uint64_t unk500; // 500 std::uint64_t unk508; // 508 std::uint64_t unk510; // 510 - std::uint8_t unk518[88]; // 518 + std::uint64_t unk518; // 518 + std::uint8_t unk520[88]; // 520 }; static_assert(sizeof(Actor) == 0x578); diff --git a/include/RE/IDs.h b/include/RE/IDs.h index 474763c7..af4d2e64 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -5,6 +5,7 @@ namespace RE::ID namespace Actor { inline constexpr REL::ID EvaluatePackage{ 150640 }; + inline constexpr REL::ID GetActorKnowledge{ 150669 }; inline constexpr REL::ID IsHostileToActor{ 150777 }; inline constexpr REL::ID IsJumping{ 150985 }; inline constexpr REL::ID IsOverEncumbered{ 150999 };