Highlight dropped books

This commit is contained in:
Eddoursul 2024-07-07 12:34:40 +02:00
parent a41283638b
commit 1c89562e2a
3 changed files with 83 additions and 45 deletions

View File

@ -6,6 +6,8 @@ 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{};
@ -29,9 +31,24 @@ void EventListener::Install()
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());
RE::TESEffectShader* defaultShader = RE::TESForm::LookupByID<RE::TESEffectShader>(0xC5EF7); RE::TESEffectShader* defaultShader = RE::TESForm::LookupByID<RE::TESEffectShader>(0xC5EF7);
EventListener::regularBookShader = retrieveFormByString(std::any_cast<const char*>(settings["sRegularBookShader"]), defaultShader)->As<RE::TESEffectShader>();
EventListener::spellBookShader = retrieveFormByString(std::any_cast<const char*>(settings["sSpellBookShader"]), defaultShader)->As<RE::TESEffectShader>(); EventListener::regularBookShader = retrieveFormByString(std::any_cast<std::string>(settings["sRegularBookShader"]), defaultShader)->As<RE::TESEffectShader>();
EventListener::skillBookShader = retrieveFormByString(std::any_cast<const char*>(settings["sSkillBookShader"]), defaultShader)->As<RE::TESEffectShader>(); EventListener::spellBookShader = retrieveFormByString(std::any_cast<std::string>(settings["sSpellBookShader"]), 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(
@ -52,27 +69,7 @@ auto EventListener::ProcessEvent(
-> RE::BSEventNotifyControl -> RE::BSEventNotifyControl
{ {
if (a_event && a_event->attached && a_event->reference) { if (a_event && a_event->attached && a_event->reference) {
if (const auto baseObj = a_event->reference->GetBaseObject(); baseObj->IsBook()) { TryAddBookRefShader(a_event->reference.get());
if (const auto bookObj = baseObj->As<RE::TESObjectBOOK>()) {
if (!bookObj->IsRead()) {
RE::TESObjectREFR* ref = a_event->reference.get();
auto shader = EventListener::regularBookShader;
if (bookObj->TeachesSpell()) {
shader = EventListener::spellBookShader;
} else if (bookObj->TeachesSkill()) {
shader = EventListener::skillBookShader;
}
SKSE::GetTaskInterface()->AddTask([ref, shader]() {
if (ref) {
ref->ApplyEffectShader(shader);
}
});
}
}
}
} }
return RE::BSEventNotifyControl::kContinue; return RE::BSEventNotifyControl::kContinue;
@ -83,9 +80,30 @@ auto EventListener::ProcessEvent(
RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource) RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource)
-> RE::BSEventNotifyControl -> RE::BSEventNotifyControl
{ {
if (a_event && !a_event->opening && a_event->menuName == RE::BookMenu::MENU_NAME) { if (a_event) {
if (a_event->opening) {
if (a_event->menuName == RE::InventoryMenu::MENU_NAME) {
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); SKSE::GetTaskInterface()->AddTask(ClearOldShaders);
} }
}
}
return RE::BSEventNotifyControl::kContinue; return RE::BSEventNotifyControl::kContinue;
} }

View File

@ -1,6 +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::TESCellAttachDetachEvent>,
public RE::BSTEventSink<RE::MenuOpenCloseEvent> public RE::BSTEventSink<RE::MenuOpenCloseEvent>
@ -15,6 +16,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)

View File

@ -2,6 +2,33 @@
#include "EventListener.h" #include "EventListener.h"
inline void TryAddBookRefShader(RE::TESObjectREFR* a_ref)
{
if (!a_ref) {
return;
}
if (const auto baseObj = a_ref->GetBaseObject(); baseObj->IsBook()) {
if (const auto bookObj = baseObj->As<RE::TESObjectBOOK>()) {
if (!bookObj->IsRead()) {
auto shader = EventListener::regularBookShader;
if (bookObj->TeachesSpell()) {
shader = EventListener::spellBookShader;
} else if (bookObj->TeachesSkill()) {
shader = EventListener::skillBookShader;
}
SKSE::GetTaskInterface()->AddTask([a_ref, shader]() {
if (a_ref) {
a_ref->ApplyEffectShader(shader);
}
});
}
}
}
}
inline void ClearOldShaders() inline void ClearOldShaders()
{ {
if (const auto processLists = RE::ProcessLists::GetSingleton()) { if (const auto processLists = RE::ProcessLists::GetSingleton()) {
@ -21,31 +48,18 @@ inline void ClearOldShaders()
} }
} }
// std::string str = "adsf+qwer+poui+fdgh"; inline RE::TESForm* retrieveFormByString(std::string a_str, RE::TESForm* a_defaultForm)
// std::vector<std::string> v = split (str, '+');
inline std::vector<std::string> split(const std::string& s, char delim)
{ {
std::vector<std::string> result; int pos = a_str.find_first_of('@');
std::stringstream ss(s); std::string sHex = a_str.substr(pos + 1),
std::string item; sFilename = a_str.substr(0, pos);
while (getline(ss, item, delim)) {
result.push_back(item);
}
return result;
}
inline RE::TESForm* retrieveFormByString(const char* a_str, RE::TESForm* a_defaultForm)
{
std::vector<std::string> segments = split(a_str, '@');
RE::FormID id; RE::FormID id;
std::stringstream ss; std::stringstream ss;
ss << std::hex << segments[1]; ss << std::hex << sHex;
ss >> id; ss >> id;
RE::TESForm* result = RE::TESDataHandler::GetSingleton()->LookupForm(id, segments[0]); RE::TESForm* result = RE::TESDataHandler::GetSingleton()->LookupForm(id, sFilename);
if (!result) { if (!result) {
logger::error("Unable to retrieve {}, using default value", a_str); logger::error("Unable to retrieve {}, using default value", a_str);