Highlight dropped books
This commit is contained in:
parent
a41283638b
commit
1c89562e2a
@ -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,8 +80,29 @@ 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) {
|
||||||
SKSE::GetTaskInterface()->AddTask(ClearOldShaders);
|
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;
|
return RE::BSEventNotifyControl::kContinue;
|
||||||
|
@ -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)
|
||||||
|
52
src/Util.h
52
src/Util.h
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user