docs: add plugin setup guide
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
#pragma once
|
||||
|
||||
namespace RE
|
||||
{
|
||||
class NiRTTI
|
||||
{
|
||||
public:
|
||||
NiRTTI(const char* a_name, const NiRTTI* a_baseRTTI) :
|
||||
name(a_name), baseRTTI(a_baseRTTI)
|
||||
{}
|
||||
|
||||
[[nodiscard]] constexpr const char* GetName() const noexcept { return name; }
|
||||
[[nodiscard]] constexpr const NiRTTI* GetBaseRTTI() const noexcept { return baseRTTI; }
|
||||
|
||||
[[nodiscard]] constexpr bool IsKindOf(const NiRTTI* a_rtti) const noexcept
|
||||
{
|
||||
for (auto iter = this; iter; iter = iter->GetBaseRTTI()) {
|
||||
if (iter == a_rtti) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// members
|
||||
const char* name; // 00
|
||||
const NiRTTI* baseRTTI; // 08
|
||||
};
|
||||
static_assert(sizeof(NiRTTI) == 0x10);
|
||||
|
||||
namespace Ni_Impl
|
||||
{
|
||||
template <class T>
|
||||
using remove_cvpr_t =
|
||||
std::remove_pointer_t<
|
||||
std::remove_reference_t<
|
||||
std::remove_cv_t<T>>>;
|
||||
|
||||
template <class To, class From>
|
||||
struct types_are_compat :
|
||||
std::false_type
|
||||
{};
|
||||
|
||||
template <class To, class From>
|
||||
struct types_are_compat<To&, From> :
|
||||
std::is_lvalue_reference<
|
||||
std::remove_cv_t<From>>
|
||||
{};
|
||||
|
||||
template <class To, class From>
|
||||
struct types_are_compat<To*, From> :
|
||||
std::is_pointer<
|
||||
std::remove_cv_t<From>>
|
||||
{};
|
||||
|
||||
template <class Base, class Derived>
|
||||
struct is_base_of_no_cvpr :
|
||||
std::is_base_of<
|
||||
remove_cvpr_t<Base>,
|
||||
remove_cvpr_t<Derived>>
|
||||
{};
|
||||
|
||||
template <class T, class Enable = void>
|
||||
struct _has_rtti :
|
||||
std::false_type
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
struct _has_rtti<T, std::void_t<decltype(T::Ni_RTTI)>> :
|
||||
std::true_type
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
struct has_rtti :
|
||||
_has_rtti<remove_cvpr_t<T>>
|
||||
{};
|
||||
|
||||
template <class To, class From>
|
||||
struct cast_is_valid :
|
||||
std::conjunction<
|
||||
types_are_compat<To, From>,
|
||||
is_base_of_no_cvpr<From, To>,
|
||||
has_rtti<To>,
|
||||
has_rtti<From>>
|
||||
{};
|
||||
|
||||
template <class To, class From>
|
||||
inline constexpr bool cast_is_valid_v = cast_is_valid<To, From>::value;
|
||||
}
|
||||
}
|
||||
|
||||
// downcast
|
||||
template <
|
||||
class To,
|
||||
class From,
|
||||
std::enable_if_t<
|
||||
RE::Ni_Impl::cast_is_valid_v<
|
||||
To,
|
||||
const From*>,
|
||||
int> = 0>
|
||||
To netimmerse_cast(const From* a_from)
|
||||
{
|
||||
if (!a_from) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static REL::Relocation<const RE::NiRTTI*> to{ RE::Ni_Impl::remove_cvpr_t<To>::Ni_RTTI };
|
||||
|
||||
const RE::NiRTTI* toRTTI = to.get();
|
||||
const RE::NiRTTI* fromRTTI = a_from->GetRTTI();
|
||||
while (fromRTTI) {
|
||||
if (fromRTTI == toRTTI) {
|
||||
return static_cast<To>(const_cast<From*>(a_from));
|
||||
}
|
||||
fromRTTI = fromRTTI->GetBaseRTTI();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// upcast
|
||||
template <
|
||||
class To,
|
||||
class From,
|
||||
std::enable_if_t<
|
||||
RE::Ni_Impl::cast_is_valid_v<
|
||||
const From*,
|
||||
To>,
|
||||
int> = 0>
|
||||
To netimmerse_cast(const From* a_from)
|
||||
{
|
||||
return static_cast<To>(const_cast<From*>(a_from));
|
||||
}
|
||||
Reference in New Issue
Block a user