fix(inventory): the ridden object and the mount item can't be deleted, as the client

LWOInventoryComponent_Common::CanRemoveFromInventory (0x00ce0d20) refuses
the possessed object (GetPossessedObject) and the mount item
(GetMountInventoryID) before the operator bypass and the deletion
restrictions. The server let a player delete the mount they were riding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-10-02 10:21:15 -05:00
parent ea875d859c
commit 5bf637b02e
3 changed files with 22 additions and 1 deletions

View File

@@ -2405,6 +2405,10 @@ namespace {
}
bool InventoryComponent::CanDelete(const Item& item) const {
// The object being ridden and the mount item are never deleted, not even by operators
const auto* const possessor = m_Parent->GetComponent<PossessorComponent>();
if (possessor && (possessor->GetPossessable() == item.GetId() || possessor->GetMountItemID() == item.GetId())) return false;
if (m_Parent->GetGMLevel() == eGameMasterLevel::OPERATOR) return true;
const auto row = static_cast<int32_t>(item.GetInfo().delResIndex);

View File

@@ -478,7 +478,8 @@ public:
/**
* Whether the player may delete this item: its ItemComponent's DeletionRestrictions row, as the client checks it
* (LWOInventoryComponent_Common::CanRemoveFromInventory @ 00ce0d20 in 1.10.64). Operators may delete anything.
* (LWOInventoryComponent_Common::CanRemoveFromInventory @ 00ce0d20 in 1.10.64). The possessed object and the mount
* item are never deleted; otherwise operators may delete anything.
*/
bool CanDelete(const Item& item) const;
void OnMoveItemInInventory(const GameMessages::MoveItemInInventory& msg);

View File

@@ -7,6 +7,7 @@
#include "Entity.h"
#include "InventoryComponent.h"
#include "Item.h"
#include "PossessorComponent.h"
#include "eGameMasterLevel.h"
#include "eReplicaComponentType.h"
@@ -123,3 +124,18 @@ TEST_F(DeletionRestrictionTests, AnyAndAllOfOtherRows) {
EXPECT_TRUE(inventory->CanDelete(*any));
EXPECT_FALSE(inventory->CanDelete(*all));
}
TEST_F(DeletionRestrictionTests, ThePossessedObjectAndTheMountItemAreNeverDeleted) {
auto* const ridden = Give(1000);
auto* const mount = Give(1000);
auto* const other = Give(1000);
auto* const possessor = entity->AddComponent<PossessorComponent>(-1);
possessor->SetPossessable(ridden->GetId());
possessor->SetMountItemID(mount->GetId());
entity->SetGMLevel(eGameMasterLevel::OPERATOR);
EXPECT_FALSE(inventory->CanDelete(*ridden));
EXPECT_FALSE(inventory->CanDelete(*mount));
EXPECT_TRUE(inventory->CanDelete(*other));
possessor->SetPossessable(LWOOBJID_EMPTY); // nothing to dismount when the entity goes
}