Compare commits
2 Commits
946e05d1ed
...
29f7c4e566
Author | SHA1 | Date | |
---|---|---|---|
29f7c4e566 | |||
3a52cb85b1 |
Binary file not shown.
@ -6,7 +6,7 @@ message("Using toolchain file ${CMAKE_TOOLCHAIN_FILE}.")
|
|||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
project(
|
project(
|
||||||
ArtifactTracker
|
ArtifactTracker
|
||||||
VERSION 1.0.3
|
VERSION 1.0.4
|
||||||
DESCRIPTION "Artifact Tracker"
|
DESCRIPTION "Artifact Tracker"
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX)
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
@ -9,6 +9,7 @@ using namespace SKSE::log;
|
|||||||
namespace ArtifactTracker
|
namespace ArtifactTracker
|
||||||
{
|
{
|
||||||
bool g_bLoaded = false;
|
bool g_bLoaded = false;
|
||||||
|
bool g_bSaveLoaded = true;
|
||||||
bool g_bHomeContainer = false;
|
bool g_bHomeContainer = false;
|
||||||
bool g_bBookShelf = false;
|
bool g_bBookShelf = false;
|
||||||
bool g_bTakeAll = false;
|
bool g_bTakeAll = false;
|
||||||
@ -316,7 +317,7 @@ namespace ArtifactTracker
|
|||||||
|
|
||||||
bool IsValidContainer(RE::TESObjectREFR* a_ref)
|
bool IsValidContainer(RE::TESObjectREFR* a_ref)
|
||||||
{
|
{
|
||||||
if (!a_ref) {
|
if (!a_ref || a_ref->IsMarkedForDeletion()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,6 +328,11 @@ namespace ArtifactTracker
|
|||||||
|
|
||||||
void OnCellEnter(const RE::FormID a_formID)
|
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::TESObjectCELL* cell = RE::TESForm::LookupByID<RE::TESObjectCELL>(a_formID);
|
||||||
RE::BGSLocation* location = cell ? cell->GetLocation() : nullptr;
|
RE::BGSLocation* location = cell ? cell->GetLocation() : nullptr;
|
||||||
|
|
||||||
@ -339,40 +345,75 @@ namespace ArtifactTracker
|
|||||||
}
|
}
|
||||||
|
|
||||||
RE::TESObjectREFR* cellStorage = nullptr;
|
RE::TESObjectREFR* cellStorage = nullptr;
|
||||||
|
bool bHasDupes = false;
|
||||||
|
|
||||||
g_persistentStorage->ForEachForm([&](RE::TESForm& a_form) {
|
g_persistentStorage->ForEachForm([&](RE::TESForm& a_form) {
|
||||||
const auto refr = a_form.As<RE::TESObjectREFR>();
|
const auto refr = a_form.As<RE::TESObjectREFR>();
|
||||||
if (refr && refr->GetBaseObject() == g_cellContainer && refr->GetParentCell()->formID == a_formID) {
|
if (refr && refr->GetParentCell()->formID == a_formID && refr->GetBaseObject() == g_cellContainer) {
|
||||||
cellStorage = refr;
|
if (cellStorage) {
|
||||||
return false;
|
log::warn("Multiple cell storages detected in {}", cell->GetName());
|
||||||
|
bHasDupes = true;
|
||||||
|
} else {
|
||||||
|
cellStorage = refr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (cellStorage) {
|
||||||
|
log::info("Found cell storage in {} (first pass)", cell->GetName());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ToggleHomeMode(cellStorage);
|
ToggleHomeMode(cellStorage);
|
||||||
|
|
||||||
if (!cellStorage) {
|
if (!cellStorage || bHasDupes) {
|
||||||
RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink<RE::TESCellFullyLoadedEvent>(EventListener::GetSingleton());
|
RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink<RE::TESCellFullyLoadedEvent>(EventListener::GetSingleton());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnCellEnter(const RE::BGSLocation* location, const RE::TESObjectCELL* cell)
|
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)) {
|
if (!location || !cell->IsInteriorCell() || cell != RE::PlayerCharacter::GetSingleton()->GetParentCell() || !location->HasKeyword(g_homeKeyword)) {
|
||||||
ToggleHomeMode(nullptr);
|
ToggleHomeMode(nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RE::TESObjectREFR* cellStorage = nullptr;
|
RE::TESObjectREFR* cellStorage = nullptr;
|
||||||
|
std::vector<RE::TESObjectREFR*> dupes;
|
||||||
|
|
||||||
for (const auto& a_ref : cell->references) {
|
cell->ForEachReference([&cellStorage, &dupes](RE::TESObjectREFR& a_ref) {
|
||||||
if (a_ref.get()->GetBaseObject() == g_cellContainer) {
|
if (a_ref.GetBaseObject() == g_cellContainer && !a_ref.IsMarkedForDeletion()) {
|
||||||
cellStorage = a_ref.get();
|
if (cellStorage) {
|
||||||
break;
|
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) {
|
if (cellStorage) {
|
||||||
|
#ifdef _DEBUG
|
||||||
|
log::info("Found cell storage in {} (second pass)", cell->GetName());
|
||||||
|
#endif
|
||||||
if (!g_persistentMap.contains(cellStorage->formID)) {
|
if (!g_persistentMap.contains(cellStorage->formID)) {
|
||||||
g_persistentStorage->AddForm(cellStorage);
|
g_persistentStorage->AddForm(cellStorage);
|
||||||
g_persistentMap[cellStorage->formID] = cellStorage;
|
g_persistentMap[cellStorage->formID] = cellStorage;
|
||||||
@ -390,6 +431,9 @@ namespace ArtifactTracker
|
|||||||
const auto cellStorage = RE::PlayerCharacter::GetSingleton()->PlaceObjectAtMe(g_cellContainer, true).get();
|
const auto cellStorage = RE::PlayerCharacter::GetSingleton()->PlaceObjectAtMe(g_cellContainer, true).get();
|
||||||
|
|
||||||
if (cellStorage) {
|
if (cellStorage) {
|
||||||
|
#ifdef _DEBUG
|
||||||
|
log::info("Created storage {:08X}", cellStorage->formID);
|
||||||
|
#endif
|
||||||
cellStorage->Disable();
|
cellStorage->Disable();
|
||||||
g_persistentStorage->AddForm(cellStorage);
|
g_persistentStorage->AddForm(cellStorage);
|
||||||
g_persistentMap[cellStorage->formID] = cellStorage;
|
g_persistentMap[cellStorage->formID] = cellStorage;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace ArtifactTracker
|
namespace ArtifactTracker
|
||||||
{
|
{
|
||||||
extern bool g_bLoaded;
|
extern bool g_bLoaded;
|
||||||
|
extern bool g_bSaveLoaded;
|
||||||
extern bool g_bHomeContainer;
|
extern bool g_bHomeContainer;
|
||||||
extern bool g_bBookShelf;
|
extern bool g_bBookShelf;
|
||||||
extern bool g_bTakeAll;
|
extern bool g_bTakeAll;
|
||||||
|
@ -117,7 +117,7 @@ auto EventListener::ProcessEvent(
|
|||||||
// This listener is expected to be unregistered outside of home.
|
// This listener is expected to be unregistered outside of home.
|
||||||
if (ArtifactTracker::IsHome() && a_event->actionRef->IsPlayerRef() && a_event->objectActivated) {
|
if (ArtifactTracker::IsHome() && a_event->actionRef->IsPlayerRef() && a_event->objectActivated) {
|
||||||
const auto ref = a_event->objectActivated.get();
|
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::thread([]() {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
ArtifactTracker::SyncCellStorage();
|
ArtifactTracker::SyncCellStorage();
|
||||||
|
@ -34,8 +34,15 @@ namespace {
|
|||||||
if (const auto pluginInfo = ArtifactTracker::g_loadInterface->GetPluginInfo("po3_KeywordItemDistributor"); !pluginInfo) {
|
if (const auto pluginInfo = ArtifactTracker::g_loadInterface->GetPluginInfo("po3_KeywordItemDistributor"); !pluginInfo) {
|
||||||
ArtifactTracker::Init(); // if KID is not installed
|
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) {
|
} 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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
|
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
|
||||||
"name": "artifact-tracker",
|
"name": "artifact-tracker",
|
||||||
"version-string": "1.0.3",
|
"version-string": "1.0.4",
|
||||||
"port-version": 0,
|
"port-version": 0,
|
||||||
"description": "Artifact Tracker",
|
"description": "Artifact Tracker",
|
||||||
"homepage": "https://eddoursul.win/mods/artifact-tracker/",
|
"homepage": "https://eddoursul.win/mods/artifact-tracker/",
|
||||||
|
Loading…
Reference in New Issue
Block a user