Skip to content

Commit dcb2556

Browse files
committed
feat: add NiRTTI
1 parent 534ac8c commit dcb2556

File tree

3 files changed

+498
-0
lines changed

3 files changed

+498
-0
lines changed

include/RE/N/NiRTTI.h

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#pragma once
2+
3+
namespace RE
4+
{
5+
struct NiRTTI
6+
{
7+
public:
8+
[[nodiscard]] constexpr const char* GetName() const noexcept { return name; }
9+
[[nodiscard]] constexpr const NiRTTI* GetBaseRTTI() const noexcept { return baseRTTI; }
10+
11+
[[nodiscard]] constexpr bool IsKindOf(const NiRTTI* a_rtti) const noexcept
12+
{
13+
for (auto iter = this; iter; iter = iter->GetBaseRTTI()) {
14+
if (iter == a_rtti) {
15+
return true;
16+
}
17+
}
18+
return false;
19+
}
20+
21+
// members
22+
const char* name; // 00
23+
NiRTTI* baseRTTI; // 08
24+
};
25+
static_assert(sizeof(NiRTTI) == 0x10);
26+
27+
namespace Ni_Impl
28+
{
29+
template <class T>
30+
using remove_cvpr_t =
31+
std::remove_pointer_t<
32+
std::remove_reference_t<
33+
std::remove_cv_t<T>>>;
34+
35+
template <class To, class From>
36+
struct types_are_compat :
37+
std::false_type
38+
{};
39+
40+
template <class To, class From>
41+
struct types_are_compat<To&, From> :
42+
std::is_lvalue_reference<
43+
std::remove_cv_t<From>>
44+
{};
45+
46+
template <class To, class From>
47+
struct types_are_compat<To*, From> :
48+
std::is_pointer<
49+
std::remove_cv_t<From>>
50+
{};
51+
52+
template <class Base, class Derived>
53+
struct is_base_of_no_cvpr :
54+
std::is_base_of<
55+
remove_cvpr_t<Base>,
56+
remove_cvpr_t<Derived>>
57+
{};
58+
59+
template <class T, class Enable = void>
60+
struct _has_rtti :
61+
std::false_type
62+
{};
63+
64+
template <class T>
65+
struct _has_rtti<T, std::void_t<decltype(T::Ni_RTTI)>> :
66+
std::true_type
67+
{};
68+
69+
template <class T>
70+
struct has_rtti :
71+
_has_rtti<remove_cvpr_t<T>>
72+
{};
73+
74+
template <class To, class From>
75+
struct cast_is_valid :
76+
std::conjunction<
77+
types_are_compat<To, From>,
78+
is_base_of_no_cvpr<From, To>,
79+
has_rtti<To>,
80+
has_rtti<From>>
81+
{};
82+
83+
template <class To, class From>
84+
inline constexpr bool cast_is_valid_v = cast_is_valid<To, From>::value;
85+
}
86+
}
87+
88+
// downcast
89+
template <
90+
class To,
91+
class From,
92+
std::enable_if_t<
93+
RE::Ni_Impl::cast_is_valid_v<
94+
To,
95+
const From*>,
96+
int> = 0>
97+
To netimmerse_cast(const From* a_from)
98+
{
99+
if (!a_from) {
100+
return nullptr;
101+
}
102+
103+
static REL::Relocation<const RE::NiRTTI*> to{ RE::Ni_Impl::remove_cvpr_t<To>::Ni_RTTI };
104+
105+
const RE::NiRTTI* toRTTI = to.get();
106+
const RE::NiRTTI* fromRTTI = a_from->GetRTTI();
107+
while (fromRTTI) {
108+
if (fromRTTI == toRTTI) {
109+
return static_cast<To>(const_cast<From*>(a_from));
110+
}
111+
fromRTTI = fromRTTI->GetBaseRTTI();
112+
}
113+
114+
return nullptr;
115+
}
116+
117+
// upcast
118+
template <
119+
class To,
120+
class From,
121+
std::enable_if_t<
122+
RE::Ni_Impl::cast_is_valid_v<
123+
const From*,
124+
To>,
125+
int> = 0>
126+
To netimmerse_cast(const From* a_from)
127+
{
128+
return static_cast<To>(const_cast<From*>(a_from));
129+
}

0 commit comments

Comments
 (0)