docs: add plugin setup guide

This commit is contained in:
2026-05-30 18:33:24 +12:00
parent f3db41c402
commit b61043a3fe
1776 changed files with 122386 additions and 2 deletions
@@ -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));
}