Skip to content

Commit fb177fb

Browse files
committed
attempt: to fix inventory crashes
1 parent cecc2f4 commit fb177fb

File tree

5 files changed

+126
-13
lines changed

5 files changed

+126
-13
lines changed

Code/client/Components.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <Components/FaceGenComponent.h>
1616
#include <Components/CacheComponent.h>
1717
#include <Components/WaitingFor3D.h>
18+
#include <Components/PendingInventoryComponent.h>
1819
#include <Components/ActorValuesComponent.h>
1920
#include <Components/ObjectComponent.h>
2021
#include <Components/PlayerComponent.h>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#ifndef TP_INTERNAL_COMPONENTS_GUARD
4+
#error Include Components.h instead
5+
#endif
6+
7+
#include <Structs/Inventory.h>
8+
9+
struct PendingInventoryComponent
10+
{
11+
PendingInventoryComponent() = default;
12+
13+
PendingInventoryComponent(Inventory aInventory, bool aIsDead, bool aIsWeaponDrawn)
14+
: InventoryContent(std::move(aInventory))
15+
, IsDead(aIsDead)
16+
, IsWeaponDrawn(aIsWeaponDrawn)
17+
{
18+
}
19+
20+
Inventory InventoryContent{};
21+
bool IsDead{false};
22+
bool IsWeaponDrawn{false};
23+
};

Code/client/Games/Skyrim/Actor.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -833,12 +833,20 @@ void Actor::SetActorInventory(const Inventory& acInventory) noexcept
833833

834834
Inventory currentInventory = GetActorInventory();
835835

836-
if (!this->GetExtension()->IsPlayer() && currentInventory.ContainsQuestItems())
836+
const bool hasQuestItems = currentInventory.ContainsQuestItems();
837+
const bool isPlayer = this->GetExtension()->IsPlayer();
838+
839+
if (!isPlayer && hasQuestItems)
840+
{
837841
SetInventoryRetainingQuestItems(currentInventory, acInventory);
842+
SetMagicEquipment(acInventory.CurrentMagicEquipment);
843+
}
838844
else
845+
{
839846
SetInventory(acInventory);
840-
841-
SetMagicEquipment(acInventory.CurrentMagicEquipment);
847+
if (isPlayer || !hasQuestItems)
848+
SetMagicEquipment(acInventory.CurrentMagicEquipment);
849+
}
842850
}
843851

844852
void Actor::SetMagicEquipment(const MagicEquipment& acEquipment) noexcept

Code/client/Games/Skyrim/TESObjectREFR.cpp

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,13 +772,48 @@ void TESObjectREFR::SetInventory(const Inventory& aInventory) noexcept
772772

773773
ScopedInventoryOverride _;
774774

775-
RemoveAllItems();
775+
Inventory currentInventory = GetInventory();
776+
Inventory desiredInventory = aInventory;
776777

777-
for (const Inventory::Entry& entry : aInventory.Entries)
778+
// Remove or adjust existing entries
779+
for (auto& currentEntry : currentInventory.Entries)
780+
{
781+
auto matchIt = std::find_if(
782+
desiredInventory.Entries.begin(), desiredInventory.Entries.end(),
783+
[&currentEntry](const Inventory::Entry& entry) { return entry.BaseId == currentEntry.BaseId && entry.IsExtraDataEquals(currentEntry); });
784+
785+
const int32_t desiredCount = matchIt != desiredInventory.Entries.end() ? matchIt->Count : 0;
786+
const int32_t diff = desiredCount - currentEntry.Count;
787+
788+
if (diff < 0)
789+
{
790+
Inventory::Entry removal = currentEntry;
791+
removal.Count = diff; // negative count removes items
792+
AddOrRemoveItem(removal, true);
793+
}
794+
795+
if (matchIt != desiredInventory.Entries.end())
796+
{
797+
if (diff > 0)
798+
{
799+
Inventory::Entry addition = *matchIt;
800+
addition.Count = diff;
801+
AddOrRemoveItem(addition, true);
802+
}
803+
804+
desiredInventory.Entries.erase(matchIt);
805+
}
806+
}
807+
808+
// Add any remaining desired entries that were not present before
809+
for (auto& entry : desiredInventory.Entries)
778810
{
779811
if (entry.Count != 0)
780812
AddOrRemoveItem(entry, true);
781813
}
814+
815+
if (auto* pActor = Cast<Actor>(this))
816+
pActor->SetMagicEquipment(aInventory.CurrentMagicEquipment);
782817
}
783818

784819
Vector<uint32_t> TESObjectREFR::RemoveNonQuestItems(Inventory& aCurrentInventory) noexcept
@@ -829,6 +864,9 @@ void TESObjectREFR::SetInventoryRetainingQuestItems(Inventory& aCurrentInventory
829864
AddOrRemoveItem(entry, true);
830865
}
831866
}
867+
868+
if (auto* pActor = Cast<Actor>(this))
869+
pActor->SetMagicEquipment(acSourceInventory.CurrentMagicEquipment);
832870
}
833871

834872
void TESObjectREFR::AddOrRemoveItem(const Inventory::Entry& arEntry, bool aIsSettingInventory) noexcept

Code/client/Services/Generic/CharacterService.cpp

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -361,12 +361,20 @@ void CharacterService::OnAssignCharacter(const AssignCharacterResponse& acMessag
361361
#endif
362362

363363
pActor->SetActorValues(acMessage.AllActorValues);
364-
pActor->SetActorInventory(acMessage.CurrentInventory);
365364

366-
if (pActor->IsDead() != acMessage.IsDead)
367-
acMessage.IsDead ? pActor->Kill() : pActor->Respawn();
365+
if (pActor->GetNiNode())
366+
{
367+
pActor->SetActorInventory(acMessage.CurrentInventory);
368368

369-
m_weaponDrawUpdates[pActor->formID] = {acMessage.IsWeaponDrawn};
369+
if (pActor->IsDead() != acMessage.IsDead)
370+
acMessage.IsDead ? pActor->Kill() : pActor->Respawn();
371+
372+
m_weaponDrawUpdates[pActor->formID] = {acMessage.IsWeaponDrawn};
373+
}
374+
else
375+
{
376+
m_world.emplace_or_replace<PendingInventoryComponent>(cEntity, acMessage.CurrentInventory, acMessage.IsDead, acMessage.IsWeaponDrawn);
377+
}
370378

371379
MoveActor(pActor, acMessage.WorldSpaceId, acMessage.CellId, acMessage.Position);
372380
}
@@ -539,11 +547,19 @@ void CharacterService::OnRemoteSpawnDataReceived(const NotifySpawnData& acMessag
539547
return;
540548

541549
pActor->SetActorValues(acMessage.NewActorData.InitialActorValues);
542-
pActor->SetActorInventory(acMessage.NewActorData.InitialInventory);
543-
m_weaponDrawUpdates[pActor->formID] = {acMessage.NewActorData.IsWeaponDrawn};
544550

545-
if (pActor->IsDead() != acMessage.NewActorData.IsDead)
546-
acMessage.NewActorData.IsDead ? pActor->Kill() : pActor->Respawn();
551+
if (pActor->GetNiNode())
552+
{
553+
pActor->SetActorInventory(acMessage.NewActorData.InitialInventory);
554+
m_weaponDrawUpdates[pActor->formID] = {acMessage.NewActorData.IsWeaponDrawn};
555+
556+
if (pActor->IsDead() != acMessage.NewActorData.IsDead)
557+
acMessage.NewActorData.IsDead ? pActor->Kill() : pActor->Respawn();
558+
}
559+
else
560+
{
561+
m_world.emplace_or_replace<PendingInventoryComponent>(*itor, acMessage.NewActorData.InitialInventory, acMessage.NewActorData.IsDead, acMessage.NewActorData.IsWeaponDrawn);
562+
}
547563

548564
spdlog::info("Applied remote spawn data, actor form id: {:X}", pActor->formID);
549565
}
@@ -1579,6 +1595,33 @@ void CharacterService::RunRemoteUpdates() noexcept
15791595

15801596
for (auto entity : toRemove)
15811597
m_world.remove<WaitingFor3D>(entity);
1598+
1599+
auto pendingInventoryView = m_world.view<FormIdComponent, PendingInventoryComponent>();
1600+
Vector<entt::entity> pendingToRemove;
1601+
1602+
for (auto entity : pendingInventoryView)
1603+
{
1604+
auto& formIdComponent = pendingInventoryView.get<FormIdComponent>(entity);
1605+
auto& pendingInventory = pendingInventoryView.get<PendingInventoryComponent>(entity);
1606+
1607+
Actor* pActor = Cast<Actor>(TESForm::GetById(formIdComponent.Id));
1608+
if (!pActor || !pActor->GetNiNode())
1609+
continue;
1610+
1611+
pActor->SetActorInventory(pendingInventory.InventoryContent);
1612+
1613+
if (pActor->IsDead() != pendingInventory.IsDead)
1614+
pendingInventory.IsDead ? pActor->Kill() : pActor->Respawn();
1615+
1616+
m_weaponDrawUpdates[pActor->formID] = {pendingInventory.IsWeaponDrawn};
1617+
1618+
pendingToRemove.push_back(entity);
1619+
1620+
spdlog::info("Applied pending inventory for actor, form id: {:X}", pActor->formID);
1621+
}
1622+
1623+
for (auto entity : pendingToRemove)
1624+
m_world.remove<PendingInventoryComponent>(entity);
15821625
}
15831626

15841627
void CharacterService::RunFactionsUpdates() const noexcept

0 commit comments

Comments
 (0)