docs: add plugin setup guide
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
#include "F4SE/API.h"
|
||||
|
||||
#include "F4SE/Interfaces.h"
|
||||
#include "REL/FHookStore.h"
|
||||
#include "REL/Trampoline.h"
|
||||
#include "REX/TSingleton.h"
|
||||
#include "REX/W32/OLE32.h"
|
||||
#include "REX/W32/SHELL32.h"
|
||||
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <spdlog/sinks/msvc_sink.h>
|
||||
#include <spdlog/sinks/rotating_file_sink.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace F4SE
|
||||
{
|
||||
namespace Impl
|
||||
{
|
||||
struct API :
|
||||
public REX::TSingleton<API>
|
||||
{
|
||||
void Init(InitInfo, const F4SE::QueryInterface* a_intfc);
|
||||
void InitLog();
|
||||
void InitTrampoline();
|
||||
void InitHook(REL::EHookStep a_step);
|
||||
|
||||
InitInfo info;
|
||||
|
||||
std::string pluginName{};
|
||||
std::string pluginAuthor{};
|
||||
REL::Version pluginVersion{};
|
||||
|
||||
REL::Version f4seVersion{};
|
||||
PluginHandle pluginHandle{ static_cast<PluginHandle>(-1) };
|
||||
std::uint32_t releaseIndex{ 0 };
|
||||
std::function<const void*(const char*)> pluginInfoAccessor;
|
||||
std::string_view saveFolderName{};
|
||||
|
||||
MessagingInterface* messagingInterface{ nullptr };
|
||||
ScaleformInterface* scaleformInterface{ nullptr };
|
||||
PapyrusInterface* papyrusInterface{ nullptr };
|
||||
SerializationInterface* serializationInterface{ nullptr };
|
||||
TaskInterface* taskInterface{ nullptr };
|
||||
ObjectInterface* objectInterface{ nullptr };
|
||||
TrampolineInterface* trampolineInterface{ nullptr };
|
||||
};
|
||||
|
||||
void API::Init(InitInfo a_info, const F4SE::QueryInterface* a_intfc)
|
||||
{
|
||||
info = a_info;
|
||||
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]() {
|
||||
if (const auto data = PluginVersionData::GetSingleton()) {
|
||||
pluginName = data->GetPluginName();
|
||||
pluginAuthor = data->GetAuthorName();
|
||||
pluginVersion = data->GetPluginVersion();
|
||||
} else {
|
||||
std::vector<char> buf(REX::W32::MAX_PATH, '\0');
|
||||
const auto size = REX::W32::GetModuleFileNameA(REX::W32::GetCurrentModule(), buf.data(), REX::W32::MAX_PATH);
|
||||
if (size) {
|
||||
std::filesystem::path p(buf.begin(), buf.begin() + size);
|
||||
pluginName = p.stem().string();
|
||||
}
|
||||
}
|
||||
|
||||
f4seVersion = a_intfc->F4SEVersion();
|
||||
pluginHandle = a_intfc->GetPluginHandle();
|
||||
releaseIndex = a_intfc->GetReleaseIndex();
|
||||
pluginInfoAccessor = reinterpret_cast<const Impl::F4SEInterface*>(a_intfc)->GetPluginInfo;
|
||||
saveFolderName = a_intfc->GetSaveFolderName();
|
||||
});
|
||||
}
|
||||
|
||||
void API::InitLog()
|
||||
{
|
||||
if (info.log) {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]() {
|
||||
if (saveFolderName.empty())
|
||||
return;
|
||||
|
||||
wchar_t* knownBuffer{ nullptr };
|
||||
const auto knownResult = REX::W32::SHGetKnownFolderPath(REX::W32::FOLDERID_Documents, REX::W32::KF_FLAG_DEFAULT, nullptr, std::addressof(knownBuffer));
|
||||
std::unique_ptr<wchar_t[], decltype(&REX::W32::CoTaskMemFree)> knownPath(knownBuffer, REX::W32::CoTaskMemFree);
|
||||
if (!knownPath || knownResult != 0) {
|
||||
REX::ERROR("failed to get known folder path");
|
||||
return;
|
||||
}
|
||||
|
||||
std::filesystem::path path = knownPath.get();
|
||||
path /= std::format("My Games/{}/F4SE/{}.log", GetSaveFolderName(), info.logName ? info.logName : GetPluginName());
|
||||
|
||||
std::vector<spdlog::sink_ptr> sinks{
|
||||
std::make_shared<spdlog::sinks::msvc_sink_mt>()
|
||||
};
|
||||
|
||||
if (info.logRotate > 0) {
|
||||
constexpr auto maxSize = std::numeric_limits<std::size_t>::max();
|
||||
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>(path.string(), maxSize, info.logRotate, true));
|
||||
} else {
|
||||
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(path.string(), true));
|
||||
}
|
||||
|
||||
auto logger = std::make_shared<spdlog::logger>("global", sinks.begin(), sinks.end());
|
||||
logger->set_level(static_cast<spdlog::level::level_enum>(info.logLevel));
|
||||
logger->flush_on(static_cast<spdlog::level::level_enum>(info.logLevel));
|
||||
|
||||
spdlog::set_default_logger(std::move(logger));
|
||||
spdlog::set_pattern(info.logPattern ? info.logPattern : "[%T.%e] [%=5t] [%L] %v");
|
||||
|
||||
REX::INFO("{} v{}", GetPluginName(), GetPluginVersion());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void API::InitTrampoline()
|
||||
{
|
||||
if (info.trampoline) {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]() {
|
||||
if (!info.trampolineSize) {
|
||||
const auto hookStore = REL::FHookStore::GetSingleton();
|
||||
info.trampolineSize += hookStore->GetSizeTrampoline();
|
||||
}
|
||||
|
||||
auto& trampoline = REL::GetTrampoline();
|
||||
if (const auto intfc = GetTrampolineInterface()) {
|
||||
if (const auto mem = intfc->AllocateFromBranchPool(info.trampolineSize))
|
||||
trampoline.set_trampoline(mem, info.trampolineSize);
|
||||
else
|
||||
trampoline.create(info.trampolineSize);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void API::InitHook(REL::EHookStep a_step)
|
||||
{
|
||||
if (info.hook) {
|
||||
const auto hookStore = REL::FHookStore::GetSingleton();
|
||||
hookStore->Init();
|
||||
hookStore->Enable(a_step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Init(const PreLoadInterface* a_intfc, InitInfo a_info) noexcept
|
||||
{
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]() {
|
||||
auto api = Impl::API::GetSingleton();
|
||||
api->Init(a_info, a_intfc);
|
||||
api->InitLog();
|
||||
|
||||
api->trampolineInterface = a_intfc->QueryInterface<TrampolineInterface>(PreLoadInterface::kTrampoline);
|
||||
|
||||
api->InitTrampoline();
|
||||
api->InitHook(REL::EHookStep::PreLoad);
|
||||
});
|
||||
}
|
||||
|
||||
void Init(const LoadInterface* a_intfc, InitInfo a_info) noexcept
|
||||
{
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]() {
|
||||
auto api = Impl::API::GetSingleton();
|
||||
api->Init(a_info, a_intfc);
|
||||
api->InitLog();
|
||||
|
||||
api->messagingInterface = a_intfc->QueryInterface<MessagingInterface>(LoadInterface::kMessaging);
|
||||
api->scaleformInterface = a_intfc->QueryInterface<ScaleformInterface>(LoadInterface::kScaleform);
|
||||
api->papyrusInterface = a_intfc->QueryInterface<PapyrusInterface>(LoadInterface::kPapyrus);
|
||||
api->serializationInterface = a_intfc->QueryInterface<SerializationInterface>(LoadInterface::kSerialization);
|
||||
api->taskInterface = a_intfc->QueryInterface<TaskInterface>(LoadInterface::kTask);
|
||||
api->objectInterface = a_intfc->QueryInterface<ObjectInterface>(LoadInterface::kObject);
|
||||
api->trampolineInterface = a_intfc->QueryInterface<TrampolineInterface>(LoadInterface::kTrampoline);
|
||||
|
||||
api->InitTrampoline();
|
||||
api->InitHook(REL::EHookStep::Load);
|
||||
});
|
||||
}
|
||||
|
||||
REL::Version GetF4SEVersion() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->f4seVersion;
|
||||
}
|
||||
|
||||
std::string_view GetPluginName() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->pluginName;
|
||||
}
|
||||
|
||||
std::string_view GetPluginAuthor() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->pluginAuthor;
|
||||
}
|
||||
|
||||
REL::Version GetPluginVersion() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->pluginVersion;
|
||||
}
|
||||
|
||||
PluginHandle GetPluginHandle() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->pluginHandle;
|
||||
}
|
||||
|
||||
const PluginInfo* GetPluginInfo(std::string_view a_plugin) noexcept
|
||||
{
|
||||
if (const auto& accessor = Impl::API::GetSingleton()->pluginInfoAccessor) {
|
||||
if (const auto result = accessor(a_plugin.data())) {
|
||||
return static_cast<const PluginInfo*>(result);
|
||||
}
|
||||
}
|
||||
|
||||
REX::ERROR("failed to get plugin info for {}", a_plugin);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::uint32_t GetReleaseIndex() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->releaseIndex;
|
||||
}
|
||||
|
||||
std::string_view GetSaveFolderName() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->saveFolderName;
|
||||
}
|
||||
|
||||
const MessagingInterface* GetMessagingInterface() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->messagingInterface;
|
||||
}
|
||||
|
||||
const ScaleformInterface* GetScaleformInterface() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->scaleformInterface;
|
||||
}
|
||||
|
||||
const PapyrusInterface* GetPapyrusInterface() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->papyrusInterface;
|
||||
}
|
||||
|
||||
const SerializationInterface* GetSerializationInterface() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->serializationInterface;
|
||||
}
|
||||
|
||||
const TaskInterface* GetTaskInterface() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->taskInterface;
|
||||
}
|
||||
|
||||
const ObjectInterface* GetObjectInterface() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->objectInterface;
|
||||
}
|
||||
|
||||
const TrampolineInterface* GetTrampolineInterface() noexcept
|
||||
{
|
||||
return Impl::API::GetSingleton()->trampolineInterface;
|
||||
}
|
||||
}
|
||||
|
||||
namespace F4SE
|
||||
{
|
||||
void Init(const LoadInterface* a_intfc, const bool a_log) noexcept
|
||||
{
|
||||
Init(a_intfc, { .log = a_log });
|
||||
}
|
||||
|
||||
void AllocTrampoline(std::size_t a_size) noexcept
|
||||
{
|
||||
auto api = Impl::API::GetSingleton();
|
||||
api->info.trampoline = true;
|
||||
api->info.trampolineSize = a_size;
|
||||
api->InitTrampoline();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "F4SE/Impl/PCH.h"
|
||||
@@ -0,0 +1,193 @@
|
||||
#include "F4SE/InputMap.h"
|
||||
|
||||
#include "RE/C/ControlMap.h"
|
||||
#include "RE/P/PC_GAMEPAD_TYPE.h"
|
||||
|
||||
#include "REX/PS4/SCEPAD.h"
|
||||
#include "REX/W32/DINPUT.h"
|
||||
#include "REX/W32/USER32.h"
|
||||
#include "REX/W32/XINPUT.h"
|
||||
|
||||
namespace F4SE
|
||||
{
|
||||
std::uint32_t InputMap::XInputToScePadOffset(std::uint32_t keyMask)
|
||||
{
|
||||
switch (keyMask) {
|
||||
case REX::W32::XINPUT_GAMEPAD_DPAD_UP:
|
||||
return REX::PS4::SCE_PAD_BUTTON_UP;
|
||||
case REX::W32::XINPUT_GAMEPAD_DPAD_DOWN:
|
||||
return REX::PS4::SCE_PAD_BUTTON_DOWN;
|
||||
case REX::W32::XINPUT_GAMEPAD_DPAD_LEFT:
|
||||
return REX::PS4::SCE_PAD_BUTTON_LEFT;
|
||||
case REX::W32::XINPUT_GAMEPAD_DPAD_RIGHT:
|
||||
return REX::PS4::SCE_PAD_BUTTON_RIGHT;
|
||||
case REX::W32::XINPUT_GAMEPAD_START:
|
||||
return REX::PS4::SCE_PAD_BUTTON_OPTIONS;
|
||||
case REX::W32::XINPUT_GAMEPAD_BACK:
|
||||
return REX::PS4::SCE_PAD_BUTTON_TOUCH_PAD;
|
||||
case REX::W32::XINPUT_GAMEPAD_LEFT_THUMB:
|
||||
return REX::PS4::SCE_PAD_BUTTON_L3;
|
||||
case REX::W32::XINPUT_GAMEPAD_RIGHT_THUMB:
|
||||
return REX::PS4::SCE_PAD_BUTTON_R3;
|
||||
case REX::W32::XINPUT_GAMEPAD_LEFT_SHOULDER:
|
||||
return REX::PS4::SCE_PAD_BUTTON_L1;
|
||||
case REX::W32::XINPUT_GAMEPAD_RIGHT_SHOULDER:
|
||||
return REX::PS4::SCE_PAD_BUTTON_R1;
|
||||
case REX::W32::XINPUT_GAMEPAD_A:
|
||||
return REX::PS4::SCE_PAD_BUTTON_CROSS;
|
||||
case REX::W32::XINPUT_GAMEPAD_B:
|
||||
return REX::PS4::SCE_PAD_BUTTON_CIRCLE;
|
||||
case REX::W32::XINPUT_GAMEPAD_X:
|
||||
return REX::PS4::SCE_PAD_BUTTON_SQUARE;
|
||||
case REX::W32::XINPUT_GAMEPAD_Y:
|
||||
return REX::PS4::SCE_PAD_BUTTON_TRIANGLE;
|
||||
default:
|
||||
return keyMask;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t InputMap::ScePadOffsetToXInput(std::uint32_t keyMask)
|
||||
{
|
||||
switch (keyMask) {
|
||||
case REX::PS4::SCE_PAD_BUTTON_UP:
|
||||
return REX::W32::XINPUT_GAMEPAD_DPAD_UP;
|
||||
case REX::PS4::SCE_PAD_BUTTON_DOWN:
|
||||
return REX::W32::XINPUT_GAMEPAD_DPAD_DOWN;
|
||||
case REX::PS4::SCE_PAD_BUTTON_LEFT:
|
||||
return REX::W32::XINPUT_GAMEPAD_DPAD_LEFT;
|
||||
case REX::PS4::SCE_PAD_BUTTON_RIGHT:
|
||||
return REX::W32::XINPUT_GAMEPAD_DPAD_RIGHT;
|
||||
case REX::PS4::SCE_PAD_BUTTON_OPTIONS:
|
||||
return REX::W32::XINPUT_GAMEPAD_START;
|
||||
case REX::PS4::SCE_PAD_BUTTON_TOUCH_PAD:
|
||||
return REX::W32::XINPUT_GAMEPAD_BACK;
|
||||
case REX::PS4::SCE_PAD_BUTTON_L3:
|
||||
return REX::W32::XINPUT_GAMEPAD_LEFT_THUMB;
|
||||
case REX::PS4::SCE_PAD_BUTTON_R3:
|
||||
return REX::W32::XINPUT_GAMEPAD_RIGHT_THUMB;
|
||||
case REX::PS4::SCE_PAD_BUTTON_L1:
|
||||
return REX::W32::XINPUT_GAMEPAD_LEFT_SHOULDER;
|
||||
case REX::PS4::SCE_PAD_BUTTON_R1:
|
||||
return REX::W32::XINPUT_GAMEPAD_RIGHT_SHOULDER;
|
||||
case REX::PS4::SCE_PAD_BUTTON_CROSS:
|
||||
return REX::W32::XINPUT_GAMEPAD_A;
|
||||
case REX::PS4::SCE_PAD_BUTTON_CIRCLE:
|
||||
return REX::W32::XINPUT_GAMEPAD_B;
|
||||
case REX::PS4::SCE_PAD_BUTTON_SQUARE:
|
||||
return REX::W32::XINPUT_GAMEPAD_X;
|
||||
case REX::PS4::SCE_PAD_BUTTON_TRIANGLE:
|
||||
return REX::W32::XINPUT_GAMEPAD_Y;
|
||||
default:
|
||||
return keyMask;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t InputMap::GamepadMaskToKeycode(std::uint32_t keyMask)
|
||||
{
|
||||
if (RE::ControlMap::GetSingleton()->pcGamePadMapType == RE::PC_GAMEPAD_TYPE::kOrbis) {
|
||||
keyMask = ScePadOffsetToXInput(keyMask);
|
||||
}
|
||||
|
||||
switch (keyMask) {
|
||||
case REX::W32::XINPUT_GAMEPAD_DPAD_UP:
|
||||
return kGamepadButtonOffset_DPAD_UP;
|
||||
case REX::W32::XINPUT_GAMEPAD_DPAD_DOWN:
|
||||
return kGamepadButtonOffset_DPAD_DOWN;
|
||||
case REX::W32::XINPUT_GAMEPAD_DPAD_LEFT:
|
||||
return kGamepadButtonOffset_DPAD_LEFT;
|
||||
case REX::W32::XINPUT_GAMEPAD_DPAD_RIGHT:
|
||||
return kGamepadButtonOffset_DPAD_RIGHT;
|
||||
case REX::W32::XINPUT_GAMEPAD_START:
|
||||
return kGamepadButtonOffset_START;
|
||||
case REX::W32::XINPUT_GAMEPAD_BACK:
|
||||
return kGamepadButtonOffset_BACK;
|
||||
case REX::W32::XINPUT_GAMEPAD_LEFT_THUMB:
|
||||
return kGamepadButtonOffset_LEFT_THUMB;
|
||||
case REX::W32::XINPUT_GAMEPAD_RIGHT_THUMB:
|
||||
return kGamepadButtonOffset_RIGHT_THUMB;
|
||||
case REX::W32::XINPUT_GAMEPAD_LEFT_SHOULDER:
|
||||
return kGamepadButtonOffset_LEFT_SHOULDER;
|
||||
case REX::W32::XINPUT_GAMEPAD_RIGHT_SHOULDER:
|
||||
return kGamepadButtonOffset_RIGHT_SHOULDER;
|
||||
case REX::W32::XINPUT_GAMEPAD_A:
|
||||
return kGamepadButtonOffset_A;
|
||||
case REX::W32::XINPUT_GAMEPAD_B:
|
||||
return kGamepadButtonOffset_B;
|
||||
case REX::W32::XINPUT_GAMEPAD_X:
|
||||
return kGamepadButtonOffset_X;
|
||||
case REX::W32::XINPUT_GAMEPAD_Y:
|
||||
return kGamepadButtonOffset_Y;
|
||||
case 0x9: // Left Trigger game-defined ID
|
||||
return kGamepadButtonOffset_LT;
|
||||
case 0xA: // Right Trigger game-defined ID
|
||||
return kGamepadButtonOffset_RT;
|
||||
default:
|
||||
return kMaxMacros; // Invalid
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t InputMap::GamepadKeycodeToMask(std::uint32_t keyCode)
|
||||
{
|
||||
std::uint32_t keyMask;
|
||||
|
||||
switch (keyCode) {
|
||||
case kGamepadButtonOffset_DPAD_UP:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_DPAD_UP;
|
||||
break;
|
||||
case kGamepadButtonOffset_DPAD_DOWN:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_DPAD_DOWN;
|
||||
break;
|
||||
case kGamepadButtonOffset_DPAD_LEFT:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_DPAD_LEFT;
|
||||
break;
|
||||
case kGamepadButtonOffset_DPAD_RIGHT:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_DPAD_RIGHT;
|
||||
break;
|
||||
case kGamepadButtonOffset_START:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_START;
|
||||
break;
|
||||
case kGamepadButtonOffset_BACK:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_BACK;
|
||||
break;
|
||||
case kGamepadButtonOffset_LEFT_THUMB:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_LEFT_THUMB;
|
||||
break;
|
||||
case kGamepadButtonOffset_RIGHT_THUMB:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_RIGHT_THUMB;
|
||||
break;
|
||||
case kGamepadButtonOffset_LEFT_SHOULDER:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_LEFT_SHOULDER;
|
||||
break;
|
||||
case kGamepadButtonOffset_RIGHT_SHOULDER:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_RIGHT_SHOULDER;
|
||||
break;
|
||||
case kGamepadButtonOffset_A:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_A;
|
||||
break;
|
||||
case kGamepadButtonOffset_B:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_B;
|
||||
break;
|
||||
case kGamepadButtonOffset_X:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_X;
|
||||
break;
|
||||
case kGamepadButtonOffset_Y:
|
||||
keyMask = REX::W32::XINPUT_GAMEPAD_Y;
|
||||
break;
|
||||
case kGamepadButtonOffset_LT:
|
||||
keyMask = 0x9; // Left Trigger game-defined ID
|
||||
break;
|
||||
case kGamepadButtonOffset_RT:
|
||||
keyMask = 0xA; // Right Trigger game-defined ID
|
||||
break;
|
||||
default:
|
||||
keyMask = 0xFF; // Invalid
|
||||
break;
|
||||
}
|
||||
|
||||
if (RE::ControlMap::GetSingleton()->pcGamePadMapType == RE::PC_GAMEPAD_TYPE::kOrbis) {
|
||||
keyMask = XInputToScePadOffset(keyMask);
|
||||
}
|
||||
|
||||
return keyMask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
#include "F4SE/Interfaces.h"
|
||||
|
||||
#include "F4SE/API.h"
|
||||
|
||||
#include "REX/W32/KERNEL32.h"
|
||||
|
||||
namespace F4SE
|
||||
{
|
||||
bool MessagingInterface::RegisterListener(EventCallback* a_handler, std::string_view a_sender) const
|
||||
{
|
||||
const auto success = GetProxy().RegisterListener(GetPluginHandle(), a_sender.data(), reinterpret_cast<void*>(a_handler));
|
||||
if (!success) {
|
||||
REX::ERROR("failed to register listener for {}", a_sender);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MessagingInterface::Dispatch(std::uint32_t a_messageType, void* a_data, std::uint32_t a_dataLen, const char* a_receiver) const
|
||||
{
|
||||
const auto success = GetProxy().Dispatch(GetPluginHandle(), a_messageType, a_data, a_dataLen, a_receiver);
|
||||
if (!success) {
|
||||
REX::ERROR("failed to dispatch to {}", (a_receiver ? a_receiver : "all listeners"));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ScaleformInterface::Register(std::string_view a_name, RegisterCallback* a_callback) const
|
||||
{
|
||||
const auto success = GetProxy().Register(a_name.data(), reinterpret_cast<void*>(a_callback));
|
||||
if (!success) {
|
||||
REX::ERROR("failed to register {}", a_name);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void SerializationInterface::SetUniqueID(std::uint32_t a_uid) const
|
||||
{
|
||||
GetProxy().SetUniqueID(GetPluginHandle(), a_uid);
|
||||
}
|
||||
|
||||
void SerializationInterface::SetRevertCallback(EventCallback* a_callback) const
|
||||
{
|
||||
GetProxy().SetRevertCallback(GetPluginHandle(), reinterpret_cast<void*>(a_callback));
|
||||
}
|
||||
|
||||
void SerializationInterface::SetSaveCallback(EventCallback* a_callback) const
|
||||
{
|
||||
GetProxy().SetSaveCallback(GetPluginHandle(), reinterpret_cast<void*>(a_callback));
|
||||
}
|
||||
|
||||
void SerializationInterface::SetLoadCallback(EventCallback* a_callback) const
|
||||
{
|
||||
GetProxy().SetLoadCallback(GetPluginHandle(), reinterpret_cast<void*>(a_callback));
|
||||
}
|
||||
|
||||
void SerializationInterface::SetFormDeleteCallback(FormDeleteCallback* a_callback) const
|
||||
{
|
||||
GetProxy().SetFormDeleteCallback(GetPluginHandle(), reinterpret_cast<void*>(a_callback));
|
||||
}
|
||||
|
||||
bool SerializationInterface::WriteRecord(std::uint32_t a_type, std::uint32_t a_version, const void* a_buf, std::uint32_t a_length) const
|
||||
{
|
||||
const auto success = GetProxy().WriteRecord(a_type, a_version, a_buf, a_length);
|
||||
if (!success) {
|
||||
REX::ERROR("failed to write record");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SerializationInterface::OpenRecord(std::uint32_t a_type, std::uint32_t a_version) const
|
||||
{
|
||||
const auto success = GetProxy().OpenRecord(a_type, a_version);
|
||||
if (!success) {
|
||||
REX::ERROR("failed to open record");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SerializationInterface::WriteRecordData(const void* a_buf, std::uint32_t a_length) const
|
||||
{
|
||||
const auto success = GetProxy().WriteRecordData(a_buf, a_length);
|
||||
if (!success) {
|
||||
REX::ERROR("failed to write record data");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SerializationInterface::GetNextRecordInfo(std::uint32_t& a_type, std::uint32_t& a_version, std::uint32_t& a_length) const
|
||||
{
|
||||
return GetProxy().GetNextRecordInfo(std::addressof(a_type), std::addressof(a_version), std::addressof(a_length));
|
||||
}
|
||||
|
||||
std::uint32_t SerializationInterface::ReadRecordData(void* a_buf, std::uint32_t a_length) const
|
||||
{
|
||||
const auto read = GetProxy().ReadRecordData(a_buf, a_length);
|
||||
if (read != a_length) {
|
||||
REX::ERROR("failed to read full record data {}B of {}B", read, a_length);
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
bool PapyrusInterface::Register(RegisterFunctions* a_callback) const
|
||||
{
|
||||
const auto success = GetProxy().Register(reinterpret_cast<void*>(a_callback));
|
||||
if (!success) {
|
||||
REX::ERROR("failed to register callback");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void* TrampolineInterface::AllocateFromBranchPool(std::size_t a_size) const
|
||||
{
|
||||
const auto mem = GetProxy().AllocateFromBranchPool(GetPluginHandle(), a_size);
|
||||
if (!mem) {
|
||||
REX::ERROR("failed to allocate from branch pool");
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
void* TrampolineInterface::AllocateFromLocalPool(std::size_t a_size) const
|
||||
{
|
||||
const auto mem = GetProxy().AllocateFromLocalPool(GetPluginHandle(), a_size);
|
||||
if (!mem) {
|
||||
REX::ERROR("failed to allocate from local pool");
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
const PluginVersionData* PluginVersionData::GetSingleton() noexcept
|
||||
{
|
||||
return reinterpret_cast<const PluginVersionData*>(REX::W32::GetProcAddress(REX::W32::GetCurrentModule(), "F4SEPlugin_Version"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user