From b45d935425d9365a5060c5cb1da1c42f9687fad5 Mon Sep 17 00:00:00 2001 From: Eddoursul Date: Fri, 5 Jul 2024 23:57:56 +0200 Subject: [PATCH] Set shaders with INI --- src/EventListener.cpp | 24 +++++++++++- src/EventListener.h | 6 ++- src/IniLoader.h | 91 +++++++++++++++++++++++++++++++++++++++++++ src/Main.cpp | 12 +++--- src/Util.h | 47 +++++++++++++++++----- 5 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 src/IniLoader.h diff --git a/src/EventListener.cpp b/src/EventListener.cpp index d7f64f6..9999772 100644 --- a/src/EventListener.cpp +++ b/src/EventListener.cpp @@ -1,4 +1,10 @@ #include "EventListener.h" +#include "IniLoader.h" +#include "Util.h" + +RE::TESEffectShader* EventListener::regularBookShader; +RE::TESEffectShader* EventListener::spellBookShader; +RE::TESEffectShader* EventListener::skillBookShader; auto EventListener::GetSingleton() -> EventListener* { @@ -8,10 +14,24 @@ auto EventListener::GetSingleton() -> EventListener* void EventListener::Install() { + logger::info("{} is initializing...", SKSE::PluginDeclaration::GetSingleton()->GetName()); + RE::ScriptEventSourceHolder::GetSingleton()->GetEventSource()->AddEventSink(EventListener::GetSingleton()); + RE::PlayerCharacter::GetSingleton()->AsBGSActorCellEventSource()->AddEventSink(EventListener::GetSingleton()); RE::UI::GetSingleton()->AddEventSink(EventListener::GetSingleton()); - // BGSActorCellEvent is registered on MessagingInterface::kDataLoaded + std::map settings{ + { "sRegularBookShader", "Skyrim.esm@C5EF7" }, + { "sSpellBookShader", "Skyrim.esm@C5EF7" }, + { "sSkillBookShader", "Skyrim.esm@C5EF7" }, + }; + + LoadINI(&settings, std::format("Data/SKSE/Plugins/{}.ini", SKSE::PluginDeclaration::GetSingleton()->GetName()).c_str()); + + RE::TESEffectShader* defaultShader = RE::TESForm::LookupByID(0xC5EF7); + EventListener::regularBookShader = retrieveFormByString(std::any_cast(settings["sRegularBookShader"]), defaultShader)->As(); + EventListener::spellBookShader = retrieveFormByString(std::any_cast(settings["sSpellBookShader"]), defaultShader)->As(); + EventListener::skillBookShader = retrieveFormByString(std::any_cast(settings["sSkillBookShader"]), defaultShader)->As(); } auto EventListener::ProcessEvent( @@ -38,7 +58,7 @@ auto EventListener::ProcessEvent( RE::TESObjectREFR* ref = a_event->reference.get(); SKSE::GetTaskInterface()->AddTask([ref]() { if (ref) { - ref->ApplyEffectShader(GetShader()); + ref->ApplyEffectShader(EventListener::regularBookShader); } }); } diff --git a/src/EventListener.h b/src/EventListener.h index d1d8f27..02004b5 100644 --- a/src/EventListener.h +++ b/src/EventListener.h @@ -1,7 +1,5 @@ #pragma once -#include "Util.h" - class EventListener : public RE::BSTEventSink, public RE::BSTEventSink, @@ -32,6 +30,10 @@ public: RE::BSTEventSource* a_eventSource) -> RE::BSEventNotifyControl override; + static RE::TESEffectShader* regularBookShader; + static RE::TESEffectShader* skillBookShader; + static RE::TESEffectShader* spellBookShader; + private: EventListener() = default; }; diff --git a/src/IniLoader.h b/src/IniLoader.h new file mode 100644 index 0000000..3fecc2c --- /dev/null +++ b/src/IniLoader.h @@ -0,0 +1,91 @@ +#pragma once + +#include +#include + +inline void LoadINI(std::map* settings, const char* iniPath) +{ + for (auto it = settings->begin(); it != settings->end(); it++) { + if (it->first[0] == 'f') { + logger::info("[DEFAULT] {} = {}", it->first, std::any_cast(it->second)); + } else if (it->first[0] == 'i') { + logger::info("[DEFAULT] {} = {}", it->first, std::any_cast(it->second)); + } else if (it->first[0] == 's') { + logger::info("[DEFAULT] {} = {}", it->first, std::any_cast(it->second)); + } else { + logger::info("[DEFAULT] {} = {}", it->first, std::any_cast(it->second)); + } + } + + if (!std::filesystem::exists(iniPath)) { + logger::warn("{} does not exist, using default values.", iniPath); + return; + } + + try { + CSimpleIniA ini; + ini.SetUnicode(false); + ini.SetMultiKey(false); + SI_Error rc = ini.LoadFile(iniPath); + + if (rc < 0) { + logger::error("{}", rc); + return; + } + + std::list keysList; + ini.GetAllKeys("", keysList); + + bool bUpdateINI = false; + for (auto it = settings->begin(); it != settings->end(); it++) { + try { + bool bExists = false; + for (const auto& k : keysList) { + if (it->first == k.pItem) { + if (k.pItem[0] == 'f') { + float fValue = ini.GetDoubleValue("", k.pItem, std::any_cast(settings->at(k.pItem))); + settings->insert_or_assign(k.pItem, fValue); + logger::info("[INI] {} = {}", k.pItem, fValue); + } else if (k.pItem[0] == 'i') { + int iValue = ini.GetLongValue("", k.pItem, std::any_cast(settings->at(k.pItem))); + settings->insert_or_assign(k.pItem, iValue); + logger::info("[INI] {} = {}", k.pItem, iValue); + } else if (k.pItem[0] == 's') { + const char* sValue = ini.GetValue("", k.pItem, std::any_cast(settings->at(k.pItem))); + settings->insert_or_assign(k.pItem, sValue); + logger::info("[INI] {} = {}", k.pItem, sValue); + } else { + bool bValue = ini.GetBoolValue("", k.pItem, std::any_cast(settings->at(k.pItem))); + settings->insert_or_assign(k.pItem, bValue); + logger::info("[INI] {} = {}", k.pItem, bValue); + } + bExists = true; + break; + } + } + if (!bExists) { + if (it->first.c_str()[0] == 'f') { + ini.SetDoubleValue("", it->first.c_str(), std::any_cast(it->second)); + } else if (it->first.c_str()[0] == 'i') { + ini.SetLongValue("", it->first.c_str(), std::any_cast(it->second)); + } else if (it->first.c_str()[0] == 's') { + ini.SetValue("", it->first.c_str(), std::any_cast(it->second)); + } else { + ini.SetBoolValue("", it->first.c_str(), std::any_cast(it->second)); + } + bUpdateINI = true; + } + } catch (const std::exception& e) { + logger::error("[INI] {} = {}", it->first, e.what()); + } + } + + if (bUpdateINI) { + logger::info("New settings detected, adding to {}", iniPath); + ini.SaveFile(iniPath); + } + + } catch (const std::exception& e) { + logger::error("{}", e.what()); + } +} diff --git a/src/Main.cpp b/src/Main.cpp index 99e7840..92c398f 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,4 +1,3 @@ -#include "Util.h" #include "EventListener.h" using namespace SKSE; @@ -39,7 +38,13 @@ namespace { GetMessagingInterface()->RegisterListener([](MessagingInterface::Message* message) { if (message->type == MessagingInterface::kDataLoaded) { - RE::PlayerCharacter::GetSingleton()->AsBGSActorCellEventSource()->AddEventSink(EventListener::GetSingleton()); + EventListener::Install(); + logger::info("{} has finished loading.", PluginDeclaration::GetSingleton()->GetName()); + } else if (message->type == MessagingInterface::kPreLoadGame || message->type == MessagingInterface::kNewGame) { + if (!EventListener::regularBookShader) { + EventListener::Install(); // backup + logger::info("{} has finished loading.", PluginDeclaration::GetSingleton()->GetName()); + } } }); } @@ -55,8 +60,5 @@ SKSEPluginLoad(const LoadInterface* skse) Init(skse); InitializeMessaging(); - EventListener::Install(); - - logger::info("{} has finished loading.", plugin->GetName()); return true; } diff --git a/src/Util.h b/src/Util.h index 095e110..2523d3d 100644 --- a/src/Util.h +++ b/src/Util.h @@ -1,19 +1,12 @@ #pragma once -#include - -inline RE::TESEffectShader* GetShader() -{ - return RE::TESForm::LookupByID(0xC5EF7); -} +#include "EventListener.h" inline void ClearOldShaders() { if (const auto processLists = RE::ProcessLists::GetSingleton()) { - const auto shader = GetShader(); - processLists->ForEachShaderEffect([&](RE::ShaderReferenceEffect* a_shaderEffect) -> RE::BSContainer::ForEachResult { - if (a_shaderEffect && a_shaderEffect->effectData == shader && a_shaderEffect->target) { + if (a_shaderEffect && a_shaderEffect->effectData == EventListener::regularBookShader && a_shaderEffect->target) { if (const auto targetRef = a_shaderEffect->target.get()) { if (const auto baseObj = targetRef->GetBaseObject(); baseObj->IsBook()) { if (baseObj->As()->IsRead()) { @@ -27,3 +20,39 @@ inline void ClearOldShaders() }); } } + +// std::string str = "adsf+qwer+poui+fdgh"; +// std::vector v = split (str, '+'); +inline std::vector split(const std::string& s, char delim) +{ + std::vector 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 segments = split(a_str, '@'); + + RE::FormID id; + std::stringstream ss; + ss << std::hex << segments[1]; + ss >> id; + + RE::TESForm* result = RE::TESDataHandler::GetSingleton()->LookupForm(id, segments[0]); + + if (!result) { + logger::error("Unable to retrieve {}, using default value", a_str); + return a_defaultForm; + } + + logger::info("Successfully retrieved {}", a_str); + + return result; +}