fix(inventory): adding an inventory group that exists does nothing, as the client

LWOInventoryComponent_Common::msgUpdateInventoryGroup (0x00c955b0) ignores
an ADD whose group id is already in the inventory. The server added a
second group with the same id, saved to the charxml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-10-02 10:30:05 -05:00
parent ba6228ef09
commit 0bc1a88e75
4 changed files with 67 additions and 0 deletions

View File

@@ -1998,6 +1998,9 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) {
return group.groupId == groupUpdate.groupId;
});
// As LWOInventoryComponent_Common::msgUpdateInventoryGroup (0x00c955b0): adding a group that exists does nothing
if (groupUpdate.command == GroupUpdateCommand::ADD && groupItr != groups.end()) return;
if (groupUpdate.command != GroupUpdateCommand::ADD && groupItr == groups.end()) {
LOG("Group %s not found in inventory %s. Cannot process command.", groupUpdate.groupId.c_str(), StringifiedEnum::ToString(groupUpdate.inventory).data());
return;

View File

@@ -453,6 +453,7 @@ public:
bool SetSkill(BehaviorSlot slot, uint32_t skillId);
void UpdateGroup(const GroupUpdate& groupUpdate);
const std::map<eInventoryType, std::vector<Group>>& GetGroups() const { return m_Groups; }
std::unordered_map<LWOOBJID, DatabasePet>& GetPetsMut() { return m_Pets; };

View File

@@ -21,6 +21,7 @@ set(DCOMPONENTS_TESTS
"ReplicaConstructionTests.cpp"
"ReplicaDecoderTests.cpp"
"CapturePropertyTests.cpp"
"InventoryGroupTests.cpp"
"InventoryMoveTests.cpp"
"ItemRemovalTests.cpp"
"UseItemResultTests.cpp"

View File

@@ -0,0 +1,62 @@
#include "GameDependencies.h"
#include "CDClientManager.h"
#include "CDComponentsRegistryTable.h"
#include "Entity.h"
#include "InventoryComponent.h"
#include "InventoryMessages.h"
#include <gtest/gtest.h>
// Inventory groups as LWOInventoryComponent_Common::msgUpdateInventoryGroup (0x00c955b0) and
// msgUpdateInventoryGroupContents (0x00ce1f50) keep them.
class InventoryGroupTests : public GameDependenciesTest {
protected:
std::unique_ptr<Entity> entity;
InventoryComponent* inventory{};
void SetUp() override {
SetUpDependencies();
CDClientManager::GetEntriesMutable<CDComponentsRegistryTable>().insert_or_assign(static_cast<uint64_t>(info.lot), 0);
entity = std::make_unique<Entity>(1, info);
inventory = entity->AddComponent<InventoryComponent>(-1);
}
void TearDown() override {
entity.reset();
TearDownDependencies();
}
void Group(const std::string& action, const std::string& id, const std::u16string& name, const eInventoryType type = eInventoryType::BRICKS, const bool locked = false) {
GameMessages::UpdateInventoryGroup msg;
msg.action = action;
msg.groupID = id;
msg.groupName = name;
msg.inventoryType = type;
msg.locked = locked;
inventory->OnUpdateInventoryGroup(msg);
}
void Contents(const std::string& action, const std::string& id, const LOT lot, const eInventoryType type = eInventoryType::BRICKS) {
GameMessages::UpdateInventoryGroupContents msg;
msg.action = action;
msg.groupID = id;
msg.lot = lot;
msg.inventoryType = type;
inventory->OnUpdateInventoryGroupContents(msg);
}
const std::vector<InventoryComponent::Group>& Groups(const eInventoryType type = eInventoryType::BRICKS) {
return inventory->GetGroups().at(type);
}
};
TEST_F(InventoryGroupTests, AddingAGroupThatExistsDoesNothing) {
Group("ADD", "user_group1", u"first");
Contents("ADD", "user_group1", 3001);
Group("ADD", "user_group1", u"second");
ASSERT_EQ(Groups().size(), 1u);
EXPECT_EQ(Groups()[0].groupName, "first");
EXPECT_EQ(Groups()[0].lots.size(), 1u);
}