Set shaders with INI
This commit is contained in:
parent
51a25d3cc7
commit
b45d935425
@ -1,4 +1,10 @@
|
|||||||
#include "EventListener.h"
|
#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*
|
auto EventListener::GetSingleton() -> EventListener*
|
||||||
{
|
{
|
||||||
@ -8,10 +14,24 @@ auto EventListener::GetSingleton() -> EventListener*
|
|||||||
|
|
||||||
void EventListener::Install()
|
void EventListener::Install()
|
||||||
{
|
{
|
||||||
|
logger::info("{} is initializing...", SKSE::PluginDeclaration::GetSingleton()->GetName());
|
||||||
|
|
||||||
RE::ScriptEventSourceHolder::GetSingleton()->GetEventSource<RE::TESCellAttachDetachEvent>()->AddEventSink(EventListener::GetSingleton());
|
RE::ScriptEventSourceHolder::GetSingleton()->GetEventSource<RE::TESCellAttachDetachEvent>()->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());
|
||||||
|
|
||||||
// BGSActorCellEvent is registered on MessagingInterface::kDataLoaded
|
std::map<std::string, std::any> 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<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>();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EventListener::ProcessEvent(
|
auto EventListener::ProcessEvent(
|
||||||
@ -38,7 +58,7 @@ auto EventListener::ProcessEvent(
|
|||||||
RE::TESObjectREFR* ref = a_event->reference.get();
|
RE::TESObjectREFR* ref = a_event->reference.get();
|
||||||
SKSE::GetTaskInterface()->AddTask([ref]() {
|
SKSE::GetTaskInterface()->AddTask([ref]() {
|
||||||
if (ref) {
|
if (ref) {
|
||||||
ref->ApplyEffectShader(GetShader());
|
ref->ApplyEffectShader(EventListener::regularBookShader);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Util.h"
|
|
||||||
|
|
||||||
class EventListener :
|
class EventListener :
|
||||||
public RE::BSTEventSink<RE::BGSActorCellEvent>,
|
public RE::BSTEventSink<RE::BGSActorCellEvent>,
|
||||||
public RE::BSTEventSink<RE::TESCellAttachDetachEvent>,
|
public RE::BSTEventSink<RE::TESCellAttachDetachEvent>,
|
||||||
@ -32,6 +30,10 @@ public:
|
|||||||
RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource)
|
RE::BSTEventSource<RE::MenuOpenCloseEvent>* a_eventSource)
|
||||||
-> RE::BSEventNotifyControl override;
|
-> RE::BSEventNotifyControl override;
|
||||||
|
|
||||||
|
static RE::TESEffectShader* regularBookShader;
|
||||||
|
static RE::TESEffectShader* skillBookShader;
|
||||||
|
static RE::TESEffectShader* spellBookShader;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventListener() = default;
|
EventListener() = default;
|
||||||
};
|
};
|
||||||
|
91
src/IniLoader.h
Normal file
91
src/IniLoader.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SimpleIni.h>
|
||||||
|
#include <any>
|
||||||
|
|
||||||
|
inline void LoadINI(std::map<std::string, std::any>* 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<float>(it->second));
|
||||||
|
} else if (it->first[0] == 'i') {
|
||||||
|
logger::info("[DEFAULT] {} = {}", it->first, std::any_cast<int>(it->second));
|
||||||
|
} else if (it->first[0] == 's') {
|
||||||
|
logger::info("[DEFAULT] {} = {}", it->first, std::any_cast<const char*>(it->second));
|
||||||
|
} else {
|
||||||
|
logger::info("[DEFAULT] {} = {}", it->first, std::any_cast<bool>(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<CSimpleIniA::Entry> 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<float>(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<int>(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<const char*>(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<bool>(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<float>(it->second));
|
||||||
|
} else if (it->first.c_str()[0] == 'i') {
|
||||||
|
ini.SetLongValue("", it->first.c_str(), std::any_cast<int>(it->second));
|
||||||
|
} else if (it->first.c_str()[0] == 's') {
|
||||||
|
ini.SetValue("", it->first.c_str(), std::any_cast<const char*>(it->second));
|
||||||
|
} else {
|
||||||
|
ini.SetBoolValue("", it->first.c_str(), std::any_cast<bool>(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());
|
||||||
|
}
|
||||||
|
}
|
12
src/Main.cpp
12
src/Main.cpp
@ -1,4 +1,3 @@
|
|||||||
#include "Util.h"
|
|
||||||
#include "EventListener.h"
|
#include "EventListener.h"
|
||||||
|
|
||||||
using namespace SKSE;
|
using namespace SKSE;
|
||||||
@ -39,7 +38,13 @@ namespace
|
|||||||
{
|
{
|
||||||
GetMessagingInterface()->RegisterListener([](MessagingInterface::Message* message) {
|
GetMessagingInterface()->RegisterListener([](MessagingInterface::Message* message) {
|
||||||
if (message->type == MessagingInterface::kDataLoaded) {
|
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);
|
Init(skse);
|
||||||
InitializeMessaging();
|
InitializeMessaging();
|
||||||
|
|
||||||
EventListener::Install();
|
|
||||||
|
|
||||||
logger::info("{} has finished loading.", plugin->GetName());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
47
src/Util.h
47
src/Util.h
@ -1,19 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SimpleIni.h>
|
#include "EventListener.h"
|
||||||
|
|
||||||
inline RE::TESEffectShader* GetShader()
|
|
||||||
{
|
|
||||||
return RE::TESForm::LookupByID<RE::TESEffectShader>(0xC5EF7);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void ClearOldShaders()
|
inline void ClearOldShaders()
|
||||||
{
|
{
|
||||||
if (const auto processLists = RE::ProcessLists::GetSingleton()) {
|
if (const auto processLists = RE::ProcessLists::GetSingleton()) {
|
||||||
const auto shader = GetShader();
|
|
||||||
|
|
||||||
processLists->ForEachShaderEffect([&](RE::ShaderReferenceEffect* a_shaderEffect) -> RE::BSContainer::ForEachResult {
|
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 targetRef = a_shaderEffect->target.get()) {
|
||||||
if (const auto baseObj = targetRef->GetBaseObject(); baseObj->IsBook()) {
|
if (const auto baseObj = targetRef->GetBaseObject(); baseObj->IsBook()) {
|
||||||
if (baseObj->As<RE::TESObjectBOOK>()->IsRead()) {
|
if (baseObj->As<RE::TESObjectBOOK>()->IsRead()) {
|
||||||
@ -27,3 +20,39 @@ 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)
|
||||||
|
{
|
||||||
|
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, '@');
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user