Files
Commonwealth-Online-Public/plugin/lib/commonlibf4/include/RE/RTTI.h
T
2026-05-30 18:33:24 +12:00

219 lines
5.2 KiB
C++

#pragma once
namespace RE
{
namespace msvc
{
class type_info;
}
namespace RTTI
{
template <class T>
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<T*>{ 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<void*>) == 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> typeDescriptor; // 00
std::uint32_t numContainedBases; // 04
PMD pmd; // 08
REX::TEnumSet<Attribute, std::uint32_t> 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<Attribute, std::uint32_t> attributes; // 04
std::uint32_t numBaseClasses; // 08
RVA<BaseClassDescriptor> baseClassArray; // 0C
};
static_assert(sizeof(ClassHierarchyDescriptor) == 0x10);
class CompleteObjectLocator
{
public:
enum class Signature
{
x86 = 0,
x64 = 1
};
// members
REX::TEnumSet<Signature, std::uint32_t> signature; // 00
std::uint32_t offset; // 04
std::uint32_t ctorDispOffset; // 08
RVA<TypeDescriptor> typeDescriptor; // 0C
RVA<ClassHierarchyDescriptor> 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_t> func{ ID::RTDynamicCast };
return func(a_inptr, a_vfDelta, a_srcType, a_targetType, a_isReference);
}
namespace detail
{
template <class T>
using remove_cvpr_t =
std::remove_cv_t<
std::remove_pointer_t<
std::remove_reference_t<T>>>;
template <class T>
struct target_is_valid :
std::disjunction<
std::is_polymorphic<
remove_cvpr_t<T>>,
std::is_same<
void*,
std::remove_cv_t<T>>>
{};
template <class, class>
struct types_are_compat :
std::false_type
{};
template <class To, class From>
struct types_are_compat<To, From*> :
std::is_pointer<To>
{};
template <class To, class From>
struct types_are_compat<To, const From*> :
std::conjunction<
std::is_pointer<To>,
std::is_const<
std::remove_pointer_t<To>>>
{};
template <class To, class From>
struct types_are_compat<To, volatile From*> :
std::conjunction<
std::is_pointer<To>,
std::is_volatile<
std::remove_pointer_t<To>>>
{};
template <class To, class From>
struct types_are_compat<To, const volatile From*> :
std::conjunction<
std::is_pointer<To>,
std::is_const<
std::remove_pointer_t<To>>,
std::is_volatile<
std::remove_pointer_t<To>>>
{};
template <class, class = void>
struct implements_rtti :
std::false_type
{};
template <class T>
struct implements_rtti<
T,
std::void_t<
decltype(remove_cvpr_t<T>::RTTI)>> :
std::true_type
{};
template <class To, class From>
struct cast_is_valid :
std::conjunction<
types_are_compat<
To,
From>,
target_is_valid<
To>,
implements_rtti<To>,
implements_rtti<From>>
{};
template <class To, class From>
inline constexpr bool cast_is_valid_v = cast_is_valid<To, From>::value;
}
template <class To, class From>
To fallout_cast(From* a_from) //
requires(detail::cast_is_valid_v<To, From*>)
{
REL::Relocation<void*> from{ detail::remove_cvpr_t<From>::RTTI };
REL::Relocation<void*> to{ detail::remove_cvpr_t<To>::RTTI };
return static_cast<To>(
RE::RTDynamicCast(
const_cast<void*>(
static_cast<const volatile void*>(a_from)),
0,
from.get(),
to.get(),
false));
}
}