From e0609148e466c9b6c61d960b6b621c146e3d7b24 Mon Sep 17 00:00:00 2001 From: DeweySalt <76853940+Deweh@users.noreply.github.com> Date: Thu, 21 Mar 2024 20:51:14 -0400 Subject: [PATCH] feat: a lot of additions, some 1.10.31.0 updates Updated the following classes for 1.10.31.0: Size, members & offset comments verified: - BSTEventSourceLazyInit - TESObjectREFR Only size verified: - Actor - PlayerCharacter - Projectile & all classes that derive from Projectile - Hazard (Other classes were updated in 1.10.31.0, this is only a partial update.) - Added BGSSaveLoadManager - Added BSInputEnableLayer - Added BSInputEnableManager - Added InputEvent - Added BSTScatterTable - Added a functional implementation of IMenu - Added a functional implementation of GameMenuBase - Added Main - Added NiAVObject - Added NiBound - Added NiCamera - Added additional operators & Transpose() to NiMatrix3 - Added additional operators to NiPoint4 - Added NiQuaternion - Added additional operators & Inverse() to NiTransform - Corrected a flaw in ScaleformGFxValue that could result in dangling pointers. - Added ScaleformMemoryHeap - Added IsMenuRegistered() and RegisterMenu() to UI - Added UIMessageQueue --- CommonLibSF/include/RE/A/Actor.h | 8 +- CommonLibSF/include/RE/A/ArrowProjectile.h | 2 +- CommonLibSF/include/RE/B/BGSSaveLoadManager.h | 20 + CommonLibSF/include/RE/B/BSInputEnableLayer.h | 120 +++ .../include/RE/B/BSInputEnableManager.h | 25 + CommonLibSF/include/RE/B/BSInputEventUser.h | 72 +- CommonLibSF/include/RE/B/BSTEvent.h | 3 +- CommonLibSF/include/RE/B/BSTScatterTable.h | 755 ++++++++++++++++++ CommonLibSF/include/RE/B/BarrierProjectile.h | 2 +- CommonLibSF/include/RE/B/BeamProjectile.h | 2 +- CommonLibSF/include/RE/C/ConeProjectile.h | 2 +- CommonLibSF/include/RE/E/EmitterProjectile.h | 2 +- CommonLibSF/include/RE/F/FlameProjectile.h | 3 +- CommonLibSF/include/RE/G/GameMenuBase.h | 72 +- CommonLibSF/include/RE/G/GrenadeProjectile.h | 2 +- CommonLibSF/include/RE/H/Hazard.h | 3 +- CommonLibSF/include/RE/I/IMenu.h | 264 ++++-- CommonLibSF/include/RE/M/Main.h | 30 + CommonLibSF/include/RE/M/MissileProjectile.h | 4 +- CommonLibSF/include/RE/N/NiAVObject.h | 146 ++++ CommonLibSF/include/RE/N/NiBound.h | 12 + CommonLibSF/include/RE/N/NiCamera.h | 92 +++ CommonLibSF/include/RE/N/NiMatrix3.h | 27 + CommonLibSF/include/RE/N/NiPoint3.h | 6 +- CommonLibSF/include/RE/N/NiPoint4.h | 11 + CommonLibSF/include/RE/N/NiQuaternion.h | 265 ++++++ CommonLibSF/include/RE/N/NiTransform.h | 41 +- CommonLibSF/include/RE/P/PlasmaProjectile.h | 2 +- CommonLibSF/include/RE/P/PlayerCharacter.h | 2 +- CommonLibSF/include/RE/P/Projectile.h | 2 +- .../include/RE/S/SWFToCodeFunctionHandler.h | 7 + CommonLibSF/include/RE/S/ScaleformGFxValue.h | 38 +- .../include/RE/S/ScaleformMemoryHeap.h | 63 ++ CommonLibSF/include/RE/Starfield.h | 11 + CommonLibSF/include/RE/T/TESObjectREFR.h | 30 +- CommonLibSF/include/RE/U/UI.h | 55 +- CommonLibSF/include/RE/U/UIMessageQueue.h | 50 ++ 37 files changed, 2140 insertions(+), 111 deletions(-) create mode 100644 CommonLibSF/include/RE/B/BGSSaveLoadManager.h create mode 100644 CommonLibSF/include/RE/B/BSInputEnableLayer.h create mode 100644 CommonLibSF/include/RE/B/BSInputEnableManager.h create mode 100644 CommonLibSF/include/RE/B/BSTScatterTable.h create mode 100644 CommonLibSF/include/RE/M/Main.h create mode 100644 CommonLibSF/include/RE/N/NiAVObject.h create mode 100644 CommonLibSF/include/RE/N/NiBound.h create mode 100644 CommonLibSF/include/RE/N/NiCamera.h create mode 100644 CommonLibSF/include/RE/N/NiQuaternion.h create mode 100644 CommonLibSF/include/RE/S/ScaleformMemoryHeap.h create mode 100644 CommonLibSF/include/RE/U/UIMessageQueue.h diff --git a/CommonLibSF/include/RE/A/Actor.h b/CommonLibSF/include/RE/A/Actor.h index d648c0f8..6c8fa0ee 100644 --- a/CommonLibSF/include/RE/A/Actor.h +++ b/CommonLibSF/include/RE/A/Actor.h @@ -168,8 +168,8 @@ namespace RE virtual void Unk_133(); // 133 virtual void Unk_134(); // 134 virtual void Unk_135(); // 135 - virtual void Unk_136(); // 136 - virtual void Unk_137(); // 137 + virtual void DrawWeaponMagicHands(bool a_draw); // 136 + virtual void SetPosition(const NiPoint3& a_pos, bool a_updateCharController); // 137 virtual void Unk_138(); // 138 virtual void Resurrect(bool a_resetInventory, bool a_attach3D); // 139 virtual void Unk_13A(); // 13A @@ -320,6 +320,7 @@ namespace RE std::uint64_t unk350; // 350 std::uint64_t unk358; // 358 std::uint64_t unk360; // 360 + std::uint64_t unk368; // 368 TESRace* race; // 368 Perks* perks; // 370 std::uint32_t unk378; // 378 @@ -379,6 +380,7 @@ namespace RE std::uint64_t unk518; // 518 std::uint64_t unk520; // 520 std::uint64_t unk528; // 528 + std::uint8_t unk530[88]; // 530 }; - static_assert(sizeof(Actor) == 0x530); + static_assert(sizeof(Actor) == 0x570); } diff --git a/CommonLibSF/include/RE/A/ArrowProjectile.h b/CommonLibSF/include/RE/A/ArrowProjectile.h index 44e99e49..aa002d67 100644 --- a/CommonLibSF/include/RE/A/ArrowProjectile.h +++ b/CommonLibSF/include/RE/A/ArrowProjectile.h @@ -17,5 +17,5 @@ namespace RE // members AlchemyItem* poison; // 2B0 }; - static_assert(sizeof(ArrowProjectile) == 0x2C0); + static_assert(sizeof(ArrowProjectile) == 0x2B0); } diff --git a/CommonLibSF/include/RE/B/BGSSaveLoadManager.h b/CommonLibSF/include/RE/B/BGSSaveLoadManager.h new file mode 100644 index 00000000..c5fb1bd2 --- /dev/null +++ b/CommonLibSF/include/RE/B/BGSSaveLoadManager.h @@ -0,0 +1,20 @@ +#pragma once + +namespace RE +{ + class BGSSaveLoadManager + { + static BGSSaveLoadManager* GetSingleton() + { + static REL::Relocation singleton{ REL::ID(880997) }; + return *singleton; + } + + bool DeleteSaveFile(const char* a_filename, void* a_unk1, bool a_unk2) + { + using func_t = decltype(&BGSSaveLoadManager::DeleteSaveFile); + REL::Relocation func{ REL::ID(147844) }; + return func(this, a_filename, a_unk1, a_unk2); + } + }; +} diff --git a/CommonLibSF/include/RE/B/BSInputEnableLayer.h b/CommonLibSF/include/RE/B/BSInputEnableLayer.h new file mode 100644 index 00000000..25e760fd --- /dev/null +++ b/CommonLibSF/include/RE/B/BSInputEnableLayer.h @@ -0,0 +1,120 @@ +#pragma once + +#include "RE/B/BSInputEnableManager.h" + +namespace RE +{ + struct BSInputEnableLayer + { + enum UserFlag + { + Walking = (1 << 0), + Looking = (1 << 1), + Activation = (1 << 2), //Unconfirmed + TabMenuMaybe = (1 << 3), //Unconfirmed + Console = (1 << 4), //Unconfirmed + POVSwitch = (1 << 5), //Unconfirmed + Fighting = (1 << 6), + Sneaking = (1 << 7), + Menu = (1 << 8), + WheelZoom = (1 << 9), //Unconfirmed + Jumping = (1 << 10), + Movement = Walking | Jumping, + }; + + enum OtherFlag + { + Journal = (1 << 0), + Activate = (1 << 1), + FastTravel = (1 << 2), + CamSwitch = (1 << 3), + VATS = (1 << 4), + Favorites = (1 << 5), + PipboyLight = (1 << 6), //Unconfirmed + ZKey = (1 << 7), + Running = (1 << 8), + Unk = (1 << 9), //?? + Sprinting = (1 << 10), + HandScanner = (1 << 11), + Takeoff = (1 << 12), + Inventory = (1 << 13), + Gravjump = (1 << 14), + FarTravel = (1 << 15), + LocationDiscovery = (1 << 16), + 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) + { + using func_t = decltype(&BSInputEnableLayer::SetUserFlags); + REL::Relocation func(REL::ID(106486)); + return func(this, flags, enabled); + } + + uint64_t SetOtherFlags(uint64_t flags, bool enabled) + { + using func_t = decltype(&BSInputEnableLayer::SetOtherFlags); + REL::Relocation func(REL::ID(109447)); + return func(this, flags, enabled); + } + }; + + class InputEnableLayer + { + public: + InputEnableLayer() {} + + InputEnableLayer(const char* layerName) + { + Create(layerName); + } + + ~InputEnableLayer() + { + Free(); + } + + bool Create(const char* layerName) + { + bool result = true; + if (!data) { + result = BSInputEnableManager::GetSingleton()->CreateLayer(this, layerName); + if (!result) + data = nullptr; + } + return result; + } + + bool Free() + { + bool result = true; + if (data) { + using func_t = decltype(&InputEnableLayer::Free); + REL::Relocation func(REL::ID(36626)); + result = func(this); + data = nullptr; + } + return result; + } + + void SetUserFlags(uint64_t flags, bool enabled) + { + if (data) + data->SetUserFlags(flags, enabled); + } + + void SetOtherFlags(uint64_t flags, bool enabled) + { + if (data) + data->SetOtherFlags(flags, enabled); + } + + BSInputEnableLayer* data{ nullptr }; + }; +} diff --git a/CommonLibSF/include/RE/B/BSInputEnableManager.h b/CommonLibSF/include/RE/B/BSInputEnableManager.h new file mode 100644 index 00000000..783df2fa --- /dev/null +++ b/CommonLibSF/include/RE/B/BSInputEnableManager.h @@ -0,0 +1,25 @@ +#pragma once + +namespace RE +{ + class InputEnableLayer; + + class BSInputEnableManager + { + public: + virtual ~BSInputEnableManager() = 0; + + static BSInputEnableManager* GetSingleton() + { + REL::Relocation singleton{ REL::ID(878792) }; + return *singleton; + } + + bool CreateLayer(InputEnableLayer* a_layer, const char* a_layerName) + { + using func_t = decltype(&BSInputEnableManager::CreateLayer); + REL::Relocation func(REL::ID(179101)); + return func(this, a_layer, a_layerName); + } + }; +} diff --git a/CommonLibSF/include/RE/B/BSInputEventUser.h b/CommonLibSF/include/RE/B/BSInputEventUser.h index 876baf21..b3c4a361 100644 --- a/CommonLibSF/include/RE/B/BSInputEventUser.h +++ b/CommonLibSF/include/RE/B/BSInputEventUser.h @@ -1,6 +1,7 @@ #pragma once #include "RE/M/MemoryManager.h" +#include "RE/B/BSFixedString.h" namespace RE { @@ -13,6 +14,70 @@ namespace RE class MouseMoveEvent; class ThumbstickEvent; + class InputEvent + { + public: + enum DeviceType : uint32_t + { + DeviceKeyboard = 0, + DeviceMouse, + DeviceGamepad, + DeviceKinect, + }; + + enum EventType : uint32_t + { + Button = 0, + MouseMove, + CursorMove, + Char, + Thumbstick, + DeviceConnect, + Kinect, + None, + }; + + enum Status : uint32_t + { + Unhandled = 0, + Continue, + Stop, + }; + + virtual ~InputEvent() = default; //00 + virtual bool Unk01() { return false; } + virtual BSFixedString GetUserEventOrDisabled() { return ""; } + + uint32_t deviceType; //08 + uint32_t deviceId; + uint32_t eventType; //10 + uint32_t pad14; + InputEvent* next; //18 + uint32_t timeCode; //20 + uint32_t status; + }; + + class IDEvent : public InputEvent + { + public: + virtual ~IDEvent() = default; + BSFixedString userEvent; //28 + uint32_t idCode; //30 + bool disabled; //34 + }; + + class ButtonEvent : public IDEvent + { + public: + virtual ~ButtonEvent() = default; + void* iCanBeDebounced; //38 + void* iCanBeChorded; //40 + float value; //48 + float held; //4C + void* unk50; + void* bsDebounceManager; + }; + class BSInputEventUser { public: @@ -29,7 +94,12 @@ namespace RE virtual void HandleEvent(const MouseMoveEvent*) { return; } // 06 virtual void HandleEvent(const CharacterEvent*) { return; } // 07 virtual void HandleEvent(const ButtonEvent*) { return; } // 08 - virtual void Unk_09(const InputEvent*); // 09 + virtual void InputEventUser_Unk_09(const InputEvent* a_event) // 09 + { + using func_t = decltype(&BSInputEventUser::InputEventUser_Unk_09); + REL::Relocation func(REL::ID(178899)); + return func(this, a_event); + } SF_HEAP_REDEFINE_NEW(BSInputEventUser); diff --git a/CommonLibSF/include/RE/B/BSTEvent.h b/CommonLibSF/include/RE/B/BSTEvent.h index 68493e2c..74b63744 100644 --- a/CommonLibSF/include/RE/B/BSTEvent.h +++ b/CommonLibSF/include/RE/B/BSTEvent.h @@ -102,7 +102,6 @@ namespace RE public: // members BSTEventSource* eventSource; // 00 - std::uint64_t unk08; // 08 }; - static_assert(sizeof(BSTEventSourceLazyInit) == 0x10); + static_assert(sizeof(BSTEventSourceLazyInit) == 0x8); } diff --git a/CommonLibSF/include/RE/B/BSTScatterTable.h b/CommonLibSF/include/RE/B/BSTScatterTable.h new file mode 100644 index 00000000..a899b22a --- /dev/null +++ b/CommonLibSF/include/RE/B/BSTScatterTable.h @@ -0,0 +1,755 @@ +#pragma once + +namespace RE +{ + struct BSCRC32 + { + static uint32_t GenerateCRC(uint32_t initial, const void* buf, size_t len) + { + static REL::Relocation uiCRCTable{ REL::ID(292339) }; + uint32_t c = initial; + const uint8_t* u = static_cast(buf); + for (size_t i = 0; i < len; ++i) + { + c = uiCRCTable.get()[(c ^ u[i]) & 0xFF] ^ (c >> 8); + } + return c; + } + }; + + namespace BSHash + { + class FNV1a + { + public: + size_t operator()(const uint32_t& key) + { + return std::_Fnv1a_append_bytes(0xCBF29CE484222325, reinterpret_cast(&key), 4); + } + }; + + template + class String + { + size_t operator()(const T& key) + { + return BSCRC32::GenerateCRC(0, key.c_str(), key.size()); + } + }; + + class XOR + { + public: + size_t operator()(const BSFixedString& key) + { + return (reinterpret_cast(key.c_str()) >> 32) ^ (reinterpret_cast(key.c_str()) & 0xFFFFFFFF); + } + size_t operator()(const BSFixedStringW& key) + { + return (reinterpret_cast(key.c_str()) >> 32) ^ (reinterpret_cast(key.c_str()) & 0xFFFFFFFF); + } + }; + } + + template + class BSTScatterTableDefaultHashPolicy + { + public: + size_t operator()(const T& key) = delete; + }; + + template<> class BSTScatterTableDefaultHashPolicy + { + public: + size_t operator()(const BSFixedString& key) + { + return BSHash::XOR()(key); + } + }; + + template<> class BSTScatterTableDefaultHashPolicy + { + public: + size_t operator()(const BSFixedStringCS& key) + { + return BSHash::XOR()(key); + } + }; + + template<> class BSTScatterTableDefaultHashPolicy + { + public: + size_t operator()(const BSFixedStringW& key) + { + return BSHash::XOR()(key); + } + }; + + template<> class BSTScatterTableDefaultHashPolicy + { + public: + size_t operator()(const BSFixedStringW& key) + { + return BSHash::XOR()(key); + } + }; + + template<> class BSTScatterTableDefaultHashPolicy + { + public: + size_t operator()(const uint32_t& key) + { + return BSCRC32::GenerateCRC(0, &key, 4); + } + }; + + template + struct BSTScatterTableDefaultKVStorage + { + public: + BSTScatterTableDefaultKVStorage() : + Key(), + Value() + {} + + BSTScatterTableDefaultKVStorage(const T1& a_first, const T2& a_second) : + Key(a_first), + Value(a_second) + {} + + BSTScatterTableDefaultKVStorage(const BSTScatterTableDefaultKVStorage& a_rhs) : + Key(a_rhs.Key), + Value(a_rhs.Value) + {} + + BSTScatterTableDefaultKVStorage& operator=(const BSTScatterTableDefaultKVStorage& a_rhs) + { + Key = a_rhs.Key; + Value = a_rhs.Value; + } + + BSTScatterTableDefaultKVStorage& operator=(BSTScatterTableDefaultKVStorage&& a_rhs) + { + Key = std::move(a_rhs.Key); + Value = std::move(a_rhs.Value); + } + + // Convenience to convert from std::make_pair + BSTScatterTableDefaultKVStorage(const std::pair& pair) : + Key(pair.first), + Value(pair.second) + {} + + + T1 Key; // 00 + T2 Value; // ?? + }; + + template class Storage = BSTScatterTableDefaultKVStorage> + struct BSTScatterTableTraits + { + public: + using key_type = Key; + using mapped_type = T; + using value_type = Storage; + + + const key_type& operator()(const value_type& a_value) const + { + return a_value.Key; + } + }; + + template class Storage = BSTScatterTableDefaultKVStorage> + struct BSTScatterTableEntry + { + Storage Value; + int32_t iNextIndex; + int32_t iIndex; + }; + + template + struct BSTScatterTableHeapAllocator + { + public: + using entry_type = T; + using size_type = uint32_t; + + BSTScatterTableHeapAllocator() {} + + entry_type* allocate(std::size_t a_num) + { + auto size = a_num * sizeof(entry_type); + auto mem = (entry_type*)RE::malloc(size, 8); + memset(mem, 0, size); + for (uint64_t i = 0; i < a_num; ++i) + { + mem[i].iNextIndex = -1; + mem[i].iIndex = -1; + } + return mem; + } + + void deallocate(entry_type* a_ptr) + { + RE::free(a_ptr, true); + } + + size_type min_size() const + { + return static_cast(1) << 3; + } + + size_type max_size() const + { + return static_cast(1) << 31; + } + }; + + // Maybe related to the allocator type? + struct BSTScatterTableParent1 + { + void* unk00 = nullptr; + uint64_t unk08 = 0; + uint64_t unk10 = 0; + }; + + // Maybe related to the allocator type? + struct BSTScatterTableParent2 + { + void* unk00 = nullptr; + uint64_t unk08 = 0; + }; + + template < + class Traits, + uint32_t N, + template class Allocator, + class Hash, + class KeyEqual, + class Parent + > + class BSTScatterTableBase : public Parent + { + public: + using traits_type = Traits; + using key_type = typename traits_type::key_type; + using mapped_type = typename traits_type::mapped_type; + using value_type = typename traits_type::value_type; + using hasher = Hash; + using key_equal = KeyEqual; + using size_type = uint32_t; + + using entry_type = BSTScatterTableEntry; + using allocator_type = Allocator; + + BSTScatterTableBase() : Parent(), + pTable(nullptr), + uiSize(0), + uiFree(0), + uiLastFree(0) + { + } + ~BSTScatterTableBase() + { + if (pTable) + { + deallocate(pTable); + pTable = nullptr; + } + } + + SF_HEAP_REDEFINE_NEW(BSTScatterTableBase); + + template + struct iterator_base + { + public: + typedef std::ptrdiff_t difference_type; + typedef U value_type; + typedef U* pointer; + typedef U& reference; + typedef std::forward_iterator_tag iterator_category; + + iterator_base() : + _entry(nullptr), + _end(nullptr) + {} + + iterator_base(const iterator_base& a_rhs) : + _entry(a_rhs._entry), + _end(a_rhs._end) + {} + + iterator_base(iterator_base&& a_rhs) noexcept : + _entry(std::move(a_rhs._entry)), + _end(a_rhs._end) + { + a_rhs._entry = a_rhs._end; + } + + iterator_base(entry_type* a_entry, entry_type* a_end) : + _entry(a_entry), + _end(a_end) + { + while (_entry != _end && _entry->iNextIndex == -1) { + ++_entry; + } + } + + ~iterator_base(){} + + iterator_base& operator=(const iterator_base& a_rhs) + { + _entry = a_rhs._entry; + } + + iterator_base& operator=(iterator_base&& a_rhs) + { + _entry = std::move(a_rhs._entry); + a_rhs._entry = a_rhs._end; + } + + void swap(iterator_base& a_rhs) + { + std::swap(_entry, a_rhs._entry); + } + + reference operator*() const + { + return _entry->Value; + } + + pointer operator->() const + { + return std::addressof(_entry->Value); + } + + bool operator==(const iterator_base& a_rhs) const + { + return _entry == a_rhs._entry; + } + + bool operator!=(const iterator_base& a_rhs) const + { + return !operator==(a_rhs); + } + + iterator_base& operator++() + { + do { + ++_entry; + } while (_entry != _end && _entry->iNextIndex == -1); + return *this; + } + + iterator_base operator++(int) + { + iterator_base tmp{ *this }; + operator++(); + return tmp; + } + + private: + entry_type* _entry; + entry_type* _end; + }; + + + using iterator = iterator_base; + using const_iterator = iterator_base; + + hasher hash_function() const + { + return hasher(); + } + + key_equal key_eq() const + { + return key_equal(); + } + + bool comp_key(const key_type& a_lhs, const key_type& a_rhs) const + { + return key_eq()(a_lhs, a_rhs); + } + + iterator begin() + { + return get_entries() ? make_iterator(get_entries()) : iterator(); + } + + + const_iterator begin() const + { + return get_entries() ? make_iterator(get_entries()) : const_iterator(); + } + + + const_iterator cbegin() const + { + return begin(); + } + + iterator end() + { + return get_entries() ? make_iterator(get_entries() + uiSize) : iterator(); + } + + + const_iterator end() const + { + return get_entries() ? make_iterator(get_entries() + uiSize) : const_iterator(); + } + + + const_iterator cend() const + { + return end(); + } + + + bool empty() const + { + return !get_entries() || uiFree == 0; + } + + + size_type size() const + { + return uiSize - uiFree; + } + + size_type max_size() const + { + return allocator_type().max_size(); + } + + std::pair insert(const value_type& a_value) + { + return insert_impl(false, a_value); + } + + std::pair insert(value_type&& a_value) + { + return insert_impl(false, std::move(a_value)); + } + + std::pair insert_or_assign(const value_type& a_value) + { + return insert_impl(true, a_value); + } + + std::pair insert_or_assign(value_type&& a_value) + { + return insert_impl(true, std::move(a_value)); + } + + std::pair insert_or_assign(const key_type& a_key, const mapped_type& a_value) + { + return insert_impl(true, value_type(a_key, a_value)); + } + + size_type erase(const key_type& a_key) + { + if (!get_entries()) { // no entries + return 0; + } + + auto entry = get_pos(calc_idx(a_key)); + if (entry->iNextIndex == -1) { // key not in table + return 0; + } + + entry_type* tail = nullptr; + while (!comp_key(get_key(entry->Value), a_key)) { // find key in table + tail = entry; + entry = get_pos(entry->iNextIndex); + if (entry == get_pos(uiSize)) { + return 0; + } + } + + entry->Value.~value_type(); + + if (entry->iNextIndex == uiSize) { // if no chain + if (tail) { + tail->iNextIndex = static_cast(uiSize); + } + entry->iNextIndex = -1; + } + else { // else move next entry into current + new (entry) entry_type(std::move(*get_pos(entry->iNextIndex))); + } + + ++uiFree; + return 1; + } + + iterator find(const key_type& a_key) + { + auto entry = find_impl(a_key); + return entry ? make_iterator(entry) : end(); + } + + + const_iterator find(const key_type& a_key) const + { + auto entry = find_impl(a_key); + return entry ? make_iterator(entry) : end(); + } + + bool contains(const key_type& a_key) const + { + return find(a_key) != end(); + } + + void reserve(size_type a_count) + { + if (a_count <= uiSize) { + return; + } + + uint32_t leftShifts = 0; + while ((a_count & static_cast(1 << 31)) == 0) { + a_count <<= 1; + ++leftShifts; + } + auto bitPos = 31 - leftShifts; + auto newCount = static_cast(1 << bitPos); + grow(newCount); + } + + void clear() + { + auto entries = get_entries(); + clear_entries(0, uiSize); + uiFree = uiSize; + } + + mapped_type& operator[](const key_type& a_key) + { + if (auto iter = find(a_key); iter != end()) { + return iter->Value; + } else { + return insert(value_type{ a_key, mapped_type{} }).first->Value; + } + } + + private: + bool grow() + { + if (uiSize == (uint32_t)1 << 31) { + return false; + } + + uint32_t newCapacity = static_cast(uiSize ? uiSize << 1 : min_size()); + return grow(newCapacity); + } + + void clear_entries(uint64_t start, uint64_t end) + { + for (uint64_t i = start; i < end; ++i) + { + auto entry = get_pos(i); + if (entry->iNextIndex != -1) + { + entry->Value.~value_type(); + entry->iNextIndex = -1; + entry->iIndex = -1; + } + } + } + + bool grow(uint32_t a_newCapacity) + { + auto oldEntries = get_entries(); + auto begIter = begin(); + auto endIter = end(); + + auto newEntries = allocate(a_newCapacity); + if (!newEntries) { + return false; + } + else if (newEntries == oldEntries) { + uiSize = a_newCapacity; + return true; + } + else { + uiSize = a_newCapacity; + uiLastFree = a_newCapacity; + uiFree = a_newCapacity; + set_entries(newEntries); + + while (begIter != endIter) { + insert(std::move(*begIter)); + ++begIter; + } + + deallocate(oldEntries); + return true; + } + } + + size_t calc_hash(const key_type& a_key) const + { + return hash_function()(a_key); + } + + uint64_t calc_idx(const key_type& a_key) const + { + return calc_hash(a_key) & (uiSize - 1); // capacity is always a factor of 2, so this is a faster modulo + } + + entry_type* find_impl(const key_type& a_key) const + { + if (!get_entries()) { + return nullptr; + } + + auto probe = get_pos(calc_idx(a_key)); // try ideal pos + if (probe->iNextIndex == -1) { + return nullptr; // nothing there + } + + do { + if (comp_key(get_key(probe->Value), a_key)) { + return probe; + } + else { + probe = get_pos(probe->iNextIndex); + } + } while (probe != get_pos(uiSize)); // follow chain + + return nullptr; + } + + template + std::pair insert_impl(bool a_overwrite, Arg&& a_value) + { + if (!get_entries() || !uiFree) { + if (!grow()) { + return std::make_pair(end(), false); // maybe throw? + } + } + + auto idealEntry = calc_pos(get_key(a_value)); + + // Slot is empty, fill it + if (idealEntry->iNextIndex == -1) { + new (std::addressof(idealEntry->Value)) value_type(std::forward(a_value)); + idealEntry->iNextIndex = static_cast(uiSize); + idealEntry->iIndex = static_cast(std::distance(get_pos(0), idealEntry)); + --uiFree; + return std::make_pair(make_iterator(idealEntry), true); + } + + for (auto iter = idealEntry; iter != get_pos(uiSize); iter = get_pos(iter->iNextIndex)) { + if (comp_key(get_key(iter->Value), get_key(a_value))) { + if (a_overwrite) { + iter->Value.~value_type(); + new (std::addressof(iter->Value)) value_type(std::forward(a_value)); + } + return std::make_pair(make_iterator(iter), false); + } + } + + auto freeEntry = get_free_entry(); + + auto takenIdealEntry = calc_pos(get_key(idealEntry->Value)); + if (takenIdealEntry == idealEntry) { // if entry occupying our slot would've hashed here anyway + freeEntry->iIndex = idealEntry->iIndex; + freeEntry->iNextIndex = idealEntry->iNextIndex; + idealEntry->iNextIndex = static_cast(std::distance(get_pos(0), freeEntry)); + new (std::addressof(freeEntry->Value)) value_type(std::forward(a_value)); + --uiFree; + return std::make_pair(make_iterator(freeEntry), true); + } + + while (takenIdealEntry->iNextIndex != static_cast(std::distance(get_pos(0), idealEntry))) { // find entry that links here + takenIdealEntry = get_pos(takenIdealEntry->iNextIndex); + } + + // move taken slot out, so we can move in + new (std::addressof(freeEntry->Value)) value_type(std::move(idealEntry->Value)); + freeEntry->iNextIndex = idealEntry->iNextIndex; + freeEntry->iIndex = idealEntry->iIndex; + takenIdealEntry->iNextIndex = static_cast(std::distance(get_pos(0), freeEntry)); + new (std::addressof(idealEntry->Value)) value_type(std::forward(a_value)); + idealEntry->iNextIndex = static_cast(uiSize); + --uiFree; + return std::make_pair(make_iterator(idealEntry), true); + } + + entry_type* get_pos(uint64_t index) const + { + return const_cast(get_entries() + index); + } + + entry_type* calc_pos(const key_type& a_key) const + { + return get_pos(calc_idx(a_key)); + } + + entry_type* get_free_entry() + { + entry_type* entry = nullptr; + do { + uiLastFree = (uiSize - 1) & (uiLastFree - 1); + entry = get_pos(uiLastFree); + } while (entry->iNextIndex != -1); + + return entry; + } + + const key_type& get_key(const value_type& a_value) const + { + traits_type traits; + return traits(a_value); + } + + iterator make_iterator(entry_type* a_entry) + { + return iterator(a_entry, pTable + uiSize); + } + + const_iterator make_iterator(entry_type* a_entry) const + { + return const_iterator(a_entry, pTable + uiSize); + } + + entry_type* allocate(std::size_t a_num) + { + return allocator_type().allocate(a_num); + } + void deallocate(entry_type* a_ptr) + { + allocator_type().deallocate(a_ptr); + } + entry_type* get_entries() const + { + return pTable; + } + void set_entries(entry_type* a_entries) + { + pTable = a_entries; + } + size_type min_size() const + { + return allocator_type().min_size(); + } + + entry_type* pTable; + uint64_t uiSize; + uint64_t uiFree; + uint64_t uiLastFree; + }; + + template , class KeyEqual = std::equal_to> + using BSTHashMap = BSTScatterTableBase, 8, BSTScatterTableHeapAllocator, Hash, KeyEqual, BSTScatterTableParent1>; + static_assert(sizeof(BSTHashMap) == 0x38); + + template , class KeyEqual = std::equal_to> + using BSTHashMap2 = BSTScatterTableBase, 8, BSTScatterTableHeapAllocator, Hash, KeyEqual, BSTScatterTableParent2>; + static_assert(sizeof(BSTHashMap2) == 0x30); +} diff --git a/CommonLibSF/include/RE/B/BarrierProjectile.h b/CommonLibSF/include/RE/B/BarrierProjectile.h index c2685616..8abc7607 100644 --- a/CommonLibSF/include/RE/B/BarrierProjectile.h +++ b/CommonLibSF/include/RE/B/BarrierProjectile.h @@ -26,5 +26,5 @@ namespace RE float width; // 260 BSTArray collisionData; // 268 }; - static_assert(sizeof(BarrierProjectile) == 0x280); + static_assert(sizeof(BarrierProjectile) == 0x260); } diff --git a/CommonLibSF/include/RE/B/BeamProjectile.h b/CommonLibSF/include/RE/B/BeamProjectile.h index 15b19f86..87fbdce4 100644 --- a/CommonLibSF/include/RE/B/BeamProjectile.h +++ b/CommonLibSF/include/RE/B/BeamProjectile.h @@ -32,5 +32,5 @@ namespace RE std::uint8_t unk3B5; // 3B5 std::uint8_t unk3B6; // 3B6 }; - static_assert(sizeof(BeamProjectile) == 0x3C0); + static_assert(sizeof(BeamProjectile) == 0x3A0); } diff --git a/CommonLibSF/include/RE/C/ConeProjectile.h b/CommonLibSF/include/RE/C/ConeProjectile.h index d4144ccd..912b3562 100644 --- a/CommonLibSF/include/RE/C/ConeProjectile.h +++ b/CommonLibSF/include/RE/C/ConeProjectile.h @@ -21,5 +21,5 @@ namespace RE void* collisionShape; // 288 BSTArray collisions; // 290 }; - static_assert(sizeof(ConeProjectile) == 0x2A0); + static_assert(sizeof(ConeProjectile) == 0x280); } diff --git a/CommonLibSF/include/RE/E/EmitterProjectile.h b/CommonLibSF/include/RE/E/EmitterProjectile.h index ef02dc5d..591f1b3a 100644 --- a/CommonLibSF/include/RE/E/EmitterProjectile.h +++ b/CommonLibSF/include/RE/E/EmitterProjectile.h @@ -30,5 +30,5 @@ namespace RE std::uint64_t unk2A0; // 2A0 std::uint64_t unk2A8; // 2A8 }; - static_assert(sizeof(EmitterProjectile) == 0x2B0); + static_assert(sizeof(EmitterProjectile) == 0x290); } diff --git a/CommonLibSF/include/RE/F/FlameProjectile.h b/CommonLibSF/include/RE/F/FlameProjectile.h index ccfacfee..2715987e 100644 --- a/CommonLibSF/include/RE/F/FlameProjectile.h +++ b/CommonLibSF/include/RE/F/FlameProjectile.h @@ -16,5 +16,6 @@ namespace RE float expirationTimer; // 260 float coneAngle; // 264 }; - static_assert(sizeof(FlameProjectile) == 0x270); + static_assert(sizeof(FlameProjectile) == 0x250); + } diff --git a/CommonLibSF/include/RE/G/GameMenuBase.h b/CommonLibSF/include/RE/G/GameMenuBase.h index 61fcbc46..269c2945 100644 --- a/CommonLibSF/include/RE/G/GameMenuBase.h +++ b/CommonLibSF/include/RE/G/GameMenuBase.h @@ -1,6 +1,7 @@ #pragma once #include "RE/I/IMenu.h" +#include "RE/S/ScaleformGFxASMovieRootBase.h" namespace RE { @@ -8,10 +9,77 @@ namespace RE public IMenu // 00 { public: + static constexpr const char* CODE_OBJ_NAME{ "BGSCodeObj" }; + static constexpr const char* ON_CODE_OBJ_CREATED_FUNC{ "onCodeObjCreate" }; + SF_RTTI_VTABLE(GameMenuBase); - GameMenuBase() = default; + GameMenuBase() + { + using func_t = GameMenuBase* (*)(GameMenuBase*); + REL::Relocation func(REL::ID(130577)); + func(this); + } + + virtual ~GameMenuBase() = default; // 00 + + //override + virtual uint64_t Unk10() override + { + using func_t = decltype(&GameMenuBase::Unk10); + REL::Relocation func(REL::ID(141505)); + return func(this); + }; + + virtual uint64_t Unk11() override + { + using func_t = decltype(&GameMenuBase::Unk11); + REL::Relocation func(REL::ID(141506)); + return func(this); + }; + + //add + virtual bool Unk1B() { return true; } //1B + + //custom add + + //Do not set this to true unless your menu SWF has Beth's AS3 event backend. + //Otherwise, it will cause a CTD. + virtual bool UseEventDispatcher() + { + return false; + } + + //custom override + virtual bool LoadMovie(bool a_addEventDispatcher, bool a_arg2) override + { + a_addEventDispatcher = UseEventDispatcher(); + bool result = IMenu::LoadMovie(a_addEventDispatcher, a_arg2); + if (result && !a_addEventDispatcher && uiMovie && uiMovie->asMovieRoot) { + uiMovie->asMovieRoot->GetVariable(&menuObj, GetRootPath()); + if (menuObj.IsObject() && menuObj.HasMember(CODE_OBJ_NAME)) { + MapCodeObjectFunctions(); + menuObj.Invoke(ON_CODE_OBJ_CREATED_FUNC); + } + } + return result; + } + + void RegisterNativeFunction(const char* a_name, uint64_t a_idx) + { + if (!uiMovie) { + return; + } + + RE::Scaleform::GFx::Value codeObjVal; + menuObj.GetMember(CODE_OBJ_NAME, &codeObjVal); + if (!codeObjVal.IsObject()) { + return; + } - virtual ~GameMenuBase() = default; // 00 + RE::Scaleform::GFx::Value funcVal; + uiMovie->asMovieRoot->CreateFunction(&funcVal, this, reinterpret_cast(a_idx)); + codeObjVal.SetMember(a_name, funcVal); + } }; } diff --git a/CommonLibSF/include/RE/G/GrenadeProjectile.h b/CommonLibSF/include/RE/G/GrenadeProjectile.h index f521b111..a95d4d37 100644 --- a/CommonLibSF/include/RE/G/GrenadeProjectile.h +++ b/CommonLibSF/include/RE/G/GrenadeProjectile.h @@ -19,5 +19,5 @@ namespace RE BSTSmartPointer decalGroup; // 260 - NiPointer? bool collisionGroupReset; // 268 }; - static_assert(sizeof(GrenadeProjectile) == 0x270); + static_assert(sizeof(GrenadeProjectile) == 0x250); } diff --git a/CommonLibSF/include/RE/H/Hazard.h b/CommonLibSF/include/RE/H/Hazard.h index bd51a43e..a6742cd7 100644 --- a/CommonLibSF/include/RE/H/Hazard.h +++ b/CommonLibSF/include/RE/H/Hazard.h @@ -27,6 +27,7 @@ namespace RE float radius; // 12C float magnitude; // 130 std::uint32_t flags; // 134 + void* unk280; // 280 }; - static_assert(sizeof(Hazard) == 0x140); + static_assert(sizeof(Hazard) == 0x120); } diff --git a/CommonLibSF/include/RE/I/IMenu.h b/CommonLibSF/include/RE/I/IMenu.h index 3602d21c..d4a33aa2 100644 --- a/CommonLibSF/include/RE/I/IMenu.h +++ b/CommonLibSF/include/RE/I/IMenu.h @@ -6,6 +6,8 @@ #include "RE/S/SWFToCodeFunctionHandler.h" #include "RE/S/ScaleformGFxMovie.h" #include "RE/S/ScaleformGFxValue.h" +#include "RE/S/ScaleformMemoryHeap.h" +#include "RE/U/UIMessageQueue.h" namespace RE { @@ -19,60 +21,218 @@ namespace RE public: SF_RTTI_VTABLE(IMenu); - virtual ~IMenu() = default; // 00 + enum Flag : uint32_t + { + Flag0 = 1 << 0, + Flag1 = 1 << 1, + ShowCursor = 1 << 3, + Flag4 = 1 << 4, + Flag6 = 1 << 6, + Flag8 = 1 << 8, + Flag9 = 1 << 9, + Flag10 = 1 << 10, + Flag18 = 1 << 18, + Flag25 = 1 << 25, + Flag27 = 1 << 27, + }; + + virtual ~IMenu() // 00 + { + using func_t = void(*)(IMenu*); + REL::Relocation func(REL::ID(187216)); + func(this); + } + + void* operator new(std::size_t count) { return Scaleform::MemoryHeapPT::GetSingleton()->Allocate(count, 0); } + void* operator new(std::size_t count, std::align_val_t) { return Scaleform::MemoryHeapPT::GetSingleton()->Allocate(count, 0); } + + void operator delete(void* a_ptr) { Scaleform::MemoryHeapPT::GetSingleton()->Free(a_ptr); } + void operator delete(void* a_ptr, std::align_val_t) { Scaleform::MemoryHeapPT::GetSingleton()->Free(a_ptr); } + void operator delete(void* a_ptr, std::size_t) { Scaleform::MemoryHeapPT::GetSingleton()->Free(a_ptr); } + void operator delete(void* a_ptr, std::size_t, std::align_val_t) { Scaleform::MemoryHeapPT::GetSingleton()->Free(a_ptr); } + + // override + virtual bool ShouldHandleEvent(const InputEvent* a_event) override + { + using func_t = bool (*)(BSInputEventUser*, const InputEvent*); + REL::Relocation func(REL::ID(187262)); + return func(this, a_event); + } + + virtual void HandleEvent(const ThumbstickEvent* a_event) override + { + using func_t = void (*)(BSInputEventUser*, const ThumbstickEvent*); + REL::Relocation func(REL::ID(187235)); + return func(this, a_event); + } + + virtual void HandleEvent(const ButtonEvent* a_event) override + { + using func_t = void (*)(BSInputEventUser*, const ButtonEvent*); + REL::Relocation func(REL::ID(187234)); + return func(this, a_event); + } // add - virtual const char* GetName() const; // 03 - virtual const char* GetRootPath() const; // 04 - virtual void Unk_05(void); // 05 - virtual void Unk_06(void); // 06 - virtual bool LoadMovie(bool a_addEventDispatcher, bool a_arg2); // 07 - virtual void Unk_08(void); // 08 - virtual void Unk_09(void); // 09 - virtual void Unk_0A(void); // 0A - virtual void Unk_0B(void); // 0B - virtual void Unk_0C(void); // 0C - virtual void Unk_0D(void); // 0D - virtual void Unk_0E(void); // 0E - virtual void Unk_0F(void); // 0F - virtual void Unk_10(void); // 10 - virtual void Unk_11(void); // 11 - virtual void Unk_12(void); // 12 - virtual void Unk_13(void); // 13 - virtual void Unk_14(void); // 14 - virtual void Unk_15(void); // 15 - virtual void Unk_16(void); // 16 - virtual void Unk_17(void); // 17 - virtual void Unk_18(void); // 18 - virtual void Unk_19(void); // 19 - virtual void Unk_1A(void); // 1A - - Scaleform::GFx::Value menuObj; // 058 - Scaleform::Ptr uiMovie; // 088 - std::uint64_t unk090; // 090 - std::uint64_t unk098; // 098 - std::uint64_t unk0A0; // 0A0 - std::uint32_t unk0A8; // 0A8 - std::uint32_t unk0AC; // 0AC - BSFixedString menuName; // 0B0 - BSFixedString unk0B8; // 0B8 - std::uint64_t unk0C0; // 0C0 - std::uint32_t unk0C8; // 0C8 - std::uint32_t unk0CC; // 0CC - std::uint32_t unk0D0; // 0D0 - std::uint32_t unk0D4; // 0D4 - std::uint64_t unk0D8; // 0D8 - std::uint64_t unk0E0; // 0E0 - std::uint64_t unk0E8; // 0E8 - std::uint64_t unk0F0; // 0F0 - std::uint64_t unk0F8; // 0F8 - std::uint64_t unk100; // 100 - std::uint32_t unk108; // 108 - std::uint32_t unk10C; // 10C - std::uint64_t unk110; // 110 - std::uint64_t unk118; // 118 - std::uint64_t unk120; // 120 - std::uint64_t unk128; // 128 + virtual const char* GetName() const = 0; // 03 + virtual const char* GetRootPath() const = 0; // 04 + virtual uint64_t GetUnk05() = 0; // 05 + + virtual bool LoadMovie(bool a_addEventDispatcher, bool a_arg2) // 06 + { + using func_t = decltype(&IMenu::LoadMovie); + REL::Relocation func(REL::ID(187240)); + return func(this, a_addEventDispatcher, a_arg2); + } + + virtual void Unk07() {} // 07 + + virtual UI_MESSAGE_RESULT ProcessMessage(UIMessageData& a_message) // 08 + { + using func_t = decltype(&IMenu::ProcessMessage); + REL::Relocation func(REL::ID(187247)); + return func(this, a_message); + } + + virtual bool Unk09() // 09 + { + using func_t = decltype(&IMenu::Unk09); + REL::Relocation func(REL::ID(80440)); + return func(this); + } + + virtual bool Unk0A() // 0A + { + using func_t = decltype(&IMenu::Unk0A); + REL::Relocation func(REL::ID(187238)); + return func(this); + } + + virtual void Unk_0B(void) {} // 0B + virtual void Unk_0C(void) {} // 0C + virtual void Unk_0D(void) {} // 0D + + virtual bool Unk0E(void* a, bool b) // 0E + { + using func_t = decltype(&IMenu::Unk0E); + REL::Relocation func(REL::ID(187242)); + return func(this, a, b); + } + + virtual void Unk0F() {}; // 0F + + virtual uint64_t Unk10() // 10 + { + using func_t = decltype(&IMenu::Unk10); + REL::Relocation func(REL::ID(187241)); + return func(this); + }; + + virtual uint64_t Unk11() // 11 + { + using func_t = decltype(&IMenu::Unk11); + REL::Relocation func(REL::ID(187243)); + return func(this); + }; + + virtual uint64_t Unk12() // 12 + { + using func_t = decltype(&IMenu::Unk12); + REL::Relocation func(REL::ID(80451)); + return func(this); + }; + + virtual BSFixedString* Unk13() // 13 + { + using func_t = decltype(&IMenu::Unk13); + REL::Relocation func(REL::ID(76183)); + return func(this); + }; + + virtual bool Unk14() // 14 + { + return true; + }; + + virtual bool Unk15(void* a) // 15 + { + using func_t = decltype(&IMenu::Unk15); + REL::Relocation func(REL::ID(187225)); + return func(this, a); + }; + + virtual bool Unk16() // 16 + { + return false; + + }; + + virtual bool ProcessInputUserEvent() // 17 + { + return false; + }; + + virtual uint64_t Unk18(void* a, uint64_t b) // 18 + { + using func_t = decltype(&IMenu::Unk18); + REL::Relocation func(REL::ID(1275268)); + return func(this, a, b); + } + + virtual uint64_t Unk19(void* a, int b, int c) { // 19 + using func_t = decltype(&IMenu::Unk19); + REL::Relocation func(REL::ID(187245)); + return func(this, a, b, c); + } + + virtual float Unk1A() // 1A + { + using func_t = decltype(&IMenu::Unk1A); + REL::Relocation func(REL::ID(187232)); + return func(this); + }; + + void SetFlags(uint32_t _flags) + { + flags |= _flags; + flagsUpdated = true; + } + + void RemoveFlags(uint32_t _flags) + { + flags &= ~_flags; + flagsUpdated = true; + } + + Scaleform::GFx::Value menuObj; // 058 + Scaleform::Ptr uiMovie; // 088 + std::uint64_t unk090; // 090 + std::uint64_t unk098; // 098 + std::uint64_t unk0A0; // 0A0 + std::uint32_t unk0A8; // 0A8 + std::uint32_t unk0AC; // 0AC + BSFixedString menuName; // 0B0 + BSFixedString unk0B8; // 0B8 + std::uint32_t flags; // 0C0 + std::uint32_t unk0C4; // 0C4 + std::uint32_t unk0C8; // 0C8 + std::uint32_t unk0CC; // 0CC + std::uint16_t unk0D0; // 0D0 + bool flagsUpdated; // 0D2 + std::uint8_t unk0D3; // 0D3 + std::uint32_t unk0D4; // 0D4 + std::uint64_t unk0D8; // 0D8 + std::uint64_t unk0E0; // 0E0 + std::uint64_t unk0E8; // 0E8 + std::uint64_t unk0F0; // 0F0 + std::uint64_t unk0F8; // 0F8 + std::uint64_t unk100; // 100 + std::uint32_t unk108; // 108 + std::uint32_t unk10C; // 10C + std::uint64_t unk110; // 110 + std::uint64_t unk118; // 118 + std::uint64_t unk120; // 120 + std::uint64_t unk128; // 128 }; static_assert(offsetof(IMenu, uiMovie) == 0x088); static_assert(offsetof(IMenu, menuName) == 0x0B0); diff --git a/CommonLibSF/include/RE/M/Main.h b/CommonLibSF/include/RE/M/Main.h new file mode 100644 index 00000000..dd7e940b --- /dev/null +++ b/CommonLibSF/include/RE/M/Main.h @@ -0,0 +1,30 @@ +#pragma once + +namespace RE +{ + class NiAVObject; + class NiCamera; + + class Main + { + public: + struct SceneGraphRoot + { + std::byte unk[120]; + NiAVObject* worldCameraRoot; //NiNode + NiCamera* worldCamera; + }; + static_assert(offsetof(SceneGraphRoot, SceneGraphRoot::worldCamera) == 0x80); + + static SceneGraphRoot* WorldRoot() + { + static REL::Relocation singleton{ REL::ID(887308) }; + return *singleton; + } + + static NiCamera* WorldCamera() + { + return WorldRoot()->worldCamera; + } + }; +} diff --git a/CommonLibSF/include/RE/M/MissileProjectile.h b/CommonLibSF/include/RE/M/MissileProjectile.h index 737327ca..6cfad744 100644 --- a/CommonLibSF/include/RE/M/MissileProjectile.h +++ b/CommonLibSF/include/RE/M/MissileProjectile.h @@ -24,6 +24,8 @@ namespace RE bool waitingToInitialize3D; // 2AC bool unk2AD; // 2AD bool unk2AE; // 2AE + void* unk2AF; + void* unk2B7; }; - static_assert(sizeof(MissileProjectile) == 0x2B0); + static_assert(sizeof(MissileProjectile) == 0x2A0); } diff --git a/CommonLibSF/include/RE/N/NiAVObject.h b/CommonLibSF/include/RE/N/NiAVObject.h new file mode 100644 index 00000000..034482d8 --- /dev/null +++ b/CommonLibSF/include/RE/N/NiAVObject.h @@ -0,0 +1,146 @@ +#pragma once +#include "RE/B/BSFixedString.h" +#include "RE/N/NiTransform.h" +#include "RE/N/NiBound.h" + +namespace RE +{ + class NiRTTI; + class NiNode; + class BSLight; + + struct NiUpdateData + { + float delta = 0; + float unk04 = 0; + float unk08 = 0; + uint32_t unk0C = 0; + NiPoint4* unk10 = nullptr; + NiPoint4* unk18 = nullptr; + uint64_t unk20 = 0; + uint64_t unk28 = 0; + uint64_t unk30 = 0; + uint32_t flags = 0x10; + uint32_t flags2 = 1; + uint32_t flags3 = 1; + uint32_t unk44 = 0; + float unk48 = 0; + uint32_t unk4C = 0; + float unk50 = 0; + float unk54 = 0; + float unk58 = 0; + uint32_t unk5C = 0; + }; + + class NiObject + { + public: + virtual ~NiObject() = default; + virtual void* DeleteThis(); + virtual NiRTTI* GetRTTI(); + virtual NiNode* GetAsNiNode(); + virtual NiNode* GetAsNiSwitchNode(); + virtual void* Unk5() { return nullptr; } + virtual void* Unk6() { return nullptr; } + virtual void* Unk7() { return nullptr; } + virtual void* Unk8() { return nullptr; } + virtual NiAVObject* GetAsBSGeometry() { return nullptr; } + virtual void* Unk10() { return nullptr; } + virtual void* Unk11() { return nullptr; } + virtual void* Unk12() { return nullptr; } + virtual void* Unk13() { return nullptr; } + virtual void* Unk14() { return nullptr; } + virtual void* Unk15() { return nullptr; } + virtual void* Unk16() { return nullptr; } + virtual void* Unk17() { return nullptr; } + virtual void* Unk18() { return nullptr; } + virtual void* Unk19() { return nullptr; } + virtual void* Unk20() { return nullptr; } + virtual void* Unk21() { return nullptr; } + virtual void* Unk22() { return nullptr; } + virtual void* Unk23() { return nullptr; } + virtual void* Unk24() { return nullptr; } + virtual void* Unk25() { return nullptr; } + virtual void* Unk26() { return nullptr; } + virtual void* Unk27() { return nullptr; } + virtual void* Unk28() { return nullptr; } + virtual void* Unk29() { return nullptr; } + virtual void* Unk30() { return nullptr; } + virtual BSLight* GetAsBSLight() { return nullptr; } + virtual void* Unk32() { return nullptr; } + virtual void* Unk33() { return nullptr; } + virtual void* Unk34() { return nullptr; } + virtual void* Unk35() { return nullptr; } + virtual void* Unk36() { return nullptr; } + virtual void* Unk37() { return nullptr; } + virtual void* Unk38() { return nullptr; } + virtual void* Unk39() { return nullptr; } + virtual void* Unk40() { return nullptr; } + virtual void* Unk41(); + virtual void* Unk42(); + virtual void* Unk43(); + virtual void* Unk44(); + virtual void* Unk45(); + virtual void* Unk46(); + virtual void* Unk47(); + virtual void* Unk48(); + virtual void* Unk49(); + virtual void* Unk50(); + virtual void* Unk51(); + virtual void* Unk52(); + virtual void* Unk53(); + virtual void* Unk54(); + }; + + class NiAVObject : public NiObject + { + public: + virtual ~NiAVObject() = default; + virtual void* Unk55(); + virtual void* Unk56(); + virtual void* Unk57(); + virtual void* Unk58(); + virtual void* Unk59(); + virtual void* Unk60(); + virtual void* Unk61(); + virtual NiNode* GetObjectByName(const BSFixedString& name); + virtual void* SetSelectiveUpdateFlags(); + virtual void* Unk64(); + virtual void* Unk65(); + virtual void* Unk66(); + virtual void* Unk67(); + virtual void* Unk68(); + virtual void* Unk69(); + virtual void* Unk70(); + virtual void* Unk71(); + virtual void* Unk72(); + virtual void* Update(NiUpdateData* data); + virtual void* Unk74(); + virtual void* Unk75(); + virtual void* Unk76(); + virtual void* Unk77(); + virtual void* Unk78(); + virtual void* UpdateWorldData(NiUpdateData* data); + virtual void* UpdateTransformAndBounds(NiUpdateData* data); + virtual void* UpdateTransforms(NiUpdateData* data); + virtual void* Unk82(); + virtual void* Unk83(); + + BSFixedString name; + uint32_t refcount; + uint32_t pad0C; + void* controller; + void* unk28; + void* unk30; + NiNode* parent; //38 + NiTransform local; //40 + NiTransform world; //80 + NiTransform previousWorld; //C0 + NiBound worldBound; //100 + void* collisionObject; + uint64_t flags; //118 + void* unk120; + void* unk128; + }; + static_assert(sizeof(NiAVObject) == 0x130); +} diff --git a/CommonLibSF/include/RE/N/NiBound.h b/CommonLibSF/include/RE/N/NiBound.h new file mode 100644 index 00000000..f54c28f1 --- /dev/null +++ b/CommonLibSF/include/RE/N/NiBound.h @@ -0,0 +1,12 @@ +#pragma once +#include "NiPoint3.h" + +namespace RE +{ + class NiBound + { + public: + NiPoint3 center; + float radius; + }; +} diff --git a/CommonLibSF/include/RE/N/NiCamera.h b/CommonLibSF/include/RE/N/NiCamera.h new file mode 100644 index 00000000..83989dc0 --- /dev/null +++ b/CommonLibSF/include/RE/N/NiCamera.h @@ -0,0 +1,92 @@ +#pragma once +#include "RE/N/NiPoint3.h" + +namespace RE +{ + template + class NiRect + { + public: + T left; // 00 + T right; // ?? + T top; // ?? + T bottom; // ?? + }; + + class NiFrustum + { + public: + float left; // 00 + float right; // 04 + float top; // 08 + float bottom; // 0C + float _near; // 10 + float _far; // 14 + bool ortho; // 18 + }; + static_assert(sizeof(NiFrustum) == 0x1C); + + class NiCamera : public NiAVObject + { + public: + virtual ~NiCamera() = default; + //leftBoundary and rightBoundary are outputted based on the W (radius) component of worldPt. + //If the W component is small enough, they are essentially equal, and point to the exact + //XYZ location provided. + //The returned NiPoint2 does not contain any world-to-screen information and can be ignored. + NiPoint2 WorldToScreenInternal(const NiPoint4* worldPt, NiPoint3* leftBoundary, NiPoint3* rightBoundary) + { + using func_t = decltype(&NiCamera::WorldToScreenInternal); + REL::Relocation func{ REL::ID(210415) }; + return func(this, worldPt, leftBoundary, rightBoundary); + } + + //The returned X and Y are in the range -1 to 1, with 1 being top right and -1 being bottom left. + //The returned Z is the distance from the camera to the worldPt, with negative values meaning the + //camera is facing away from the worldPt. + //Note: The Z component is very small due to Starfield's unit scale. + //i.e. distance from player to camera when the camera is close is ~0.0004 + NiPoint3 WorldToScreen(const NiPoint3& worldPt) + { + NiPoint3 result{ 0.0f, 0.0f, -1.0f }; + float worldDiffRotated = ( + ((worldPt.y - world.translate.y) * world.rotate[0][1]) + + ((worldPt.x - world.translate.x) * world.rotate[0][0]) + + ((worldPt.z - world.translate.z) * world.rotate[0][2]) + ) - viewFrustum._near; + + result.z = worldDiffRotated * (1.0f / (viewFrustum._far - viewFrustum._near)); + + float trace = (worldPt.x * worldToCam[3][0]) + (worldPt.y * worldToCam[3][1]) + ((worldPt.z * worldToCam[3][2]) + worldToCam[3][3]); + if (trace <= 0.00001f) { + return result; + } + + float traceInv = 1.0f / trace; + result.x = (((worldPt.y * worldToCam[0][1]) + (worldPt.x * worldToCam[0][0])) + ((worldPt.z * worldToCam[0][2]) + worldToCam[0][3])) * traceInv; + result.y = (((worldPt.y * worldToCam[1][1]) + (worldPt.x * worldToCam[1][0])) + ((worldPt.z * worldToCam[1][2]) + worldToCam[1][3])) * traceInv; + return result; + } + + //Same as WorldToScreen, but normalizes X and Y to the 0 to 1 range, + //and flips the Y component so that 0 is top left and 1 is bottom right. + NiPoint3 WorldToScreenNormalized(const NiPoint3& worldPt) + { + auto result = WorldToScreen(worldPt); + result.x = (result.x + 1.0f) * 0.5f; + result.y = -result.y; + result.y = (result.y + 1.0f) * 0.5f; + return result; + } + + float unk[20]; + float worldToCam[4][4]; + NiFrustum viewFrustum; + float minNearPlaneDist; + float maxFarNearRatio; + NiRect port; + float lodAdjust; + float unk2[24]; + }; + static_assert(offsetof(NiCamera, NiCamera::worldToCam) == 384); +} diff --git a/CommonLibSF/include/RE/N/NiMatrix3.h b/CommonLibSF/include/RE/N/NiMatrix3.h index dc700a3c..2dbb362d 100644 --- a/CommonLibSF/include/RE/N/NiMatrix3.h +++ b/CommonLibSF/include/RE/N/NiMatrix3.h @@ -79,6 +79,18 @@ namespace RE entry[2].pt[0] * p.x + entry[2].pt[1] * p.y + entry[2].pt[2] * p.z); } + RE::NiPoint4& operator[](size_t i) + { + assert(i < 3); + return entry[i]; + } + + const RE::NiPoint4& operator[](size_t i) const + { + assert(i < 3); + return entry[i]; + } + bool ToEulerAnglesXYZ(float& a_x, float& a_y, float& a_z) { using func_t = decltype(&NiMatrix3::ToEulerAnglesXYZ); @@ -86,6 +98,21 @@ namespace RE return func(this, a_x, a_y, a_z); } + NiMatrix3 Transpose() const + { + NiMatrix3 result; + result.entry[0].pt[0] = entry[0].pt[0]; + result.entry[0].pt[1] = entry[1].pt[0]; + result.entry[0].pt[2] = entry[2].pt[0]; + result.entry[1].pt[0] = entry[0].pt[1]; + result.entry[1].pt[1] = entry[1].pt[1]; + result.entry[1].pt[2] = entry[2].pt[1]; + result.entry[2].pt[0] = entry[0].pt[2]; + result.entry[2].pt[1] = entry[1].pt[2]; + result.entry[2].pt[2] = entry[2].pt[2]; + return result; + } + // members NiPoint4 entry[3]; // 00 }; diff --git a/CommonLibSF/include/RE/N/NiPoint3.h b/CommonLibSF/include/RE/N/NiPoint3.h index 9b96d3d7..4805ee9f 100644 --- a/CommonLibSF/include/RE/N/NiPoint3.h +++ b/CommonLibSF/include/RE/N/NiPoint3.h @@ -39,9 +39,9 @@ namespace RE float Unitize(); // members - float x{}; // 0x0 - float y{}; // 0x4 - float z{}; // 0x8 + float x{ 0.0f }; // 0x0 + float y{ 0.0f }; // 0x4 + float z{ 0.0f }; // 0x8 }; static_assert(sizeof(NiPoint3) == 0xC); diff --git a/CommonLibSF/include/RE/N/NiPoint4.h b/CommonLibSF/include/RE/N/NiPoint4.h index 7757867f..8fd348ea 100644 --- a/CommonLibSF/include/RE/N/NiPoint4.h +++ b/CommonLibSF/include/RE/N/NiPoint4.h @@ -22,6 +22,17 @@ namespace RE NiPoint4Struct v; float pt[4]{ 0.0F }; }; // 00 + + float& operator[](size_t i) { + assert(i < 4); + return pt[i]; + } + + const float& operator[](size_t i) const + { + assert(i < 4); + return pt[i]; + } }; static_assert(sizeof(NiPoint4) == 0x10); } diff --git a/CommonLibSF/include/RE/N/NiQuaternion.h b/CommonLibSF/include/RE/N/NiQuaternion.h new file mode 100644 index 00000000..93d2045b --- /dev/null +++ b/CommonLibSF/include/RE/N/NiQuaternion.h @@ -0,0 +1,265 @@ +#pragma once + +namespace RE +{ + class NiQuaternion + { + public: + float w{ 1.0f }; + float x{ 0.0f }; + float y{ 0.0f }; + float z{ 0.0f }; + + NiQuaternion() {} + + NiQuaternion(float w, float x, float y, float z) : + w(w), x(x), y(y), z(z) {} + + NiQuaternion(const NiMatrix3& mat) + { + FromMatrix(mat); + } + + static NiQuaternion Slerp(const NiQuaternion& prev, NiQuaternion next, float t) + { + NiQuaternion result; + float dot = prev.Dot(next); + if (dot < 0.0f) { + next = -next; + dot = -dot; + } + + const float epsilon = 1e-6f; + if (1.0f - dot > epsilon) { + float theta = std::acosf(dot); + float sinTheta = std::sinf(theta); + float weight1 = std::sinf((1.0f - t) * theta) / sinTheta; + float weight2 = std::sinf(t * theta) / sinTheta; + + result = (prev * weight1) + (next * weight2); + } else { + float tInverse = 1.0f - t; + result.w = tInverse * prev.w + t * next.w; + result.x = tInverse * prev.x + t * next.x; + result.y = tInverse * prev.y + t * next.y; + result.z = tInverse * prev.z + t * next.z; + } + + return result; + } + + static NiQuaternion EulerZXY(const NiPoint3& euler) + { + NiQuaternion result; + result.FromEulerAnglesZXY(euler); + return result; + } + + static NiQuaternion AngleAxis(float angle, const NiPoint3& axis) + { + NiQuaternion result; + result.FromAngleAxis(angle, axis); + return result; + } + + NiPoint3 ToEulerAnglesZXY() const + { + NiPoint3 euler; + euler.x = std::atan2(2.0f * (w * x + y * z), 1.0f - 2.0f * (x * x + y * y)); + euler.y = std::asin(2.0f * (w * y - z * x)); + euler.z = std::atan2(2.0f * (w * z + x * y), 1.0f - 2.0f * (y * y + z * z)); + + return euler; + } + + void FromEulerAnglesZXY(const NiPoint3& euler) + { + float cy = std::cos(euler.z * 0.5f); + float sy = std::sin(euler.z * 0.5f); + float cp = std::cos(euler.y * 0.5f); + float sp = std::sin(euler.y * 0.5f); + float cr = std::cos(euler.x * 0.5f); + float sr = std::sin(euler.x * 0.5f); + + w = cr * cp * cy + sr * sp * sy; + x = sr * cp * cy - cr * sp * sy; + y = cr * sp * cy + sr * cp * sy; + z = cr * cp * sy - sr * sp * cy; + } + + void FromAngleAxis(float angle, const NiPoint3& axis) + { + float halfAngle = angle / 2.0f; + w = std::cos(halfAngle); + x = std::sin(halfAngle) * axis.x; + y = std::sin(halfAngle) * axis.y; + z = std::sin(halfAngle) * axis.z; + } + + void ToMatrix(NiMatrix3& a_mat) const + { + float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; + x2 = x + x; + y2 = y + y; + z2 = z + z; + xx = x * x2; + xy = x * y2; + xz = x * z2; + yy = y * y2; + yz = y * z2; + zz = z * z2; + wx = w * x2; + wy = w * y2; + wz = w * z2; + + a_mat[0][0] = 1.0f - (zz + yy); + a_mat[0][1] = xy + wz; + a_mat[0][2] = xz - wy; + a_mat[0][3] = 0.0f; + + a_mat[1][0] = xy - wz; + a_mat[1][1] = 1.0f - (zz + xx); + a_mat[1][2] = yz + wx; + a_mat[1][3] = 0.0f; + + a_mat[2][0] = xz + wy; + a_mat[2][1] = yz - wx; + a_mat[2][2] = 1.0f - (yy + xx); + a_mat[2][3] = 0.0f; + } + + void FromMatrix(const NiMatrix3& a_mat) + { + auto& q = *this; + float trace = a_mat[0][0] + a_mat[1][1] + a_mat[2][2]; + + if (trace <= 0.0f) { + int i = (a_mat[1][1] > a_mat[0][0]) ? 1 : 0; + + if (a_mat[2][2] > a_mat[i][i]) { + i = 2; + } + + const int next[4] = { + 1, 2, 0, 0 + }; + + int j = next[i]; + int k = next[j]; + + float root = std::sqrtf(((a_mat[i][i] - a_mat[j][j]) - a_mat[k][k]) + 1.0f); + q[i + 1] = root * 0.5f; + root = 0.5f / root; + q[0] = (a_mat[j][k] - a_mat[k][j]) * root; + q[j + 1] = (a_mat[j][i] + a_mat[i][j]) * root; + q[k + 1] = (a_mat[i][k] + a_mat[k][i]) * root; + } else { + float root = std::sqrtf(trace + 1.0f); + q[0] = root * 0.5f; + root = 0.5f / root; + q[1] = (a_mat[1][2] - a_mat[2][1]) * root; + q[2] = (a_mat[2][0] - a_mat[0][2]) * root; + q[3] = (a_mat[0][1] - a_mat[1][0]) * root; + } + } + + float Dot() const + { + return w * w + x * x + y * y + z * z; + } + + float Dot(const NiQuaternion& q) const + { + return w * q.w + x * q.x + y * q.y + z * q.z; + } + + float Magnitude() const + { + return std::sqrt(Dot()); + } + + //Faster than Normalize(), but with less precision. + NiQuaternion FastNormalize() const + { + __m128 temp = _mm_set_ss(Dot()); + temp = _mm_rsqrt_ss(temp); + float rsqrt = _mm_cvtss_f32(temp); + return { w * rsqrt, x * rsqrt, y * rsqrt, z * rsqrt }; + } + + NiQuaternion Normalize() const + { + float rsqrt = 1.0f / Magnitude(); + return { w * rsqrt, x * rsqrt, y * rsqrt, z * rsqrt }; + } + + NiQuaternion InvertVector() const + { + return { w, -x, -y, -z }; + } + + NiQuaternion InvertScalar() const + { + return { -w, x, y, z }; + } + + float& operator[](size_t i) + { + assert(i < 4); + return (&w)[i]; + } + + const float& operator[](size_t i) const + { + assert(i < 4); + return (&w)[i]; + } + + NiQuaternion operator*(const NiQuaternion& a_rhs) const + { + return { + a_rhs.w * w - a_rhs.x * x - a_rhs.y * y - a_rhs.z * z, + a_rhs.w * x + a_rhs.x * w - a_rhs.y * z + a_rhs.z * y, + a_rhs.w * y + a_rhs.x * z + a_rhs.y * w - a_rhs.z * x, + a_rhs.w * z - a_rhs.x * y + a_rhs.y * x + a_rhs.z * w + }; + } + + NiPoint3 operator*(const NiPoint3& a_rhs) const + { + NiQuaternion res = (*this) * NiQuaternion{ 0.0f, a_rhs.x, a_rhs.y, a_rhs.z } * InvertVector(); + return { res.x, res.y, res.z }; + } + + void operator*=(const NiQuaternion& a_rhs) + { + (*this) = operator*(a_rhs); + } + + NiQuaternion operator*(float s) const + { + return { w * s, x * s, y * s, z * s }; + } + + NiQuaternion operator+(const NiQuaternion& a_rhs) const + { + return { w + a_rhs.w, x + a_rhs.x, y + a_rhs.y, z + a_rhs.z }; + } + + NiQuaternion operator-(const NiQuaternion& a_rhs) const + { + return { w - a_rhs.w, x - a_rhs.x, y - a_rhs.y, z - a_rhs.z }; + } + + NiQuaternion operator/(float s) const + { + return { w / s, x / s, y / s, z / s }; + } + + NiQuaternion operator-() const + { + return { -w, -x, -y, -z }; + } + }; + static_assert(sizeof(NiQuaternion) == 0x10); +} diff --git a/CommonLibSF/include/RE/N/NiTransform.h b/CommonLibSF/include/RE/N/NiTransform.h index 28ed90ec..cd4092cc 100644 --- a/CommonLibSF/include/RE/N/NiTransform.h +++ b/CommonLibSF/include/RE/N/NiTransform.h @@ -8,6 +8,11 @@ namespace RE class NiTransform { public: + // members + NiMatrix3 rotate; // 00 + NiPoint3 translate; // 30 + float scale{ 1.0F }; // 3C + void MakeIdentity() noexcept { rotate.MakeIdentity(); @@ -15,10 +20,38 @@ namespace RE scale = 1.0F; } - // members - NiMatrix3 rotate; // 00 - NiPoint3 translate; // 30 - float scale{ 1.0F }; // 3C + NiTransform operator*(const NiTransform& a_rhs) const + { + NiTransform result; + result.scale = scale * a_rhs.scale; + result.rotate = rotate * a_rhs.rotate; + result.translate = translate + (rotate * a_rhs.translate) * scale; + return result; + } + + void operator*=(const NiTransform& a_rhs) + { + *this = *this * a_rhs; + } + + NiTransform operator/(const NiTransform& a_rhs) const + { + return Inverse() * a_rhs; + } + + void operator/=(const NiTransform& a_rhs) + { + *this = *this / a_rhs; + } + + NiTransform Inverse() const + { + NiTransform result; + result.scale = scale == 0.0f ? 1.0f : 1.0f / scale; + result.rotate = rotate.Transpose(); + result.translate = result.rotate * (-translate / result.scale); + return result; + } }; static_assert(sizeof(NiTransform) == 0x40); } diff --git a/CommonLibSF/include/RE/P/PlasmaProjectile.h b/CommonLibSF/include/RE/P/PlasmaProjectile.h index 67a562fc..d85105ae 100644 --- a/CommonLibSF/include/RE/P/PlasmaProjectile.h +++ b/CommonLibSF/include/RE/P/PlasmaProjectile.h @@ -12,5 +12,5 @@ namespace RE ~PlasmaProjectile() override; // 00 }; - static_assert(sizeof(PlasmaProjectile) == 0x2A0); + static_assert(sizeof(PlasmaProjectile) == 0x280); } diff --git a/CommonLibSF/include/RE/P/PlayerCharacter.h b/CommonLibSF/include/RE/P/PlayerCharacter.h index 70653c60..e36aec29 100644 --- a/CommonLibSF/include/RE/P/PlayerCharacter.h +++ b/CommonLibSF/include/RE/P/PlayerCharacter.h @@ -410,5 +410,5 @@ namespace RE std::uint32_t unk10D4; // 10D4 std::uint64_t unk10D8; // 10D8 }; - static_assert(sizeof(PlayerCharacter) == 0x10E0); + static_assert(sizeof(PlayerCharacter) == 0x1120); } diff --git a/CommonLibSF/include/RE/P/Projectile.h b/CommonLibSF/include/RE/P/Projectile.h index 0fb24b69..7eb2f52c 100644 --- a/CommonLibSF/include/RE/P/Projectile.h +++ b/CommonLibSF/include/RE/P/Projectile.h @@ -223,5 +223,5 @@ namespace RE bool animationsLoaded; // 25B std::uint8_t unk25C; // 25C }; - static_assert(sizeof(Projectile) == 0x260); + static_assert(sizeof(Projectile) == 0x240); } diff --git a/CommonLibSF/include/RE/S/SWFToCodeFunctionHandler.h b/CommonLibSF/include/RE/S/SWFToCodeFunctionHandler.h index bd211cae..50e1d07a 100644 --- a/CommonLibSF/include/RE/S/SWFToCodeFunctionHandler.h +++ b/CommonLibSF/include/RE/S/SWFToCodeFunctionHandler.h @@ -17,6 +17,13 @@ namespace RE // add virtual void MapCodeObjectFunctions() { return; } // 02 + + void RegisterNativeFunction(const char* name, uint64_t idx) + { + using func_t = decltype(&SWFToCodeFunctionHandler::RegisterNativeFunction); + REL::Relocation func(REL::ID(187274)); + func(this, name, idx); + } }; static_assert(sizeof(SWFToCodeFunctionHandler) == 0x10); } diff --git a/CommonLibSF/include/RE/S/ScaleformGFxValue.h b/CommonLibSF/include/RE/S/ScaleformGFxValue.h index e3e76980..1c6bd153 100644 --- a/CommonLibSF/include/RE/S/ScaleformGFxValue.h +++ b/CommonLibSF/include/RE/S/ScaleformGFxValue.h @@ -322,8 +322,9 @@ namespace RE::Scaleform::GFx // members MovieImpl* movieRoot; // 08 + Value* lastValue; }; - static_assert(sizeof(ObjectInterface) == 0x10); + static_assert(sizeof(ObjectInterface) == 0x18); using ArrayVisitor = ObjectInterface::ArrVisitor; using ObjectVisitor = ObjectInterface::ObjVisitor; @@ -340,14 +341,19 @@ namespace RE::Scaleform::GFx } } - Value(Value&& a_rhs) noexcept : - _objectInterface(a_rhs._objectInterface), - _type(a_rhs._type), - _value(std::move(a_rhs._value)), - _dataAux(a_rhs._dataAux) + Value(Value&& a_rhs) noexcept { - a_rhs._objectInterface = nullptr; + _type = a_rhs._type; + _value = a_rhs._value; + _dataAux = a_rhs._dataAux; + + if (a_rhs.IsManagedValue()) { + AcquireManagedValue(a_rhs); + a_rhs.ReleaseManagedValue(); + } + a_rhs._type = ValueType::kUndefined; + a_rhs._value = 0; a_rhs._dataAux = 0; } @@ -419,15 +425,17 @@ namespace RE::Scaleform::GFx ReleaseManagedValue(); } - _objectInterface = a_rhs._objectInterface; - a_rhs._objectInterface = nullptr; - _type = a_rhs._type; - a_rhs._type = ValueType::kUndefined; + _value = a_rhs._value; + _dataAux = a_rhs._dataAux; - _value = std::move(a_rhs._value); + if (a_rhs.IsManagedValue()) { + AcquireManagedValue(a_rhs); + a_rhs.ReleaseManagedValue(); + } - _dataAux = a_rhs._dataAux; + a_rhs._type = ValueType::kUndefined; + a_rhs._value = 0; a_rhs._dataAux = 0; } return *this; @@ -733,8 +741,8 @@ namespace RE::Scaleform::GFx } // members - void* _unk00{}; // 00 - void* _unk08{}; // 08 + Value* _prev{}; // 00 + Value* _next{}; // 08 ObjectInterface* _objectInterface{}; // 10 stl::enumeration _type{ ValueType::kUndefined }; // 18 ValueUnion _value{}; // 20 diff --git a/CommonLibSF/include/RE/S/ScaleformMemoryHeap.h b/CommonLibSF/include/RE/S/ScaleformMemoryHeap.h new file mode 100644 index 00000000..ad507136 --- /dev/null +++ b/CommonLibSF/include/RE/S/ScaleformMemoryHeap.h @@ -0,0 +1,63 @@ +#pragma once + +namespace RE::Scaleform +{ + class MemoryHeap + { + public: + virtual ~MemoryHeap(); + virtual void Unk1(); + virtual void Unk2(); + virtual void Unk3(); + virtual void Unk4(); + virtual void Unk5(); + virtual void Unk6(); + virtual void Unk7(); + virtual void Unk8(); + virtual void Unk9(); + virtual void* Allocate(uint64_t size, void* unk); + virtual void Unk11(); + virtual void Free(void*); + virtual void Unk13(); + virtual void Unk14(); + virtual void Unk15(); + virtual void Unk16(); + virtual void Unk17(); + virtual void Unk18(); + virtual void Unk19(); + virtual void Unk20(); + virtual void Unk21(); + virtual void Unk22(); + virtual void Unk23(); + virtual void Unk24(); + virtual void Unk25(); + virtual void Unk26(); + virtual void Unk27(); + virtual void Unk28(); + virtual void Unk29(); + virtual void Unk30(); + virtual void Unk31(); + virtual void Unk32(); + virtual void Unk33(); + virtual void Unk34(); + virtual void Unk35(); + virtual void Unk36(); + virtual void Unk37(); + virtual void Unk38(); + virtual void Unk39(); + virtual void Unk40(); + virtual void Unk41(); + virtual void Unk42(); + virtual void Unk43(); + }; + + class MemoryHeapPT : public MemoryHeap + { + public: + static MemoryHeapPT* GetSingleton() + { + REL::Relocation memoryHeapPT(REL::ID(820297)); + return *memoryHeapPT; + } + }; +} diff --git a/CommonLibSF/include/RE/Starfield.h b/CommonLibSF/include/RE/Starfield.h index 7a7929ac..49dc4137 100644 --- a/CommonLibSF/include/RE/Starfield.h +++ b/CommonLibSF/include/RE/Starfield.h @@ -182,6 +182,8 @@ #include "RE/B/BSFixedString.h" #include "RE/B/BSFloat3DCurve.h" #include "RE/B/BSFloatCurve.h" +#include "RE/B/BSInputEnableLayer.h" +#include "RE/B/BSInputEnableManager.h" #include "RE/B/BSInputEventReceiver.h" #include "RE/B/BSInputEventUser.h" #include "RE/B/BSIntrusiveRefCounted.h" @@ -195,6 +197,7 @@ #include "RE/B/BSTEvent.h" #include "RE/B/BSTList.h" #include "RE/B/BSTOptional.h" +#include "RE/B/BSTScatterTable.h" #include "RE/B/BSTSingleton.h" #include "RE/B/BSTSmartPointer.h" #include "RE/B/BSTTuple.h" @@ -202,6 +205,7 @@ #include "RE/B/BarrierProjectile.h" #include "RE/B/BaseFormComponent.h" #include "RE/B/BeamProjectile.h" +#include "RE/B/BGSSaveLoadManager.h" #include "RE/C/CodeTasklet.h" #include "RE/C/CollisionLayers.h" #include "RE/C/Color.h" @@ -272,13 +276,18 @@ #include "RE/M/Misc.h" #include "RE/M/MissileProjectile.h" #include "RE/M/msvc.h" +#include "RE/M/Main.h" #include "RE/N/NativeFunction.h" #include "RE/N/NativeFunctionBase.h" +#include "RE/N/NiAVObject.h" +#include "RE/N/NiBound.h" +#include "RE/N/NiCamera.h" #include "RE/N/NiColor.h" #include "RE/N/NiMatrix3.h" #include "RE/N/NiPoint2.h" #include "RE/N/NiPoint3.h" #include "RE/N/NiPoint4.h" +#include "RE/N/NiQuaternion.h" #include "RE/N/NiSmartPointer.h" #include "RE/N/NiTransform.h" #include "RE/O/Object.h" @@ -303,6 +312,7 @@ #include "RE/S/ScaleformGFxState.h" #include "RE/S/ScaleformGFxStateBag.h" #include "RE/S/ScaleformGFxValue.h" +#include "RE/S/ScaleformMemoryHeap.h" #include "RE/S/ScaleformPtr.h" #include "RE/S/ScaleformRefCount.h" #include "RE/S/Script.h" @@ -395,6 +405,7 @@ #include "RE/T/TESWorldSpace.h" #include "RE/T/TypeInfo.h" #include "RE/U/UI.h" +#include "RE/U/UIMessageQueue.h" #include "RE/V/Variable.h" #include "RE/W/WwiseGUID.h" #include "RE/W/WwiseSoundHook.h" diff --git a/CommonLibSF/include/RE/T/TESObjectREFR.h b/CommonLibSF/include/RE/T/TESObjectREFR.h index 50623fb4..194d367b 100644 --- a/CommonLibSF/include/RE/T/TESObjectREFR.h +++ b/CommonLibSF/include/RE/T/TESObjectREFR.h @@ -110,11 +110,11 @@ namespace RE { public: // members - NiPoint3A angle; // 00 - NiPoint3A location; // 10 - NiPointer objectReference; // 20 - ref counted in SetObjectReference vfunc + NiPoint3 angle; // 00 + NiPoint3 location; // 0C + NiPointer objectReference; // 18 - ref counted in SetObjectReference vfunc }; - static_assert(sizeof(OBJ_REFR) == 0x30); + static_assert(sizeof(OBJ_REFR) == 0x20); struct LOADED_REF_DATA { @@ -359,7 +359,7 @@ namespace RE void ForEachEquippedItem(std::function a_callback) const; void ForEachInventoryItem(std::function a_callback) const; - [[nodiscard]] constexpr NiPoint3A GetAngle() const { return data.angle; } + [[nodiscard]] constexpr NiPoint3 GetAngle() const { return data.angle; } [[nodiscard]] constexpr float GetAngleX() const { return data.angle.x; } [[nodiscard]] constexpr float GetAngleY() const { return data.angle.y; } [[nodiscard]] constexpr float GetAngleZ() const { return data.angle.z; } @@ -370,7 +370,7 @@ namespace RE [[nodiscard]] REFR_LOCK* GetLock() const; [[nodiscard]] LOCK_LEVEL GetLockLevel() const; [[nodiscard]] TESWorldSpace* GetParentWorldSpace(); - [[nodiscard]] constexpr NiPoint3A GetPosition() const noexcept { return data.location; } + [[nodiscard]] constexpr NiPoint3 GetPosition() const noexcept { return data.location; } [[nodiscard]] constexpr float GetPositionX() const noexcept { return data.location.x; } [[nodiscard]] constexpr float GetPositionY() const noexcept { return data.location.y; } [[nodiscard]] constexpr float GetPositionZ() const noexcept { return data.location.z; } @@ -389,17 +389,17 @@ namespace RE void Unlock(); // members - OBJ_REFR data; // 80 - BSGuarded inventoryList; // B0 - TESObjectCELL* parentCell; // C0 - BSGuarded loadedData; // C8 - BSTSmartPointer extraDataList; // D8 - std::uint16_t scale; // E0 - std::uint8_t unkE2; // E2 - std::uint8_t flags; // E3 + 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 private: void AddLockChange(); }; - static_assert(sizeof(TESObjectREFR) == 0xF0); + static_assert(sizeof(TESObjectREFR) == 0xD0); } diff --git a/CommonLibSF/include/RE/U/UI.h b/CommonLibSF/include/RE/U/UI.h index 6cb6f2b6..1cc823dd 100644 --- a/CommonLibSF/include/RE/U/UI.h +++ b/CommonLibSF/include/RE/U/UI.h @@ -1,4 +1,9 @@ #pragma once +#include "RE/B/BSTArray.h" +#include "RE/B/BSTEvent.h" +#include "RE/B/BSInputEventReceiver.h" +#include "RE/B/BSTScatterTable.h" +#include "RE/I/IMenu.h" namespace RE { @@ -17,6 +22,8 @@ namespace RE struct MenuPauseChangeEvent; struct MenuPauseCounterChangeEvent; struct TutorialEvent; + struct MenuOpenCloseEvent; + struct MenuModeChangeEvent; class UI : //public BSTSingletonSDM, @@ -34,6 +41,17 @@ namespace RE public: SF_RTTI_VTABLE(UI); + struct UIMenuEntry + { + using Create_t = Scaleform::Ptr*(Scaleform::Ptr*); + + Scaleform::Ptr menu; + Create_t* initFunc; + void* unk18 = nullptr; + uint64_t unk20 = 1; + uint64_t unk28 = 0; + }; + template [[nodiscard]] auto GetEventSource() { @@ -53,6 +71,29 @@ namespace RE return func(this, a_name); } + bool IsMenuRegistered(const BSFixedString& a_name) + { + return menuMap.contains(a_name); + } + + template + requires(std::derived_from) + bool RegisterMenu(const BSFixedString& a_name) + { + if (menuMap.contains(a_name)) + return false; + + auto& entry = menuMap[a_name]; + entry.initFunc = [](Scaleform::Ptr* menu) { + auto createdMenu = new T(); + REL::Relocation*(Scaleform::Ptr*, T*)> CopyRef(REL::ID(80375)); + CopyRef(menu, createdMenu); + return menu; + }; + + return true; + } + template void RegisterSink(BSTEventSink* a_sink) { @@ -65,8 +106,18 @@ namespace RE GetEventSource()->UnregisterSink(a_sink); } - std::uint8_t pad178[0x278]; // 178 - BSTArray> menuStack; // 3F0 + std::uint8_t pad178[0x278]; // 178 + BSTArray> menuStack; // 3F0 + std::uint8_t pad02[0x18]; + uint64_t unk418; + uint64_t unk420; + uint64_t unk428; + BSTHashMap menuMap; //430 + void* unk460_4F8[18]; + uint16_t unk4F8; + bool menusVisible; // 4FA }; static_assert(offsetof(UI, menuStack) == 0x3F0); + static_assert(offsetof(UI, menuMap) == 0x430); + static_assert(offsetof(UI, menusVisible) == 0x4FA); } diff --git a/CommonLibSF/include/RE/U/UIMessageQueue.h b/CommonLibSF/include/RE/U/UIMessageQueue.h new file mode 100644 index 00000000..d9fa5de3 --- /dev/null +++ b/CommonLibSF/include/RE/U/UIMessageQueue.h @@ -0,0 +1,50 @@ +#pragma once + +namespace RE +{ + enum UIMessage : uint32_t + { + kShow = 0, + kHide = 2 + }; + + class IUIMessageData + { + public: + virtual ~IUIMessageData() = default; + virtual void* GetRTTI() = 0; + }; + + class UIMessageData + { + public: + virtual ~UIMessageData() = default; + + UIMessage type; //08 + //...more? + }; + + enum UI_MESSAGE_RESULT : int64_t + { + kHandled = 0, + kIgnore, + kPassOn + }; + + class UIMessageQueue + { + public: + static UIMessageQueue* GetSingleton() + { + REL::Relocation singleton{ REL::ID(878637) }; + return *singleton; + } + + int64_t AddMessage(const BSFixedString& a_menuName, UIMessage a_message) + { + using func_t = decltype(&UIMessageQueue::AddMessage); + REL::Relocation func{ REL::ID(187268) }; + return func(this, a_menuName, a_message); + } + }; +}