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,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;
}