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
+14
View File
@@ -0,0 +1,14 @@
#include "RE/A/Actor.h"
#include "RE/T/TESBoundObject.h"
#include "RE/T/TESNPC.h"
namespace RE
{
TESNPC* Actor::GetNPC() const noexcept
{
const auto objRef = GetObjectReference();
assert(objRef->GetFormType() == ENUM_FORM_ID::kNPC_);
return static_cast<TESNPC*>(objRef);
}
}
@@ -0,0 +1,13 @@
#include "RE/B/BGSCreatedObjectManager.h"
#include "RE/A/AlchemyItem.h"
#include "RE/T/TESForm.h"
namespace RE
{
template class BGSCreatedObjectManager::BSTCreatedObjectSmartPointerPolicy<AlchemyItem>;
static_assert(std::is_empty_v<BGSCreatedObjectManager::BSTCreatedObjectSmartPointerPolicy<AlchemyItem>>);
template class BGSCreatedObjectManager::BSTCreatedObjectSmartPointerPolicy<TESForm>;
static_assert(std::is_empty_v<BGSCreatedObjectManager::BSTCreatedObjectSmartPointerPolicy<TESForm>>);
}
@@ -0,0 +1,13 @@
#include "RE/B/BGSInventoryItem.h"
namespace RE
{
std::uint32_t BGSInventoryItem::GetCount() const noexcept
{
std::uint32_t count = 0;
for (auto iter = stackData.get(); iter; iter = iter->nextStack.get()) {
count += iter->GetCount();
}
return count;
}
}
@@ -0,0 +1,17 @@
#include "RE/B/BGSKeyword.h"
namespace RE
{
namespace detail
{
BGSKeyword* BGSKeywordGetTypedKeywordByIndex(KeywordType a_type, std::uint16_t a_index)
{
return BGSKeyword::GetTypedKeywordByIndex(a_type, a_index);
}
std::uint16_t BGSKeywordGetIndexForTypedKeyword(BGSKeyword* a_keyword, KeywordType a_type)
{
return BGSKeyword::GetIndexForTypedKeyword(a_keyword, a_type);
}
}
}
@@ -0,0 +1,77 @@
#include "RE/B/BGSKeywordForm.h"
namespace RE
{
void BGSKeywordForm::CopyKeywords(const std::vector<BGSKeyword*>& a_copiedData)
{
const auto oldData = keywords;
const auto newSize = a_copiedData.size();
const auto newData = calloc<BGSKeyword*>(newSize);
std::ranges::copy(a_copiedData, newData);
numKeywords = static_cast<std::uint32_t>(newSize);
keywords = newData;
free(oldData);
}
bool BGSKeywordForm::AddKeywords(const std::vector<BGSKeyword*>& a_keywords)
{
std::vector<BGSKeyword*> copiedData{ keywords, keywords + numKeywords };
std::ranges::remove_copy_if(a_keywords, std::back_inserter(copiedData), [&](auto& keyword) {
return std::ranges::find(copiedData, keyword) != copiedData.end();
});
CopyKeywords(copiedData);
return true;
}
bool BGSKeywordForm::ContainsKeywordString(std::string_view a_editorID) const
{
bool result = false;
ForEachKeyword([&](const BGSKeyword* a_keyword) {
if (a_keyword->formEditorID.contains(a_editorID)) {
result = true;
return BSContainer::ForEachResult::kStop;
}
return BSContainer::ForEachResult::kContinue;
});
return result;
}
bool BGSKeywordForm::HasKeywordID(TESFormID a_formID) const
{
bool result = false;
ForEachKeyword([&](const BGSKeyword* a_keyword) {
if (a_keyword->GetFormID() == a_formID) {
result = true;
return BSContainer::ForEachResult::kStop;
}
return BSContainer::ForEachResult::kContinue;
});
return result;
}
bool BGSKeywordForm::HasKeywordString(std::string_view a_editorID) const
{
bool result = false;
ForEachKeyword([&](const BGSKeyword* a_keyword) {
if (a_keyword->formEditorID == a_editorID) {
result = true;
return BSContainer::ForEachResult::kStop;
}
return BSContainer::ForEachResult::kContinue;
});
return result;
}
bool BGSKeywordForm::RemoveKeywords(const std::vector<BGSKeyword*>& a_keywords)
{
std::vector<BGSKeyword*> copiedData{ keywords, keywords + numKeywords };
if (std::erase_if(copiedData, [&](auto& keyword) { return std::ranges::find(a_keywords, keyword) != a_keywords.end(); }) > 0) {
CopyKeywords(copiedData);
return true;
}
return false;
}
}
@@ -0,0 +1,28 @@
#include "RE/B/BGSLocation.h"
namespace RE
{
bool BGSLocation::IsChild(const BGSLocation* a_possibleChild) const
{
if (a_possibleChild) {
for (auto it = a_possibleChild->parentLoc; it; it = it->parentLoc) {
if (this == it) {
return true;
}
}
}
return false;
}
bool BGSLocation::IsParent(const BGSLocation* a_possibleParent) const
{
if (a_possibleParent) {
for (auto it = parentLoc; it; it = it->parentLoc) {
if (a_possibleParent == it) {
return true;
}
}
}
return false;
}
}
@@ -0,0 +1,19 @@
#include "RE/B/BGSObjectInstanceExtra.h"
#include "RE/B/BGSMod.h"
#include "RE/T/TESBoundObject.h"
namespace RE
{
void BGSObjectInstanceExtra::CreateBaseInstanceData(const TESBoundObject& a_object, BSTSmartPointer<TBO_InstanceData>& a_instanceData) const
{
if (values && itemIndex != static_cast<std::uint16_t>(-1)) {
a_object.ApplyMods(a_instanceData, this);
}
}
std::span<BGSMod::ObjectIndexData> BGSObjectInstanceExtra::GetIndexData() const noexcept
{
return values->GetBuffer<BGSMod::ObjectIndexData>(0);
}
}
@@ -0,0 +1,13 @@
#include "RE/B/BSCRC32.h"
namespace RE
{
template struct BSCRC32<std::int8_t>;
template struct BSCRC32<std::uint8_t>;
template struct BSCRC32<std::int16_t>;
template struct BSCRC32<std::uint16_t>;
template struct BSCRC32<std::int32_t>;
template struct BSCRC32<std::uint32_t>;
template struct BSCRC32<std::int64_t>;
template struct BSCRC32<std::uint64_t>;
}
@@ -0,0 +1,24 @@
#include "RE/B/BSFixedString.h"
namespace RE
{
namespace detail
{
template class BSFixedString<char, false>;
static_assert(sizeof(BSFixedString<char, false>) == 0x8);
template class BSFixedString<char, true>;
static_assert(sizeof(BSFixedString<char, true>) == 0x8);
template class BSFixedString<wchar_t, false>;
static_assert(sizeof(BSFixedString<wchar_t, false>) == 0x8);
template class BSFixedString<wchar_t, true>;
static_assert(sizeof(BSFixedString<wchar_t, true>) == 0x8);
}
template struct BSCRC32<BSFixedString>;
template struct BSCRC32<BSFixedStringCS>;
template struct BSCRC32<BSFixedStringW>;
template struct BSCRC32<BSFixedStringWCS>;
}
@@ -0,0 +1,29 @@
#include "RE/B/BSPointerHandle.h"
#include "RE/A/Actor.h"
#include "RE/P/Projectile.h"
#include "RE/T/TESObjectREFR.h"
namespace RE
{
template class BSPointerHandle<Actor>;
static_assert(sizeof(BSPointerHandle<Actor>) == 0x4);
template class BSPointerHandle<Projectile>;
static_assert(sizeof(BSPointerHandle<Projectile>) == 0x4);
template class BSPointerHandle<TESObjectREFR>;
static_assert(sizeof(BSPointerHandle<TESObjectREFR>) == 0x4);
template class BSUntypedPointerHandle<>;
static_assert(sizeof(BSUntypedPointerHandle<>) == 0x4);
template class BSPointerHandleManagerInterface<Actor>;
static_assert(std::is_empty_v<BSPointerHandleManagerInterface<Actor>>);
template class BSPointerHandleManagerInterface<Projectile>;
static_assert(std::is_empty_v<BSPointerHandleManagerInterface<Projectile>>);
template class BSPointerHandleManagerInterface<TESObjectREFR>;
static_assert(std::is_empty_v<BSPointerHandleManagerInterface<TESObjectREFR>>);
}
@@ -0,0 +1,11 @@
#include "RE/B/BSResource.h"
namespace RE::BSResource
{
ErrorCode GetOrCreateStream(const char* a_fileName, BSTSmartPointer<Stream>& a_result, bool a_writable, Location* a_optionalStart)
{
using func_t = decltype(&GetOrCreateStream);
static REL::Relocation<func_t> func{ ID::BSResource::GetOrCreateStream };
return func(a_fileName, a_result, a_writable, a_optionalStart);
}
}
@@ -0,0 +1,58 @@
#include "RE/B/BSResourceNiBinaryStream.h"
namespace RE
{
BSResourceNiBinaryStream::BSResourceNiBinaryStream() :
NiBinaryStream()
{}
BSResourceNiBinaryStream::BSResourceNiBinaryStream(const char* a_file, bool a_writeable, BSResource::Location* a_optionalStart, bool a_fullReadHint) :
NiBinaryStream()
{
using func_t = void (*)(BSResourceNiBinaryStream*, const char*, bool, BSResource::Location*, bool);
static REL::Relocation<func_t> func{ ID::BSResourceNiBinaryStream::Ctor };
func(this, a_file, a_writeable, a_optionalStart, a_fullReadHint);
}
BSResourceNiBinaryStream::~BSResourceNiBinaryStream()
{
using func_t = void (*)(BSResourceNiBinaryStream*);
static REL::Relocation<func_t> func{ ID::BSResourceNiBinaryStream::Dtor };
func(this);
}
void BSResourceNiBinaryStream::Seek(std::ptrdiff_t a_numBytes)
{
using func_t = decltype(&BSResourceNiBinaryStream::Seek);
static REL::Relocation<func_t> func{ ID::BSResourceNiBinaryStream::Seek };
return func(this, a_numBytes);
}
void BSResourceNiBinaryStream::GetBufferInfo(BufferInfo& a_buf)
{
using func_t = decltype(&BSResourceNiBinaryStream::GetBufferInfo);
static REL::Relocation<func_t> func{ ID::BSResourceNiBinaryStream::GetBufferInfo };
return func(this, a_buf);
}
std::size_t BSResourceNiBinaryStream::DoRead(void* a_buf, std::size_t a_toRead)
{
using func_t = decltype(&BSResourceNiBinaryStream::DoRead);
static REL::Relocation<func_t> func{ ID::BSResourceNiBinaryStream::DoRead };
return func(this, a_buf, a_toRead);
}
std::size_t BSResourceNiBinaryStream::DoWrite(const void* a_buf, std::size_t a_toWrite)
{
using func_t = decltype(&BSResourceNiBinaryStream::DoWrite);
static REL::Relocation<func_t> func{ ID::BSResourceNiBinaryStream::DoWrite };
return func(this, a_buf, a_toWrite);
}
[[nodiscard]] BSResourceNiBinaryStream* BSResourceNiBinaryStream::BinaryStreamWithRescan(const char* a_fileName)
{
using func_t = decltype(&BSResourceNiBinaryStream::BinaryStreamWithRescan);
static REL::Relocation<func_t> func{ ID::BSResourceNiBinaryStream::BinaryStreamWithRescan };
return func(a_fileName);
}
}
@@ -0,0 +1,197 @@
#include "RE/B/BSResource_Stream.h"
namespace RE::BSResource
{
Stream::Stream() :
Stream(0, false)
{}
Stream::Stream(std::uint32_t a_totalSize, bool writable) :
StreamBase(a_totalSize, writable)
{}
Stream::Stream(const Stream& a_rhs) :
StreamBase(a_rhs)
{}
Stream::Stream(Stream&& a_rhs) :
StreamBase(std::move(a_rhs))
{}
ErrorCode Stream::DoSetEndOfStream()
{
return ErrorCode::kUnsupported;
}
ErrorCode Stream::DoPrefetchAt([[maybe_unused]] std::uint64_t a_v, [[maybe_unused]] std::uint64_t b_v, [[maybe_unused]] std::uint32_t c_v) const
{
return ErrorCode::kUnsupported;
}
ErrorCode Stream::DoPrefetchAll([[maybe_unused]] std::uint32_t a_v) const
{
return ErrorCode::kUnsupported;
}
ErrorCode Stream::DoStartTaggedPrioritizedRead([[maybe_unused]] void* a_buf,
[[maybe_unused]] std::uint64_t a_v,
[[maybe_unused]] std::uint64_t b_v,
[[maybe_unused]] std::uint32_t c_v,
[[maybe_unused]] std::uint32_t volatile* d_v,
[[maybe_unused]] std::uint32_t& e_v,
[[maybe_unused]] BSEventFlag* event_flag) const
{
return ErrorCode::kUnsupported;
}
bool Stream::DoGetName(BSFixedString& a_dst) const
{
a_dst = "";
return false;
}
ErrorCode Stream::DoCreateAsync(BSTSmartPointer<BSResource::AsyncStream>&) const
{
return ErrorCode::kUnsupported;
}
bool Stream::DoGetIsFromArchive() const
{
return false;
}
ErrorCode Stream::DoWaitTags([[maybe_unused]] volatile std::uint32_t* a_completionTag,
[[maybe_unused]] std::uint32_t a_completionTagWaitValue,
[[maybe_unused]] BSEventFlag* a_eventFlag) const
{
return ErrorCode::kUnsupported;
}
bool Stream::DoQTaggedPrioritizedReadSupported() const
{
return false;
}
ErrorCode Stream::DoCreateOp([[maybe_unused]] BSTSmartPointer<ICacheDriveOp>& p_op, [[maybe_unused]] char const* name) const
{
return ErrorCode::kUnsupported;
}
ErrorCode Stream::DoReadAt([[maybe_unused]] void* a_buffer,
[[maybe_unused]] std::uint64_t a_offset,
[[maybe_unused]] std::uint64_t a_toRead,
[[maybe_unused]] std::uint64_t& a_read) const
{
return ErrorCode::kUnsupported;
}
// interface functions
ErrorCode Stream::Read(void* a_buffer, std::uint64_t a_toRead, std::uint64_t& a_read) const
{
if ((flags & kWritable) != 0) {
return ErrorCode::kUnsupported;
}
return DoRead(a_buffer, a_toRead, a_read);
}
ErrorCode Stream::ReadAt(void* a_buffer, std::uint64_t a_offset, std::uint64_t a_toRead, std::uint64_t& a_read) const
{
if ((flags & kWritable) != 0) {
return ErrorCode::kUnsupported;
}
return DoReadAt(a_buffer, a_offset, a_toRead, a_read);
}
bool Stream::GetName(BSFixedString& a_dst) const
{
return DoGetName(a_dst);
}
ErrorCode Stream::Open(bool buffered, bool readFullHint)
{
uint32_t _flags = kUnk3;
if (buffered) {
_flags |= kBuffered;
}
if (readFullHint) {
_flags |= kBuffered | kFullReadHint;
}
static std::atomic_ref myflags{ flags };
uint32_t old_flags = flags;
while (!myflags.compare_exchange_strong(old_flags, (old_flags | _flags))) {
old_flags = flags;
}
return DoOpen();
}
ErrorCode Stream::Seek(std::uint64_t a_toSeek, SeekMode a_mode, std::uint64_t& a_sought) const
{
return DoSeek(a_toSeek, a_mode, a_sought);
}
ErrorCode Stream::Write(const void* a_buffer, std::uint64_t a_toWrite, std::uint64_t& a_written) const
{
if ((flags & kWritable) != 0) {
return DoWrite(a_buffer, a_toWrite, a_written);
}
return ErrorCode::kUnsupported;
}
ErrorCode Stream::CreateOp(BSTSmartPointer<ICacheDriveOp>& a_opOut, const char* name) const
{
return DoCreateOp(a_opOut, name);
}
ErrorCode Stream::CreateAsync(BSTSmartPointer<AsyncStream>& a_streamOut) const
{
return DoCreateAsync(a_streamOut);
}
ErrorCode Stream::PrefetchAll(std::uint32_t a_v) const
{
if ((flags & kWritable) != 0) {
return ErrorCode::kUnsupported;
}
return DoPrefetchAll(a_v);
}
ErrorCode Stream::PrefetchAt(std::uint64_t a_v, std::uint64_t b_v, std::uint32_t c_v) const
{
if ((flags & kWritable) != 0) {
return ErrorCode::kUnsupported;
}
return DoPrefetchAt(a_v, b_v, c_v);
}
std::uint32_t Stream::QFullReadHint() const
{
return flags & kFullReadHint;
}
bool Stream::QTaggedPrioritizedReadSupported() const
{
return DoQTaggedPrioritizedReadSupported();
}
ErrorCode Stream::StartTaggedPrioritizedRead(void* buf, std::uint64_t a_v, std::uint64_t b_v, std::uint32_t c_V, std::uint32_t volatile* d_v, std::uint32_t& e_v, BSEventFlag* event_flag) const
{
if ((flags & kWritable) != 0) {
return ErrorCode::kUnsupported;
}
return DoStartTaggedPrioritizedRead(buf, a_v, b_v, c_V, d_v, e_v, event_flag);
}
ErrorCode Stream::WaitTags(std::uint32_t volatile* a_v, std::uint32_t b_v, BSEventFlag* event_flag) const
{
return DoWaitTags(a_v, b_v, event_flag);
}
std::uint32_t Stream::QBuffered() const
{
return flags & kBuffered;
}
ErrorCode Stream::SetEndOfStream()
{
return DoSetEndOfStream();
}
}
@@ -0,0 +1,62 @@
#include "RE/B/BSResource_StreamBase.h"
namespace RE
{
namespace BSResource
{
StreamBase::StreamBase() :
totalSize(0),
flags(0)
{}
StreamBase::StreamBase(const StreamBase& a_rhs) :
totalSize(a_rhs.totalSize),
flags(a_rhs.flags & ~kRefCountMask)
{}
StreamBase::StreamBase(StreamBase&& a_rhs) :
totalSize(a_rhs.totalSize),
flags(a_rhs.flags & ~kRefCountMask)
{}
StreamBase::StreamBase(std::uint32_t a_totalSize, bool writable) :
totalSize(a_totalSize),
flags(writable ? 1 : 0)
{}
std::uint64_t StreamBase::DoGetKey() const
{
return 0;
}
ErrorCode StreamBase::DoGetInfo(Info&)
{
return ErrorCode::kUnsupported;
}
std::uint32_t StreamBase::DecRef()
{
REX::TAtomicRef myFlags{ flags };
std::uint32_t expected;
do {
expected = myFlags;
} while (!myFlags.compare_exchange_weak(expected, expected - kRefCountBeg));
return (expected - kRefCountBeg) & kRefCountMask;
}
std::uint32_t StreamBase::IncRef()
{
REX::TAtomicRef myFlags{ flags };
std::uint32_t expected;
do {
expected = myFlags;
} while (!myFlags.compare_exchange_weak(expected, expected + kRefCountBeg));
return (expected - kRefCountBeg) & kRefCountMask;
}
bool StreamBase::IsWritable() const
{
return static_cast<bool>(flags & kWritable);
}
}
}
@@ -0,0 +1,54 @@
#include "RE/B/BSScaleformManager.h"
#include "RE/B/BSSystemFileStreamer.h"
#include "RE/I/IMenu.h"
#include "RE/S/Setting.h"
#include "Scaleform/G/GFx_Loader.h"
#include "Scaleform/G/GFx_MovieDef.h"
#include "Scaleform/P/Ptr.h"
namespace RE
{
bool BSScaleformManager::LoadMovieEx(
IMenu& a_menu,
std::string_view a_filePath,
std::string_view a_menuObjPath,
ScaleModeType a_scaleMode,
float a_backgroundAlpha)
{
static REL::Relocation<SettingT<INISettingCollection>*> fileUncacheOnMenuOpen{ ID::BSScaleformManager::FileUncacheOnMenuOpen };
if (fileUncacheOnMenuOpen && fileUncacheOnMenuOpen->GetBinary()) {
BSSystemFileStreamer::UncacheAll(true);
}
REX::TEnumSet loadConstants{
Scaleform::GFx::Loader::LoadConstants::kKeepBindData,
Scaleform::GFx::Loader::LoadConstants::kWaitFrame1
};
const auto movieDef = Scaleform::Ptr{ loader->CreateMovie(a_filePath.data(), loadConstants.get()) };
if (!movieDef) {
return false;
}
movieDef->Release();
auto& movie = a_menu.uiMovie;
movie.reset(movieDef->CreateInstance(true));
if (!movie) {
return false;
}
movie->Release();
movie->SetViewScaleMode(a_scaleMode);
movie->SetBackgroundAlpha(a_backgroundAlpha);
a_menu.DoAdvanceMovie(0.0);
if (!a_menuObjPath.empty()) {
a_menu.SetMenuCodeObject(*movie, a_menuObjPath);
}
a_menu.RefreshPlatform();
InitMovieViewport(*movie, 1.0F, 1.0F);
a_menu.OnSetSafeRect();
return true;
}
}
@@ -0,0 +1,183 @@
#include "RE/B/BSScript_Array.h"
namespace RE
{
namespace BSScript
{
Array::~Array()
{
}
// Array* Array::ctor(const TypeInfo *type_info, std::uint32_t initial_size)
// {
// using func_t = decltype(&Array::ctor);
// REL::Relocation<func_t> func{ ID::BSScript_Array::ctor };
// return func(this, type_info, initial_size);
// }
[[nodiscard]] auto Array::operator[](size_type a_pos)
-> reference
{
assert(a_pos < size());
return elements[a_pos];
}
[[nodiscard]] auto Array::operator[](size_type a_pos) const
-> const_reference
{
assert(a_pos < size());
return elements[a_pos];
}
[[nodiscard]] auto Array::front()
-> reference
{
return operator[](0);
}
[[nodiscard]] auto Array::front() const
-> const_reference
{
return operator[](0);
}
[[nodiscard]] auto Array::back()
-> reference
{
return operator[](size() - 1);
}
[[nodiscard]] auto Array::back() const
-> const_reference
{
return operator[](size() - 1);
}
[[nodiscard]] auto Array::data() noexcept
-> pointer
{
return size() > 0 ? elements.data() : nullptr;
}
[[nodiscard]] auto Array::data() const noexcept
-> const_pointer
{
return size() > 0 ? elements.data() : nullptr;
}
[[nodiscard]] auto Array::begin() noexcept
-> iterator
{
return elements.begin();
}
[[nodiscard]] auto Array::begin() const noexcept
-> const_iterator
{
return elements.begin();
}
[[nodiscard]] auto Array::cbegin() const noexcept
-> const_iterator
{
return elements.begin();
}
[[nodiscard]] auto Array::end() noexcept
-> iterator
{
return size() > 0 ? elements.end() : nullptr;
}
[[nodiscard]] auto Array::end() const noexcept
-> const_iterator
{
return size() > 0 ? elements.end() : nullptr;
}
[[nodiscard]] auto Array::cend() const noexcept
-> const_iterator
{
return elements.end();
}
[[nodiscard]] auto Array::rbegin() noexcept
-> reverse_iterator
{
return reverse_iterator(end());
}
[[nodiscard]] auto Array::rbegin() const noexcept
-> const_reverse_iterator
{
return const_reverse_iterator(end());
}
[[nodiscard]] auto Array::crbegin() const noexcept
-> const_reverse_iterator
{
return rbegin();
}
[[nodiscard]] auto Array::rend() noexcept
-> reverse_iterator
{
return reverse_iterator(begin());
}
[[nodiscard]] auto Array::rend() const noexcept
-> const_reverse_iterator
{
return const_reverse_iterator(begin());
}
[[nodiscard]] auto Array::crend() const noexcept
-> const_reverse_iterator
{
return rend();
}
[[nodiscard]] bool Array::empty() const noexcept
{
return size() > 0;
}
[[nodiscard]] auto Array::size() const noexcept
-> size_type
{
return elements.size();
}
[[nodiscard]] auto Array::max_size() const noexcept
-> size_type
{
return elements.max_size();
}
[[nodiscard]] TypeInfo& Array::type_info()
{
return elementType;
}
[[nodiscard]] const TypeInfo& Array::type_info() const
{
return elementType;
}
[[nodiscard]] TypeInfo::RawType Array::type() const
{
const REX::TEnumSet typeID = elementType.GetRawType();
switch (*typeID) {
case TypeInfo::RawType::kNone:
case TypeInfo::RawType::kObject:
case TypeInfo::RawType::kString:
case TypeInfo::RawType::kInt:
case TypeInfo::RawType::kFloat:
case TypeInfo::RawType::kBool:
return *(typeID + TypeInfo::RawType::kArrayStart);
default:
return *(typeID + TypeInfo::RawType::kObject);
}
}
}
}
@@ -0,0 +1,18 @@
#include "RE/B/BSScript_Internal_VirtualMachine.h"
#include "RE/G/GameScript.h"
namespace RE
{
namespace BSScript
{
namespace Internal
{
VirtualMachine* VirtualMachine::GetSingleton()
{
auto vm = GameVM::GetSingleton();
return vm ? static_cast<VirtualMachine*>(vm->impl.get()) : nullptr;
}
}
}
}
@@ -0,0 +1,68 @@
#include "RE/B/BSScript_Object.h"
#include "RE/B/BSScript_IObjectHandlePolicy.h"
#include "RE/B/BSScript_Internal_VirtualMachine.h"
namespace RE::BSScript
{
Object::~Object()
{
if (IsConstructed()) {
const std::uint32_t size = type ? type->GetVariableCount() : 0;
for (std::uint32_t i = 0; i < size; ++i) {
variables[i].reset();
}
constructed = false;
initialized = false;
}
auto lock = reinterpret_cast<std::uintptr_t>(lockStructure) & ~static_cast<std::uintptr_t>(1);
if (lock) {
REX::TAtomicRef l{ lock };
--l;
}
}
ObjectTypeInfo* Object::GetTypeInfo()
{
return type.get();
}
const ObjectTypeInfo* Object::GetTypeInfo() const
{
return type.get();
}
void* Object::Resolve(std::uint32_t a_typeID) const
{
auto vm = Internal::VirtualMachine::GetSingleton();
if (!vm) {
return nullptr;
}
IObjectHandlePolicy& policy = vm->GetObjectHandlePolicy();
auto myHandle = GetHandle();
if (policy.HandleIsType(a_typeID, myHandle) && policy.IsHandleObjectAvailable(myHandle)) {
return policy.GetObjectForHandle(a_typeID, myHandle);
} else {
return nullptr;
}
}
Variable* Object::GetProperty(const BSFixedString& a_name)
{
return const_cast<Variable*>(
const_cast<const Object*>(this)->GetProperty(a_name));
}
const Variable* Object::GetProperty(const BSFixedString& a_name) const
{
constexpr auto INVALID = static_cast<std::uint32_t>(-1);
auto idx = INVALID;
for (auto cls = type.get(); cls && idx == INVALID; cls = cls->GetParent()) {
idx = cls->GetPropertyIndex(a_name);
}
return idx != INVALID ? std::addressof(variables[idx]) : nullptr;
}
}
@@ -0,0 +1,187 @@
#include "RE/B/BSScript_ObjectTypeInfo.h"
namespace RE
{
namespace BSScript
{
BSFixedString ObjectTypeInfo::UserFlagInfo::GetUserFlag() const
{
auto sanitizedType = data & ~kSetOnObject;
return *reinterpret_cast<BSFixedString*>(&sanitizedType);
}
auto ObjectTypeInfo::NamedStateInfo::GetFuncIter()
-> Func*
{
return reinterpret_cast<Func*>((std::uintptr_t)this + memberFunctionOffset);
}
auto ObjectTypeInfo::NamedStateInfo::GetFuncIter() const
-> const Func*
{
return reinterpret_cast<const Func*>((std::uintptr_t)this + memberFunctionOffset);
}
ObjectTypeInfo::~ObjectTypeInfo()
{
dtor();
}
const char* ObjectTypeInfo::GetName() const
{
return name.c_str();
}
ObjectTypeInfo* ObjectTypeInfo::GetParent()
{
return parentTypeInfo.get();
}
const ObjectTypeInfo* ObjectTypeInfo::GetParent() const
{
return parentTypeInfo.get();
}
TypeInfo::RawType ObjectTypeInfo::GetRawType() const
{
return TypeInfo::RawType::kObject;
}
auto ObjectTypeInfo::GetUnlinkedFunctionIter()
-> UnlinkedNativeFunction*
{
return reinterpret_cast<UnlinkedNativeFunction*>(data);
}
auto ObjectTypeInfo::GetUnlinkedFunctionIter() const
-> const UnlinkedNativeFunction*
{
return reinterpret_cast<const UnlinkedNativeFunction*>(data);
}
auto ObjectTypeInfo::GetUserFlagIter()
-> UserFlagInfo*
{
return reinterpret_cast<UserFlagInfo*>(data);
}
auto ObjectTypeInfo::GetUserFlagIter() const
-> const UserFlagInfo*
{
return reinterpret_cast<const UserFlagInfo*>(data);
}
std::uint32_t ObjectTypeInfo::GetTotalNumVariables() const
{
auto numVars = GetNumVariables();
for (auto iter = GetParent(); iter; iter = iter->GetParent()) {
numVars += iter->GetNumVariables();
}
return numVars;
}
auto ObjectTypeInfo::GetVariableIter()
-> VariableInfo*
{
return reinterpret_cast<VariableInfo*>(GetUserFlagIter() + GetNumUserFlags());
}
auto ObjectTypeInfo::GetVariableIter() const
-> const VariableInfo*
{
return reinterpret_cast<const VariableInfo*>(GetUserFlagIter() + GetNumUserFlags());
}
auto ObjectTypeInfo::GetInitialValueIter()
-> InitialValueInfo*
{
return reinterpret_cast<InitialValueInfo*>(GetVariableIter() + GetNumVariables());
}
auto ObjectTypeInfo::GetInitialValueIter() const
-> const InitialValueInfo*
{
return reinterpret_cast<const InitialValueInfo*>(GetVariableIter() + GetNumVariables());
}
auto ObjectTypeInfo::GetPropertyIter()
-> PropertyInfo*
{
return reinterpret_cast<PropertyInfo*>(GetInitialValueIter() + GetNumInitalValues());
}
auto ObjectTypeInfo::GetPropertyIter() const
-> const PropertyInfo*
{
return reinterpret_cast<const PropertyInfo*>(GetInitialValueIter() + GetNumInitalValues());
}
auto ObjectTypeInfo::GetGlobalFuncIter()
-> GlobalFuncInfo*
{
return reinterpret_cast<GlobalFuncInfo*>(GetPropertyIter() + GetNumProperties());
}
auto ObjectTypeInfo::GetGlobalFuncIter() const
-> const GlobalFuncInfo*
{
return reinterpret_cast<const GlobalFuncInfo*>(GetPropertyIter() + GetNumProperties());
}
auto ObjectTypeInfo::GetMemberFuncIter()
-> MemberFuncInfo*
{
return reinterpret_cast<MemberFuncInfo*>(GetGlobalFuncIter() + GetNumGlobalFuncs());
}
auto ObjectTypeInfo::GetMemberFuncIter() const
-> const MemberFuncInfo*
{
return reinterpret_cast<const MemberFuncInfo*>(GetGlobalFuncIter() + GetNumGlobalFuncs());
}
auto ObjectTypeInfo::GetNamedStateIter()
-> NamedStateInfo*
{
return reinterpret_cast<NamedStateInfo*>(GetMemberFuncIter() + GetNumMemberFuncs());
}
auto ObjectTypeInfo::GetNamedStateIter() const
-> const NamedStateInfo*
{
return reinterpret_cast<const NamedStateInfo*>(GetMemberFuncIter() + GetNumMemberFuncs());
}
std::uint32_t ObjectTypeInfo::GetPropertyIndex(const BSFixedString& a_name) const
{
const auto props = GetPropertyIter();
if (props) {
for (std::uint32_t i = 0; i < GetNumProperties(); ++i) {
const auto& prop = props[i];
if (prop.name == a_name) {
return prop.info.autoVarIndex;
}
}
}
return static_cast<std::uint32_t>(-1);
}
constexpr bool ObjectTypeInfo::HasPropertyGroups() const
{
return propertyGroups.size();
}
auto ObjectTypeInfo::GetInitialState() const -> const BSFixedString*
{
BSFixedString thing = "hello";
return reinterpret_cast<const BSFixedString*>(GetNamedStateIter() + GetNumNamedStates());
}
void ObjectTypeInfo::dtor()
{
using func_t = decltype(&ObjectTypeInfo::dtor);
REL::Relocation<func_t> func{ ID::BSScript_ObjectTypeInfo::dtor };
return func(this);
}
}
}
@@ -0,0 +1,31 @@
#include "RE/B/BSScript_PackedInstructionStream.h"
namespace RE
{
namespace BSScript
{
namespace ByteCode
{
PackedInstructionStream::PackedInstructionStream() :
numInstructionBits(0),
jumpTargetBitCount(0),
localVariableBitCount(0),
memberVariableBitCount(0),
instructions(nullptr)
{}
PackedInstructionStream::PackedInstructionStream(
void* a_instructions,
std::uint32_t a_numInstrBits,
std::uint16_t a_jumpTargetBitCount,
std::int8_t a_localVariableBitCount,
std::int8_t a_memberVariableBitCount) :
numInstructionBits(a_numInstrBits),
jumpTargetBitCount(a_jumpTargetBitCount),
localVariableBitCount(a_localVariableBitCount),
memberVariableBitCount(a_memberVariableBitCount),
instructions(a_instructions)
{}
}
}
}
@@ -0,0 +1,19 @@
#include "RE/B/BSScript_StackFrame.h"
#include "RE/B/BSScript_Internal_Stack.h"
namespace RE
{
namespace BSScript
{
std::uint32_t StackFrame::GetPageForFrame() const
{
return parent->GetPageForFrame(this);
}
Variable& StackFrame::GetStackFrameVariable(std::uint32_t a_index, std::uint32_t a_pageHint) const
{
return parent->GetStackFrameVariable(this, a_index, a_pageHint);
}
}
}
@@ -0,0 +1,16 @@
#include "RE/B/BSScript_Struct.h"
namespace RE::BSScript
{
Struct::~Struct()
{
if (constructed) {
const std::uint32_t size = type ? type->variables.size() : 0;
for (std::uint32_t i = 0; i < size; ++i) {
variables[i].reset();
}
constructed = false;
}
}
}
@@ -0,0 +1,12 @@
#include "RE/B/BSScript_StructTypeInfo.h"
namespace RE
{
namespace BSScript
{
TypeInfo::RawType StructTypeInfo::GetRawType() const
{
return TypeInfo::RawType::kStruct;
}
}
}
@@ -0,0 +1,42 @@
#include "RE/B/BSScript_TypeInfo.h"
#include "RE/B/BSScript_IComplexType.h"
namespace RE::BSScript
{
auto TypeInfo::GetRawType() const
-> RawType
{
if (IsComplex()) {
const auto complex =
reinterpret_cast<IComplexType*>(
reinterpret_cast<std::uintptr_t>(data.complexTypeInfo) &
~static_cast<std::uintptr_t>(1));
uint32_t rtype = (uint32_t)complex->GetRawType();
if (IsArray()) {
rtype += 10;
}
return (RawType)rtype;
} else {
return *data.rawType;
}
}
IComplexType* TypeInfo::GetComplexType() const
{
return IsComplex() ? reinterpret_cast<IComplexType*>(
reinterpret_cast<std::uintptr_t>(data.complexTypeInfo) &
~static_cast<std::uintptr_t>(1)) :
nullptr;
}
ObjectTypeInfo* TypeInfo::GetObjectTypeInfo() const
{
return IsObject() || IsObjectArray() ? reinterpret_cast<ObjectTypeInfo*>(GetComplexType()) : nullptr;
}
StructTypeInfo* TypeInfo::GetStructTypeInfo() const
{
return IsStruct() || IsStructArray() ? reinterpret_cast<StructTypeInfo*>(GetComplexType()) : nullptr;
}
}
@@ -0,0 +1,139 @@
#include "RE/B/BSScript_Variable.h"
#include "RE/B/BSScript_Array.h"
#include "RE/B/BSScript_Object.h"
#include "RE/B/BSScript_Struct.h"
namespace RE::BSScript
{
Variable& Variable::operator=(BSTSmartPointer<Object> a_object)
{
reset();
if (a_object) {
value.o = std::move(a_object);
varType = value.o->type.get();
} else {
assert(false);
}
assert(is<Object>());
return *this;
}
Variable& Variable::operator=(BSTSmartPointer<Struct> a_struct)
{
reset();
if (a_struct) {
value.t = std::move(a_struct);
varType = value.t->type.get();
} else {
assert(false);
}
assert(is<Struct>());
return *this;
}
Variable& Variable::operator=(BSTSmartPointer<Array> a_array)
{
reset();
if (a_array) {
value.a = std::move(a_array);
varType = value.a->elementType;
varType.SetArray(true);
} else {
assert(false);
}
assert(is<Array>());
return *this;
}
void Variable::reset()
{
switch (varType.GetRawType()) {
case RawType::kObject:
value.o.reset();
break;
case RawType::kString:
value.s.~BSFixedString();
break;
case RawType::kVar:
delete value.v;
break;
case RawType::kStruct:
value.t.reset();
break;
case RawType::kArrayObject:
case RawType::kArrayString:
case RawType::kArrayInt:
case RawType::kArrayFloat:
case RawType::kArrayBool:
case RawType::kArrayVar:
case RawType::kArrayStruct:
value.a.reset();
break;
case RawType::kNone:
case RawType::kInt:
case RawType::kFloat:
case RawType::kBool:
break;
default:
assert(false); // unhandled type
break;
}
varType = RawType::kNone;
value.v = nullptr;
assert(is<std::nullptr_t>());
}
// NOLINTNEXTLINE(misc-no-recursion)
void Variable::copy(const Variable& a_rhs)
{
assert(varType.GetRawType() == RawType::kNone);
assert(value.v == nullptr);
switch (a_rhs.varType.GetRawType()) {
case RawType::kObject:
value.o = a_rhs.value.o;
break;
case RawType::kString:
value.s = a_rhs.value.s;
break;
case RawType::kVar:
if (a_rhs.value.v) {
value.v = new Variable(*a_rhs.value.v);
}
break;
case RawType::kStruct:
value.t = a_rhs.value.t;
break;
case RawType::kArrayObject:
case RawType::kArrayString:
case RawType::kArrayInt:
case RawType::kArrayFloat:
case RawType::kArrayBool:
case RawType::kArrayVar:
case RawType::kArrayStruct:
value.a = a_rhs.value.a;
break;
case RawType::kNone:
break;
case RawType::kInt:
value.u = a_rhs.value.u;
break;
case RawType::kFloat:
value.f = a_rhs.value.f;
break;
case RawType::kBool:
value.b = a_rhs.value.b;
break;
default:
assert(false); // unhandled type
break;
}
varType = a_rhs.varType;
}
}
@@ -0,0 +1,22 @@
#include "RE/B/BSSpinLock.h"
namespace RE
{
template class BSAutoLockReadLockPolicy<BSReadWriteLock>;
static_assert(std::is_empty_v<BSAutoLockReadLockPolicy<BSReadWriteLock>>);
template class BSAutoLockWriteLockPolicy<BSReadWriteLock>;
static_assert(std::is_empty_v<BSAutoLockWriteLockPolicy<BSReadWriteLock>>);
template class BSAutoLockDefaultPolicy<BSSpinLock>;
static_assert(std::is_empty_v<BSAutoLockDefaultPolicy<BSSpinLock>>);
template class BSAutoLock<BSReadWriteLock, BSAutoLockReadLockPolicy>;
static_assert(sizeof(BSAutoLock<BSReadWriteLock, BSAutoLockReadLockPolicy>) == 0x8);
template class BSAutoLock<BSReadWriteLock, BSAutoLockWriteLockPolicy>;
static_assert(sizeof(BSAutoLock<BSReadWriteLock, BSAutoLockWriteLockPolicy>) == 0x8);
template class BSAutoLock<BSSpinLock, BSAutoLockDefaultPolicy>;
static_assert(sizeof(BSAutoLock<BSSpinLock, BSAutoLockDefaultPolicy>) == 0x8);
}
@@ -0,0 +1,16 @@
#include "RE/B/BSSpring_SpringState.h"
namespace RE
{
namespace BSSpring
{
template class SpringState<float>;
static_assert(sizeof(SpringState<float>) == 0xC);
template class SpringState<NiPoint2>;
static_assert(sizeof(SpringState<NiPoint2>) == 0x14);
template class SpringState<NiPoint3>;
static_assert(sizeof(SpringState<NiPoint3>) == 0x1C);
}
}
@@ -0,0 +1,7 @@
#include "RE/B/BSTArray.h"
namespace RE
{
template class BSTAlignedHeapArrayAllocator<0x10>::Allocator;
static_assert(sizeof(BSTAlignedHeapArrayAllocator<0x10>::Allocator) == 0x10);
}
@@ -0,0 +1,16 @@
#include "RE/B/BSTAtomicValue.h"
namespace RE
{
template class BSTAtomicValue<std::int32_t>;
static_assert(sizeof(BSTAtomicValue<std::int32_t>) == 0x4);
template class BSTAtomicValue<std::uint32_t>;
static_assert(sizeof(BSTAtomicValue<std::uint32_t>) == 0x4);
template class BSTAtomicValue<std::int64_t>;
static_assert(sizeof(BSTAtomicValue<std::int64_t>) == 0x8);
template class BSTAtomicValue<std::uint64_t>;
static_assert(sizeof(BSTAtomicValue<std::uint64_t>) == 0x8);
}
@@ -0,0 +1,10 @@
#include "RE/B/BSTDataBuffer.h"
namespace RE
{
template class BSTDataBuffer<1>;
static_assert(sizeof(BSTDataBuffer<1>) == 0x10);
template class BSTDataBuffer<2>;
static_assert(sizeof(BSTDataBuffer<2>) == 0x10);
}
@@ -0,0 +1,7 @@
#include "RE/B/BSTInterpolator.h"
namespace RE
{
template class BSTInterpolator<float, EaseOutInterpolator, GetCurrentPositionFunctor>;
static_assert(sizeof(BSTInterpolator<float, EaseOutInterpolator, GetCurrentPositionFunctor>) == 0x18);
}
@@ -0,0 +1,124 @@
#include "RE/B/BSTPoint.h"
namespace RE
{
template class BSTPoint2<std::int8_t>;
static_assert(sizeof(BSTPoint2<std::int8_t>) == 0x2);
template class BSTPoint2<std::uint8_t>;
static_assert(sizeof(BSTPoint2<std::uint8_t>) == 0x2);
template class BSTPoint2<std::int16_t>;
static_assert(sizeof(BSTPoint2<std::int16_t>) == 0x4);
template class BSTPoint2<std::uint16_t>;
static_assert(sizeof(BSTPoint2<std::uint16_t>) == 0x4);
template class BSTPoint2<std::int32_t>;
static_assert(sizeof(BSTPoint2<std::int32_t>) == 0x8);
template class BSTPoint2<std::uint32_t>;
static_assert(sizeof(BSTPoint2<std::uint32_t>) == 0x8);
template class BSTPoint2<float>;
static_assert(sizeof(BSTPoint2<float>) == 0x8);
template class BSTPoint2<double>;
static_assert(sizeof(BSTPoint2<double>) == 0x10);
template class BSTPoint2Base<std::int8_t>;
static_assert(sizeof(BSTPoint2Base<std::int8_t>) == 0x2);
template class BSTPoint2Base<std::uint8_t>;
static_assert(sizeof(BSTPoint2Base<std::uint8_t>) == 0x2);
template class BSTPoint2Base<std::int16_t>;
static_assert(sizeof(BSTPoint2Base<std::int16_t>) == 0x4);
template class BSTPoint2Base<std::uint16_t>;
static_assert(sizeof(BSTPoint2Base<std::uint16_t>) == 0x4);
template class BSTPoint2Base<std::int32_t>;
static_assert(sizeof(BSTPoint2Base<std::int32_t>) == 0x8);
template class BSTPoint2Base<std::uint32_t>;
static_assert(sizeof(BSTPoint2Base<std::uint32_t>) == 0x8);
template class BSTPoint2Base<float>;
static_assert(sizeof(BSTPoint2Base<float>) == 0x8);
template class BSTPoint2Base<double>;
static_assert(sizeof(BSTPoint2Base<double>) == 0x10);
template class BSTPoint3<std::int8_t>;
static_assert(sizeof(BSTPoint3<std::int8_t>) == 0x3);
template class BSTPoint3<std::uint8_t>;
static_assert(sizeof(BSTPoint3<std::uint8_t>) == 0x3);
template class BSTPoint3<std::int16_t>;
static_assert(sizeof(BSTPoint3<std::int16_t>) == 0x6);
template class BSTPoint3<std::uint16_t>;
static_assert(sizeof(BSTPoint3<std::uint16_t>) == 0x6);
template class BSTPoint3<std::int32_t>;
static_assert(sizeof(BSTPoint3<std::int32_t>) == 0xC);
template class BSTPoint3<std::uint32_t>;
static_assert(sizeof(BSTPoint3<std::uint32_t>) == 0xC);
template class BSTPoint3<float>;
static_assert(sizeof(BSTPoint3<float>) == 0xC);
template class BSTPoint3<double>;
static_assert(sizeof(BSTPoint3<double>) == 0x18);
template class BSTPoint3Base<std::int8_t>;
static_assert(sizeof(BSTPoint3Base<std::int8_t>) == 0x3);
template class BSTPoint3Base<std::uint8_t>;
static_assert(sizeof(BSTPoint3Base<std::uint8_t>) == 0x3);
template class BSTPoint3Base<std::int16_t>;
static_assert(sizeof(BSTPoint3Base<std::int16_t>) == 0x6);
template class BSTPoint3Base<std::uint16_t>;
static_assert(sizeof(BSTPoint3Base<std::uint16_t>) == 0x6);
template class BSTPoint3Base<std::int32_t>;
static_assert(sizeof(BSTPoint3Base<std::int32_t>) == 0xC);
template class BSTPoint3Base<std::uint32_t>;
static_assert(sizeof(BSTPoint3Base<std::uint32_t>) == 0xC);
template class BSTPoint3Base<float>;
static_assert(sizeof(BSTPoint3Base<float>) == 0xC);
template class BSTPoint3Base<double>;
static_assert(sizeof(BSTPoint3Base<double>) == 0x18);
template class BSTPointDefaultOps<std::int8_t>;
static_assert(std::is_empty_v<BSTPointDefaultOps<std::int8_t>>);
template class BSTPointDefaultOps<std::uint8_t>;
static_assert(std::is_empty_v<BSTPointDefaultOps<std::uint8_t>>);
template class BSTPointDefaultOps<std::int16_t>;
static_assert(std::is_empty_v<BSTPointDefaultOps<std::int16_t>>);
template class BSTPointDefaultOps<std::uint16_t>;
static_assert(std::is_empty_v<BSTPointDefaultOps<std::uint16_t>>);
template class BSTPointDefaultOps<std::int32_t>;
static_assert(std::is_empty_v<BSTPointDefaultOps<std::int32_t>>);
template class BSTPointDefaultOps<std::uint32_t>;
static_assert(std::is_empty_v<BSTPointDefaultOps<std::uint32_t>>);
template class BSTPointDefaultOps<float>;
static_assert(std::is_empty_v<BSTPointDefaultOps<float>>);
template class BSTPointDefaultOps<double>;
static_assert(std::is_empty_v<BSTPointDefaultOps<double>>);
}
@@ -0,0 +1,66 @@
#include "RE/B/BSVisit.h"
#include "RE/N/NiAVObject.h"
#include "RE/N/NiNode.h"
namespace RE::BSVisit
{
BSVisitControl TraverseScenegraphGeometries(NiAVObject* a_object, std::function<BSVisitControl(BSGeometry*)> a_func)
{
if (a_object) {
if (auto geom = a_object->IsGeometry())
return a_func(geom);
if (const auto node = a_object->IsNode()) {
for (const auto& child : node->children) {
if (TraverseScenegraphGeometries(child.get(), a_func) == BSVisitControl::kStop) {
return BSVisitControl::kStop;
}
}
}
}
return BSVisitControl::kContinue;
}
BSVisitControl TraverseScenegraphObjects(NiAVObject* a_object, std::function<BSVisitControl(NiAVObject*)> a_func)
{
if (a_object) {
if (a_func(a_object) == BSVisitControl::kStop)
return BSVisitControl::kStop;
if (const auto node = a_object->IsNode()) {
for (const auto& child : node->children) {
if (TraverseScenegraphObjects(child.get(), a_func) == BSVisitControl::kStop) {
return BSVisitControl::kStop;
}
}
}
}
return BSVisitControl::kContinue;
}
BSVisitControl TraverseScenegraphCollision(const NiAVObject* a_object, std::function<BSVisitControl(bhkNPCollisionObject*)> a_func)
{
if (a_object) {
if (const auto collision = a_object->GetCollisionObject()) {
if (const auto collisionNP = collision->IsbhkNPCollisionObject()) {
if (a_func(collisionNP) == BSVisitControl::kStop) {
return BSVisitControl::kStop;
}
}
}
if (const auto node = a_object->IsNode()) {
for (const auto& child : node->children) {
if (TraverseScenegraphCollision(child.get(), a_func) == BSVisitControl::kStop) {
return BSVisitControl::kStop;
}
}
}
}
return BSVisitControl::kContinue;
}
}
@@ -0,0 +1,7 @@
#include "RE/B/ButtonEvent.h"
namespace RE
{
template ButtonEvent* InputEvent::As() noexcept;
template const ButtonEvent* InputEvent::As() const noexcept;
}
@@ -0,0 +1,15 @@
#include "RE/C/Calendar.h"
namespace RE
{
float Calendar::GetHoursPassed() const noexcept
{
const auto days = gameDaysPassed ? gameDaysPassed->GetValue() : 1.0F;
return days * 24.0F;
}
std::uint32_t Calendar::GetMonth() const noexcept
{
return gameMonth ? static_cast<std::uint32_t>(gameMonth->value) : 8;
}
}
@@ -0,0 +1,7 @@
#include "RE/C/CharacterEvent.h"
namespace RE
{
template CharacterEvent* InputEvent::As() noexcept;
template const CharacterEvent* InputEvent::As() const noexcept;
}
@@ -0,0 +1,7 @@
#include "RE/C/CursorMoveEvent.h"
namespace RE
{
template CursorMoveEvent* InputEvent::As() noexcept;
template const CursorMoveEvent* InputEvent::As() const noexcept;
}
@@ -0,0 +1,7 @@
#include "RE/D/DeviceConnectEvent.h"
namespace RE
{
template DeviceConnectEvent* InputEvent::As() noexcept;
template const DeviceConnectEvent* InputEvent::As() const noexcept;
}
@@ -0,0 +1,18 @@
#include "RE/E/ExtraInstanceData.h"
#include "RE/T/TBO_InstanceData.h"
namespace RE
{
ExtraInstanceData::ExtraInstanceData() :
ExtraInstanceData(nullptr, nullptr)
{}
ExtraInstanceData::ExtraInstanceData(const TESBoundObject* a_base, BSTSmartPointer<TBO_InstanceData> a_data) :
BSExtraData(TYPE),
base(a_base),
data(std::move(a_data))
{
REX::EMPLACE_VTABLE(this);
}
}
@@ -0,0 +1 @@
#include "RE/Fallout.h"
@@ -0,0 +1,7 @@
#include "RE/G/GetCurrentPositionFunctor.h"
namespace RE
{
template class GetCurrentPositionFunctor<float>;
static_assert(std::is_empty_v<GetCurrentPositionFunctor<float>>);
}
@@ -0,0 +1,33 @@
#include "RE/H/hkVector4.h"
namespace RE
{
hkVector4f hkVector4f::GetNormalized() const
{
hkVector4f norm = *this;
norm.Normalize();
return norm;
}
float hkVector4f::Length() const
{
return std::sqrt(x * x + y * y + z * z);
}
hkVector4f& hkVector4f::Normalize()
{
float l = Length();
if (l == 0) {
this->x = 0;
this->y = 0;
this->z = 0;
return *this;
}
this->x /= l;
this->y /= l;
this->z /= l;
return *this;
}
}
@@ -0,0 +1,7 @@
#include "RE/I/IDEvent.h"
namespace RE
{
template IDEvent* InputEvent::As<IDEvent>();
template const IDEvent* InputEvent::As<IDEvent>() const;
}
@@ -0,0 +1,9 @@
#include "RE/I/InventoryInterface.h"
namespace RE
{
std::uint32_t BSCRC32<InventoryInterface::Handle>::operator()(InventoryInterface::Handle a_data) const noexcept
{
return BSCRC32<std::uint32_t>()(a_data.id);
}
}
@@ -0,0 +1,7 @@
#include "RE/K/KinectEvent.h"
namespace RE
{
template KinectEvent* InputEvent::As() noexcept;
template const KinectEvent* InputEvent::As() const noexcept;
}
@@ -0,0 +1,24 @@
#include "RE/M/MenuCursor.h"
#include "RE/S/Setting.h"
namespace RE
{
void MenuCursor::ConstrainForPipboy()
{
static REL::Relocation<Setting*> TLX{ ID::MenuCursor::PipboyConstraintTLX };
static REL::Relocation<Setting*> TLY{ ID::MenuCursor::PipboyConstraintTLY };
static REL::Relocation<Setting*> Width{ ID::MenuCursor::PipboyConstraintWidth };
static REL::Relocation<Setting*> Height{ ID::MenuCursor::PipboyConstraintHeight };
SetCursorConstraintsRaw(TLX->GetUInt(), TLY->GetUInt(), Width->GetUInt(), Height->GetUInt());
}
void MenuCursor::ConstrainForPipboyPA()
{
static REL::Relocation<Setting*> TLX{ ID::MenuCursor::PipboyConstraintTLX_PowerArmor };
static REL::Relocation<Setting*> TLY{ ID::MenuCursor::PipboyConstraintTLY_PowerArmor };
static REL::Relocation<Setting*> Width{ ID::MenuCursor::PipboyConstraintWidth_PowerArmor };
static REL::Relocation<Setting*> Height{ ID::MenuCursor::PipboyConstraintHeight_PowerArmor };
SetCursorConstraintsRaw(TLX->GetUInt(), TLY->GetUInt(), Width->GetUInt(), Height->GetUInt());
}
}
@@ -0,0 +1,7 @@
#include "RE/M/MouseMoveEvent.h"
namespace RE
{
template MouseMoveEvent* InputEvent::As() noexcept;
template const MouseMoveEvent* InputEvent::As() const noexcept;
}
@@ -0,0 +1,44 @@
#include "RE/N/NiAVObject.h"
#include "RE/B/BSGeometry.h"
#include "RE/B/BSVisit.h"
#include "RE/N/NiNode.h"
#include "RE/N/NiUpdateData.h"
namespace RE
{
NiAVObject::NiAVObject()
{
REX::EMPLACE_VTABLE(this);
local.MakeIdentity();
world.MakeIdentity();
previousWorld.MakeIdentity();
flags.flags = 0xE;
}
NiAVObject::~NiAVObject() {} // NOLINT(modernize-use-equals-default)
void NiAVObject::CullGeometry(bool a_cull)
{
BSVisit::TraverseScenegraphGeometries(this, [&](BSGeometry* a_geo) -> BSVisitControl {
a_geo->SetAppCulled(a_cull);
return BSVisitControl::kContinue;
});
}
void NiAVObject::CullNode(bool a_cull)
{
BSVisit::TraverseScenegraphObjects(this, [&](NiAVObject* a_object) -> BSVisitControl {
a_object->SetAppCulled(a_cull);
return BSVisitControl::kContinue;
});
}
void NiAVObject::Update(NiUpdateData& a_data)
{
UpdateDownwardPass(a_data, 0);
if (parent && ((a_data.flags & 0x200) == 0)) {
parent->UpdateUpwardPass(a_data);
}
}
}
@@ -0,0 +1,28 @@
#include "RE/N/NiBinaryStream.h"
namespace RE
{
void NiBinaryStream::GetBufferInfo(BufferInfo& a_buf)
{
a_buf.buffer = nullptr;
a_buf.pos = 0;
a_buf.bufferAllocSize = 0;
a_buf.fileSize = 0;
a_buf.bufferReadSize = 0;
a_buf.absCurrentPos = 0;
}
std::size_t NiBinaryStream::binary_read(void* a_buffer, std::size_t a_totalBytes)
{
std::size_t bytesRead = DoRead(a_buffer, a_totalBytes);
absoluteCurrentPos += bytesRead;
return bytesRead;
}
std::size_t NiBinaryStream::binary_write(const void* a_buffer, std::size_t a_totalBytes)
{
std::size_t bytesWritten = DoWrite(a_buffer, a_totalBytes);
absoluteCurrentPos += bytesWritten;
return bytesWritten;
}
}
@@ -0,0 +1,27 @@
#include "RE/N/NiExtraData.h"
namespace RE
{
NiExtraData::NiExtraData()
{
REX::EMPLACE_VTABLE(this);
}
NiExtraData::NiExtraData(const BSFixedString& a_name) :
name(a_name)
{
REX::EMPLACE_VTABLE(this);
}
NiExtraData::~NiExtraData() = default;
const BSFixedString& NiExtraData::GetName() const
{
return name;
}
void NiExtraData::SetName(const BSFixedString& a_name)
{
name = a_name;
}
}
@@ -0,0 +1,58 @@
#include "RE/N/NiExtraDataContainer.h"
#include "RE/N/NiExtraData.h"
namespace RE
{
NiExtraDataContainer::NiExtraDataContainer(const std::uint32_t a_count) :
extra(a_count)
{}
void NiExtraDataContainer::Add(NiExtraData* a_extra)
{
const BSAutoWriteLock l(lock);
extra.push_back(a_extra);
}
NiExtraData* NiExtraDataContainer::FindExtra(const BSFixedString& a_key) const
{
const BSAutoReadLock l(lock);
for (auto& entry : extra)
if (entry->GetName() == a_key)
return entry.get();
return nullptr;
}
std::int32_t NiExtraDataContainer::FindIndex(const BSFixedString& a_key) const
{
const BSAutoReadLock l(lock);
for (auto i = 0u; i < extra.size(); i++)
if (extra[i]->GetName() == a_key)
return i;
return -1;
}
std::uint32_t NiExtraDataContainer::GetSize() const
{
const BSAutoReadLock l(lock);
return extra.size();
}
bool NiExtraDataContainer::RemoveExtra(const BSFixedString& a_key)
{
const BSAutoWriteLock l(lock);
const auto it = std::find_if(extra.begin(), extra.end(), [&](auto& entry) {
return entry->GetName() == a_key;
});
if (it != extra.end()) {
extra.erase(it);
return true;
}
return false;
}
}
@@ -0,0 +1,98 @@
#include "RE/N/NiMatrix3.h"
namespace RE
{
bool NiMatrix3::ToEulerAnglesXYZ(NiPoint3& a_point) const
{
return ToEulerAnglesXYZ(a_point.x, a_point.y, a_point.z);
}
bool NiMatrix3::ToEulerAnglesXYZ(float& a_x, float& a_y, float& a_z) const
{
using func_t = bool (*)(const NiMatrix3*, float&, float&, float&);
static REL::Relocation<func_t> func{ ID::NiMatrix3::ToEulerAnglesXYZ };
return func(this, a_x, a_y, a_z);
}
bool NiMatrix3::ToEulerAnglesXZY(float& a_x, float& a_z, float& a_y) const
{
using func_t = bool (*)(const NiMatrix3*, float&, float&, float&);
static REL::Relocation<func_t> func{ ID::NiMatrix3::ToEulerAnglesXZY };
return func(this, a_x, a_z, a_y);
}
bool NiMatrix3::ToEulerAnglesYXZ(float& a_y, float& a_x, float& a_z) const
{
using func_t = bool (*)(const NiMatrix3*, float&, float&, float&);
static REL::Relocation<func_t> func{ ID::NiMatrix3::ToEulerAnglesYXZ };
return func(this, a_y, a_x, a_z);
}
bool NiMatrix3::ToEulerAnglesYZX(float& a_y, float& a_z, float& a_x) const
{
using func_t = bool (*)(const NiMatrix3*, float&, float&, float&);
static REL::Relocation<func_t> func{ ID::NiMatrix3::ToEulerAnglesYZX };
return func(this, a_y, a_z, a_x);
}
bool NiMatrix3::ToEulerAnglesZYX(float& a_z, float& a_y, float& a_x) const
{
using func_t = bool (*)(const NiMatrix3*, float&, float&, float&);
static REL::Relocation<func_t> func{ ID::NiMatrix3::ToEulerAnglesZYX };
return func(this, a_z, a_y, a_x);
}
bool NiMatrix3::ToEulerAnglesZXY(float& a_z, float& a_x, float& a_y) const
{
using func_t = bool (*)(const NiMatrix3*, float&, float&, float&);
static REL::Relocation<func_t> func{ ID::NiMatrix3::ToEulerAnglesZXY };
return func(this, a_z, a_x, a_y);
}
void NiMatrix3::FromEulerAnglesXYZ(const NiPoint3& a_point)
{
FromEulerAnglesXYZ(a_point.x, a_point.y, a_point.z);
}
void NiMatrix3::FromEulerAnglesXYZ(float a_x, float a_y, float a_z)
{
using func_t = void (*)(NiMatrix3*, float, float, float);
static REL::Relocation<func_t> func{ ID::NiMatrix3::FromEulerAnglesXYZ };
return func(this, a_x, a_y, a_z);
}
void NiMatrix3::FromEulerAnglesXZY(float a_x, float a_z, float a_y)
{
using func_t = void (*)(NiMatrix3*, float, float, float);
static REL::Relocation<func_t> func{ ID::NiMatrix3::FromEulerAnglesXZY };
return func(this, a_x, a_z, a_y);
}
void NiMatrix3::FromEulerAnglesYXZ(float a_y, float a_x, float a_z)
{
using func_t = void (*)(NiMatrix3*, float, float, float);
static REL::Relocation<func_t> func{ ID::NiMatrix3::FromEulerAnglesYXZ };
return func(this, a_y, a_x, a_z);
}
void NiMatrix3::FromEulerAnglesYZX(float a_y, float a_z, float a_x)
{
using func_t = void (*)(NiMatrix3*, float, float, float);
static REL::Relocation<func_t> func{ ID::NiMatrix3::FromEulerAnglesYZX };
return func(this, a_y, a_z, a_x);
}
void NiMatrix3::FromEulerAnglesZYX(float a_z, float a_y, float a_x)
{
using func_t = void (*)(NiMatrix3*, float, float, float);
static REL::Relocation<func_t> func{ ID::NiMatrix3::FromEulerAnglesZYX };
return func(this, a_z, a_y, a_x);
}
void NiMatrix3::FromEulerAnglesZXY(float a_z, float a_x, float a_y)
{
using func_t = void (*)(NiMatrix3*, float, float, float);
static REL::Relocation<func_t> func{ ID::NiMatrix3::FromEulerAnglesZXY };
return func(this, a_z, a_x, a_y);
}
}
@@ -0,0 +1,78 @@
#include "RE/N/NiObjectNET.h"
#include "RE/N/NiExtraData.h"
#include "RE/N/NiRTTI.h"
#include "RE/N/NiTimeController.h"
namespace RE
{
NiObjectNET::NiObjectNET()
{
REX::EMPLACE_VTABLE(this);
}
NiObjectNET::~NiObjectNET() = default;
bool NiObjectNET::AddExtraData(const BSFixedString& a_key, NiExtraData* a_extra)
{
if (a_key.empty())
return false;
if (!a_extra)
return false;
if (!a_extra->GetName().empty())
a_extra->SetName(a_key);
else if (a_key != a_extra->GetName())
return false;
return InsertExtraData(a_extra);
}
bool NiObjectNET::AddExtraData(NiExtraData* a_extra)
{
if (!a_extra)
return false;
const auto& extraName = a_extra->GetName();
if (extraName.empty()) {
// TODO: Game handles nameless ExtraData by using the rtti name and a suffix?
assert(false);
}
return InsertExtraData(a_extra);
}
NiExtraData* NiObjectNET::GetExtraData(const BSFixedString& a_key) const
{
return extra ? extra->FindExtra(a_key) : nullptr;
}
std::uint16_t NiObjectNET::GetExtraDataSize() const
{
return extra ? static_cast<std::uint16_t>(extra->GetSize()) : 0;
}
bool NiObjectNET::HasExtraData(const BSFixedString& a_key) const
{
return extra ? extra->FindExtra(a_key) : false;
}
bool NiObjectNET::InsertExtraData(NiExtraData* a_extra)
{
if (extra) {
extra->Add(a_extra);
return true;
}
return false;
}
bool NiObjectNET::RemoveExtraData(const BSFixedString& a_key)
{
if (a_key.empty())
return false;
return extra && extra->RemoveExtra(a_key);
}
}
@@ -0,0 +1,45 @@
#include "RE/N/NiPoint3.h"
namespace RE
{
float NiPoint3::GetDistance(const NiPoint3& a_point) const noexcept
{
// std math functions are not constexpr yet
return std::sqrtf(GetSquaredDistance(a_point));
}
float NiPoint3::GetZAngleFromVector() const
{
using func_t = decltype(&NiPoint3::GetZAngleFromVector);
static REL::Relocation<func_t> func{ ID::NiPoint3::GetZAngleFromVector };
return func(this);
}
float NiPoint3::Length() const noexcept
{
return std::sqrtf(x * x + y * y + z * z);
}
NiPoint3 NiPoint3::UnitCross(const NiPoint3& a_point) const noexcept
{
auto cross = Cross(a_point);
cross.Unitize();
return cross;
}
float NiPoint3::Unitize() noexcept
{
auto length = Length();
if (length == 1.f) {
return length;
} else if (length > FLT_EPSILON) {
operator/=(length);
} else {
x = 0.0;
y = 0.0;
z = 0.0;
length = 0.0;
}
return length;
}
}
@@ -0,0 +1,13 @@
#include "RE/N/NiRect.h"
namespace RE
{
template class NiRect<float>;
static_assert(sizeof(NiRect<float>) == 0x10);
template class NiRect<std::int32_t>;
static_assert(sizeof(NiRect<std::int32_t>) == 0x10);
template class NiRect<std::uint32_t>;
static_assert(sizeof(NiRect<std::uint32_t>) == 0x10);
}
@@ -0,0 +1,53 @@
#include "RE/P/PlayerCharacter.h"
#include "RE/B/BGSEntryPoint.h"
#include "RE/C/Calendar.h"
#include "RE/S/Setting.h"
namespace RE
{
void PlayerCharacter::LockOutOfTerminal(ObjectRefHandle a_handle)
{
float TerminalLockoutTime{ 0.0f };
if (auto INISettingCollection = RE::INISettingCollection::GetSingleton()) {
if (auto setting = INISettingCollection->GetSetting("iTerminalLockoutTime:Gameplay")) {
TerminalLockoutTime = static_cast<float>(setting->GetInt());
}
}
BGSEntryPoint::HandleEntryPoint(RE::BGSEntryPoint::ENTRY_POINT::kModTerminalLockoutTime, this, &TerminalLockoutTime);
if (auto Calendar = RE::Calendar::GetSingleton()) {
auto TimeScale = Calendar->timeScale ? Calendar->timeScale->GetValue() : 0.0f;
TerminalLockoutTime *= TimeScale * 0.00027799999f;
TerminalLockoutTime += Calendar->GetHoursPassed();
}
lockedTerminals.emplace_back(a_handle, TerminalLockoutTime);
}
bool PlayerCharacter::IsLockedOutOfTerminal(ObjectRefHandle a_handle)
{
float HoursPassed{ 24.0f };
if (auto Calendar = RE::Calendar::GetSingleton()) {
HoursPassed = Calendar->GetHoursPassed();
}
for (std::uint32_t i = 0; i < lockedTerminals.size();) {
auto& iter = lockedTerminals.at(i);
if (HoursPassed <= iter.second) {
i++;
continue;
}
lockedTerminals.erase(&iter);
}
for (auto& iter : lockedTerminals) {
if (iter.first == a_handle) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,10 @@
#include "RE/S/SCRIPT_FUNCTION.h"
namespace RE
{
void SCRIPT_FUNCTION::SetParameters()
{
paramCount = 0;
parameters = nullptr;
}
}
@@ -0,0 +1,28 @@
#include "RE/S/Setting.h"
namespace RE
{
template class SettingT<GameSettingCollection>;
static_assert(sizeof(SettingT<GameSettingCollection>) == 0x18);
template class SettingT<INIPrefSettingCollection>;
static_assert(sizeof(SettingT<INIPrefSettingCollection>) == 0x18);
template class SettingT<INISettingCollection>;
static_assert(sizeof(SettingT<INISettingCollection>) == 0x18);
template class SettingT<LipSynchroSettingCollection>;
static_assert(sizeof(SettingT<LipSynchroSettingCollection>) == 0x18);
template class SettingT<RegSettingCollection>;
static_assert(sizeof(SettingT<RegSettingCollection>) == 0x18);
template class SettingCollection<Setting>;
static_assert(sizeof(SettingCollection<Setting>) == 0x118);
template class SettingCollectionList<Setting>;
static_assert(sizeof(SettingCollectionList<Setting>) == 0x128);
template class SettingCollectionMap<Setting>;
static_assert(sizeof(SettingCollectionMap<Setting>) == 0x138);
}
+92
View File
@@ -0,0 +1,92 @@
#include "RE/T/TES.h"
#include "RE/E/EXTERIOR_DATA.h"
#include "RE/G/GridCellArray.h"
#include "RE/T/TESObjectCELL.h"
#include "RE/T/TESObjectREFR.h"
#include "RE/T/TESWorldSpace.h"
namespace RE
{
void TES::ForEachReference(std::function<BSContainer::ForEachResult(TESObjectREFR* a_ref)> a_callback)
{
if (interiorCell) {
interiorCell->ForEachReference([&](TESObjectREFR* a_ref) {
return a_callback(a_ref);
});
} else {
if (const auto gridLength = gridCells ? gridCells->dimension : 0; gridLength > 0) {
std::uint32_t x = 0;
do {
std::uint32_t y = 0;
do {
if (const auto cell = gridCells->GetCell(x, y); cell && cell->IsAttached()) {
cell->ForEachReference([&](TESObjectREFR* a_ref) {
return a_callback(a_ref);
});
}
++y;
} while (y < gridLength);
++x;
} while (x < gridLength);
}
}
if (const auto skyCell = worldSpace ? worldSpace->GetSkyCell() : nullptr; skyCell) {
skyCell->ForEachReference([&](TESObjectREFR* a_ref) {
return a_callback(a_ref);
});
}
}
void TES::ForEachReferenceInRange(const NiPoint3& a_origin, const float a_radius, std::function<BSContainer::ForEachResult(TESObjectREFR* a_ref)> a_callback)
{
if (a_radius > 0.0f) {
if (interiorCell) {
interiorCell->ForEachReferenceInRange(a_origin, a_radius, [&](TESObjectREFR* a_ref) {
return a_callback(a_ref);
});
} else {
if (const auto gridLength = gridCells ? gridCells->dimension : 0; gridLength > 0) {
const float yPlus = a_origin.y + a_radius;
const float yMinus = a_origin.y - a_radius;
const float xPlus = a_origin.x + a_radius;
const float xMinus = a_origin.x - a_radius;
std::uint32_t x = 0;
do {
std::uint32_t y = 0;
do {
if (const auto cell = gridCells->GetCell(x, y); cell && cell->IsAttached()) {
if (const auto cellCoords = cell->GetCoordinates(); cellCoords) {
const NiPoint2 worldPos{ cellCoords->worldX, cellCoords->worldY };
if (worldPos.x < xPlus && (worldPos.x + 4096.0f) > xMinus && worldPos.y < yPlus && (worldPos.y + 4096.0f) > yMinus) {
cell->ForEachReferenceInRange(a_origin, a_radius, [&](TESObjectREFR* a_ref) {
return a_callback(a_ref);
});
}
}
}
++y;
} while (y < gridLength);
++x;
} while (x < gridLength);
}
}
if (const auto skyCell = worldSpace ? worldSpace->GetSkyCell() : nullptr; skyCell) {
skyCell->ForEachReferenceInRange(a_origin, a_radius, [&](TESObjectREFR* a_ref) {
return a_callback(a_ref);
});
}
} else {
ForEachReference([&](TESObjectREFR* a_ref) {
return a_callback(a_ref);
});
}
}
void TES::ForEachReferenceInRange(const TESObjectREFR* a_ref, const float a_radius, std::function<BSContainer::ForEachResult(TESObjectREFR* a_ref)> a_callback)
{
ForEachReferenceInRange(a_ref->GetPosition(), a_radius, a_callback);
}
}
@@ -0,0 +1,52 @@
#include "RE/T/TESFullName.h"
#include "RE/C/CHANGE_TYPES.h"
#include "RE/T/TESActorBase.h"
#include "RE/T/TESForm.h"
#include "RE/T/TESFormUtil.h"
#include "RE/T/TESObjectCELL.h"
namespace RE
{
std::string_view TESFullName::GetFullName(const TESForm& a_form, bool a_strict)
{
if (const auto fullName = a_form.As<TESFullName>()) {
const auto name = fullName->GetFullName();
return name ? name : ""sv;
} else {
if (a_strict) {
switch (a_form.GetFormType()) {
case ENUM_FORM_ID::kKYWD: // BGSKeyword
case ENUM_FORM_ID::kLCRT: // BGSLocationRefType
case ENUM_FORM_ID::kAACT: // BGSAction
case ENUM_FORM_ID::kLIGH: // TESObjectLIGH
case ENUM_FORM_ID::kSTAT: // TESObjectSTAT
case ENUM_FORM_ID::kSCOL: // BGSStaticCollection
case ENUM_FORM_ID::kMSTT: // BGSMovableStatic
case ENUM_FORM_ID::kFLST: // BGSListForm
break;
default:
return ""sv;
}
}
const auto& map = GetSparseFullNameMap();
const auto it = map.find(std::addressof(a_form));
return it != map.end() ? it->second : ""sv;
}
}
void TESFullName::SetFullName(TESForm& a_form, std::string_view a_fullName)
{
if (const auto full = a_form.As<TESFullName>()) {
full->fullName = a_fullName;
if (const auto actor = a_form.As<TESActorBase>()) {
actor->AddChange(CHANGE_TYPES::kActorBaseFullName);
} else if (const auto cell = a_form.As<TESObjectCELL>()) {
cell->AddChange(CHANGE_TYPES::kCellFullname);
} else {
a_form.AddChange(CHANGE_TYPES::kBaseObjectFullName);
}
}
}
}
@@ -0,0 +1,76 @@
#include "RE/T/TESNPC.h"
#include "RE/P/PlayerCharacter.h"
#include "RE/T/TESRace.h"
namespace RE
{
void TESNPC::CopyPerkRankArray(const std::vector<PerkRankData>& a_copiedData)
{
const auto oldData = perks;
const auto newSize = a_copiedData.size();
const auto newData = calloc<PerkRankData>(newSize);
std::ranges::copy(a_copiedData, newData);
perkCount = static_cast<std::uint32_t>(newSize);
perks = newData;
free(oldData);
}
bool TESNPC::AddPerks(const std::vector<BGSPerk*>& a_perks, std::int8_t a_rank)
{
std::vector<PerkRankData> copiedData{ perks, perks + perkCount };
std::ranges::for_each(a_perks, [&](auto& perk) {
if (!GetPerkIndex(perk)) {
const auto newPerk = new PerkRankData(perk, a_rank);
copiedData.push_back(*newPerk);
}
});
CopyPerkRankArray(copiedData);
return true;
}
bool TESNPC::ContainsKeyword(std::string_view a_editorID) const
{
if (ContainsKeywordString(a_editorID)) {
return true;
}
if (const auto npcRace = GetFormRace(); npcRace && npcRace->ContainsKeywordString(a_editorID)) {
return true;
}
return false;
}
bool TESNPC::HasApplicableKeywordString(std::string_view a_editorID) const
{
if (HasKeywordString(a_editorID)) {
return true;
}
if (const auto npcRace = GetFormRace(); npcRace && npcRace->HasKeywordString(a_editorID)) {
return true;
}
return false;
}
bool TESNPC::RemovePerks(const std::vector<BGSPerk*>& a_perks)
{
std::vector<PerkRankData> copiedData{ perks, perks + perkCount };
if (std::erase_if(copiedData, [&](auto& perkRank) { return std::ranges::find(a_perks, perkRank.perk) != a_perks.end(); }) > 0) {
CopyPerkRankArray(copiedData);
return true;
}
return false;
}
bool TESNPC::UsingAlternateHeadPartList() const
{
if (const auto player = PlayerCharacter::GetSingleton(); IsPlayer() && player) {
const auto& map = GetAlternateHeadPartListMap();
return player->charGenRace && player->charGenRace != formRace && map.contains(player->GetNPC());
} else {
return originalRace && originalRace != formRace;
}
}
}
@@ -0,0 +1,52 @@
#include "RE/T/TESObjectCELL.h"
#include "RE/E/EXTERIOR_DATA.h"
#include "RE/E/ExtraCellWaterType.h"
#include "RE/E/ExtraDataList.h"
#include "RE/T/TESObjectREFR.h"
#include "RE/T/TESWorldSpace.h"
namespace RE
{
void TESObjectCELL::ForEachReference(std::function<BSContainer::ForEachResult(TESObjectREFR*)> a_callback)
{
const BSAutoLock locker(spinLock);
for (const auto& ref : references) {
if (ref && a_callback(ref.get()) == BSContainer::ForEachResult::kStop) {
break;
}
}
}
void TESObjectCELL::ForEachReferenceInRange(const NiPoint3& a_origin, float a_radius, std::function<BSContainer::ForEachResult(TESObjectREFR*)> a_callback)
{
const float squaredRadius = a_radius * a_radius;
ForEachReference([&](TESObjectREFR* a_ref) {
const auto distance = a_origin.GetSquaredDistance(a_ref->GetPosition());
if (distance <= squaredRadius)
return a_callback(a_ref);
return BSContainer::ForEachResult::kContinue;
});
}
EXTERIOR_DATA* TESObjectCELL::GetCoordinates() const
{
return IsExterior() ? cellData.exterior : nullptr;
}
TESWaterForm* TESObjectCELL::GetWaterType() const noexcept
{
const auto xWater = extraList ? extraList->GetByType<ExtraCellWaterType>() : nullptr;
auto water = xWater ? xWater->water : nullptr;
if (!water) {
water = IsExterior() && worldSpace ? worldSpace->GetWaterType() : nullptr;
if (!water) {
static REL::Relocation<TESWaterForm**> defaultWater{ ID::TESObjectCELL::DefaultWater };
water = *defaultWater;
}
}
return water;
}
}
@@ -0,0 +1,15 @@
#include "RE/T/TESValueForm.h"
#include "RE/C/CHANGE_TYPES.h"
#include "RE/T/TESForm.h"
namespace RE
{
void TESValueForm::SetFormValue(TESForm& a_form, std::int32_t a_value)
{
if (const auto val = a_form.As<TESValueForm>()) {
val->value = a_value;
a_form.AddChange(CHANGE_TYPES::kBaseObjectValue);
}
}
}
@@ -0,0 +1,7 @@
#include "RE/T/ThumbstickEvent.h"
namespace RE
{
template ThumbstickEvent* InputEvent::As() noexcept;
template const ThumbstickEvent* InputEvent::As() const noexcept;
}
@@ -0,0 +1,12 @@
#include "RE/W/WorkbenchMenuBase.h"
#include "RE/P/PlayerCharacter.h"
namespace RE
{
WorkbenchMenuBase::InitParams::InitParams()
{
workbenchFurniture.reset();
inventorySource = RE::PlayerCharacter::GetPlayerHandle();
}
}