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,42 @@
#pragma once
namespace RE
{
enum class WARNING_TYPES : std::int32_t
{
kDefault = 0x0,
kSystem = 0x1,
kCombat = 0x2,
kAnimation = 0x3,
kAI = 0x4,
kScripts = 0x5,
kSaveLoad = 0x6,
kDialogue = 0x7,
kQuests = 0x8,
kPackages = 0x9,
kEditor = 0xA,
kModels = 0xB,
kTextures = 0xC,
kPlugins = 0xD,
kMasterFile = 0xE,
kForms = 0xF,
kMagic = 0x10,
kShaders = 0x11,
kRendering = 0x12,
kPathfinding = 0x13,
kMenus = 0x14,
kAudio = 0x15,
kCells = 0x16,
kHavok = 0x17,
kFaceGen = 0x18,
kWater = 0x19,
kInGameMessage = 0x1A,
kMemory = 0x1B,
kPerformance = 0x1C,
kLootJoy = 0x1D,
kVATS = 0x1E,
kDismember = 0x1F,
kCompanion = 0x20,
kWorkshop = 0x21,
};
}
@@ -0,0 +1,12 @@
#pragma once
namespace RE
{
enum class WEAPONHITBEHAVIOR : std::int32_t
{
kNormal = 0x0,
kDismemberOnly = 0x1,
kExplodeOnly = 0x2,
kNoDismemberOrExplode = 0x3
};
}
@@ -0,0 +1,11 @@
#pragma once
namespace RE
{
enum class WEAPON_CULL_TYPE : std::int32_t
{
kGeneral = 0x0,
kAnimation = 0x1,
kWeaponSwitch = 0x2,
};
}
@@ -0,0 +1,31 @@
#pragma once
namespace RE
{
enum class WEAPON_FLAGS : std::int32_t
{
kPlayerOnly = 0x00000001,
kNPCsUseAmmo = 0x00000002,
kNoJamAfterReload = 0x00000004,
kChargingReload = 0x00000008,
kMinorCrime = 0x00000010,
kFixedRange = 0x00000020,
kNotUsedInNormalCombat = 0x00000040,
kCritEffectOnDeath = 0x00000100,
kChargingAttack = 0x00000200,
kHoldInputToPower = 0x00000800,
kNonHostile = 0x00001000,
kBoundWeapon = 0x00002000,
kIgnoresNormalWeaponResistance = 0x00004000,
kAutomatic = 0x00008000,
kRepeatableSingleFire = 0x00010000,
kCantDrop = 0x00020000,
kHideBackpack = 0x00040000,
kEmbeddedWeapon = 0x00080000,
kNotPlayable = 0x00100000,
kHasScope = 0x00200000,
kBoltAction = 0x00400000,
kSecondaryWeapon = 0x00800000,
kDisableShells = 0x01000000,
};
}
@@ -0,0 +1,13 @@
#pragma once
namespace RE
{
enum class WEAPON_RUMBLE_PATTERN : std::int32_t
{
kConstant = 0x0,
kPeriodicSquare = 0x1,
kPeriodicTriangle = 0x2,
kPeriodicSawtooth = 0x3,
kPatternCount = 0x4
};
}
@@ -0,0 +1,14 @@
#pragma once
namespace RE
{
enum class WEAPON_STATE : std::int32_t
{
kSheathed = 0x0,
kWantToDraw = 0x1,
kDrawing = 0x2,
kDrawn = 0x3,
kWantToSheathe = 0x4,
kSheathing = 0x5
};
}
@@ -0,0 +1,21 @@
#pragma once
namespace RE
{
enum class WEAPON_TYPE : std::int32_t
{
kNone = 0xFF,
kHandToHand = 0x0,
kOneHandSword = 0x1,
kOneHandDagger = 0x2,
kOneHandAxe = 0x3,
kOneHandMace = 0x4,
kTwoHandSword = 0x5,
kTwoHandAxe = 0x6,
kBow = 0x7,
kStaff = 0x8,
kGun = 0x9,
kGrenade = 0xA,
kMine = 0xB,
};
}
@@ -0,0 +1,18 @@
#pragma once
#include "RE/N/NiPoint3.h"
namespace RE
{
class TESForm;
class WORLD_LOCATION
{
public:
// members
TESForm* locationForm; // 00
NiPoint3 locPt; // 08
float zRot; // 14
};
static_assert(sizeof(WORLD_LOCATION) == 0x18);
}
@@ -0,0 +1,17 @@
#pragma once
namespace RE
{
class WORLD_MAP_DATA
{
public:
// members
std::uint32_t usableWidth; // 00
std::uint32_t usableHeight; // 04
std::int16_t nwCellX; // 08
std::int16_t nwCellY; // 0A
std::int16_t seCellX; // 0C
std::int16_t seCellY; // 0E
};
static_assert(sizeof(WORLD_MAP_DATA) == 0x10);
}
@@ -0,0 +1,15 @@
#pragma once
namespace RE
{
class WORLD_MAP_OFFSET_DATA
{
public:
// members
float mapScale; // 00
float mapOffsetX; // 04
float mapOffsetY; // 08
float mapOffsetZ; // 0C
};
static_assert(sizeof(WORLD_MAP_OFFSET_DATA) == 0x10);
}
@@ -0,0 +1,14 @@
#pragma once
namespace RE
{
class WadingWaterData
{
public:
// members
NiPoint2 lastPlaceOffset;
NiPoint2 lastDisplaceOffset;
NiPoint3 lastPosition;
};
static_assert(sizeof(WadingWaterData) == 0x1C);
}
@@ -0,0 +1,52 @@
#pragma once
namespace RE
{
class WaterShaderData
{
public:
// members
float maxDepth; // 00
std::uint32_t shallowWaterColor; // 04
std::uint32_t deepWaterColor; // 08
float shallowFogColorRange; // 0C
float deepFogColorRange; // 10
float shallowAlpha; // 14
float deepAlpha; // 18
float shallowFogAlphaRange; // 1C
float deepFogAlphaRange; // 20
std::uint32_t underwaterFogColor; // 24
float underwaterFogAmount; // 28
float underwaterFogDistNear; // 2C
float underwaterFogDistFar; // 30
float normalMagnitude; // 34
float normalFalloffShallow; // 38
float normalFalloffDeep; // 3C
float reflectionAmount; // 40
float fresnelAmount; // 44
float surfaceEffectFalloff; // 48
float displacementForce; // 4C
float displacementVelocity; // 50
float displacementFalloff; // 54
float displacementDampener; // 58
float displacementSize; // 5C
std::uint32_t reflectionWaterColor; // 60
float sunSpecularPower; // 64
float sunSpecularMagnitude; // 68
float sunSparklePower; // 6C
float sunSparkleMagnitude; // 70
float lightRadius; // 74
float lightBrightness; // 78
float shininess; // 7C
float noiseWindDirections[3]; // 80
float noiseWindSpeeds[3]; // 8C
float amplitude[3]; // 98
float uvScales[3]; // A4
float noiseFalloff[3]; // B0
float siltAmount; // BC
std::uint32_t lightSiltColor; // C0
std::uint32_t darkSiltColor; // C4
bool ssrEnabled; // C8
};
static_assert(sizeof(WaterShaderData) == 0xCC);
}
@@ -0,0 +1,33 @@
#pragma once
#include "RE/B/BSIntrusiveRefCounted.h"
#include "RE/B/BSPointerHandle.h"
#include "RE/B/BSTEvent.h"
#include "RE/B/BSTSmartPointer.h"
#include "RE/I/IAnimationGraphManagerHolder.h"
namespace RE
{
class BSAnimationGraphEvent;
class BSAnimationGraphManager;
class __declspec(novtable) WeaponAnimationGraphManagerHolder :
public IAnimationGraphManagerHolder,
public BSTEventSink<BSAnimationGraphEvent>,
public BSIntrusiveRefCounted
{
public:
static constexpr auto RTTI{ RTTI::WeaponAnimationGraphManagerHolder };
static constexpr auto VTABLE{ VTABLE::WeaponAnimationGraphManagerHolder };
virtual ~WeaponAnimationGraphManagerHolder() = default; // 00
// override (BSTEventSink<BSAnimationGraphEvent>)
BSEventNotifyControl ProcessEvent(const BSAnimationGraphEvent& a_event, BSTEventSource<BSAnimationGraphEvent>* a_eventSource) override;
// members
BSTSmartPointer<BSAnimationGraphManager> animationGraphManager; // 08
ObjectRefHandle owner; // 10
};
static_assert(sizeof(WeaponAnimationGraphManagerHolder) == 0x28);
}
@@ -0,0 +1,14 @@
#pragma once
namespace RE
{
class WeatherEntry
{
public:
// members
TESWeather* weather; // 00
std::uint32_t chance; // 08
TESGlobal* chanceVar; // 10
};
static_assert(sizeof(WeatherEntry) == 0x18);
}
@@ -0,0 +1,26 @@
#pragma once
namespace RE
{
class WorkbenchData
{
public:
enum class Type
{
kNone = 0x0,
kCreateObject = 0x1,
kWeapons = 0x2,
kEnchanting = 0x3,
kEnchantingExperiment = 0x4,
kAlchemy = 0x5,
kAlchemyExperiment = 0x6,
kArmor = 0x7,
kPowerArmor = 0x8,
kRobotMod = 0x9
};
// members
REX::TEnumSet<Type, std::int8_t> type; // 00
};
static_assert(sizeof(WorkbenchData) == 0x01);
}
@@ -0,0 +1,124 @@
#pragma once
#include "RE/B/BGSInventoryList.h"
#include "RE/B/BGSTypedFormValuePair.h"
#include "RE/B/BSPointerHandle.h"
#include "RE/B/BSTSmartPointer.h"
#include "RE/B/BSTTuple.h"
#include "RE/G/GameMenuBase.h"
#include "RE/I/Inventory3DManager.h"
#include "RE/I/InventoryInterface.h"
#include "RE/N/NiPointer.h"
#include "RE/R/Rumble.h"
namespace RE
{
class ExtraDataList;
class NiNode;
class __declspec(novtable) WorkbenchMenuBase :
public GameMenuBase // 00
{
public:
static constexpr auto RTTI{ RTTI::WorkbenchMenuBase };
static constexpr auto VTABLE{ VTABLE::WorkbenchMenuBase };
enum class HighlightMode
{
kModMenu,
kAll,
kWorld
};
class InitParams
{
public:
InitParams();
// members
ObjectRefHandle workbenchFurniture; // 00
ObjectRefHandle inventorySource; // 04
InventoryInterface::Handle item{ 0xFFFFFFFF }; // 08
NiPointer<Actor> actor{ nullptr }; // 10
std::uint32_t stack{ 0 }; // 18
bool inspectMode{ true }; // 1C
bool inspectingSingleItem{ false }; // 1D
bool inspectingFeaturedItem{ false }; // 1E
bool showFeaturedItemMessage{ false }; // 1F
bool botCompanion{ false }; // 20
};
static_assert(sizeof(InitParams) == 0x28);
class ModChoiceData
{
public:
// members
union
{
BGSMod::Attachment::Mod* mod;
TESBoundObject* object;
}; // 00
const BGSConstructibleObject* recipe; // 08
BSTArray<BSTTuple<TESForm*, BGSTypedFormValuePair::SharedVal>>* requiredItems; // 10
BSTArray<BSTTuple<BGSPerk*, std::uint32_t>> requiredPerks; // 18
std::uint8_t rank; // 30
std::uint8_t index; // 31
};
static_assert(sizeof(ModChoiceData) == 0x38);
virtual ~WorkbenchMenuBase(); // 00
// override (GameMenuBase)
virtual void Call(const Params&) override; // 01
virtual void MapCodeObjectFunctions() override; // 02
virtual void PreDisplay() override; // 05
virtual void OnMenuStackChanged(const BSFixedString& a_topMenuName, bool a_passesTopMenuTest) override; // 09
// override (BSInputEventUser)
virtual bool ShouldHandleEvent(const InputEvent*) override; // 01
virtual void OnThumbstickEvent(const ThumbstickEvent*) override; // 04
virtual void OnCursorMoveEvent(const CursorMoveEvent*) override; // 05
virtual void OnButtonEvent(const ButtonEvent*) override; // 08
// add
virtual void OnHideMenu(); // 14
virtual void UpdateMenu(); // 15
virtual void BuildCanceled(); // 16
virtual void BuildConfirmed(bool a_ownerIsWorkbench) = 0; // 17
virtual bool GetWorkbenchHasInventory(); // 18
virtual const ModChoiceData* QCurrentModChoiceData(); // 19
virtual void ShowBuildFailureMessage(); // 1A
virtual bool TryCreate() = 0; // 1B
void UpdateOptimizedAutoBuildInv()
{
using func_t = decltype(&WorkbenchMenuBase::UpdateOptimizedAutoBuildInv);
static REL::Relocation<func_t> func{ ID::WorkbenchMenuBase::UpdateOptimizedAutoBuildInv };
return func(this);
}
// members
NiPointer<TESObjectREFR> sharedContainerRef; // 0E0
NiPointer<TESObjectREFR> workbenchContainerRef; // 0E8
BSTArray<NiPointer<TESObjectREFR>> sharedContainers; // 0F0
Inventory3DManager inv3DModelManager; // 110
BGSInventoryList optimizedAutoBuildInv; // 250
BSTArray<ModChoiceData> modChoiceArray; // 2D0
std::uint32_t modChoiceIndex; // 2E8
std::uint32_t lastModChoiceIndex; // 2EC
bool repairing; // 2F0
bool queueHide; // 2F1
bool hiding; // 2F2
bool VATSWasEnabled; // 2F3
NiPointer<TESObjectREFR> workbenchRef; // 2F8
BSTSmartPointer<ExtraDataList> recipeExtraDataList; // 300
NiPointer<NiNode> item3DGeometry; // 308
BSTArray<TESForm*> queuedCraftingComponents; // 310
std::uint64_t soundTimer; // 328
REX::TEnumSet<HighlightMode, std::uint32_t> highlightMode; // 330
Rumble::AutoRumblePause autoRumblePause; // 334
bool initialized; // 335
bool soundsQueued; // 336
};
static_assert(sizeof(WorkbenchMenuBase) == 0x340);
}
@@ -0,0 +1,395 @@
#pragma once
#include "RE/A/Actor.h"
#include "RE/B/BSExtraData.h"
#include "RE/B/BSPointerHandle.h"
#include "RE/B/BSTArray.h"
#include "RE/B/BSTTuple.h"
#include "RE/N/NiPoint3.h"
#include "RE/N/NiPointer.h"
#include "RE/P/PowerUtils.h"
#include "RE/T/TESObjectCELL.h"
namespace RE
{
template <class>
class BSPointerHandleSmartPointer;
class bhkNPCollisionObject;
class hknpShape;
namespace Workshop
{
enum class PlacementStatusValue : std::int8_t
{
kNoEditItem = 0x0,
kValidPlacement = 0x1,
kFloating = 0x2,
kIntersecting = 0x3,
kTerrainOnly = 0x4,
kWaterRestriction = 0x5,
kSplineTooLong = 0x6,
kOutsideBuildArea = 0x7,
kRedundantSpline = 0x8,
kAttachedSplineInvalid = 0x9,
kUnsupported = 0xA,
kMustSnap = 0xB,
kRadiusOverlap = 0xC,
kTimer = 0xD,
kReasonCount = 0xE
};
enum class StartWorkshopStatus
{
kOk = 0x0,
kNoNearbyWorkshop = 0x1,
kAlreadyInWorkshopMode = 0x2,
kActivationBlocked = 0x3
};
class BuildableAreaEvent
{
public:
// members
bool exit; // 00
};
static_assert(sizeof(BuildableAreaEvent) == 0x1);
class ContextData
{
public:
ContextData(Actor* a_actor)
{
// lookDir.y = 1.0f;
zAngle = a_actor->data.angle.z;
parentCell = a_actor->parentCell;
worldSpace = a_actor->parentCell->worldSpace;
a_actor->GetEyeVector(lookPos, lookDir, false);
}
// members
NiPoint3 lookPos; // 00
NiPoint3 lookDir; // 0C
float zAngle; // 18
TESObjectCELL* parentCell; // 20
TESWorldSpace* worldSpace; // 28
};
static_assert(sizeof(ContextData) == 0x30);
class DeletedItemInfo
{
public:
~DeletedItemInfo() noexcept {} // NOLINT(modernize-use-equals-default)
// members
TESFormID formID; // 0
std::uint32_t count; // 4
};
static_assert(sizeof(DeletedItemInfo) == 0x8);
class __declspec(novtable) ExtraData :
public BSExtraData // 00
{
public:
static constexpr auto RTTI{ RTTI::Workshop__ExtraData };
static constexpr auto VTABLE{ VTABLE::Workshop__ExtraData };
static constexpr auto TYPE{ EXTRA_DATA_TYPE::kWorkshop };
// members
PowerUtils::PowerGrid* currentPowerGrid; // 18
BSTArray<PowerUtils::PowerGrid*> powerGrid; // 20
BSTArray<DeletedItemInfo*> deletedItems; // 38
std::int32_t powerRating; // 50
bool offGridItems; // 54
};
static_assert(sizeof(ExtraData) == 0x58);
class ItemDestroyedEvent
{
public:
// members
NiPointer<TESObjectREFR> workshop; // 00
NiPointer<TESObjectREFR> objectDestroyed; // 08
};
static_assert(sizeof(ItemDestroyedEvent) == 0x10);
class ItemMovedEvent
{
public:
// members
NiPointer<TESObjectREFR> workshop; // 00
NiPointer<TESObjectREFR> movedItem; // 08
};
static_assert(sizeof(ItemMovedEvent) == 0x10);
class ItemPlacedEvent
{
public:
// members
NiPointer<TESObjectREFR> workshop; // 00
NiPointer<TESObjectREFR> placedItem; // 08
};
static_assert(sizeof(ItemPlacedEvent) == 0x10);
class alignas(0x10) PlacementItemData
{
public:
void Set(TESObjectREFR& a_refr)
{
using func_t = decltype(&PlacementItemData::Set);
static REL::Relocation<func_t> func{ ID::Workshop::PlacementItemData::Set };
return func(this, a_refr);
}
// members
ObjectRefHandle placementItem; // 00
BSTArray<hknpShape*> dropProxy; // 08
BSTArray<bhkNPCollisionObject*> body; // 20
std::byte pad38[0x80 - 0x38]; // 38 - TODO
float sinkDepth; // 80
float zOffset; // 84
float intersectTolerance; // 88
float snapPointQueryRadius; // 8C
float forwardCastZRot; // 90
float xyBoundOverride; // 94
float xBoundMinOverride; // 98
float xBoundMaxOverride; // 9C
float yBoundMinOverride; // A0
float yBoundMaxOverride; // A4
float zBoundMinOverride; // A8
float zBoundMaxOverride; // AC
std::uint32_t dropProxyIndex; // B0
bool anythingIsGround; // B4
bool clampUp; // B5
bool forwardCast; // B6
bool recenter; // B7
bool ignoreSimpleIntersection; // B8
bool allowUnsupportedStacking; // B9
bool isSet; // BA
bool mustSnap; // BB
bool stacksWhenSnapped; // BC
};
static_assert(sizeof(PlacementItemData) == 0xC0);
class PlacementStatusEvent
{
public:
// members
PlacementStatusValue value; // 00
};
static_assert(sizeof(PlacementStatusEvent) == 0x1);
class WorkshopMenuNode
{
public:
~WorkshopMenuNode() { Clear(); }
void Clear()
{
filterKeyword = nullptr;
parent = nullptr;
recipe = nullptr;
row = 0;
column = 0;
selected = false;
children.clear();
}
bool FindAndSetSelectedNode(std::uint16_t a_row, std::uint32_t a_crc, std::uint16_t& a_outRow)
{
using func_t = decltype(&WorkshopMenuNode::FindAndSetSelectedNode);
static REL::Relocation<func_t> func{ ID::Workshop::WorkshopMenuNode::FindAndSetSelectedNode };
return func(this, a_row, a_crc, a_outRow);
}
F4_HEAP_REDEFINE_NEW(WorkshopMenuNode);
// members
BGSKeyword* filterKeyword{ nullptr }; // 00
WorkshopMenuNode* parent{ nullptr }; // 08
BSTArray<std::unique_ptr<WorkshopMenuNode>> children; // 10
BGSConstructibleObject* recipe{ nullptr }; // 28
BGSConstructibleObject* sourceFormListRecipe{ nullptr }; // 30
TESForm* form{ nullptr }; // 38
std::uint32_t uniqueID{ static_cast<std::uint32_t>(-1) }; // 40
std::uint16_t row{ 0 }; // 44
std::uint16_t column{ 0 }; // 46
bool selected{ false }; // 48
};
static_assert(sizeof(WorkshopMenuNode) == 0x50);
class WorkshopModeEvent
{
public:
// members
NiPointer<TESObjectREFR> workshop; // 00
bool start; // 08
};
static_assert(sizeof(WorkshopModeEvent) == 0x10);
[[nodiscard]] inline TESObjectREFR* FindNearestValidWorkshop(const TESObjectREFR& a_refr)
{
using func_t = decltype(&Workshop::FindNearestValidWorkshop);
static REL::Relocation<func_t> func{ ID::Workshop::FindNearestValidWorkshop };
return func(a_refr);
}
[[nodiscard]] inline bool FreeBuild()
{
using func_t = decltype(&Workshop::FreeBuild);
static REL::Relocation<func_t> func{ ID::Workshop::FreeBuild };
return func();
}
[[nodiscard]] inline WorkshopMenuNode* GetSelectedWorkshopMenuNode(std::uint32_t a_row, std::uint32_t& a_column)
{
using func_t = decltype(&Workshop::GetSelectedWorkshopMenuNode);
static REL::Relocation<func_t> func{ ID::Workshop::GetSelectedWorkshopMenuNode };
return func(a_row, a_column);
}
inline void InitializePlacementReference(const ContextData& a_context, TESBoundObject& a_object)
{
using func_t = decltype(&Workshop::InitializePlacementReference);
static REL::Relocation<func_t> func{ ID::Workshop::InitializePlacementReference };
return func(a_context, a_object);
}
[[nodiscard]] inline bool IsLocationWithinBuildableArea(const TESObjectREFR& a_workshop, const NiPoint3& a_location)
{
using func_t = decltype(&Workshop::IsLocationWithinBuildableArea);
static REL::Relocation<func_t> func{ ID::Workshop::IsLocationWithinBuildableArea };
return func(a_workshop, a_location);
}
inline bool PlaceCurrentReference(const ContextData& a_context)
{
using func_t = decltype(&Workshop::PlaceCurrentReference);
static REL::Relocation<func_t> func{ ID::Workshop::PlaceCurrentReference };
return func(a_context);
}
inline void RegisterForItemDestroyed(BSTEventSink<ItemDestroyedEvent>* a_sink)
{
using func_t = decltype(&Workshop::RegisterForItemDestroyed);
static REL::Relocation<func_t> func{ ID::Workshop::RegisterForItemDestroyed };
return func(a_sink);
}
inline void RegisterForItemMoved(BSTEventSink<ItemMovedEvent>* a_sink)
{
using func_t = decltype(&Workshop::RegisterForItemMoved);
static REL::Relocation<func_t> func{ ID::Workshop::RegisterForItemMoved };
return func(a_sink);
}
inline void RegisterForItemPlaced(BSTEventSink<ItemPlacedEvent>* a_sink)
{
using func_t = decltype(&Workshop::RegisterForItemPlaced);
static REL::Relocation<func_t> func{ ID::Workshop::RegisterForItemPlaced };
return func(a_sink);
}
inline void RegisterForWorkshopModeEvent(BSTEventSink<WorkshopModeEvent>* a_sink)
{
using func_t = decltype(&Workshop::RegisterForWorkshopModeEvent);
static REL::Relocation<func_t> func{ ID::Workshop::RegisterForWorkshopModeEvent };
return func(a_sink);
}
inline void RequestExitWorkshop(bool a_allowReEntry)
{
using func_t = decltype(&Workshop::RequestExitWorkshop);
static REL::Relocation<func_t> func{ ID::Workshop::RequestExitWorkshop };
return func(a_allowReEntry);
}
inline void ScrapReference(const ContextData& a_context, BSPointerHandleSmartPointer<BSPointerHandleManagerInterface<TESObjectREFR, HandleManager>>& a_scrapRef, BSTArray<BSTTuple<TESBoundObject*, std::uint32_t>>* a_rewards)
{
using func_t = decltype(&Workshop::ScrapReference);
static REL::Relocation<func_t> func{ ID::Workshop::ScrapReference };
return func(a_context, a_scrapRef, a_rewards);
}
inline void SetSelectedEditItem(ObjectRefHandle a_refr)
{
using func_t = decltype(&Workshop::SetSelectedEditItem);
static REL::Relocation<func_t> func{ ID::Workshop::SetSelectedEditItem };
return func(a_refr);
}
inline void StartWorkshop(TESObjectREFR* a_workshopRef)
{
using func_t = decltype(&Workshop::StartWorkshop);
static REL::Relocation<func_t> func{ ID::Workshop::StartWorkshop };
return func(a_workshopRef);
}
inline void ToggleEditMode(const ContextData& a_context)
{
using func_t = decltype(&Workshop::ToggleEditMode);
static REL::Relocation<func_t> func{ ID::Workshop::ToggleEditMode };
return func(a_context);
}
inline void UnregisterForItemDestroyed(BSTEventSink<ItemDestroyedEvent>* a_sink)
{
using func_t = decltype(&Workshop::UnregisterForItemDestroyed);
static REL::Relocation<func_t> func{ ID::Workshop::UnregisterForItemDestroyed };
return func(a_sink);
}
inline void UnregisterForItemMoved(BSTEventSink<ItemMovedEvent>* a_sink)
{
using func_t = decltype(&Workshop::UnregisterForItemMoved);
static REL::Relocation<func_t> func{ ID::Workshop::UnregisterForItemMoved };
return func(a_sink);
}
inline void UnregisterForItemPlaced(BSTEventSink<ItemPlacedEvent>* a_sink)
{
using func_t = decltype(&Workshop::UnregisterForItemPlaced);
static REL::Relocation<func_t> func{ ID::Workshop::UnregisterForItemPlaced };
return func(a_sink);
}
inline void UnregisterForWorkshopModeEvent(BSTEventSink<WorkshopModeEvent>* a_sink)
{
using func_t = decltype(&Workshop::UnregisterForWorkshopModeEvent);
static REL::Relocation<func_t> func{ ID::Workshop::UnregisterForWorkshopModeEvent };
return func(a_sink);
}
inline void UpdateActiveEdit(const ContextData& a_context, bool a_multiselect = false)
{
using func_t = decltype(&Workshop::UpdateActiveEdit);
static REL::Relocation<func_t> func{ ID::Workshop::UpdateActiveEdit };
return func(a_context, a_multiselect);
}
[[nodiscard]] inline bool WorkshopCanShowRecipe(BGSConstructibleObject* a_recipe, BGSKeyword* a_filter)
{
using func_t = decltype(&Workshop::WorkshopCanShowRecipe);
static REL::Relocation<func_t> func{ ID::Workshop::WorkshopCanShowRecipe };
return func(a_recipe, a_filter);
}
[[nodiscard]] inline PlacementItemData* GetCurrentPlacementItemData()
{
static REL::Relocation<PlacementItemData*> value{ ID::Workshop::CurrentPlacementItemData };
return value.get();
}
[[nodiscard]] inline std::uint16_t* GetCurrentRow()
{
static REL::Relocation<std::uint16_t*> value{ ID::Workshop::CurrentRow };
return value.get();
}
[[nodiscard]] inline ObjectRefHandle* GetPlacementItem()
{
static REL::Relocation<ObjectRefHandle*> value{ ID::Workshop::PlacementItem };
return value.get();
}
}
}
@@ -0,0 +1,142 @@
#pragma once
#include "RE/B/BGSListForm.h"
#include "RE/B/BSSpinLock.h"
#include "RE/B/BSTEvent.h"
#include "RE/B/BSTInterpolator.h"
#include "RE/B/BSTSmartPointer.h"
#include "RE/B/BSTTuple.h"
#include "RE/D/DisplayItemModel.h"
#include "RE/G/GameMenuBase.h"
#include "RE/I/Inventory3DManager.h"
#include "RE/N/NiPoint3.h"
#include "RE/N/NiPointer.h"
namespace RE
{
class PickRefUpdateEvent;
class UserEventEnabledEvent;
class WorkshopMenuGeometry;
namespace Workshop
{
class BuildableAreaEvent;
class PlacementStatusEvent;
}
class __declspec(novtable) WorkshopMenu :
public GameMenuBase, // 000
public BSTEventSink<UserEventEnabledEvent>, // 0E0
public BSTEventSink<Workshop::BuildableAreaEvent>, // 0E8
public BSTEventSink<PickRefUpdateEvent>, // 0F0
public BSTEventSink<Workshop::PlacementStatusEvent> // 0F8
{
public:
static constexpr auto RTTI{ RTTI::WorkshopMenu };
static constexpr auto VTABLE{ VTABLE::WorkshopMenu };
static constexpr auto MENU_NAME{ "WorkshopMenu"sv };
enum class TAG_FOR_SEARCH_RESULT
{
kNone = 0x0,
kTaggedComponents = 0x1,
kUntaggedComponents = 0x2
};
class FXWorkshopMenu :
public BSGFxShaderFXTarget // 000
{
public:
// members
std::unique_ptr<BSGFxShaderFXTarget> happyBackground1; // 0B0
std::unique_ptr<BSGFxShaderFXTarget> happyBackground2; // 0B8
std::unique_ptr<BSGFxShaderFXTarget> happyBackground3; // 0C0
std::unique_ptr<BSGFxShaderFXTarget> happyBackground4; // 0C8
std::unique_ptr<BSGFxShaderFXTarget> happyBackground5; // 0D0
std::unique_ptr<BSGFxShaderFXTarget> happyBackground6; // 0D8
std::unique_ptr<BSGFxShaderFXTarget> happyBackground7; // 0E0
std::unique_ptr<BSGFxShaderFXTarget> happyBackground8; // 0E8
std::unique_ptr<BSGFxShaderFXTarget> buttonBackground; // 0F0
std::unique_ptr<BSGFxShaderFXTarget> iconCardBackground; // 0F8
std::unique_ptr<BSGFxShaderFXTarget> requirementsListBackground; // 100
std::unique_ptr<BSGFxShaderFXTarget> happinessPeopleBase; // 108
std::unique_ptr<BSGFxShaderFXTarget> happinessFoodBase; // 110
std::unique_ptr<BSGFxShaderFXTarget> happinessWaterBase; // 118
std::unique_ptr<BSGFxShaderFXTarget> happinessPowerBase; // 120
std::unique_ptr<BSGFxShaderFXTarget> happinessSafetyBase; // 128
std::unique_ptr<BSGFxShaderFXTarget> happinessBedsBase; // 130
std::unique_ptr<BSGFxShaderFXTarget> happinessHappyValue; // 138
std::unique_ptr<BSGFxShaderFXTarget> happinessHappyLabel; // 140
std::unique_ptr<BSGFxShaderFXTarget> happinessHappyIcon; // 148
std::unique_ptr<BSGFxShaderFXTarget> happinessHappyArrow; // 150
std::unique_ptr<BSGFxShaderFXTarget> happinessSizeBase; // 158
std::unique_ptr<BSGFxShaderFXTarget> happinessBarBrackets; // 160
std::unique_ptr<BSGFxShaderFXTarget> requirementsBase; // 168
std::unique_ptr<BSGFxShaderFXTarget> itemName; // 170
std::unique_ptr<BSGFxShaderFXTarget> selectionBracket; // 178
std::unique_ptr<BSGFxShaderFXTarget> itemCounts; // 180
std::unique_ptr<BSGFxShaderFXTarget> newRecipeIcon; // 188
std::unique_ptr<BSGFxShaderFXTarget> iconCardBracketsAndText; // 190
std::unique_ptr<BSGFxShaderFXTarget> producesIcons; // 198
std::unique_ptr<BSGFxShaderFXTarget> requiresIcon1; // 1A0
std::unique_ptr<BSGFxShaderFXTarget> requiresIcon2; // 1A8
std::unique_ptr<BSGFxShaderFXTarget> assignmentIcon; // 1B0
std::unique_ptr<BSGFxShaderFXTarget> rowBrackets; // 1B8
std::unique_ptr<BSGFxShaderFXTarget> displayPath; // 1C0
std::unique_ptr<BSGFxShaderFXTarget> perkPanel1; // 1C8
std::unique_ptr<BSGFxShaderFXTarget> perkPanel2; // 1D0
std::unique_ptr<BSGFxShaderFXTarget> descriptionBase; // 1D8
std::unique_ptr<BSGFxShaderFXTarget> iconBackground; // 1E0
};
static_assert(sizeof(FXWorkshopMenu) == 0x1E8);
class IconBG
{
public:
BSTAlignedArray<UIShaderFXInfo> cachedColorFXInfos; // 00
BSTAlignedArray<UIShaderFXInfo> cachedBackgroundFXInfos; // 18
BSReadWriteLock cachedQuadsLock; // 30
};
static_assert(sizeof(IconBG) == 0x38);
void CheckAndSetItemForPlacement()
{
using func_t = decltype(&WorkshopMenu::CheckAndSetItemForPlacement);
static REL::Relocation<func_t> func{ ID::WorkshopMenu::CheckAndSetItemForPlacement };
return func(this);
}
void UpdateButtonText()
{
using func_t = decltype(&WorkshopMenu::UpdateButtonText);
static REL::Relocation<func_t> func{ ID::WorkshopMenu::UpdateButtonText };
return func(this);
}
// members
BSTArray<NiPoint3> item3DPositions[4]; // 100
BSTArray<BSTTuple<DisplayItemModel, TESObjectREFR*>> displayItemModels; // 160
IconBG iconBG; // 178
Inventory3DManager inv3DModelManager; // 1B0
BSTArray<BSTTuple<NiPointer<nsInventory3DManager::NewInventoryMenuItemLoadTask>, NiPoint3>> loadTasks; // 2F0
BSTInterpolator<float, EaseOutInterpolator, GetCurrentPositionFunctor> upDownGlassAnimationInterpolator; // 308
BSTInterpolator<float, EaseOutInterpolator, GetCurrentPositionFunctor> leftRightGlassAnimationInterpolator[4]; // 320
BSTSmartPointer<WorkshopMenuGeometry> displayGeometry; // 380
BSFixedString dpadInput; // 388
BGSListForm includeList; // 390
BGSListForm excludeList; // 3D8
long double lastBudget; // 420
std::uint16_t topMenuCount; // 428
bool inputAdjustMode; // 42A
bool verticalAdjustment; // 42B
bool disableAdjustOnThumbEvent; // 42C
bool initialized; // 42D
bool inEditMode; // 42E
bool electricalDevice; // 42F
bool useMovementAsDirectional; // 430
bool motionBlurActive; // 431
bool exitDebounce; // 432
std::unique_ptr<FXWorkshopMenu> workshopMenuBase; // 438
};
static_assert(sizeof(WorkshopMenu) == 0x440);
}