#pragma once namespace RE { namespace msvc { class type_info; } namespace RTTI { template class RVA { public: using value_type = T; using pointer = value_type*; using reference = value_type&; constexpr RVA() noexcept = default; constexpr RVA(std::uint32_t a_rva) noexcept : _rva(a_rva) {} [[nodiscard]] pointer get() const { return is_good() ? REL::Relocation{ REL::Offset(_rva) }.get() : nullptr; } [[nodiscard]] std::uint32_t offset() const noexcept { return _rva; } [[nodiscard]] reference operator*() const { return *get(); } [[nodiscard]] pointer operator->() const { return get(); } [[nodiscard]] explicit constexpr operator bool() const noexcept { return is_good(); } protected: [[nodiscard]] constexpr bool is_good() const noexcept { return _rva != 0; } // members std::uint32_t _rva{ 0 }; // 00 }; static_assert(sizeof(RVA) == 0x4); using TypeDescriptor = std::type_info; class PMD { public: // members std::int32_t mDisp; // 0 std::int32_t pDisp; // 4 std::int32_t vDisp; // 8 }; static_assert(sizeof(PMD) == 0xC); class BaseClassDescriptor { public: enum class Attribute : std::uint32_t { kNone = 0, kNotVisible = 1 << 0, kAmbiguous = 1 << 1, kPrivate = 1 << 2, kPrivateOrProtectedBase = 1 << 3, kVirtual = 1 << 4, kNonPolymorphic = 1 << 5, kHasHierarchyDescriptor = 1 << 6 }; // members RVA typeDescriptor; // 00 std::uint32_t numContainedBases; // 04 PMD pmd; // 08 REX::TEnumSet attributes; // 14 }; static_assert(sizeof(BaseClassDescriptor) == 0x18); class ClassHierarchyDescriptor { public: enum class Attribute { kNoInheritance = 0, kMultipleInheritance = 1 << 0, kVirtualInheritance = 1 << 1, kAmbiguousInheritance = 1 << 2 }; // members std::uint32_t signature; // 00 REX::TEnumSet attributes; // 04 std::uint32_t numBaseClasses; // 08 RVA baseClassArray; // 0C }; static_assert(sizeof(ClassHierarchyDescriptor) == 0x10); class CompleteObjectLocator { public: enum class Signature { x86 = 0, x64 = 1 }; // members REX::TEnumSet signature; // 00 std::uint32_t offset; // 04 std::uint32_t ctorDispOffset; // 08 RVA typeDescriptor; // 0C RVA classDescriptor; // 10 }; static_assert(sizeof(CompleteObjectLocator) == 0x14); } inline void* RTDynamicCast(void* a_inptr, std::int32_t a_vfDelta, void* a_srcType, void* a_targetType, std::int32_t a_isReference) { using func_t = decltype(&RTDynamicCast); static REL::Relocation func{ ID::RTDynamicCast }; return func(a_inptr, a_vfDelta, a_srcType, a_targetType, a_isReference); } namespace detail { template using remove_cvpr_t = std::remove_cv_t< std::remove_pointer_t< std::remove_reference_t>>; template struct target_is_valid : std::disjunction< std::is_polymorphic< remove_cvpr_t>, std::is_same< void*, std::remove_cv_t>> {}; template struct types_are_compat : std::false_type {}; template struct types_are_compat : std::is_pointer {}; template struct types_are_compat : std::conjunction< std::is_pointer, std::is_const< std::remove_pointer_t>> {}; template struct types_are_compat : std::conjunction< std::is_pointer, std::is_volatile< std::remove_pointer_t>> {}; template struct types_are_compat : std::conjunction< std::is_pointer, std::is_const< std::remove_pointer_t>, std::is_volatile< std::remove_pointer_t>> {}; template struct implements_rtti : std::false_type {}; template struct implements_rtti< T, std::void_t< decltype(remove_cvpr_t::RTTI)>> : std::true_type {}; template struct cast_is_valid : std::conjunction< types_are_compat< To, From>, target_is_valid< To>, implements_rtti, implements_rtti> {}; template inline constexpr bool cast_is_valid_v = cast_is_valid::value; } template To fallout_cast(From* a_from) // requires(detail::cast_is_valid_v) { REL::Relocation from{ detail::remove_cvpr_t::RTTI }; REL::Relocation to{ detail::remove_cvpr_t::RTTI }; return static_cast( RE::RTDynamicCast( const_cast( static_cast(a_from)), 0, from.get(), to.get(), false)); } }