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
+143
View File
@@ -0,0 +1,143 @@
#pragma once
#include "RE/B/BSInputEventReceiver.h"
#include "RE/B/BSSpinLock.h"
#include "RE/B/BSTEvent.h"
#include "RE/B/BSTHashMap.h"
#include "RE/B/BSTSingleton.h"
#include "RE/B/BSTimer.h"
#include "RE/I/IMenu.h"
#include "RE/U/UIMenuEntry.h"
namespace RE
{
class MenuModeChangeEvent;
class MenuOpenCloseEvent;
class MenuModeCounterChangedEvent;
class TutorialEvent;
class __declspec(novtable) UI :
public BSInputEventReceiver, // 000
public BSTSingletonSDM<UI>, // 010
public BSTEventSource<MenuOpenCloseEvent>, // 018
public BSTEventSource<MenuModeChangeEvent>, // 070
public BSTEventSource<MenuModeCounterChangedEvent>, // 0C8
public BSTEventSource<TutorialEvent> // 120
{
public:
static constexpr auto RTTI{ RTTI::UI };
static constexpr auto VTABLE{ VTABLE::UI };
using Create_t = typename UIMenuEntry::Create_t;
using StaticUpdate_t = typename UIMenuEntry::StaticUpdate_t;
// add
virtual ~UI() = default; // 01
[[nodiscard]] bool CustomRendererHasQuads(const BSFixedString& a_customRendererName)
{
using func_t = decltype(&UI::CustomRendererHasQuads);
static REL::Relocation<func_t> func{ ID::UI::CustomRendererHasQuads };
return func(this, a_customRendererName);
}
template <class T>
[[nodiscard]] BSTEventSource<T>* GetEventSource()
{
return static_cast<RE::BSTEventSource<T>*>(this);
}
[[nodiscard]] static BSReadWriteLock& GetMenuMapRWLock()
{
static REL::Relocation<BSReadWriteLock*> menuMapRWLock{ ID::UI::GetMenuMapRWLock };
return *menuMapRWLock;
}
[[nodiscard]] static UI* GetSingleton()
{
static REL::Relocation<UI**> singleton{ ID::UI::Singleton };
return *singleton;
}
[[nodiscard]] Scaleform::Ptr<IMenu> GetMenu(const BSFixedString& a_name) const
{
BSAutoReadLock l{ GetMenuMapRWLock() };
const auto it = menuMap.find(a_name);
return it != menuMap.end() ? it->second.menu : nullptr;
}
template <class T>
[[nodiscard]] Scaleform::Ptr<T> GetMenu() const
requires(requires { T::MENU_NAME; })
{
const auto ptr = GetMenu(T::MENU_NAME);
return Scaleform::Ptr{ static_cast<T*>(ptr.get()) };
}
[[nodiscard]] bool GetMenuOpen(const BSFixedString& a_name) const
{
const auto menu = GetMenu(a_name);
return menu ? menu->OnStack() : false;
}
template <class T>
[[nodiscard]] bool GetMenuOpen() const
requires(requires { T::MENU_NAME; })
{
return GetMenuOpen(T::MENU_NAME);
}
void RefreshCursor()
{
using func_t = decltype(&UI::RefreshCursor);
static REL::Relocation<func_t> func{ ID::UI::RefreshCursor };
return func(this);
}
void RegisterMenu(const char* a_menu, Create_t* a_create, StaticUpdate_t* a_staticUpdate = nullptr)
{
using func_t = decltype(&UI::RegisterMenu);
static REL::Relocation<func_t> func{ ID::UI::RegisterMenu };
return func(this, a_menu, a_create, a_staticUpdate);
}
template <class T>
void RegisterSink(BSTEventSink<T>* a_sink)
{
GetEventSource<T>()->RegisterSink(a_sink);
}
void UpdateControllerType()
{
using func_t = decltype(&UI::UpdateControllerType);
static REL::Relocation<func_t> func{ ID::UI::UpdateControllerType };
return func(this);
}
template <class T>
void UnregisterSink(BSTEventSink<T>* a_sink)
{
GetEventSource<T>()->UnregisterSink(a_sink);
}
// members
BSTArray<BSFixedString> releasedMovies; // 178
BSTArray<Scaleform::Ptr<IMenu>> menuStack; // 190
BSTHashMap<BSFixedString, UIMenuEntry> menuMap; // 1A8
BSSpinLock processMessagesLock; // 1D8
std::uint32_t menuMode; // 1E0
BSTAtomicValue<std::uint32_t> itemMenuMode; // 1E4
BSTAtomicValue<std::uint32_t> pauseMenuDisableCt; // 1E8
std::uint32_t freezeFrameMenuBG; // 1EC
std::uint32_t freezeFramePause; // 1F0
std::uint32_t savingDisabled; // 1F4
std::uint32_t disablesCompanion; // 1F8
std::uint32_t largeCacheRenderModeCount; // 1FC
std::uint32_t movementToDirectionalCount; // 200
BSTimer uiTimer; // 208
bool menuSystemVisible; // 258
bool closingAllMenus; // 259
bool freezeFrameScreenshotReady; // 25A
};
static_assert(sizeof(UI) == 0x260);
}
@@ -0,0 +1,23 @@
#pragma once
#include "RE/B/BSTEvent.h"
namespace RE
{
class UIAdvanceMenusFunctionCompleteEvent
{
private:
using EventSource_t = BSTGlobalEvent::EventSource<UIAdvanceMenusFunctionCompleteEvent>;
public:
[[nodiscard]] static EventSource_t* GetEventSource()
{
static REL::Relocation<EventSource_t**> singleton{ ID::UIAdvanceMenusFunctionCompleteEvent::GetEventSource };
if (!*singleton) {
*singleton = new EventSource_t(&BSTGlobalEvent::GetSingleton()->eventSourceSDMKiller);
}
return *singleton;
}
};
static_assert(std::is_empty_v<UIAdvanceMenusFunctionCompleteEvent>);
}
@@ -0,0 +1,22 @@
#pragma once
#include "Scaleform/P/Ptr.h"
namespace RE
{
class IMenu;
class UIMessage;
class UIMenuEntry
{
public:
using Create_t = IMenu*(const UIMessage&);
using StaticUpdate_t = void();
// members
Scaleform::Ptr<IMenu> menu; // 00
Create_t* create; // 08
StaticUpdate_t* staticUpdate{ nullptr }; // 10
};
static_assert(sizeof(UIMenuEntry) == 0x18);
}
@@ -0,0 +1,29 @@
#pragma once
#include "RE/B/BSFixedString.h"
#include "RE/M/MemoryManager.h"
#include "RE/U/UI_MESSAGE_TYPE.h"
namespace RE
{
class IUIMessageData;
class __declspec(novtable) UIMessage
{
public:
static constexpr auto RTTI{ RTTI::UIMessage };
static constexpr auto VTABLE{ VTABLE::UIMessage };
virtual ~UIMessage() = default; // 00
virtual IUIMessageData* QData() { return nullptr; } // 02
virtual const IUIMessageData* QData() const { return nullptr; } // 01
F4_HEAP_REDEFINE_NEW(UIMessage);
// members
BSFixedString menu; // 08
REX::TEnumSet<UI_MESSAGE_TYPE, std::int32_t> type{ UI_MESSAGE_TYPE::kTotal }; // 10
};
static_assert(sizeof(UIMessage) == 0x18);
}
@@ -0,0 +1,33 @@
#pragma once
#include "RE/B/BSFixedString.h"
#include "RE/B/BSSpinLock.h"
#include "RE/B/BSTArray.h"
#include "RE/B/BSTSingleton.h"
#include "RE/U/UIMessage.h"
namespace RE
{
class UIMessageQueue :
public BSTSingletonSDM<UIMessageQueue> // 000
{
public:
[[nodiscard]] static UIMessageQueue* GetSingleton()
{
static REL::Relocation<UIMessageQueue**> singleton{ ID::UIMessageQueue::Singleton };
return *singleton;
}
void AddMessage(const BSFixedString& a_menu, UI_MESSAGE_TYPE a_type)
{
using func_t = decltype(&UIMessageQueue::AddMessage);
static REL::Relocation<func_t> func{ ID::UIMessageQueue::AddMessage };
return func(this, a_menu, a_type);
}
// members
BSTSmallArray<std::unique_ptr<UIMessage>, 64> messages; // 008
BSSpinLock uiMessagesLock; // 218
};
static_assert(sizeof(UIMessageQueue) == 0x220);
}
@@ -0,0 +1,27 @@
#pragma once
#include "RE/N/NiColor.h"
#include "RE/N/NiRect.h"
namespace RE
{
class UIShaderColors
{
public:
enum class Flags
{
kBackgroundQuad = 1u << 0,
kColorMultiplier = 1u << 1,
kVerticalGradient = 1u << 2,
kUseAlphaForDropshadow = 1u << 3
};
// members
NiRect<float> backgroundQuad; // 00
NiColorA backgroundColor; // 10
NiColorA colorMultipliers; // 20
float colorBrightness; // 30
REX::TEnumSet<Flags, std::uint32_t> enabledStates; // 34
};
static_assert(sizeof(UIShaderColors) == 0x38);
}
@@ -0,0 +1,15 @@
#pragma once
#include "RE/U/UIShaderColors.h"
namespace RE
{
class alignas(0x10) UIShaderFXInfo
{
public:
// members
NiRect<float> renderQuad; // 00
UIShaderColors shaderFX; // 10
};
static_assert(sizeof(UIShaderFXInfo) == 0x50);
}
@@ -0,0 +1,56 @@
#pragma once
#include "RE/B/BSTArray.h"
#include "RE/B/BSTTuple.h"
namespace RE
{
class BGSInventoryItem;
namespace UIUtils
{
using ComparisonItems = BSScrapArray<BSTTuple<const BGSInventoryItem*, std::uint32_t>>;
inline void GetComparisonItems(const TESBoundObject* a_object, ComparisonItems& a_comparisonItems)
{
using func_t = decltype(&GetComparisonItems);
static REL::Relocation<func_t> func{ ID::UIUtils::GetComparisonItems };
return func(a_object, a_comparisonItems);
}
inline void PlayPipboySound(const char* a_soundName)
{
using func_t = decltype(&PlayPipboySound);
static REL::Relocation<func_t> func{ ID::UIUtils::PlayPipboySound };
return func(a_soundName);
}
inline void PlayMenuSound(const char* a_soundName)
{
using func_t = decltype(&PlayMenuSound);
static REL::Relocation<func_t> func{ ID::UIUtils::PlayMenuSound };
return func(a_soundName);
}
inline void UpdateGamepadDependentButtonCodes(bool a_usingGamepad)
{
using func_t = decltype(&UpdateGamepadDependentButtonCodes);
static REL::Relocation<func_t> func{ ID::UIUtils::UpdateGamepadDependentButtonCodes };
return func(a_usingGamepad);
}
inline void ShowCraftingMenu(TESObjectREFR* a_furniture)
{
using func_t = decltype(&ShowCraftingMenu);
static REL::Relocation<func_t> func{ ID::UIUtils::ShowCraftingMenu };
return func(a_furniture);
}
inline bool HasRequiredInventoryForCraftingMenu(TESObjectREFR* a_furniture)
{
using func_t = decltype(&HasRequiredInventoryForCraftingMenu);
static REL::Relocation<func_t> func{ ID::UIUtils::HasRequiredInventoryForCraftingMenu };
return func(a_furniture);
}
}
}
@@ -0,0 +1,29 @@
#pragma once
namespace RE
{
enum class UI_DEPTH_PRIORITY : std::int32_t
{
kUndefined = 0x0, //
k3DUnderHUD = 0x1, // WorkshopMenu3D
kBook = 0x2, // BookMenu
kScope = 0x3, // ScopeMenu
kSWFLoader = 0x4, //
kHUD = 0x5, //
kStandard = 0x6, // PipboyMenu, PowerArmorRenderer, HUDRainRenderer, LockpickingMenu3D
kStandard3DModel = 0x7, // Container3D, WorkbenchItem3D
kPipboy = 0x8, //
kTerminal = 0x9, //
kGameMessage = 0xA, //
kPauseMenu = 0xB, //
kLoadingFader = 0xC, //
kLoading3DModel = 0xD, // BackgroundScreenModel
kLoadingMenu = 0xE, //
kMessage = 0xF, //
kButtonBarMenu = 0x10, // FlatScreenModel, HUDScreenModel
kButtonBarSupressingMenu = 0x11, //
kDebug = 0x12, //
kConsole = 0x13, //
kCursor = 0x14 //
};
}
@@ -0,0 +1,36 @@
#pragma once
namespace RE
{
enum class UI_MENU_FLAGS : std::int32_t
{
kPausesGame = 1 << 0,
kAlwaysOpen = 1 << 1,
kUsesCursor = 1 << 2,
kUsesMenuContext = 1 << 3,
kModal = 1 << 4,
kFreezeFrameBackground = 1 << 5,
kOnStack = 1 << 6,
kDisablePauseMenu = 1 << 7,
kRequiresUpdate = 1 << 8,
kTopmostRenderedMenu = 1 << 9,
kUpdateUsesCursor = 1 << 10,
kAllowSaving = 1 << 11,
kRendersOffscreenTargets = 1 << 12,
kInventoryItemMenu = 1 << 13,
kDontHideCursorWhenTopmost = 1 << 14,
kCustomRendering = 1 << 15,
kAssignCursorToRenderer = 1 << 16,
kApplicationMenu = 1 << 17,
kHasButtonBar = 1 << 18,
kIsTopButtonBar = 1 << 19,
kAdvancesUnderPauseMenu = 1 << 20,
kRendersUnderPauseMenu = 1 << 21,
kUsesBlurredBackground = 1 << 22,
kCompanionAppAllowed = 1 << 23,
kFreezeFramePause = 1 << 24,
kSkipRenderDuringFreezeFrameScreenshot = 1 << 25,
kLargeScaleformRenderCacheMode = 1 << 26,
kUsesMovementToDirection = 1 << 27
};
}
@@ -0,0 +1,11 @@
#pragma once
namespace RE
{
enum class UI_MESSAGE_RESULTS : std::int32_t
{
kHandled = 0x0,
kIgnore = 0x1,
kPassOn = 0x2
};
}
@@ -0,0 +1,22 @@
#pragma once
namespace RE
{
enum class UI_MESSAGE_TYPE : std::int32_t
{
kUpdate = 0x0,
kShow = 0x1,
kReshow = 0x2,
kHide = 0x3,
kForceHide = 0x4,
kScaleformEvent = 0x5,
kUserEvent = 0x6,
kInventoryUpdate = 0x7,
kUserProfileChange = 0x8,
kMUStatusChange = 0x9,
kResumeCaching = 0xA,
kUpdateController = 0xB,
kChatterEvent = 0xC,
kTotal = 0xD
};
}
@@ -0,0 +1,12 @@
#pragma once
namespace RE
{
class __declspec(novtable) UnequipObjectFunctor
{
public:
// members
Actor* actor; // 00
};
static_assert(sizeof(UnequipObjectFunctor) == 0x08);
}
@@ -0,0 +1,14 @@
#pragma once
namespace RE
{
class UniqueNPCData
{
public:
// members
TESNPC* npc; // 00
std::uint32_t refID; // 08
BGSLocation* editorLoc; // 10
};
static_assert(sizeof(UniqueNPCData) == 0x18);
}
@@ -0,0 +1,14 @@
#pragma once
namespace RE
{
class UnloadedRefData
{
public:
// members
std::uint32_t refID; // 0
std::uint32_t parentSpaceID; // 4
std::uint32_t cellKey; // 8
};
static_assert(sizeof(UnloadedRefData) == 0xC);
}
@@ -0,0 +1,16 @@
#pragma once
#include "RE/U/UserEvents.h"
namespace RE
{
class UserEventEnabledEvent
{
public:
// members
REX::TEnumSet<UserEvents::USER_EVENT_FLAG, std::int32_t> newUserEventFlag; // 0
REX::TEnumSet<UserEvents::USER_EVENT_FLAG, std::int32_t> oldUserEventFlag; // 4
REX::TEnumSet<UserEvents::SENDER_ID, std::int32_t> senderID; // 8
};
static_assert(sizeof(UserEventEnabledEvent) == 0xC);
}
@@ -0,0 +1,74 @@
#pragma once
namespace RE
{
namespace UserEvents
{
enum class INPUT_CONTEXT_ID : std::int32_t
{
kMainGameplay = 0x0,
kBasicMenuNav = 0x1,
kThumbNav = 0x2,
kVirtualController = 0x3,
kCursor = 0x4,
kLThumbCursor = 0x5,
kConsole = 0x6,
kDebugText = 0x7,
kBook = 0x8,
kDebugOverlay = 0x9,
kTFC = 0xA,
kDebugMap = 0xB,
kLockpick = 0xC,
kVATS = 0xD,
kVATSPlayback = 0xE,
kMultiActivate = 0xF,
kWorkshop = 0x10,
kScope = 0x11,
kSitWait = 0x12,
kLooksMenu = 0x13,
kWorkshopAddendum = 0x14,
kPauseMenu = 0x15,
kLevelUpMenu = 0x16,
kLevelUpMenuPrevNext = 0x17,
kMainMenu = 0x18,
kQuickContainerMenu = 0x19,
kSpecialActivateRollover = 0x1A,
kTwoButtonRollover = 0x1B,
kQuickContainerMenuPerk = 0x1C,
kVertibird = 0x1D,
kPlayBinkMenu = 0x1E,
kRobotModAddendum = 0x1F,
kCreationClub = 0x20,
kTotal = 0x21,
kNone = 0x22
};
enum class SENDER_ID : std::int32_t
{
kNone = 0x0,
kGameplay = 0x1,
kMenu = 0x2,
kScript = 0x3
};
enum class USER_EVENT_FLAG : std::int32_t
{
kAll = static_cast<std::underlying_type_t<USER_EVENT_FLAG>>(-1),
kMovement = 1 << 0,
kLooking = 1 << 1,
kActivate = 1 << 2,
kMenu = 1 << 3,
kConsole = 1 << 4,
kPOVSwitch = 1 << 5,
kFighting = 1 << 6,
kSneaking = 1 << 7,
kMainFour = 1 << 8,
kWheelZoom = 1 << 9,
kJumping = 1 << 10,
kVATS = 1 << 11
};
}
}
@@ -0,0 +1,17 @@
#pragma once
#include "RE/B/BSGFxFunctionBase.h"
#include "RE/B/BSTArray.h"
namespace RE
{
class UsesBSGFXFunctionHandler
{
public:
static constexpr auto RTTI{ RTTI::UsesBSGFXFunctionHandler };
// members
BSTArray<std::unique_ptr<BSGFxFunctionBase>> functions; // 00
};
static_assert(sizeof(UsesBSGFXFunctionHandler) == 0x18);
}