From 4e19ded56f3c45c0b610360a1e42f7539b2e3eeb Mon Sep 17 00:00:00 2001 From: Arkadii Hlushchevskyi Date: Sat, 27 Jul 2024 12:53:59 +0300 Subject: [PATCH] Added formatting for reverse outfit replacements logging --- SPID/include/OutfitManager.h | 42 ++++++++++++++++++++++++++++++------ SPID/src/Distribute.cpp | 2 +- SPID/src/OutfitManager.cpp | 34 ++++++++++++++--------------- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/SPID/include/OutfitManager.h b/SPID/include/OutfitManager.h index 3a3be9c..1add179 100644 --- a/SPID/include/OutfitManager.h +++ b/SPID/include/OutfitManager.h @@ -2,6 +2,16 @@ namespace Outfits { + enum class ReplacementResult + { + /// New outfit for the actor was successfully set. + Set, + /// New outfit for the actor is not valid and was skipped. + Skipped, + /// Outfit for the actor was already set and the new outfit was not allowed to overwrite it. + NotOverwrittable + };; + class Manager : public ISingleton, public RE::BSTEventSink @@ -28,8 +38,8 @@ namespace Outfits /// Target Actor for whom the outfit will be set. /// A new outfit to set as the default. /// If true, the outfit will be set even if the actor already has a distributed outfit. - /// True if the outfit was successfully set, false otherwise. - bool SetDefaultOutfit(RE::Actor*, RE::BGSOutfit*, bool allowOverwrites); + /// 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. @@ -76,20 +86,40 @@ template <> struct fmt::formatter { template - constexpr auto parse(ParseContext& a_ctx) + constexpr auto parse(ParseContext& ctx) { - return a_ctx.begin(); + auto it = ctx.begin(); + auto end = ctx.end(); + + if (it != end && *it == 'R') { + reverse = true; + ++it; + } + + // Check if there are any other format specifiers + if (it != end && *it != '}') { + throw fmt::format_error("OutfitReplacement only supports Reversing format"); + } + + return it; } template constexpr auto format(const Outfits::Manager::OutfitReplacement& replacement, FormatContext& a_ctx) { if (replacement.UsesOriginalOutfit()) { - return fmt::format_to(a_ctx.out(), "NO REPLACEMENT (Uses {})", *replacement.original); + return fmt::format_to(a_ctx.out(), "♻ {}", *replacement.original); } else if (replacement.original && replacement.distributed) { - return fmt::format_to(a_ctx.out(), "{} -> {}", *replacement.original, *replacement.distributed); + if (reverse) { + return fmt::format_to(a_ctx.out(), "{} 🔙 {}", *replacement.original, *replacement.distributed); + } else { + return fmt::format_to(a_ctx.out(), "{} ➡️ {}", *replacement.original, *replacement.distributed); + } } else { return fmt::format_to(a_ctx.out(), "INVALID REPLACEMENT"); } } + +private: + bool reverse = false; }; diff --git a/SPID/src/Distribute.cpp b/SPID/src/Distribute.cpp index 846859e..481baf8 100644 --- a/SPID/src/Distribute.cpp +++ b/SPID/src/Distribute.cpp @@ -106,7 +106,7 @@ namespace Distribute if (!for_first_form( npcData, forms.outfits, input, [&](auto* a_outfit) { - return Outfits::Manager::GetSingleton()->SetDefaultOutfit(npcData.GetActor(), a_outfit, allowOverwrites); + 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()); diff --git a/SPID/src/OutfitManager.cpp b/SPID/src/OutfitManager.cpp index 175811e..dbfbc5b 100644 --- a/SPID/src/OutfitManager.cpp +++ b/SPID/src/OutfitManager.cpp @@ -145,24 +145,28 @@ namespace Outfits return true; } - bool Manager::SetDefaultOutfit(RE::Actor* actor, RE::BGSOutfit* outfit, bool allowOverwrites) + ReplacementResult Manager::SetDefaultOutfit(RE::Actor* actor, RE::BGSOutfit* outfit, bool allowOverwrites) { - if (!actor || !outfit) { - return false; + if (!actor || !outfit) { // invalid call + return ReplacementResult::Skipped; } auto* npc = actor->GetActorBase(); auto defaultOutfit = npc->defaultOutfit; - if (!allowOverwrites && replacements.find(actor->formID) != replacements.end()) { - return true; // return true to indicate that some outfit was already set for this actor, and with overwrite disabled we won't be able to set any outfit. + if (auto existing = replacements.find(actor->formID); existing != replacements.end()) { // we already have tracked replacement + if (outfit == defaultOutfit && outfit == existing->second.distributed) { // if the outfit we are trying to set is already the default one and we have a replacement for it, then we confirm that it was set. + return ReplacementResult::Set; + } else if (!allowOverwrites) { // if we are trying to set any other outfit and overwrites are not allowed, we skip it, indicating overwriting status. + return ReplacementResult::NotOverwrittable; + } } if (!CanEquipOutfit(actor, outfit)) { #ifndef NDEBUG logger::warn("Attempted to equip Outfit that can't be worn by given actor. Actor: {}; Outfit: {}", *actor, *outfit); #endif - return false; + return ReplacementResult::Skipped; } actor->SetDefaultOutfit(outfit, false); // Having true here causes infinite loading. It seems that equipping works either way, so we are good :) @@ -173,7 +177,7 @@ namespace Outfits replacements.try_emplace(actor->formID, defaultOutfit, outfit); } - return true; + return ReplacementResult::Set; } void Manager::UseOriginalOutfit(RE::Actor* actor) @@ -202,12 +206,8 @@ namespace Outfits RE::Actor* actor; RE::BGSOutfit* original; RE::BGSOutfit* distributed; - if (Data::Load(a_interface, actor, original, distributed)) { - OutfitReplacement replacement(original, distributed); -#ifndef NDEBUG - logger::info("\tLoaded Outfit Replacement ({}) for actor {}", replacement, *actor); -#endif - loadedReplacements[actor] = replacement; + if (Data::Load(a_interface, actor, original, distributed); actor) { + loadedReplacements[actor] = {original, distributed}; } } } @@ -236,7 +236,7 @@ namespace Outfits if (!replacement.UsesOriginalOutfit() && replacement.distributed == actor->GetActorBase()->defaultOutfit) { // but previous one doesn't and NPC still wears the distributed outfit #ifndef NDEBUG logger::info("\tReverting Outfit Replacement for {}", *actor); - logger::info("\t\t{}", replacement); + 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; @@ -275,7 +275,7 @@ namespace Outfits } #ifndef NDEBUG if (const auto actor = RE::TESForm::LookupByID(pair.first); actor) { - logger::info("\tSaved Outfit Replacement ({}) for actor {}", pair.second, *actor); + logger::info("\tSaved Outfit Replacement ({}) for actor {:F}", pair.second, *actor); } #endif ++savedCount; @@ -287,7 +287,7 @@ namespace Outfits void Manager::Revert(SKSE::SerializationInterface*) { logger::info("{:*^30}", "REVERTING"); - Manager::GetSingleton()->replacements.clear(); - logger::info("\tOutfit Replacements have been cleared."); + /*Manager::GetSingleton()->replacements.clear(); + logger::info("\tOutfit Replacements have been cleared.");*/ } }