From b1db59f0b5350a7c30368cab4d4fb5445910b3d0 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 19 May 2024 03:46:50 -0700 Subject: [PATCH 1/9] Added feature grouping logic --- dCommon/dEnums/eInventoryType.h | 9 ++++ dGame/dComponents/InventoryComponent.cpp | 53 ++++++++++++++++++ dGame/dComponents/InventoryComponent.h | 36 ++++++++++++- dGame/dGameMessages/GameMessageHandler.cpp | 7 +++ dGame/dGameMessages/GameMessages.cpp | 63 ++++++++++++++++++++++ dGame/dGameMessages/GameMessages.h | 3 ++ 6 files changed, 170 insertions(+), 1 deletion(-) diff --git a/dCommon/dEnums/eInventoryType.h b/dCommon/dEnums/eInventoryType.h index 12573aa4b..1c6688b22 100644 --- a/dCommon/dEnums/eInventoryType.h +++ b/dCommon/dEnums/eInventoryType.h @@ -4,6 +4,9 @@ #define __EINVENTORYTYPE__H__ #include + +#include "magic_enum.hpp" + static const uint8_t NUMBER_OF_INVENTORIES = 17; /** * Represents the different types of inventories an entity may have @@ -56,4 +59,10 @@ class InventoryType { }; }; +template <> +struct magic_enum::customize::enum_range { + static constexpr int min = 0; + static constexpr int max = 16; +}; + #endif //!__EINVENTORYTYPE__H__ diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 60dd071c0..c56755a5d 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -37,6 +37,7 @@ #include "CDScriptComponentTable.h" #include "CDObjectSkillsTable.h" #include "CDSkillBehaviorTable.h" +#include "StringifiedEnum.h" InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) { this->m_Dirty = true; @@ -1624,3 +1625,55 @@ bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){ return true; } +void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { + if (groupUpdate.groupId.empty()) return; + + if (groupUpdate.inventory != eInventoryType::BRICKS && groupUpdate.inventory != eInventoryType::MODELS) { + LOG("Invalid inventory type for grouping %s", StringifiedEnum::ToString(groupUpdate.inventory).data()); + return; + } + + auto& groups = m_Groups[groupUpdate.inventory]; + + if (groupUpdate.command != GroupUpdateCommand::ADD && !groups.contains(groupUpdate.groupId)) { + LOG("Group %i not found in inventory %s. Cannot process command.", groupUpdate.groupId, StringifiedEnum::ToString(groupUpdate.inventory).data()); + return; + } + + switch (groupUpdate.command) { + case GroupUpdateCommand::ADD: { + auto& group = groups[groupUpdate.groupId]; + group.groupName = groupUpdate.groupName; + group.inventory = groupUpdate.inventory; + break; + } + case GroupUpdateCommand::ADD_LOT: { + groups[groupUpdate.groupId].lots.insert(groupUpdate.lot); + break; + } + case GroupUpdateCommand::REMOVE: { + groups.erase(groupUpdate.groupId); + break; + } + case GroupUpdateCommand::REMOVE_LOT: { + groups[groupUpdate.groupId].lots.erase(groupUpdate.lot); + break; + } + case GroupUpdateCommand::MODIFY: { + groups[groupUpdate.groupId].groupName = groupUpdate.groupName; + break; + } + default: { + LOG("Invalid group update command %i", groupUpdate.command); + break; + } + } + + // debug printing of groups + for (const auto& [groupId, group] : groups) { + LOG("Group %s: %s inventory %s", groupId.c_str(), group.groupName.c_str(), StringifiedEnum::ToString(group.inventory).data()); + for (const auto& lot : group.lots) { + LOG("Lot %i", lot); + } + } +} diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index a1eb14d18..02f7aea4e 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -37,6 +37,31 @@ enum class eItemType : int32_t; */ class InventoryComponent final : public Component { public: + struct Group { + // Custom name assigned by the user. + std::string groupName; + // All the lots the user has in the group. + std::set lots; + // The inventory this group belongs to. + eInventoryType inventory; + }; + + enum class GroupUpdateCommand { + ADD, + ADD_LOT, + MODIFY, + REMOVE, + REMOVE_LOT, + }; + + struct GroupUpdate { + std::string groupId; + std::string groupName; + LOT lot; + eInventoryType inventory; + GroupUpdateCommand command; + }; + static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY; InventoryComponent(Entity* parent); @@ -367,14 +392,23 @@ class InventoryComponent final : public Component { */ void UnequipScripts(Item* unequippedItem); - std::map GetSkills(){ return m_Skills; }; + std::map GetSkills() { return m_Skills; }; bool SetSkill(int slot, uint32_t skillId); bool SetSkill(BehaviorSlot slot, uint32_t skillId); + void UpdateGroup(const GroupUpdate& groupUpdate); + void RemoveGroup(const std::string& groupId); + ~InventoryComponent() override; private: + /** + * The key is the inventory the group belongs to, the value maps' key is the id for the group. + * This is only used for bricks and model inventories. + */ + std::map> m_Groups{ { eInventoryType::BRICKS, {} }, { eInventoryType::MODELS, {} } }; + /** * All the inventory this entity possesses */ diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index d2432e363..76fabce2a 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -685,6 +685,13 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System case eGameMessageType::REQUEST_VENDOR_STATUS_UPDATE: GameMessages::SendVendorStatusUpdate(entity, sysAddr, true); break; + case eGameMessageType::UPDATE_INVENTORY_GROUP: + GameMessages::HandleUpdateInventoryGroup(inStream, entity, sysAddr); + break; + case eGameMessageType::UPDATE_INVENTORY_GROUP_CONTENTS: + GameMessages::HandleUpdateInventoryGroupContents(inStream, entity, sysAddr); + break; + default: LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data()); break; diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 93b10cec7..88838ca88 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -6209,3 +6209,66 @@ void GameMessages::SendSlashCommandFeedbackText(Entity* entity, std::u16string t auto sysAddr = entity->GetSystemAddress(); SEND_PACKET; } + +void GameMessages::HandleUpdateInventoryGroup(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { + std::string action; + std::u16string groupName; + InventoryComponent::GroupUpdate groupUpdate; + bool locked{}; // All groups are locked by default + + uint32_t size{}; + if (!inStream.Read(size)) return; + action.resize(size); + if (!inStream.Read(action.data(), size)) return; + + if (!inStream.Read(size)) return; + groupUpdate.groupId.resize(size); + if (!inStream.Read(groupUpdate.groupId.data(), size)) return; + + if (!inStream.Read(size)) return; + groupName.resize(size); + if (!inStream.Read(reinterpret_cast(groupName.data()), size * 2)) return; + + if (!inStream.Read(groupUpdate.inventory)) return; + if (!inStream.Read(locked)) return; + + groupUpdate.groupName = GeneralUtils::UTF16ToWTF8(groupName); + + if (action == "ADD") groupUpdate.command = InventoryComponent::GroupUpdateCommand::ADD; + else if (action == "MODIFY") groupUpdate.command = InventoryComponent::GroupUpdateCommand::MODIFY; + else if (action == "REMOVE") groupUpdate.command = InventoryComponent::GroupUpdateCommand::REMOVE; + else { + LOG("Invalid action %s", action.c_str()); + return; + } + + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) inventoryComponent->UpdateGroup(groupUpdate); +} + +void GameMessages::HandleUpdateInventoryGroupContents(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { + std::string action; + InventoryComponent::GroupUpdate groupUpdate; + + uint32_t size{}; + if (!inStream.Read(size)) return; + action.resize(size); + if (!inStream.Read(action.data(), size)) return; + + if (action == "ADD") groupUpdate.command = InventoryComponent::GroupUpdateCommand::ADD_LOT; + else if (action == "REMOVE") groupUpdate.command = InventoryComponent::GroupUpdateCommand::REMOVE_LOT; + else { + LOG("Invalid action %s", action.c_str()); + return; + } + + if (!inStream.Read(size)) return; + groupUpdate.groupId.resize(size); + if (!inStream.Read(groupUpdate.groupId.data(), size)) return; + + if (!inStream.Read(groupUpdate.inventory)) return; + if (!inStream.Read(groupUpdate.lot)) return; + + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) inventoryComponent->UpdateGroup(groupUpdate); +} diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index b842710ec..8b51d3bc0 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -666,6 +666,9 @@ namespace GameMessages { void HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity); void SendSlashCommandFeedbackText(Entity* entity, std::u16string text); + + void HandleUpdateInventoryGroup(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleUpdateInventoryGroupContents(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); }; #endif // GAMEMESSAGES_H From dee0ada9ecd51cc758a1a8e9b4a558c0e5d9c93f Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 19 May 2024 04:18:57 -0700 Subject: [PATCH 2/9] Add saving of brick buckets --- dGame/dComponents/InventoryComponent.cpp | 136 +++++++++++++++++------ dGame/dComponents/InventoryComponent.h | 3 + 2 files changed, 105 insertions(+), 34 deletions(-) diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index c56755a5d..6ce34e5f5 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -493,6 +493,11 @@ void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) { return; } + auto* const groups = inventoryElement->FirstChildElement("grps"); + if (groups) { + LoadGroupXml(*groups); + } + m_Consumable = inventoryElement->IntAttribute("csl", LOT_NULL); auto* bag = bags->FirstChildElement(); @@ -641,6 +646,15 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument& document) { bags->LinkEndChild(bag); } + auto* groups = inventoryElement->FirstChildElement("grps"); + if (groups) { + groups->DeleteChildren(); + } else { + groups = inventoryElement->InsertNewChildElement("grps"); + } + + UpdateGroupXml(*groups); + auto* items = inventoryElement->FirstChildElement("items"); if (items == nullptr) { @@ -1601,18 +1615,18 @@ void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument& document) { } -bool InventoryComponent::SetSkill(int32_t slot, uint32_t skillId){ +bool InventoryComponent::SetSkill(int32_t slot, uint32_t skillId) { BehaviorSlot behaviorSlot = BehaviorSlot::Invalid; - if (slot == 1 ) behaviorSlot = BehaviorSlot::Primary; - else if (slot == 2 ) behaviorSlot = BehaviorSlot::Offhand; - else if (slot == 3 ) behaviorSlot = BehaviorSlot::Neck; - else if (slot == 4 ) behaviorSlot = BehaviorSlot::Head; - else if (slot == 5 ) behaviorSlot = BehaviorSlot::Consumable; + if (slot == 1) behaviorSlot = BehaviorSlot::Primary; + else if (slot == 2) behaviorSlot = BehaviorSlot::Offhand; + else if (slot == 3) behaviorSlot = BehaviorSlot::Neck; + else if (slot == 4) behaviorSlot = BehaviorSlot::Head; + else if (slot == 5) behaviorSlot = BehaviorSlot::Consumable; else return false; return SetSkill(behaviorSlot, skillId); } -bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){ +bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId) { if (skillId == 0) return false; const auto index = m_Skills.find(slot); if (index != m_Skills.end()) { @@ -1627,7 +1641,7 @@ bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { if (groupUpdate.groupId.empty()) return; - + if (groupUpdate.inventory != eInventoryType::BRICKS && groupUpdate.inventory != eInventoryType::MODELS) { LOG("Invalid inventory type for grouping %s", StringifiedEnum::ToString(groupUpdate.inventory).data()); return; @@ -1641,32 +1655,32 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { } switch (groupUpdate.command) { - case GroupUpdateCommand::ADD: { - auto& group = groups[groupUpdate.groupId]; - group.groupName = groupUpdate.groupName; - group.inventory = groupUpdate.inventory; - break; - } - case GroupUpdateCommand::ADD_LOT: { - groups[groupUpdate.groupId].lots.insert(groupUpdate.lot); - break; - } - case GroupUpdateCommand::REMOVE: { - groups.erase(groupUpdate.groupId); - break; - } - case GroupUpdateCommand::REMOVE_LOT: { - groups[groupUpdate.groupId].lots.erase(groupUpdate.lot); - break; - } - case GroupUpdateCommand::MODIFY: { - groups[groupUpdate.groupId].groupName = groupUpdate.groupName; - break; - } - default: { - LOG("Invalid group update command %i", groupUpdate.command); - break; - } + case GroupUpdateCommand::ADD: { + auto& group = groups[groupUpdate.groupId]; + group.groupName = groupUpdate.groupName; + group.inventory = groupUpdate.inventory; + break; + } + case GroupUpdateCommand::ADD_LOT: { + groups[groupUpdate.groupId].lots.insert(groupUpdate.lot); + break; + } + case GroupUpdateCommand::REMOVE: { + groups.erase(groupUpdate.groupId); + break; + } + case GroupUpdateCommand::REMOVE_LOT: { + groups[groupUpdate.groupId].lots.erase(groupUpdate.lot); + break; + } + case GroupUpdateCommand::MODIFY: { + groups[groupUpdate.groupId].groupName = groupUpdate.groupName; + break; + } + default: { + LOG("Invalid group update command %i", groupUpdate.command); + break; + } } // debug printing of groups @@ -1677,3 +1691,57 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { } } } + +void InventoryComponent::UpdateGroupXml(tinyxml2::XMLElement& groups) const { + for (const auto& [inventory, groupsData] : m_Groups) { + for (const auto& [groupId, group] : groupsData) { + auto* const groupElement = groups.InsertNewChildElement("grp"); + + groupElement->SetAttribute("id", groupId.c_str()); + groupElement->SetAttribute("n", group.groupName.c_str()); + groupElement->SetAttribute("t", static_cast(group.inventory)); + groupElement->SetAttribute("u", 0); + std::ostringstream lots; + bool first = true; + for (const auto lot : group.lots) { + if (!first) lots << ' '; + first = false; + + lots << lot; + } + groupElement->SetAttribute("l", lots.str().c_str()); + } + } +} + +void InventoryComponent::LoadGroupXml(const tinyxml2::XMLElement& groups) { + auto* groupElement = groups.FirstChildElement("grp"); + + while (groupElement) { + const char* groupId = nullptr; + const char* groupName = nullptr; + const char* lots = nullptr; + eInventoryType inventory = eInventoryType::INVALID; + + groupElement->QueryStringAttribute("id", &groupId); + groupElement->QueryStringAttribute("n", &groupName); + groupElement->QueryStringAttribute("l", &lots); + groupElement->QueryAttribute("t", reinterpret_cast(&inventory)); + + if (!groupId || !groupName || !lots) { + LOG("Failed to load group from xml id %i name %i lots %i", + groupId == nullptr, groupName == nullptr, lots == nullptr); + } else { + auto& group = m_Groups[inventory][groupId]; + group.groupName = groupName; + group.inventory = inventory; + + for (const auto& lotStr : GeneralUtils::SplitString(lots, ' ')) { + auto lot = GeneralUtils::TryParse(lotStr); + if (lot) group.lots.insert(*lot); + } + } + + groupElement = groupElement->NextSiblingElement("grp"); + } +} diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 02f7aea4e..3abb919ff 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -511,6 +511,9 @@ class InventoryComponent final : public Component { * @param document the xml doc to load from */ void UpdatePetXml(tinyxml2::XMLDocument& document); + + void LoadGroupXml(const tinyxml2::XMLElement& groups); + void UpdateGroupXml(tinyxml2::XMLElement& groups) const; }; #endif From e888f3e89031c5c64899b0636565f77343604658 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 19 May 2024 04:24:31 -0700 Subject: [PATCH 3/9] Add edge case check for max group count --- dGame/dComponents/InventoryComponent.cpp | 5 +++++ dGame/dComponents/InventoryComponent.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 6ce34e5f5..ed4b9476c 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1654,6 +1654,11 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { return; } + if (groupUpdate.command == GroupUpdateCommand::ADD && groups.size() >= MaximumGroupCount) { + LOG("Cannot add group to inventory %s. Maximum group count reached.", StringifiedEnum::ToString(groupUpdate.inventory).data()); + return; + } + switch (groupUpdate.command) { case GroupUpdateCommand::ADD: { auto& group = groups[groupUpdate.groupId]; diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 3abb919ff..90d2f30df 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -62,6 +62,8 @@ class InventoryComponent final : public Component { GroupUpdateCommand command; }; + static constexpr uint32_t MaximumGroupCount = 50; + static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY; InventoryComponent(Entity* parent); From 386bb2c2bb4906449a022940a8eddb57555d9f28 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 19 May 2024 20:55:19 -0700 Subject: [PATCH 4/9] Use vector for storing groups --- dGame/dComponents/InventoryComponent.cpp | 41 +++++++++++------------- dGame/dComponents/InventoryComponent.h | 5 ++- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index ed4b9476c..16e4a4093 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -39,6 +39,8 @@ #include "CDSkillBehaviorTable.h" #include "StringifiedEnum.h" +#include + InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) { this->m_Dirty = true; this->m_Equipped = {}; @@ -1648,8 +1650,11 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { } auto& groups = m_Groups[groupUpdate.inventory]; + auto groupItr = std::ranges::find_if(groups, [&groupUpdate](const Group& group) { + return group.groupId == groupUpdate.groupId; + }); - if (groupUpdate.command != GroupUpdateCommand::ADD && !groups.contains(groupUpdate.groupId)) { + if (groupUpdate.command != GroupUpdateCommand::ADD && groupItr == groups.end()) { LOG("Group %i not found in inventory %s. Cannot process command.", groupUpdate.groupId, StringifiedEnum::ToString(groupUpdate.inventory).data()); return; } @@ -1661,25 +1666,25 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { switch (groupUpdate.command) { case GroupUpdateCommand::ADD: { - auto& group = groups[groupUpdate.groupId]; + auto& group = groups.emplace_back(); + group.groupId = groupUpdate.groupId; group.groupName = groupUpdate.groupName; - group.inventory = groupUpdate.inventory; break; } case GroupUpdateCommand::ADD_LOT: { - groups[groupUpdate.groupId].lots.insert(groupUpdate.lot); + groupItr->lots.insert(groupUpdate.lot); break; } case GroupUpdateCommand::REMOVE: { - groups.erase(groupUpdate.groupId); + groups.erase(groupItr); break; } case GroupUpdateCommand::REMOVE_LOT: { - groups[groupUpdate.groupId].lots.erase(groupUpdate.lot); + groupItr->lots.erase(groupUpdate.lot); break; } case GroupUpdateCommand::MODIFY: { - groups[groupUpdate.groupId].groupName = groupUpdate.groupName; + groupItr->groupName = groupUpdate.groupName; break; } default: { @@ -1687,24 +1692,16 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { break; } } - - // debug printing of groups - for (const auto& [groupId, group] : groups) { - LOG("Group %s: %s inventory %s", groupId.c_str(), group.groupName.c_str(), StringifiedEnum::ToString(group.inventory).data()); - for (const auto& lot : group.lots) { - LOG("Lot %i", lot); - } - } } void InventoryComponent::UpdateGroupXml(tinyxml2::XMLElement& groups) const { for (const auto& [inventory, groupsData] : m_Groups) { - for (const auto& [groupId, group] : groupsData) { + for (const auto& group : groupsData) { auto* const groupElement = groups.InsertNewChildElement("grp"); - groupElement->SetAttribute("id", groupId.c_str()); + groupElement->SetAttribute("id", group.groupId.c_str()); groupElement->SetAttribute("n", group.groupName.c_str()); - groupElement->SetAttribute("t", static_cast(group.inventory)); + groupElement->SetAttribute("t", static_cast(inventory)); groupElement->SetAttribute("u", 0); std::ostringstream lots; bool first = true; @@ -1726,20 +1723,20 @@ void InventoryComponent::LoadGroupXml(const tinyxml2::XMLElement& groups) { const char* groupId = nullptr; const char* groupName = nullptr; const char* lots = nullptr; - eInventoryType inventory = eInventoryType::INVALID; + uint32_t inventory = eInventoryType::INVALID; groupElement->QueryStringAttribute("id", &groupId); groupElement->QueryStringAttribute("n", &groupName); groupElement->QueryStringAttribute("l", &lots); - groupElement->QueryAttribute("t", reinterpret_cast(&inventory)); + groupElement->QueryAttribute("t", &inventory); if (!groupId || !groupName || !lots) { LOG("Failed to load group from xml id %i name %i lots %i", groupId == nullptr, groupName == nullptr, lots == nullptr); } else { - auto& group = m_Groups[inventory][groupId]; + auto& group = m_Groups[static_cast(inventory)].emplace_back(); + group.groupId = groupId; group.groupName = groupName; - group.inventory = inventory; for (const auto& lotStr : GeneralUtils::SplitString(lots, ' ')) { auto lot = GeneralUtils::TryParse(lotStr); diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 90d2f30df..3cba0d3c9 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -38,12 +38,11 @@ enum class eItemType : int32_t; class InventoryComponent final : public Component { public: struct Group { + std::string groupId; // Custom name assigned by the user. std::string groupName; // All the lots the user has in the group. std::set lots; - // The inventory this group belongs to. - eInventoryType inventory; }; enum class GroupUpdateCommand { @@ -409,7 +408,7 @@ class InventoryComponent final : public Component { * The key is the inventory the group belongs to, the value maps' key is the id for the group. * This is only used for bricks and model inventories. */ - std::map> m_Groups{ { eInventoryType::BRICKS, {} }, { eInventoryType::MODELS, {} } }; + std::map> m_Groups{ { eInventoryType::BRICKS, {} }, { eInventoryType::MODELS, {} } }; /** * All the inventory this entity possesses From b018a49904c0ff91213ea01a04cb32629c570f6b Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 19 May 2024 20:56:32 -0700 Subject: [PATCH 5/9] Update InventoryComponent.cpp --- dGame/dComponents/InventoryComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 16e4a4093..466ab9266 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1655,7 +1655,7 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { }); if (groupUpdate.command != GroupUpdateCommand::ADD && groupItr == groups.end()) { - LOG("Group %i not found in inventory %s. Cannot process command.", groupUpdate.groupId, StringifiedEnum::ToString(groupUpdate.inventory).data()); + LOG("Group %i not found in inventory %s. Cannot process command.", groupUpdate.groupId.c_str(), StringifiedEnum::ToString(groupUpdate.inventory).data()); return; } From 9a34b48a5eba82db36f7b393c2458ec053e581c4 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 19 May 2024 21:00:50 -0700 Subject: [PATCH 6/9] Update InventoryComponent.h --- dGame/dComponents/InventoryComponent.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 3cba0d3c9..cee57ea69 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -38,6 +38,7 @@ enum class eItemType : int32_t; class InventoryComponent final : public Component { public: struct Group { + // Generated ID for the group. The ID is sent by the client and has the format user_group + Math.random() * UINT_MAX. std::string groupId; // Custom name assigned by the user. std::string groupName; From 81a87cf254a28f6b42550bb1c7e6812b4bdef2a5 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 19 May 2024 21:01:51 -0700 Subject: [PATCH 7/9] Update InventoryComponent.h --- dGame/dComponents/InventoryComponent.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index cee57ea69..28158ab58 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -54,6 +54,8 @@ class InventoryComponent final : public Component { REMOVE_LOT, }; + // Based on the command, certain fields will be used or not used. + // for example, ADD_LOT wont use groupName, MODIFY wont use lots, etc. struct GroupUpdate { std::string groupId; std::string groupName; From 7f77c599576108bd1d006a639a958c9d26594805 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 19 May 2024 21:12:14 -0700 Subject: [PATCH 8/9] fix string log format --- dGame/dComponents/InventoryComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 466ab9266..c05c10cfe 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1655,7 +1655,7 @@ void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { }); if (groupUpdate.command != GroupUpdateCommand::ADD && groupItr == groups.end()) { - LOG("Group %i not found in inventory %s. Cannot process command.", groupUpdate.groupId.c_str(), StringifiedEnum::ToString(groupUpdate.inventory).data()); + LOG("Group %s not found in inventory %s. Cannot process command.", groupUpdate.groupId.c_str(), StringifiedEnum::ToString(groupUpdate.inventory).data()); return; } From cd5740f03092584ae0e3bbd01128ca6ed59b75c1 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Wed, 12 Jun 2024 19:19:49 -0700 Subject: [PATCH 9/9] Update GameMessages.cpp --- dGame/dGameMessages/GameMessages.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 494f3742b..2fba411b8 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -6312,6 +6312,8 @@ void GameMessages::HandleUpdateInventoryGroupContents(RakNet::BitStream& inStrea auto* inventoryComponent = entity->GetComponent(); if (inventoryComponent) inventoryComponent->UpdateGroup(groupUpdate); +} + void GameMessages::SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID) { CBITSTREAM; CMSGHEADER;