1

Compare commits

...

2 Commits

7 changed files with 65 additions and 13 deletions

Binary file not shown.

View File

@ -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)

View File

@ -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<RE::TESObjectCELL>(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<RE::TESObjectREFR>();
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<RE::TESCellFullyLoadedEvent>(EventListener::GetSingleton());
}
}
void OnCellEnter(const RE::BGSLocation* location, const RE::TESObjectCELL* cell)
{
RE::ScriptEventSourceHolder::GetSingleton()->RemoveEventSink<RE::TESCellFullyLoadedEvent>(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<RE::TESObjectREFR*> 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;

View File

@ -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;

View File

@ -117,7 +117,7 @@ auto EventListener::ProcessEvent(
// This listener is expected to be unregistered outside of home.
if (ArtifactTracker::IsHome() && a_event->actionRef->IsPlayerRef() && a_event->objectActivated) {
const auto ref = a_event->objectActivated.get();
if (ref && ArtifactTracker::IsArtifact(ref->GetBaseObject())) {
if (ref && ArtifactTracker::g_artifactAllFormTypes.contains(ref->GetBaseObject()->GetFormType())) {
std::thread([]() {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
ArtifactTracker::SyncCellStorage();

View File

@ -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);
});
}
});
}

View File

@ -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/",