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::skillBookShader;
inline bool bScanDroppedBooks = false;
auto EventListener::GetSingleton() -> EventListener*
{
static EventListener singleton{};
@ -29,9 +31,24 @@ void EventListener::Install()
LoadINI(&settings, std::format("Data/SKSE/Plugins/{}.ini", SKSE::PluginDeclaration::GetSingleton()->GetName()).c_str());
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::skillBookShader = retrieveFormByString(std::any_cast<const char*>(settings["sSkillBookShader"]), defaultShader)->As<RE::TESEffectShader>();
EventListener::regularBookShader = retrieveFormByString(std::any_cast<std::string>(settings["sRegularBookShader"]), 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(
@ -52,27 +69,7 @@ auto EventListener::ProcessEvent(
-> RE::BSEventNotifyControl
{
if (a_event && a_event->attached && a_event->reference) {
if (const auto baseObj = a_event->reference->GetBaseObject(); baseObj->IsBook()) {
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);
}
});
}
}
}
TryAddBookRefShader(a_event->reference.get());
}
return RE::BSEventNotifyControl::kContinue;
@ -83,8 +80,29 @@ auto EventListener::ProcessEvent(
RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource)
-> RE::BSEventNotifyControl
{
if (a_event && !a_event->opening && a_event->menuName == RE::BookMenu::MENU_NAME) {
SKSE::GetTaskInterface()->AddTask(ClearOldShaders);
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);
}
}
}
return RE::BSEventNotifyControl::kContinue;

View File

@ -1,6 +1,7 @@
#pragma once
class EventListener :
public RE::BSTEventSink<RE::TESContainerChangedEvent>,
public RE::BSTEventSink<RE::BGSActorCellEvent>,
public RE::BSTEventSink<RE::TESCellAttachDetachEvent>,
public RE::BSTEventSink<RE::MenuOpenCloseEvent>
@ -15,6 +16,11 @@ public:
static void Install();
auto ProcessEvent(
const RE::TESContainerChangedEvent* a_event,
RE::BSTEventSource<RE::TESContainerChangedEvent>* a_eventSource)
-> RE::BSEventNotifyControl override;
auto ProcessEvent(
const RE::BGSActorCellEvent* a_event,
RE::BSTEventSource<RE::BGSActorCellEvent>* a_eventSource)

View File

@ -2,6 +2,33 @@
#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()
{
if (const auto processLists = RE::ProcessLists::GetSingleton()) {
@ -21,31 +48,18 @@ inline void ClearOldShaders()
}
}
// std::string str = "adsf+qwer+poui+fdgh";
// std::vector<std::string> v = split (str, '+');
inline std::vector<std::string> split(const std::string& s, char delim)
inline RE::TESForm* retrieveFormByString(std::string a_str, RE::TESForm* a_defaultForm)
{
std::vector<std::string> result;
std::stringstream ss(s);
std::string item;
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, '@');
int pos = a_str.find_first_of('@');
std::string sHex = a_str.substr(pos + 1),
sFilename = a_str.substr(0, pos);
RE::FormID id;
std::stringstream ss;
ss << std::hex << segments[1];
ss << std::hex << sHex;
ss >> id;
RE::TESForm* result = RE::TESDataHandler::GetSingleton()->LookupForm(id, segments[0]);
RE::TESForm* result = RE::TESDataHandler::GetSingleton()->LookupForm(id, sFilename);
if (!result) {
logger::error("Unable to retrieve {}, using default value", a_str);