diff --git a/include/RED4ext/CString-inl.hpp b/include/RED4ext/CString-inl.hpp deleted file mode 100644 index fdd71c3bf..000000000 --- a/include/RED4ext/CString-inl.hpp +++ /dev/null @@ -1,144 +0,0 @@ -#pragma once - -#ifdef RED4EXT_STATIC_LIB -#include -#endif - -#include - -#include -#include - -RED4EXT_INLINE RED4ext::CString::CString(Memory::IAllocator* aAllocator) - : text{} - , length(0) - , allocator(aAllocator ? *reinterpret_cast(aAllocator) : nullptr) -{ -} - -RED4EXT_INLINE RED4ext::CString::CString(const char* aText, Memory::IAllocator* aAllocator) - : CString(aAllocator) -{ - static UniversalRelocFunc func(Detail::AddressHashes::CString_ctor_str); - func(this, aText); -} - -RED4EXT_INLINE RED4ext::CString::CString(const char* aText, uint32_t aLength, Memory::IAllocator* aAllocator) - : CString(aAllocator) -{ - static UniversalRelocFunc func( - Detail::AddressHashes::CString_ctor_span); - func(this, aText, aLength); -} - -RED4EXT_INLINE RED4ext::CString::CString(const std::string& aText, Memory::IAllocator* aAllocator) - : CString(aAllocator) -{ - static UniversalRelocFunc func(Detail::AddressHashes::CString_ctor_str); - func(this, aText.data()); -} - -RED4EXT_INLINE RED4ext::CString::CString(const std::string_view& aText, Memory::IAllocator* aAllocator) - : CString(aAllocator) -{ - static UniversalRelocFunc func( - Detail::AddressHashes::CString_ctor_span); - func(this, aText.data(), static_cast(aText.size())); -} - -RED4EXT_INLINE RED4ext::CString::CString(const CString& aOther) - : CString() -{ - static UniversalRelocFunc func(Detail::AddressHashes::CString_copy); - func(this, aOther); -} - -RED4EXT_INLINE RED4ext::CString::~CString() -{ - static UniversalRelocFunc func(Detail::AddressHashes::CString_dtor); - func(this); -} - -RED4EXT_INLINE RED4ext::CString::CString(CString&& aOther) noexcept - : length(aOther.length) - , allocator(aOther.allocator) -{ - std::memmove(&text, &aOther.text, sizeof(text)); - - std::memset(&aOther.text, 0, sizeof(aOther.text)); - aOther.length = 0; - aOther.allocator = nullptr; -} - -RED4EXT_INLINE RED4ext::CString& RED4ext::CString::operator=(const CString& aRhs) -{ - static UniversalRelocFunc func(Detail::AddressHashes::CString_copy); - func(this, aRhs); - return *this; -} - -RED4EXT_INLINE RED4ext::CString& RED4ext::CString::operator=(CString&& aRhs) noexcept -{ - std::memmove(&text, &aRhs.text, sizeof(text)); - - length = aRhs.length; - allocator = aRhs.allocator; - - std::memset(&aRhs.text, 0, sizeof(aRhs.text)); - aRhs.length = 0; - aRhs.allocator = nullptr; - - return *this; -} - -RED4EXT_INLINE bool RED4ext::CString::operator==(const char* aRhs) const noexcept -{ - auto lhsText = c_str(); - if (!lhsText || !aRhs) - { - return false; - } - - return strcmp(lhsText, aRhs) == 0; -} - -RED4EXT_INLINE bool RED4ext::CString::operator==(const CString& aRhs) const noexcept -{ - auto lhsText = c_str(); - if (!lhsText) - { - return false; - } - auto rhsText = aRhs.c_str(); - if (!rhsText) - { - return false; - } - - if (Length() != aRhs.Length()) - { - return false; - } - - return strcmp(lhsText, rhsText) == 0; -} - -RED4EXT_INLINE bool RED4ext::CString::IsInline() const noexcept -{ - return length < 0x40000000; -} - -RED4EXT_INLINE const char* RED4ext::CString::c_str() const noexcept -{ - if (IsInline()) - { - return text.inline_str; - } - - return text.str.ptr; -} - -RED4EXT_INLINE uint32_t RED4ext::CString::Length() const noexcept -{ - return length & 0x3FFFFFFF; -} diff --git a/include/RED4ext/CString.hpp b/include/RED4ext/CString.hpp index 03ca07d99..5339e7522 100644 --- a/include/RED4ext/CString.hpp +++ b/include/RED4ext/CString.hpp @@ -1,106 +1,10 @@ #pragma once -#include -#include -#include -#include -#include +#include namespace RED4ext { -namespace Memory -{ -struct IAllocator; -} - -struct CString -{ - CString(Memory::IAllocator* aAllocator = nullptr); - CString(const char* aText, Memory::IAllocator* aAllocator = nullptr); - CString(const char* aText, uint32_t aLength, Memory::IAllocator* aAllocator = nullptr); - CString(const std::string& aText, Memory::IAllocator* aAllocator = nullptr); - CString(const std::string_view& aText, Memory::IAllocator* aAllocator = nullptr); - - CString(const CString& aOther); - CString(CString&& aOther) noexcept; - - ~CString(); - - CString& operator=(const CString& aRhs); - CString& operator=(CString&& aRhs) noexcept; - - bool operator==(const char* aRhs) const noexcept; - bool operator==(const CString& aRhs) const noexcept; - - inline bool operator!=(const char* aRhs) const noexcept - { - return !(*this == aRhs); - } - - inline bool operator!=(const CString& aRhs) const noexcept - { - return !(*this == aRhs); - } - - inline const char& operator[](size_t aIndex) const - { - return c_str()[aIndex]; - } - - [[nodiscard]] bool IsInline() const noexcept; - - [[nodiscard]] const char* c_str() const noexcept; - [[nodiscard]] uint32_t Length() const noexcept; - - [[nodiscard]] const char* begin() const - { - return c_str(); - } - - [[nodiscard]] const char* end() const - { - return c_str() + Length(); - } - -#pragma pack(push, 4) - union - { - char inline_str[0x14]; - struct - { - char* ptr; - int8_t unk[8]; - int32_t capacity; - } str; - } text; // 00 -#pragma pack(pop) - - uint32_t length; // 14 - Memory::IAllocator* allocator; // 18 -}; -RED4EXT_ASSERT_SIZE(CString, 0x20); -RED4EXT_ASSERT_OFFSET(CString, text, 0x00); -RED4EXT_ASSERT_OFFSET(CString, length, 0x14); -RED4EXT_ASSERT_OFFSET(CString, allocator, 0x18); - -template -struct HashMapHash>> -{ - uint32_t operator()(const T& aKey) const noexcept - { - // I believe the game uses this implementation for StringView and String? - std::uint32_t hash{}; - - for (const auto i : aKey) - { - hash = static_cast(i) + 31u * hash; - } - return hash; - } -}; -} // namespace RED4ext +using CString [[deprecated("Use red::String")]] = red::String; -#ifdef RED4EXT_HEADER_ONLY -#include -#endif +} \ No newline at end of file diff --git a/include/RED4ext/Dump/Reflection.hpp b/include/RED4ext/Dump/Reflection.hpp index 8669132e4..f393d7b7c 100644 --- a/include/RED4ext/Dump/Reflection.hpp +++ b/include/RED4ext/Dump/Reflection.hpp @@ -7,11 +7,10 @@ #include #include +#include namespace RED4ext { -struct CClass; -struct CBaseRTTIType; struct CProperty; struct CEnum; struct CBitfield; @@ -21,10 +20,10 @@ namespace RED4ext::GameReflection { using GetPrefix = std::function; using NameSantizer = std::function; -using NameTransformer = std::function; -using DescriptorPath = std::function; -using NamespaceTransformer = std::function(const RED4ext::CBaseRTTIType*)>; -using TypeChecker = std::function; +using NameTransformer = std::function; +using DescriptorPath = std::function; +using NamespaceTransformer = std::function(const RED4ext::rtti::IType*)>; +using TypeChecker = std::function; using FixedTypeMapping = std::unordered_map; static constexpr const char* INVALID_CHARACTERS = R"(-|'|\(|\)|\]|\[|/|\.|\s|:)"; @@ -102,13 +101,13 @@ struct BitfieldFileDescriptor struct ClassDependencyBuilder { - const RED4ext::CClass* pType; - std::unordered_set mDirect; - std::unordered_set mIndirect; + const RED4ext::rtti::ClassType* pType; + std::unordered_set mDirect; + std::unordered_set mIndirect; std::map mPropertyMap; std::map mHolderPropertyMap; - void Accumulate(const RED4ext::CBaseRTTIType* type); + void Accumulate(const RED4ext::rtti::IType* type); void ToFileDescriptor(ClassFileDescriptor& aFd, NameTransformer aNameTransformer, NameTransformer aQualifiedTransformer, DescriptorPath aTypeToPath, @@ -116,7 +115,7 @@ struct ClassDependencyBuilder const FixedTypeMapping& aFixedMapping, bool aVerbose); }; -std::string TypeToString(const RED4ext::CBaseRTTIType* aType, NameTransformer aNameTransformer, bool aVerbose = false); +std::string TypeToString(const RED4ext::rtti::IType* aType, NameTransformer aNameTransformer, bool aVerbose = false); void EmitBulkGenerated(std::filesystem::path aOutPath, const std::set& aIncludes); diff --git a/include/RED4ext/DynArray.hpp b/include/RED4ext/DynArray.hpp index 40524c2dd..84511a353 100644 --- a/include/RED4ext/DynArray.hpp +++ b/include/RED4ext/DynArray.hpp @@ -18,6 +18,9 @@ namespace Memory struct IAllocator; } +namespace red +{ + template struct DynArray { @@ -351,7 +354,14 @@ struct DynArray } } }; + RED4EXT_ASSERT_SIZE(DynArray, 0x10); RED4EXT_ASSERT_OFFSET(DynArray, capacity, 0x8); RED4EXT_ASSERT_OFFSET(DynArray, size, 0xC); + +} // namespace red + +template +using DynArray [[deprecated("Use red::DynArray")]] = red::DynArray; + } // namespace RED4ext diff --git a/include/RED4ext/ERTTIType.hpp b/include/RED4ext/ERTTIType.hpp new file mode 100644 index 000000000..39ded19d5 --- /dev/null +++ b/include/RED4ext/ERTTIType.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace RED4ext { + +enum class ERTTIType : uint8_t +{ + Name = 0, + Fundamental = 1, + Class = 2, + Array = 3, + Simple = 4, + Enum = 5, + StaticArray = 6, + NativeArray = 7, + Pointer = 8, + Handle = 9, + WeakHandle = 10, + ResourceReference = 11, + ResourceAsyncReference = 12, + BitField = 13, + LegacySingleChannelCurve = 14, + ScriptReference = 15, + FixedArray = 16 +}; + +} \ No newline at end of file diff --git a/include/RED4ext/GameEngine.hpp b/include/RED4ext/GameEngine.hpp index eeb32e54f..f90528c65 100644 --- a/include/RED4ext/GameEngine.hpp +++ b/include/RED4ext/GameEngine.hpp @@ -9,10 +9,10 @@ #include #include #include +#include namespace RED4ext { -struct CBaseRTTIType; struct IScriptable; struct CGameOptions; @@ -32,7 +32,7 @@ enum class EEngineState : int32_t struct GameInstance { virtual ~GameInstance() = 0; // 00 - virtual IScriptable* GetSystem(const CBaseRTTIType* aType) = 0; // 08 + virtual IScriptable* GetSystem(const rtti::IType* aType) = 0; // 08 virtual void Unk_10() = 0; // 10 virtual void Unk_18() = 0; // 18 virtual void Unk_20() = 0; // 20 @@ -46,9 +46,9 @@ struct GameInstance virtual void Unk_60() = 0; // 60 virtual void Unk_68() = 0; // 68 - HashMap> systemMap; // 08 - Maps implementation type to instance + HashMap> systemMap; // 08 - Maps implementation type to instance DynArray> systemInstances; // 38 - HashMap systemImplementations; // 48 - Maps interface type to implementation type + HashMap systemImplementations; // 48 - Maps interface type to implementation type uintptr_t unk78[(0x138 - 0x78) >> 3]; // 78 }; RED4EXT_ASSERT_SIZE(GameInstance, 0x138); @@ -91,8 +91,8 @@ struct CBaseEngine }; RED4EXT_ASSERT_SIZE(Unk110, 0x10); - virtual CBaseRTTIType* GetNativeType() = 0; // 00 - virtual CBaseRTTIType* GetParentType() = 0; // 08 + virtual rtti::IType* GetNativeType() = 0; // 00 + virtual rtti::IType* GetParentType() = 0; // 08 virtual Memory::IAllocator* GetAllocator() = 0; // 10 virtual ~CBaseEngine() = 0; // 18 virtual void sub_18() = 0; // 20 diff --git a/include/RED4ext/GpuApi/CommandListContext.hpp b/include/RED4ext/GpuApi/CommandListContext.hpp index 018622041..4ac70b494 100644 --- a/include/RED4ext/GpuApi/CommandListContext.hpp +++ b/include/RED4ext/GpuApi/CommandListContext.hpp @@ -33,7 +33,7 @@ struct CommandListContext void Close(); void FlushPendingBarriers(); - CString debugName; // 000 + red::String debugName; // 000 uint64_t hash; // 020 Microsoft::WRL::ComPtr commandAllocator; // 028 Microsoft::WRL::ComPtr commandList; // 030 diff --git a/include/RED4ext/ISerializable.hpp b/include/RED4ext/ISerializable.hpp index 8f1a1bf65..c14b791f6 100644 --- a/include/RED4ext/ISerializable.hpp +++ b/include/RED4ext/ISerializable.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace RED4ext { @@ -12,9 +13,11 @@ namespace Memory struct IAllocator; } -struct CClass; struct BaseStream; -struct CString; +namespace red +{ +struct String; +} struct PostLoadParams { @@ -27,8 +30,8 @@ struct ISerializable { ISerializable(); - virtual CClass* GetNativeType() = 0; // 00 - virtual CClass* GetType(); // 08 + virtual rtti::ClassType* GetNativeType() = 0; // 00 + virtual rtti::ClassType* GetType(); // 08 virtual Memory::IAllocator* GetAllocator(); // 10 virtual ~ISerializable() = default; // 18 virtual void sub_20(); // 20 @@ -48,9 +51,9 @@ struct ISerializable virtual bool sub_90(); // 90 virtual bool sub_98(); // 98 virtual void* sub_A0(); // A0 - virtual CClass* sub_A8(); // A8 + virtual rtti::ClassType* sub_A8(); // A8 virtual void sub_B0(void* a1); // B0 - virtual CString sub_B8(); // B8 + virtual red::String sub_B8(); // B8 virtual void* sub_C0(void* a1); // C0 virtual void* sub_C8(void* a1); // C8 virtual bool CanBeDestructed(); // D0 @@ -72,7 +75,7 @@ RED4EXT_ASSERT_SIZE(ISerializable, 0x30); */ #ifndef RED4EXT_IMPL_NATIVE_TYPE #define RED4EXT_IMPL_NATIVE_TYPE() \ - CClass* GetNativeType() override \ + rtti::ClassType* GetNativeType() override \ { \ return CRTTISystem::Get()->GetClass(NAME); \ } diff --git a/include/RED4ext/InstanceType.hpp b/include/RED4ext/InstanceType.hpp index 1b8ddf86c..ab73e726c 100644 --- a/include/RED4ext/InstanceType.hpp +++ b/include/RED4ext/InstanceType.hpp @@ -8,7 +8,10 @@ namespace RED4ext { -struct CString; +namespace red +{ +struct String; +} struct ISerializable; struct IScriptable; struct TweakDBID; @@ -25,7 +28,7 @@ union ScriptInstanceUnion RED4EXT_DECLARE_TYPE(int32_t, i32); RED4EXT_DECLARE_TYPE(uint64_t, u64); RED4EXT_DECLARE_TYPE(int64_t, i64); - RED4EXT_DECLARE_TYPE(CString, str); + RED4EXT_DECLARE_TYPE(red::String, str); RED4EXT_DECLARE_TYPE(TweakDBID, tdbid); RED4EXT_DECLARE_TYPE(ItemID, itemid); RED4EXT_DECLARE_TYPE(ISerializable, serializable); diff --git a/include/RED4ext/NativeTypes.hpp b/include/RED4ext/NativeTypes.hpp index e7461cdd4..526efdcca 100644 --- a/include/RED4ext/NativeTypes.hpp +++ b/include/RED4ext/NativeTypes.hpp @@ -16,10 +16,10 @@ #include #include #include +#include namespace RED4ext { -struct CBaseRTTIType; struct CDateTime { @@ -147,8 +147,8 @@ struct Variant static constexpr uintptr_t TypeMask = ~InlineFlag; Variant() noexcept = default; - Variant(const CBaseRTTIType* aType); - Variant(const CBaseRTTIType* aType, const ScriptInstance aData); + Variant(const rtti::IType* aType); + Variant(const rtti::IType* aType, const ScriptInstance aData); Variant(CName aTypeName); Variant(CName aTypeName, const ScriptInstance aData); Variant(const Variant& aOther); @@ -161,17 +161,17 @@ struct Variant bool IsEmpty() const noexcept; bool IsInlined() const noexcept; - CBaseRTTIType* GetType() const noexcept; + rtti::IType* GetType() const noexcept; ScriptInstance GetDataPtr() const noexcept; - bool Init(const CBaseRTTIType* aType); - bool Fill(const CBaseRTTIType* aType, const ScriptInstance aData); + bool Init(const rtti::IType* aType); + bool Fill(const rtti::IType* aType, const ScriptInstance aData); bool Extract(ScriptInstance aBuffer); void Free(); - static bool CanBeInlined(const CBaseRTTIType* aType) noexcept; + static bool CanBeInlined(const rtti::IType* aType) noexcept; - const CBaseRTTIType* type{nullptr}; + const rtti::IType* type{nullptr}; union { uint8_t inlined[InlineSize]{0}; @@ -262,7 +262,7 @@ struct CurveData CName name; // 00 RawBuffer buffer; // 08 - CBaseRTTIType* valueType; // 40 + rtti::IType* valueType; // 40 curve::EInterpolationType interpolationType; // 48 curve::ESegmentsLinkType linkType; // 49 }; @@ -277,7 +277,7 @@ template struct ScriptRef { uint8_t unk00[0x10]; // 00 - CBaseRTTIType* innerType; // 10 + rtti::IType* innerType; // 10 T* ref; // 18 CName hash; // 20 }; diff --git a/include/RED4ext/RTTITypes-inl.hpp b/include/RED4ext/RTTITypes-inl.hpp index c10cee838..968366a27 100644 --- a/include/RED4ext/RTTITypes-inl.hpp +++ b/include/RED4ext/RTTITypes-inl.hpp @@ -9,417 +9,7 @@ #include #include #include - -RED4EXT_INLINE RED4ext::CBaseRTTIType::CBaseRTTIType() - : unk8(0) -{ -} - -RED4EXT_INLINE RED4ext::CString RED4ext::CBaseRTTIType::GetTypeName() const -{ - switch (GetType()) - { - case ERTTIType::Name: - { - return "RT_Name"; - } - case ERTTIType::Fundamental: - { - return "RT_Fundamental"; - } - case ERTTIType::Class: - { - return "RT_Class"; - } - case ERTTIType::Array: - { - return "RT_Array"; - } - case ERTTIType::Simple: - { - return "RT_Simple"; - } - case ERTTIType::Enum: - { - return "RT_Enum"; - } - case ERTTIType::StaticArray: - { - return "RT_StaticArray"; - } - case ERTTIType::NativeArray: - { - return "RT_NativeArray"; - } - case ERTTIType::Pointer: - { - return "RT_Pointer"; - } - case ERTTIType::Handle: - { - return "RT_Handle"; - } - case ERTTIType::WeakHandle: - { - return "RT_WeakHandle"; - } - case ERTTIType::ResourceReference: - { - return "RT_ResourceReference"; - } - case ERTTIType::ResourceAsyncReference: - { - return "RT_ResourceAsyncReference"; - } - case ERTTIType::BitField: - { - return "RT_BitField"; - } - case ERTTIType::LegacySingleChannelCurve: - { - return "RT_LegacySingleChannelCurve"; - } - case ERTTIType::ScriptReference: - { - return "RT_ScriptReference"; - } - default: - { - return "Unhandled ERTTITypeType"; - } - } -} - -RED4EXT_INLINE RED4ext::CName RED4ext::CBaseRTTIType::GetComputedName() const -{ - std::string name = "script_ref:"; - auto hash = GetName(); - if (!hash.IsNone()) - { - name += hash.ToString(); - return CNamePool::Add(name.c_str()); - } - - return 0ull; -} - -RED4EXT_INLINE void RED4ext::CBaseRTTIType::Move(ScriptInstance aLhs, ScriptInstance aRhs) const -{ - Assign(aLhs, aRhs); -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::ToString(const ScriptInstance aInstance, CString& aOut) const -{ - RED4EXT_UNUSED_PARAMETER(aInstance); - RED4EXT_UNUSED_PARAMETER(aOut); - - return false; -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::FromString(ScriptInstance aInstance, const CString& aString) const -{ - RED4EXT_UNUSED_PARAMETER(aInstance); - RED4EXT_UNUSED_PARAMETER(aString); - - return false; -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::sub_78() -{ - return true; -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::sub_80(int64_t a1, ScriptInstance aInstance) -{ - using func_t = bool (*)(CBaseRTTIType*, int64_t, ScriptInstance); - static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_80); - return func(this, a1, aInstance); -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::sub_88(int64_t a1, ScriptInstance aInstance) -{ - using func_t = bool (*)(CBaseRTTIType*, int64_t, ScriptInstance); - static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_88); - return func(this, a1, aInstance); -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::sub_90(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4) -{ - using func_t = bool (*)(CBaseRTTIType*, int64_t, ScriptInstance, CString&, int64_t); - static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_90); - return func(this, a1, aInstance, a3, a4); -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::sub_98(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4, - bool a5) -{ - using func_t = bool (*)(CBaseRTTIType*, int64_t, ScriptInstance, CString&, int64_t, bool); - static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_98); - return func(this, a1, aInstance, a3, a4, a5); -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::sub_A0(int64_t a1, CString& a2, bool a3) -{ - using func_t = bool (*)(CBaseRTTIType*, int64_t, CString&, bool); - static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_A0); - return func(this, a1, a2, a3); -} - -RED4EXT_INLINE bool RED4ext::CBaseRTTIType::sub_A8() -{ - return false; -} - -RED4EXT_INLINE void RED4ext::CBaseRTTIType::sub_B0(int64_t a1, int64_t a2) -{ - RED4EXT_UNUSED_PARAMETER(a1); - RED4EXT_UNUSED_PARAMETER(a2); -} - -RED4EXT_INLINE RED4ext::Memory::IAllocator* RED4ext::CBaseRTTIType::GetAllocator() const -{ - return Memory::RTTIAllocator::Get(); -} - -RED4EXT_INLINE RED4ext::CClass::CClass(CName aName, uint32_t aSize, Flags aFlags) - : parent(nullptr) - , name(aName) - , computedName(CBaseRTTIType::GetComputedName()) - , size(aSize) - , flags(aFlags) - , holderSize(0) - , alignment(4) - , props(Memory::RTTIAllocator::Get()) - , overriddenProps(Memory::RTTIAllocator::Get()) - , funcs(Memory::RTTIAllocator::Get()) - , staticFuncs(Memory::RTTIAllocator::Get()) - , funcsByName(Memory::RTTIAllocator::Get()) - , unkA8(Memory::RTTIAllocator::Get()) - , unkD8(0) - , unkE0(0) - , propsByName(Memory::RTTIAllocator::Get()) - , unk118(Memory::RTTIAllocator::Get()) - , unk128(Memory::RTTIAllocator::Get()) - , unk138(Memory::RTTIAllocator::Get()) - , unk148(Memory::RTTIAllocator::Get()) - , defaults(Memory::ScriptAllocator::Get()) - , unk180(Memory::RTTIAllocator::Get()) - , listeners(Memory::RTTIAllocator::Get()) - , eventTypeId(-1) - , unk2C4(-1) - , unk2C9(0xE6) -{ - std::memset(listening, 0, sizeof(listening)); -} - -RED4EXT_INLINE RED4ext::CName RED4ext::CClass::GetName() const -{ - return name; -} - -RED4EXT_INLINE uint32_t RED4ext::CClass::GetSize() const -{ - return size; -} - -RED4EXT_INLINE uint32_t RED4ext::CClass::GetAlignment() const -{ - return alignment; -} - -RED4EXT_INLINE RED4ext::ERTTIType RED4ext::CClass::GetType() const -{ - return ERTTIType::Class; -} - -RED4EXT_INLINE RED4ext::CName RED4ext::CClass::GetComputedName() const -{ - return computedName; -} - -RED4EXT_INLINE void RED4ext::CClass::Construct(ScriptInstance aMemory) const -{ - ConstructCls(aMemory); -} - -RED4EXT_INLINE void RED4ext::CClass::Destruct(ScriptInstance aMemory) const -{ - DestructCls(aMemory); -} - -RED4EXT_INLINE bool RED4ext::CClass::Unserialize(BaseStream* aStream, ScriptInstance aInstance, int64_t a3) const -{ - using func_t = bool (*)(const CClass*, BaseStream*, ScriptInstance, int64_t); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_Unserialize); - return func(this, aStream, aInstance, a3); -} - -RED4EXT_INLINE bool RED4ext::CClass::ToString(const ScriptInstance aInstance, CString& aOut) const -{ - using func_t = bool (*)(const CClass*, ScriptInstance, CString&); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_ToString); - return func(this, aInstance, aOut); -} - -RED4EXT_INLINE bool RED4ext::CClass::sub_80(int64_t a1, ScriptInstance aInstance) -{ - using func_t = bool (*)(const CClass*, int64_t, ScriptInstance); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_sub_80); - return func(this, a1, aInstance); -} - -RED4EXT_INLINE bool RED4ext::CClass::sub_88(int64_t a1, ScriptInstance aInstance) -{ - using func_t = bool (*)(const CClass*, int64_t, ScriptInstance); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_sub_88); - return func(this, a1, aInstance); -} - -RED4EXT_INLINE bool RED4ext::CClass::sub_90(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4) -{ - using func_t = bool (*)(const CClass*, int64_t, ScriptInstance, CString&, int64_t); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_sub_90); - return func(this, a1, aInstance, a3, a4); -} - -RED4EXT_INLINE bool RED4ext::CClass::sub_98(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4, bool a5) -{ - RED4EXT_UNUSED_PARAMETER(a5); - - using func_t = bool (*)(const CClass*, int64_t, ScriptInstance, CString&, int64_t); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_sub_90); - return func(this, a1, aInstance, a3, a4); -} - -RED4EXT_INLINE bool RED4ext::CClass::sub_A0(int64_t a1, CString& a2, bool a3) -{ - using func_t = bool (*)(const CClass*, int64_t, CString&, bool); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_sub_A0); - return func(this, a1, a2, a3); -} - -RED4EXT_INLINE void RED4ext::CClass::sub_B0(int64_t a1, int64_t a2) -{ - using func_t = bool (*)(const CClass*, int64_t, int64_t); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_sub_B0); - func(this, a1, a2); -} - -RED4EXT_INLINE void RED4ext::CClass::sub_C0() -{ - using func_t = void (*)(CClass*); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_sub_C0); - func(this); -} - -RED4EXT_INLINE uint32_t RED4ext::CClass::GetMaxAlignment() const -{ - using func_t = uint32_t (*)(const CClass*); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_GetMaxAlignment); - return func(this); -} - -RED4EXT_INLINE bool RED4ext::CClass::sub_D0() const -{ - using func_t = bool (*)(const CClass*); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_sub_D0); - return func(this); -} - -RED4EXT_INLINE RED4ext::ScriptInstance RED4ext::CClass::CreateInstance(bool aZeroMemory) const -{ - using func_t = ScriptInstance (*)(const CClass*, uint32_t, bool); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_CreateInstance); - return func(this, GetSize(), aZeroMemory); -} - -RED4EXT_INLINE bool RED4ext::CClass::IsA(const CBaseRTTIType* aType) const -{ - if (this == aType) - { - return true; - } - - if (parent) - { - return parent->IsA(aType); - } - - return false; -} - -RED4EXT_INLINE RED4ext::CProperty* RED4ext::CClass::GetProperty(CName aName) -{ - // Not recreating this because they do something strage with overriden properties and I am not sure what exactly - // they do. - - using func_t = CProperty* (*)(CClass*, CName); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_GetProperty); - return func(this, aName); -} - -RED4EXT_INLINE void RED4ext::CClass::InitializeProperties(ScriptInstance aInstance) -{ - static UniversalRelocFunc initializeProperties( - Detail::AddressHashes::CClass_InitializeProperties); - initializeProperties(this, aInstance); - - static UniversalRelocFunc assignDefaultValuesToProperties( - Detail::AddressHashes::CClass_AssignDefaultValuesToProperties); - assignDefaultValuesToProperties(this, aInstance); -} - -RED4EXT_INLINE void RED4ext::CClass::GetProperties(DynArray& aProps) -{ - using func_t = CProperty* (*)(CClass*, DynArray&); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_GetProperties); - func(this, aProps); -} - -RED4EXT_INLINE RED4ext::CClassFunction* RED4ext::CClass::GetFunction(CName aShortName) const -{ - for (auto func : staticFuncs) - { - if (func->shortName == aShortName) - { - return func; - } - } - - for (auto func : funcs) - { - if (func->shortName == aShortName) - { - return func; - } - } - - if (parent) - { - return parent->GetFunction(aShortName); - } - - return nullptr; -} - -RED4EXT_INLINE void RED4ext::CClass::RegisterFunction(CClassFunction* aFunc) -{ - if (aFunc->flags.isStatic) - { - staticFuncs.PushBack(static_cast(aFunc)); - } - else - { - funcs.PushBack(aFunc); - } -} - -RED4EXT_INLINE void RED4ext::CClass::ClearScriptedData() -{ - using func_t = void (*)(CClass*); - static UniversalRelocFunc func(Detail::AddressHashes::CClass_ClearScriptedData); - func(this); -} +#include RED4EXT_INLINE RED4ext::CEnum::CEnum(CName aName, int8_t aActualSize, Flags aFlags) : name(aName) diff --git a/include/RED4ext/RTTITypes.hpp b/include/RED4ext/RTTITypes.hpp index cb1de9218..be60ba2af 100644 --- a/include/RED4ext/RTTITypes.hpp +++ b/include/RED4ext/RTTITypes.hpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace RED4ext { @@ -19,224 +21,8 @@ struct CClassFunction; struct CClassStaticFunction; struct Variant; -enum class ERTTIType : uint8_t -{ - Name = 0, - Fundamental = 1, - Class = 2, - Array = 3, - Simple = 4, - Enum = 5, - StaticArray = 6, - NativeArray = 7, - Pointer = 8, - Handle = 9, - WeakHandle = 10, - ResourceReference = 11, - ResourceAsyncReference = 12, - BitField = 13, - LegacySingleChannelCurve = 14, - ScriptReference = 15, - FixedArray = 16 -}; - -struct CBaseRTTIType -{ - CBaseRTTIType(); - virtual ~CBaseRTTIType() = default; // 00 - - virtual CName GetName() const = 0; // 08 - virtual uint32_t GetSize() const = 0; // 10 - virtual uint32_t GetAlignment() const = 0; // 18 - virtual ERTTIType GetType() const = 0; // 20 - virtual CString GetTypeName() const; // 28 - virtual CName GetComputedName() const; // 30 - virtual void Construct(ScriptInstance aMemory) const = 0; // 38 - virtual void Destruct(ScriptInstance aMemory) const = 0; // 40 - virtual const bool IsEqual(const ScriptInstance aLhs, const ScriptInstance aRhs, - uint32_t a3 = 0) = 0; // 48 - Not const because CClass aquire some mutex when this is - // called and a flag is modified. - virtual void Assign(ScriptInstance aLhs, const ScriptInstance aRhs) const = 0; // 50 - virtual void Move(ScriptInstance aLhs, ScriptInstance aRhs) const; // 58 - virtual bool Unserialize(BaseStream* aStream, ScriptInstance aInstance, int64_t a3) const = 0; // 60 - virtual bool ToString(const ScriptInstance aInstance, CString& aOut) const; // 68 - virtual bool FromString(ScriptInstance aInstance, const CString& aString) const; // 70 - virtual bool sub_78(); // 78 - virtual bool sub_80(int64_t a1, ScriptInstance aInstance); // 80 - virtual bool sub_88(int64_t a1, ScriptInstance aInstance); // 88 - virtual bool sub_90(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4); // 90 - virtual bool sub_98(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4, bool a5); // 98 - virtual bool sub_A0(int64_t a1, CString& a2, bool a3); // A0 - virtual bool sub_A8(); // A8 - virtual void sub_B0(int64_t a1, int64_t a2); // B0 - virtual Memory::IAllocator* GetAllocator() const; // B8 - - [[deprecated("Use 'GetName()' instead.")]] - inline void GetName(CName& aOut) const - { - aOut = GetName(); - } - - [[deprecated("Use 'GetComputedName()' instead.")]] - inline CName GetName2() const - { - return GetComputedName(); - } - - [[deprecated("Use 'GetComputedName()' instead.")]] - inline void GetName2(CName& aOut) const - { - aOut = GetComputedName(); - } - - [[deprecated("Use 'GetTypeName()' instead.")]] - inline void GetTypeName(CString& aOut) const - { - auto name = GetTypeName(); - aOut = name; - } - - [[deprecated("Use 'Construct()' instead.")]] - inline void Init(ScriptInstance aMemory) const - { - Construct(aMemory); - } - - [[deprecated("Use 'Destruct()' instead.")]] - inline void Destroy(ScriptInstance aMemory) const - { - Destruct(aMemory); - } - - int64_t unk8; -}; -RED4EXT_ASSERT_SIZE(CBaseRTTIType, 0x10); - -struct CClass : CBaseRTTIType -{ - struct Flags - { - uint32_t isAbstract : 1; // 00 - uint32_t isNative : 1; // 01 - uint32_t isScriptedClass : 1; // 02 - uint32_t isScriptedStruct : 1; // 03 - uint32_t hasNoDefaultObjectSerialization : 1; // 04 - uint32_t isAlwaysTransient : 1; // 05 - uint32_t isImportOnly : 1; // 06 - uint32_t isPrivate : 1; // 07 - uint32_t isProtected : 1; // 08 - uint32_t isTestOnly : 1; // 09 - uint32_t isSavable : 1; // 0A - uint32_t b10 : 21; // 0B - }; - RED4EXT_ASSERT_SIZE(CClass::Flags, 0x4); - - struct Listener - { - Callback&), 16> callback; // 00 - CName callbackName; // 18 - int16_t eventTypeId; // 20 - bool isScripted; // 22 - }; - RED4EXT_ASSERT_SIZE(CClass::Listener, 0x28); - RED4EXT_ASSERT_OFFSET(CClass::Listener, callbackName, 0x18); - RED4EXT_ASSERT_OFFSET(CClass::Listener, isScripted, 0x22); - - CClass(CName aName, uint32_t aSize, Flags aFlags); - - CName GetName() const final; // 08 - uint32_t GetSize() const final; // 10 - uint32_t GetAlignment() const final; // 18 - ERTTIType GetType() const final; // 20 - CName GetComputedName() const final; // 30 - void Construct(ScriptInstance aMemory) const final; // 38 - void Destruct(ScriptInstance aMemory) const final; // 40 - bool Unserialize(BaseStream* aStream, ScriptInstance aInstance, int64_t a3) const final; // 60 - bool ToString(const ScriptInstance aInstance, CString& aOut) const final; // 68 - bool sub_80(int64_t a1, ScriptInstance aInstance) final; // 80 - bool sub_88(int64_t a1, ScriptInstance aInstance) final; // 88 - bool sub_90(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4) final; // 90 - bool sub_98(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4, bool a5) final; // 98 - bool sub_A0(int64_t a1, CString& a2, bool a3) final; // A0 - void sub_B0(int64_t a1, int64_t a2) final; // B0 - - virtual void sub_C0(); // C0 - virtual uint32_t GetMaxAlignment() const; // C8 - virtual bool sub_D0() const; // D0 - virtual void ConstructCls(ScriptInstance aMemory) const = 0; // D8 - virtual void DestructCls(ScriptInstance aMemory) const = 0; // E0 - virtual void* AllocMemory() const = 0; // E8 - - ScriptInstance CreateInstance(bool aZeroMemory = false) const; - - bool IsA(const CBaseRTTIType* aType) const; - - CProperty* GetProperty(CName aName); - CClassFunction* GetFunction(CName aShortName) const; - - void InitializeProperties(ScriptInstance aInstance); - void GetProperties(DynArray& aProps); - - void RegisterFunction(CClassFunction* aFunc); - - void ClearScriptedData(); - - [[deprecated("Use 'ConstructCls()' instead.")]] - inline void InitCls(ScriptInstance aMemory) const - { - ConstructCls(aMemory); - } - - [[deprecated("Use 'DestructCls()' instead.")]] - inline void DestroyCls(ScriptInstance aMemory) const - { - DestructCls(aMemory); - } - - [[deprecated("Use 'CreateInstance()' instead.")]] - inline ScriptInstance AllocInstance(bool aZeroMemory = false) const - { - return CreateInstance(aZeroMemory); - } - - CClass* parent; // 10 - CName name; // 18 - CName computedName; // 20 - DynArray props; // 28 - DynArray overriddenProps; // 38 - DynArray funcs; // 48 - DynArray staticFuncs; // 58 - uint32_t size; // 68 - uint32_t holderSize; // 6C - Flags flags; // 70 - uint32_t alignment; // 74 - HashMap funcsByName; // 78 - HashMap unkA8; // A8 - int64_t unkD8; // D8 - int64_t unkE0; // E0 - HashMap propsByName; // E8 - DynArray unk118; // 118 - More entries than 0x28, will contain native props - DynArray unk128; // 128 - DynArray unk138; // 138 - Only RT_Class types? - DynArray unk148; // 148 - Map defaults; // 158 - HashMap unk180; // 180 - DynArray listeners; // 1B0 - Event listeners - int8_t listening[256]; // 1C0 - Bitmask of event types that this class listens to - int16_t eventTypeId; // 2C0 - Assigned to event classes only - int32_t unk2C4; // 2C4 - SharedSpinLock unk2C8; // 2C8 - uint8_t unk2C9; // 2C9 -}; -RED4EXT_ASSERT_SIZE(CClass, 0x2D0); -RED4EXT_ASSERT_OFFSET(CClass, parent, 0x10); -RED4EXT_ASSERT_OFFSET(CClass, name, 0x18); -RED4EXT_ASSERT_OFFSET(CClass, props, 0x28); -RED4EXT_ASSERT_OFFSET(CClass, overriddenProps, 0x38); -RED4EXT_ASSERT_OFFSET(CClass, funcs, 0x48); -RED4EXT_ASSERT_OFFSET(CClass, size, 0x68); -RED4EXT_ASSERT_OFFSET(CClass, flags, 0x70); -RED4EXT_ASSERT_OFFSET(CClass, alignment, 0x74); +using CBaseRTTIType [[deprecated("Use rtti::IType")]] = rtti::IType; +using CClass [[deprecated("Use rtti::ClassType")]] = rtti::ClassType; template struct TTypedClass : CClass @@ -245,7 +31,7 @@ struct TTypedClass : CClass static_assert(std::is_default_constructible_v, "T must be default-constructible"); static_assert(std::is_destructible_v, "T must be destructible"); - TTypedClass(CName aName, CClass::Flags aFlags = {.isNative = true}) + TTypedClass(CName aName, rtti::ClassType::Flags aFlags = {.isNative = true}) : CClass(aName, sizeof(T), aFlags) { } diff --git a/include/RED4ext/Scripting/Functions.hpp b/include/RED4ext/Scripting/Functions.hpp index 2408f83e5..58fbfff94 100644 --- a/include/RED4ext/Scripting/Functions.hpp +++ b/include/RED4ext/Scripting/Functions.hpp @@ -7,16 +7,15 @@ #include #include #include +#include namespace RED4ext { -struct CClass; struct CStack; struct CStackFrame; struct CProperty; struct PoolRTTIFunctionAllocator; struct IScriptable; -struct CBaseRTTIType; struct IFunction { @@ -25,12 +24,12 @@ struct IFunction virtual void sub_0() = 0; virtual void sub_8() = 0; virtual void Execute(ScriptInstance aInstance, CStackFrame& aFrame, void* aResult, - const CBaseRTTIType* aResultType) = 0; + const rtti::IType* aResultType) = 0; }; virtual Memory::IAllocator* GetAllocator() = 0; // 00 virtual ~IFunction() = 0; // 08 - virtual CClass* GetParent() = 0; // 10 + virtual rtti::ClassType* GetParent() = 0; // 10 virtual uint32_t GetRegIndex() = 0; // 18 virtual Invokable* GetInvokable() = 0; // 20 - Returns an object, vf obj+0x20 is the function to invoke only used // if static func @@ -88,7 +87,7 @@ struct CBaseFunction : IFunction int32_t unkAC; // AC private: - using Handler_t = void (*)(ScriptInstance, RED4ext::CStackFrame&, void*, CBaseRTTIType*); + using Handler_t = void (*)(ScriptInstance, RED4ext::CStackFrame&, void*, rtti::IType*); bool Execute_(CStack* aStack); static Handler_t GetHandler(uint32_t aIndex); @@ -127,7 +126,7 @@ RED4EXT_ASSERT_OFFSET(CGlobalFunction, regIndex, 0xB0); struct CClassFunction : CBaseFunction { template - static CClassFunction* Create(CClass* aParent, const char* aFullName, const char* aShortName, + static CClassFunction* Create(rtti::ClassType* aParent, const char* aFullName, const char* aShortName, ScriptingFunction_t aFunc, Flags aFlags = {}) { Memory::RTTIFunctionAllocator allocator; @@ -137,7 +136,7 @@ struct CClassFunction : CBaseFunction auto fullName = CNamePool::Add(aFullName); auto shortName = CNamePool::Add(aShortName); - using func_t = CClassFunction* (*)(CClassFunction*, CClass*, CName, CName, ScriptingFunction_t, Flags); + using func_t = CClassFunction* (*)(CClassFunction*, rtti::ClassType*, CName, CName, ScriptingFunction_t, Flags); static UniversalRelocFunc func(Detail::AddressHashes::CClassFunction_ctor); func(memory, aParent, fullName, shortName, aFunc, aFlags); } @@ -145,7 +144,7 @@ struct CClassFunction : CBaseFunction return memory; } - CClass* parent; // B0 + rtti::ClassType* parent; // B0 uint32_t regIndex; // B8 }; RED4EXT_ASSERT_SIZE(CClassFunction, 0xC0); @@ -155,7 +154,7 @@ RED4EXT_ASSERT_OFFSET(CClassFunction, regIndex, 0xB8); struct CClassStaticFunction : CClassFunction { template - static CClassStaticFunction* Create(CClass* aParent, const char* aFullName, const char* aShortName, + static CClassStaticFunction* Create(rtti::ClassType* aParent, const char* aFullName, const char* aShortName, ScriptingFunction_t aFunc, Flags aFlags = {}) { Memory::RTTIFunctionAllocator allocator; @@ -166,7 +165,7 @@ struct CClassStaticFunction : CClassFunction auto shortName = CNamePool::Add(aShortName); using func_t = - CClassStaticFunction* (*)(CClassStaticFunction*, CClass*, CName, CName, ScriptingFunction_t, Flags); + CClassStaticFunction* (*)(CClassStaticFunction*, rtti::ClassType*, CName, CName, ScriptingFunction_t, Flags); static UniversalRelocFunc func(Detail::AddressHashes::CClassStaticFunction_ctor); func(memory, aParent, fullName, shortName, aFunc, aFlags); } @@ -178,7 +177,7 @@ RED4EXT_ASSERT_SIZE(CClassStaticFunction, 0xC0); struct CScriptedFunction : CBaseFunction { - CClass* parent; // B0 + rtti::ClassType* parent; // B0 }; RED4EXT_ASSERT_SIZE(CScriptedFunction, 0xB8); RED4EXT_ASSERT_OFFSET(CScriptedFunction, parent, 0xB0); diff --git a/include/RED4ext/Scripting/IScriptable.hpp b/include/RED4ext/Scripting/IScriptable.hpp index e5e2859b2..80bf2a78e 100644 --- a/include/RED4ext/Scripting/IScriptable.hpp +++ b/include/RED4ext/Scripting/IScriptable.hpp @@ -4,18 +4,18 @@ #include #include +#include namespace RED4ext { struct CBaseFunction; -struct CClass; struct IScriptable : ISerializable { IScriptable(); ~IScriptable() override; - CClass* GetType() override; + rtti::ClassType* GetType() override; virtual void sub_D8(int64_t a1, int64_t a2); // D8 virtual void sub_E0(); // E0 @@ -30,7 +30,7 @@ struct IScriptable : ISerializable void* GetValueHolder(); void DestructValueHolder(); - CClass* nativeType; // 30 + rtti::ClassType* nativeType; // 30 void* valueHolder; // 38 }; RED4EXT_ASSERT_SIZE(IScriptable, 0x40); diff --git a/include/RED4ext/Scripting/Natives/gameIPersistencySystem.hpp b/include/RED4ext/Scripting/Natives/gameIPersistencySystem.hpp index f9bd2e540..4212bc28d 100644 --- a/include/RED4ext/Scripting/Natives/gameIPersistencySystem.hpp +++ b/include/RED4ext/Scripting/Natives/gameIPersistencySystem.hpp @@ -22,7 +22,7 @@ struct IPersistencySystem : IGameSystem static constexpr const char* ALIAS = "IGamePersistencySystem"; virtual void* GetPersistentState(Handle& aState, const PersistentID& aPersistentID, - CClass* aPersistentStateType, bool aCreateState) = 0; // 1A8 + rtti::ClassType* aPersistentStateType, bool aCreateState) = 0; // 1A8 virtual void sub_1B0() = 0; // 1B0 virtual void sub_1B8() = 0; // 1B8 virtual void sub_1C0() = 0; // 1C0 diff --git a/include/RED4ext/Scripting/Natives/inkWidgetReference.hpp b/include/RED4ext/Scripting/Natives/inkWidgetReference.hpp index daae5a744..74f29d56d 100644 --- a/include/RED4ext/Scripting/Natives/inkWidgetReference.hpp +++ b/include/RED4ext/Scripting/Natives/inkWidgetReference.hpp @@ -12,8 +12,8 @@ struct WidgetReference static constexpr const char* NAME = "inkWidgetReference"; static constexpr const char* ALIAS = "inkWidgetRef"; - virtual CClass* GetNativeType() {}; // 00 - virtual CClass* GetType() {}; // 08 + virtual rtti::ClassType* GetNativeType() {}; // 00 + virtual rtti::ClassType* GetType() {}; // 08 WeakHandle widget; // 08 }; diff --git a/include/RED4ext/Scripting/Stack.hpp b/include/RED4ext/Scripting/Stack.hpp index 5d29563d0..a346adc88 100644 --- a/include/RED4ext/Scripting/Stack.hpp +++ b/include/RED4ext/Scripting/Stack.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace RED4ext { @@ -16,15 +17,13 @@ namespace RED4ext * Maybe this should have the name 'CStack', but I am not entirely sure how to call '*Stack', so until a better name is * found, the names will be kept as they are now. */ -struct CBaseRTTIType; -struct CClass; struct IScriptable; struct CStackType { - CStackType(CBaseRTTIType* aType = nullptr, ScriptInstance aValue = nullptr); + CStackType(rtti::IType* aType = nullptr, ScriptInstance aValue = nullptr); - CBaseRTTIType* type; // 00 + rtti::IType* type; // 00 ScriptInstance value; // 08 }; RED4EXT_ASSERT_SIZE(CStackType, 0x10); @@ -40,7 +39,7 @@ struct IStack return nullptr; } - virtual CBaseRTTIType* GetResultType() // 10 + virtual rtti::IType* GetResultType() // 10 { return nullptr; } @@ -69,7 +68,7 @@ struct CBaseStack : IStack void* unk10; // 10 IScriptable* context18; // 18 IScriptable* context20; // 20 - CClass* unk28; // 28 + rtti::ClassType* unk28; // 28 protected: CBaseStack(IScriptable* aContext) noexcept; @@ -100,7 +99,7 @@ struct CScriptStack : CBaseStack uint8_t* args; // 30 ScriptInstance value; // 38 - CBaseRTTIType* type; // 40 + rtti::IType* type; // 40 }; RED4EXT_ASSERT_SIZE(CScriptStack, 0x48); @@ -119,7 +118,7 @@ struct CStackFrame int64_t unk20; // 20 int64_t unk28; // 28 void* data; // 30 - The result of the opcode, points to the original instance (local, param, etc.) - CBaseRTTIType* dataType; // 38 - The type of the result + rtti::IType* dataType; // 38 - The type of the result IScriptable* context; // 40 CStackFrame* parent; // 48 int16_t unk50; // 50 diff --git a/include/RED4ext/Scripting/Utils.hpp b/include/RED4ext/Scripting/Utils.hpp index 487257a9f..c7fbceeac 100644 --- a/include/RED4ext/Scripting/Utils.hpp +++ b/include/RED4ext/Scripting/Utils.hpp @@ -10,21 +10,20 @@ namespace RED4ext { struct CBaseFunction; -struct CClass; bool ExecuteFunction(ScriptInstance aInstance, CBaseFunction* aFunc, void* aOut); bool ExecuteFunction(ScriptInstance aInstance, CBaseFunction* aFunc, void* aOut, StackArgs_t& aArgs); -bool ExecuteFunction(CClass* aContext, CBaseFunction* aFunc, void* aOut, StackArgs_t& aArgs); -bool ExecuteFunction(CClass* aContext, CName aFunc, void* aOut, StackArgs_t& aArgs); +bool ExecuteFunction(rtti::ClassType* aContext, CBaseFunction* aFunc, void* aOut, StackArgs_t& aArgs); +bool ExecuteFunction(rtti::ClassType* aContext, CName aFunc, void* aOut, StackArgs_t& aArgs); bool ExecuteFunction(CName aContext, CName aFunc, void* aOut, StackArgs_t& aArgs); -bool ExecuteGlobalFunction(CClass* aContext, CName aFunc, void* aOut, StackArgs_t& aArgs); +bool ExecuteGlobalFunction(rtti::ClassType* aContext, CName aFunc, void* aOut, StackArgs_t& aArgs); bool ExecuteGlobalFunction(CName aContext, CName aFunc, void* aOut, StackArgs_t& aArgs); bool ExecuteGlobalFunction(CName aFunc, void* aOut, StackArgs_t& aArgs); template -bool ExecuteFunction(CClass* aContext, CBaseFunction* aFunc, void* aOut, Args&&... aArgs) +bool ExecuteFunction(rtti::ClassType* aContext, CBaseFunction* aFunc, void* aOut, Args&&... aArgs) { StackArgs_t args; ((args.emplace_back(nullptr, &aArgs)), ...); @@ -33,7 +32,7 @@ bool ExecuteFunction(CClass* aContext, CBaseFunction* aFunc, void* aOut, Args&&. } template -bool ExecuteFunction(CClass* aContext, CName aFunc, void* aOut, Args&&... aArgs) +bool ExecuteFunction(rtti::ClassType* aContext, CName aFunc, void* aOut, Args&&... aArgs) { StackArgs_t args; ((args.emplace_back(nullptr, &aArgs)), ...); @@ -51,7 +50,7 @@ bool ExecuteFunction(CName aContext, CName aFunc, void* aOut, Args&&... aArgs) } template -bool ExecuteGlobalFunction(CClass* aContext, CName aFunc, void* aOut, Args&&... aArgs) +bool ExecuteGlobalFunction(rtti::ClassType* aContext, CName aFunc, void* aOut, Args&&... aArgs) { StackArgs_t args; ((args.emplace_back(nullptr, &aArgs)), ...); diff --git a/include/RED4ext/String-inl.hpp b/include/RED4ext/String-inl.hpp new file mode 100644 index 000000000..a9240b811 --- /dev/null +++ b/include/RED4ext/String-inl.hpp @@ -0,0 +1,144 @@ +#pragma once + +#ifdef RED4EXT_STATIC_LIB +#include +#endif + +#include + +#include +#include + +RED4EXT_INLINE RED4ext::red::String::String(Memory::IAllocator* aAllocator) + : text{} + , length(0) + , allocator(aAllocator ? *reinterpret_cast(aAllocator) : nullptr) +{ +} + +RED4EXT_INLINE RED4ext::red::String::String(const char* aText, Memory::IAllocator* aAllocator) + : red::String(aAllocator) +{ + static UniversalRelocFunc func(Detail::AddressHashes::CString_ctor_str); + func(this, aText); +} + +RED4EXT_INLINE RED4ext::red::String::String(const char* aText, uint32_t aLength, Memory::IAllocator* aAllocator) + : red::String(aAllocator) +{ + static UniversalRelocFunc func( + Detail::AddressHashes::CString_ctor_span); + func(this, aText, aLength); +} + +RED4EXT_INLINE RED4ext::red::String::String(const std::string& aText, Memory::IAllocator* aAllocator) + : red::String(aAllocator) +{ + static UniversalRelocFunc func(Detail::AddressHashes::CString_ctor_str); + func(this, aText.data()); +} + +RED4EXT_INLINE RED4ext::red::String::String(const std::string_view& aText, Memory::IAllocator* aAllocator) + : red::String(aAllocator) +{ + static UniversalRelocFunc func( + Detail::AddressHashes::CString_ctor_span); + func(this, aText.data(), static_cast(aText.size())); +} + +RED4EXT_INLINE RED4ext::red::String::String(const red::String& aOther) + : red::String() +{ + static UniversalRelocFunc func(Detail::AddressHashes::CString_copy); + func(this, aOther); +} + +RED4EXT_INLINE RED4ext::red::String::~String() +{ + static UniversalRelocFunc func(Detail::AddressHashes::CString_dtor); + func(this); +} + +RED4EXT_INLINE RED4ext::red::String::String(String&& aOther) noexcept + : length(aOther.length) + , allocator(aOther.allocator) +{ + std::memmove(&text, &aOther.text, sizeof(text)); + + std::memset(&aOther.text, 0, sizeof(aOther.text)); + aOther.length = 0; + aOther.allocator = nullptr; +} + +RED4EXT_INLINE RED4ext::red::String& RED4ext::red::String::operator=(const red::String& aRhs) +{ + static UniversalRelocFunc func(Detail::AddressHashes::CString_copy); + func(this, aRhs); + return *this; +} + +RED4EXT_INLINE RED4ext::red::String& RED4ext::red::String::operator=(String&& aRhs) noexcept +{ + std::memmove(&text, &aRhs.text, sizeof(text)); + + length = aRhs.length; + allocator = aRhs.allocator; + + std::memset(&aRhs.text, 0, sizeof(aRhs.text)); + aRhs.length = 0; + aRhs.allocator = nullptr; + + return *this; +} + +RED4EXT_INLINE bool RED4ext::red::String::operator==(const char* aRhs) const noexcept +{ + auto lhsText = c_str(); + if (!lhsText || !aRhs) + { + return false; + } + + return strcmp(lhsText, aRhs) == 0; +} + +RED4EXT_INLINE bool RED4ext::red::String::operator==(const red::String& aRhs) const noexcept +{ + auto lhsText = c_str(); + if (!lhsText) + { + return false; + } + auto rhsText = aRhs.c_str(); + if (!rhsText) + { + return false; + } + + if (Length() != aRhs.Length()) + { + return false; + } + + return strcmp(lhsText, rhsText) == 0; +} + +RED4EXT_INLINE bool RED4ext::red::String::IsInline() const noexcept +{ + return length < 0x40000000; +} + +RED4EXT_INLINE const char* RED4ext::red::String::c_str() const noexcept +{ + if (IsInline()) + { + return text.inline_str; + } + + return text.str.ptr; +} + +RED4EXT_INLINE uint32_t RED4ext::red::String::Length() const noexcept +{ + return length & 0x3FFFFFFF; +} diff --git a/include/RED4ext/String.hpp b/include/RED4ext/String.hpp new file mode 100644 index 000000000..558101696 --- /dev/null +++ b/include/RED4ext/String.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace RED4ext +{ +namespace Memory +{ +struct IAllocator; +} + +namespace red +{ + +struct String +{ + String(Memory::IAllocator* aAllocator = nullptr); + String(const char* aText, Memory::IAllocator* aAllocator = nullptr); + String(const char* aText, uint32_t aLength, Memory::IAllocator* aAllocator = nullptr); + String(const std::string& aText, Memory::IAllocator* aAllocator = nullptr); + String(const std::string_view& aText, Memory::IAllocator* aAllocator = nullptr); + + String(const String& aOther); + String(String&& aOther) noexcept; + + ~String(); + + String& operator=(const String& aRhs); + String& operator=(String&& aRhs) noexcept; + + bool operator==(const char* aRhs) const noexcept; + bool operator==(const String& aRhs) const noexcept; + + inline bool operator!=(const char* aRhs) const noexcept + { + return !(*this == aRhs); + } + + inline bool operator!=(const String& aRhs) const noexcept + { + return !(*this == aRhs); + } + + inline const char& operator[](size_t aIndex) const + { + return c_str()[aIndex]; + } + + [[nodiscard]] bool IsInline() const noexcept; + + [[nodiscard]] const char* c_str() const noexcept; + [[nodiscard]] uint32_t Length() const noexcept; + + [[nodiscard]] const char* begin() const + { + return c_str(); + } + + [[nodiscard]] const char* end() const + { + return c_str() + Length(); + } + +#pragma pack(push, 4) + union + { + char inline_str[0x14]; + struct + { + char* ptr; + int8_t unk[8]; + int32_t capacity; + } str; + } text; // 00 +#pragma pack(pop) + + uint32_t length; // 14 + Memory::IAllocator* allocator; // 18 +}; +RED4EXT_ASSERT_SIZE(String, 0x20); +RED4EXT_ASSERT_OFFSET(String, text, 0x00); +RED4EXT_ASSERT_OFFSET(String, length, 0x14); +RED4EXT_ASSERT_OFFSET(String, allocator, 0x18); + +template +struct HashMapHash>> +{ + uint32_t operator()(const T& aKey) const noexcept + { + // I believe the game uses this implementation for StringView and String? + std::uint32_t hash{}; + + for (const auto i : aKey) + { + hash = static_cast(i) + 31u * hash; + } + + return hash; + } +}; +} // namespace red +} // namespace RED4ext + +#ifdef RED4EXT_HEADER_ONLY +#include +#endif diff --git a/include/RED4ext/StringView-inl.hpp b/include/RED4ext/StringView-inl.hpp index 468c26eaa..098704f9d 100644 --- a/include/RED4ext/StringView-inl.hpp +++ b/include/RED4ext/StringView-inl.hpp @@ -6,101 +6,101 @@ #include -RED4EXT_INLINE constexpr RED4ext::StringView::StringView() noexcept +RED4EXT_INLINE constexpr RED4ext::red::StringView::StringView() noexcept : ptr(nullptr) , length(0u) { } -RED4EXT_INLINE constexpr RED4ext::StringView::StringView(const char* aStr) noexcept +RED4EXT_INLINE constexpr RED4ext::red::StringView::StringView(const char* aStr) noexcept : ptr(aStr) , length(static_cast(std::char_traits::length(aStr))) { } -RED4EXT_INLINE constexpr RED4ext::StringView::StringView(std::string_view aView) noexcept +RED4EXT_INLINE constexpr RED4ext::red::StringView::StringView(std::string_view aView) noexcept : ptr(aView.data()) , length(static_cast(aView.length())) { } -RED4EXT_INLINE RED4ext::StringView::StringView(const RED4ext::CString& aStr) noexcept +RED4EXT_INLINE RED4ext::red::StringView::StringView(const RED4ext::red::String& aStr) noexcept : ptr(aStr.c_str()) , length(aStr.Length()) { } -RED4EXT_INLINE constexpr bool RED4ext::StringView::IsEmpty() const noexcept +RED4EXT_INLINE constexpr bool RED4ext::red::StringView::IsEmpty() const noexcept { return !ptr || length == 0u; } -RED4EXT_INLINE constexpr RED4ext::StringView::operator bool() const noexcept +RED4EXT_INLINE constexpr RED4ext::red::StringView::operator bool() const noexcept { return !IsEmpty(); } -RED4EXT_INLINE constexpr bool RED4ext::StringView::operator==(const StringView& aRhs) const noexcept +RED4EXT_INLINE constexpr bool RED4ext::red::StringView::operator==(const StringView& aRhs) const noexcept { return Length() == aRhs.Length() && std::char_traits::compare(Data(), aRhs.Data(), Length()) == 0; } -RED4EXT_INLINE constexpr bool RED4ext::StringView::operator!=(const StringView& aRhs) const noexcept +RED4EXT_INLINE constexpr bool RED4ext::red::StringView::operator!=(const StringView& aRhs) const noexcept { return !(*this == aRhs); } -RED4EXT_INLINE constexpr bool RED4ext::StringView::operator==(const char* aRhs) const noexcept +RED4EXT_INLINE constexpr bool RED4ext::red::StringView::operator==(const char* aRhs) const noexcept { return *this == StringView{aRhs}; } -RED4EXT_INLINE constexpr bool RED4ext::StringView::operator!=(const char* aRhs) const noexcept +RED4EXT_INLINE constexpr bool RED4ext::red::StringView::operator!=(const char* aRhs) const noexcept { return *this != StringView{aRhs}; } -RED4EXT_INLINE constexpr bool RED4ext::StringView::operator==(std::string_view aRhs) const noexcept +RED4EXT_INLINE constexpr bool RED4ext::red::StringView::operator==(std::string_view aRhs) const noexcept { return *this == StringView{aRhs}; } -RED4EXT_INLINE constexpr bool RED4ext::StringView::operator!=(std::string_view aRhs) const noexcept +RED4EXT_INLINE constexpr bool RED4ext::red::StringView::operator!=(std::string_view aRhs) const noexcept { return *this != StringView{aRhs}; } -RED4EXT_INLINE bool RED4ext::StringView::operator==(const RED4ext::CString& aRhs) const noexcept +RED4EXT_INLINE bool RED4ext::red::StringView::operator==(const RED4ext::CString& aRhs) const noexcept { return *this == StringView{aRhs}; } -RED4EXT_INLINE bool RED4ext::StringView::operator!=(const RED4ext::CString& aRhs) const noexcept +RED4EXT_INLINE bool RED4ext::red::StringView::operator!=(const RED4ext::CString& aRhs) const noexcept { return *this != StringView{aRhs}; } -RED4EXT_INLINE constexpr char RED4ext::StringView::operator[](std::size_t aIndex) const noexcept +RED4EXT_INLINE constexpr char RED4ext::red::StringView::operator[](std::size_t aIndex) const noexcept { return Data()[aIndex]; } -RED4EXT_INLINE constexpr const char* RED4ext::StringView::Data() const noexcept +RED4EXT_INLINE constexpr const char* RED4ext::red::StringView::Data() const noexcept { return ptr; } -RED4EXT_INLINE constexpr std::uint32_t RED4ext::StringView::Length() const noexcept +RED4EXT_INLINE constexpr std::uint32_t RED4ext::red::StringView::Length() const noexcept { return length; } -RED4EXT_INLINE constexpr const char* RED4ext::StringView::begin() const noexcept +RED4EXT_INLINE constexpr const char* RED4ext::red::StringView::begin() const noexcept { return Data(); } -RED4EXT_INLINE constexpr const char* RED4ext::StringView::end() const noexcept +RED4EXT_INLINE constexpr const char* RED4ext::red::StringView::end() const noexcept { return Data() + Length(); } diff --git a/include/RED4ext/StringView.hpp b/include/RED4ext/StringView.hpp index 4c3b7578b..ed2ab42da 100644 --- a/include/RED4ext/StringView.hpp +++ b/include/RED4ext/StringView.hpp @@ -6,7 +6,11 @@ namespace RED4ext { -struct CString; + +namespace red +{ + +struct String; #pragma pack(push, 4) struct StringView @@ -14,7 +18,7 @@ struct StringView constexpr StringView() noexcept; constexpr StringView(const char* aStr) noexcept; constexpr StringView(std::string_view aView) noexcept; - StringView(const RED4ext::CString& aStr) noexcept; + StringView(const RED4ext::red::String& aStr) noexcept; constexpr bool IsEmpty() const noexcept; constexpr operator bool() const noexcept; @@ -25,8 +29,8 @@ struct StringView constexpr bool operator!=(const char* aRhs) const noexcept; constexpr bool operator==(std::string_view aRhs) const noexcept; constexpr bool operator!=(std::string_view aRhs) const noexcept; - bool operator==(const RED4ext::CString& aRhs) const noexcept; - bool operator!=(const RED4ext::CString& aRhs) const noexcept; + bool operator==(const RED4ext::red::String& aRhs) const noexcept; + bool operator!=(const RED4ext::red::String& aRhs) const noexcept; constexpr char operator[](std::size_t aIndex) const noexcept; @@ -44,6 +48,11 @@ struct StringView RED4EXT_ASSERT_SIZE(StringView, 0xC); RED4EXT_ASSERT_OFFSET(StringView, ptr, 0x0); RED4EXT_ASSERT_OFFSET(StringView, length, 0x8); + +} // namespace red + +using StringView [[deprecated("Use red::StringView")]] = red::StringView; + } // namespace RED4ext #ifdef RED4EXT_HEADER_ONLY diff --git a/include/RED4ext/SystemUpdate-inl.hpp b/include/RED4ext/SystemUpdate-inl.hpp index b93c8b05d..e44414d3c 100644 --- a/include/RED4ext/SystemUpdate-inl.hpp +++ b/include/RED4ext/SystemUpdate-inl.hpp @@ -12,7 +12,7 @@ RED4EXT_INLINE void RED4ext::UpdateRegistrar::RegisterUpdate(UpdateTickGroup aGroup, IUpdatableSystem* aSystem, const char* aName, GroupUpdateCallback&& aCallback) { - using func_t = void (*)(UpdateRegistrar*, UpdateTickGroup, CClass*, const char*, GroupUpdateCallback&&, uint32_t); + using func_t = void (*)(UpdateRegistrar*, UpdateTickGroup, rtti::ClassType*, const char*, GroupUpdateCallback&&, uint32_t); static UniversalRelocFunc func(Detail::AddressHashes::UpdateRegistrar_RegisterGroupUpdate); func(this, aGroup, aSystem->GetNativeType(), aName, std::forward(aCallback), 0); @@ -22,7 +22,7 @@ RED4EXT_INLINE void RED4ext::UpdateRegistrar::RegisterUpdate(UpdateBucketMask aB IUpdatableSystem* aSystem, const char* aName, BucketUpdateCallback&& aCallback) { - using func_t = void (*)(UpdateRegistrar*, UpdateBucketMask, UpdateBucketStage, CClass*, const char*, + using func_t = void (*)(UpdateRegistrar*, UpdateBucketMask, UpdateBucketStage, rtti::ClassType*, const char*, BucketUpdateCallback&&, uint32_t); static UniversalRelocFunc func(Detail::AddressHashes::UpdateRegistrar_RegisterBucketUpdate); diff --git a/include/RED4ext/rtti/ClassType-inl.hpp b/include/RED4ext/rtti/ClassType-inl.hpp new file mode 100644 index 000000000..fd574dd3f --- /dev/null +++ b/include/RED4ext/rtti/ClassType-inl.hpp @@ -0,0 +1,251 @@ +#pragma once + +#ifdef RED4EXT_STATIC_LIB +#include +#endif + +#include +#include +#include +#include +#include + +RED4EXT_INLINE RED4ext::rtti::ClassType::ClassType(CName aName, uint32_t aSize, Flags aFlags) + : parent(nullptr) + , name(aName) + , computedName(rtti::IType::GetComputedName()) + , size(aSize) + , flags(aFlags) + , holderSize(0) + , alignment(4) + , props(Memory::RTTIAllocator::Get()) + , overriddenProps(Memory::RTTIAllocator::Get()) + , funcs(Memory::RTTIAllocator::Get()) + , staticFuncs(Memory::RTTIAllocator::Get()) + , funcsByName(Memory::RTTIAllocator::Get()) + , unkA8(Memory::RTTIAllocator::Get()) + , unkD8(0) + , unkE0(0) + , propsByName(Memory::RTTIAllocator::Get()) + , unk118(Memory::RTTIAllocator::Get()) + , unk128(Memory::RTTIAllocator::Get()) + , unk138(Memory::RTTIAllocator::Get()) + , unk148(Memory::RTTIAllocator::Get()) + , defaults(Memory::ScriptAllocator::Get()) + , unk180(Memory::RTTIAllocator::Get()) + , listeners(Memory::RTTIAllocator::Get()) + , eventTypeId(-1) + , unk2C4(-1) + , unk2C9(0xE6) +{ + std::memset(listening, 0, sizeof(listening)); +} + +RED4EXT_INLINE RED4ext::CName RED4ext::rtti::ClassType::GetName() const +{ + return name; +} + +RED4EXT_INLINE uint32_t RED4ext::rtti::ClassType::GetSize() const +{ + return size; +} + +RED4EXT_INLINE uint32_t RED4ext::rtti::ClassType::GetAlignment() const +{ + return alignment; +} + +RED4EXT_INLINE RED4ext::ERTTIType RED4ext::rtti::ClassType::GetType() const +{ + return ERTTIType::Class; +} + +RED4EXT_INLINE RED4ext::CName RED4ext::rtti::ClassType::GetComputedName() const +{ + return computedName; +} + +RED4EXT_INLINE void RED4ext::rtti::ClassType::Construct(ScriptInstance aMemory) const +{ + ConstructCls(aMemory); +} + +RED4EXT_INLINE void RED4ext::rtti::ClassType::Destruct(ScriptInstance aMemory) const +{ + DestructCls(aMemory); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::Unserialize(BaseStream* aStream, ScriptInstance aInstance, int64_t a3) const +{ + using func_t = bool (*)(const ClassType*, BaseStream*, ScriptInstance, int64_t); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_Unserialize); + return func(this, aStream, aInstance, a3); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::ToString(const ScriptInstance aInstance, CString& aOut) const +{ + using func_t = bool (*)(const ClassType*, ScriptInstance, CString&); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_ToString); + return func(this, aInstance, aOut); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::sub_80(int64_t a1, ScriptInstance aInstance) +{ + using func_t = bool (*)(const ClassType*, int64_t, ScriptInstance); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_sub_80); + return func(this, a1, aInstance); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::sub_88(int64_t a1, ScriptInstance aInstance) +{ + using func_t = bool (*)(const ClassType*, int64_t, ScriptInstance); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_sub_88); + return func(this, a1, aInstance); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::sub_90(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4) +{ + using func_t = bool (*)(const ClassType*, int64_t, ScriptInstance, CString&, int64_t); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_sub_90); + return func(this, a1, aInstance, a3, a4); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::sub_98(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4, bool a5) +{ + RED4EXT_UNUSED_PARAMETER(a5); + + using func_t = bool (*)(const ClassType*, int64_t, ScriptInstance, CString&, int64_t); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_sub_90); + return func(this, a1, aInstance, a3, a4); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::sub_A0(int64_t a1, CString& a2, bool a3) +{ + using func_t = bool (*)(const ClassType*, int64_t, CString&, bool); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_sub_A0); + return func(this, a1, a2, a3); +} + +RED4EXT_INLINE void RED4ext::rtti::ClassType::sub_B0(int64_t a1, int64_t a2) +{ + using func_t = bool (*)(const ClassType*, int64_t, int64_t); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_sub_B0); + func(this, a1, a2); +} + +RED4EXT_INLINE void RED4ext::rtti::ClassType::sub_C0() +{ + using func_t = void (*)(ClassType*); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_sub_C0); + func(this); +} + +RED4EXT_INLINE uint32_t RED4ext::rtti::ClassType::GetMaxAlignment() const +{ + using func_t = uint32_t (*)(const ClassType*); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_GetMaxAlignment); + return func(this); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::sub_D0() const +{ + using func_t = bool (*)(const ClassType*); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_sub_D0); + return func(this); +} + +RED4EXT_INLINE RED4ext::ScriptInstance RED4ext::rtti::ClassType::CreateInstance(bool aZeroMemory) const +{ + using func_t = ScriptInstance (*)(const ClassType*, uint32_t, bool); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_CreateInstance); + return func(this, GetSize(), aZeroMemory); +} + +RED4EXT_INLINE bool RED4ext::rtti::ClassType::IsA(const CBaseRTTIType* aType) const +{ + if (this == aType) + { + return true; + } + + if (parent) + { + return parent->IsA(aType); + } + + return false; +} + +RED4EXT_INLINE RED4ext::CProperty* RED4ext::rtti::ClassType::GetProperty(CName aName) +{ + // Not recreating this because they do something strage with overriden properties and I am not sure what exactly + // they do. + + using func_t = CProperty* (*)(ClassType*, CName); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_GetProperty); + return func(this, aName); +} + +RED4EXT_INLINE void RED4ext::rtti::ClassType::InitializeProperties(ScriptInstance aInstance) +{ + static UniversalRelocFunc initializeProperties( + Detail::AddressHashes::ClassType_InitializeProperties); + initializeProperties(this, aInstance); + + static UniversalRelocFunc assignDefaultValuesToProperties( + Detail::AddressHashes::ClassType_AssignDefaultValuesToProperties); + assignDefaultValuesToProperties(this, aInstance); +} + +RED4EXT_INLINE void RED4ext::rtti::ClassType::GetProperties(DynArray& aProps) +{ + using func_t = CProperty* (*)(ClassType*, DynArray&); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_GetProperties); + func(this, aProps); +} + +RED4EXT_INLINE RED4ext::rtti::ClassTypeFunction* RED4ext::rtti::ClassType::GetFunction(CName aShortName) const +{ + for (auto func : staticFuncs) + { + if (func->shortName == aShortName) + { + return func; + } + } + + for (auto func : funcs) + { + if (func->shortName == aShortName) + { + return func; + } + } + + if (parent) + { + return parent->GetFunction(aShortName); + } + + return nullptr; +} + +RED4EXT_INLINE void RED4ext::rtti::ClassType::RegisterFunction(ClassTypeFunction* aFunc) +{ + if (aFunc->flags.isStatic) + { + staticFuncs.PushBack(static_cast(aFunc)); + } + else + { + funcs.PushBack(aFunc); + } +} + +RED4EXT_INLINE void RED4ext::rtti::ClassType::ClearScriptedData() +{ + using func_t = void (*)(ClassType*); + static UniversalRelocFunc func(Detail::AddressHashes::ClassType_ClearScriptedData); + func(this); +} \ No newline at end of file diff --git a/include/RED4ext/rtti/ClassType.hpp b/include/RED4ext/rtti/ClassType.hpp new file mode 100644 index 000000000..6d236cf0e --- /dev/null +++ b/include/RED4ext/rtti/ClassType.hpp @@ -0,0 +1,157 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace RED4ext +{ +struct BaseStream; +struct CProperty; +struct CClassFunction; +struct CClassStaticFunction; +struct Variant; + +namespace rtti { + +struct ClassType : IType +{ + struct Flags + { + uint32_t isAbstract : 1; // 00 + uint32_t isNative : 1; // 01 + uint32_t isScriptedClass : 1; // 02 + uint32_t isScriptedStruct : 1; // 03 + uint32_t hasNoDefaultObjectSerialization : 1; // 04 + uint32_t isAlwaysTransient : 1; // 05 + uint32_t isImportOnly : 1; // 06 + uint32_t isPrivate : 1; // 07 + uint32_t isProtected : 1; // 08 + uint32_t isTestOnly : 1; // 09 + uint32_t isSavable : 1; // 0A + uint32_t b10 : 21; // 0B + }; + RED4EXT_ASSERT_SIZE(ClassType::Flags, 0x4); + + struct Listener + { + Callback&), 16> callback; // 00 + CName callbackName; // 18 + int16_t eventTypeId; // 20 + bool isScripted; // 22 + }; + RED4EXT_ASSERT_SIZE(ClassType::Listener, 0x28); + RED4EXT_ASSERT_OFFSET(ClassType::Listener, callbackName, 0x18); + RED4EXT_ASSERT_OFFSET(ClassType::Listener, isScripted, 0x22); + + ClassType(CName aName, uint32_t aSize, Flags aFlags); + + CName GetName() const final; // 08 + uint32_t GetSize() const final; // 10 + uint32_t GetAlignment() const final; // 18 + ERTTIType GetType() const final; // 20 + CName GetComputedName() const final; // 30 + void Construct(ScriptInstance aMemory) const final; // 38 + void Destruct(ScriptInstance aMemory) const final; // 40 + bool Unserialize(BaseStream* aStream, ScriptInstance aInstance, int64_t a3) const final; // 60 + bool ToString(const ScriptInstance aInstance, CString& aOut) const final; // 68 + bool sub_80(int64_t a1, ScriptInstance aInstance) final; // 80 + bool sub_88(int64_t a1, ScriptInstance aInstance) final; // 88 + bool sub_90(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4) final; // 90 + bool sub_98(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4, bool a5) final; // 98 + bool sub_A0(int64_t a1, CString& a2, bool a3) final; // A0 + void sub_B0(int64_t a1, int64_t a2) final; // B0 + + virtual void sub_C0(); // C0 + virtual uint32_t GetMaxAlignment() const; // C8 + virtual bool sub_D0() const; // D0 + virtual void ConstructCls(ScriptInstance aMemory) const = 0; // D8 + virtual void DestructCls(ScriptInstance aMemory) const = 0; // E0 + virtual void* AllocMemory() const = 0; // E8 + + ScriptInstance CreateInstance(bool aZeroMemory = false) const; + + bool IsA(const IType* aType) const; + + CProperty* GetProperty(CName aName); + CClassFunction* GetFunction(CName aShortName) const; + + void InitializeProperties(ScriptInstance aInstance); + void GetProperties(DynArray& aProps); + + void RegisterFunction(CClassFunction* aFunc); + + void ClearScriptedData(); + + [[deprecated("Use 'ConstructCls()' instead.")]] + inline void InitCls(ScriptInstance aMemory) const + { + ConstructCls(aMemory); + } + + [[deprecated("Use 'DestructCls()' instead.")]] + inline void DestroyCls(ScriptInstance aMemory) const + { + DestructCls(aMemory); + } + + [[deprecated("Use 'CreateInstance()' instead.")]] + inline ScriptInstance AllocInstance(bool aZeroMemory = false) const + { + return CreateInstance(aZeroMemory); + } + + ClassType* parent; // 10 + CName name; // 18 + CName computedName; // 20 + DynArray props; // 28 + DynArray overriddenProps; // 38 + DynArray funcs; // 48 + DynArray staticFuncs; // 58 + uint32_t size; // 68 + uint32_t holderSize; // 6C + Flags flags; // 70 + uint32_t alignment; // 74 + HashMap funcsByName; // 78 + HashMap unkA8; // A8 + int64_t unkD8; // D8 + int64_t unkE0; // E0 + HashMap propsByName; // E8 + DynArray unk118; // 118 - More entries than 0x28, will contain native props + DynArray unk128; // 128 + DynArray unk138; // 138 - Only RT_Class types? + DynArray unk148; // 148 + Map defaults; // 158 + HashMap unk180; // 180 + DynArray listeners; // 1B0 - Event listeners + int8_t listening[256]; // 1C0 - Bitmask of event types that this class listens to + int16_t eventTypeId; // 2C0 - Assigned to event classes only + int32_t unk2C4; // 2C4 + SharedSpinLock unk2C8; // 2C8 + uint8_t unk2C9; // 2C9 +}; +RED4EXT_ASSERT_SIZE(ClassType, 0x2D0); +RED4EXT_ASSERT_OFFSET(ClassType, parent, 0x10); +RED4EXT_ASSERT_OFFSET(ClassType, name, 0x18); +RED4EXT_ASSERT_OFFSET(ClassType, props, 0x28); +RED4EXT_ASSERT_OFFSET(ClassType, overriddenProps, 0x38); +RED4EXT_ASSERT_OFFSET(ClassType, funcs, 0x48); +RED4EXT_ASSERT_OFFSET(ClassType, size, 0x68); +RED4EXT_ASSERT_OFFSET(ClassType, flags, 0x70); +RED4EXT_ASSERT_OFFSET(ClassType, alignment, 0x74); + +} + +} + +#ifdef RED4EXT_HEADER_ONLY +#include +#endif diff --git a/include/RED4ext/rtti/IType-inl.hpp b/include/RED4ext/rtti/IType-inl.hpp new file mode 100644 index 000000000..b7f40c1ba --- /dev/null +++ b/include/RED4ext/rtti/IType-inl.hpp @@ -0,0 +1,182 @@ +#pragma once + +#ifdef RED4EXT_STATIC_LIB +#include +#endif + +#include +#include +#include +#include +#include + +RED4EXT_INLINE RED4ext::rtti::IType::CBaseRTTIType() + : unk8(0) +{ +} + +RED4EXT_INLINE RED4ext::CString RED4ext::rtti::IType::GetTypeName() const +{ + switch (GetType()) + { + case ERTTIType::Name: + { + return "RT_Name"; + } + case ERTTIType::Fundamental: + { + return "RT_Fundamental"; + } + case ERTTIType::Class: + { + return "RT_Class"; + } + case ERTTIType::Array: + { + return "RT_Array"; + } + case ERTTIType::Simple: + { + return "RT_Simple"; + } + case ERTTIType::Enum: + { + return "RT_Enum"; + } + case ERTTIType::StaticArray: + { + return "RT_StaticArray"; + } + case ERTTIType::NativeArray: + { + return "RT_NativeArray"; + } + case ERTTIType::Pointer: + { + return "RT_Pointer"; + } + case ERTTIType::Handle: + { + return "RT_Handle"; + } + case ERTTIType::WeakHandle: + { + return "RT_WeakHandle"; + } + case ERTTIType::ResourceReference: + { + return "RT_ResourceReference"; + } + case ERTTIType::ResourceAsyncReference: + { + return "RT_ResourceAsyncReference"; + } + case ERTTIType::BitField: + { + return "RT_BitField"; + } + case ERTTIType::LegacySingleChannelCurve: + { + return "RT_LegacySingleChannelCurve"; + } + case ERTTIType::ScriptReference: + { + return "RT_ScriptReference"; + } + default: + { + return "Unhandled ERTTITypeType"; + } + } +} + +RED4EXT_INLINE RED4ext::CName RED4ext::rtti::IType::GetComputedName() const +{ + std::string name = "script_ref:"; + auto hash = GetName(); + if (!hash.IsNone()) + { + name += hash.ToString(); + return CNamePool::Add(name.c_str()); + } + + return 0ull; +} + +RED4EXT_INLINE void RED4ext::rtti::IType::Move(ScriptInstance aLhs, ScriptInstance aRhs) const +{ + Assign(aLhs, aRhs); +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::ToString(const ScriptInstance aInstance, CString& aOut) const +{ + RED4EXT_UNUSED_PARAMETER(aInstance); + RED4EXT_UNUSED_PARAMETER(aOut); + + return false; +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::FromString(ScriptInstance aInstance, const CString& aString) const +{ + RED4EXT_UNUSED_PARAMETER(aInstance); + RED4EXT_UNUSED_PARAMETER(aString); + + return false; +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::sub_78() +{ + return true; +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::sub_80(int64_t a1, ScriptInstance aInstance) +{ + using func_t = bool (*)(CBaseRTTIType*, int64_t, ScriptInstance); + static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_80); + return func(this, a1, aInstance); +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::sub_88(int64_t a1, ScriptInstance aInstance) +{ + using func_t = bool (*)(CBaseRTTIType*, int64_t, ScriptInstance); + static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_88); + return func(this, a1, aInstance); +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::sub_90(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4) +{ + using func_t = bool (*)(CBaseRTTIType*, int64_t, ScriptInstance, CString&, int64_t); + static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_90); + return func(this, a1, aInstance, a3, a4); +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::sub_98(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4, + bool a5) +{ + using func_t = bool (*)(CBaseRTTIType*, int64_t, ScriptInstance, CString&, int64_t, bool); + static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_98); + return func(this, a1, aInstance, a3, a4, a5); +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::sub_A0(int64_t a1, CString& a2, bool a3) +{ + using func_t = bool (*)(CBaseRTTIType*, int64_t, CString&, bool); + static UniversalRelocFunc func(Detail::AddressHashes::CBaseRTTIType_sub_A0); + return func(this, a1, a2, a3); +} + +RED4EXT_INLINE bool RED4ext::rtti::IType::sub_A8() +{ + return false; +} + +RED4EXT_INLINE void RED4ext::rtti::IType::sub_B0(int64_t a1, int64_t a2) +{ + RED4EXT_UNUSED_PARAMETER(a1); + RED4EXT_UNUSED_PARAMETER(a2); +} + +RED4EXT_INLINE RED4ext::Memory::IAllocator* RED4ext::rtti::IType::GetAllocator() const +{ + return Memory::RTTIAllocator::Get(); +} \ No newline at end of file diff --git a/include/RED4ext/rtti/IType.hpp b/include/RED4ext/rtti/IType.hpp new file mode 100644 index 000000000..db80f3d3f --- /dev/null +++ b/include/RED4ext/rtti/IType.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace RED4ext::rtti { + +struct IType +{ + IType(); + virtual ~IType() = default; // 00 + + virtual CName GetName() const = 0; // 08 + virtual uint32_t GetSize() const = 0; // 10 + virtual uint32_t GetAlignment() const = 0; // 18 + virtual ERTTIType GetType() const = 0; // 20 + virtual CString GetTypeName() const; // 28 + virtual CName GetComputedName() const; // 30 + virtual void Construct(ScriptInstance aMemory) const = 0; // 38 + virtual void Destruct(ScriptInstance aMemory) const = 0; // 40 + virtual const bool IsEqual(const ScriptInstance aLhs, const ScriptInstance aRhs, + uint32_t a3 = 0) = 0; // 48 - Not const because CClass aquire some mutex when this is + // called and a flag is modified. + virtual void Assign(ScriptInstance aLhs, const ScriptInstance aRhs) const = 0; // 50 + virtual void Move(ScriptInstance aLhs, ScriptInstance aRhs) const; // 58 + virtual bool Unserialize(BaseStream* aStream, ScriptInstance aInstance, int64_t a3) const = 0; // 60 + virtual bool ToString(const ScriptInstance aInstance, CString& aOut) const; // 68 + virtual bool FromString(ScriptInstance aInstance, const CString& aString) const; // 70 + virtual bool sub_78(); // 78 + virtual bool sub_80(int64_t a1, ScriptInstance aInstance); // 80 + virtual bool sub_88(int64_t a1, ScriptInstance aInstance); // 88 + virtual bool sub_90(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4); // 90 + virtual bool sub_98(int64_t a1, ScriptInstance aInstance, CString& a3, int64_t a4, bool a5); // 98 + virtual bool sub_A0(int64_t a1, CString& a2, bool a3); // A0 + virtual bool sub_A8(); // A8 + virtual void sub_B0(int64_t a1, int64_t a2); // B0 + virtual Memory::IAllocator* GetAllocator() const; // B8 + + [[deprecated("Use 'GetName()' instead.")]] + inline void GetName(CName& aOut) const + { + aOut = GetName(); + } + + [[deprecated("Use 'GetComputedName()' instead.")]] + inline CName GetName2() const + { + return GetComputedName(); + } + + [[deprecated("Use 'GetComputedName()' instead.")]] + inline void GetName2(CName& aOut) const + { + aOut = GetComputedName(); + } + + [[deprecated("Use 'GetTypeName()' instead.")]] + inline void GetTypeName(CString& aOut) const + { + auto name = GetTypeName(); + aOut = name; + } + + [[deprecated("Use 'Construct()' instead.")]] + inline void Init(ScriptInstance aMemory) const + { + Construct(aMemory); + } + + [[deprecated("Use 'Destruct()' instead.")]] + inline void Destroy(ScriptInstance aMemory) const + { + Destruct(aMemory); + } + + int64_t unk8; +}; +RED4EXT_ASSERT_SIZE(IType, 0x10); + +} + +#ifdef RED4EXT_HEADER_ONLY +#include +#endif diff --git a/src/CString.cpp b/src/String.cpp similarity index 73% rename from src/CString.cpp rename to src/String.cpp index 9288a4140..648e390a5 100644 --- a/src/CString.cpp +++ b/src/String.cpp @@ -2,4 +2,4 @@ #error Please define 'RED4EXT_STATIC_LIB' to compile this file. #endif -#include +#include