From 81404d9671425025d00786dc917461e3d8b8bf9b Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Wed, 28 Jun 2023 01:20:41 -0700 Subject: [PATCH] InventoryComponent pass - reduce scope usage - bouncing returns - std::for_each in some contexts - extra nullptr checks - constiness - extra logs - scoped enum type for eItemType - lol serialization. --- dCommon/dEnums/dCommonVars.h | 1 + dDatabase/Tables/CDItemComponentTable.cpp | 4 +- dDatabase/Tables/CDItemComponentTable.h | 4 +- dGame/dComponents/InventoryComponent.cpp | 566 ++++++++-------------- dGame/dComponents/InventoryComponent.h | 24 +- 5 files changed, 216 insertions(+), 383 deletions(-) diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index b2688c96..3ae5c831 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -60,6 +60,7 @@ const LOT LOT_ZONE_CONTROL = 2365; const LOT LOT_3D_AMBIENT_SOUND = 6368; const LOT LOT_MODEL_IN_WORLD = 14; const LOT LOT_THINKING_CAP = 6086; +const LOT LOT_ROCKET = 6416; const float PI = 3.14159f; diff --git a/dDatabase/Tables/CDItemComponentTable.cpp b/dDatabase/Tables/CDItemComponentTable.cpp index 01f36062..d44b9d28 100644 --- a/dDatabase/Tables/CDItemComponentTable.cpp +++ b/dDatabase/Tables/CDItemComponentTable.cpp @@ -1,6 +1,8 @@ #include "CDItemComponentTable.h" #include "GeneralUtils.h" +#include "eItemType.h" + CDItemComponent CDItemComponentTable::Default = {}; //! Constructor @@ -98,7 +100,7 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int i entry.baseValue = tableData.getIntField("baseValue", -1); entry.isKitPiece = tableData.getIntField("isKitPiece", -1) == 1 ? true : false; entry.rarity = tableData.getIntField("rarity", 0); - entry.itemType = tableData.getIntField("itemType", -1); + entry.itemType = static_cast(tableData.getIntField("itemType", -1)); entry.itemInfo = tableData.getInt64Field("itemInfo", -1); entry.inLootTable = tableData.getIntField("inLootTable", -1) == 1 ? true : false; entry.inVendor = tableData.getIntField("inVendor", -1) == 1 ? true : false; diff --git a/dDatabase/Tables/CDItemComponentTable.h b/dDatabase/Tables/CDItemComponentTable.h index 08761d61..3e1eaf1d 100644 --- a/dDatabase/Tables/CDItemComponentTable.h +++ b/dDatabase/Tables/CDItemComponentTable.h @@ -4,13 +4,15 @@ #include "CDTable.h" #include "dCommonVars.h" +enum class eItemType : int32_t; + struct CDItemComponent { unsigned int id; //!< The Component ID std::string equipLocation; //!< The equip location unsigned int baseValue; //!< The monetary base value of the item bool isKitPiece; //!< Whether or not the item belongs to a kit unsigned int rarity; //!< The rarity of the item - unsigned int itemType; //!< The item type + eItemType itemType; //!< The item type int64_t itemInfo; //!< The item info bool inLootTable; //!< Whether or not the item is in a loot table bool inVendor; //!< Whether or not the item is in a vendor inventory diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 80109ef5..0e1c2427 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -47,7 +47,7 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do const auto lot = parent->GetLOT(); - if (lot == 1) { + if (m_ParentEntity->IsPlayer()) { LoadXml(document); CheckProxyIntegrity(); @@ -59,7 +59,7 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do const auto componentId = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::INVENTORY); auto* inventoryComponentTable = CDClientManager::Instance().GetTable(); - auto items = inventoryComponentTable->Query([=](const CDInventoryComponent entry) { return entry.id == componentId; }); + auto items = inventoryComponentTable->Query([&componentId](const CDInventoryComponent entry) { return entry.id == componentId; }); auto slot = 0u; @@ -79,18 +79,21 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do subItems.erase(std::remove_if(subItems.begin(), subItems.end(), ::isspace), subItems.end()); - if (!subItems.empty()) { - const auto subItemsSplit = GeneralUtils::SplitString(subItems, ','); + if (subItems.empty()) return; + const auto subItemsSplit = GeneralUtils::SplitString(subItems, ','); - for (auto proxyLotAsString : subItemsSplit) { - const auto proxyLOT = static_cast(std::stoi(proxyLotAsString)); - - const auto& proxyInfo = Inventory::FindItemComponent(proxyLOT); - const LWOOBJID proxyId = ObjectIDManager::Instance()->GenerateObjectID(); - - // Use item.count since we equip item.count number of the item this is a requested proxy of - UpdateSlot(proxyInfo.equipLocation, EquippedItem(proxyId, proxyLOT, item.count, slot++)); + for (const auto& proxyLotAsString : subItemsSplit) { + LOT proxyLot; + if (GeneralUtils::TryParse(proxyLotAsString, proxyLot)) { + Game::logger->Log("InventoryComponent", "Failed to parse %s to lot for entity %i:%llu", proxyLotAsString.c_str(), m_ParentEntity->GetLOT(), m_ParentEntity->GetObjectID()); + continue; } + + const auto& proxyInfo = Inventory::FindItemComponent(proxyLot); + const LWOOBJID proxyId = ObjectIDManager::Instance()->GenerateObjectID(); + + // Use item.count since we equip item.count number of the item this is a requested proxy of + UpdateSlot(proxyInfo.equipLocation, EquippedItem(proxyId, proxyLot, item.count, slot++)); } } } @@ -98,9 +101,7 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do Inventory* InventoryComponent::GetInventory(const eInventoryType type) { const auto index = m_Inventories.find(type); - if (index != m_Inventories.end()) { - return index->second; - } + if (index != m_Inventories.end()) return index->second; // Create new empty inventory uint32_t size = 240u; @@ -120,22 +121,18 @@ Inventory* InventoryComponent::GetInventory(const eInventoryType type) { break; } - auto* inventory = new Inventory(type, size, {}, this); + auto* inventory = new Inventory(type, size, std::vector(), this); m_Inventories.insert_or_assign(type, inventory); return inventory; } -const std::map& InventoryComponent::GetInventories() const { - return m_Inventories; -} - uint32_t InventoryComponent::GetLotCount(const LOT lot) const { uint32_t count = 0; - for (const auto& inventory : m_Inventories) { - count += inventory.second->GetLotCount(lot); + for (const auto& [inventoryId, inventory] : m_Inventories) { + count += inventory->GetLotCount(lot); } return count; @@ -144,19 +141,15 @@ uint32_t InventoryComponent::GetLotCount(const LOT lot) const { uint32_t InventoryComponent::GetLotCountNonTransfer(LOT lot) const { uint32_t count = 0; - for (const auto& inventory : m_Inventories) { - if (IsTransferInventory(inventory.second->GetType())) continue; + for (const auto [inventoryId, inventory] : m_Inventories) { + if (IsTransferInventory(inventory->GetType())) continue; - count += inventory.second->GetLotCount(lot); + count += inventory->GetLotCount(lot); } return count; } -const EquipmentMap& InventoryComponent::GetEquippedItems() const { - return m_Equipped; -} - void InventoryComponent::AddItem( const LOT lot, const uint32_t count, @@ -172,46 +165,43 @@ void InventoryComponent::AddItem( const bool bound, int32_t preferredSlot) { if (count == 0) { - Game::logger->Log("InventoryComponent", "Attempted to add 0 of item (%i) to the inventory!", lot); - + Game::logger->Log("InventoryComponent", "Attempted to add 0 of item (%i) to the inventory of %i:%llu!", lot, m_ParentEntity->GetLOT(), m_ParentEntity->GetObjectID()); return; } if (!Inventory::IsValidItem(lot)) { if (lot > 0) { - Game::logger->Log("InventoryComponent", "Attempted to add invalid item (%i) to the inventory!", lot); + Game::logger->Log("InventoryComponent", "Attempted to add invalid item (%i) to the inventory of %i:%llu!", lot, m_ParentEntity->GetLOT(), m_ParentEntity->GetObjectID()); } - return; } - if (inventoryType == INVALID) { - inventoryType = Inventory::FindInventoryTypeForLot(lot); - } + if (inventoryType == INVALID) inventoryType = Inventory::FindInventoryTypeForLot(lot); - auto* missions = m_ParentEntity->GetComponent(); + auto* missionComponent = m_ParentEntity->GetComponent(); auto* inventory = GetInventory(inventoryType); + // Config items cant stack as they are unique per item. if (!config.empty() || bound) { const auto slot = preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot) ? preferredSlot : inventory->FindEmptySlot(); if (slot == -1) { - Game::logger->Log("InventoryComponent", "Failed to find empty slot for inventory (%i)!", inventoryType); + Game::logger->Log("InventoryComponent", "Failed to find empty slot for inventory (%i) of %i:%llu!", inventoryType, m_ParentEntity->GetLOT(), m_ParentEntity->GetObjectID()); return; } auto* item = new Item(lot, inventory, slot, count, config, parent, showFlyingLoot, isModMoveAndEquip, subKey, bound, lootSourceType); - if (missions != nullptr && !IsTransferInventory(inventoryType)) { - missions->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count, IsTransferInventory(inventorySourceType)); + if (missionComponent && !IsTransferInventory(inventoryType)) { + missionComponent->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count, IsTransferInventory(inventorySourceType)); } return; } - const auto info = Inventory::FindItemComponent(lot); + const auto& info = Inventory::FindItemComponent(lot); auto left = count; @@ -219,7 +209,7 @@ void InventoryComponent::AddItem( auto stack = static_cast(info.stackSize); - bool isBrick = inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == 1); + bool isBrick = inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == eItemType::BRICK); // info.itemType of 1 is item type brick if (isBrick) { @@ -230,7 +220,7 @@ void InventoryComponent::AddItem( auto* existing = FindItemByLot(lot, inventoryType); - if (existing != nullptr) { + if (existing) { const auto delta = std::min(left, stack - existing->GetCount()); left -= delta; @@ -263,9 +253,7 @@ void InventoryComponent::AddItem( if (slot == -1) { auto* player = dynamic_cast(GetParentEntity()); - if (player == nullptr) { - return; - } + if (!player) return; outOfSpace += size; @@ -292,14 +280,14 @@ void InventoryComponent::AddItem( isModMoveAndEquip = false; } - if (missions != nullptr && !IsTransferInventory(inventoryType)) { - missions->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count - outOfSpace, IsTransferInventory(inventorySourceType)); - } + if (!missionComponent || IsTransferInventory(inventoryType)) return; + + missionComponent->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count - outOfSpace, IsTransferInventory(inventorySourceType)); } void InventoryComponent::RemoveItem(const LOT lot, const uint32_t count, eInventoryType inventoryType, const bool ignoreBound) { if (count == 0) { - Game::logger->Log("InventoryComponent", "Attempted to remove 0 of item (%i) from the inventory!", lot); + Game::logger->Log("InventoryComponent", "Attempted to remove 0 of item (%i) from the inventory of %i:%llu!", lot, m_ParentEntity->GetLOT(), m_ParentEntity->GetObjectID()); return; } @@ -310,18 +298,14 @@ void InventoryComponent::RemoveItem(const LOT lot, const uint32_t count, eInvent auto* inventory = GetInventory(inventoryType); - if (inventory == nullptr) { - return; - } + if (!inventory) return; auto left = std::min(count, inventory->GetLotCount(lot)); while (left > 0) { auto* item = FindItemByLot(lot, inventoryType, false, ignoreBound); - if (item == nullptr) { - break; - } + if (!item) break; const auto delta = std::min(left, item->GetCount()); @@ -332,9 +316,7 @@ void InventoryComponent::RemoveItem(const LOT lot, const uint32_t count, eInvent } void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType inventory, const uint32_t count, const bool showFlyingLot, bool isModMoveAndEquip, const bool ignoreEquipped, const int32_t preferredSlot) { - if (item == nullptr) { - return; - } + if (!item) return; auto* origin = item->GetInventory(); @@ -346,12 +328,10 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in auto left = std::min(count, origin->GetLotCount(lot)); while (left > 0) { - if (item == nullptr) { + if (!item) { item = origin->FindItemByLot(lot, false); - if (item == nullptr) { - break; - } + if (!item) break; } const auto delta = std::min(item->GetCount(), left); @@ -380,7 +360,7 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in auto* missionComponent = m_ParentEntity->GetComponent(); - if (missionComponent != nullptr) { + if (missionComponent) { if (IsTransferInventory(inventory)) { missionComponent->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", -static_cast(count)); } @@ -388,6 +368,8 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in } void InventoryComponent::MoveStack(Item* item, const eInventoryType inventory, const uint32_t slot) { + if (!item) return; + if (inventory != INVALID && item->GetInventory()->GetType() != inventory) { auto* newInventory = GetInventory(inventory); @@ -398,12 +380,15 @@ void InventoryComponent::MoveStack(Item* item, const eInventoryType inventory, c } Item* InventoryComponent::FindItemById(const LWOOBJID id) const { - for (const auto& inventory : m_Inventories) { - auto* item = inventory.second->FindItemById(id); + if (id == LWOOBJID_EMPTY) { + Game::logger->Log("InventoryComponent", "Attempted to find item with empty id!"); - if (item != nullptr) { - return item; - } + return nullptr; + } + for (const auto [inventoryType, inventory] : m_Inventories) { + auto* item = inventory->FindItemById(id); + + if (item) return item; } return nullptr; @@ -420,13 +405,17 @@ Item* InventoryComponent::FindItemByLot(const LOT lot, eInventoryType inventoryT } Item* InventoryComponent::FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType) { - if (inventoryType == INVALID) { - for (const auto& inventory : m_Inventories) { - auto* item = inventory.second->FindItemBySubKey(id); + if (id == LWOOBJID_EMPTY) { + Game::logger->Log("InventoryComponent", "Attempted to find item by SubKey with empty id!"); - if (item != nullptr) { - return item; - } + return nullptr; + } + + if (inventoryType == INVALID) { + for (const auto& [inventoryId, inventory] : m_Inventories) { + auto* item = inventory->FindItemBySubKey(id); + + if (item) return item; } return nullptr; @@ -440,28 +429,24 @@ bool InventoryComponent::HasSpaceForLoot(const std::unordered_map& uint32_t slotsNeeded = 0; - for (const auto& pair : loot) { - const auto inventoryType = Inventory::FindInventoryTypeForLot(pair.first); + for (const auto& [item, count] : loot) { + const auto inventoryType = Inventory::FindInventoryTypeForLot(item); - if (inventoryType == BRICKS) { - continue; - } + if (inventoryType == BRICKS) continue; auto* inventory = GetInventory(inventoryType); - if (inventory == nullptr) { - return false; - } + if (!inventory) return false; - const auto info = Inventory::FindItemComponent(pair.first); + const auto info = Inventory::FindItemComponent(item); auto stack = static_cast(info.stackSize); - auto left = pair.second; + auto left = count; - auto* partial = inventory->FindItemByLot(pair.first); + auto* partial = inventory->FindItemByLot(item); - if (partial != nullptr && partial->GetCount() < stack) { + if (partial && partial->GetCount() < stack) { left -= stack - partial->GetCount(); } @@ -492,7 +477,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { auto* inventoryElement = document->FirstChildElement("obj")->FirstChildElement("inv"); - if (inventoryElement == nullptr) { + if (!inventoryElement) { Game::logger->Log("InventoryComponent", "Failed to find 'inv' xml element!"); return; @@ -500,7 +485,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { auto* bags = inventoryElement->FirstChildElement("bag"); - if (bags == nullptr) { + if (!bags) { Game::logger->Log("InventoryComponent", "Failed to find 'bags' xml element!"); return; @@ -510,7 +495,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { auto* bag = bags->FirstChildElement(); - while (bag != nullptr) { + while (bag) { unsigned int type; unsigned int size; @@ -526,7 +511,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { auto* items = inventoryElement->FirstChildElement("items"); - if (items == nullptr) { + if (!items) { Game::logger->Log("InventoryComponent", "Failed to find 'items' xml element!"); return; @@ -534,7 +519,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { bag = items->FirstChildElement(); - while (bag != nullptr) { + while (bag) { unsigned int type; bag->QueryAttribute("t", &type); @@ -549,7 +534,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { auto* itemElement = bag->FirstChildElement(); - while (itemElement != nullptr) { + while (itemElement) { LWOOBJID id; LOT lot; bool equipped; @@ -600,11 +585,11 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { bag = bag->NextSiblingElement(); } - for (const auto inventory : m_Inventories) { - const auto itemCount = inventory.second->GetItems().size(); + for (const auto [inventoryId, inventory] : m_Inventories) { + const auto itemCount = inventory->GetItems().size(); - if (inventory.second->GetSize() < itemCount) { - inventory.second->SetSize(itemCount); + if (inventory->GetSize() < itemCount) { + inventory->SetSize(itemCount); } } } @@ -623,9 +608,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { std::vector inventoriesToSave; // Need to prevent some transfer inventories from being saved - for (const auto& pair : this->m_Inventories) { - auto* inventory = pair.second; - + for (const auto [inventoryId, inventory] : this->m_Inventories) { if (inventory->GetType() == VENDOR_BUYBACK || inventory->GetType() == eInventoryType::MODELS_IN_BBB) { continue; } @@ -637,7 +620,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { auto* bags = inventoryElement->FirstChildElement("bag"); - if (bags == nullptr) { + if (!bags) { Game::logger->Log("InventoryComponent", "Failed to find 'bags' xml element!"); return; @@ -656,7 +639,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { auto* items = inventoryElement->FirstChildElement("items"); - if (items == nullptr) { + if (!items) { Game::logger->Log("InventoryComponent", "Failed to find 'items' xml element!"); return; @@ -665,17 +648,13 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { items->DeleteChildren(); for (auto* inventory : inventoriesToSave) { - if (inventory->GetSize() == 0) { - continue; - } + if (inventory->GetSize() == 0) continue; auto* bagElement = document->NewElement("in"); bagElement->SetAttribute("t", inventory->GetType()); - for (const auto& pair : inventory->GetItems()) { - auto* item = pair.second; - + for (const auto [itemObjId, item] : inventory->GetItems()) { auto* itemElement = document->NewElement("i"); itemElement->SetAttribute("l", item->GetLot()); @@ -710,12 +689,11 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { } void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool bIsInitialUpdate, unsigned& flags) { + outBitStream->Write(bIsInitialUpdate || m_Dirty); if (bIsInitialUpdate || m_Dirty) { - outBitStream->Write(true); - outBitStream->Write(m_Equipped.size()); - for (const auto&[x, item] : m_Equipped) { + for (const auto [itemObjId, item] : m_Equipped) { if (bIsInitialUpdate) AddItemSkills(item.lot); outBitStream->Write(item.id); @@ -755,16 +733,10 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b outBitStream->Write1(); } - m_Dirty = false; - } else { - outBitStream->Write(false); + if (!bIsInitialUpdate) m_Dirty = false; } - outBitStream->Write(false); -} - -void InventoryComponent::ResetFlags() { - m_Dirty = false; + outBitStream->Write0(); // Equipped model transforms } void InventoryComponent::Update(float deltaTime) { @@ -787,7 +759,7 @@ void InventoryComponent::UpdateSlot(const std::string& location, EquippedItem it auto* old = FindItemById(index->second.id); - if (old != nullptr) { + if (old) { UnEquipItem(old); } } @@ -798,9 +770,7 @@ void InventoryComponent::UpdateSlot(const std::string& location, EquippedItem it } void InventoryComponent::RemoveSlot(const std::string& location) { - if (m_Equipped.find(location) == m_Equipped.end()) { - return; - } + if (m_Equipped.find(location) == m_Equipped.end()) return; m_Equipped.erase(location); @@ -819,9 +789,9 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { auto* character = m_ParentEntity->GetCharacter(); - if (character != nullptr && !skipChecks) { + if (character && !skipChecks) { // Hacky proximity rocket - if (item->GetLot() == 6416) { + if (item->GetLot() == LOT_ROCKET) { const auto rocketLauchPads = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::ROCKET_LAUNCHPAD_CONTROL); const auto position = m_ParentEntity->GetPosition(); @@ -839,7 +809,7 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { auto* characterComponent = m_ParentEntity->GetComponent(); - if (characterComponent != nullptr) characterComponent->SetLastRocketItemID(item->GetId()); + if (characterComponent) characterComponent->SetLastRocketItemID(item->GetId()); launchPad->OnUse(m_ParentEntity); @@ -851,10 +821,10 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { const auto building = character->GetBuildMode(); - const auto type = static_cast(item->GetInfo().itemType); + const auto type = item->GetInfo().itemType; - if (!building && (item->GetLot() == 6086 || type == eItemType::LOOT_MODEL || type == eItemType::VEHICLE)) return; + if (!building && (item->GetLot() == LOT_THINKING_CAP || type == eItemType::LOOT_MODEL || type == eItemType::VEHICLE)) return; if (type != eItemType::LOOT_MODEL && type != eItemType::MODEL) { if (!item->GetBound() && !item->GetPreconditionExpression()->Check(m_ParentEntity)) { @@ -887,15 +857,11 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { } void InventoryComponent::UnEquipItem(Item* item) { - if (!item->IsEquipped()) { - return; - } + if (!item->IsEquipped()) return; const auto lot = item->GetLot(); - if (!Inventory::IsValidItem(lot)) { - return; - } + if (!Inventory::IsValidItem(lot)) return; CheckItemSet(lot); @@ -923,37 +889,33 @@ void InventoryComponent::UnEquipItem(Item* item) { } -void InventoryComponent::EquipScripts(Item* equippedItem) { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); - if (!compRegistryTable) return; +void InventoryComponent::EquipScripts(Item* equippedItem) const { + auto* compRegistryTable = CDClientManager::Instance().GetTable(); + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1); if (scriptComponentID > -1) { - CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable(); - CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); + auto* scriptCompTable = CDClientManager::Instance().GetTable(); + auto scriptCompData = scriptCompTable->GetByID(scriptComponentID); auto* itemScript = CppScripts::GetScript(m_ParentEntity, scriptCompData.script_name); - if (!itemScript) { - Game::logger->Log("InventoryComponent", "null script?"); - } + DluAssert(itemScript != nullptr); itemScript->OnFactionTriggerItemEquipped(m_ParentEntity, equippedItem->GetId()); } } -void InventoryComponent::UnequipScripts(Item* unequippedItem) { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); - if (!compRegistryTable) return; +void InventoryComponent::UnequipScripts(Item* unequippedItem) const { + auto* compRegistryTable = CDClientManager::Instance().GetTable(); + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1); if (scriptComponentID > -1) { - CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable(); - CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); + auto* scriptCompTable = CDClientManager::Instance().GetTable(); + auto scriptCompData = scriptCompTable->GetByID(scriptComponentID); auto* itemScript = CppScripts::GetScript(m_ParentEntity, scriptCompData.script_name); - if (!itemScript) { - Game::logger->Log("InventoryComponent", "null script?"); - } + DluAssert(itemScript != nullptr); itemScript->OnFactionTriggerItemUnequipped(m_ParentEntity, unequippedItem->GetId()); } } -void InventoryComponent::HandlePossession(Item* item) { +void InventoryComponent::HandlePossession(Item* item) const { auto* characterComponent = m_ParentEntity->GetComponent(); if (!characterComponent) return; @@ -991,23 +953,11 @@ void InventoryComponent::HandlePossession(Item* item) { // Check to see if the mount is a vehicle, if so, flip it auto* havokVehiclePhysicsComponent = mount->GetComponent(); - if (havokVehiclePhysicsComponent) { - auto angles = startRotation.GetEulerAngles(); - // Make it right side up - angles.x -= PI; - // Make it going in the direction of the player - angles.y -= PI; - startRotation = NiQuaternion::FromEulerAngles(angles); - mount->SetRotation(startRotation); - // We're pod racing now - characterComponent->SetIsRacing(true); - } + if (havokVehiclePhysicsComponent) characterComponent->SetIsRacing(true); // Setup the destroyable stats auto* destroyableComponent = mount->GetComponent(); - if (destroyableComponent) { - destroyableComponent->SetIsImmune(true); - } + if (destroyableComponent) destroyableComponent->SetIsImmune(true); // Mount it auto* possessableComponent = mount->GetComponent(); @@ -1060,21 +1010,13 @@ void InventoryComponent::PopEquippedItems() { for (const auto& pair : current) { auto* const item = FindItemById(pair.second.id); - if (item == nullptr) { - continue; - } - - item->UnEquip(); + if (item) item->UnEquip(); } for (const auto& pair : m_Pushed) { auto* const item = FindItemById(pair.second.id); - if (item == nullptr) { - continue; - } - - item->Equip(); + if (item) item->Equip(); } m_Pushed.clear(); @@ -1094,8 +1036,8 @@ void InventoryComponent::PopEquippedItems() { bool InventoryComponent::IsEquipped(const LOT lot) const { - for (const auto& pair : m_Equipped) { - if (pair.second.lot == lot) { + for (const auto& [equipLocation, equippedItem] : m_Equipped) { + if (equippedItem.lot == lot) { return true; } } @@ -1105,15 +1047,11 @@ bool InventoryComponent::IsEquipped(const LOT lot) const { void InventoryComponent::CheckItemSet(const LOT lot) { // Check if the lot is in the item set cache - if (std::find(m_ItemSetsChecked.begin(), m_ItemSetsChecked.end(), lot) != m_ItemSetsChecked.end()) { - return; - } - - const std::string lot_query = "%" + std::to_string(lot) + "%"; + if (std::find(m_ItemSetsChecked.begin(), m_ItemSetsChecked.end(), lot) != m_ItemSetsChecked.end()) return; auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT setID FROM ItemSets WHERE itemIDs LIKE ?;"); - query.bind(1, lot_query.c_str()); + "SELECT setID FROM ItemSets WHERE itemIDs LIKE %?%;"); + query.bind(1, lot); auto result = query.execQuery(); @@ -1140,34 +1078,20 @@ void InventoryComponent::CheckItemSet(const LOT lot) { } m_ItemSetsChecked.push_back(lot); - - result.finalize(); -} - -void InventoryComponent::SetConsumable(LOT lot) { - m_Consumable = lot; -} - -LOT InventoryComponent::GetConsumable() const { - return m_Consumable; } void InventoryComponent::AddItemSkills(const LOT lot) { const auto info = Inventory::FindItemComponent(lot); - const auto slot = FindBehaviorSlot(static_cast(info.itemType)); + const auto slot = FindBehaviorSlot(info.itemType); - if (slot == BehaviorSlot::Invalid) { - return; - } + if (slot == BehaviorSlot::Invalid) return; const auto index = m_Skills.find(slot); const auto skill = FindSkill(lot); - if (skill == 0) { - return; - } + if (skill == 0) return; if (index != m_Skills.end()) { const auto old = index->second; @@ -1183,32 +1107,27 @@ void InventoryComponent::AddItemSkills(const LOT lot) { void InventoryComponent::RemoveItemSkills(const LOT lot) { const auto info = Inventory::FindItemComponent(lot); - const auto slot = FindBehaviorSlot(static_cast(info.itemType)); + const auto slot = FindBehaviorSlot(info.itemType); - if (slot == BehaviorSlot::Invalid) { - return; - } + if (slot == BehaviorSlot::Invalid) return; const auto index = m_Skills.find(slot); - if (index == m_Skills.end()) { - return; - } + if (index == m_Skills.end()) return; - const auto old = index->second; + const auto skillId = index->second; - GameMessages::SendRemoveSkill(m_ParentEntity, old); + GameMessages::SendRemoveSkill(m_ParentEntity, skillId); m_Skills.erase(slot); - if (slot == BehaviorSlot::Primary) { - m_Skills.insert_or_assign(BehaviorSlot::Primary, 1); + if (slot != BehaviorSlot::Primary) return; - GameMessages::SendAddSkill(m_ParentEntity, 1, static_cast(BehaviorSlot::Primary)); - } + m_Skills.insert_or_assign(BehaviorSlot::Primary, 1); + GameMessages::SendAddSkill(m_ParentEntity, 1, static_cast(BehaviorSlot::Primary)); } -void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) { +void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) const { for (auto* set : m_Itemsets) { set->TriggerPassiveAbility(trigger, target); } @@ -1231,16 +1150,14 @@ bool InventoryComponent::HasAnyPassive(const std::vectorGetObjectID()); - - if (current != nullptr) { - current->Deactivate(); - } + if (!current) return; + current->Deactivate(); } void InventoryComponent::SpawnPet(Item* item) { auto current = PetComponent::GetActivePet(m_ParentEntity->GetObjectID()); - if (current != nullptr) { + if (current) { current->Deactivate(); if (current->GetDatabaseId() == item->GetSubKey()) { @@ -1266,9 +1183,7 @@ void InventoryComponent::SpawnPet(Item* item) { auto* petComponent = pet->GetComponent(); - if (petComponent != nullptr) { - petComponent->Activate(item); - } + if (petComponent) petComponent->Activate(item); EntityManager::Instance()->ConstructEntity(pet); } @@ -1280,19 +1195,7 @@ void InventoryComponent::SetDatabasePet(LWOOBJID id, const DatabasePet& data) { const DatabasePet& InventoryComponent::GetDatabasePet(LWOOBJID id) const { const auto& pair = m_Pets.find(id); - if (pair == m_Pets.end()) return DATABASE_PET_INVALID; - - return pair->second; -} - -bool InventoryComponent::IsPet(LWOOBJID id) const { - const auto& pair = m_Pets.find(id); - - return pair != m_Pets.end(); -} - -void InventoryComponent::RemoveDatabasePet(LWOOBJID id) { - m_Pets.erase(id); + return pair == m_Pets.end() ? DATABASE_PET_INVALID : pair->second; } BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type) { @@ -1319,8 +1222,8 @@ bool InventoryComponent::IsTransferInventory(eInventoryType type) { uint32_t InventoryComponent::FindSkill(const LOT lot) { auto* table = CDClientManager::Instance().GetTable(); - const auto results = table->Query([=](const CDObjectSkills& entry) { - return entry.objectTemplate == static_cast(lot); + const auto results = table->Query([&lot](const CDObjectSkills& entry) { + return entry.objectTemplate == static_cast(lot); }); for (const auto& result : results) { @@ -1334,33 +1237,33 @@ uint32_t InventoryComponent::FindSkill(const LOT lot) { std::vector InventoryComponent::FindBuffs(Item* item, bool castOnEquip) const { std::vector buffs; - if (item == nullptr) return buffs; + if (!item) return buffs; auto* table = CDClientManager::Instance().GetTable(); auto* behaviors = CDClientManager::Instance().GetTable(); - const auto results = table->Query([=](const CDObjectSkills& entry) { + const auto results = table->Query([item](const CDObjectSkills& entry) { return entry.objectTemplate == static_cast(item->GetLot()); }); auto* missions = m_ParentEntity->GetComponent(); for (const auto& result : results) { - if (result.castOnType == 1) { - const auto entry = behaviors->GetSkillByID(result.skillID); + if (result.castOnType != 1) continue; - if (entry.skillID == 0) { - Game::logger->Log("InventoryComponent", "Failed to find buff behavior for skill (%i)!", result.skillID); + const auto entry = behaviors->GetSkillByID(result.skillID); - continue; - } + if (entry.skillID == 0) { + Game::logger->Log("InventoryComponent", "Failed to find buff behavior for skill (%i)!", result.skillID); - if (missions != nullptr && castOnEquip) { - missions->Progress(eMissionTaskType::USE_SKILL, result.skillID); - } - - // If item is not a proxy, add its buff to the added buffs. - if (item->GetParentEntity() == LWOOBJID_EMPTY) buffs.push_back(static_cast(entry.behaviorID)); + continue; } + + if (missions && castOnEquip) { + missions->Progress(eMissionTaskType::USE_SKILL, result.skillID); + } + + // If item is not a proxy, add its buff to the added buffs. + if (item->GetParentEntity() == LWOOBJID_EMPTY) buffs.push_back(static_cast(entry.behaviorID)); } return buffs; @@ -1383,15 +1286,13 @@ void InventoryComponent::SetNPCItems(const std::vector& items) { } InventoryComponent::~InventoryComponent() { - for (const auto& inventory : m_Inventories) { - delete inventory.second; + for (const auto& [inventoryId, inventory] : m_Inventories) { + delete inventory; } m_Inventories.clear(); - for (auto* set : m_Itemsets) { - delete set; - } + std::for_each(m_Itemsets.begin(), m_Itemsets.end(), [](ItemSet* set) { delete set; }); m_Itemsets.clear(); m_Pets.clear(); @@ -1402,28 +1303,21 @@ std::vector InventoryComponent::GenerateProxies(Item* parent) { auto subItems = parent->GetInfo().subItems; - if (subItems.empty()) { - return proxies; - } + if (subItems.empty()) return proxies; subItems.erase(std::remove_if(subItems.begin(), subItems.end(), ::isspace), subItems.end()); - std::stringstream stream(subItems); - std::string segment; - std::vector lots; + auto itemsAsStr = GeneralUtils::SplitString(subItems, ','); - while (std::getline(stream, segment, ',')) { - try { - lots.push_back(std::stoi(segment)); - } catch (std::invalid_argument& exception) { - Game::logger->Log("InventoryComponent", "Failed to parse proxy (%s): (%s)!", segment.c_str(), exception.what()); - } - } + std::vector lots; + std::for_each(itemsAsStr.begin(), itemsAsStr.end(), [&lots](const std::string& str) { + int32_t lot; + if (GeneralUtils::TryParse(str, lot)) lots.push_back(lot); + else Game::logger->Log("InventoryComponent", "failed to parse %s to a lot.", str.c_str()); + }); - for (const auto lot : lots) { - if (!Inventory::IsValidItem(lot)) { - continue; - } + std::for_each(lots.begin(), lots.end(), [&proxies, parent, this](const int lot) { + if (!Inventory::IsValidItem(lot)) return; auto* inventory = GetInventory(ITEM_SETS); @@ -1432,7 +1326,7 @@ std::vector InventoryComponent::GenerateProxies(Item* parent) { EquipItem(proxy); proxies.push_back(proxy); - } + }); return proxies; } @@ -1441,28 +1335,18 @@ std::vector InventoryComponent::FindProxies(const LWOOBJID parent) { auto* inventory = GetInventory(ITEM_SETS); std::vector proxies; - - for (const auto& pair : inventory->GetItems()) { - auto* item = pair.second; - - if (item->GetParentEntity() == parent) { - proxies.push_back(item); - } + for (const auto& [itemObjId, item] : inventory->GetItems()) { + if (item && item->GetParentEntity() != parent) proxies.push_back(item); } return proxies; } bool InventoryComponent::IsValidProxy(const LWOOBJID parent) { - for (const auto& pair : m_Inventories) { - const auto items = pair.second->GetItems(); - - for (const auto& candidate : items) { - auto* item = candidate.second; - - if (item->GetId() == parent) { - return true; - } + for (const auto& [inventoryType, inventory] : m_Inventories) { + if (!inventory) continue; + for (const auto& [itemObjId, item] : inventory->GetItems()) { + if (item->GetId() == parent) return true; } } @@ -1470,21 +1354,14 @@ bool InventoryComponent::IsValidProxy(const LWOOBJID parent) { } bool InventoryComponent::IsParentValid(Item* root) { - if (root->GetInfo().subItems.empty()) { - return true; - } + if (root->GetInfo().subItems.empty()) return true; const auto id = root->GetId(); - for (const auto& pair : m_Inventories) { - const auto items = pair.second->GetItems(); - - for (const auto& candidate : items) { - auto* item = candidate.second; - - if (item->GetParentEntity() == id) { - return true; - } + for (const auto& [inventoryType, inventory] : m_Inventories) { + if (!inventory) continue; + for (const auto& [itemObjId, item] : inventory->GetItems()) { + if (item->GetParentEntity() == id) return true; } } @@ -1494,67 +1371,16 @@ bool InventoryComponent::IsParentValid(Item* root) { void InventoryComponent::CheckProxyIntegrity() { std::vector dead; - for (const auto& pair : m_Inventories) { - const auto& items = pair.second->GetItems(); - - for (const auto& candidate : items) { - auto* item = candidate.second; - + for (const auto& [inventoryType, inventory] : m_Inventories) { + if (!inventory) continue; + for (const auto& [itemObjId, item] : inventory->GetItems()) { const auto parent = item->GetParentEntity(); - if (parent == LWOOBJID_EMPTY) { - continue; - } - - if (IsValidProxy(parent)) { - continue; - } - - dead.push_back(item); + if (parent != LWOOBJID_EMPTY && !IsValidProxy(parent)) dead.push_back(item); } } - for (auto* item : dead) { - item->RemoveFromInventory(); - } - - dead.clear(); - - /* - for (const auto& pair : inventories) - { - const auto& items = pair.second->GetItems(); - - for (const auto& candidate : items) - { - auto* item = candidate.second; - - const auto parent = item->GetParentEntity(); - - if (parent != LWOOBJID_EMPTY) - { - continue; - } - - if (!item->IsEquipped()) - { - continue; - } - - if (IsParentValid(item)) - { - continue; - } - - dead.push_back(item); - } - } - - for (auto* item : dead) - { - item->RemoveFromInventory(); - } - */ + std::for_each(dead.begin(), dead.end(), [](Item* item) { if (item) item->RemoveFromInventory(); }); } void InventoryComponent::PurgeProxies(Item* item) { @@ -1563,7 +1389,7 @@ void InventoryComponent::PurgeProxies(Item* item) { if (root != LWOOBJID_EMPTY) { item = FindItemById(root); - if (item != nullptr) { + if (item) { UnEquipItem(item); } @@ -1572,17 +1398,17 @@ void InventoryComponent::PurgeProxies(Item* item) { auto proxies = FindProxies(item->GetId()); - for (auto* proxy : proxies) { + std::for_each(proxies.begin(), proxies.end(), [](Item* proxy) { + if (!proxy) return; proxy->UnEquip(); - proxy->RemoveFromInventory(); - } + }); } void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) { auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); - if (petInventoryElement == nullptr) { + if (!petInventoryElement) { m_Pets.clear(); return; @@ -1590,7 +1416,7 @@ void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) { auto* petElement = petInventoryElement->FirstChildElement(); - while (petElement != nullptr) { + while (petElement) { LWOOBJID id; LOT lot; int32_t moderationStatus; @@ -1622,13 +1448,13 @@ void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) { petInventoryElement->DeleteChildren(); - for (const auto& pet : m_Pets) { + for (const auto& [petObjId, pet] : m_Pets) { auto* petElement = document->NewElement("p"); - petElement->SetAttribute("id", pet.first); - petElement->SetAttribute("l", pet.second.lot); - petElement->SetAttribute("m", pet.second.moderationState); - petElement->SetAttribute("n", pet.second.name.c_str()); + petElement->SetAttribute("id", petObjId); + petElement->SetAttribute("l", pet.lot); + petElement->SetAttribute("m", pet.moderationState); + petElement->SetAttribute("n", pet.name.c_str()); petElement->SetAttribute("t", 0); petInventoryElement->LinkEndChild(petElement); diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index b5b32cbf..fc4b4921 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -45,7 +45,7 @@ public: void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); void LoadXml(tinyxml2::XMLDocument* document); void UpdateXml(tinyxml2::XMLDocument* document) override; - void ResetFlags(); + void ResetFlags() { m_Dirty = false; }; /** * Returns an inventory of the specified type, if it exists @@ -58,10 +58,12 @@ public: * Returns all the inventories this entity has, indexed by type * @return all the inventories this entity has, indexed by type */ - const std::map& GetInventories() const; + const std::map& GetInventories() const { return m_Inventories; } /** * Returns the amount of items this entity possesses of a certain LOT + * This method counts the lot count for all inventories, including inventories the player may not be able to see. + * If you need the count in a specific inventory, call the inventory equivalent. * @param lot the lot to search for * @return the amount of items this entity possesses the specified LOT */ @@ -79,7 +81,7 @@ public: * Returns the items that are currently equipped by this entity * @return the items that are currently equipped by this entity */ - const EquipmentMap& GetEquippedItems() const; + const EquipmentMap& GetEquippedItems() const { return m_Equipped; } /** * Adds an item to the inventory of the entity @@ -206,7 +208,7 @@ public: * @param item the Item to unequip * @return if we were successful */ - void HandlePossession(Item* item); + void HandlePossession(Item* item) const; /** * Adds a buff related to equipping a lot to the entity @@ -247,13 +249,13 @@ public: * Sets the current consumable lot * @param lot the lot to set as consumable */ - void SetConsumable(LOT lot); + void SetConsumable(LOT lot) { m_Consumable = lot; }; /** * Returns the current consumable lot * @return the current consumable lot */ - LOT GetConsumable() const; + LOT GetConsumable() const { return m_Consumable; } /** * Finds all the buffs related to a lot @@ -285,7 +287,7 @@ public: * Triggers one of the passive abilities from the equipped item set * @param trigger the trigger to fire */ - void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr); + void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr) const; /** * Returns if the entity has any of the passed passive abilities equipped @@ -325,13 +327,13 @@ public: * @param id the id of the object to check for * @return if the provided object ID is in this inventory and is a pet */ - bool IsPet(LWOOBJID id) const; + bool IsPet(const LWOOBJID& id) const { return m_Pets.find(id) != m_Pets.end(); } /** * Removes pet database information from the item with the specified object id * @param id the object id to remove pet info for */ - void RemoveDatabasePet(LWOOBJID id); + void RemoveDatabasePet(const LWOOBJID& id) { m_Pets.erase(id); } /** * Returns the current behavior slot active for the passed item type @@ -359,14 +361,14 @@ public: * * @param equippedItem The item script to lookup and call equip on */ - void EquipScripts(Item* equippedItem); + void EquipScripts(Item* equippedItem) const; /** * Call this when you unequip an item. This calls OnFactionTriggerItemUnequipped for any scripts found on the items. * * @param unequippedItem The item script to lookup and call unequip on */ - void UnequipScripts(Item* unequippedItem); + void UnequipScripts(Item* unequippedItem) const; ~InventoryComponent() override;