Use a Load3D hook
This commit is contained in:
parent
1c89562e2a
commit
2b38e77101
@ -1,13 +1,12 @@
|
|||||||
#include "EventListener.h"
|
#include "EventListener.h"
|
||||||
#include "IniLoader.h"
|
#include "IniLoader.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
#include "Hooks.h"
|
||||||
|
|
||||||
RE::TESEffectShader* EventListener::regularBookShader;
|
RE::TESEffectShader* EventListener::regularBookShader;
|
||||||
RE::TESEffectShader* EventListener::spellBookShader;
|
RE::TESEffectShader* EventListener::spellBookShader;
|
||||||
RE::TESEffectShader* EventListener::skillBookShader;
|
RE::TESEffectShader* EventListener::skillBookShader;
|
||||||
|
|
||||||
inline bool bScanDroppedBooks = false;
|
|
||||||
|
|
||||||
auto EventListener::GetSingleton() -> EventListener*
|
auto EventListener::GetSingleton() -> EventListener*
|
||||||
{
|
{
|
||||||
static EventListener singleton{};
|
static EventListener singleton{};
|
||||||
@ -18,14 +17,15 @@ void EventListener::Install()
|
|||||||
{
|
{
|
||||||
logger::info("{} is initializing...", SKSE::PluginDeclaration::GetSingleton()->GetName());
|
logger::info("{} is initializing...", SKSE::PluginDeclaration::GetSingleton()->GetName());
|
||||||
|
|
||||||
RE::ScriptEventSourceHolder::GetSingleton()->GetEventSource<RE::TESCellAttachDetachEvent>()->AddEventSink(EventListener::GetSingleton());
|
SetBookShaderHook::Install();
|
||||||
|
|
||||||
RE::PlayerCharacter::GetSingleton()->AsBGSActorCellEventSource()->AddEventSink(EventListener::GetSingleton());
|
RE::PlayerCharacter::GetSingleton()->AsBGSActorCellEventSource()->AddEventSink(EventListener::GetSingleton());
|
||||||
RE::UI::GetSingleton()->AddEventSink<RE::MenuOpenCloseEvent>(EventListener::GetSingleton());
|
RE::UI::GetSingleton()->AddEventSink<RE::MenuOpenCloseEvent>(EventListener::GetSingleton());
|
||||||
|
|
||||||
std::map<std::string, std::any> settings{
|
std::map<std::string, std::any> settings{
|
||||||
{ "sRegularBookShader", "Skyrim.esm@D2057" },
|
{ "sRegularBookShader", "Skyrim.esm@C723A" },
|
||||||
{ "sSpellBookShader", "Skyrim.esm@C5EF7" },
|
{ "sSpellBookShader", "Skyrim.esm@B6BF9" },
|
||||||
{ "sSkillBookShader", "Skyrim.esm@C34B1" },
|
{ "sSkillBookShader", "Skyrim.esm@B6BFA" },
|
||||||
};
|
};
|
||||||
|
|
||||||
LoadINI(&settings, std::format("Data/SKSE/Plugins/{}.ini", SKSE::PluginDeclaration::GetSingleton()->GetName()).c_str());
|
LoadINI(&settings, std::format("Data/SKSE/Plugins/{}.ini", SKSE::PluginDeclaration::GetSingleton()->GetName()).c_str());
|
||||||
@ -37,39 +37,13 @@ void EventListener::Install()
|
|||||||
EventListener::skillBookShader = retrieveFormByString(std::any_cast<std::string>(settings["sSkillBookShader"]), defaultShader)->As<RE::TESEffectShader>();
|
EventListener::skillBookShader = retrieveFormByString(std::any_cast<std::string>(settings["sSkillBookShader"]), defaultShader)->As<RE::TESEffectShader>();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EventListener::ProcessEvent(
|
|
||||||
const RE::TESContainerChangedEvent* a_event,
|
|
||||||
RE::BSTEventSource<RE::TESContainerChangedEvent>* a_eventSource)
|
|
||||||
-> RE::BSEventNotifyControl
|
|
||||||
{
|
|
||||||
if (!a_event->newContainer && a_event->oldContainer == 0x14) {
|
|
||||||
if (const auto baseObj = RE::TESForm::LookupByID(a_event->baseObj); baseObj->Is(RE::FormType::Book)) {
|
|
||||||
bScanDroppedBooks = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RE::BSEventNotifyControl::kContinue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto EventListener::ProcessEvent(
|
auto EventListener::ProcessEvent(
|
||||||
const RE::BGSActorCellEvent* a_event,
|
const RE::BGSActorCellEvent* a_event,
|
||||||
RE::BSTEventSource<RE::BGSActorCellEvent>* a_eventSource)
|
RE::BSTEventSource<RE::BGSActorCellEvent>* a_eventSource)
|
||||||
-> RE::BSEventNotifyControl
|
-> RE::BSEventNotifyControl
|
||||||
{
|
{
|
||||||
if (a_event->flags == RE::BGSActorCellEvent::CellFlag::kEnter) {
|
if (a_event->flags == RE::BGSActorCellEvent::CellFlag::kEnter) {
|
||||||
SKSE::GetTaskInterface()->AddTask(ClearOldShaders);
|
ClearOldShaders();
|
||||||
}
|
|
||||||
|
|
||||||
return RE::BSEventNotifyControl::kContinue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto EventListener::ProcessEvent(
|
|
||||||
const RE::TESCellAttachDetachEvent* a_event,
|
|
||||||
RE::BSTEventSource<RE::TESCellAttachDetachEvent>* a_eventSource)
|
|
||||||
-> RE::BSEventNotifyControl
|
|
||||||
{
|
|
||||||
if (a_event && a_event->attached && a_event->reference) {
|
|
||||||
TryAddBookRefShader(a_event->reference.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return RE::BSEventNotifyControl::kContinue;
|
return RE::BSEventNotifyControl::kContinue;
|
||||||
@ -80,28 +54,9 @@ auto EventListener::ProcessEvent(
|
|||||||
RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource)
|
RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource)
|
||||||
-> RE::BSEventNotifyControl
|
-> RE::BSEventNotifyControl
|
||||||
{
|
{
|
||||||
if (a_event) {
|
if (a_event && !a_event->opening) {
|
||||||
if (a_event->opening) {
|
if (a_event->menuName == RE::BookMenu::MENU_NAME) {
|
||||||
if (a_event->menuName == RE::InventoryMenu::MENU_NAME) {
|
ClearOldShaders();
|
||||||
RE::ScriptEventSourceHolder::GetSingleton()->GetEventSource<RE::TESContainerChangedEvent>()->AddEventSink(EventListener::GetSingleton());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (a_event->menuName == RE::InventoryMenu::MENU_NAME) {
|
|
||||||
RE::ScriptEventSourceHolder::GetSingleton()->GetEventSource<RE::TESContainerChangedEvent>()->RemoveEventSink(EventListener::GetSingleton());
|
|
||||||
|
|
||||||
if (bScanDroppedBooks) {
|
|
||||||
bScanDroppedBooks = false;
|
|
||||||
if (const auto TES = RE::TES::GetSingleton()) {
|
|
||||||
TES->ForEachReferenceInRange(RE::PlayerCharacter::GetSingleton(), 300.0f, [](RE::TESObjectREFR* a_ref) {
|
|
||||||
TryAddBookRefShader(a_ref);
|
|
||||||
return RE::BSContainer::ForEachResult::kContinue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (a_event->menuName == RE::BookMenu::MENU_NAME) {
|
|
||||||
SKSE::GetTaskInterface()->AddTask(ClearOldShaders);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class EventListener :
|
class EventListener :
|
||||||
public RE::BSTEventSink<RE::TESContainerChangedEvent>,
|
|
||||||
public RE::BSTEventSink<RE::BGSActorCellEvent>,
|
public RE::BSTEventSink<RE::BGSActorCellEvent>,
|
||||||
public RE::BSTEventSink<RE::TESCellAttachDetachEvent>,
|
|
||||||
public RE::BSTEventSink<RE::MenuOpenCloseEvent>
|
public RE::BSTEventSink<RE::MenuOpenCloseEvent>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -16,21 +14,11 @@ public:
|
|||||||
|
|
||||||
static void Install();
|
static void Install();
|
||||||
|
|
||||||
auto ProcessEvent(
|
|
||||||
const RE::TESContainerChangedEvent* a_event,
|
|
||||||
RE::BSTEventSource<RE::TESContainerChangedEvent>* a_eventSource)
|
|
||||||
-> RE::BSEventNotifyControl override;
|
|
||||||
|
|
||||||
auto ProcessEvent(
|
auto ProcessEvent(
|
||||||
const RE::BGSActorCellEvent* a_event,
|
const RE::BGSActorCellEvent* a_event,
|
||||||
RE::BSTEventSource<RE::BGSActorCellEvent>* a_eventSource)
|
RE::BSTEventSource<RE::BGSActorCellEvent>* a_eventSource)
|
||||||
-> RE::BSEventNotifyControl override;
|
-> RE::BSEventNotifyControl override;
|
||||||
|
|
||||||
auto ProcessEvent(
|
|
||||||
const RE::TESCellAttachDetachEvent* a_event,
|
|
||||||
RE::BSTEventSource<RE::TESCellAttachDetachEvent>* a_eventSource)
|
|
||||||
-> RE::BSEventNotifyControl override;
|
|
||||||
|
|
||||||
auto ProcessEvent(
|
auto ProcessEvent(
|
||||||
const RE::MenuOpenCloseEvent* a_event,
|
const RE::MenuOpenCloseEvent* a_event,
|
||||||
RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource)
|
RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource)
|
||||||
|
24
src/Hooks.h
Normal file
24
src/Hooks.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Util.h"
|
||||||
|
|
||||||
|
struct SetBookShaderHook
|
||||||
|
{
|
||||||
|
static RE::NiAVObject* thunk(RE::TESObjectREFR& a_this, bool a_loadInBackground)
|
||||||
|
{
|
||||||
|
const auto ret = func(a_this, a_loadInBackground);
|
||||||
|
|
||||||
|
TryAddBookRefShader(&a_this);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline REL::Relocation<decltype(thunk)> func;
|
||||||
|
|
||||||
|
static void Install()
|
||||||
|
{
|
||||||
|
REL::Relocation<uintptr_t> vTable(RE::TESObjectREFR::VTABLE[0]);
|
||||||
|
func = vTable.write_vfunc(0x6A, thunk); // NiAVObject* Load3D(bool a_backgroundLoading)
|
||||||
|
logger::info("Added book shader hook");
|
||||||
|
}
|
||||||
|
};
|
@ -31,6 +31,7 @@ inline void TryAddBookRefShader(RE::TESObjectREFR* a_ref)
|
|||||||
|
|
||||||
inline void ClearOldShaders()
|
inline void ClearOldShaders()
|
||||||
{
|
{
|
||||||
|
SKSE::GetTaskInterface()->AddTask([]() {
|
||||||
if (const auto processLists = RE::ProcessLists::GetSingleton()) {
|
if (const auto processLists = RE::ProcessLists::GetSingleton()) {
|
||||||
processLists->ForEachShaderEffect([&](RE::ShaderReferenceEffect* a_shaderEffect) -> RE::BSContainer::ForEachResult {
|
processLists->ForEachShaderEffect([&](RE::ShaderReferenceEffect* a_shaderEffect) -> RE::BSContainer::ForEachResult {
|
||||||
if (a_shaderEffect && (a_shaderEffect->effectData == EventListener::regularBookShader || a_shaderEffect->effectData == EventListener::spellBookShader || a_shaderEffect->effectData == EventListener::skillBookShader) && a_shaderEffect->target) {
|
if (a_shaderEffect && (a_shaderEffect->effectData == EventListener::regularBookShader || a_shaderEffect->effectData == EventListener::spellBookShader || a_shaderEffect->effectData == EventListener::skillBookShader) && a_shaderEffect->target) {
|
||||||
@ -42,10 +43,10 @@ inline void ClearOldShaders()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return RE::BSContainer::ForEachResult::kContinue;
|
return RE::BSContainer::ForEachResult::kContinue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline RE::TESForm* retrieveFormByString(std::string a_str, RE::TESForm* a_defaultForm)
|
inline RE::TESForm* retrieveFormByString(std::string a_str, RE::TESForm* a_defaultForm)
|
||||||
|
Loading…
Reference in New Issue
Block a user