From 8555f3060f117dacca035483df5d648477aa4bdc Mon Sep 17 00:00:00 2001 From: Mordred Date: Tue, 24 Jul 2018 23:58:08 +0200 Subject: [PATCH 01/12] Not compilable atm, still moving stuff around --- src/servers/sapphire_api/Forwards.h | 2 - src/servers/sapphire_zone/Actor/Player.cpp | 12 +- src/servers/sapphire_zone/Actor/Player.h | 78 +- .../sapphire_zone/Actor/PlayerInventory.cpp | 709 +++++++++++- .../sapphire_zone/Actor/PlayerQuest.cpp | 2 +- src/servers/sapphire_zone/Actor/PlayerSql.cpp | 173 ++- src/servers/sapphire_zone/Forwards.h | 2 - .../sapphire_zone/Inventory/Inventory.cpp | 1024 ----------------- .../sapphire_zone/Inventory/Inventory.h | 88 -- src/servers/sapphire_zone/Inventory/Item.cpp | 6 + src/servers/sapphire_zone/Inventory/Item.h | 3 + .../sapphire_zone/Inventory/ItemUtil.cpp | 171 +++ .../sapphire_zone/Inventory/ItemUtil.h | 30 + .../Network/Handlers/GMCommandHandlers.cpp | 6 +- .../Network/Handlers/InventoryHandler.cpp | 10 +- .../PacketWrappers/PlayerSpawnPacket.h | 3 +- 16 files changed, 1131 insertions(+), 1188 deletions(-) delete mode 100644 src/servers/sapphire_zone/Inventory/Inventory.cpp delete mode 100644 src/servers/sapphire_zone/Inventory/Inventory.h create mode 100644 src/servers/sapphire_zone/Inventory/ItemUtil.cpp create mode 100644 src/servers/sapphire_zone/Inventory/ItemUtil.h diff --git a/src/servers/sapphire_api/Forwards.h b/src/servers/sapphire_api/Forwards.h index 73b6429d..bb416e83 100644 --- a/src/servers/sapphire_api/Forwards.h +++ b/src/servers/sapphire_api/Forwards.h @@ -12,7 +12,6 @@ namespace Core class ItemContainer; class Inventory; class Session; - class XMLConfig; class ZonePosition; typedef boost::shared_ptr ZonePtr; @@ -20,7 +19,6 @@ namespace Core typedef boost::shared_ptr ItemContainerPtr; typedef boost::shared_ptr InventoryPtr; typedef boost::shared_ptr SessionPtr; - typedef boost::shared_ptr XMLConfigPtr; typedef boost::shared_ptr ZonePositionPtr; namespace StatusEffect diff --git a/src/servers/sapphire_zone/Actor/Player.cpp b/src/servers/sapphire_zone/Actor/Player.cpp index 27cf2775..6895ea5a 100644 --- a/src/servers/sapphire_zone/Actor/Player.cpp +++ b/src/servers/sapphire_zone/Actor/Player.cpp @@ -47,6 +47,10 @@ using namespace Core::Network::Packets; using namespace Core::Network::Packets::Server; using namespace Core::Network::ActorControl; +using InventoryMap = std::map< uint16_t, Core::ItemContainerPtr >; +using InvSlotPair = std::pair< uint16_t, int8_t >; +using InvSlotPairVec = std::vector< InvSlotPair >; + // player constructor Core::Entity::Player::Player() : Chara( ObjKind::Player ), @@ -1023,7 +1027,7 @@ void Core::Entity::Player::update( int64_t currTime ) { if( m_targetId && m_currentStance == Entity::Chara::Stance::Active && isAutoattackOn() ) { - auto mainWeap = m_pInventory->getItemAt( Common::GearSet0, Common::EquipSlot::MainHand ); + auto mainWeap = getItemAt( Common::GearSet0, Common::EquipSlot::MainHand ); // @TODO i dislike this, iterating over all in range actors when you already know the id of the actor you need... for( auto actor : m_inRangeActor ) @@ -1406,8 +1410,7 @@ uint32_t Core::Entity::Player::getPersistentEmote() const void Core::Entity::Player::autoAttack( CharaPtr pTarget ) { - auto mainWeap = m_pInventory->getItemAt( Common::GearSet0, - Common::EquipSlot::MainHand ); + auto mainWeap = getItemAt( Common::GearSet0, Common::EquipSlot::MainHand ); pTarget->onActionHostile( *this ); //uint64_t tick = Util::getTimeMs(); @@ -1572,7 +1575,7 @@ void Core::Entity::Player::sendZonePackets() classInfoPacket->data().level1 = getLevel(); queuePacket( classInfoPacket ); - m_itemLevel = getInventory()->calculateEquippedGearItemLevel(); + m_itemLevel = calculateEquippedGearItemLevel(); sendItemLevel(); } @@ -1748,4 +1751,3 @@ bool Core::Entity::Player::isOnEnterEventDone() const return m_onEnterEventDone; } - diff --git a/src/servers/sapphire_zone/Actor/Player.h b/src/servers/sapphire_zone/Actor/Player.h index 33dc78f5..3feb94d5 100644 --- a/src/servers/sapphire_zone/Actor/Player.h +++ b/src/servers/sapphire_zone/Actor/Player.h @@ -7,7 +7,6 @@ #include #include "Chara.h" -#include "Inventory/Inventory.h" #include "Event/EventHandler.h" #include #include @@ -23,11 +22,13 @@ struct QueuedZoning float m_targetRotation; uint64_t m_queueTime; - QueuedZoning( uint16_t targetZone, const Common::FFXIVARR_POSITION3& targetPosition, uint64_t queuedTime, float targetRotation ) - : m_targetZone( targetZone ) - , m_targetPosition( targetPosition ) - , m_queueTime( queuedTime ) - , m_targetRotation( targetRotation ) {} + QueuedZoning( uint16_t targetZone, const Common::FFXIVARR_POSITION3& targetPosition, + uint64_t queuedTime, float targetRotation ) : + m_targetZone( targetZone ), + m_targetPosition( targetPosition ), + m_queueTime( queuedTime ), + m_targetRotation( targetRotation ) + {} }; /** Class representing the Player @@ -221,7 +222,7 @@ public: /*! add an item to the first free slot in one of the 4 main containers */ bool tryAddItem( uint16_t catalogId, uint32_t quantity ); /*! add an item to a given container */ - bool addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity ); +// bool addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity ); /*! equip an item to a specified slot */ void equipItem( Common::EquipSlot equipSlotId, ItemPtr pItem, bool sendModel ); /*! remove an item from an equipment slot */ @@ -232,8 +233,6 @@ public: uint16_t getItemLevel() const; /*! send player ilvl */ void sendItemLevel(); - /*! get a const pointer to the inventory object */ - InventoryPtr getInventory() const; /*! get the current main hand model */ uint64_t getModelMainWeapon() const; /*! get the current off hand model */ @@ -246,10 +245,8 @@ public: uint32_t getModelForSlot( Common::EquipSlot slot ); /*! set the equipment model in a specified equipment slot */ void setModelForSlot( Common::EquipSlot slot, uint32_t val ); - /*! return the current amount of currency of type */ - uint32_t getCurrency( uint8_t type ) const; /*! add amount to the currency of type */ - void addCurrency( uint8_t type, uint32_t amount ); + void addCurrency( Common::CurrencyType type, uint32_t amount ); /*! remove amount from the currency of type */ void removeCurrency( uint8_t type, uint32_t amount ); /*! return the current amount of crystals of type */ @@ -493,7 +490,7 @@ public: /*! send status update */ void sendStatusUpdate( bool toSelf = true ) override; /*! send the entire inventory sequence */ - void sendInventory() const; + void sendInventory(); /*! send active quest list */ void sendQuestInfo(); /*! send a quest specific message */ @@ -604,6 +601,56 @@ public: /*! checks if a spawn index is valid */ bool isObjSpawnIndexValid( uint8_t index ); + + // Inventory Handling + ////////////////////////////////////////////////////////////////////////////////////////////////////// + void initInventory(); + + using InvSlotPair = std::pair< uint16_t, int8_t >; + using InvSlotPairVec = std::vector< InvSlotPair >; + + ItemPtr createItem( uint32_t catalogId, uint16_t quantity = 1 ); + bool loadInventory(); + InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId ); + InvSlotPair getFreeBagSlot(); + int16_t addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity = 1, bool isHq = false, bool silent = false ); + void moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ); + void swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ); + void discardItem( uint16_t fromInventoryId, uint8_t fromSlotId ); + void splitItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot, uint16_t splitCount ); + void mergeItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ); + + ItemPtr getItemAt( uint16_t containerId, uint8_t slotId ); + + bool updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem ); + + /*! calculate and return player ilvl based off equipped gear */ + uint16_t calculateEquippedGearItemLevel(); + /*! return the current amount of currency of type */ + uint32_t getCurrency( Common::CurrencyType type ); + + void updateCurrencyDb(); + void updateBagDb( Common::InventoryType type ); + void updateMannequinDb( Common::InventoryType type ); + void updateItemDb( ItemPtr pItem ) const; + void deleteItemDb( ItemPtr pItem ) const; + + /*! return the crystal amount of currency of type */ + uint32_t getCrystal( Common::CrystalType type ); + /*! add amount to the crystal of type */ + bool addCrystal( Common::CrystalType type, uint32_t amount ); + /*! remove amount from the crystals of type */ + bool removeCrystal( Common::CrystalType type, uint32_t amount ); + bool isObtainable( uint32_t catalogId, uint8_t quantity ); + + void updateCrystalDb(); + + void send(); + + uint8_t getFreeSlotsInBags(); + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + uint64_t m_lastMoveTime; uint8_t m_lastMoveflag; @@ -625,8 +672,9 @@ private: bool m_onEnterEventDone; private: + using InventoryMap = std::map< uint16_t, Core::ItemContainerPtr >; - + InventoryMap m_inventoryMap; Common::FFXIVARR_POSITION3 m_prevPos; uint32_t m_prevZoneType; @@ -678,8 +726,6 @@ private: uint8_t m_openingSequence; uint16_t m_itemLevel; - InventoryPtr m_pInventory; - std::map< uint32_t, Event::EventHandlerPtr > m_eventHandlerMap; std::queue< uint8_t > m_freeHateSlotQueue; // queue with "hate slots" free to be assigned diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index 4e4a6eaa..fce1dbcd 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -7,22 +7,104 @@ #include "Network/PacketWrappers/ActorControlPacket142.h" #include "Network/PacketWrappers/ActorControlPacket143.h" -#include "Inventory/Inventory.h" #include "Inventory/Item.h" +#include "Inventory/ItemContainer.h" +#include "Inventory/ItemUtil.h" #include "Player.h" #include "Framework.h" -extern Core::Framework g_framework; +#include +#include + +#include + +#include +#include +#include + +#include "Actor/Player.h" + +#include "Network/PacketWrappers/ServerNoticePacket.h" +#include "Network/PacketWrappers/ActorControlPacket143.h" + + +#include "Framework.h" +#include + +extern Core::Framework g_fw; using namespace Core::Common; using namespace Core::Network::Packets; using namespace Core::Network::Packets::Server; using namespace Core::Network::ActorControl; -Core::InventoryPtr Core::Entity::Player::getInventory() const + + + +void Core::Entity::Player::initInventory() { - return m_pInventory; + auto setupContainer = [this]( InventoryType type ) + { m_inventoryMap[type] = make_ItemContainer( type ); }; + + // main bags + setupContainer( Bag0 ); + setupContainer( Bag1 ); + setupContainer( Bag2 ); + setupContainer( Bag3 ); + + // gear set + setupContainer( GearSet0 ); + + // gil contianer + setupContainer( Currency ); + + // crystals?? + setupContainer( Crystal ); + //m_inventoryMap[0x07D3] = ItemContainerPtr( new ItemContainer( UNKNOWN_0 ) ); + //m_inventoryMap[0x07D8] = ItemContainerPtr( new ItemContainer( UNKNOWN_1 ) ); + + // armory weapons - 0 + setupContainer( ArmoryMain ); + + // armory offhand - 1 + setupContainer( ArmoryOff ); + + //armory head - 2 + setupContainer( ArmoryHead ); + + //armory body - 3 + setupContainer( ArmoryBody ); + + //armory hand - 4 + setupContainer( ArmoryHand ); + + //armory waist - 5 + setupContainer( ArmoryWaist ); + + //armory legs - 6 + setupContainer( ArmoryLegs ); + + //armory feet - 7 + setupContainer( ArmoryFeet ); + + //neck + setupContainer( ArmotyNeck ); + + //earring + setupContainer( ArmoryEar ); + + //wrist + setupContainer( ArmoryWrist ); + + //armory rings - 11 + setupContainer( ArmoryRing ); + + //soul crystals - 13 + setupContainer( ArmorySoulCrystal ); + + loadInventory(); + } void Core::Entity::Player::sendItemLevel() @@ -121,7 +203,7 @@ void Core::Entity::Player::equipItem( Common::EquipSlot equipSlotId, ItemPtr pIt if( sendUpdate ) { this->sendModel(); - m_itemLevel = getInventory()->calculateEquippedGearItemLevel(); + m_itemLevel = calculateEquippedGearItemLevel(); sendItemLevel(); } } @@ -131,59 +213,83 @@ void Core::Entity::Player::unequipItem( Common::EquipSlot equipSlotId, ItemPtr p m_modelEquip[static_cast< uint8_t >( equipSlotId )] = 0; sendModel(); - m_itemLevel = getInventory()->calculateEquippedGearItemLevel(); + m_itemLevel = calculateEquippedGearItemLevel(); sendItemLevel(); } -uint32_t Core::Entity::Player::getCurrency( uint8_t type ) const -{ - return m_pInventory->getCurrency( static_cast< Common::CurrencyType >( type ) ); -} - // TODO: these next functions are so similar that they could likely be simplified -void Core::Entity::Player::addCurrency( uint8_t type, uint32_t amount ) +void Core::Entity::Player::addCurrency( CurrencyType type, uint32_t amount ) { - if( !m_pInventory->addCurrency( static_cast< Common::CurrencyType >( type ), amount ) ) - return; + auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); + + if( !currItem ) + { + // TODO: map currency type to itemid + currItem = createItem( 1 ); + m_inventoryMap[Currency]->setItem( static_cast< uint8_t >( type ) - 1, currItem ); + updateCurrencyDb(); + } + + uint32_t currentAmount = currItem->getStackSize(); + currItem->setStackSize( currentAmount + amount ); + updateItemDb( currItem ); auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); invUpPacket->data().containerId = Common::InventoryType::Currency; invUpPacket->data().catalogId = 1; - invUpPacket->data().quantity = m_pInventory->getCurrency( static_cast< Common::CurrencyType >( type ) ); + invUpPacket->data().quantity = getCurrency( type ); invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; queuePacket( invUpPacket ); } -void Core::Entity::Player::removeCurrency( uint8_t type, uint32_t amount ) +void Core::Entity::Player::removeCurrency( Common::CurrencyType type, uint32_t amount ) { - if( !m_pInventory->removeCurrency( static_cast< Common::CurrencyType >( type ), amount ) ) - return; + auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); + + if( !currItem ) + return false; + + uint32_t currentAmount = currItem->getStackSize(); + if( amount > currentAmount ) + currItem->setStackSize( 0 ); + else + currItem->setStackSize( currentAmount - amount ); + + updateItemDb( currItem ); auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); invUpPacket->data().containerId = Common::InventoryType::Currency; invUpPacket->data().catalogId = 1; - invUpPacket->data().quantity = m_pInventory->getCurrency( static_cast< Common::CurrencyType >( type ) ); + invUpPacket->data().quantity = getCurrency( type ); invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; queuePacket( invUpPacket ); } -uint32_t Core::Entity::Player::getCrystal( uint8_t type ) const +void Core::Entity::Player::addCrystal( Common::CrystalType type, uint32_t amount ) { - return m_pInventory->getCrystal( static_cast< Common::CrystalType >( type ) ); -} + auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); -void Core::Entity::Player::addCrystal( uint8_t type, uint32_t amount ) -{ - if( !m_pInventory->addCrystal( static_cast< Common::CrystalType >( type ), amount ) ) - return; + if( !currItem ) + { + // TODO: map currency type to itemid + currItem = createItem( static_cast< uint8_t >( type ) + 1 ); + m_inventoryMap[Crystal]->setItem( static_cast< uint8_t >( type ) - 1, currItem ); + updateCrystalDb(); + } + + uint32_t currentAmount = currItem->getStackSize(); + + currItem->setStackSize( currentAmount + amount ); + + updateItemDb( currItem ); auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); invUpPacket->data().containerId = Common::InventoryType::Crystal; invUpPacket->data().catalogId = static_cast< uint8_t >( type ) + 1; - invUpPacket->data().quantity = m_pInventory->getCrystal( static_cast< Common::CrystalType >( type ) ); + invUpPacket->data().quantity = getCrystal( type ); invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; queuePacket( invUpPacket ); @@ -192,15 +298,25 @@ void Core::Entity::Player::addCrystal( uint8_t type, uint32_t amount ) static_cast< uint8_t >( type ) + 1, amount ) ); } -void Core::Entity::Player::removeCrystal( uint8_t type, uint32_t amount ) +void Core::Entity::Player::removeCrystal( Common::CrystalType type, uint32_t amount ) { - if( !m_pInventory->removeCrystal( static_cast< Common::CrystalType >( type ), amount ) ) + auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); + + if( !currItem ) return; + uint32_t currentAmount = currItem->getStackSize(); + if( amount > currentAmount ) + currItem->setStackSize( 0 ); + else + currItem->setStackSize( currentAmount - amount ); + + updateItemDb( currItem ); + auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); invUpPacket->data().containerId = Common::InventoryType::Crystal; invUpPacket->data().catalogId = static_cast< uint8_t >( type ) + 1; - invUpPacket->data().quantity = m_pInventory->getCrystal( static_cast< Common::CrystalType >( type ) ); + invUpPacket->data().quantity = getCrystal( static_cast< Common::CrystalType >( type ) ); invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; queuePacket( invUpPacket ); @@ -211,22 +327,543 @@ bool Core::Entity::Player::tryAddItem( uint16_t catalogId, uint32_t quantity ) for( uint16_t i = 0; i < 4; i++ ) { - if( m_pInventory->addItem( i, -1, catalogId, quantity ) != -1 ) + if( addItem( i, -1, catalogId, quantity ) != -1 ) return true; } return false; } -bool Core::Entity::Player::addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity ) +/*bool Core::Entity::Player::addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity ) { - if( m_pInventory->addItem( containerId, -1, catalogId, quantity ) != -1 ) + if( addItem( containerId, -1, catalogId, quantity ) != -1 ) return true; return false; -} +}*/ -void Core::Entity::Player::sendInventory() const +void Core::Entity::Player::sendInventory() { - m_pInventory->send(); + InventoryMap::iterator it; + + int32_t count = 0; + for( it = m_inventoryMap.begin(); it != m_inventoryMap.end(); ++it, count++ ) + { + + auto pMap = it->second->getItemMap(); + auto itM = pMap.begin(); + + for( ; itM != pMap.end(); ++itM ) + { + if( !itM->second ) + return; + + if( it->second->getId() == InventoryType::Currency || it->second->getId() == InventoryType::Crystal ) + { + auto currencyInfoPacket = makeZonePacket< FFXIVIpcCurrencyCrystalInfo >( getId() ); + currencyInfoPacket->data().sequence = count; + currencyInfoPacket->data().catalogId = itM->second->getId(); + currencyInfoPacket->data().unknown = 1; + currencyInfoPacket->data().quantity = itM->second->getStackSize(); + currencyInfoPacket->data().containerId = it->second->getId(); + currencyInfoPacket->data().slot = 0; + queuePacket( currencyInfoPacket ); + } + else + { + auto itemInfoPacket = makeZonePacket< FFXIVIpcItemInfo >( getId() ); + itemInfoPacket->data().sequence = count; + itemInfoPacket->data().containerId = it->second->getId(); + itemInfoPacket->data().slot = itM->first; + itemInfoPacket->data().quantity = itM->second->getStackSize(); + itemInfoPacket->data().catalogId = itM->second->getId(); + itemInfoPacket->data().condition = 30000; + itemInfoPacket->data().spiritBond = 0; + itemInfoPacket->data().hqFlag = itM->second->isHq() ? 1 : 0; + queuePacket( itemInfoPacket ); + } + } + + auto containerInfoPacket = makeZonePacket< FFXIVIpcContainerInfo >( getId() ); + containerInfoPacket->data().sequence = count; + containerInfoPacket->data().numItems = it->second->getEntryCount(); + containerInfoPacket->data().containerId = it->second->getId(); + queuePacket( containerInfoPacket ); + + + } + } +Core::Entity::Player::InvSlotPairVec Core::Entity::Player::getSlotsOfItemsInInventory( uint32_t catalogId ) +{ + InvSlotPairVec outVec; + for( auto i : { Bag0, Bag1, Bag2, Bag3 } ) + { + auto inv = m_inventoryMap[i]; + for( auto item : inv->getItemMap() ) + { + if( item.second && item.second->getId() == catalogId ) + outVec.push_back( std::make_pair( i, static_cast< int8_t >( item.first ) ) ); + } + } + return outVec; +} + +Core::Entity::Player::InvSlotPair Core::Entity::Player::getFreeBagSlot() +{ + for( auto i : { Bag0, Bag1, Bag2, Bag3 } ) + { + auto freeSlot = static_cast< int8_t >( m_inventoryMap[i]->getFreeSlot() ); + + if( freeSlot != -1 ) + return std::make_pair( i, freeSlot ); + } + // no room in inventory + return std::make_pair( 0, -1 ); +} + +Core::ItemPtr Core::Entity::Player::getItemAt( uint16_t containerId, uint8_t slotId ) +{ + return m_inventoryMap[containerId]->getItem( slotId ); +} + + +uint32_t Core::Entity::Player::getCurrency( CurrencyType type ) +{ + + auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); + + if( !currItem ) + return 0; + + return currItem->getStackSize(); + +} + +uint32_t Core::Entity::Player::getCrystal( CrystalType type ) +{ + + auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); + + if( !currItem ) + return 0; + + return currItem->getStackSize(); + +} + +void Core::Entity::Player::updateCurrencyDb() +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + int32_t firstItemPos = -1; + std::string query = "UPDATE charaitemcurrency SET "; + + for( int32_t i = 0; i <= 11; i++ ) + { + auto currItem = m_inventoryMap[Currency]->getItem( i ); + + if( currItem ) + { + if( firstItemPos == -1 ) + firstItemPos = i; + + if( i > firstItemPos ) + query += ", "; + + query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem->getUId() ); + } + } + + query += " WHERE CharacterId = " + std::to_string( getId() ); + + pDb->execute( query ); +} + + +void Core::Entity::Player::updateCrystalDb() +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + int32_t firstItemPos = -1; + std::string query = "UPDATE charaitemcrystal SET "; + + for( int32_t i = 0; i <= 11; i++ ) + { + auto currItem = m_inventoryMap[Crystal]->getItem( i ); + + if( currItem ) + { + if( firstItemPos == -1 ) + firstItemPos = i; + + if( i > firstItemPos ) + query += ", "; + + query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem->getUId() ); + } + } + + query += " WHERE CharacterId = " + std::to_string( getId() ); + + pDb->execute( query ); +} + +void Core::Entity::Player::updateBagDb( InventoryType type ) +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + std::string query = "UPDATE charaiteminventory SET "; + + for( int32_t i = 0; i <= 34; i++ ) + { + auto currItem = m_inventoryMap[type]->getItem( i ); + + if( i > 0 ) + query += ", "; + + query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem ? currItem->getUId() : 0 ); + } + + query += " WHERE CharacterId = " + std::to_string( getId() ) + + " AND storageId = " + std::to_string( static_cast< uint16_t >( type ) ); + + pDb->execute( query ); +} + + +void Core::Entity::Player::updateMannequinDb( InventoryType type ) +{ + auto pLog = g_fw.get< Logger >(); + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + std::string query = "UPDATE charaitemgearset SET "; + + for( int32_t i = 0; i <= 13; i++ ) + { + auto currItem = m_inventoryMap[type]->getItem( i ); + + if( i > 0 ) + query += ", "; + + query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem ? currItem->getUId() : 0 ); + } + + query += " WHERE CharacterId = " + std::to_string( getId() ) + + " AND storageId = " + std::to_string( static_cast< uint16_t >( type ) ); + + pLog->debug( query ); + pDb->execute( query ); +} + + +void Core::Entity::Player::updateItemDb( Core::ItemPtr pItem ) const +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + pDb->execute( "UPDATE charaglobalitem SET stack = " + std::to_string( pItem->getStackSize() ) + " " + + // TODO: add other attributes + " WHERE itemId = " + std::to_string( pItem->getUId() ) ); +} + +void Core::Entity::Player::deleteItemDb( Core::ItemPtr item ) const +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + pDb->execute( "UPDATE charaglobalitem SET IS_DELETE = 1 WHERE itemId = " + std::to_string( item->getUId() ) ); +} + + +bool Core::Entity::Player::isObtainable( uint32_t catalogId, uint8_t quantity ) +{ + + return true; +} + + +int16_t Core::Entity::Player::addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity, bool isHq, bool silent ) +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + auto pExdData = g_fw.get< Data::ExdDataGenerated >(); + auto itemInfo = pExdData->get< Core::Data::Item >( catalogId ); + + // if item data doesn't exist or it's a blank field + if( !itemInfo || itemInfo->levelItem == 0 ) + { + return -1; + } + + int8_t rSlotId = -1; + + //if( itemInfo->stack_size > 1 ) + //{ + // auto itemList = this->getSlotsOfItemsInInventory( catalogId ); + // // TODO: this is a stacked item so we need to see if the item is already in inventory and + // // check how much free space we have on existing stacks before looking for empty slots. + //} + //else + { + auto freeSlot = getFreeBagSlot(); + inventoryId = freeSlot.first; + rSlotId = freeSlot.second; + + if( rSlotId == -1 ) + return -1; + } + + auto item = createItem( catalogId, quantity ); + + item->setHq( isHq ); + + if( rSlotId != -1 ) + { + + m_inventoryMap[inventoryId]->setItem( rSlotId, item ); + + pDb->execute( "UPDATE charaiteminventory SET container_" + std::to_string( rSlotId ) + " = " + std::to_string( item->getUId() ) + + " WHERE storageId = " + std::to_string( inventoryId ) + + " AND CharacterId = " + std::to_string( getId() ) ); + + + auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); + invUpPacket->data().containerId = inventoryId; + invUpPacket->data().catalogId = catalogId; + invUpPacket->data().quantity = item->getStackSize(); + invUpPacket->data().hqFlag = item->isHq() ? 1 : 0; + invUpPacket->data().slot = rSlotId; + invUpPacket->data().condition = 30000; + queuePacket( invUpPacket ); + + if( !silent ) + queuePacket( boost::make_shared< ActorControlPacket143 >( getId(), ItemObtainIcon, + catalogId, item->getStackSize() ) ); + + } + + return rSlotId; + +} + +void Core::Entity::Player::moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ) +{ + + auto tmpItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); + auto& itemMap = m_inventoryMap[fromInventoryId]->getItemMap(); + + if( tmpItem == nullptr ) + return; + + itemMap[fromSlotId].reset(); + + m_inventoryMap[toInventoryId]->setItem( toSlot, tmpItem ); + + if( toInventoryId != GearSet0 ) + updateBagDb( static_cast< InventoryType >( toInventoryId ) ); + + if( fromInventoryId != GearSet0 && fromInventoryId != toInventoryId ) + updateBagDb( static_cast< InventoryType >( fromInventoryId ) ); + + if( static_cast< InventoryType >( toInventoryId ) == GearSet0 ) + { + equipItem( static_cast< EquipSlot >( toSlot ), tmpItem, true ); + updateMannequinDb( static_cast< InventoryType >( toInventoryId ) ); + } + + if( static_cast< InventoryType >( fromInventoryId ) == GearSet0 ) + { + unequipItem( static_cast< EquipSlot >( fromSlotId ), tmpItem ); + updateMannequinDb( static_cast< InventoryType >( fromInventoryId ) ); + } + + +} + +bool Core::Entity::Player::updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem ) +{ + auto containerType = Items::Util::getContainerType( containerId ); + + m_inventoryMap[containerId]->setItem( slotId, pItem ); + + switch( containerType ) + { + case Armory: + case CurrencyCrystal: + case Bag: + { + updateBagDb( static_cast< InventoryType >( containerId ) ); + break; + } + + case GearSet: + { + if( pItem ) + equipItem( static_cast< EquipSlot >( slotId ), pItem, true ); + else + unequipItem( static_cast< EquipSlot >( slotId ), pItem ); + + updateMannequinDb( static_cast< InventoryType >( containerId ) ); + break; + } + default: + break; + } + + return true; +} + +void Core::Entity::Player::splitItem( uint16_t fromInventoryId, uint8_t fromSlotId, + uint16_t toInventoryId, uint8_t toSlot, uint16_t itemCount ) +{ + auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); + if( !fromItem ) + return; + + // check we have enough items in the origin slot + // nb: don't let the client 'split' a whole stack into another slot + if( fromItem->getStackSize() < itemCount ) + // todo: correct the invalid item split? does retail do this or does it just ignore it? + return; + + // make sure toInventoryId & toSlot are actually free so we don't orphan an item + if( m_inventoryMap[toInventoryId]->getItem( toSlot ) ) + // todo: correct invalid move? again, not sure what retail does here + return; + + auto newSlot = addItem( toInventoryId, toSlot, fromItem->getId(), itemCount, fromItem->isHq(), true ); + if( newSlot == -1 ) + return; + + auto newItem = m_inventoryMap[toInventoryId]->getItem( static_cast< uint8_t >( newSlot ) ); + + fromItem->setStackSize( fromItem->getStackSize() - itemCount ); + + updateContainer( fromInventoryId, fromSlotId, fromItem ); + updateContainer( toInventoryId, toSlot, newItem ); + + updateItemDb( fromItem ); +} + +void Core::Entity::Player::mergeItem( uint16_t fromInventoryId, uint8_t fromSlotId, + uint16_t toInventoryId, uint8_t toSlot ) +{ + auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); + auto toItem = m_inventoryMap[toInventoryId]->getItem( toSlot ); + + if( !fromItem || !toItem ) + return; + + if( fromItem->getId() != toItem->getId() ) + return; + + uint32_t stackSize = fromItem->getStackSize() + toItem->getStackSize(); + uint32_t stackOverflow = stackSize - std::min< uint32_t >( fromItem->getMaxStackSize(), stackSize ); + + // we can destroy the original stack if there's no overflow + if( stackOverflow == 0 ) + { + m_inventoryMap[fromInventoryId]->removeItem( fromSlotId ); + deleteItemDb( fromItem ); + } + else + { + fromItem->setStackSize( stackOverflow ); + updateItemDb( fromItem ); + } + + + toItem->setStackSize( stackSize ); + updateItemDb( toItem ); + + updateContainer( fromInventoryId, fromSlotId, fromItem ); + updateContainer( toInventoryId, toSlot, toItem ); +} + +void Core::Entity::Player::swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, + uint16_t toInventoryId, uint8_t toSlot ) +{ + auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); + auto toItem = m_inventoryMap[toInventoryId]->getItem( toSlot ); + auto& itemMap = m_inventoryMap[fromInventoryId]->getItemMap(); + + if( fromItem == nullptr || toItem == nullptr ) + return; + + // An item is being moved from bag0-3 to equippment, meaning + // the swapped out item will be placed in the matching armory. + if( Items::Util::isEquipment( toInventoryId ) + && !Items::Util::isEquipment( fromInventoryId ) + && !Items::Util::isArmory( fromInventoryId ) ) + { + updateContainer( fromInventoryId, fromSlotId, nullptr ); + fromInventoryId = Items::Util::getArmoryToEquipSlot( toSlot ); + fromSlotId = static_cast < uint8_t >( m_inventoryMap[fromInventoryId]->getFreeSlot() ); + } + + auto containerTypeFrom = Items::Util::getContainerType( fromInventoryId ); + auto containerTypeTo = Items::Util::getContainerType( toInventoryId ); + + updateContainer( toInventoryId, toSlot, fromItem ); + updateContainer( fromInventoryId, fromSlotId, toItem ); +} + +void Core::Entity::Player::discardItem( uint16_t fromInventoryId, uint8_t fromSlotId ) +{ + // i am not entirely sure how this should be generated or if it even is important for us... + uint32_t transactionId = 1; + + auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); + + deleteItemDb( fromItem ); + + m_inventoryMap[fromInventoryId]->removeItem( fromSlotId ); + updateContainer( fromInventoryId, fromSlotId, nullptr ); + + auto invTransPacket = makeZonePacket< FFXIVIpcInventoryTransaction >( getId() ); + invTransPacket->data().transactionId = transactionId; + invTransPacket->data().ownerId = getId(); + invTransPacket->data().storageId = fromInventoryId; + invTransPacket->data().catalogId = fromItem->getId(); + invTransPacket->data().stackSize = fromItem->getStackSize(); + invTransPacket->data().slotId = fromSlotId; + invTransPacket->data().type = 7; + queuePacket( invTransPacket ); + + auto invTransFinPacket = makeZonePacket< FFXIVIpcInventoryTransactionFinish >( getId() ); + invTransFinPacket->data().transactionId = transactionId; + invTransFinPacket->data().transactionId1 = transactionId; + queuePacket( invTransFinPacket ); +} + +uint16_t Core::Entity::Player::calculateEquippedGearItemLevel() +{ + uint32_t iLvlResult = 0; + + auto gearSetMap = m_inventoryMap[GearSet0]->getItemMap(); + + auto it = gearSetMap.begin(); + + while( it != gearSetMap.end() ) + { + auto currItem = it->second; + + if( currItem ) + { + iLvlResult += currItem->getItemLevel(); + + // If item is weapon and isn't one-handed + if( currItem->isWeapon() && !Items::Util::isOneHandedWeapon( currItem->getCategory() ) ) + { + iLvlResult += currItem->getItemLevel(); + } + } + + it++; + } + + return boost::algorithm::clamp( iLvlResult / 13, 0, 9999 ); +} + + +uint8_t Core::Entity::Player::getFreeSlotsInBags() +{ + uint8_t slots = 0; + for( uint8_t container : { 0, 1, 2, 3 } ) + { + slots += 34 - m_inventoryMap[container]->getEntryCount(); + } + return slots; +} diff --git a/src/servers/sapphire_zone/Actor/PlayerQuest.cpp b/src/servers/sapphire_zone/Actor/PlayerQuest.cpp index 7c8a10f9..7cdfaed4 100644 --- a/src/servers/sapphire_zone/Actor/PlayerQuest.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerQuest.cpp @@ -1070,7 +1070,7 @@ bool Core::Entity::Player::giveQuestRewards( uint32_t questId, uint32_t optional } if( gilReward > 0 ) - addCurrency( 1, gilReward ); + addCurrency( CurrencyType::Gil, gilReward ); return true; } diff --git a/src/servers/sapphire_zone/Actor/PlayerSql.cpp b/src/servers/sapphire_zone/Actor/PlayerSql.cpp index 94224bf2..bed620ca 100644 --- a/src/servers/sapphire_zone/Actor/PlayerSql.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerSql.cpp @@ -14,6 +14,9 @@ #include "Zone/TerritoryMgr.h" #include "Zone/Zone.h" +#include "Inventory/Item.h" +#include "Inventory/ItemContainer.h" +#include "Inventory/ItemUtil.h" #include "ServerZone.h" #include "Framework.h" @@ -200,9 +203,6 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession ) m_modelSubWeapon = 0; m_lastTickTime = 0; - // TODO: remove Inventory and actually inline it in Player class - m_pInventory = make_Inventory( this ); - calculateStats(); // first login, run the script event @@ -228,7 +228,9 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession ) setStateFlag( PlayerStateFlag::BetweenAreas ); - m_pInventory->load(); + //m_pInventory->load(); + + initInventory(); initHateSlotQueue(); @@ -554,3 +556,166 @@ void Core::Entity::Player::insertQuest( uint16_t questId, uint8_t index, uint8_t stmt->setInt( 12, 0 ); pDb->execute( stmt ); } + +Core::ItemPtr Core::Entity::Player::createItem( uint32_t catalogId, uint16_t quantity ) +{ + auto pExdData = g_fw.get< Data::ExdDataGenerated >(); + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + auto itemInfo = pExdData->get< Core::Data::Item >( catalogId ); + + if( !itemInfo ) + return nullptr; + + uint16_t itemAmount = quantity; + + if( itemInfo->stackSize == 1 ) + itemAmount = 1; + + if( !itemInfo ) + return nullptr; + + uint8_t flags = 0; + + ItemPtr pItem = make_Item( Items::Util::getNextUId(), + catalogId, + itemInfo->modelMain, + itemInfo->modelSub ); + + pItem->setStackSize( itemAmount ); + + pDb->execute( "INSERT INTO charaglobalitem ( CharacterId, itemId, catalogId, stack, flags ) VALUES ( " + + std::to_string( getId() ) + ", " + + std::to_string( pItem->getUId() ) + ", " + + std::to_string( pItem->getId() ) + ", " + + std::to_string( itemAmount ) + ", " + + std::to_string( flags ) + ");" ); + + return pItem; +} + +bool Core::Entity::Player::loadInventory() +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // load active gearset + auto res = pDb->query( "SELECT storageId, container_0, container_1, container_2, container_3, " + "container_4, container_5, container_6, container_7, " + "container_8, container_9, container_10, container_11, " + "container_12, container_13 " + "FROM charaitemgearset " \ + "WHERE CharacterId = " + std::to_string( getId() ) + " " \ + "ORDER BY storageId ASC;" ); + + while( res->next() ) + { + uint16_t storageId = res->getUInt16( 1 ); + + for( uint32_t i = 1; i <= 14; i++ ) + { + uint64_t uItemId = res->getUInt64( i + 1 ); + if( uItemId == 0 ) + continue; + + ItemPtr pItem = Items::Util::loadItem( uItemId ); + + if( pItem == nullptr ) + continue; + + m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; + equipItem( static_cast< EquipSlot >( i - 1 ), pItem, false ); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // Load Bags + auto bagRes = pDb->query( "SELECT storageId, " + "container_0, container_1, container_2, container_3, container_4, " + "container_5, container_6, container_7, container_8, container_9, " + "container_10, container_11, container_12, container_13, container_14, " + "container_15, container_16, container_17, container_18, container_19, " + "container_20, container_21, container_22, container_23, container_24, " + "container_25, container_26, container_27, container_28, container_29, " + "container_30, container_31, container_32, container_33, container_34 " + "FROM charaiteminventory " \ + "WHERE CharacterId = " + std::to_string( getId() ) + " " \ + "ORDER BY storageId ASC;" ); + + while( bagRes->next() ) + { + uint16_t storageId = bagRes->getUInt16( 1 ); + for( uint32_t i = 1; i <= 35; i++ ) + { + uint64_t uItemId = bagRes->getUInt64( i + 1 ); + if( uItemId == 0 ) + continue; + + ItemPtr pItem = Items::Util::loadItem( uItemId ); + + if( pItem == nullptr ) + continue; + + m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // Load Currency + auto curRes = pDb->query( "SELECT storageId, " + "container_0, container_1, container_2, container_3, container_4, " + "container_5, container_6, container_7, container_8, container_9, " + "container_10, container_11 " + "FROM charaitemcurrency " \ + "WHERE CharacterId = " + std::to_string( getId() ) + " " \ + "ORDER BY storageId ASC;" ); + + while( curRes->next() ) + { + uint16_t storageId = curRes->getUInt16( 1 ); + for( uint32_t i = 1; i <= 12; i++ ) + { + uint64_t uItemId = curRes->getUInt64( i + 1 ); + if( uItemId == 0 ) + continue; + + ItemPtr pItem = Items::Util::loadItem( uItemId ); + + if( pItem == nullptr ) + continue; + + m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // Load Crystals + auto crystalRes = pDb->query( "SELECT storageId, " + "container_0, container_1, container_2, container_3, container_4, " + "container_5, container_6, container_7, container_8, container_9, " + "container_10, container_11, container_12, container_13, container_14, " + "container_15, container_16, container_17 " + "FROM charaitemcrystal " \ + "WHERE CharacterId = " + std::to_string( getId() ) + " " \ + "ORDER BY storageId ASC;" ); + + while( crystalRes->next() ) + { + uint16_t storageId = crystalRes->getUInt16( 1 ); + for( int32_t i = 1; i <= 17; i++ ) + { + uint64_t uItemId = crystalRes->getUInt64( i + 1 ); + if( uItemId == 0 ) + continue; + + ItemPtr pItem = Items::Util::loadItem( uItemId ); + + if( pItem == nullptr ) + continue; + + m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; + } + } + + return true; +} diff --git a/src/servers/sapphire_zone/Forwards.h b/src/servers/sapphire_zone/Forwards.h index b81d6dee..f685b569 100644 --- a/src/servers/sapphire_zone/Forwards.h +++ b/src/servers/sapphire_zone/Forwards.h @@ -24,9 +24,7 @@ namespace Core TYPE_FORWARD( InstanceContent ); TYPE_FORWARD( Item ); TYPE_FORWARD( ItemContainer ); - TYPE_FORWARD( Inventory ); TYPE_FORWARD( Session ); - TYPE_FORWARD( XMLConfig ); TYPE_FORWARD( ZonePosition ) namespace StatusEffect diff --git a/src/servers/sapphire_zone/Inventory/Inventory.cpp b/src/servers/sapphire_zone/Inventory/Inventory.cpp deleted file mode 100644 index 61a8a82e..00000000 --- a/src/servers/sapphire_zone/Inventory/Inventory.cpp +++ /dev/null @@ -1,1024 +0,0 @@ -#include -#include - -#include - -#include -#include -#include - -#include "Actor/Player.h" - -#include "Network/PacketWrappers/ServerNoticePacket.h" -#include "Network/PacketWrappers/ActorControlPacket143.h" - -#include "ItemContainer.h" -#include "Item.h" -#include "Framework.h" -#include - -extern Core::Framework g_fw; - -using namespace Core::Common; -using namespace Core::Network; -using namespace Core::Network::Packets; -using namespace Core::Network::Packets::Server; -using namespace Core::Network::ActorControl; - -Core::Inventory::Inventory( Core::Entity::Player* pOwner ) -{ - - m_pOwner = pOwner; - - // shortcut for setting up inventory - // TODO: use a loop to set theese up? - auto setupContainer = []( InventoryMap& map, InventoryType type ) - { map[type] = make_ItemContainer( type ); }; - - // main bags - setupContainer( m_inventoryMap, Bag0 ); - setupContainer( m_inventoryMap, Bag1 ); - setupContainer( m_inventoryMap, Bag2 ); - setupContainer( m_inventoryMap, Bag3 ); - - // gear set - setupContainer( m_inventoryMap, GearSet0 ); - - // gil contianer - setupContainer( m_inventoryMap, Currency ); - - // crystals?? - setupContainer( m_inventoryMap, Crystal ); - //m_inventoryMap[0x07D3] = ItemContainerPtr( new ItemContainer( UNKNOWN_0 ) ); - //m_inventoryMap[0x07D8] = ItemContainerPtr( new ItemContainer( UNKNOWN_1 ) ); - - // armory weapons - 0 - setupContainer( m_inventoryMap, ArmoryMain ); - - // armory offhand - 1 - setupContainer( m_inventoryMap, ArmoryOff ); - - //armory head - 2 - setupContainer( m_inventoryMap, ArmoryHead ); - - //armory body - 3 - setupContainer( m_inventoryMap, ArmoryBody ); - - //armory hand - 4 - setupContainer( m_inventoryMap, ArmoryHand ); - - //armory waist - 5 - setupContainer( m_inventoryMap, ArmoryWaist ); - - //armory legs - 6 - setupContainer( m_inventoryMap, ArmoryLegs ); - - //armory feet - 7 - setupContainer( m_inventoryMap, ArmoryFeet ); - - //neck - setupContainer( m_inventoryMap, ArmotyNeck ); - - //earring - setupContainer( m_inventoryMap, ArmoryEar ); - - //wrist - setupContainer( m_inventoryMap, ArmoryWrist ); - - //armory rings - 11 - setupContainer( m_inventoryMap, ArmoryRing ); - - //soul crystals - 13 - setupContainer( m_inventoryMap, ArmorySoulCrystal ); -} - - -Core::Inventory::~Inventory() -{ -} - -Core::Inventory::InvSlotPairVec Core::Inventory::getSlotsOfItemsInInventory( uint32_t catalogId ) -{ - InvSlotPairVec outVec; - for( auto i : { Bag0, Bag1, Bag2, Bag3 } ) - { - auto inv = m_inventoryMap[i]; - for( auto item : inv->getItemMap() ) - { - if( item.second && item.second->getId() == catalogId ) - outVec.push_back( std::make_pair( i, static_cast< int8_t >( item.first ) ) ); - } - } - return outVec; -} - -Core::Inventory::InvSlotPair Core::Inventory::getFreeBagSlot() -{ - for( auto i : { Bag0, Bag1, Bag2, Bag3 } ) - { - auto freeSlot = static_cast< int8_t >( m_inventoryMap[i]->getFreeSlot() ); - - if( freeSlot != -1 ) - return std::make_pair( i, freeSlot ); - } - // no room in inventory - return std::make_pair( 0, -1 ); -} - -Core::ItemPtr Core::Inventory::getItemAt( uint16_t containerId, uint8_t slotId ) -{ - return m_inventoryMap[containerId]->getItem( slotId ); -} - -Core::ItemPtr Core::Inventory::createItem( uint32_t catalogId, uint16_t quantity ) -{ - auto pExdData = g_fw.get< Data::ExdDataGenerated >(); - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - auto itemInfo = pExdData->get< Core::Data::Item >( catalogId ); - - if( !itemInfo ) - return nullptr; - - uint16_t itemAmount = quantity; - - if( itemInfo->stackSize == 1 ) - itemAmount = 1; - - if( !itemInfo ) - return nullptr; - - uint8_t flags = 0; - - ItemPtr pItem = make_Item( getNextUId(), - catalogId, - itemInfo->modelMain, - itemInfo->modelSub ); - - pItem->setStackSize( itemAmount ); - - pDb->execute( "INSERT INTO charaglobalitem ( CharacterId, itemId, catalogId, stack, flags ) VALUES ( " + - std::to_string( m_pOwner->getId() ) + ", " + - std::to_string( pItem->getUId() ) + ", " + - std::to_string( pItem->getId() ) + ", " + - std::to_string( itemAmount ) + ", " + - std::to_string( flags ) + ");" ); - - return pItem; -} - - -uint32_t Core::Inventory::getCurrency( CurrencyType type ) -{ - - auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); - - if( !currItem ) - return 0; - - return currItem->getStackSize(); - -} - -uint32_t Core::Inventory::getCrystal( CrystalType type ) -{ - - auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); - - if( !currItem ) - return 0; - - return currItem->getStackSize(); - -} - -bool Core::Inventory::addCrystal( CrystalType type, uint32_t amount ) -{ - auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); - - if( !currItem ) - { - // TODO: map currency type to itemid - currItem = createItem( static_cast< uint8_t >( type ) + 1 ); - m_inventoryMap[Crystal]->setItem( static_cast< uint8_t >( type ) - 1, currItem ); - updateCrystalDb(); - } - - uint32_t currentAmount = currItem->getStackSize(); - - currItem->setStackSize( currentAmount + amount ); - - updateItemDb( currItem ); - - return true; - -} - -bool Core::Inventory::addCurrency( CurrencyType type, uint32_t amount ) -{ - auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); - - if( !currItem ) - { - // TODO: map currency type to itemid - currItem = createItem( 1 ); - m_inventoryMap[Currency]->setItem( static_cast< uint8_t >( type ) - 1, currItem ); - updateCurrencyDb(); - } - - uint32_t currentAmount = currItem->getStackSize(); - - currItem->setStackSize( currentAmount + amount ); - - updateItemDb( currItem ); - - return true; - -} - -void Core::Inventory::updateCurrencyDb() -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - int32_t firstItemPos = -1; - std::string query = "UPDATE charaitemcurrency SET "; - - for( int32_t i = 0; i <= 11; i++ ) - { - auto currItem = m_inventoryMap[Currency]->getItem( i ); - - if( currItem ) - { - if( firstItemPos == -1 ) - firstItemPos = i; - - if( i > firstItemPos ) - query += ", "; - - query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem->getUId() ); - } - } - - query += " WHERE CharacterId = " + std::to_string( m_pOwner->getId() ); - - pDb->execute( query ); -} - - -void Core::Inventory::updateCrystalDb() -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - int32_t firstItemPos = -1; - std::string query = "UPDATE charaitemcrystal SET "; - - for( int32_t i = 0; i <= 11; i++ ) - { - auto currItem = m_inventoryMap[Crystal]->getItem( i ); - - if( currItem ) - { - if( firstItemPos == -1 ) - firstItemPos = i; - - if( i > firstItemPos ) - query += ", "; - - query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem->getUId() ); - } - } - - query += " WHERE CharacterId = " + std::to_string( m_pOwner->getId() ); - - pDb->execute( query ); -} - -void Core::Inventory::updateBagDb( InventoryType type ) -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - std::string query = "UPDATE charaiteminventory SET "; - - for( int32_t i = 0; i <= 34; i++ ) - { - auto currItem = m_inventoryMap[type]->getItem( i ); - - if( i > 0 ) - query += ", "; - - query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem ? currItem->getUId() : 0 ); - } - - query += " WHERE CharacterId = " + std::to_string( m_pOwner->getId() ) + - " AND storageId = " + std::to_string( static_cast< uint16_t >( type ) ); - - pDb->execute( query ); -} - -bool Core::Inventory::isArmory( uint16_t containerId ) -{ - return - containerId == ArmoryBody || - containerId == ArmoryEar || - containerId == ArmoryFeet || - containerId == ArmoryHand || - containerId == ArmoryHead || - containerId == ArmoryLegs || - containerId == ArmoryMain || - containerId == ArmoryOff || - containerId == ArmoryRing || - containerId == ArmoryWaist || - containerId == ArmoryWrist; -} - -uint16_t Core::Inventory::getArmoryToEquipSlot( uint8_t slotId ) -{ - switch( slotId ) - { - case Body: - return ArmoryBody; - - case Ear: - return ArmoryEar; - - case Feet: - return ArmoryFeet; - - case Hands: - return ArmoryHand; - - case Legs: - return ArmoryLegs; - - case MainHand: - return ArmoryMain; - - case OffHand: - return ArmoryOff; - - case Ring2: - case Ring1: - return ArmoryRing; - - case Waist: - return ArmoryWaist; - - case Wrist: - return ArmoryWrist; - } - - return 0; -} - - - -bool Core::Inventory::isEquipment( uint16_t containerId ) -{ - return containerId == GearSet0; -} - - -void Core::Inventory::updateMannequinDb( InventoryType type ) -{ - auto pLog = g_fw.get< Logger >(); - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - std::string query = "UPDATE charaitemgearset SET "; - - for( int32_t i = 0; i <= 13; i++ ) - { - auto currItem = m_inventoryMap[type]->getItem( i ); - - if( i > 0 ) - query += ", "; - - query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem ? currItem->getUId() : 0 ); - } - - query += " WHERE CharacterId = " + std::to_string( m_pOwner->getId() ) + - " AND storageId = " + std::to_string( static_cast< uint16_t >( type ) ); - - pLog->debug( query ); - pDb->execute( query ); -} - - -void Core::Inventory::updateItemDb( Core::ItemPtr pItem ) const -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - pDb->execute( "UPDATE charaglobalitem SET stack = " + std::to_string( pItem->getStackSize() ) + " " + - // TODO: add other attributes - " WHERE itemId = " + std::to_string( pItem->getUId() ) ); -} - -void Core::Inventory::deleteItemDb( Core::ItemPtr item ) const -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - pDb->execute( "UPDATE charaglobalitem SET IS_DELETE = 1 WHERE itemId = " + std::to_string( item->getUId() ) ); -} - -bool Core::Inventory::removeCurrency( CurrencyType type, uint32_t amount ) -{ - - auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); - - if( !currItem ) - return false; - - uint32_t currentAmount = currItem->getStackSize(); - if( amount > currentAmount ) - currItem->setStackSize( 0 ); - else - currItem->setStackSize( currentAmount - amount ); - - updateItemDb( currItem ); - - return true; -} - -bool Core::Inventory::removeCrystal( CrystalType type, uint32_t amount ) -{ - - auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); - - if( !currItem ) - return false; - - uint32_t currentAmount = currItem->getStackSize(); - if( amount > currentAmount ) - currItem->setStackSize( 0 ); - else - currItem->setStackSize( currentAmount - amount ); - - updateItemDb( currItem ); - - return true; -} - -bool Core::Inventory::isOneHandedWeapon( ItemUICategory weaponCategory ) -{ - switch ( weaponCategory ) - { - case ItemUICategory::AlchemistsPrimaryTool: - case ItemUICategory::ArmorersPrimaryTool: - case ItemUICategory::BotanistsPrimaryTool: - case ItemUICategory::CulinariansPrimaryTool: - case ItemUICategory::OnehandedConjurersArm: - case ItemUICategory::CarpentersPrimaryTool: - case ItemUICategory::FishersPrimaryTool: - case ItemUICategory::GladiatorsArm: - case ItemUICategory::GoldsmithsPrimaryTool: - case ItemUICategory::LeatherworkersPrimaryTool: - case ItemUICategory::MinersPrimaryTool: - case ItemUICategory::OnehandedThaumaturgesArm: - case ItemUICategory::WeaversPrimaryTool: - case ItemUICategory::BlacksmithsPrimaryTool: - return true; - default: - return false; - } -} - -bool Core::Inventory::isObtainable( uint32_t catalogId, uint8_t quantity ) -{ - - return true; -} - - -int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity, bool isHq, bool silent ) -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - auto pExdData = g_fw.get< Data::ExdDataGenerated >(); - auto itemInfo = pExdData->get< Core::Data::Item >( catalogId ); - - // if item data doesn't exist or it's a blank field - if( !itemInfo || itemInfo->levelItem == 0 ) - { - return -1; - } - - int8_t rSlotId = -1; - - //if( itemInfo->stack_size > 1 ) - //{ - // auto itemList = this->getSlotsOfItemsInInventory( catalogId ); - // // TODO: this is a stacked item so we need to see if the item is already in inventory and - // // check how much free space we have on existing stacks before looking for empty slots. - //} - //else - { - auto freeSlot = this->getFreeBagSlot(); - inventoryId = freeSlot.first; - rSlotId = freeSlot.second; - - if( rSlotId == -1 ) - return -1; - } - - auto item = createItem( catalogId, quantity ); - - item->setHq( isHq ); - - if( rSlotId != -1 ) - { - - m_inventoryMap[inventoryId]->setItem( rSlotId, item ); - - pDb->execute( "UPDATE charaiteminventory SET container_" + std::to_string( rSlotId ) + " = " + std::to_string( item->getUId() ) + - " WHERE storageId = " + std::to_string( inventoryId ) + - " AND CharacterId = " + std::to_string( m_pOwner->getId() ) ); - - - auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( m_pOwner->getId() ); - invUpPacket->data().containerId = inventoryId; - invUpPacket->data().catalogId = catalogId; - invUpPacket->data().quantity = item->getStackSize(); - invUpPacket->data().hqFlag = item->isHq() ? 1 : 0; - invUpPacket->data().slot = rSlotId; - invUpPacket->data().condition = 30000; - m_pOwner->queuePacket( invUpPacket ); - - if( !silent ) - m_pOwner->queuePacket( boost::make_shared< ActorControlPacket143 >( m_pOwner->getId(), ItemObtainIcon, - catalogId, item->getStackSize() ) ); - - } - - return rSlotId; - -} - -void Core::Inventory::moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ) -{ - - auto tmpItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); - auto& itemMap = m_inventoryMap[fromInventoryId]->getItemMap(); - - if( tmpItem == nullptr ) - return; - - itemMap[fromSlotId].reset(); - - m_inventoryMap[toInventoryId]->setItem( toSlot, tmpItem ); - - if( toInventoryId != GearSet0 ) - updateBagDb( static_cast< InventoryType >( toInventoryId ) ); - - if( fromInventoryId != GearSet0 && fromInventoryId != toInventoryId ) - updateBagDb( static_cast< InventoryType >( fromInventoryId ) ); - - if( static_cast< InventoryType >( toInventoryId ) == GearSet0 ) - { - m_pOwner->equipItem( static_cast< EquipSlot >( toSlot ), tmpItem, true ); - updateMannequinDb( static_cast< InventoryType >( toInventoryId ) ); - } - - if( static_cast< InventoryType >( fromInventoryId ) == GearSet0 ) - { - m_pOwner->unequipItem( static_cast< EquipSlot >( fromSlotId ), tmpItem ); - updateMannequinDb( static_cast< InventoryType >( fromInventoryId ) ); - } - - -} - -bool Core::Inventory::updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem ) -{ - auto containerType = getContainerType( containerId ); - - m_inventoryMap[containerId]->setItem( slotId, pItem ); - - switch( containerType ) - { - case Armory: - case CurrencyCrystal: - case Bag: - { - updateBagDb( static_cast< InventoryType >( containerId ) ); - break; - } - - case GearSet: - { - if( pItem ) - m_pOwner->equipItem( static_cast< EquipSlot >( slotId ), pItem, true ); - else - m_pOwner->unequipItem( static_cast< EquipSlot >( slotId ), pItem ); - - updateMannequinDb( static_cast< InventoryType >( containerId ) ); - break; - } - default: - break; - } - - return true; -} - -void Core::Inventory::splitItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot, uint16_t itemCount ) -{ - auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); - if( !fromItem ) - return; - - // check we have enough items in the origin slot - // nb: don't let the client 'split' a whole stack into another slot - if( fromItem->getStackSize() < itemCount ) - // todo: correct the invalid item split? does retail do this or does it just ignore it? - return; - - // make sure toInventoryId & toSlot are actually free so we don't orphan an item - if( m_inventoryMap[toInventoryId]->getItem( toSlot ) ) - // todo: correct invalid move? again, not sure what retail does here - return; - - auto newSlot = addItem( toInventoryId, toSlot, fromItem->getId(), itemCount, fromItem->isHq(), true ); - if( newSlot == -1 ) - return; - - auto newItem = m_inventoryMap[toInventoryId]->getItem( static_cast< uint8_t >( newSlot ) ); - - fromItem->setStackSize( fromItem->getStackSize() - itemCount ); - - updateContainer( fromInventoryId, fromSlotId, fromItem ); - updateContainer( toInventoryId, toSlot, newItem ); - - updateItemDb( fromItem ); -} - -void Core::Inventory::mergeItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ) -{ - auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); - auto toItem = m_inventoryMap[toInventoryId]->getItem( toSlot ); - - if( !fromItem || !toItem ) - return; - - if( fromItem->getId() != toItem->getId() ) - return; - - uint32_t stackSize = fromItem->getStackSize() + toItem->getStackSize(); - uint32_t stackOverflow = stackSize - std::min< uint32_t >( m_maxSlotSize, stackSize ); - - // we can destroy the original stack if there's no overflow - if( stackOverflow == 0 ) - { - m_inventoryMap[fromInventoryId]->removeItem( fromSlotId ); - deleteItemDb( fromItem ); - } - else - { - fromItem->setStackSize( stackOverflow ); - updateItemDb( fromItem ); - } - - - toItem->setStackSize( stackSize ); - updateItemDb( toItem ); - - updateContainer( fromInventoryId, fromSlotId, fromItem ); - updateContainer( toInventoryId, toSlot, toItem ); -} - -void Core::Inventory::swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ) -{ - auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); - auto toItem = m_inventoryMap[toInventoryId]->getItem( toSlot ); - auto& itemMap = m_inventoryMap[fromInventoryId]->getItemMap(); - - if( fromItem == nullptr || toItem == nullptr ) - return; - - // An item is being moved from bag0-3 to equippment, meaning - // the swapped out item will be placed in the matching armory. - if( isEquipment( toInventoryId ) - && !isEquipment( fromInventoryId ) - && !isArmory( fromInventoryId ) ) - { - updateContainer( fromInventoryId, fromSlotId, nullptr ); - fromInventoryId = getArmoryToEquipSlot( toSlot ); - fromSlotId = static_cast < uint8_t >( m_inventoryMap[fromInventoryId]->getFreeSlot() ); - } - - auto containerTypeFrom = getContainerType( fromInventoryId ); - auto containerTypeTo = getContainerType( toInventoryId ); - - updateContainer( toInventoryId, toSlot, fromItem ); - updateContainer( fromInventoryId, fromSlotId, toItem ); -} - -void Core::Inventory::discardItem( uint16_t fromInventoryId, uint8_t fromSlotId ) -{ - // i am not entirely sure how this should be generated or if it even is important for us... - uint32_t transactionId = 1; - - auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); - - deleteItemDb( fromItem ); - - m_inventoryMap[fromInventoryId]->removeItem( fromSlotId ); - updateContainer( fromInventoryId, fromSlotId, nullptr ); - - auto invTransPacket = makeZonePacket< FFXIVIpcInventoryTransaction >( m_pOwner->getId() ); - invTransPacket->data().transactionId = transactionId; - invTransPacket->data().ownerId = m_pOwner->getId(); - invTransPacket->data().storageId = fromInventoryId; - invTransPacket->data().catalogId = fromItem->getId(); - invTransPacket->data().stackSize = fromItem->getStackSize(); - invTransPacket->data().slotId = fromSlotId; - invTransPacket->data().type = 7; - m_pOwner->queuePacket( invTransPacket ); - - auto invTransFinPacket = makeZonePacket< FFXIVIpcInventoryTransactionFinish >( m_pOwner->getId() ); - invTransFinPacket->data().transactionId = transactionId; - invTransFinPacket->data().transactionId1 = transactionId; - m_pOwner->queuePacket( invTransFinPacket ); -} - -Core::ItemPtr Core::Inventory::loadItem( uint64_t uId ) -{ - auto pExdData = g_fw.get< Data::ExdDataGenerated >(); - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - // load actual item - auto itemRes = pDb->query( "SELECT catalogId, stack, flags FROM charaglobalitem WHERE itemId = " + std::to_string( uId ) + ";" ); - if( !itemRes->next() ) - return nullptr; - - try - { - auto itemInfo = pExdData->get< Core::Data::Item >( itemRes->getUInt( 1 ) ); - bool isHq = itemRes->getUInt( 3 ) == 1; - - ItemPtr pItem = make_Item( uId, - itemRes->getUInt( 1 ), - itemInfo->modelMain, - itemInfo->modelSub, - isHq ); - - pItem->setStackSize( itemRes->getUInt( 2 ) ); - - return pItem; - } - catch( ... ) - { - return nullptr; - } -} - -bool Core::Inventory::load() -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - ////////////////////////////////////////////////////////////////////////////////////////////////////// - // load active gearset - auto res = pDb->query( "SELECT storageId, container_0, container_1, container_2, container_3, " - "container_4, container_5, container_6, container_7, " - "container_8, container_9, container_10, container_11, " - "container_12, container_13 " - "FROM charaitemgearset " \ - "WHERE CharacterId = " + std::to_string( m_pOwner->getId() ) + " " \ - "ORDER BY storageId ASC;" ); - - while( res->next() ) - { - uint16_t storageId = res->getUInt16( 1 ); - - for( uint32_t i = 1; i <= 14; i++ ) - { - uint64_t uItemId = res->getUInt64( i + 1 ); - if( uItemId == 0 ) - continue; - - ItemPtr pItem = loadItem( uItemId ); - - if( pItem == nullptr ) - continue; - - m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; - m_pOwner->equipItem( static_cast< EquipSlot >( i - 1 ), pItem, false ); - } - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - // Load Bags - auto bagRes = pDb->query( "SELECT storageId, " - "container_0, container_1, container_2, container_3, container_4, " - "container_5, container_6, container_7, container_8, container_9, " - "container_10, container_11, container_12, container_13, container_14, " - "container_15, container_16, container_17, container_18, container_19, " - "container_20, container_21, container_22, container_23, container_24, " - "container_25, container_26, container_27, container_28, container_29, " - "container_30, container_31, container_32, container_33, container_34 " - "FROM charaiteminventory " \ - "WHERE CharacterId = " + std::to_string( m_pOwner->getId() ) + " " \ - "ORDER BY storageId ASC;" ); - - while( bagRes->next() ) - { - uint16_t storageId = bagRes->getUInt16( 1 ); - for( uint32_t i = 1; i <= 35; i++ ) - { - uint64_t uItemId = bagRes->getUInt64( i + 1 ); - if( uItemId == 0 ) - continue; - - ItemPtr pItem = loadItem( uItemId ); - - if( pItem == nullptr ) - continue; - - m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; - } - } - - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - // Load Currency - auto curRes = pDb->query( "SELECT storageId, " - "container_0, container_1, container_2, container_3, container_4, " - "container_5, container_6, container_7, container_8, container_9, " - "container_10, container_11 " - "FROM charaitemcurrency " \ - "WHERE CharacterId = " + std::to_string( m_pOwner->getId() ) + " " \ - "ORDER BY storageId ASC;" ); - - while( curRes->next() ) - { - uint16_t storageId = curRes->getUInt16( 1 ); - for( uint32_t i = 1; i <= 12; i++ ) - { - uint64_t uItemId = curRes->getUInt64( i + 1 ); - if( uItemId == 0 ) - continue; - - ItemPtr pItem = loadItem( uItemId ); - - if( pItem == nullptr ) - continue; - - m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; - } - } - - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - // Load Crystals - auto crystalRes = pDb->query( "SELECT storageId, " - "container_0, container_1, container_2, container_3, container_4, " - "container_5, container_6, container_7, container_8, container_9, " - "container_10, container_11, container_12, container_13, container_14, " - "container_15, container_16, container_17 " - "FROM charaitemcrystal " \ - "WHERE CharacterId = " + std::to_string( m_pOwner->getId() ) + " " \ - "ORDER BY storageId ASC;" ); - - while( crystalRes->next() ) - { - uint16_t storageId = crystalRes->getUInt16( 1 ); - for( int32_t i = 1; i <= 17; i++ ) - { - uint64_t uItemId = crystalRes->getUInt64( i + 1 ); - if( uItemId == 0 ) - continue; - - ItemPtr pItem = loadItem( uItemId ); - - if( pItem == nullptr ) - continue; - - m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; - } - } - - return true; -} - - -void Core::Inventory::send() -{ - InventoryMap::iterator it; - - int32_t count = 0; - for( it = m_inventoryMap.begin(); it != m_inventoryMap.end(); ++it, count++ ) - { - - auto pMap = it->second->getItemMap(); - auto itM = pMap.begin(); - - for( ; itM != pMap.end(); ++itM ) - { - if( !itM->second ) - return; - - if( it->second->getId() == InventoryType::Currency || it->second->getId() == InventoryType::Crystal ) - { - auto currencyInfoPacket = makeZonePacket< FFXIVIpcCurrencyCrystalInfo >( m_pOwner->getId() ); - currencyInfoPacket->data().sequence = count; - currencyInfoPacket->data().catalogId = itM->second->getId(); - currencyInfoPacket->data().unknown = 1; - currencyInfoPacket->data().quantity = itM->second->getStackSize(); - currencyInfoPacket->data().containerId = it->second->getId(); - currencyInfoPacket->data().slot = 0; - m_pOwner->queuePacket( currencyInfoPacket ); - } - else - { - auto itemInfoPacket = makeZonePacket< FFXIVIpcItemInfo >( m_pOwner->getId() ); - itemInfoPacket->data().sequence = count; - itemInfoPacket->data().containerId = it->second->getId(); - itemInfoPacket->data().slot = itM->first; - itemInfoPacket->data().quantity = itM->second->getStackSize(); - itemInfoPacket->data().catalogId = itM->second->getId(); - itemInfoPacket->data().condition = 30000; - itemInfoPacket->data().spiritBond = 0; - itemInfoPacket->data().hqFlag = itM->second->isHq() ? 1 : 0; - m_pOwner->queuePacket( itemInfoPacket ); - } - } - - auto containerInfoPacket = makeZonePacket< FFXIVIpcContainerInfo >( m_pOwner->getId() ); - containerInfoPacket->data().sequence = count; - containerInfoPacket->data().numItems = it->second->getEntryCount(); - containerInfoPacket->data().containerId = it->second->getId(); - m_pOwner->queuePacket( containerInfoPacket ); - - - } - -} - -uint16_t Core::Inventory::calculateEquippedGearItemLevel() -{ - uint32_t iLvlResult = 0; - - auto gearSetMap = m_inventoryMap[GearSet0]->getItemMap(); - - auto it = gearSetMap.begin(); - - while( it != gearSetMap.end() ) - { - auto currItem = it->second; - - if( currItem ) - { - iLvlResult += currItem->getItemLevel(); - - // If item is weapon and isn't one-handed - if( currItem->isWeapon() && !isOneHandedWeapon( currItem->getCategory() ) ) - { - iLvlResult += currItem->getItemLevel(); - } - } - - it++; - } - - return boost::algorithm::clamp( iLvlResult / 13, 0, 9999 ); -} - - -uint8_t Core::Inventory::getFreeSlotsInBags() -{ - uint8_t slots = 0; - for( uint8_t container : { 0, 1, 2, 3 } ) - { - slots += 34 - m_inventoryMap[container]->getEntryCount(); - } - return slots; -} - - -Core::Common::ContainerType Core::Inventory::getContainerType( uint32_t containerId ) -{ - if( containerId < 5 ) - { - return Bag; - } - else if( containerId < 2000 ) - { - return GearSet; - } - else if( containerId < 3200 ) - { - return CurrencyCrystal; - } - else if( containerId < 3600 ) - { - return Armory; - } - else - { - return Common::Unknown; - } -} - -uint32_t Core::Inventory::getNextUId() -{ - uint32_t charId = 0; - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - auto pQR = pDb->query( "SELECT MAX(ItemId) FROM charaglobalitem" ); - - if( !pQR->next() ) - return 0x00500001; - - charId = pQR->getUInt( 1 ) + 1; - if( charId < 0x00500001 ) - return 0x00500001; - - return charId; -} diff --git a/src/servers/sapphire_zone/Inventory/Inventory.h b/src/servers/sapphire_zone/Inventory/Inventory.h deleted file mode 100644 index daaa188c..00000000 --- a/src/servers/sapphire_zone/Inventory/Inventory.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef INVENTORY_H_ -#define INVENTORY_H_ -#include -#include -#include "Forwards.h" - -namespace Core -{ - -class ItemContainer; - -using InventoryMap = std::map< uint16_t, ItemContainerPtr >; -class Inventory -{ -public: - Inventory( Entity::Player* pOwner ); - ~Inventory(); - - using InvSlotPair = std::pair< uint16_t, int8_t >; - typedef std::vector< InvSlotPair > InvSlotPairVec; - - InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId ); - InvSlotPair getFreeBagSlot(); - int16_t addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity = 1, bool isHq = false, bool silent = false ); - void moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ); - void swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ); - void discardItem( uint16_t fromInventoryId, uint8_t fromSlotId ); - void splitItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot, uint16_t splitCount ); - void mergeItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ); - - ItemPtr createItem( uint32_t catalogId, uint16_t quantity = 1 ); - - ItemPtr loadItem( uint64_t uId ); - - ItemPtr getItemAt( uint16_t containerId, uint8_t slotId ); - - bool updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem ); - - /*! heck if weapon category qualifies the weapon as onehanded */ - bool isOneHandedWeapon( Common::ItemUICategory weaponCategory ); - /*! calculate and return player ilvl based off equipped gear */ - uint16_t calculateEquippedGearItemLevel(); - /*! return the current amount of currency of type */ - uint32_t getCurrency( Common::CurrencyType type ); - /*! add amount to the current of type */ - bool addCurrency( Common::CurrencyType type, uint32_t amount ); - /*! remove amount from the currency of type */ - bool removeCurrency( Common::CurrencyType type, uint32_t amount ); - - void updateCurrencyDb(); - void updateBagDb( Common::InventoryType type ); - void updateMannequinDb( Common::InventoryType type ); - void updateItemDb( ItemPtr pItem ) const; - void deleteItemDb( ItemPtr pItem ) const; - - bool isArmory( uint16_t containerId ); - bool isEquipment( uint16_t containerId ); - uint16_t getArmoryToEquipSlot( uint8_t slotId ); - - /*! return the crystal amount of currency of type */ - uint32_t getCrystal( Common::CrystalType type ); - /*! add amount to the crystal of type */ - bool addCrystal( Common::CrystalType type, uint32_t amount ); - /*! remove amount from the crystals of type */ - bool removeCrystal( Common::CrystalType type, uint32_t amount ); - bool isObtainable( uint32_t catalogId, uint8_t quantity ); - - void updateCrystalDb(); - - bool load(); - - void send(); - - uint8_t getFreeSlotsInBags(); - - Common::ContainerType getContainerType( uint32_t containerId ); - - uint32_t getNextUId(); - - -private: - Entity::Player* m_pOwner; - InventoryMap m_inventoryMap; - const uint32_t m_maxSlotSize = 999; -}; - -} -#endif diff --git a/src/servers/sapphire_zone/Inventory/Item.cpp b/src/servers/sapphire_zone/Inventory/Item.cpp index 73727509..e16a294a 100644 --- a/src/servers/sapphire_zone/Inventory/Item.cpp +++ b/src/servers/sapphire_zone/Inventory/Item.cpp @@ -24,6 +24,7 @@ Core::Item::Item( uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t mo m_autoAttackDmg = static_cast< float >( m_weaponDmg * m_delayMs ) / 3000; m_category = static_cast< Common::ItemUICategory >( itemInfo->itemUICategory ); m_itemLevel = itemInfo->levelItem; + m_maxStackSize = itemInfo->stackSize; } float Core::Item::getAutoAttackDmg() const @@ -126,3 +127,8 @@ void Core::Item::setHq( bool isHq ) { m_isHq = isHq; } + +uint32_t Core::Item::getMaxStackSize() const +{ + return m_maxStackSize; +} diff --git a/src/servers/sapphire_zone/Inventory/Item.h b/src/servers/sapphire_zone/Inventory/Item.h index 2801adf4..f694fccb 100644 --- a/src/servers/sapphire_zone/Inventory/Item.h +++ b/src/servers/sapphire_zone/Inventory/Item.h @@ -52,6 +52,8 @@ public: uint16_t getItemLevel() const; + uint32_t getMaxStackSize() const; + protected: uint32_t m_id; @@ -61,6 +63,7 @@ protected: Common::ItemUICategory m_category; uint32_t m_stackSize; + uint32_t m_maxStackSize; std::vector< uint8_t > m_classJobList; uint64_t m_model1; diff --git a/src/servers/sapphire_zone/Inventory/ItemUtil.cpp b/src/servers/sapphire_zone/Inventory/ItemUtil.cpp new file mode 100644 index 00000000..340dd7dc --- /dev/null +++ b/src/servers/sapphire_zone/Inventory/ItemUtil.cpp @@ -0,0 +1,171 @@ +#include "ItemUtil.h" + +#include "ItemContainer.h" +#include "Item.h" +#include "Framework.h" +#include + +#include +#include +#include + + +extern Core::Framework g_fw; + +bool Core::Items::Util::isArmory( uint16_t containerId ) +{ + return + containerId == Common::ArmoryBody || + containerId == Common::ArmoryEar || + containerId == Common::ArmoryFeet || + containerId == Common::ArmoryHand || + containerId == Common::ArmoryHead || + containerId == Common::ArmoryLegs || + containerId == Common::ArmoryMain || + containerId == Common::ArmoryOff || + containerId == Common::ArmoryRing || + containerId == Common::ArmoryWaist || + containerId == Common::ArmoryWrist; +} + +uint16_t Core::Items::Util::getArmoryToEquipSlot( uint8_t slotId ) +{ + switch( slotId ) + { + case Common::Body: + return Common::ArmoryBody; + + case Common::Ear: + return Common::ArmoryEar; + + case Common::Feet: + return Common::ArmoryFeet; + + case Common::Hands: + return Common::ArmoryHand; + + case Common::Legs: + return Common::ArmoryLegs; + + case Common::MainHand: + return Common::ArmoryMain; + + case Common::OffHand: + return Common::ArmoryOff; + + case Common::Ring2: + case Common::Ring1: + return Common::ArmoryRing; + + case Common::Waist: + return Common::ArmoryWaist; + + case Common::Wrist: + return Common::ArmoryWrist; + } + + return 0; +} + + + +bool Core::Items::Util::isEquipment( uint16_t containerId ) +{ + return containerId == Common::GearSet0; +} + + +bool Core::Items::Util::isOneHandedWeapon( Common::ItemUICategory weaponCategory ) +{ + switch ( weaponCategory ) + { + case Common::ItemUICategory::AlchemistsPrimaryTool: + case Common::ItemUICategory::ArmorersPrimaryTool: + case Common::ItemUICategory::BotanistsPrimaryTool: + case Common::ItemUICategory::CulinariansPrimaryTool: + case Common::ItemUICategory::OnehandedConjurersArm: + case Common::ItemUICategory::CarpentersPrimaryTool: + case Common::ItemUICategory::FishersPrimaryTool: + case Common::ItemUICategory::GladiatorsArm: + case Common::ItemUICategory::GoldsmithsPrimaryTool: + case Common::ItemUICategory::LeatherworkersPrimaryTool: + case Common::ItemUICategory::MinersPrimaryTool: + case Common::ItemUICategory::OnehandedThaumaturgesArm: + case Common::ItemUICategory::WeaversPrimaryTool: + case Common::ItemUICategory::BlacksmithsPrimaryTool: + return true; + default: + return false; + } +} + +Core::ItemPtr Core::Items::Util::loadItem( uint64_t uId ) +{ + auto pExdData = g_fw.get< Data::ExdDataGenerated >(); + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + // load actual item + auto itemRes = pDb->query( "SELECT catalogId, stack, flags FROM charaglobalitem WHERE itemId = " + std::to_string( uId ) + ";" ); + if( !itemRes->next() ) + return nullptr; + + try + { + auto itemInfo = pExdData->get< Core::Data::Item >( itemRes->getUInt( 1 ) ); + bool isHq = itemRes->getUInt( 3 ) == 1; + + ItemPtr pItem = make_Item( uId, + itemRes->getUInt( 1 ), + itemInfo->modelMain, + itemInfo->modelSub, + isHq ); + + pItem->setStackSize( itemRes->getUInt( 2 ) ); + + return pItem; + } + catch( ... ) + { + return nullptr; + } +} + +Core::Common::ContainerType Core::Items::Util::getContainerType( uint32_t containerId ) +{ + if( containerId < 5 ) + { + return Common::Bag; + } + else if( containerId < 2000 ) + { + return Common::GearSet; + } + else if( containerId < 3200 ) + { + return Common::CurrencyCrystal; + } + else if( containerId < 3600 ) + { + return Common::Armory; + } + else + { + return Common::Unknown; + } +} + + +uint32_t Core::Items::Util::getNextUId() +{ + uint32_t charId = 0; + auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); + auto pQR = pDb->query( "SELECT MAX(ItemId) FROM charaglobalitem" ); + + if( !pQR->next() ) + return 0x00500001; + + charId = pQR->getUInt( 1 ) + 1; + if( charId < 0x00500001 ) + return 0x00500001; + + return charId; +} diff --git a/src/servers/sapphire_zone/Inventory/ItemUtil.h b/src/servers/sapphire_zone/Inventory/ItemUtil.h new file mode 100644 index 00000000..9d0e401c --- /dev/null +++ b/src/servers/sapphire_zone/Inventory/ItemUtil.h @@ -0,0 +1,30 @@ +#ifndef SAPPHIRE_ITEMUTIL_H +#define SAPPHIRE_ITEMUTIL_H + +#include +#include "Forwards.h" + +namespace Core { +namespace Items { +namespace Util { + + ItemPtr loadItem( uint64_t uId ); + + /*! check if weapon category qualifies the weapon as onehanded */ + bool isOneHandedWeapon( Common::ItemUICategory weaponCategory ); + + bool isArmory( uint16_t containerId ); + bool isEquipment( uint16_t containerId ); + uint16_t getArmoryToEquipSlot( uint8_t slotId ); + + Common::ContainerType getContainerType( uint32_t containerId ); + + uint32_t getNextUId(); + +} +} +} + + + +#endif //SAPPHIRE_ITEMMGR_H diff --git a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp index 4a583bc6..27950719 100644 --- a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp @@ -196,7 +196,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_R case GmCommand::Inspect: { player.sendNotice( "Name: " + targetPlayer->getName() + - "\nGil: " + std::to_string( targetPlayer->getCurrency( 1 ) ) + + "\nGil: " + std::to_string( targetPlayer->getCurrency( CurrencyType::Gil ) ) + "\nZone: " + targetPlayer->getCurrentZone()->getName() + "(" + std::to_string( targetPlayer->getZoneId() ) + ")" + "\nClass: " + std::to_string( static_cast< uint8_t >( targetPlayer->getClass() ) ) + @@ -329,13 +329,13 @@ void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_R } case GmCommand::Gil: { - targetPlayer->addCurrency( 1, param1 ); + targetPlayer->addCurrency( CurrencyType::Gil, param1 ); player.sendNotice( "Added " + std::to_string( param1 ) + " Gil for " + targetPlayer->getName() ); break; } case GmCommand::Collect: { - uint32_t gil = targetPlayer->getCurrency( 1 ); + uint32_t gil = targetPlayer->getCurrency( CurrencyType::Gil ); if( gil < param1 ) { diff --git a/src/servers/sapphire_zone/Network/Handlers/InventoryHandler.cpp b/src/servers/sapphire_zone/Network/Handlers/InventoryHandler.cpp index 71ae48cc..91e962f2 100644 --- a/src/servers/sapphire_zone/Network/Handlers/InventoryHandler.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/InventoryHandler.cpp @@ -58,31 +58,31 @@ void Core::Network::GameConnection::inventoryModifyHandler( const Packets::FFXIV case InventoryOperation::Discard: // discard item action { - player.getInventory()->discardItem( fromContainer, fromSlot ); + player.discardItem( fromContainer, fromSlot ); } break; case InventoryOperation::Move: // move item action { - player.getInventory()->moveItem( fromContainer, fromSlot, toContainer, toSlot ); + player.moveItem( fromContainer, fromSlot, toContainer, toSlot ); } break; case InventoryOperation::Swap: // swap item action { - player.getInventory()->swapItem( fromContainer, fromSlot, toContainer, toSlot ); + player.swapItem( fromContainer, fromSlot, toContainer, toSlot ); } break; case InventoryOperation::Merge: // merge stack action { - player.getInventory()->mergeItem( fromContainer, fromSlot, toContainer, toSlot ); + player.mergeItem( fromContainer, fromSlot, toContainer, toSlot ); } break; case InventoryOperation::Split: // split stack action { - player.getInventory()->splitItem( fromContainer, fromSlot, toContainer, toSlot, splitCount ); + player.splitItem( fromContainer, fromSlot, toContainer, toSlot, splitCount ); } break; diff --git a/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h b/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h index 760a1c2b..b41282de 100644 --- a/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h +++ b/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h @@ -6,7 +6,6 @@ #include #include "Actor/Player.h" #include "Forwards.h" -#include "Inventory/Inventory.h" #include "Inventory/Item.h" #include "StatusEffect/StatusEffect.h" @@ -50,7 +49,7 @@ namespace Server { memcpy( m_data.look, player.getLookArray(), 26 ); - auto item = player.getInventory()->getItemAt( Common::GearSet0, Common::EquipSlot::MainHand ); + auto item = player.getItemAt( Common::GearSet0, Common::EquipSlot::MainHand ); if( item ) m_data.mainWeaponModel = item->getModelId1(); m_data.secWeaponModel = player.getModelSubWeapon(); From e11f1b3f20c3af9606dcf62cb399ca0453d9f732 Mon Sep 17 00:00:00 2001 From: Mordred Admin Date: Wed, 25 Jul 2018 09:48:54 +0200 Subject: [PATCH 02/12] Finished removing old inventory class and moving stuff into player --- src/servers/sapphire_zone/Actor/Player.h | 10 +++------- src/servers/sapphire_zone/Actor/PlayerInventory.cpp | 13 +++---------- .../Network/Handlers/GMCommandHandlers.cpp | 2 +- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/servers/sapphire_zone/Actor/Player.h b/src/servers/sapphire_zone/Actor/Player.h index 3feb94d5..cce73edb 100644 --- a/src/servers/sapphire_zone/Actor/Player.h +++ b/src/servers/sapphire_zone/Actor/Player.h @@ -248,13 +248,9 @@ public: /*! add amount to the currency of type */ void addCurrency( Common::CurrencyType type, uint32_t amount ); /*! remove amount from the currency of type */ - void removeCurrency( uint8_t type, uint32_t amount ); + void removeCurrency( Common::CurrencyType type, uint32_t amount ); /*! return the current amount of crystals of type */ uint32_t getCrystal( uint8_t type ) const; - /*! add amount to the crystals of type */ - void addCrystal( uint8_t type, uint32_t amount ); - /*! remove amount from the crystals of type */ - void removeCrystal( uint8_t type, uint32_t amount ); // Class / Job / Exp ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -638,9 +634,9 @@ public: /*! return the crystal amount of currency of type */ uint32_t getCrystal( Common::CrystalType type ); /*! add amount to the crystal of type */ - bool addCrystal( Common::CrystalType type, uint32_t amount ); + void addCrystal( Common::CrystalType type, uint32_t amount ); /*! remove amount from the crystals of type */ - bool removeCrystal( Common::CrystalType type, uint32_t amount ); + void removeCrystal( Common::CrystalType type, uint32_t amount ); bool isObtainable( uint32_t catalogId, uint8_t quantity ); void updateCrystalDb(); diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index fce1dbcd..40a853df 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -249,7 +249,7 @@ void Core::Entity::Player::removeCurrency( Common::CurrencyType type, uint32_t a auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); if( !currItem ) - return false; + return; uint32_t currentAmount = currItem->getStackSize(); if( amount > currentAmount ) @@ -316,7 +316,7 @@ void Core::Entity::Player::removeCrystal( Common::CrystalType type, uint32_t amo auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); invUpPacket->data().containerId = Common::InventoryType::Crystal; invUpPacket->data().catalogId = static_cast< uint8_t >( type ) + 1; - invUpPacket->data().quantity = getCrystal( static_cast< Common::CrystalType >( type ) ); + invUpPacket->data().quantity = getCrystal( type ); invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; queuePacket( invUpPacket ); @@ -333,14 +333,6 @@ bool Core::Entity::Player::tryAddItem( uint16_t catalogId, uint32_t quantity ) return false; } -/*bool Core::Entity::Player::addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity ) -{ - if( addItem( containerId, -1, catalogId, quantity ) != -1 ) - return true; - - return false; -}*/ - void Core::Entity::Player::sendInventory() { InventoryMap::iterator it; @@ -863,6 +855,7 @@ uint8_t Core::Entity::Player::getFreeSlotsInBags() uint8_t slots = 0; for( uint8_t container : { 0, 1, 2, 3 } ) { + // TODO: this feels hackish at best slots += 34 - m_inventoryMap[container]->getEntryCount(); } return slots; diff --git a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp index 27950719..7a05e469 100644 --- a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp @@ -343,7 +343,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_R } else { - targetPlayer->removeCurrency( 1, param1 ); + targetPlayer->removeCurrency( CurrencyType::Gil, param1 ); player.sendNotice( "Removed " + std::to_string( param1 ) + " Gil from " + targetPlayer->getName() + "(" + std::to_string( gil ) + " before)" ); From 260092f5427b5915eece9467c93c39d5201bec2d Mon Sep 17 00:00:00 2001 From: Mordred Admin Date: Wed, 25 Jul 2018 14:03:43 +0200 Subject: [PATCH 03/12] Storing container configuration in container object --- .../sapphire_zone/Actor/PlayerInventory.cpp | 46 +++++++++---------- .../sapphire_zone/Inventory/ItemContainer.cpp | 27 +++++++++-- .../sapphire_zone/Inventory/ItemContainer.h | 14 ++++-- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index 40a853df..90a7fbef 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -44,64 +44,62 @@ using namespace Core::Network::ActorControl; void Core::Entity::Player::initInventory() { - auto setupContainer = [this]( InventoryType type ) - { m_inventoryMap[type] = make_ItemContainer( type ); }; + auto setupContainer = [this]( InventoryType type, uint8_t maxSize, const std::string& tableName, bool isMultiStorage ) + { m_inventoryMap[type] = make_ItemContainer( type, maxSize, tableName, isMultiStorage ); }; // main bags - setupContainer( Bag0 ); - setupContainer( Bag1 ); - setupContainer( Bag2 ); - setupContainer( Bag3 ); + setupContainer( Bag0, 34, "charaiteminventory", true ); + setupContainer( Bag1, 34, "charaiteminventory", true ); + setupContainer( Bag2, 34, "charaiteminventory", true ); + setupContainer( Bag3, 34, "charaiteminventory", true ); // gear set - setupContainer( GearSet0 ); + setupContainer( GearSet0, 13, "charaitemgearset", true ); // gil contianer - setupContainer( Currency ); + setupContainer( Currency, 11, "charaitemcurrency", false ); // crystals?? - setupContainer( Crystal ); - //m_inventoryMap[0x07D3] = ItemContainerPtr( new ItemContainer( UNKNOWN_0 ) ); - //m_inventoryMap[0x07D8] = ItemContainerPtr( new ItemContainer( UNKNOWN_1 ) ); + setupContainer( Crystal, 11, "charaitemcrystal", false ); // armory weapons - 0 - setupContainer( ArmoryMain ); + setupContainer( ArmoryMain, 34, "charaiteminventory", true ); // armory offhand - 1 - setupContainer( ArmoryOff ); + setupContainer( ArmoryOff, 34, "charaiteminventory", true ); //armory head - 2 - setupContainer( ArmoryHead ); + setupContainer( ArmoryHead, 34, "charaiteminventory", true ); //armory body - 3 - setupContainer( ArmoryBody ); + setupContainer( ArmoryBody, 34, "charaiteminventory", true ); //armory hand - 4 - setupContainer( ArmoryHand ); + setupContainer( ArmoryHand, 34, "charaiteminventory", true ); //armory waist - 5 - setupContainer( ArmoryWaist ); + setupContainer( ArmoryWaist, 34, "charaiteminventory", true ); //armory legs - 6 - setupContainer( ArmoryLegs ); + setupContainer( ArmoryLegs, 34, "charaiteminventory", true ); //armory feet - 7 - setupContainer( ArmoryFeet ); + setupContainer( ArmoryFeet, 34, "charaiteminventory", true ); //neck - setupContainer( ArmotyNeck ); + setupContainer( ArmotyNeck, 34, "charaiteminventory", true ); //earring - setupContainer( ArmoryEar ); + setupContainer( ArmoryEar, 34, "charaiteminventory", true ); //wrist - setupContainer( ArmoryWrist ); + setupContainer( ArmoryWrist, 34, "charaiteminventory", true ); //armory rings - 11 - setupContainer( ArmoryRing ); + setupContainer( ArmoryRing, 34, "charaiteminventory", true ); //soul crystals - 13 - setupContainer( ArmorySoulCrystal ); + setupContainer( ArmorySoulCrystal, 34, "charaiteminventory", true ); loadInventory(); diff --git a/src/servers/sapphire_zone/Inventory/ItemContainer.cpp b/src/servers/sapphire_zone/Inventory/ItemContainer.cpp index 54a65309..330c77f7 100644 --- a/src/servers/sapphire_zone/Inventory/ItemContainer.cpp +++ b/src/servers/sapphire_zone/Inventory/ItemContainer.cpp @@ -11,9 +11,11 @@ extern Core::Framework g_fw; -Core::ItemContainer::ItemContainer( uint16_t locationId ) : - m_id( locationId ), - m_size( 35 ) +Core::ItemContainer::ItemContainer( uint16_t storageId, uint8_t maxSize, const std::string& tableName, bool isMultiStorage ) : + m_id( storageId ), + m_size( maxSize ), + m_tableName( tableName ), + m_bMultiStorage( isMultiStorage ) { } @@ -63,7 +65,7 @@ const Core::ItemMap & Core::ItemContainer::getItemMap() const return m_itemMap; } -int16_t Core::ItemContainer::getFreeSlot() +int8_t Core::ItemContainer::getFreeSlot() { for( uint8_t slotId = 0; slotId < m_size; slotId++ ) { @@ -95,3 +97,20 @@ void Core::ItemContainer::setItem( uint8_t slotId, ItemPtr pItem ) m_itemMap[slotId] = pItem; } + +uint8_t Core::ItemContainer::getMaxSize() const +{ + return m_size; +} + +std::string Core::ItemContainer::getTableName() const +{ + return m_tableName; +} + +bool Core::ItemContainer::isMultiStorage() const +{ + return m_bMultiStorage; +} + + diff --git a/src/servers/sapphire_zone/Inventory/ItemContainer.h b/src/servers/sapphire_zone/Inventory/ItemContainer.h index 223dd7ae..0d0334bf 100644 --- a/src/servers/sapphire_zone/Inventory/ItemContainer.h +++ b/src/servers/sapphire_zone/Inventory/ItemContainer.h @@ -10,13 +10,13 @@ namespace Core { - typedef std::map< uint8_t, ItemPtr > ItemMap; + using ItemMap = std::map< uint8_t, ItemPtr >; class ItemContainer { public: - ItemContainer( uint16_t locationId ); + ItemContainer( uint16_t storageId, uint8_t maxSize, const std::string& tableName, bool isMultiStorage ); ~ItemContainer(); uint16_t getId() const; @@ -33,11 +33,19 @@ namespace Core void setItem( uint8_t slotId, ItemPtr item ); - int16_t getFreeSlot(); + int8_t getFreeSlot(); + uint8_t getMaxSize() const; + + std::string getTableName() const; + + bool isMultiStorage() const; + private: uint16_t m_id; uint8_t m_size; + std::string m_tableName; + bool m_bMultiStorage; ItemMap m_itemMap; Entity::PlayerPtr m_pOwner; }; From 783bd655a8ed06d4df1ab723f4810f43d505c6fc Mon Sep 17 00:00:00 2001 From: Mordred Admin Date: Thu, 26 Jul 2018 14:09:09 +0200 Subject: [PATCH 04/12] Inventory code cleanup number 2, packetWrapper for slot update --- .../sapphire_zone/Actor/PlayerInventory.cpp | 70 ++++++++----------- .../sapphire_zone/Inventory/ItemContainer.cpp | 4 +- .../UpdateInventorySlotPacket.h | 60 ++++++++++++++++ 3 files changed, 92 insertions(+), 42 deletions(-) create mode 100644 src/servers/sapphire_zone/Network/PacketWrappers/UpdateInventorySlotPacket.h diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index 90a7fbef..23220637 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -6,6 +6,7 @@ #include "Network/PacketWrappers/ActorControlPacket142.h" #include "Network/PacketWrappers/ActorControlPacket143.h" +#include "Network/PacketWrappers/UpdateInventorySlotPacket.h" #include "Inventory/Item.h" #include "Inventory/ItemContainer.h" @@ -232,13 +233,11 @@ void Core::Entity::Player::addCurrency( CurrencyType type, uint32_t amount ) currItem->setStackSize( currentAmount + amount ); updateItemDb( currItem ); - auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); - invUpPacket->data().containerId = Common::InventoryType::Currency; - invUpPacket->data().catalogId = 1; - invUpPacket->data().quantity = getCurrency( type ); - invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; - - queuePacket( invUpPacket ); + auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), + static_cast< uint8_t >( type ) - 1, + Common::InventoryType::Currency, + *currItem ); + queuePacket( invUpdate ); } void Core::Entity::Player::removeCurrency( Common::CurrencyType type, uint32_t amount ) @@ -254,15 +253,13 @@ void Core::Entity::Player::removeCurrency( Common::CurrencyType type, uint32_t a currItem->setStackSize( 0 ); else currItem->setStackSize( currentAmount - amount ); - updateItemDb( currItem ); - auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); - invUpPacket->data().containerId = Common::InventoryType::Currency; - invUpPacket->data().catalogId = 1; - invUpPacket->data().quantity = getCurrency( type ); - invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; - queuePacket( invUpPacket ); + auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), + static_cast< uint8_t >( type ) - 1, + Common::InventoryType::Currency, + *currItem ); + queuePacket( invUpdate ); } @@ -284,14 +281,12 @@ void Core::Entity::Player::addCrystal( Common::CrystalType type, uint32_t amount updateItemDb( currItem ); - auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); - invUpPacket->data().containerId = Common::InventoryType::Crystal; - invUpPacket->data().catalogId = static_cast< uint8_t >( type ) + 1; - invUpPacket->data().quantity = getCrystal( type ); - invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; - - queuePacket( invUpPacket ); + auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), + static_cast< uint8_t >( type ) - 1, + Common::InventoryType::Crystal, + *currItem ); + queuePacket( invUpdate ); queuePacket( boost::make_shared< ActorControlPacket143 >( getId(), ItemObtainIcon, static_cast< uint8_t >( type ) + 1, amount ) ); } @@ -311,13 +306,11 @@ void Core::Entity::Player::removeCrystal( Common::CrystalType type, uint32_t amo updateItemDb( currItem ); - auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); - invUpPacket->data().containerId = Common::InventoryType::Crystal; - invUpPacket->data().catalogId = static_cast< uint8_t >( type ) + 1; - invUpPacket->data().quantity = getCrystal( type ); - invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1; - - queuePacket( invUpPacket ); + auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), + static_cast< uint8_t >( type ) - 1, + Common::InventoryType::Crystal, + *currItem ); + queuePacket( invUpdate ); } bool Core::Entity::Player::tryAddItem( uint16_t catalogId, uint32_t quantity ) @@ -609,14 +602,11 @@ int16_t Core::Entity::Player::addItem( uint16_t inventoryId, int8_t slotId, uint " AND CharacterId = " + std::to_string( getId() ) ); - auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() ); - invUpPacket->data().containerId = inventoryId; - invUpPacket->data().catalogId = catalogId; - invUpPacket->data().quantity = item->getStackSize(); - invUpPacket->data().hqFlag = item->isHq() ? 1 : 0; - invUpPacket->data().slot = rSlotId; - invUpPacket->data().condition = 30000; - queuePacket( invUpPacket ); + auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), + rSlotId, + inventoryId, + *item ); + queuePacket( invUpdate ); if( !silent ) queuePacket( boost::make_shared< ActorControlPacket143 >( getId(), ItemObtainIcon, @@ -851,10 +841,10 @@ uint16_t Core::Entity::Player::calculateEquippedGearItemLevel() uint8_t Core::Entity::Player::getFreeSlotsInBags() { uint8_t slots = 0; - for( uint8_t container : { 0, 1, 2, 3 } ) - { - // TODO: this feels hackish at best - slots += 34 - m_inventoryMap[container]->getEntryCount(); + for( uint8_t container : { Bag0, Bag1, Bag2, Bag3 } ) + { + const auto& storage = m_inventoryMap[container]; + slots += ( storage->getMaxSize() - storage->getEntryCount() ); } return slots; } diff --git a/src/servers/sapphire_zone/Inventory/ItemContainer.cpp b/src/servers/sapphire_zone/Inventory/ItemContainer.cpp index 330c77f7..e9a4d28d 100644 --- a/src/servers/sapphire_zone/Inventory/ItemContainer.cpp +++ b/src/servers/sapphire_zone/Inventory/ItemContainer.cpp @@ -55,12 +55,12 @@ void Core::ItemContainer::removeItem( uint8_t slotId ) } } -Core::ItemMap & Core::ItemContainer::getItemMap() +Core::ItemMap& Core::ItemContainer::getItemMap() { return m_itemMap; } -const Core::ItemMap & Core::ItemContainer::getItemMap() const +const Core::ItemMap& Core::ItemContainer::getItemMap() const { return m_itemMap; } diff --git a/src/servers/sapphire_zone/Network/PacketWrappers/UpdateInventorySlotPacket.h b/src/servers/sapphire_zone/Network/PacketWrappers/UpdateInventorySlotPacket.h new file mode 100644 index 00000000..00a9e31a --- /dev/null +++ b/src/servers/sapphire_zone/Network/PacketWrappers/UpdateInventorySlotPacket.h @@ -0,0 +1,60 @@ +#ifndef _INVENTORY_SLOT_UPDATE_PACKET_H +#define _INVENTORY_SLOT_UPDATE_PACKET_H + +#include +#include "Actor/Player.h" +#include "Inventory/Item.h" +#include "Forwards.h" + +namespace Core { +namespace Network { +namespace Packets { +namespace Server { + +/** +* @brief The update inventory-slot packet. +*/ +class UpdateInventorySlotPacket : + public ZoneChannelPacket< FFXIVIpcUpdateInventorySlot > +{ +public: + UpdateInventorySlotPacket( uint32_t playerId, uint8_t slot, uint16_t storageId, const Item& item ) : + ZoneChannelPacket< FFXIVIpcUpdateInventorySlot >( playerId, playerId ) + { + initialize( slot, storageId, item ); + }; + +private: + void initialize( uint8_t slot, uint16_t storageId, const Item& item ) + { + m_data.sequence = 0; + m_data.containerId = storageId; + m_data.slot = slot; + m_data.quantity = item.getStackSize(); + m_data.catalogId = item.getId(); + m_data.reservedFlag = 0; // no idea + m_data.signatureId = 0; + m_data.hqFlag = item.isHq() ? 1 : 0; + m_data.condition = 60000; // 200% + m_data.spiritBond = 0; + m_data.color = 0; + m_data.glamourCatalogId = 0; + m_data.materia1 = 0; + m_data.materia2 = 0; + m_data.materia3 = 0; + m_data.materia4 = 0; + m_data.materia5 = 0; + //m_data.buffer1; + //uint8_t buffer2; + //uint8_t buffer3; + //uint8_t buffer4; + //uint8_t buffer5; + }; +}; + +} +} +} +} + +#endif /*_MODELEQUIPPACKET_H*/ From 791f934a2dbe9e4019a8e976fcf83d27cf0aa31d Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 26 Jul 2018 23:12:02 +1000 Subject: [PATCH 05/12] fix loading of currency/crystal items --- .../sapphire_zone/Actor/PlayerInventory.cpp | 84 ++++--------------- src/servers/sapphire_zone/Actor/PlayerSql.cpp | 63 +------------- 2 files changed, 20 insertions(+), 127 deletions(-) diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index 23220637..c1161064 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -58,10 +58,10 @@ void Core::Entity::Player::initInventory() setupContainer( GearSet0, 13, "charaitemgearset", true ); // gil contianer - setupContainer( Currency, 11, "charaitemcurrency", false ); + setupContainer( Currency, 11, "charaiteminventory", false ); // crystals?? - setupContainer( Crystal, 11, "charaitemcrystal", false ); + setupContainer( Crystal, 11, "charaiteminventory", false ); // armory weapons - 0 setupContainer( ArmoryMain, 34, "charaiteminventory", true ); @@ -219,20 +219,22 @@ void Core::Entity::Player::unequipItem( Common::EquipSlot equipSlotId, ItemPtr p // TODO: these next functions are so similar that they could likely be simplified void Core::Entity::Player::addCurrency( CurrencyType type, uint32_t amount ) { - auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); + auto slot = static_cast< uint8_t >( static_cast< uint8_t >( type ) - 1 ); + auto currItem = m_inventoryMap[Currency]->getItem( slot ); if( !currItem ) { // TODO: map currency type to itemid currItem = createItem( 1 ); - m_inventoryMap[Currency]->setItem( static_cast< uint8_t >( type ) - 1, currItem ); - updateCurrencyDb(); + m_inventoryMap[Currency]->setItem( slot, currItem ); } uint32_t currentAmount = currItem->getStackSize(); currItem->setStackSize( currentAmount + amount ); updateItemDb( currItem ); + updateContainer( Currency, slot, currItem ); + auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), static_cast< uint8_t >( type ) - 1, Common::InventoryType::Currency, @@ -272,7 +274,6 @@ void Core::Entity::Player::addCrystal( Common::CrystalType type, uint32_t amount // TODO: map currency type to itemid currItem = createItem( static_cast< uint8_t >( type ) + 1 ); m_inventoryMap[Crystal]->setItem( static_cast< uint8_t >( type ) - 1, currItem ); - updateCrystalDb(); } uint32_t currentAmount = currItem->getStackSize(); @@ -281,6 +282,8 @@ void Core::Entity::Player::addCrystal( Common::CrystalType type, uint32_t amount updateItemDb( currItem ); + updateBagDb( Crystal ); + auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), static_cast< uint8_t >( type ) - 1, @@ -435,69 +438,16 @@ uint32_t Core::Entity::Player::getCrystal( CrystalType type ) } -void Core::Entity::Player::updateCurrencyDb() -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - int32_t firstItemPos = -1; - std::string query = "UPDATE charaitemcurrency SET "; - - for( int32_t i = 0; i <= 11; i++ ) - { - auto currItem = m_inventoryMap[Currency]->getItem( i ); - - if( currItem ) - { - if( firstItemPos == -1 ) - firstItemPos = i; - - if( i > firstItemPos ) - query += ", "; - - query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem->getUId() ); - } - } - - query += " WHERE CharacterId = " + std::to_string( getId() ); - - pDb->execute( query ); -} - - -void Core::Entity::Player::updateCrystalDb() -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - int32_t firstItemPos = -1; - std::string query = "UPDATE charaitemcrystal SET "; - - for( int32_t i = 0; i <= 11; i++ ) - { - auto currItem = m_inventoryMap[Crystal]->getItem( i ); - - if( currItem ) - { - if( firstItemPos == -1 ) - firstItemPos = i; - - if( i > firstItemPos ) - query += ", "; - - query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem->getUId() ); - } - } - - query += " WHERE CharacterId = " + std::to_string( getId() ); - - pDb->execute( query ); -} - void Core::Entity::Player::updateBagDb( InventoryType type ) { auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); std::string query = "UPDATE charaiteminventory SET "; - for( int32_t i = 0; i <= 34; i++ ) + auto container = m_inventoryMap[type]; + + for( int32_t i = 0; i <= container->getMaxSize(); i++ ) { - auto currItem = m_inventoryMap[type]->getItem( i ); + auto currItem = container->getItem( i ); if( i > 0 ) query += ", "; @@ -518,9 +468,11 @@ void Core::Entity::Player::updateMannequinDb( InventoryType type ) auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); std::string query = "UPDATE charaitemgearset SET "; - for( int32_t i = 0; i <= 13; i++ ) + auto container = m_inventoryMap[type]; + + for( int32_t i = 0; i <= container->getMaxSize(); i++ ) { - auto currItem = m_inventoryMap[type]->getItem( i ); + auto currItem = container->getItem( i ); if( i > 0 ) query += ", "; @@ -661,8 +613,8 @@ bool Core::Entity::Player::updateContainer( uint16_t containerId, uint8_t slotId switch( containerType ) { case Armory: - case CurrencyCrystal: case Bag: + case CurrencyCrystal: { updateBagDb( static_cast< InventoryType >( containerId ) ); break; diff --git a/src/servers/sapphire_zone/Actor/PlayerSql.cpp b/src/servers/sapphire_zone/Actor/PlayerSql.cpp index bed620ca..98d897de 100644 --- a/src/servers/sapphire_zone/Actor/PlayerSql.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerSql.cpp @@ -627,7 +627,7 @@ bool Core::Entity::Player::loadInventory() } /////////////////////////////////////////////////////////////////////////////////////////////////////// - // Load Bags + // Load everything auto bagRes = pDb->query( "SELECT storageId, " "container_0, container_1, container_2, container_3, container_4, " "container_5, container_6, container_7, container_8, container_9, " @@ -643,7 +643,7 @@ bool Core::Entity::Player::loadInventory() while( bagRes->next() ) { uint16_t storageId = bagRes->getUInt16( 1 ); - for( uint32_t i = 1; i <= 35; i++ ) + for( uint32_t i = 1; i <= m_inventoryMap[storageId]->getMaxSize(); i++ ) { uint64_t uItemId = bagRes->getUInt64( i + 1 ); if( uItemId == 0 ) @@ -658,64 +658,5 @@ bool Core::Entity::Player::loadInventory() } } - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - // Load Currency - auto curRes = pDb->query( "SELECT storageId, " - "container_0, container_1, container_2, container_3, container_4, " - "container_5, container_6, container_7, container_8, container_9, " - "container_10, container_11 " - "FROM charaitemcurrency " \ - "WHERE CharacterId = " + std::to_string( getId() ) + " " \ - "ORDER BY storageId ASC;" ); - - while( curRes->next() ) - { - uint16_t storageId = curRes->getUInt16( 1 ); - for( uint32_t i = 1; i <= 12; i++ ) - { - uint64_t uItemId = curRes->getUInt64( i + 1 ); - if( uItemId == 0 ) - continue; - - ItemPtr pItem = Items::Util::loadItem( uItemId ); - - if( pItem == nullptr ) - continue; - - m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; - } - } - - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - // Load Crystals - auto crystalRes = pDb->query( "SELECT storageId, " - "container_0, container_1, container_2, container_3, container_4, " - "container_5, container_6, container_7, container_8, container_9, " - "container_10, container_11, container_12, container_13, container_14, " - "container_15, container_16, container_17 " - "FROM charaitemcrystal " \ - "WHERE CharacterId = " + std::to_string( getId() ) + " " \ - "ORDER BY storageId ASC;" ); - - while( crystalRes->next() ) - { - uint16_t storageId = crystalRes->getUInt16( 1 ); - for( int32_t i = 1; i <= 17; i++ ) - { - uint64_t uItemId = crystalRes->getUInt64( i + 1 ); - if( uItemId == 0 ) - continue; - - ItemPtr pItem = Items::Util::loadItem( uItemId ); - - if( pItem == nullptr ) - continue; - - m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; - } - } - return true; } From 2bcc2b713fc7f75191986b084b779e50c7c1502f Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 26 Jul 2018 23:12:30 +1000 Subject: [PATCH 06/12] remove now unused sql tables --- sql/charaitemcrystal.sql | 74 --------------------------------------- sql/charaitemcurrency.sql | 68 ----------------------------------- 2 files changed, 142 deletions(-) delete mode 100644 sql/charaitemcrystal.sql delete mode 100644 sql/charaitemcurrency.sql diff --git a/sql/charaitemcrystal.sql b/sql/charaitemcrystal.sql deleted file mode 100644 index 1f9c2d57..00000000 --- a/sql/charaitemcrystal.sql +++ /dev/null @@ -1,74 +0,0 @@ --- MySQL dump 10.13 Distrib 5.7.13, for Win64 (x86_64) --- --- Host: localhost Database: sapphire --- ------------------------------------------------------ --- Server version 5.7.13-log - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `charaitemcrystal` --- - -DROP TABLE IF EXISTS `charaitemcrystal`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `charaitemcrystal` ( - `CharacterId` int(20) DEFAULT '0', - `storageId` int(10) DEFAULT '2001', - `type` int(5) DEFAULT '0', - `idx` int(5) NOT NULL AUTO_INCREMENT, - `container_0` int(20) DEFAULT '0', - `container_1` int(20) DEFAULT '0', - `container_2` int(20) DEFAULT '0', - `container_3` int(20) DEFAULT '0', - `container_4` int(20) DEFAULT '0', - `container_5` int(20) DEFAULT '0', - `container_6` int(20) DEFAULT '0', - `container_7` int(20) DEFAULT '0', - `container_8` int(20) DEFAULT '0', - `container_9` int(20) DEFAULT '0', - `container_10` int(20) DEFAULT '0', - `container_11` int(20) DEFAULT '0', - `container_12` int(20) DEFAULT '0', - `container_13` int(20) DEFAULT '0', - `container_14` int(20) DEFAULT '0', - `container_15` int(20) DEFAULT '0', - `container_16` int(20) DEFAULT '0', - `container_17` int(20) DEFAULT '0', - `IS_DELETE` int(3) DEFAULT '0', - `IS_NOT_ACTIVE_FLG` int(3) DEFAULT '0', - `UPDATE_DATE` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`idx`), - KEY `CharacterId` (`CharacterId`) -) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `charaitemcrystal` --- - -LOCK TABLES `charaitemcrystal` WRITE; -/*!40000 ALTER TABLE `charaitemcrystal` DISABLE KEYS */; -/*!40000 ALTER TABLE `charaitemcrystal` ENABLE KEYS */; -UNLOCK TABLES; -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2016-12-09 17:37:10 diff --git a/sql/charaitemcurrency.sql b/sql/charaitemcurrency.sql deleted file mode 100644 index 681dc036..00000000 --- a/sql/charaitemcurrency.sql +++ /dev/null @@ -1,68 +0,0 @@ --- MySQL dump 10.13 Distrib 5.7.13, for Win64 (x86_64) --- --- Host: localhost Database: sapphire --- ------------------------------------------------------ --- Server version 5.7.13-log - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `charaitemcurrency` --- - -DROP TABLE IF EXISTS `charaitemcurrency`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `charaitemcurrency` ( - `CharacterId` int(20) NOT NULL, - `storageId` int(10) DEFAULT '2000', - `type` int(5) DEFAULT '0', - `idx` int(5) NOT NULL AUTO_INCREMENT, - `container_0` int(20) DEFAULT '0', - `container_1` int(20) DEFAULT '0', - `container_2` int(20) DEFAULT '0', - `container_3` int(20) DEFAULT '0', - `container_4` int(20) DEFAULT '0', - `container_5` int(20) DEFAULT '0', - `container_6` int(20) DEFAULT '0', - `container_7` int(20) DEFAULT '0', - `container_8` int(20) NOT NULL DEFAULT '0', - `container_9` int(20) NOT NULL DEFAULT '0', - `container_10` int(20) NOT NULL DEFAULT '0', - `container_11` int(20) NOT NULL DEFAULT '0', - `IS_DELETE` int(3) DEFAULT '0', - `IS_NOT_ACTIVE_FLG` int(3) DEFAULT '0', - `UPDATE_DATE` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`idx`), - UNIQUE KEY `CharacterId` (`CharacterId`) -) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `charaitemcurrency` --- - -LOCK TABLES `charaitemcurrency` WRITE; -/*!40000 ALTER TABLE `charaitemcurrency` DISABLE KEYS */; -/*!40000 ALTER TABLE `charaitemcurrency` ENABLE KEYS */; -UNLOCK TABLES; -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2016-12-09 17:37:11 From cf661c57dfc553200aa5bde7ac19f12b94869e6e Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 26 Jul 2018 23:17:39 +1000 Subject: [PATCH 07/12] fix CurrencyCrystalInfo opcode --- src/common/Network/PacketDef/Ipcs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index d8010c37..435fc172 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -130,8 +130,8 @@ namespace Packets { ContainerInfo = 0x0192, // updated 4.3 InventoryTransactionFinish = 0x0193, // updated 4.3 InventoryTransaction = 0x0194, // updated 4.3 + CurrencyCrystalInfo = 0x0195, // updated 4.3 InventoryActionAck = 0x0197, // updated 4.3 - CurrencyCrystalInfo = 0xFFFF, // updated 4.3 - wrong opcode UpdateInventorySlot = 0x0198, // updated 4.3 From 438592312907520b4865ede37e43d2387adc1095 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 26 Jul 2018 23:21:57 +1000 Subject: [PATCH 08/12] currency and crystal are now multistorage containers --- src/servers/sapphire_zone/Actor/PlayerInventory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index c1161064..bc1f2313 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -58,10 +58,10 @@ void Core::Entity::Player::initInventory() setupContainer( GearSet0, 13, "charaitemgearset", true ); // gil contianer - setupContainer( Currency, 11, "charaiteminventory", false ); + setupContainer( Currency, 11, "charaiteminventory", true ); // crystals?? - setupContainer( Crystal, 11, "charaiteminventory", false ); + setupContainer( Crystal, 11, "charaiteminventory", true ); // armory weapons - 0 setupContainer( ArmoryMain, 34, "charaiteminventory", true ); From 47f86e13c72bc2576a16331efb487a41316728b7 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 26 Jul 2018 23:29:58 +1000 Subject: [PATCH 09/12] improve behaviour for creating items with correct max stack sizes --- src/servers/sapphire_zone/Actor/PlayerSql.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/servers/sapphire_zone/Actor/PlayerSql.cpp b/src/servers/sapphire_zone/Actor/PlayerSql.cpp index 98d897de..04a3d900 100644 --- a/src/servers/sapphire_zone/Actor/PlayerSql.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerSql.cpp @@ -566,10 +566,7 @@ Core::ItemPtr Core::Entity::Player::createItem( uint32_t catalogId, uint16_t qua if( !itemInfo ) return nullptr; - uint16_t itemAmount = quantity; - - if( itemInfo->stackSize == 1 ) - itemAmount = 1; + auto itemAmount = std::min< uint16_t >( quantity, static_cast< uint16_t >( itemInfo->stackSize ) ); if( !itemInfo ) return nullptr; From 460d4c79b7ec43b3796de67ef7642a101017f7c9 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 26 Jul 2018 23:37:12 +1000 Subject: [PATCH 10/12] the last commit was shit, now it's done properly --- src/servers/sapphire_zone/Actor/Player.h | 5 +---- src/servers/sapphire_zone/Actor/PlayerSql.cpp | 8 +++----- src/servers/sapphire_zone/Inventory/Item.cpp | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/servers/sapphire_zone/Actor/Player.h b/src/servers/sapphire_zone/Actor/Player.h index cce73edb..6b204d3e 100644 --- a/src/servers/sapphire_zone/Actor/Player.h +++ b/src/servers/sapphire_zone/Actor/Player.h @@ -605,7 +605,7 @@ public: using InvSlotPair = std::pair< uint16_t, int8_t >; using InvSlotPairVec = std::vector< InvSlotPair >; - ItemPtr createItem( uint32_t catalogId, uint16_t quantity = 1 ); + ItemPtr createItem( uint32_t catalogId, uint32_t quantity = 1 ); bool loadInventory(); InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId ); InvSlotPair getFreeBagSlot(); @@ -625,7 +625,6 @@ public: /*! return the current amount of currency of type */ uint32_t getCurrency( Common::CurrencyType type ); - void updateCurrencyDb(); void updateBagDb( Common::InventoryType type ); void updateMannequinDb( Common::InventoryType type ); void updateItemDb( ItemPtr pItem ) const; @@ -639,8 +638,6 @@ public: void removeCrystal( Common::CrystalType type, uint32_t amount ); bool isObtainable( uint32_t catalogId, uint8_t quantity ); - void updateCrystalDb(); - void send(); uint8_t getFreeSlotsInBags(); diff --git a/src/servers/sapphire_zone/Actor/PlayerSql.cpp b/src/servers/sapphire_zone/Actor/PlayerSql.cpp index 04a3d900..e72c0b7f 100644 --- a/src/servers/sapphire_zone/Actor/PlayerSql.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerSql.cpp @@ -557,7 +557,7 @@ void Core::Entity::Player::insertQuest( uint16_t questId, uint8_t index, uint8_t pDb->execute( stmt ); } -Core::ItemPtr Core::Entity::Player::createItem( uint32_t catalogId, uint16_t quantity ) +Core::ItemPtr Core::Entity::Player::createItem( uint32_t catalogId, uint32_t quantity ) { auto pExdData = g_fw.get< Data::ExdDataGenerated >(); auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); @@ -566,8 +566,6 @@ Core::ItemPtr Core::Entity::Player::createItem( uint32_t catalogId, uint16_t qua if( !itemInfo ) return nullptr; - auto itemAmount = std::min< uint16_t >( quantity, static_cast< uint16_t >( itemInfo->stackSize ) ); - if( !itemInfo ) return nullptr; @@ -578,13 +576,13 @@ Core::ItemPtr Core::Entity::Player::createItem( uint32_t catalogId, uint16_t qua itemInfo->modelMain, itemInfo->modelSub ); - pItem->setStackSize( itemAmount ); + pItem->setStackSize( quantity ); pDb->execute( "INSERT INTO charaglobalitem ( CharacterId, itemId, catalogId, stack, flags ) VALUES ( " + std::to_string( getId() ) + ", " + std::to_string( pItem->getUId() ) + ", " + std::to_string( pItem->getId() ) + ", " + - std::to_string( itemAmount ) + ", " + + std::to_string( quantity ) + ", " + std::to_string( flags ) + ");" ); return pItem; diff --git a/src/servers/sapphire_zone/Inventory/Item.cpp b/src/servers/sapphire_zone/Inventory/Item.cpp index e16a294a..cf959296 100644 --- a/src/servers/sapphire_zone/Inventory/Item.cpp +++ b/src/servers/sapphire_zone/Inventory/Item.cpp @@ -84,7 +84,7 @@ void Core::Item::setUId( uint64_t id ) void Core::Item::setStackSize( uint32_t size ) { - m_stackSize = size; + m_stackSize = std::min< uint32_t >( size, m_maxStackSize ); } uint32_t Core::Item::getStackSize() const From d8afc7a83ec8492a92c477dab9a50f0c8f35f410 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 26 Jul 2018 23:38:58 +1000 Subject: [PATCH 11/12] remove a 2nd space in //gm gil output --- .../sapphire_zone/Network/Handlers/GMCommandHandlers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp index 7a05e469..f009e69d 100644 --- a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp @@ -330,7 +330,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_R case GmCommand::Gil: { targetPlayer->addCurrency( CurrencyType::Gil, param1 ); - player.sendNotice( "Added " + std::to_string( param1 ) + " Gil for " + targetPlayer->getName() ); + player.sendNotice( "Added " + std::to_string( param1 ) + " Gil for " + targetPlayer->getName() ); break; } case GmCommand::Collect: From 2f814ca60ec456319765d2fea796676a50372757 Mon Sep 17 00:00:00 2001 From: Mordred Date: Thu, 26 Jul 2018 23:40:46 +0200 Subject: [PATCH 12/12] Inventory Overhaul wrapup --- src/servers/sapphire_zone/Actor/Player.h | 10 +- .../sapphire_zone/Actor/PlayerInventory.cpp | 149 +++++++----------- src/servers/sapphire_zone/Actor/PlayerSql.cpp | 6 +- 3 files changed, 68 insertions(+), 97 deletions(-) diff --git a/src/servers/sapphire_zone/Actor/Player.h b/src/servers/sapphire_zone/Actor/Player.h index 6b204d3e..7fa9677a 100644 --- a/src/servers/sapphire_zone/Actor/Player.h +++ b/src/servers/sapphire_zone/Actor/Player.h @@ -618,16 +618,15 @@ public: ItemPtr getItemAt( uint16_t containerId, uint8_t slotId ); - bool updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem ); + bool updateContainer( uint16_t storageId, uint8_t slotId, ItemPtr pItem ); /*! calculate and return player ilvl based off equipped gear */ uint16_t calculateEquippedGearItemLevel(); /*! return the current amount of currency of type */ uint32_t getCurrency( Common::CurrencyType type ); - void updateBagDb( Common::InventoryType type ); - void updateMannequinDb( Common::InventoryType type ); - void updateItemDb( ItemPtr pItem ) const; + void writeInventory( Common::InventoryType type ); + void writeItem( ItemPtr pItem ) const; void deleteItemDb( ItemPtr pItem ) const; /*! return the crystal amount of currency of type */ @@ -645,7 +644,6 @@ public: ////////////////////////////////////////////////////////////////////////////////////////////////////// uint64_t m_lastMoveTime; - uint8_t m_lastMoveflag; private: @@ -667,7 +665,7 @@ private: private: using InventoryMap = std::map< uint16_t, Core::ItemContainerPtr >; - InventoryMap m_inventoryMap; + InventoryMap m_storageMap; Common::FFXIVARR_POSITION3 m_prevPos; uint32_t m_prevZoneType; diff --git a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp index bc1f2313..6ae062ad 100644 --- a/src/servers/sapphire_zone/Actor/PlayerInventory.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerInventory.cpp @@ -46,7 +46,7 @@ using namespace Core::Network::ActorControl; void Core::Entity::Player::initInventory() { auto setupContainer = [this]( InventoryType type, uint8_t maxSize, const std::string& tableName, bool isMultiStorage ) - { m_inventoryMap[type] = make_ItemContainer( type, maxSize, tableName, isMultiStorage ); }; + { m_storageMap[type] = make_ItemContainer( type, maxSize, tableName, isMultiStorage ); }; // main bags setupContainer( Bag0, 34, "charaiteminventory", true ); @@ -220,18 +220,18 @@ void Core::Entity::Player::unequipItem( Common::EquipSlot equipSlotId, ItemPtr p void Core::Entity::Player::addCurrency( CurrencyType type, uint32_t amount ) { auto slot = static_cast< uint8_t >( static_cast< uint8_t >( type ) - 1 ); - auto currItem = m_inventoryMap[Currency]->getItem( slot ); + auto currItem = m_storageMap[Currency]->getItem( slot ); if( !currItem ) { // TODO: map currency type to itemid currItem = createItem( 1 ); - m_inventoryMap[Currency]->setItem( slot, currItem ); + m_storageMap[Currency]->setItem( slot, currItem ); } uint32_t currentAmount = currItem->getStackSize(); currItem->setStackSize( currentAmount + amount ); - updateItemDb( currItem ); + writeItem(currItem); updateContainer( Currency, slot, currItem ); @@ -245,7 +245,7 @@ void Core::Entity::Player::addCurrency( CurrencyType type, uint32_t amount ) void Core::Entity::Player::removeCurrency( Common::CurrencyType type, uint32_t amount ) { - auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); + auto currItem = m_storageMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); if( !currItem ) return; @@ -255,7 +255,7 @@ void Core::Entity::Player::removeCurrency( Common::CurrencyType type, uint32_t a currItem->setStackSize( 0 ); else currItem->setStackSize( currentAmount - amount ); - updateItemDb( currItem ); + writeItem(currItem); auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), static_cast< uint8_t >( type ) - 1, @@ -267,22 +267,22 @@ void Core::Entity::Player::removeCurrency( Common::CurrencyType type, uint32_t a void Core::Entity::Player::addCrystal( Common::CrystalType type, uint32_t amount ) { - auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); + auto currItem = m_storageMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); if( !currItem ) { // TODO: map currency type to itemid currItem = createItem( static_cast< uint8_t >( type ) + 1 ); - m_inventoryMap[Crystal]->setItem( static_cast< uint8_t >( type ) - 1, currItem ); + m_storageMap[Crystal]->setItem( static_cast< uint8_t >( type ) - 1, currItem ); } uint32_t currentAmount = currItem->getStackSize(); currItem->setStackSize( currentAmount + amount ); - updateItemDb( currItem ); + writeItem(currItem); - updateBagDb( Crystal ); + writeInventory( Crystal ); auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), @@ -296,7 +296,7 @@ void Core::Entity::Player::addCrystal( Common::CrystalType type, uint32_t amount void Core::Entity::Player::removeCrystal( Common::CrystalType type, uint32_t amount ) { - auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); + auto currItem = m_storageMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); if( !currItem ) return; @@ -307,7 +307,7 @@ void Core::Entity::Player::removeCrystal( Common::CrystalType type, uint32_t amo else currItem->setStackSize( currentAmount - amount ); - updateItemDb( currItem ); + writeItem(currItem); auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), static_cast< uint8_t >( type ) - 1, @@ -332,7 +332,7 @@ void Core::Entity::Player::sendInventory() InventoryMap::iterator it; int32_t count = 0; - for( it = m_inventoryMap.begin(); it != m_inventoryMap.end(); ++it, count++ ) + for( it = m_storageMap.begin(); it != m_storageMap.end(); ++it, count++ ) { auto pMap = it->second->getItemMap(); @@ -385,7 +385,7 @@ Core::Entity::Player::InvSlotPairVec Core::Entity::Player::getSlotsOfItemsInInve InvSlotPairVec outVec; for( auto i : { Bag0, Bag1, Bag2, Bag3 } ) { - auto inv = m_inventoryMap[i]; + auto inv = m_storageMap[i]; for( auto item : inv->getItemMap() ) { if( item.second && item.second->getId() == catalogId ) @@ -399,7 +399,7 @@ Core::Entity::Player::InvSlotPair Core::Entity::Player::getFreeBagSlot() { for( auto i : { Bag0, Bag1, Bag2, Bag3 } ) { - auto freeSlot = static_cast< int8_t >( m_inventoryMap[i]->getFreeSlot() ); + auto freeSlot = static_cast< int8_t >( m_storageMap[i]->getFreeSlot() ); if( freeSlot != -1 ) return std::make_pair( i, freeSlot ); @@ -410,14 +410,14 @@ Core::Entity::Player::InvSlotPair Core::Entity::Player::getFreeBagSlot() Core::ItemPtr Core::Entity::Player::getItemAt( uint16_t containerId, uint8_t slotId ) { - return m_inventoryMap[containerId]->getItem( slotId ); + return m_storageMap[containerId]->getItem( slotId ); } uint32_t Core::Entity::Player::getCurrency( CurrencyType type ) { - auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); + auto currItem = m_storageMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 ); if( !currItem ) return 0; @@ -429,7 +429,7 @@ uint32_t Core::Entity::Player::getCurrency( CurrencyType type ) uint32_t Core::Entity::Player::getCrystal( CrystalType type ) { - auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); + auto currItem = m_storageMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 ); if( !currItem ) return 0; @@ -438,41 +438,18 @@ uint32_t Core::Entity::Player::getCrystal( CrystalType type ) } -void Core::Entity::Player::updateBagDb( InventoryType type ) -{ - auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - std::string query = "UPDATE charaiteminventory SET "; - - auto container = m_inventoryMap[type]; - - for( int32_t i = 0; i <= container->getMaxSize(); i++ ) - { - auto currItem = container->getItem( i ); - - if( i > 0 ) - query += ", "; - - query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem ? currItem->getUId() : 0 ); - } - - query += " WHERE CharacterId = " + std::to_string( getId() ) + - " AND storageId = " + std::to_string( static_cast< uint16_t >( type ) ); - - pDb->execute( query ); -} - - -void Core::Entity::Player::updateMannequinDb( InventoryType type ) +void Core::Entity::Player::writeInventory( InventoryType type ) { auto pLog = g_fw.get< Logger >(); auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); - std::string query = "UPDATE charaitemgearset SET "; - auto container = m_inventoryMap[type]; + auto storage = m_storageMap[type]; - for( int32_t i = 0; i <= container->getMaxSize(); i++ ) + std::string query = "UPDATE " + storage->getTableName() + " SET "; + + for( int32_t i = 0; i <= storage->getMaxSize(); i++ ) { - auto currItem = container->getItem( i ); + auto currItem = storage->getItem( i ); if( i > 0 ) query += ", "; @@ -480,15 +457,16 @@ void Core::Entity::Player::updateMannequinDb( InventoryType type ) query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem ? currItem->getUId() : 0 ); } - query += " WHERE CharacterId = " + std::to_string( getId() ) + - " AND storageId = " + std::to_string( static_cast< uint16_t >( type ) ); + query += " WHERE CharacterId = " + std::to_string( getId() ); + + if( storage->isMultiStorage() ) + query += " AND storageId = " + std::to_string( static_cast< uint16_t >( type ) ); pLog->debug( query ); pDb->execute( query ); } - -void Core::Entity::Player::updateItemDb( Core::ItemPtr pItem ) const +void Core::Entity::Player::writeItem( Core::ItemPtr pItem ) const { auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >(); pDb->execute( "UPDATE charaglobalitem SET stack = " + std::to_string( pItem->getStackSize() ) + " " + @@ -547,9 +525,11 @@ int16_t Core::Entity::Player::addItem( uint16_t inventoryId, int8_t slotId, uint if( rSlotId != -1 ) { - m_inventoryMap[inventoryId]->setItem( rSlotId, item ); + auto storage = m_storageMap[inventoryId]; + storage->setItem( rSlotId, item ); - pDb->execute( "UPDATE charaiteminventory SET container_" + std::to_string( rSlotId ) + " = " + std::to_string( item->getUId() ) + + pDb->execute( "UPDATE " + storage->getTableName() + " SET container_" + + std::to_string( rSlotId ) + " = " + std::to_string( item->getUId() ) + " WHERE storageId = " + std::to_string( inventoryId ) + " AND CharacterId = " + std::to_string( getId() ) ); @@ -573,42 +553,35 @@ int16_t Core::Entity::Player::addItem( uint16_t inventoryId, int8_t slotId, uint void Core::Entity::Player::moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ) { - auto tmpItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); - auto& itemMap = m_inventoryMap[fromInventoryId]->getItemMap(); + auto tmpItem = m_storageMap[fromInventoryId]->getItem( fromSlotId ); + auto& itemMap = m_storageMap[fromInventoryId]->getItemMap(); if( tmpItem == nullptr ) return; itemMap[fromSlotId].reset(); - m_inventoryMap[toInventoryId]->setItem( toSlot, tmpItem ); + m_storageMap[toInventoryId]->setItem( toSlot, tmpItem ); - if( toInventoryId != GearSet0 ) - updateBagDb( static_cast< InventoryType >( toInventoryId ) ); + writeInventory( static_cast< InventoryType >( toInventoryId ) ); - if( fromInventoryId != GearSet0 && fromInventoryId != toInventoryId ) - updateBagDb( static_cast< InventoryType >( fromInventoryId ) ); + if( fromInventoryId != toInventoryId ) + writeInventory( static_cast< InventoryType >( fromInventoryId ) ); if( static_cast< InventoryType >( toInventoryId ) == GearSet0 ) - { equipItem( static_cast< EquipSlot >( toSlot ), tmpItem, true ); - updateMannequinDb( static_cast< InventoryType >( toInventoryId ) ); - } if( static_cast< InventoryType >( fromInventoryId ) == GearSet0 ) - { unequipItem( static_cast< EquipSlot >( fromSlotId ), tmpItem ); - updateMannequinDb( static_cast< InventoryType >( fromInventoryId ) ); - } } -bool Core::Entity::Player::updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem ) +bool Core::Entity::Player::updateContainer( uint16_t storageId, uint8_t slotId, ItemPtr pItem ) { - auto containerType = Items::Util::getContainerType( containerId ); + auto containerType = Items::Util::getContainerType( storageId ); - m_inventoryMap[containerId]->setItem( slotId, pItem ); + m_storageMap[storageId]->setItem( slotId, pItem ); switch( containerType ) { @@ -616,7 +589,7 @@ bool Core::Entity::Player::updateContainer( uint16_t containerId, uint8_t slotId case Bag: case CurrencyCrystal: { - updateBagDb( static_cast< InventoryType >( containerId ) ); + writeInventory( static_cast< InventoryType >( storageId ) ); break; } @@ -627,7 +600,7 @@ bool Core::Entity::Player::updateContainer( uint16_t containerId, uint8_t slotId else unequipItem( static_cast< EquipSlot >( slotId ), pItem ); - updateMannequinDb( static_cast< InventoryType >( containerId ) ); + writeInventory( static_cast< InventoryType >( storageId ) ); break; } default: @@ -640,7 +613,7 @@ bool Core::Entity::Player::updateContainer( uint16_t containerId, uint8_t slotId void Core::Entity::Player::splitItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot, uint16_t itemCount ) { - auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); + auto fromItem = m_storageMap[fromInventoryId]->getItem( fromSlotId ); if( !fromItem ) return; @@ -651,7 +624,7 @@ void Core::Entity::Player::splitItem( uint16_t fromInventoryId, uint8_t fromSlot return; // make sure toInventoryId & toSlot are actually free so we don't orphan an item - if( m_inventoryMap[toInventoryId]->getItem( toSlot ) ) + if( m_storageMap[toInventoryId]->getItem( toSlot ) ) // todo: correct invalid move? again, not sure what retail does here return; @@ -659,21 +632,21 @@ void Core::Entity::Player::splitItem( uint16_t fromInventoryId, uint8_t fromSlot if( newSlot == -1 ) return; - auto newItem = m_inventoryMap[toInventoryId]->getItem( static_cast< uint8_t >( newSlot ) ); + auto newItem = m_storageMap[toInventoryId]->getItem( static_cast< uint8_t >( newSlot ) ); fromItem->setStackSize( fromItem->getStackSize() - itemCount ); updateContainer( fromInventoryId, fromSlotId, fromItem ); updateContainer( toInventoryId, toSlot, newItem ); - updateItemDb( fromItem ); + writeItem(fromItem); } void Core::Entity::Player::mergeItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ) { - auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); - auto toItem = m_inventoryMap[toInventoryId]->getItem( toSlot ); + auto fromItem = m_storageMap[fromInventoryId]->getItem( fromSlotId ); + auto toItem = m_storageMap[toInventoryId]->getItem( toSlot ); if( !fromItem || !toItem ) return; @@ -687,18 +660,18 @@ void Core::Entity::Player::mergeItem( uint16_t fromInventoryId, uint8_t fromSlot // we can destroy the original stack if there's no overflow if( stackOverflow == 0 ) { - m_inventoryMap[fromInventoryId]->removeItem( fromSlotId ); + m_storageMap[fromInventoryId]->removeItem( fromSlotId ); deleteItemDb( fromItem ); } else { fromItem->setStackSize( stackOverflow ); - updateItemDb( fromItem ); + writeItem(fromItem); } toItem->setStackSize( stackSize ); - updateItemDb( toItem ); + writeItem(toItem); updateContainer( fromInventoryId, fromSlotId, fromItem ); updateContainer( toInventoryId, toSlot, toItem ); @@ -707,9 +680,9 @@ void Core::Entity::Player::mergeItem( uint16_t fromInventoryId, uint8_t fromSlot void Core::Entity::Player::swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot ) { - auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); - auto toItem = m_inventoryMap[toInventoryId]->getItem( toSlot ); - auto& itemMap = m_inventoryMap[fromInventoryId]->getItemMap(); + auto fromItem = m_storageMap[fromInventoryId]->getItem( fromSlotId ); + auto toItem = m_storageMap[toInventoryId]->getItem( toSlot ); + auto& itemMap = m_storageMap[fromInventoryId]->getItemMap(); if( fromItem == nullptr || toItem == nullptr ) return; @@ -722,7 +695,7 @@ void Core::Entity::Player::swapItem( uint16_t fromInventoryId, uint8_t fromSlotI { updateContainer( fromInventoryId, fromSlotId, nullptr ); fromInventoryId = Items::Util::getArmoryToEquipSlot( toSlot ); - fromSlotId = static_cast < uint8_t >( m_inventoryMap[fromInventoryId]->getFreeSlot() ); + fromSlotId = static_cast < uint8_t >( m_storageMap[fromInventoryId]->getFreeSlot() ); } auto containerTypeFrom = Items::Util::getContainerType( fromInventoryId ); @@ -737,11 +710,11 @@ void Core::Entity::Player::discardItem( uint16_t fromInventoryId, uint8_t fromSl // i am not entirely sure how this should be generated or if it even is important for us... uint32_t transactionId = 1; - auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId ); + auto fromItem = m_storageMap[fromInventoryId]->getItem( fromSlotId ); deleteItemDb( fromItem ); - m_inventoryMap[fromInventoryId]->removeItem( fromSlotId ); + m_storageMap[fromInventoryId]->removeItem( fromSlotId ); updateContainer( fromInventoryId, fromSlotId, nullptr ); auto invTransPacket = makeZonePacket< FFXIVIpcInventoryTransaction >( getId() ); @@ -764,7 +737,7 @@ uint16_t Core::Entity::Player::calculateEquippedGearItemLevel() { uint32_t iLvlResult = 0; - auto gearSetMap = m_inventoryMap[GearSet0]->getItemMap(); + auto gearSetMap = m_storageMap[GearSet0]->getItemMap(); auto it = gearSetMap.begin(); @@ -795,7 +768,7 @@ uint8_t Core::Entity::Player::getFreeSlotsInBags() uint8_t slots = 0; for( uint8_t container : { Bag0, Bag1, Bag2, Bag3 } ) { - const auto& storage = m_inventoryMap[container]; + const auto& storage = m_storageMap[container]; slots += ( storage->getMaxSize() - storage->getEntryCount() ); } return slots; diff --git a/src/servers/sapphire_zone/Actor/PlayerSql.cpp b/src/servers/sapphire_zone/Actor/PlayerSql.cpp index e72c0b7f..f87a2fc5 100644 --- a/src/servers/sapphire_zone/Actor/PlayerSql.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerSql.cpp @@ -616,7 +616,7 @@ bool Core::Entity::Player::loadInventory() if( pItem == nullptr ) continue; - m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; + m_storageMap[storageId]->getItemMap()[i - 1] = pItem; equipItem( static_cast< EquipSlot >( i - 1 ), pItem, false ); } } @@ -638,7 +638,7 @@ bool Core::Entity::Player::loadInventory() while( bagRes->next() ) { uint16_t storageId = bagRes->getUInt16( 1 ); - for( uint32_t i = 1; i <= m_inventoryMap[storageId]->getMaxSize(); i++ ) + for( uint32_t i = 1; i <= m_storageMap[storageId]->getMaxSize(); i++ ) { uint64_t uItemId = bagRes->getUInt64( i + 1 ); if( uItemId == 0 ) @@ -649,7 +649,7 @@ bool Core::Entity::Player::loadInventory() if( pItem == nullptr ) continue; - m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem; + m_storageMap[storageId]->getItemMap()[i - 1] = pItem; } }