Skip to content

Commit

Permalink
Few improvements for debugging
Browse files Browse the repository at this point in the history
- Added more information on deserialization error.
- Extracted equipping outfits to a separate method for easier replacement.
  • Loading branch information
adya committed Nov 24, 2024
1 parent 6ca28fb commit d7f30bc
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 9 deletions.
8 changes: 8 additions & 0 deletions SPID/include/OutfitManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ namespace Outfits
static void Save(SKSE::SerializationInterface*);
static void Revert(SKSE::SerializationInterface*);

/// <summary>
/// This method performs the actual change of the outfit.
/// </summary>
/// <param name="actor">Actor for whom outfit should be changed</param>
/// <param name="outift">The outfit to be set</param>
/// <returns>True if the outfit was successfully set, false otherwise</returns>
bool SetDefaultOutfit(RE::Actor*, RE::BGSOutfit*);

struct OutfitReplacement
{
/// The one that NPC had before SPID distribution.
Expand Down
39 changes: 30 additions & 9 deletions SPID/src/OutfitManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ namespace Outfits
constexpr std::uint32_t recordType = 'OTFT';

template <typename T>
bool Load(SKSE::SerializationInterface* interface, T*& output)
bool Load(SKSE::SerializationInterface* interface, T*& output, RE::FormID& formID)
{
RE::FormID id = 0;

Expand All @@ -62,10 +62,14 @@ namespace Outfits
return false;
}

formID = id; // save the originally read formID

if (!interface->ResolveFormID(id, id)) {
return false;
}

formID = id; // save the resolved formID

if (const auto form = RE::TESForm::LookupByID<T>(id); form) {
output = form;
return true;
Expand All @@ -76,18 +80,20 @@ namespace Outfits

bool Load(SKSE::SerializationInterface* interface, RE::Actor*& loadedActor, RE::BGSOutfit*& loadedOriginalOutfit, RE::BGSOutfit*& loadedDistributedOutfit)
{
if (!Load(interface, loadedActor)) {
logger::warn("Failed to load Outfit Replacement record: Corrupted actor.");
RE::FormID id = 0;

if (!Load(interface, loadedActor, id)) {
logger::warn("Failed to load Outfit Replacement record: Corrupted actor [{:08X}].", id);
return false;
}

if (!Load(interface, loadedOriginalOutfit)) {
logger::warn("Failed to load Outfit Replacement record: Corrupted original outfit.");
if (!Load(interface, loadedOriginalOutfit, id)) {
logger::warn("Failed to load Outfit Replacement record: Corrupted original outfit [{:08X}].", id);
return false;
}

if (!Load(interface, loadedDistributedOutfit)) {
logger::warn("Failed to load Outfit Replacement record: Corrupted distributed outfit.");
if (!Load(interface, loadedDistributedOutfit, id)) {
logger::warn("Failed to load Outfit Replacement record: Corrupted distributed outfit [{:08X}].", id);
return false;
}

Expand Down Expand Up @@ -172,7 +178,7 @@ namespace Outfits
return ReplacementResult::Skipped;
}

actor->SetDefaultOutfit(outfit, false); // Having true here causes infinite loading. It seems that equipping works either way, so we are good :)
SetDefaultOutfit(actor, outfit);

if (auto previous = replacements.find(actor->formID); previous != replacements.end()) {
previous->second.distributed = outfit;
Expand Down Expand Up @@ -231,7 +237,7 @@ namespace Outfits
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.
if (manager->SetDefaultOutfit(actor, replacement.original)) {
++revertedCount;
}
}
Expand All @@ -243,6 +249,21 @@ namespace Outfits
#endif
}

bool Manager::SetDefaultOutfit(RE::Actor* actor, RE::BGSOutfit* outfit)
{
actor->SetDefaultOutfit(outfit, false); // Having true here causes infinite loading. It seems that equipping works either way, so we are good :)

// TODO: Implement the equipment solution from po3 to avoid crashes :)
// With that approach nothing will be saved in the save file again, as such we'll only need to make sure that whatever was NPC's default outfit will get equipped once replacement no longer available.
/*
if (const auto npc = actor->GetActorBase(); npc) {
npc->defaultOutfit = outfit;
}
force_equip_outfit(actor, actor->GetActorBase());
*/
return true;
}

void Manager::Save(SKSE::SerializationInterface* interface)
{
#ifndef NDEBUG
Expand Down

0 comments on commit d7f30bc

Please sign in to comment.