fix: the model vault uses the models' inventory groups, as the client

LWOInventoryComponent_Common::msgUpdateInventoryGroup (0x00c955b0) and msgUpdateInventoryGroupContents (0x00ce1f50) look the inventory type up in m_VaultToPlayerInventory first, which maps VAULT_MODELS to MODELS. The server refused group updates for the model vault.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-10-16 20:09:54 -05:00
parent 13be051af9
commit 4dcd8b8204
4 changed files with 64 additions and 2 deletions

View File

@@ -1688,12 +1688,14 @@ bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId) {
void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) {
if (groupUpdate.groupId.empty()) return; if (groupUpdate.groupId.empty()) return;
if (groupUpdate.inventory != eInventoryType::BRICKS && groupUpdate.inventory != eInventoryType::MODELS) { // The model vault shares the models' groups (the client's m_VaultToPlayerInventory: VAULT_MODELS -> MODELS)
const auto inventory = groupUpdate.inventory == eInventoryType::VAULT_MODELS ? eInventoryType::MODELS : groupUpdate.inventory;
if (inventory != eInventoryType::BRICKS && inventory != eInventoryType::MODELS) {
LOG("Invalid inventory type for grouping %s", StringifiedEnum::ToString(groupUpdate.inventory).data()); LOG("Invalid inventory type for grouping %s", StringifiedEnum::ToString(groupUpdate.inventory).data());
return; return;
} }
auto& groups = m_Groups[groupUpdate.inventory]; auto& groups = m_Groups[inventory];
auto groupItr = std::ranges::find_if(groups, [&groupUpdate](const Group& group) { auto groupItr = std::ranges::find_if(groups, [&groupUpdate](const Group& group) {
return group.groupId == groupUpdate.groupId; return group.groupId == groupUpdate.groupId;
}); });

View File

@@ -409,6 +409,8 @@ public:
void UpdateGroup(const GroupUpdate& groupUpdate); 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; }; std::unordered_map<LWOOBJID, DatabasePet>& GetPetsMut() { return m_Pets; };
void FixInvisibleItems(); void FixInvisibleItems();

View File

@@ -1,5 +1,7 @@
set(DCOMPONENTS_TESTS set(DCOMPONENTS_TESTS
"DestroyableComponentTests.cpp" "DestroyableComponentTests.cpp"
"InventoryGroupTests.cpp"
"ModelComponentTests.cpp"
"PetComponentTests.cpp" "PetComponentTests.cpp"
"SimplePhysicsComponentTests.cpp" "SimplePhysicsComponentTests.cpp"
"SavingTests.cpp" "SavingTests.cpp"

View File

@@ -0,0 +1,56 @@
#include "GameDependencies.h"
#include "CDClientManager.h"
#include "CDComponentsRegistryTable.h"
#include "Entity.h"
#include "InventoryComponent.h"
#include <gtest/gtest.h>
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 Update(const InventoryComponent::GroupUpdateCommand command, const std::string& id, const eInventoryType type, const LOT lot = LOT_NULL) {
InventoryComponent::GroupUpdate update{};
update.groupId = id;
update.groupName = "name";
update.lot = lot;
update.inventory = type;
update.command = command;
inventory->UpdateGroup(update);
}
};
// The client's LWOInventoryComponent_Common::msgUpdateInventoryGroup (0x00c955b0) and msgUpdateInventoryGroupContents
// (0x00ce1f50) map the model vault to the models inventory (m_VaultToPlayerInventory)
TEST_F(InventoryGroupTests, TheModelVaultUsesTheModelsGroups) {
Update(InventoryComponent::GroupUpdateCommand::ADD, "user_group1", eInventoryType::VAULT_MODELS);
Update(InventoryComponent::GroupUpdateCommand::ADD_LOT, "user_group1", eInventoryType::VAULT_MODELS, 3001);
const auto& groups = inventory->GetGroups();
ASSERT_EQ(groups.at(eInventoryType::MODELS).size(), 1u);
EXPECT_EQ(groups.at(eInventoryType::MODELS)[0].lots.size(), 1u);
EXPECT_FALSE(groups.contains(eInventoryType::VAULT_MODELS));
}
TEST_F(InventoryGroupTests, OnlyBricksAndModelsHaveGroups) {
Update(InventoryComponent::GroupUpdateCommand::ADD, "user_group1", eInventoryType::ITEMS);
EXPECT_FALSE(inventory->GetGroups().contains(eInventoryType::ITEMS));
Update(InventoryComponent::GroupUpdateCommand::ADD, "user_group1", eInventoryType::BRICKS);
EXPECT_EQ(inventory->GetGroups().at(eInventoryType::BRICKS).size(), 1u);
}