From dc6420603191477ab50648bd9b89cf88ade6f982 Mon Sep 17 00:00:00 2001 From: Arkadii Hlushchevskyi Date: Tue, 30 Jul 2024 23:48:34 +0300 Subject: [PATCH] Simplified outfit management, by not reverting anything. Distribution is persistent between saves within the same game session, so only actual replacements are tracked and saved in a co-save to be able to revert distributed outfits that are no longer valid in current distribution. --- SPID/include/OutfitManager.h | 16 +----------- SPID/src/Distribute.cpp | 12 ++++----- SPID/src/OutfitManager.cpp | 47 ++++++++---------------------------- 3 files changed, 16 insertions(+), 59 deletions(-) diff --git a/SPID/include/OutfitManager.h b/SPID/include/OutfitManager.h index 1add179..4baa2a3 100644 --- a/SPID/include/OutfitManager.h +++ b/SPID/include/OutfitManager.h @@ -41,13 +41,6 @@ namespace Outfits /// Result of the replacement. ReplacementResult SetDefaultOutfit(RE::Actor*, RE::BGSOutfit*, bool allowOverwrites); - /// - /// Indicates that given actor didn't receive any distributed outfit and will be using the original one. - /// - /// This method helps distinguish cases when there was no outfit distribution for the actor vs when we're reloading the save and replacements cache was cleared. - /// - void UseOriginalOutfit(RE::Actor*); - protected: RE::BSEventNotifyControl ProcessEvent(const RE::TESFormDeleteEvent* a_event, RE::BSTEventSource*) override; @@ -69,11 +62,6 @@ namespace Outfits original(original), distributed(nullptr) {} OutfitReplacement(RE::BGSOutfit* original, RE::BGSOutfit* distributed) : original(original), distributed(distributed) {} - - bool UsesOriginalOutfit() const - { - return original && !distributed; - } }; friend fmt::formatter; @@ -107,9 +95,7 @@ struct fmt::formatter template constexpr auto format(const Outfits::Manager::OutfitReplacement& replacement, FormatContext& a_ctx) { - if (replacement.UsesOriginalOutfit()) { - return fmt::format_to(a_ctx.out(), "♻ {}", *replacement.original); - } else if (replacement.original && replacement.distributed) { + if (replacement.original && replacement.distributed) { if (reverse) { return fmt::format_to(a_ctx.out(), "{} 🔙 {}", *replacement.original, *replacement.distributed); } else { diff --git a/SPID/src/Distribute.cpp b/SPID/src/Distribute.cpp index 481baf8..2cb984e 100644 --- a/SPID/src/Distribute.cpp +++ b/SPID/src/Distribute.cpp @@ -104,13 +104,11 @@ namespace Distribute }, accumulatedForms); - if (!for_first_form( - npcData, forms.outfits, input, [&](auto* a_outfit) { - return Outfits::Manager::GetSingleton()->SetDefaultOutfit(npcData.GetActor(), a_outfit, allowOverwrites) != Outfits::ReplacementResult::Skipped; // terminate as soon as valid outfit is confirmed. - }, - accumulatedForms)) { - Outfits::Manager::GetSingleton()->UseOriginalOutfit(npcData.GetActor()); - } + for_first_form( + npcData, forms.outfits, input, [&](auto* a_outfit) { + return Outfits::Manager::GetSingleton()->SetDefaultOutfit(npcData.GetActor(), a_outfit, allowOverwrites) != Outfits::ReplacementResult::Skipped; // terminate as soon as valid outfit is confirmed. + }, + accumulatedForms); for_first_form( npcData, forms.sleepOutfits, input, [&](auto* a_outfit) { diff --git a/SPID/src/OutfitManager.cpp b/SPID/src/OutfitManager.cpp index dbfbc5b..49c6730 100644 --- a/SPID/src/OutfitManager.cpp +++ b/SPID/src/OutfitManager.cpp @@ -58,9 +58,8 @@ namespace Outfits return false; } - if (!id) { // If ID was 0 it means we don't have the outfit stored in this record. - output = nullptr; - return true; + if (!id) { + return false; } if (!interface->ResolveFormID(id, id)) { @@ -113,7 +112,6 @@ namespace Outfits serializationInterface->SetUniqueID(serializationKey); serializationInterface->SetSaveCallback(Save); serializationInterface->SetLoadCallback(Load); - serializationInterface->SetRevertCallback(Revert); if (const auto scripts = RE::ScriptEventSourceHolder::GetSingleton()) { scripts->AddEventSink(GetSingleton()); @@ -180,16 +178,6 @@ namespace Outfits return ReplacementResult::Set; } - void Manager::UseOriginalOutfit(RE::Actor* actor) - { - if (auto npc = actor->GetActorBase(); npc && npc->defaultOutfit) { - if (replacements.find(actor->formID) != replacements.end()) { - logger::warn("Overwriting replacement for {}", *actor); - } - replacements.try_emplace(actor->formID, npc->defaultOutfit); - } - } - void Manager::Load(SKSE::SerializationInterface* a_interface) { logger::info("{:*^30}", "LOADING"); @@ -230,24 +218,16 @@ namespace Outfits for (const auto& it : loadedReplacements) { const auto& actor = it.first; const auto& replacement = it.second; - - if (auto newIt = newReplacements.find(actor->formID); newIt != newReplacements.end()) { - if (newIt->second.UsesOriginalOutfit()) { // If new replacement uses original outfit - if (!replacement.UsesOriginalOutfit() && replacement.distributed == actor->GetActorBase()->defaultOutfit) { // but previous one doesn't and NPC still wears the distributed outfit + if (auto newIt = newReplacements.find(actor->formID); newIt != newReplacements.end()) { // If we have some new replacement for this actor + newIt->second.original = replacement.original; // we want to forward original outfit from the previous replacement to the new one. (so that a chain of outfits like this A->B->C becomes A->C and we'll be able to revert to the very first outfit) + } else if (replacement.distributed == actor->GetActorBase()->defaultOutfit) { // If there is no new replacement, and an actor is currently wearing the same outfit that was distributed to them last time, we want to revert whatever outfit was in previous replacement #ifndef NDEBUG - logger::info("\tReverting Outfit Replacement for {}", *actor); - logger::info("\t\t{:R}", replacement); + logger::info("\tReverting Outfit Replacement for {}", *actor); + logger::info("\t\t{:R}", replacement); #endif - if (actor->SetDefaultOutfit(replacement.original, false)) { // Having true here causes infinite loading. It seems that it works either way. - ++revertedCount; - } - } - } else { // If new replacement - newIt->second.original = replacement.original; // if there was a previous distribution we want to forward original outfit from there to new distribution. + if (actor->SetDefaultOutfit(replacement.original, false)) { // Having true here causes infinite loading. It seems that it works either way. + ++revertedCount; } - - } else { // If there is no new distribution, we want to keep the old one, assuming that whatever outfit is stored in this replacement is what NPC still wears in this save file - newReplacements[actor->formID] = replacement; } } @@ -275,7 +255,7 @@ namespace Outfits } #ifndef NDEBUG if (const auto actor = RE::TESForm::LookupByID(pair.first); actor) { - logger::info("\tSaved Outfit Replacement ({}) for actor {:F}", pair.second, *actor); + logger::info("\tSaved Outfit Replacement ({}) for actor {}", pair.second, *actor); } #endif ++savedCount; @@ -283,11 +263,4 @@ namespace Outfits logger::info("Saved {} names", savedCount); } - - void Manager::Revert(SKSE::SerializationInterface*) - { - logger::info("{:*^30}", "REVERTING"); - /*Manager::GetSingleton()->replacements.clear(); - logger::info("\tOutfit Replacements have been cleared.");*/ - } }