Files
Commonwealth-Online-Public/plugin/lib/commonlibf4/include/RE/T/TESForm.h
T
2026-05-30 18:33:24 +12:00

377 lines
25 KiB
C++

#pragma once
#include "RE/B/BSFixedString.h"
#include "RE/B/BSSpinLock.h"
#include "RE/B/BSTHashMap.h"
#include "RE/B/BaseFormComponent.h"
#include "RE/E/ENUM_FORM_ID.h"
#include "RE/F/FORM_ENUM_STRING.h"
#include "RE/T/TESFile.h"
#include "RE/T/TESFileContainer.h"
namespace RE
{
class BGSLoadFormBuffer;
class BGSPreviewTransform;
class BGSSaveFormBuffer;
class BGSSoundTagComponent;
class __declspec(novtable) TESForm :
public BaseFormComponent // 00
{
public:
static constexpr auto RTTI{ RTTI::TESForm };
static constexpr auto VTABLE{ VTABLE::TESForm };
static constexpr auto FORM_ID{ ENUM_FORM_ID::kNONE };
class FormSortFunc
{
public:
std::int32_t operator()(const TESForm* a_arg1, const TESForm* a_arg2)
{
using func_t = decltype(&FormSortFunc::operator());
static REL::Relocation<func_t> func{ ID::TESForm::FormSortFunc };
return func(this, a_arg1, a_arg2);
}
};
static_assert(std::is_empty_v<FormSortFunc>);
// override (BaseFormComponent)
void InitializeDataComponent() override { return; } // 02
void ClearDataComponent() override { SetFormEditorID(""); } // 03
void CopyComponent(BaseFormComponent*) override { return; } // 06
// add
virtual void InitializeData() { return; } // 07
virtual void ClearData() { return; } // 08
virtual bool Load([[maybe_unused]] TESFile* a_file) { return true; } // 09
virtual bool LoadPartial([[maybe_unused]] TESFile* a_file) { return true; } // 0A
virtual bool LoadEdit(TESFile* a_file) { return Load(a_file); } // 0B
virtual TESForm* CreateDuplicateForm(bool a_createEditorID, BSTHashMap<TESForm*, TESForm*>* a_copyMap); // 0C
virtual bool AddChange(std::uint32_t a_changeFlags); // 0D
virtual void RemoveChange(std::uint32_t a_changeFlags); // 0E
virtual bool FindInFileFast([[maybe_unused]] TESFile* a_file) { return false; } // 0F
virtual bool CheckSaveGame([[maybe_unused]] BGSSaveFormBuffer* a_saveGameBuffer) const { return true; } // 10
virtual void SaveGame(BGSSaveFormBuffer* a_saveGameBuffer); // 11
virtual void LoadGame(BGSLoadFormBuffer* a_loadGameBuffer); // 12
virtual void InitLoadGame([[maybe_unused]] BGSLoadFormBuffer* a_loadGameBuffer) { return; } // 13
virtual void FinishLoadGame([[maybe_unused]] BGSLoadFormBuffer* a_loadGameBuffer) { return; } // 14
virtual void Revert([[maybe_unused]] BGSLoadFormBuffer* a_loadGameBuffer) { return; } // 15
virtual void InitItemImpl() { return; } // 16
virtual TESFile* GetRevertFile() const; // 17
virtual TESFile* GetDescriptionOwnerFile() const; // 18
virtual ENUM_FORM_ID GetSavedFormType() const { return *formType; } // 19
virtual void GetFormDetailedString(char* a_dest, std::uint32_t a_size) const; // 1A
virtual bool GetKnown() const { return (formFlags >> 6) & 1; } // 1B
virtual bool GetRandomAnim() const { return (formFlags >> 16) & 1; } // 1C
virtual bool GetPlayable([[maybe_unused]] const TBO_InstanceData* a_data) const { return (formFlags >> 2) & 1; } // 1D
virtual bool IsHeadingMarker() const { return false; } // 1E
virtual bool IsHeadtrackMarker() const { return false; } // 1F
virtual bool GetDangerous() const { return (formFlags >> 17) & 1; } // 20
virtual bool QHasCurrents() const { return (formFlags >> 19) & 1; } // 21
virtual bool GetObstacle() const { return (formFlags >> 25) & 1; } // 22
virtual bool QIsLODLandObject() const { return false; } // 23
virtual bool GetOnLocalMap() const { return (formFlags >> 9) & 1; } // 24
virtual bool GetMustUpdate() const { return (formFlags >> 8) & 1; } // 25
virtual void SetOnLocalMap(bool a_val); // 26
virtual bool GetIgnoredBySandbox() const { return false; } // 27
virtual void SetDelete(bool a_deleted); // 28
virtual void SetAltered(bool a_altered); // 29
virtual void SaveObjectBound() { return; } // 2A
virtual void LoadObjectBound([[maybe_unused]] TESFile* a_file) { return; } // 2B
virtual void SavePreviewTransform(CHUNK_ID) { return; } // 2C
virtual void LoadPreviewTransform([[maybe_unused]] TESFile* a_file) { return; } // 2D
virtual bool IsBoundObject() const { return false; } // 2E
virtual bool IsObject() const { return false; } // 2F
virtual bool IsMagicItem() const { return false; } // 30
virtual bool IsWater() const { return false; } // 31
virtual TESObjectREFR* IsReference() { return nullptr; } // 33
virtual const TESObjectREFR* IsReference() const { return nullptr; } // 32
virtual std::uint32_t GetRefCount() const { return 0; } // 34
virtual const char* GetTextForParsedSubTag(const BSFixedString& a_subTag) const; // 35
virtual void Copy([[maybe_unused]] TESForm* a_copy) { return; } // 36
virtual bool BelongsInGroup(FORM* a_groupFORM, bool a_allowParentGroups, bool a_currentOnly); // 37
virtual void CreateGroupData(FORM* a_outGroupFORM, FORM_GROUP* a_parentGroup); // 38
virtual std::uint32_t GetFormEditorIDLength() const; // 39
virtual const char* GetFormEditorID() const { return ""; } // 3A
virtual bool SetFormEditorID([[maybe_unused]] const char* a_editorID) { return true; } // 3B
virtual bool IsParentForm() { return false; } // 3C
virtual bool IsParentFormTree() { return false; } // 3D
virtual bool IsFormTypeChild([[maybe_unused]] std::uint8_t a_type) { return false; } // 3E
virtual bool LoopingActivate(TESObjectREFR* a_itemActivated, TESObjectREFR* a_actionRef) { return Activate(a_itemActivated, a_actionRef, nullptr, 1); } // 3F
virtual bool Activate([[maybe_unused]] TESObjectREFR* a_itemActivated, [[maybe_unused]] TESObjectREFR* a_actionRef, [[maybe_unused]] TESBoundObject* a_objectToGet, [[maybe_unused]] std::int32_t a_count) { return false; } // 40
virtual void SetFormID(TESFormID a_formID, bool a_updateFile); // 41
virtual const char* GetObjectTypeName() const { return ""; } // 42
virtual bool QAvailableInGame() const { return true; } // 43
virtual BGSMod::Template::Items* GetObjectTemplate() { return nullptr; } // 44
virtual BGSPreviewTransform* GetPreviewTransform() { return nullptr; } // 45
virtual BGSSoundTagComponent* GetSoundTagComponent() { return nullptr; } // 46
virtual std::uint32_t GetFilledSlots() const; // 47
virtual std::uint32_t GetFilledSlotsImpl() const { return static_cast<std::uint32_t>(-1); } // 48
virtual float GetDesirability([[maybe_unused]] TBO_InstanceData* a_instanceData, [[maybe_unused]] const TESForm* a_user) const { return 0.0F; } // 49
static void AddCompileIndex(std::uint32_t& a_id, TESFile* a_file)
{
using func_t = decltype(&TESForm::AddCompileIndex);
static REL::Relocation<func_t> func{ ID::TESForm::AddCompileIndex };
return func(a_id, a_file);
}
[[nodiscard]] static auto GetAllForms()
-> std::pair<
BSTHashMap<std::uint32_t, TESForm*>*,
std::reference_wrapper<BSReadWriteLock>>
{
static REL::Relocation<BSTHashMap<std::uint32_t, TESForm*>**> allForms{ ID::TESForm::AllForms };
static REL::Relocation<BSReadWriteLock*> allFormsMapLock{ ID::TESForm::AllFormsMapLock };
return { *allForms, *allFormsMapLock };
}
[[nodiscard]] static auto GetAllFormsByEditorID()
-> std::pair<
BSTHashMap<BSFixedString, TESForm*>*,
std::reference_wrapper<BSReadWriteLock>>
{
static REL::Relocation<BSTHashMap<BSFixedString, TESForm*>**> allFormsByEditorID{ ID::TESForm::AllFormsByEditorID };
static REL::Relocation<BSReadWriteLock*> allFormsEditorIDMapLock{ ID::TESForm::AllFormsEditorIDMapLock };
return { *allFormsByEditorID, *allFormsEditorIDMapLock };
}
[[nodiscard]] bool GetDelete()
{
return (formFlags & 0x20);
}
[[nodiscard]] TESFile* GetFile(std::int32_t a_index = -1) const
{
using func_t = decltype(&TESForm::GetFile);
static REL::Relocation<func_t> func{ ID::TESForm::GetFile };
return func(this, a_index);
}
[[nodiscard]] static TESForm* GetFormByID(TESFormID a_formID)
{
const auto& [map, lock] = GetAllForms();
BSAutoReadLock l{ lock };
if (map) {
const auto it = map->find(a_formID);
return it != map->end() ? it->second : nullptr;
} else {
return nullptr;
}
}
template <class T>
[[nodiscard]] static T* GetFormByID(TESFormID a_formID)
{
const auto form = GetFormByID(a_formID);
return form ? form->As<T>() : nullptr;
}
[[nodiscard]] static TESForm* GetFormByEditorID(const BSFixedString& a_editorID)
{
const auto& [map, lock] = GetAllFormsByEditorID();
BSAutoReadLock l{ lock };
if (map) {
const auto it = map->find(a_editorID);
return it != map->end() ? it->second : nullptr;
} else {
return nullptr;
}
}
template <class T>
[[nodiscard]] static T* GetFormByEditorID(const BSFixedString& a_editorID)
{
const auto form = GetFormByEditorID(a_editorID);
return form ? form->As<T>() : nullptr;
}
[[nodiscard]] static std::uint32_t GetFormCode(ENUM_FORM_ID a_formType)
{
auto formEnumString = GetFormEnumString();
return formEnumString[std::to_underlying(a_formType)].formCode;
}
[[nodiscard]] std::uint32_t GetFormCode() const
{
return GetFormCode(GetFormType());
}
[[nodiscard]] static std::span<FORM_ENUM_STRING, 159> GetFormEnumString()
{
static REL::Relocation<FORM_ENUM_STRING(*)[159]> functions{ ID::TESForm::GetFormEnumString };
return { *functions };
}
[[nodiscard]] static ENUM_FORM_ID GetFormTypeFromString(const char* a_formTypeString)
{
using func_t = decltype(&TESForm::GetFormTypeFromString);
static REL::Relocation<func_t> func{ ID::TESForm::GetFormTypeFromString };
return func(a_formTypeString);
}
[[nodiscard]] static const char* GetFormTypeString(ENUM_FORM_ID a_formType)
{
auto formEnumString = GetFormEnumString();
return formEnumString[std::to_underlying(a_formType)].formString;
}
[[nodiscard]] const char* GetFormTypeString() const
{
return GetFormTypeString(GetFormType());
}
[[nodiscard]] std::uint32_t GetFormFlags() const noexcept { return formFlags; }
[[nodiscard]] TESFormID GetFormID() const noexcept { return formID; }
[[nodiscard]] ENUM_FORM_ID GetFormType() const noexcept { return *formType; }
[[nodiscard]] TESFormID GetLocalFormID()
{
auto file = GetFile(0);
std::uint32_t fileIndex = file->compileIndex << (3 * 8);
fileIndex += file->smallFileCompileIndex << ((1 * 8) + 4);
return formID & ~fileIndex;
}
[[nodiscard]] bool Is(ENUM_FORM_ID a_type) const noexcept { return GetFormType() == a_type; }
template <class... Args>
[[nodiscard]] bool Is(Args... a_args) const noexcept //
requires(std::same_as<Args, ENUM_FORM_ID> && ...)
{
return (Is(a_args) || ...);
}
template <class T>
[[nodiscard]] bool Is() const noexcept //
requires(std::derived_from<T, TESForm> &&
!std::is_pointer_v<T> &&
!std::is_reference_v<T>)
{
return Is(T::FORM_ID);
}
[[nodiscard]] bool IsActor() const noexcept { return Is(ENUM_FORM_ID::kACHR); }
[[nodiscard]] bool IsAlchemyItem() const noexcept { return Is(ENUM_FORM_ID::kALCH); }
[[nodiscard]] bool IsCreated() const noexcept { return (formID >> (8 * 3)) == 0xFF; }
[[nodiscard]] bool IsDeleted() noexcept { return (formFlags & (1u << 5)) != 0; }
[[nodiscard]] bool IsDisabled() noexcept { return (formFlags & (1u << 11)) != 0; }
[[nodiscard]] bool IsInitialized() const noexcept { return (formFlags & (1u << 3)) != 0; }
[[nodiscard]] bool IsNot(ENUM_FORM_ID a_type) const noexcept { return !Is(a_type); }
template <class... Args>
[[nodiscard]] bool IsNot(Args... a_args) const noexcept //
requires(std::same_as<Args, ENUM_FORM_ID> && ...)
{
return (IsNot(a_args) && ...);
}
[[nodiscard]] bool IsPlayer() const noexcept { return GetFormID() == 0x00000007; }
[[nodiscard]] bool IsPlayerRef() const noexcept { return GetFormID() == 0x00000014; }
[[nodiscard]] bool IsWeapon() const noexcept { return Is(ENUM_FORM_ID::kWEAP); }
void SetInGameFormFlags(std::uint16_t a_flags, bool a_value)
{
if (a_value) {
inGameFormFlags |= a_flags;
AddChange(1);
} else {
inGameFormFlags &= ~a_flags;
AddChange(1);
}
}
void SetTemporary()
{
using func_t = decltype(&TESForm::SetTemporary);
static REL::Relocation<func_t> func{ ID::TESForm::SetTemporary };
return func(this);
}
static TESForm* GetFormByNumericID(std::uint32_t a_searchID)
{
using func_t = decltype(&TESForm::GetFormByNumericID);
static REL::Relocation<func_t> func{ ID::TESForm::GetFormByNumericID };
return func(a_searchID);
}
template <
class T,
class = std::enable_if_t<
std::negation_v<
std::disjunction<
std::is_pointer<T>,
std::is_reference<T>,
std::is_const<T>,
std::is_volatile<T>>>>>
[[nodiscard]] T* As() noexcept;
template <
class T,
class = std::enable_if_t<
std::negation_v<
std::disjunction<
std::is_pointer<T>,
std::is_reference<T>,
std::is_const<T>,
std::is_volatile<T>>>>>
[[nodiscard]] const T* As() const noexcept;
// members
TESFileContainer sourceFiles; // 08
std::uint32_t formFlags; // 10
TESFormID formID; // 14
std::uint16_t inGameFormFlags; // 18
REX::TEnumSet<ENUM_FORM_ID, std::uint8_t> formType; // 1A
};
static_assert(sizeof(TESForm) == 0x20);
}
namespace std
{
[[nodiscard]] inline std::string to_string(RE::ENUM_FORM_ID a_formType)
{
return RE::TESForm::GetFormTypeString(a_formType);
}
}
#ifdef FMT_VERSION
namespace fmt
{
template <>
struct formatter<RE::ENUM_FORM_ID>
{
template <class ParseContext>
constexpr auto parse(ParseContext& a_ctx)
{
return a_ctx.begin();
}
template <class FormatContext>
auto format(const RE::ENUM_FORM_ID& a_formType, FormatContext& a_ctx)
{
return fmt::format_to(a_ctx.out(), "{}", RE::TESForm::GetFormTypeString(a_formType));
}
};
}
#endif
#ifdef __cpp_lib_format
namespace std
{
template <class CharT>
struct formatter<RE::ENUM_FORM_ID, CharT> : std::formatter<std::string_view, CharT>
{
template <class FormatContext>
auto format(RE::ENUM_FORM_ID a_formType, FormatContext& a_ctx)
{
return formatter<std::string_view, CharT>::format(RE::TESForm::GetFormTypeString(a_formType), a_ctx);
}
};
}
#endif