Rewritten OnContainerChanged to cover non-player events as well
This commit is contained in:
parent
52a1bb4e46
commit
cd66ad1eac
Binary file not shown.
@ -303,7 +303,7 @@ namespace ArtifactTracker
|
||||
}
|
||||
}
|
||||
|
||||
void SyncCellStorage()
|
||||
void SyncCellStorage(RE::FormID a_ignoreRef)
|
||||
{
|
||||
if (!IsHome()) {
|
||||
#ifdef _DEBUG
|
||||
@ -322,6 +322,10 @@ namespace ArtifactTracker
|
||||
const auto inv = g_cellStorage->GetInventory();
|
||||
|
||||
for (const auto& a_ref : cell->references) {
|
||||
if (a_ignoreRef == a_ref->formID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto baseObj = a_ref->GetBaseObject();
|
||||
|
||||
if (IsValidContainer(a_ref.get())) {
|
||||
@ -382,6 +386,7 @@ namespace ArtifactTracker
|
||||
if (count > 0 && !cellItems.contains(item->formID)) {
|
||||
g_cellStorage->RemoveItem(item, count, RE::ITEM_REMOVE_REASON::kRemove, nullptr, nullptr);
|
||||
if (!RefListHasItem(g_persistentStorage, item->formID)) {
|
||||
ListRemoveItem(g_listNew, item);
|
||||
ListRemoveItem(g_listStored, item);
|
||||
g_listFound->AddForm(item);
|
||||
}
|
||||
@ -393,124 +398,182 @@ namespace ArtifactTracker
|
||||
|
||||
void OnContainerChanged(const RE::TESContainerChangedEvent* a_event, RE::TESForm* form)
|
||||
{
|
||||
if (a_event->newContainer == 0x14) {
|
||||
|
||||
if (a_event->oldContainer) {
|
||||
if (a_event->newContainer) { // added to a container or actor
|
||||
|
||||
if (g_persistentMap.contains(a_event->oldContainer)) {
|
||||
if (a_event->newContainer == 0x14) { // acquired by player
|
||||
|
||||
if (a_event->oldContainer) {
|
||||
|
||||
if (const auto it = g_persistentMap.find(a_event->oldContainer); it != g_persistentMap.end()) { // moved from a persistent container
|
||||
|
||||
const auto ref = it->second;
|
||||
|
||||
if (ref && GetItemCount(ref, form) - a_event->itemCount <= 0) { // no items left in the container
|
||||
for (const auto& persref : g_persistentMap) {
|
||||
if (persref.second != ref) {
|
||||
if (GetItemCount(persref.second, form) > 0) {
|
||||
// if other containers have it, do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
ListRemoveItem(g_listStored, form);
|
||||
g_listFound->AddForm(form);
|
||||
}
|
||||
|
||||
} else if (g_cellStorage && !g_bHomeContainer) { // taken from a container at home
|
||||
|
||||
const auto container = RE::TESForm::LookupByID<RE::TESObjectREFR>(a_event->oldContainer);
|
||||
if (container && GetItemCount(container, form) - a_event->itemCount <= 0) {
|
||||
SyncCellStorage(container->formID);
|
||||
}
|
||||
|
||||
// Items in persistent containers are marked as stored by definition, no need to check the list
|
||||
if (!RefListHasItem(g_persistentStorage, a_event->baseObj)) {
|
||||
ListRemoveItem(g_listStored, form);
|
||||
g_listFound->AddForm(form);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
} else if (g_cellStorage) { // non-persistent container at home
|
||||
|
||||
// g_bContainerMode is expected to be true, enabling processing after closing container.
|
||||
// Reachable by Loot Menu or a mod, retrieving items via a spell of after scanning containers in cell.
|
||||
// In extreme cases of mass retrieval, this can result in a few frames lag.
|
||||
|
||||
#ifdef _DEBUG
|
||||
SKSE::log::info("Synchronous processing of a non-persistent container (moved to player)");
|
||||
#endif
|
||||
|
||||
SyncCellStorage();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (g_cellStorage && !g_listNew->HasForm(form)) {
|
||||
// Items picked up at home are handled in the perk
|
||||
return;
|
||||
}
|
||||
|
||||
// Instead of looking up in huge g_listNew, we check smaller g_listStored and g_listFound.
|
||||
// Mass retrieval of found items is rare, so we check the stored list first.
|
||||
if (g_listStored->HasForm(form) || g_listFound->HasForm(form)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// It's a new item, move it to found
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listFound->AddForm(form);
|
||||
|
||||
return;
|
||||
|
||||
} else if (a_event->oldContainer == 0x14) {
|
||||
|
||||
// Items moved from player's inventory
|
||||
|
||||
if (!a_event->newContainer) { // no destination container
|
||||
|
||||
if (g_cellStorage && a_event->reference) { // dropped or placed on rack at home
|
||||
if (GetItemCount(g_cellStorage, form) <= 0) {
|
||||
#ifdef _DEBUG
|
||||
SKSE::log::info("Added dropped {} to cell storage", form->GetName());
|
||||
RE::DebugNotification("Adding to cell storage");
|
||||
#endif
|
||||
g_cellStorage->AddObjectToContainer(form->As<RE::TESBoundObject>(), nullptr, 1, nullptr);
|
||||
}
|
||||
ListRemoveItem(g_listFound, form);
|
||||
if (!g_listStored->HasForm(form) && !g_listFound->HasForm(form)) { // it's a new item, move it to found
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listStored->AddForm(form);
|
||||
return;
|
||||
g_listFound->AddForm(form);
|
||||
}
|
||||
|
||||
if (g_listStored->HasForm(form)) {
|
||||
return;
|
||||
}
|
||||
} else if (g_cellStorage && g_cellStorage->formID == a_event->newContainer) {
|
||||
return; // ignore cell storage
|
||||
|
||||
// NB: During OnContainerChanged, InventoryChanges do not have the current change included yet
|
||||
if ((GetItemCount(RE::PlayerCharacter::GetSingleton(), form) - a_event->itemCount <= 0) && !FollowersHaveItem(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listNew->AddForm(form);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_persistentMap.contains(a_event->newContainer)) { // moved to a persistent container
|
||||
} else if (g_persistentMap.contains(a_event->newContainer)) { // stored in a registered persistent container
|
||||
|
||||
if (!g_listStored->HasForm(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listStored->AddForm(form);
|
||||
}
|
||||
|
||||
} else if (g_cellStorage) { // stored at home in a non-persistent/non-registered container
|
||||
|
||||
// g_bContainerMode is expected to be true, enabling processing after closing container.
|
||||
// Can be hit by autosorting mods. Most of them work with persistent containers, which should be added to the list of persistent containers.
|
||||
|
||||
#ifdef _DEBUG
|
||||
SKSE::log::info("Synchronous processing of a non-persistent container (moved from player)");
|
||||
#endif
|
||||
|
||||
const auto targetContainer = RE::TESForm::LookupByID<RE::TESObjectREFR>(a_event->newContainer);
|
||||
|
||||
if (IsValidContainer(targetContainer)) {
|
||||
if (GetItemCount(g_cellStorage, form) <= 0) {
|
||||
g_cellStorage->AddObjectToContainer(form->As<RE::TESBoundObject>(), nullptr, 1, nullptr);
|
||||
} else {
|
||||
const auto ref = RE::TESForm::LookupByID(a_event->newContainer);
|
||||
if (ref->Is(RE::FormType::ActorCharacter)) {
|
||||
if (ref->As<RE::Actor>()->IsPlayerTeammate()) { // acquired by companion
|
||||
if (!g_listFound->HasForm(form) && !g_listStored->HasForm(form)) {
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listFound->AddForm(form);
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_listStored->HasForm(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listStored->AddForm(form);
|
||||
|
||||
} else {
|
||||
const auto container = ref->As<RE::TESObjectREFR>();
|
||||
if (container) {
|
||||
if (g_cellStorage && container->GetParentCell() == RE::PlayerCharacter::GetSingleton()->GetParentCell()) { // stored at home
|
||||
|
||||
if (!g_bHomeContainer && !g_listStored->HasForm(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listStored->AddForm(form);
|
||||
}
|
||||
|
||||
// During OnContainerChanged, InventoryChanges do not have the current change included yet
|
||||
} else if (a_event->oldContainer == 0x14 && !g_listStored->HasForm(form) && (GetItemCount(RE::PlayerCharacter::GetSingleton(), form) - a_event->itemCount <= 0) && !FollowersHaveItem(form)) {
|
||||
// disposed by player
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listNew->AddForm(form);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (a_event->oldContainer) { // removed from container
|
||||
|
||||
if (g_cellStorage && a_event->reference) { // dropped or placed on rack at home by any actor
|
||||
|
||||
if (GetItemCount(g_cellStorage, form) <= 0) {
|
||||
#ifdef _DEBUG
|
||||
SKSE::log::info("Added dropped {} to cell storage", form->GetName());
|
||||
RE::DebugNotification("Adding to cell storage");
|
||||
#endif
|
||||
g_cellStorage->AddObjectToContainer(form->As<RE::TESBoundObject>(), nullptr, 1, nullptr);
|
||||
}
|
||||
|
||||
if (!g_listStored->HasForm(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listStored->AddForm(form);
|
||||
}
|
||||
|
||||
} else if (a_event->oldContainer == 0x14) { // dropped, dismantled, consumed, removed by a script
|
||||
|
||||
if (!g_listStored->HasForm(form)) {
|
||||
if ((GetItemCount(RE::PlayerCharacter::GetSingleton(), form) - a_event->itemCount <= 0) && !FollowersHaveItem(form)) {
|
||||
if (g_listFound->HasForm(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listNew->AddForm(form);
|
||||
}
|
||||
|
||||
} else if (!g_listFound->HasForm(form)) {
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listFound->AddForm(form);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (g_cellStorage && g_cellStorage->formID == a_event->oldContainer) {
|
||||
return; // ignore cell storage
|
||||
|
||||
} else if (const auto it = g_persistentMap.find(a_event->oldContainer); it != g_persistentMap.end()) { // deleted from a persistent container
|
||||
|
||||
const auto ref = it->second;
|
||||
|
||||
if (ref && GetItemCount(ref, form) - a_event->itemCount <= 0) { // no items left in the container
|
||||
for (const auto& persref : g_persistentMap) {
|
||||
if (persref.second != ref) {
|
||||
if (GetItemCount(persref.second, form) > 0) {
|
||||
// if other containers have it, do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
ListRemoveItem(g_listStored, form);
|
||||
if (GetItemCount(RE::PlayerCharacter::GetSingleton(), form) || FollowersHaveItem(form)) {
|
||||
g_listFound->AddForm(form);
|
||||
} else {
|
||||
g_listNew->AddForm(form);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
const auto ref = RE::TESForm::LookupByID(a_event->oldContainer);
|
||||
|
||||
if (ref->Is(RE::FormType::ActorCharacter)) {
|
||||
if (ref->As<RE::Actor>()->IsPlayerTeammate() && GetItemCount(ref->As<RE::TESObjectREFR>(), form) - a_event->itemCount <= 0) { // removed from companion (probably, disarmed)
|
||||
if (!g_listStored->HasForm(form) && g_listFound->HasForm(form)) {
|
||||
|
||||
if (GetItemCount(RE::PlayerCharacter::GetSingleton(), form) <= 0) {
|
||||
// player does not have it, check companions
|
||||
if (const auto processLists = RE::ProcessLists::GetSingleton(); processLists) {
|
||||
for (auto& actorHandle : processLists->highActorHandles) {
|
||||
if (auto actor = actorHandle.get(); actor && actor->IsPlayerTeammate() && actor->formID != ref->formID) {
|
||||
if (GetItemCount(actor.get(), form) > 0) {
|
||||
// other companion has it, do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listNew->AddForm(form);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
const auto container = ref->As<RE::TESObjectREFR>();
|
||||
if (container) {
|
||||
if (g_cellStorage && container->GetParentCell() == RE::PlayerCharacter::GetSingleton()->GetParentCell()) { // deleted from container at home
|
||||
|
||||
if (GetItemCount(container, form) - a_event->itemCount <= 0) {
|
||||
SyncCellStorage(container->formID);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NB: During OnContainerChanged, InventoryChanges do not have the current change included yet
|
||||
} else if (g_listFound->HasForm(form) && (GetItemCount(RE::PlayerCharacter::GetSingleton(), form) - a_event->itemCount <= 0) && !FollowersHaveItem(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listNew->AddForm(form);
|
||||
}
|
||||
} else if (g_cellStorage && a_event->reference) {
|
||||
// Items dropped by someone else at home.
|
||||
// Mainly for compatibility with Immersive Display Overhaul
|
||||
SyncCellStorage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace ArtifactTracker
|
||||
|
||||
void OnCellEnter(RE::BGSLocation* location, RE::TESObjectCELL* cell);
|
||||
|
||||
void SyncCellStorage();
|
||||
void SyncCellStorage(RE::FormID a_ignoreRef = NULL);
|
||||
|
||||
void OnContainerChanged(const RE::TESContainerChangedEvent* a_event, RE::TESForm* form);
|
||||
|
||||
|
@ -31,11 +31,9 @@ auto EventListener::ProcessEvent(
|
||||
RE::BSTEventSource<RE::TESContainerChangedEvent>* a_eventSource)
|
||||
-> RE::BSEventNotifyControl
|
||||
{
|
||||
if (!ArtifactTracker::g_bHomeContainer && (a_event->newContainer == 0x14 || a_event->oldContainer == 0x14 || (ArtifactTracker::IsHome() && a_event->reference))) {
|
||||
const auto form = ArtifactTracker::GetArtifactByID(a_event->baseObj);
|
||||
if (form) {
|
||||
ArtifactTracker::OnContainerChanged(a_event, form);
|
||||
}
|
||||
const auto form = ArtifactTracker::GetArtifactByID(a_event->baseObj);
|
||||
if (form) {
|
||||
ArtifactTracker::OnContainerChanged(a_event, form);
|
||||
}
|
||||
|
||||
return RE::BSEventNotifyControl::kContinue;
|
||||
|
Loading…
Reference in New Issue
Block a user