From c03968b1949b92ccb437b5c32ffe54e1d752bfec Mon Sep 17 00:00:00 2001 From: Rushi <44952533+Skyliegirl33@users.noreply.github.com> Date: Fri, 18 Feb 2022 02:24:18 +0100 Subject: [PATCH] WIP: Implement gearset handler --- .../Network/PacketDef/Zone/ClientZoneDef.h | 7 +++ src/world/Actor/Player.h | 2 + src/world/Actor/PlayerInventory.cpp | 19 +++++- src/world/Inventory/Item.cpp | 6 ++ src/world/Inventory/Item.h | 3 + src/world/Network/GameConnection.cpp | 3 + src/world/Network/GameConnection.h | 2 + src/world/Network/Handlers/PacketHandlers.cpp | 61 +++++++++++++++++++ .../UpdateInventorySlotPacket.h | 15 +++++ 9 files changed, 115 insertions(+), 3 deletions(-) diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 8826e50c..ef57c377 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -587,6 +587,13 @@ struct FFXIVIpcCatalogSearch : FFXIVIpcBasePacket< CatalogSearch > char ItemName[121]; }; +struct FFXIVIpcGearSetEquip : FFXIVIpcBasePacket< GearSetEquip > +{ + uint32_t contextId; + uint16_t storageId[14]; + int16_t containerIndex[14]; +}; + struct FFXIVIpcMarketBoardRequestItemListingInfo : FFXIVIpcBasePacket< MarketBoardRequestItemListingInfo > { /* 0000 */ uint32_t catalogId; diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 02d0db58..c5f05dfe 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -705,6 +705,8 @@ namespace Sapphire::Entity InvSlotPair getFreeBagSlot(); + InvSlotPair getFreeContainerSlot( uint32_t containerId ); + ItemPtr addItem( uint32_t catalogId, uint32_t quantity = 1, bool isHq = false, bool slient = false, bool canMerge = true ); void moveItem( uint16_t fromInventoryId, uint16_t fromSlotId, uint16_t toInventoryId, uint16_t toSlot ); diff --git a/src/world/Actor/PlayerInventory.cpp b/src/world/Actor/PlayerInventory.cpp index b1112d47..75f8b59d 100644 --- a/src/world/Actor/PlayerInventory.cpp +++ b/src/world/Actor/PlayerInventory.cpp @@ -472,6 +472,17 @@ Sapphire::Entity::Player::InvSlotPair Sapphire::Entity::Player::getFreeBagSlot() return std::make_pair( 0, -1 ); } +Sapphire::Entity::Player::InvSlotPair Sapphire::Entity::Player::getFreeContainerSlot( uint32_t containerId ) +{ + auto freeSlot = static_cast < int8_t >( m_storageMap[ containerId ]->getFreeSlot() ); + + if( freeSlot != -1 ) + return std::make_pair( containerId, freeSlot ); + + // no room in inventory + return std::make_pair( 0, -1 ); +} + Sapphire::ItemPtr Sapphire::Entity::Player::getItemAt( uint16_t containerId, uint16_t slotId ) { return m_storageMap[ containerId ]->getItem( slotId ); @@ -587,7 +598,7 @@ Sapphire::ItemPtr Sapphire::Entity::Player::addItem( uint32_t catalogId, uint32_ // add the related armoury bag to the applicable bags and try and fill a free slot there before falling back to regular inventory // EXD TODO: wtf... - if( /* No idea what it maps to itemInfo->data().isEquippable && */ getEquipDisplayFlags() & StoreNewItemsInArmouryChest ) + if( itemInfo->data().Slot > 0 && getEquipDisplayFlags() & StoreNewItemsInArmouryChest ) { auto bag = World::Manager::ItemMgr::getCharaEquipSlotCategoryToArmoryId( itemInfo->data().Slot ); @@ -606,7 +617,7 @@ Sapphire::ItemPtr Sapphire::Entity::Player::addItem( uint32_t catalogId, uint32_ auto item = storage->getItem( slot ); // add any items that are stackable - if( canMerge && item && /*!itemInfo->isEquippable &&*/ item->getId() == catalogId ) + if( canMerge && item && itemInfo->data().Slot > 0 && item->getId() == catalogId ) { uint32_t count = item->getStackSize(); uint32_t maxStack = item->getMaxStackSize(); @@ -851,7 +862,9 @@ void Sapphire::Entity::Player::swapItem( uint16_t fromInventoryId, uint16_t from && !World::Manager::ItemMgr::isArmory( fromInventoryId ) ) { updateContainer( fromInventoryId, fromSlotId, nullptr ); - fromInventoryId = World::Manager::ItemMgr::getCharaEquipSlotCategoryToArmoryId( toSlot ); + auto& exdData = Common::Service< Data::ExdData >::ref(); + auto itemInfo = exdData.getRow< Excel::Item >( toItem->getId() ); + fromInventoryId = World::Manager::ItemMgr::getCharaEquipSlotCategoryToArmoryId( static_cast< Common::EquipSlotCategory >( itemInfo->data().Slot ) ); fromSlotId = static_cast < uint8_t >( m_storageMap[ fromInventoryId ]->getFreeSlot() ); } diff --git a/src/world/Inventory/Item.cpp b/src/world/Inventory/Item.cpp index 4be8741d..03286805 100644 --- a/src/world/Inventory/Item.cpp +++ b/src/world/Inventory/Item.cpp @@ -25,6 +25,7 @@ Sapphire::Item::Item( uint64_t uId, uint32_t catalogId, bool isHq ) : m_weaponDmg = ( m_physicalDmg != 0 ) ? m_physicalDmg : m_magicalDmg; m_autoAttackDmg = static_cast< float >( m_weaponDmg * m_delayMs ) / 3000; m_category = static_cast< Common::ItemUICategory >( itemInfo->data().UICategory ); + m_slot = itemInfo->data().Slot; m_itemLevel = itemInfo->data().EquipLevel; m_maxStackSize = itemInfo->data().StackMax; // EXD TODO: Not sure what this maps to @@ -76,6 +77,11 @@ uint16_t Sapphire::Item::getItemLevel() const return m_itemLevel; } +uint8_t Sapphire::Item::getSlot() const +{ + return m_slot; +} + uint16_t Sapphire::Item::getWeaponDmg() const { return m_weaponDmg; diff --git a/src/world/Inventory/Item.h b/src/world/Inventory/Item.h index b6bbccbd..5f641ebd 100644 --- a/src/world/Inventory/Item.h +++ b/src/world/Inventory/Item.h @@ -65,6 +65,8 @@ namespace Sapphire uint16_t getItemLevel() const; + uint8_t getSlot() const; + uint32_t getMaxStackSize() const; uint16_t getDurability() const; @@ -105,6 +107,7 @@ namespace Sapphire uint16_t m_weaponDmg; float m_autoAttackDmg; uint16_t m_itemLevel; + uint8_t m_slot; uint16_t m_durability; uint16_t m_stain; uint16_t m_spiritBond; diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index eecf4ea2..7bae56cf 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -140,6 +140,9 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::Config, "Config", &GameConnection::configHandler ); setZoneHandler( CatalogSearch, "CatalogSearch", &GameConnection::catalogSearch ); + + setZoneHandler( GearSetEquip, "GearSetEquip", &GameConnection::gearSetEquip ); + setZoneHandler( MarketBoardRequestItemListingInfo, "MarketBoardRequestItemListingInfo", &GameConnection::marketBoardRequestItemInfo ); setZoneHandler( MarketBoardRequestItemListings, "MarketBoardRequestItemListings", &GameConnection::marketBoardRequestItemListings ); diff --git a/src/world/Network/GameConnection.h b/src/world/Network/GameConnection.h index a9c371bc..c4215446 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -214,6 +214,8 @@ namespace Sapphire::Network DECLARE_HANDLER( catalogSearch ); + DECLARE_HANDLER( gearSetEquip ); + DECLARE_HANDLER( marketBoardRequestItemInfo ); DECLARE_HANDLER( marketBoardRequestItemListings ); diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index 86a258f3..1cc700d5 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -27,6 +27,8 @@ #include "Linkshell/Linkshell.h" +#include "Inventory/Item.h" + #include "Network/PacketWrappers/PlayerSetupPacket.h" #include "Network/PacketWrappers/PingPacket.h" #include "Network/PacketWrappers/MoveActorPacket.h" @@ -38,6 +40,7 @@ #include "Network/PacketWrappers/EventStartPacket.h" #include "Network/PacketWrappers/EventFinishPacket.h" #include "Network/PacketWrappers/PlayerStateFlagsPacket.h" +#include "Network/PacketWrappers/UpdateInventorySlotPacket.h" #include "Manager/DebugCommandMgr.h" #include "Manager/EventMgr.h" @@ -51,6 +54,7 @@ #include "Manager/PartyMgr.h" #include "Manager/PlayerMgr.h" #include "Manager/WarpMgr.h" +#include "Manager/ItemMgr.h" #include "Action/Action.h" @@ -629,6 +633,63 @@ void Sapphire::Network::GameConnection::catalogSearch( const Packets::FFXIVARR_P ); } +// Also used for recommended gear +void Sapphire::Network::GameConnection::gearSetEquip( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) +{ + const auto packet = ZoneChannelPacket< Client::FFXIVIpcGearSetEquip >( inPacket ); + + auto& server = Common::Service< World::WorldServer >::ref(); + + // Loop over all slots + for (int slot = 0; slot < 14; slot++ ) + { + const auto fromSlot = packet.data().containerIndex[ slot ]; + const auto fromContainer = packet.data().storageId[ slot ]; + + if ( fromContainer == Common::GearSet0 ) + continue; + + const auto fromItem = fromSlot == -1 ? nullptr : player.getItemAt( fromContainer, fromSlot ); + const auto equippedItem = player.getItemAt( Common::GearSet0, slot ); + const auto operationType = ( fromItem && !equippedItem ) || ( !fromItem && equippedItem ) ? + ITEM_OPERATION_TYPE::ITEM_OPERATION_TYPE_MOVEITEM : ITEM_OPERATION_TYPE::ITEM_OPERATION_TYPE_SWAPITEM; + + auto ackPacket = makeZonePacket< FFXIVIpcItemOperationBatch >( player.getId() ); + ackPacket->data().contextId = packet.data().contextId; + ackPacket->data().operationType = operationType; + server.queueForPlayer( player.getCharacterId(), ackPacket ); + + if ( fromItem && equippedItem ) + { + player.swapItem( fromContainer, fromSlot, Common::GearSet0, slot ); + server.queueForPlayer( player.getCharacterId(), std::make_shared< UpdateInventorySlotPacket >( player.getId(), fromSlot, fromContainer, *equippedItem, 0 ) ); + server.queueForPlayer( player.getCharacterId(), std::make_shared< UpdateInventorySlotPacket >( player.getId(), slot, Common::GearSet0, *fromItem, 0 ) ); + } + else if ( fromItem && !equippedItem ) + { + player.moveItem( fromContainer, fromSlot, Common::GearSet0, slot ); + server.queueForPlayer( player.getCharacterId(), std::make_shared< UpdateInventorySlotPacket >( player.getId(), fromSlot, fromContainer, 0 ) ); + server.queueForPlayer( player.getCharacterId(), std::make_shared< UpdateInventorySlotPacket >( player.getId(), slot, Common::GearSet0, *fromItem, 0 ) ); + } + else if ( !fromItem && equippedItem ) + { + auto containerId = World::Manager::ItemMgr::getCharaEquipSlotCategoryToArmoryId( static_cast< Common::EquipSlotCategory >( equippedItem->getSlot() ) ); + auto freeSlot = player.getFreeContainerSlot( containerId ).second; + player.moveItem( Common::GearSet0, slot, containerId, freeSlot ); + server.queueForPlayer( player.getCharacterId(), std::make_shared< UpdateInventorySlotPacket >( player.getId(), freeSlot, containerId, *equippedItem, 0 ) ); + server.queueForPlayer( player.getCharacterId(), std::make_shared< UpdateInventorySlotPacket >( player.getId(), slot, Common::GearSet0, 0 ) ); + } + } + + // Send the inventory + //player.sendInventory(); + + if( packet.data().contextId < 0xFE ) + { + server.queueForPlayer( player.getCharacterId(), makeActorControlSelf( player.getId(), Network::ActorControl::GearSetEquipMsg, packet.data().contextId ) ); + } +} + void Sapphire::Network::GameConnection::marketBoardRequestItemInfo( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) { const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListingInfo >( inPacket ); diff --git a/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h b/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h index aad26098..57d0ee63 100644 --- a/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h +++ b/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h @@ -21,6 +21,12 @@ namespace Sapphire::Network::Packets::WorldPackets::Server initialize( slot, storageId, item, contextId ); }; + UpdateInventorySlotPacket( uint32_t playerId, uint16_t slot, uint16_t storageId, uint32_t contextId ) : + ZoneChannelPacket< FFXIVIpcNormalItem >( playerId, playerId ) + { + initialize( slot, storageId, contextId ); + }; + private: void initialize( uint16_t slot, uint16_t storageId, const Item& item, uint32_t contextId ) { @@ -34,6 +40,15 @@ namespace Sapphire::Network::Packets::WorldPackets::Server m_data.item.stain = static_cast< uint8_t >( item.getStain() ); m_data.item.signatureId = 0; }; + + void initialize( uint16_t slot, uint16_t storageId, uint32_t contextId ) + { + m_data.contextId = contextId; + m_data.item.storageId = storageId; + m_data.item.containerIndex = slot; + m_data.item.stack = 0; + m_data.item.catalogId = 0; + }; }; }