Skip to content

Commit

Permalink
Added formatting for reverse outfit replacements logging
Browse files Browse the repository at this point in the history
  • Loading branch information
adya committed Jul 27, 2024
1 parent 8ff681c commit 4e19ded
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 24 deletions.
42 changes: 36 additions & 6 deletions SPID/include/OutfitManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Manager>,
public RE::BSTEventSink<RE::TESFormDeleteEvent>
Expand All @@ -28,8 +38,8 @@ namespace Outfits
/// <param name="Actor">Target Actor for whom the outfit will be set.</param>
/// <param name="Outfit">A new outfit to set as the default.</param>
/// <param name="allowOverwrites">If true, the outfit will be set even if the actor already has a distributed outfit.</param>
/// <returns>True if the outfit was successfully set, false otherwise.</returns>
bool SetDefaultOutfit(RE::Actor*, RE::BGSOutfit*, bool allowOverwrites);
/// <returns>Result of the replacement.</returns>
ReplacementResult SetDefaultOutfit(RE::Actor*, RE::BGSOutfit*, bool allowOverwrites);

/// <summary>
/// Indicates that given actor didn't receive any distributed outfit and will be using the original one.
Expand Down Expand Up @@ -76,20 +86,40 @@ template <>
struct fmt::formatter<Outfits::Manager::OutfitReplacement>
{
template <class ParseContext>
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 <class FormatContext>
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;
};
2 changes: 1 addition & 1 deletion SPID/src/Distribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ namespace Distribute

if (!for_first_form<RE::BGSOutfit>(
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());
Expand Down
34 changes: 17 additions & 17 deletions SPID/src/OutfitManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 :)
Expand All @@ -173,7 +177,7 @@ namespace Outfits
replacements.try_emplace(actor->formID, defaultOutfit, outfit);
}

return true;
return ReplacementResult::Set;
}

void Manager::UseOriginalOutfit(RE::Actor* actor)
Expand Down Expand Up @@ -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};
}
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -275,7 +275,7 @@ namespace Outfits
}
#ifndef NDEBUG
if (const auto actor = RE::TESForm::LookupByID<RE::Actor>(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;
Expand All @@ -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.");*/
}
}

0 comments on commit 4e19ded

Please sign in to comment.