diff --git a/SKSE/Plugins/ArtifactTracker.dll b/SKSE/Plugins/ArtifactTracker.dll index 6f675bd..f49e1cd 100644 Binary files a/SKSE/Plugins/ArtifactTracker.dll and b/SKSE/Plugins/ArtifactTracker.dll differ diff --git a/Source/ArtifactTrackerDLL/CMakeLists.txt b/Source/ArtifactTrackerDLL/CMakeLists.txt index 3d04e96..fb9bfc9 100644 --- a/Source/ArtifactTrackerDLL/CMakeLists.txt +++ b/Source/ArtifactTrackerDLL/CMakeLists.txt @@ -6,7 +6,7 @@ message("Using toolchain file ${CMAKE_TOOLCHAIN_FILE}.") ######################################################################################################################## project( ArtifactTracker - VERSION 1.0.3 + VERSION 1.0.4 DESCRIPTION "Artifact Tracker" LANGUAGES CXX) set(CMAKE_CXX_STANDARD 23) diff --git a/Source/ArtifactTrackerDLL/src/ArtifactTracker.cpp b/Source/ArtifactTrackerDLL/src/ArtifactTracker.cpp index ea92be6..5ec1c63 100644 --- a/Source/ArtifactTrackerDLL/src/ArtifactTracker.cpp +++ b/Source/ArtifactTrackerDLL/src/ArtifactTracker.cpp @@ -9,6 +9,7 @@ using namespace SKSE::log; namespace ArtifactTracker { bool g_bLoaded = false; + bool g_bSaveLoaded = true; bool g_bHomeContainer = false; bool g_bBookShelf = false; bool g_bTakeAll = false; @@ -316,7 +317,7 @@ namespace ArtifactTracker bool IsValidContainer(RE::TESObjectREFR* a_ref) { - if (!a_ref) { + if (!a_ref || a_ref->IsMarkedForDeletion()) { return false; } @@ -327,6 +328,11 @@ namespace ArtifactTracker void OnCellEnter(const RE::FormID a_formID) { + if (!g_bSaveLoaded) { + // Cell load events fire before formlists are loaded from savegame + return; + } + RE::TESObjectCELL* cell = RE::TESForm::LookupByID(a_formID); RE::BGSLocation* location = cell ? cell->GetLocation() : nullptr; @@ -339,40 +345,75 @@ namespace ArtifactTracker } RE::TESObjectREFR* cellStorage = nullptr; + bool bHasDupes = false; g_persistentStorage->ForEachForm([&](RE::TESForm& a_form) { const auto refr = a_form.As(); - if (refr && refr->GetBaseObject() == g_cellContainer && refr->GetParentCell()->formID == a_formID) { - cellStorage = refr; - return false; + if (refr && refr->GetParentCell()->formID == a_formID && refr->GetBaseObject() == g_cellContainer) { + if (cellStorage) { + log::warn("Multiple cell storages detected in {}", cell->GetName()); + bHasDupes = true; + } else { + cellStorage = refr; + } } return true; }); + #ifdef _DEBUG + if (cellStorage) { + log::info("Found cell storage in {} (first pass)", cell->GetName()); + } + #endif + ToggleHomeMode(cellStorage); - if (!cellStorage) { + if (!cellStorage || bHasDupes) { RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink(EventListener::GetSingleton()); } } void OnCellEnter(const RE::BGSLocation* location, const RE::TESObjectCELL* cell) { + RE::ScriptEventSourceHolder::GetSingleton()->RemoveEventSink(EventListener::GetSingleton()); + + if (!g_bSaveLoaded) { + // Cell load events fire before formlists are loaded from savegame, duh! + return; + } + if (!location || !cell->IsInteriorCell() || cell != RE::PlayerCharacter::GetSingleton()->GetParentCell() || !location->HasKeyword(g_homeKeyword)) { ToggleHomeMode(nullptr); return; } RE::TESObjectREFR* cellStorage = nullptr; + std::vector dupes; - for (const auto& a_ref : cell->references) { - if (a_ref.get()->GetBaseObject() == g_cellContainer) { - cellStorage = a_ref.get(); - break; + cell->ForEachReference([&cellStorage, &dupes](RE::TESObjectREFR& a_ref) { + if (a_ref.GetBaseObject() == g_cellContainer && !a_ref.IsMarkedForDeletion()) { + if (cellStorage) { + dupes.push_back(&a_ref); + } else { + cellStorage = &a_ref; + } } + return true; + }); + + for (int i = 0; i < dupes.size(); i++) { + log::warn("Removing duplicate storage {:08X}", dupes[i]->formID); + g_persistentMap.erase(dupes[i]->formID); + ListRemoveItem(g_persistentStorage, dupes[i]); + dupes[i]->Disable(); + dupes[i]->SetDelete(true); } + dupes.clear(); if (cellStorage) { + #ifdef _DEBUG + log::info("Found cell storage in {} (second pass)", cell->GetName()); + #endif if (!g_persistentMap.contains(cellStorage->formID)) { g_persistentStorage->AddForm(cellStorage); g_persistentMap[cellStorage->formID] = cellStorage; @@ -390,6 +431,9 @@ namespace ArtifactTracker const auto cellStorage = RE::PlayerCharacter::GetSingleton()->PlaceObjectAtMe(g_cellContainer, true).get(); if (cellStorage) { + #ifdef _DEBUG + log::info("Created storage {:08X}", cellStorage->formID); + #endif cellStorage->Disable(); g_persistentStorage->AddForm(cellStorage); g_persistentMap[cellStorage->formID] = cellStorage; diff --git a/Source/ArtifactTrackerDLL/src/ArtifactTracker.h b/Source/ArtifactTrackerDLL/src/ArtifactTracker.h index dd7479a..f10f518 100644 --- a/Source/ArtifactTrackerDLL/src/ArtifactTracker.h +++ b/Source/ArtifactTrackerDLL/src/ArtifactTracker.h @@ -3,6 +3,7 @@ namespace ArtifactTracker { extern bool g_bLoaded; + extern bool g_bSaveLoaded; extern bool g_bHomeContainer; extern bool g_bBookShelf; extern bool g_bTakeAll; diff --git a/Source/ArtifactTrackerDLL/src/Main.cpp b/Source/ArtifactTrackerDLL/src/Main.cpp index e6b7756..85cb0c7 100644 --- a/Source/ArtifactTrackerDLL/src/Main.cpp +++ b/Source/ArtifactTrackerDLL/src/Main.cpp @@ -34,8 +34,15 @@ namespace { if (const auto pluginInfo = ArtifactTracker::g_loadInterface->GetPluginInfo("po3_KeywordItemDistributor"); !pluginInfo) { ArtifactTracker::Init(); // if KID is not installed } + } else if (message->type == MessagingInterface::kPreLoadGame) { + ArtifactTracker::g_bSaveLoaded = false; // block cell load events } else if (message->type == MessagingInterface::kPostLoadGame) { - ArtifactTracker::OnGameLoad(); // save-specific updates + SKSE::GetTaskInterface()->AddTask([]() { + ArtifactTracker::OnGameLoad(); // save-specific updates + ArtifactTracker::g_bSaveLoaded = true; + const auto cell = RE::PlayerCharacter::GetSingleton()->GetParentCell(); + ArtifactTracker::OnCellEnter(cell->GetLocation(), cell); + }); } }); } diff --git a/Source/ArtifactTrackerDLL/vcpkg.json b/Source/ArtifactTrackerDLL/vcpkg.json index 563e49a..2ecfaba 100644 --- a/Source/ArtifactTrackerDLL/vcpkg.json +++ b/Source/ArtifactTrackerDLL/vcpkg.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", "name": "artifact-tracker", - "version-string": "1.0.3", + "version-string": "1.0.4", "port-version": 0, "description": "Artifact Tracker", "homepage": "https://eddoursul.win/mods/artifact-tracker/",