#pragma once #include template struct GameArray { T* data; alignas(sizeof(void*)) uint32_t capacity; // Might be size_t alignas(sizeof(void*)) uint32_t length; // Might be size_t GameArray() : data{nullptr} , capacity{} , length{0} { } ~GameArray() = default; T& operator[](uint32_t aIndex) { return data[aIndex]; } const T& operator[](uint32_t aIndex) const { return data[aIndex]; } void Resize(size_t aLength) noexcept; // Range for loop compatibility struct Iterator { Iterator(T* apEntry) : m_pEntry(apEntry) { } Iterator operator++() { ++m_pEntry; return *this; } bool operator!=(const Iterator& acRhs) const { return m_pEntry != acRhs.m_pEntry; } const T& operator*() const { return *m_pEntry; } private: T* m_pEntry; }; Iterator begin() { return Iterator(&data[0]); } Iterator end() { return Iterator(&data[length]); } struct ConstIterator { ConstIterator(const T* apEntry) : m_pEntry(apEntry) {} ConstIterator operator++() { ++m_pEntry; return *this; } bool operator!=(const ConstIterator& acRhs) const { return m_pEntry != acRhs.m_pEntry; } const T& operator*() const { return *m_pEntry; } private: const T* m_pEntry; }; ConstIterator begin() const { return ConstIterator(&data[0]); } ConstIterator end() const { return ConstIterator(&data[length]); } inline bool Empty() const noexcept { return length == 0; } }; template void GameArray::Resize(size_t aLength) noexcept { if (capacity >= aLength) { length = aLength & 0xFFFFFFFF; } else { T* pNewData = reinterpret_cast(Memory::Allocate(sizeof(T) * aLength)); std::copy(data, data + length, pNewData); Memory::Free(data); data = pNewData; capacity = length = aLength; } } static_assert(offsetof(GameArray, length) == 0x10); static_assert(sizeof(GameArray) == 0x18); template struct BSTSmallArray { int32_t capacity; // 0 T** data; // 8 uint32_t size; // 10 T* Get(uint32_t aIndex) { auto pData = reinterpret_cast(&data); if (capacity >= 0) pData = data; return pData[aIndex]; } }; #if TP_PLATFORM_64 static_assert(offsetof(BSTSmallArray, size) == 0x10); static_assert(sizeof(BSTSmallArray) == 0x18); #else static_assert(offsetof(BSTSmallArray, size) == 0x8); static_assert(sizeof(BSTSmallArray) == 0xC); #endif template struct GameList { struct Entry { T* data; Entry* next; }; Entry entry; inline bool Empty() const noexcept { return entry.data == nullptr; } inline size_t Size() const noexcept { if (entry.data == nullptr) return 0ULL; size_t size = 0; for (const Entry* current = &entry; current; current = current->next) size++; return size; } // Range for loop compatibility struct Iterator { Iterator(Entry* apEntry) : m_pEntry(apEntry) { } Iterator operator++() { m_pEntry = m_pEntry->next; return *this; } bool operator!=(const Iterator& acRhs) const { return m_pEntry != acRhs.m_pEntry; } T* operator*() const { return m_pEntry->data; } private: Entry* m_pEntry; }; Iterator begin() { return Iterator(&entry); } Iterator end() { return Iterator(nullptr); } }; #if TP_PLATFORM_64 static_assert(offsetof(GameArray, length) == 0x10); static_assert(sizeof(GameArray) == 0x18); #else static_assert(offsetof(GameArray, length) == 0x8); #endif struct NiRefObject { virtual ~NiRefObject(); virtual void Destroy(); void IncRef(); void DecRef(); bool Release(); volatile long refCount; uint32_t padC; }; #if TP_PLATFORM_64 static_assert(sizeof(NiRefObject) == 0x10); #endif struct BSHandleRefObject : NiRefObject { void DecRefHandle() { if ((InterlockedDecrement(&refCount) & 0x3FF) == 0) Destroy(); } }; struct NiPoint3 : glm::vec3 { NiPoint3() : glm::vec3() { } NiPoint3(const glm::vec3& acRhs) : glm::vec3(acRhs) { } float* AsArray() { return &x; } }; static_assert(sizeof(NiPoint3) == 12); static_assert(offsetof(NiPoint3, x) == 0); static_assert(offsetof(NiPoint3, y) == 4); static_assert(offsetof(NiPoint3, z) == 8); struct NiPoint2 : glm::vec2 { float* AsArray() { return &x; } }; static_assert(sizeof(NiPoint2) == 8); static_assert(offsetof(NiPoint2, x) == 0); static_assert(offsetof(NiPoint2, y) == 4); struct BSRecursiveLock { volatile DWORD m_tid; volatile LONG m_counter; void Lock(); void Unlock(); }; template struct BSScopedLock { BSScopedLock(T& aLock) : m_lock(aLock) { m_lock.Lock(); } ~BSScopedLock() { m_lock.Unlock(); } private: T& m_lock; }; template struct GamePtr { GamePtr() : m_pPointer(nullptr) { } GamePtr(T* apPointer) : m_pPointer(apPointer) { if (m_pPointer) m_pPointer->handleRefObject.IncRef(); } GamePtr(const GamePtr& acRhs) : m_pPointer(acRhs.m_pPointer) { if (m_pPointer) m_pPointer->handleRefObject.IncRef(); } GamePtr(GamePtr&& aRhs) { std::swap(m_pPointer, aRhs.m_pPointer); } GamePtr& operator=(const GamePtr& acRhs) { Release(); m_pPointer = acRhs.m_pPointer; if (m_pPointer) m_pPointer->handleRefObject.IncRef(); return *this; } GamePtr& operator=(T* apPointer) { Release(); m_pPointer = apPointer; if (m_pPointer) m_pPointer->handleRefObject.IncRef(); return *this; } GamePtr& operator=(GamePtr&& aRhs) { std::swap(m_pPointer, aRhs.m_pPointer); return *this; } T* operator->() { return m_pPointer; } T* operator*() { return m_pPointer; } operator T*() { return m_pPointer; } ~GamePtr() { Release(); } void Release() { if (m_pPointer) m_pPointer->handleRefObject.DecRefHandle(); m_pPointer = nullptr; } private: T* m_pPointer; }; struct alignas(sizeof(void*)) BSIntrusiveRefCounted { volatile int32_t refCount; }; static_assert(sizeof(BSIntrusiveRefCounted) == sizeof(void*)); enum ETiltedFlags : uint8_t { kRemote = 1 << 0 }; template Target* niptr_cast(const Source& acSrc) { return static_cast(acSrc.object); } template struct BSUntypedPointerHandle { uint32_t iBits = 0; }; template > struct BSPointerHandle { BSPointerHandle() = default; operator bool() const { return handle.iBits != 0; } THandle handle{}; }; struct BSReadWriteLock { uint32_t uiWriterThread; volatile uint32_t uiLock; };