From 50276dcbc3220e571a972029b75c8a18de0ea740 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 17:44:03 +1100 Subject: [PATCH 01/16] #448 - remove deed on build --- src/common/Common.h | 2 +- src/world/Actor/Player.h | 2 +- src/world/Actor/PlayerInventory.cpp | 21 ++++++++++ src/world/Manager/HousingMgr.cpp | 41 ++++++++++++------- src/world/Manager/HousingMgr.h | 2 +- src/world/Territory/House.cpp | 4 +- src/world/Territory/House.h | 4 +- .../Housing/HousingInteriorTerritory.cpp | 2 +- 8 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 29296509..9363426d 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -791,7 +791,7 @@ namespace Sapphire::Common ExteriorFence }; - enum HousingInteriorSlot + enum HouseInteriorSlot { InteriorWall, InteriorFloor, diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index ce11587c..2721bba2 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -916,7 +916,7 @@ namespace Sapphire::Entity uint32_t getNextInventorySequence(); - void send(); + bool findFirstItemWithId( uint32_t catalogId, Inventory::InventoryContainerPair& location ); uint8_t getFreeSlotsInBags(); diff --git a/src/world/Actor/PlayerInventory.cpp b/src/world/Actor/PlayerInventory.cpp index d0b9cf82..df42dc8d 100644 --- a/src/world/Actor/PlayerInventory.cpp +++ b/src/world/Actor/PlayerInventory.cpp @@ -932,4 +932,25 @@ void Sapphire::Entity::Player::insertInventoryItem( Sapphire::Common::InventoryT auto slotUpdate = std::make_shared< UpdateInventorySlotPacket >( getId(), slot, type, *item ); queuePacket( slotUpdate ); +} + +bool Sapphire::Entity::Player::findFirstItemWithId( uint32_t catalogId, + Inventory::InventoryContainerPair& location ) +{ + for( auto bagId : { Bag0, Bag1, Bag2, Bag3 } ) + { + auto& container = m_storageMap[ bagId ]; + + for( const auto& item : container->getItemMap() ) + { + if( item.second->getId() != catalogId ) + continue; + + location = std::make_pair( bagId, item.first ); + + return true; + } + } + + return false; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index b14ac88b..1d3d079b 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -564,6 +564,18 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play if( !preset ) return false; + // remove preset item + Inventory::InventoryContainerPair foundItem; + if( !player.findFirstItemWithId( presetCatalogId, foundItem ) ) + return false; + + auto item = player.dropInventoryItem( foundItem.first, foundItem.second ); + if( !item ) + return false; + + // move preset item into ext appearance container + houseInventory[ InventoryType::HousingExteriorAppearance ]->setItem( HouseExteriorSlot::HousePermit, item ); + // high iq shit auto invMap = std::map< uint16_t, std::map< uint32_t, int32_t > > { @@ -583,19 +595,19 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play InventoryType::HousingInteriorAppearance, { // lobby/middle floor - { HousingInteriorSlot::InteriorWall, preset->interiorWall }, - { HousingInteriorSlot::InteriorFloor, preset->interiorFlooring }, - { HousingInteriorSlot::InteriorLight, preset->interiorLighting }, + { HouseInteriorSlot::InteriorWall, preset->interiorWall }, + { HouseInteriorSlot::InteriorFloor, preset->interiorFlooring }, + { HouseInteriorSlot::InteriorLight, preset->interiorLighting }, // attic - { HousingInteriorSlot::InteriorWall_Attic, preset->otherFloorWall }, - { HousingInteriorSlot::InteriorFloor_Attic, preset->otherFloorFlooring }, - { HousingInteriorSlot::InteriorLight_Attic, preset->otherFloorLighting }, + { HouseInteriorSlot::InteriorWall_Attic, preset->otherFloorWall }, + { HouseInteriorSlot::InteriorFloor_Attic, preset->otherFloorFlooring }, + { HouseInteriorSlot::InteriorLight_Attic, preset->otherFloorLighting }, // basement - { HousingInteriorSlot::InteriorWall_Basement, preset->basementWall }, - { HousingInteriorSlot::InteriorFloor_Basement, preset->basementFlooring }, - { HousingInteriorSlot::InteriorLight_Basement, preset->basementLighting }, + { HouseInteriorSlot::InteriorWall_Basement, preset->basementWall }, + { HouseInteriorSlot::InteriorFloor_Basement, preset->basementFlooring }, + { HouseInteriorSlot::InteriorLight_Basement, preset->basementLighting }, } } }; @@ -641,7 +653,7 @@ void Sapphire::World::Manager::HousingMgr::createHouse( Sapphire::HousePtr house pDb->execute( stmt ); } -void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetItem ) +void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetCatalogId ) { auto hZone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); @@ -656,8 +668,6 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl if( pLand->getOwnerId() != player.getId() ) return; - // todo: check if permit is in inventory and remove one - // create house auto ident = pLand->getLandIdent(); auto house = make_House( getNextHouseId(), pLand->getLandSetId(), ident, @@ -666,8 +676,11 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl pLand->setHouse( house ); // create inventory items - if( !initHouseModels( player, pLand, presetItem ) ) + if( !initHouseModels( player, pLand, presetCatalogId ) ) + { + pLand->setHouse( nullptr ); return; + } createHouse( house ); @@ -913,7 +926,7 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { for( auto& item : intContainer->second->getItemMap() ) { - house->setInteriorModel( static_cast< Common::HousingInteriorSlot >( item.first ), + house->setInteriorModel( static_cast< Common::HouseInteriorSlot >( item.first ), getItemAdditionalData( item.second->getId() ) ); } } diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 9dd0bd23..4f2a6898 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -91,7 +91,7 @@ namespace Sapphire::World::Manager bool relinquishLand( Entity::Player& player, uint8_t plot ); - void buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetItem ); + void buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetCatalogId ); void requestEstateRename( Entity::Player& player, const Common::LandIdent ident ); diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index 396e763e..fe08783d 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -96,12 +96,12 @@ Sapphire::House::HousePart Sapphire::House::getExteriorModel( Sapphire::Common:: return m_exteriorModelCache[ slot ]; } -void Sapphire::House::setInteriorModel( Sapphire::Common::HousingInteriorSlot slot, uint32_t modelId ) +void Sapphire::House::setInteriorModel( Sapphire::Common::HouseInteriorSlot slot, uint32_t modelId ) { m_interiorModelCache[ slot ] = modelId; } -uint32_t Sapphire::House::getInteriorModel( Sapphire::Common::HousingInteriorSlot slot ) +uint32_t Sapphire::House::getInteriorModel( Sapphire::Common::HouseInteriorSlot slot ) { return m_interiorModelCache[ slot ]; } diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index 3229e0e0..21d3ea86 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -34,8 +34,8 @@ namespace Sapphire void setExteriorModel( Common::HouseExteriorSlot slot, uint32_t modelId, uint16_t stain ); HousePart getExteriorModel( Common::HouseExteriorSlot slot ); - void setInteriorModel( Common::HousingInteriorSlot slot, uint32_t modelId ); - uint32_t getInteriorModel( Common::HousingInteriorSlot slot ); + void setInteriorModel( Common::HouseInteriorSlot slot, uint32_t modelId ); + uint32_t getInteriorModel( Common::HouseInteriorSlot slot ); HouseModelsArray const& getHouseModels() const; diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index dddbd86d..1ad7b57e 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -71,7 +71,7 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone for( auto i = 0; i < 10; i++ ) { indoorInitPacket->data().indoorItems[ i ] = pHouse->getInteriorModel( - static_cast< Common::HousingInteriorSlot >( i ) ); + static_cast< Common::HouseInteriorSlot >( i ) ); } player.queuePacket( indoorInitPacket ); From e418e61b4aa5ab8eb74aeb66e8e8550fa2942447 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 18:48:45 +1100 Subject: [PATCH 02/16] #448 - Place character correctly on entering a house --- .../common/eobj/HousingEstateEntrance.cpp | 41 ++++++++++++++++--- src/world/Actor/Player.cpp | 27 ++++++++++++ src/world/Actor/Player.h | 3 ++ src/world/Manager/TerritoryMgr.cpp | 8 ++-- src/world/Manager/TerritoryMgr.h | 2 +- 5 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/scripts/common/eobj/HousingEstateEntrance.cpp b/src/scripts/common/eobj/HousingEstateEntrance.cpp index a576bc19..7461ef1e 100644 --- a/src/scripts/common/eobj/HousingEstateEntrance.cpp +++ b/src/scripts/common/eobj/HousingEstateEntrance.cpp @@ -4,6 +4,7 @@ #include "Actor/EventObject.h" #include "Territory/HousingZone.h" #include "Manager/TerritoryMgr.h" +#include "Territory/Land.h" #include "Framework.h" using namespace Sapphire; @@ -19,8 +20,6 @@ public: void onTalk( uint32_t eventId, Entity::Player& player, Entity::EventObject& eobj ) override { - player.sendDebug( "Found plot entrance for plot: " + std::to_string( eobj.getHousingLink() >> 8 ) ); - player.playScene( eventId, 0, 0, [this, eobj]( Entity::Player& player, const Event::SceneResult& result ) { // param2 == 1 when player wants to enter house @@ -42,15 +41,45 @@ public: ident.worldId = 67; auto internalZone = terriMgr->findOrCreateHousingInterior( ident ); - if( internalZone ) + if( !internalZone ) { - player.sendDebug( "created zone with guid: " + std::to_string( internalZone->getGuId() ) + "\nname: " + internalZone->getName() ); + // an error occurred during event movement + // lol + player.sendLogMessage( 1311 ); + player.eventFinish( result.eventId, 1 ); + return; } player.eventFinish( result.eventId, 1 ); - player.setPos( { 0.f, 0.f, 0.f } ); - player.setInstance( internalZone ); + Common::FFXIVARR_POSITION3 pos {}; + + auto land = zone->getLand( eobj.getHousingLink() >> 8 ); + if( !land ) + return; + + switch( land->getSize() ) + { + case 0: + { + pos = { 0.1321167f, 0.f, 2.746273f }; + break; + } + case 1: + { + pos = { 1.337722f, 0.f, 3.995964f }; + break; + } + case 2: + { + pos = { 0.07214607f, 0.f, 8.217761f }; + break; + } + default: + return; + } + + player.setInstance( internalZone, pos ); } ); } }; \ No newline at end of file diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 33bcb871..5696a8a0 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -459,6 +459,33 @@ bool Sapphire::Entity::Player::setInstance( ZonePtr instance ) return true; } +bool Sapphire::Entity::Player::setInstance( ZonePtr instance, Common::FFXIVARR_POSITION3 pos ) +{ + if( !instance ) + return false; + + m_onEnterEventDone = false; + + auto pTeriMgr = m_pFw->get< TerritoryMgr >(); + auto currentZone = getCurrentZone(); + + m_prevPos = m_pos; + m_prevRot = m_rot; + m_prevTerritoryTypeId = currentZone->getTerritoryTypeId(); + m_prevTerritoryId = getTerritoryId(); + + if( pTeriMgr->movePlayer( instance, getAsPlayer() ) ) + { + m_pos = pos; + + sendZonePackets(); + + return true; + } + + return false; +} + bool Sapphire::Entity::Player::exitInstance() { auto pTeriMgr = m_pFw->get< TerritoryMgr >(); diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 2721bba2..218b27f9 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -482,6 +482,9 @@ namespace Sapphire::Entity /*! sets the players instance & initiates zoning process */ bool setInstance( ZonePtr instance ); + /*! sets the players instance & initiates zoning process */ + bool setInstance( Sapphire::ZonePtr instance, Sapphire::Common::FFXIVARR_POSITION3 pos ); + /*! returns the player to their position before zoning into an instance */ bool exitInstance(); diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 575c60b7..9e260c61 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -287,7 +287,7 @@ Sapphire::ZonePtr Sapphire::World::Manager::TerritoryMgr::createInstanceContent( pTeri->name, pInstanceContent->name, instanceContentId, framework() ); pZone->init(); - m_instanceContentToInstanceMap[ instanceContentId ][ pZone->getGuId() ] = pZone; + m_instanceContentIdToInstanceMap[ instanceContentId ][ pZone->getGuId() ] = pZone; m_instanceIdToZonePtrMap[ pZone->getGuId() ] = pZone; m_instanceZoneSet.insert( pZone ); @@ -381,7 +381,7 @@ bool Sapphire::World::Manager::TerritoryMgr::removeTerritoryInstance( uint32_t i if( isInstanceContentTerritory( pZone->getTerritoryTypeId() ) ) { auto instance = std::dynamic_pointer_cast< InstanceContent >( pZone ); - m_instanceContentToInstanceMap[ instance->getInstanceContentId() ].erase( pZone->getGuId() ); + m_instanceContentIdToInstanceMap[ instance->getInstanceContentId() ].erase( pZone->getGuId() ); } else m_territoryTypeIdToInstanceGuidMap[ pZone->getTerritoryTypeId() ].erase( pZone->getGuId() ); @@ -486,8 +486,8 @@ void Sapphire::World::Manager::TerritoryMgr::updateTerritoryInstances( uint32_t Sapphire::World::Manager::TerritoryMgr::InstanceIdList Sapphire::World::Manager::TerritoryMgr::getInstanceContentIdList( uint16_t instanceContentId ) const { std::vector< uint32_t > idList; - auto zoneMap = m_instanceContentToInstanceMap.find( instanceContentId ); - if( zoneMap == m_instanceContentToInstanceMap.end() ) + auto zoneMap = m_instanceContentIdToInstanceMap.find( instanceContentId ); + if( zoneMap == m_instanceContentIdToInstanceMap.end() ) return idList; for( auto& entry : zoneMap->second ) diff --git a/src/world/Manager/TerritoryMgr.h b/src/world/Manager/TerritoryMgr.h index b32c9fcb..1905b7f6 100644 --- a/src/world/Manager/TerritoryMgr.h +++ b/src/world/Manager/TerritoryMgr.h @@ -176,7 +176,7 @@ namespace Sapphire::World::Manager LandSetIdToZonePtrMap m_landSetIdToZonePtrMap; /*! map holding actual instances of InstanceContent */ - InstanceContentIdToInstanceMap m_instanceContentToInstanceMap; + InstanceContentIdToInstanceMap m_instanceContentIdToInstanceMap; /*! flat map for easier lookup of instances by guid */ InstanceIdToZonePtrMap m_instanceIdToZonePtrMap; From e7587972136c61b332e78e42447933b96162558d Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 20:24:20 +1100 Subject: [PATCH 03/16] minor refactoring and zero out model cache arrays on init --- src/world/Territory/House.cpp | 7 +++++-- src/world/Territory/House.h | 10 ++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index fe08783d..def91bc6 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -19,7 +19,10 @@ Sapphire::House::House( uint32_t houseId, uint32_t landSetId, Common::LandIdent m_estateName( estateName ), m_estateComment( estateComment ), m_pFw( pFw ) -{} +{ + m_interiorModelCache.fill( 0 ); + m_exteriorModelCache.fill( std::make_pair( 0, 0 ) ); +} Sapphire::House::~House() = default; @@ -57,7 +60,7 @@ uint32_t Sapphire::House::getId() const return m_houseId; } -Sapphire::House::HouseModelsArray const& Sapphire::House::getHouseModels() const +Sapphire::House::ExteriorModelsArray const& Sapphire::House::getHouseModels() const { return m_exteriorModelCache; } diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index 21d3ea86..1fa0ca43 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace Sapphire { @@ -17,7 +18,8 @@ namespace Sapphire virtual ~House(); using HousePart = std::pair< uint32_t, uint16_t >; - using HouseModelsArray = std::array< HousePart, 8 >; + using ExteriorModelsArray = std::array< HousePart, 8 >; + using InteriorModelsArray = std::array< uint32_t, 10 >; //gerneral uint32_t getLandSetId() const; @@ -37,7 +39,7 @@ namespace Sapphire void setInteriorModel( Common::HouseInteriorSlot slot, uint32_t modelId ); uint32_t getInteriorModel( Common::HouseInteriorSlot slot ); - HouseModelsArray const& getHouseModels() const; + ExteriorModelsArray const& getHouseModels() const; void updateHouseDb(); @@ -52,8 +54,8 @@ namespace Sapphire uint64_t m_buildTime; bool m_hasAetheryte; - HouseModelsArray m_exteriorModelCache; - uint32_t m_interiorModelCache[10]; + ExteriorModelsArray m_exteriorModelCache; + InteriorModelsArray m_interiorModelCache; std::string m_estateComment; std::string m_estateName; From 35db5865a29ad4991782838d335b357b3eeed03a Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 20:26:03 +1100 Subject: [PATCH 04/16] fix eobj id allocation skipping every nth index --- src/world/Territory/Zone.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/world/Territory/Zone.cpp b/src/world/Territory/Zone.cpp index 699a1dfd..1a3a5745 100644 --- a/src/world/Territory/Zone.cpp +++ b/src/world/Territory/Zone.cpp @@ -714,7 +714,6 @@ void Sapphire::Zone::registerEObj( Entity::EventObjectPtr object ) if( !object ) return; - object->setId( getNextEObjId() ); pushActor( object ); m_eventObjects[ object->getId() ] = object; From 66964ec8f6892adcbb54df18a41f967d84c9a1aa Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 21:26:32 +1100 Subject: [PATCH 05/16] fix issue where items couldn't be placed in storeroom from inv --- src/common/Logging/Logger.cpp | 10 ++ src/common/Logging/Logger.h | 4 + .../Network/PacketDef/Zone/ClientZoneDef.h | 2 +- src/world/Manager/HousingMgr.cpp | 133 ++++++++++++++---- src/world/Manager/HousingMgr.h | 4 + src/world/Network/Handlers/PacketHandlers.cpp | 10 +- 6 files changed, 130 insertions(+), 33 deletions(-) diff --git a/src/common/Logging/Logger.cpp b/src/common/Logging/Logger.cpp index 1a599551..c051e946 100644 --- a/src/common/Logging/Logger.cpp +++ b/src/common/Logging/Logger.cpp @@ -58,6 +58,11 @@ namespace Sapphire spdlog::get( "logger" )->error( text ); } + void Logger::warn( const std::string& text ) + { + spdlog::get( "logger" )->warn( text ); + } + void Logger::info( const std::string& text ) { spdlog::get( "logger" )->info( text ); @@ -73,4 +78,9 @@ namespace Sapphire spdlog::get( "logger" )->critical( text ); } + void Logger::trace( const std::string& text ) + { + spdlog::get( "logger" )->trace( text ); + } + } diff --git a/src/common/Logging/Logger.h b/src/common/Logging/Logger.h index 876fadc3..b716e319 100644 --- a/src/common/Logging/Logger.h +++ b/src/common/Logging/Logger.h @@ -20,12 +20,16 @@ namespace Sapphire static void error( const std::string& text ); + static void warn( const std::string& text ); + static void info( const std::string& text ); static void debug( const std::string& text ); static void fatal( const std::string& text ); + static void trace( const std::string& text ); + }; } diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 12b452dd..e096fa8a 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -253,7 +253,7 @@ struct FFXIVIpcReqPlaceHousingItem : /* 000C */ Common::FFXIVARR_POSITION3 position; /* 0018 */ float rotation; - /* 001C */ uint32_t unknown3; // always 1? + /* 001C */ uint32_t shouldPlaceItem; // 1 if placing an item, 0 if placing in store /* 0020 */ uint32_t unknown4[2]; // always 0 it looks like }; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 1d3d079b..8badd385 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -416,11 +416,10 @@ bool Sapphire::World::Manager::HousingMgr::relinquishLand( Entity::Player& playe auto pLand = pHousing->getLand( plot ); auto plotMaxPrice = pLand->getCurrentPrice(); - auto landOwnerId = pLand->getOwnerId(); // can't relinquish when you are not the owner // TODO: actually use permissions here for FC houses - if( landOwnerId != player.getId() ) + if( !hasPermission( player, *pLand, 0 ) ) { auto msgPkt = makeActorControl143( player.getId(), ActorControl::LogMsg, 3304, 0 ); player.queuePacket( msgPkt ); @@ -664,8 +663,7 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl if( !pLand ) return; - // todo: when doing FC houses, look up the type from the original purchase and check perms from FC and set state accordingly - if( pLand->getOwnerId() != player.getId() ) + if( !hasPermission( player, *pLand, 0 ) ) return; // create house @@ -763,8 +761,7 @@ void Sapphire::World::Manager::HousingMgr::updateEstateGreeting( Entity::Player& if( !land ) return; - // todo: implement proper permissions checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto house = land->getHouse(); @@ -789,8 +786,7 @@ void Sapphire::World::Manager::HousingMgr::requestEstateEditGuestAccess( Entity: if( !land ) return; - // todo: add proper permission check - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto packet = makeZonePacket< Server::FFXIVIpcHousingShowEstateGuestAccess >( player.getId() ); @@ -854,8 +850,7 @@ void Sapphire::World::Manager::HousingMgr::sendEstateInventory( Entity::Player& if( !targetLand ) return; - // todo: add proper permissions checks - if( targetLand->getOwnerId() != player.getId() ) + if( !hasPermission( player, *targetLand, 0 ) ) return; auto& containers = getEstateInventory( targetLand->getLandIdent() ); @@ -993,12 +988,11 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity if( !land ) return; - // todo: add proper permissions checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; // todo: check item position and make sure it's not outside the plot - // retail uses a radius based check + // anecdotal evidence on reddit seems to imply retail uses a radius based check // unlink item Inventory::HousingItemPtr item; @@ -1009,6 +1003,8 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity containerId == InventoryType::Bag3 ) { auto tmpItem = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + if( !tmpItem ) + return; item = Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId(), framework() ); @@ -1042,6 +1038,76 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity player.sendUrgent( "An internal error occurred when placing the item." ); } +void Sapphire::World::Manager::HousingMgr::reqPlaceItemInStore( Sapphire::Entity::Player& player, uint16_t landId, + uint16_t containerId, uint16_t slotId ) +{ + LandPtr land; + bool isOutside = false; + + if( auto zone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ) ) + { + land = zone->getLand( landId ); + isOutside = true; + } + else if( auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ) ) + { + // todo: this whole process is retarded and needs to be fixed + // perhaps maintain a list of estates by ident inside housingmgr? + auto ident = zone->getLandIdent(); + auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); + + land = getHousingZoneByLandSetId( landSet )->getLand( ident.landId ); + } + + if( !hasPermission( player, *land, 0 ) ) + return; + + auto invMgr = framework()->get< InventoryMgr >(); + auto ident = land->getLandIdent(); + auto& containers = getEstateInventory( ident ); + + if( isOutside ) + { + auto& container = containers[ InventoryType::HousingExteriorStoreroom ]; + + auto freeSlot = container->getFreeSlot(); + if( freeSlot == -1 ) + return; + + auto item = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + if( !item ) + return; + + container->setItem( freeSlot, item ); + invMgr->sendInventoryContainer( player, container ); + invMgr->saveHousingContainer( ident, container ); + } + else + { + for( auto houseContainer : m_internalStoreroomContainers ) + { + auto needle = containers.find( houseContainer ); + if( needle == containers.end() ) + continue; + + auto container = needle->second; + auto freeSlot = container->getFreeSlot(); + if( freeSlot == -1 ) + { + continue; + } + + auto item = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + if( !item ) + return; + + container->setItem( freeSlot, item ); + invMgr->sendInventoryContainer( player, container ); + invMgr->saveHousingContainer( ident, container ); + } + } +} + bool Sapphire::World::Manager::HousingMgr::placeExternalItem( Entity::Player& player, Inventory::HousingItemPtr item, Common::LandIdent ident ) @@ -1107,9 +1173,6 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl // have a free slot container->setItem( freeSlot, item ); - // todo: see comment above in placeExternalItem where the same func is called - invMgr->saveItem( player, item ); - // resend container invMgr->sendInventoryContainer( player, container ); invMgr->saveHousingContainer( ident, container ); @@ -1176,8 +1239,7 @@ void Sapphire::World::Manager::HousingMgr::reqMoveHousingItem( Entity::Player& p if( !land ) return; - // todo: proper perms checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; // todo: what happens when either of these fail? how does the server let the client know that the moment failed @@ -1250,8 +1312,7 @@ bool Sapphire::World::Manager::HousingMgr::moveExternalItem( Entity::Player& pla { auto land = terri.getLand( ident.landId ); - // todo: add proper perms check - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return false; auto& containers = getEstateInventory( ident ); @@ -1298,8 +1359,7 @@ void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entit if( !land ) return; - // todo: proper perms checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; removeInternalItem( player, *terri, containerId, slot, sendToStoreroom ); @@ -1310,7 +1370,7 @@ void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entit if( !land ) return; - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto containerType = static_cast< Common::InventoryType >( containerId ); @@ -1419,11 +1479,13 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p if( !item ) return false; + bool shouldDespawnItem = containerType != InventoryType::HousingExteriorStoreroom; + auto invMgr = framework()->get< InventoryMgr >(); if( sendToStoreroom ) { - auto& storeroomContainer = containers[ InventoryType::HousingExteriorStoreroom ]; + auto& storeroomContainer = containers[ containerType ]; auto freeSlot = storeroomContainer->getFreeSlot(); if( freeSlot == -1 ) @@ -1431,8 +1493,8 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p sourceContainer->removeItem( slotId ); invMgr->sendInventoryContainer( player, sourceContainer ); - invMgr->removeHousingItemPosition( *item ); invMgr->removeItemFromHousingContainer( land.getLandIdent(), sourceContainer->getId(), slotId ); + invMgr->removeHousingItemPosition( *item ); storeroomContainer->setItem( freeSlot, item ); invMgr->sendInventoryContainer( player, storeroomContainer ); @@ -1454,7 +1516,8 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p player.insertInventoryItem( containerPair.first, containerPair.second, item ); } - terri.despawnYardObject( land.getLandIdent().landId, slotId ); + if( shouldDespawnItem ) + terri.despawnYardObject( land.getLandIdent().landId, slotId ); return true; } @@ -1495,8 +1558,7 @@ void Sapphire::World::Manager::HousingMgr::reqEstateExteriorRemodel( Sapphire::E if( !land ) return; - // todo: proper perms checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto& inv = getEstateInventory( land->getLandIdent() ); @@ -1526,8 +1588,7 @@ void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::E if( !land ) return; - // todo: proper perms checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto& inv = getEstateInventory( land->getLandIdent() ); @@ -1541,4 +1602,16 @@ void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::E auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateInternalAppearanceUI ); player.queuePacket( pkt ); +} + +bool Sapphire::World::Manager::HousingMgr::hasPermission( Sapphire::Entity::Player& player, Sapphire::Land& land, + uint32_t permission ) +{ + // todo: proper perms checks pls + if( land.getOwnerId() == player.getId() ) + return true; + + // todo: check perms here + + return false; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 4f2a6898..deb6c099 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -159,6 +159,8 @@ namespace Sapphire::World::Manager void reqPlaceHousingItem( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId, Common::FFXIVARR_POSITION3 pos, float rotation ); + void reqPlaceItemInStore( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId ); + /*! * @brief Returns the equivalent YardObject for a HousingItem * @param item The item to convert into a YardObject @@ -179,6 +181,8 @@ namespace Sapphire::World::Manager void reqEstateInteriorRemodel( Entity::Player& player ); + bool hasPermission( Entity::Player& player, Land& land, uint32_t permission ); + private: ItemContainerPtr getFreeEstateInventorySlot( Common::LandIdent ident, diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index a41ed334..fa6543bf 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -731,8 +731,14 @@ void Sapphire::Network::GameConnection::reqPlaceHousingItem( FrameworkPtr pFw, const auto packet = ZoneChannelPacket< Client::FFXIVIpcReqPlaceHousingItem >( inPacket ); const auto& data = packet.data(); - housingMgr->reqPlaceHousingItem( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId, - data.position, data.rotation ); + if( data.shouldPlaceItem == 1 ) + { + housingMgr->reqPlaceHousingItem( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId, + data.position, data.rotation ); + } + else + housingMgr->reqPlaceItemInStore( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId ); + } void Sapphire::Network::GameConnection::reqMoveHousingItem( FrameworkPtr pFw, From d21b0018dce8f8610f0809e680bfb1772f727f17 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 22:36:44 +1100 Subject: [PATCH 06/16] standardise log names and potentially fix log folder issue on windows --- src/api/main.cpp | 2 +- src/common/Logging/Logger.cpp | 2 +- src/dbm/main.cpp | 2 +- src/lobby/ServerLobby.cpp | 8 +++----- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/api/main.cpp b/src/api/main.cpp index 81aa0024..f287fc08 100644 --- a/src/api/main.cpp +++ b/src/api/main.cpp @@ -734,7 +734,7 @@ void defaultGet( shared_ptr< HttpServer::Response > response, shared_ptr< HttpSe int main( int argc, char* argv[] ) { - Logger::init( "log/SapphireAPI" ); + Logger::init( "log/api" ); Logger::info( "===========================================================" ); Logger::info( "Sapphire API Server " ); diff --git a/src/common/Logging/Logger.cpp b/src/common/Logging/Logger.cpp index c051e946..dbf83f4f 100644 --- a/src/common/Logging/Logger.cpp +++ b/src/common/Logging/Logger.cpp @@ -25,7 +25,7 @@ namespace Sapphire void Logger::init( const std::string& logPath ) { - auto pos = logPath.find_last_of( '/' ); + auto pos = logPath.find_last_of( fs::path::preferred_separator ); if( pos != std::string::npos ) { diff --git a/src/dbm/main.cpp b/src/dbm/main.cpp index 6cce2ac4..b82dde0c 100644 --- a/src/dbm/main.cpp +++ b/src/dbm/main.cpp @@ -104,7 +104,7 @@ int main( int32_t argc, char* argv[] ) std::string database; std::string pass; - Logger::init( "log/SapphireDbm" ); + Logger::init( "log/dbm" ); std::string sFile; std::string iFile; diff --git a/src/lobby/ServerLobby.cpp b/src/lobby/ServerLobby.cpp index dcdacee1..c0ad8ebf 100644 --- a/src/lobby/ServerLobby.cpp +++ b/src/lobby/ServerLobby.cpp @@ -31,12 +31,10 @@ namespace Sapphire m_configPath( configPath ), m_numConnections( 0 ) { - m_pConfig = std::shared_ptr< ConfigMgr >( new ConfigMgr ); + m_pConfig = std::make_shared< ConfigMgr >(); } - ServerLobby::~ServerLobby( void ) - { - } + ServerLobby::~ServerLobby( void ) = default; LobbySessionPtr ServerLobby::getSession( char* sessionId ) { @@ -50,7 +48,7 @@ namespace Sapphire void ServerLobby::run( int32_t argc, char* argv[] ) { - Logger::init( "log/SapphireLobby" ); + Logger::init( "log/lobby" ); Logger::info( "===========================================================" ); Logger::info( "Sapphire Server Project " ); From 06afdfb79ef9f8f187f6b80bfa157e3f5efbdc74 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 23:25:52 +1100 Subject: [PATCH 07/16] hide additional quarters door in private housing --- src/common/Network/CommonActorControl.h | 1 + src/common/Network/PacketDef/Zone/ServerZoneDef.h | 4 ++++ src/world/Territory/Housing/HousingInteriorTerritory.cpp | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 6438bc49..32a00705 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -240,6 +240,7 @@ enum ActorControlType : uint16_t */ HousingItemMoveConfirm = 0x3F9, OpenEstateSettingsUI = 0x3FF, + HideAdditionalChambersDoor = 0x400, /*! * param1 = outdoor furnishings diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 40cd48a3..63ea03ba 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1701,6 +1701,10 @@ struct FFXIVIpcHousingObjectMove : FFXIVIpcBasePacket< HousingObjectMove > struct FFXIVIpcHousingObjectInitialize : FFXIVIpcBasePacket< HousingObjectInitialize > { Common::LandIdent landIdent; + /*! + * when this is 2, actrl 0x400 will hide the additional quarters door + * if it's any other value, it will stay there regardless + */ int8_t u1; //Outdoor -1 / Indoor 0 - probably indicator uint8_t packetNum; uint8_t packetTotal; diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index 1ad7b57e..63fb581e 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -76,12 +76,14 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone player.queuePacket( indoorInitPacket ); + auto yardPacketTotal = static_cast< uint8_t >( 2 + pLand->getSize() ); for( uint8_t yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ ) { auto objectInitPacket = makeZonePacket< Server::FFXIVIpcHousingObjectInitialize >( player.getId() ); memcpy( &objectInitPacket->data().landIdent, &m_landIdent, sizeof( Common::LandIdent ) ); - objectInitPacket->data().u1 = 0; + // todo: change this when FC houses become a thing + objectInitPacket->data().u1 = 2; // 2 = actrl 0x400 will hide the fc door, otherwise it will stay there objectInitPacket->data().u2 = 100; objectInitPacket->data().packetNum = yardPacketNum; objectInitPacket->data().packetTotal = yardPacketTotal; @@ -92,6 +94,8 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone player.queuePacket( objectInitPacket ); } + // todo: if in fc house, don't send this + player.queuePacket( Server::makeActorControl143( player.getId(), Network::ActorControl::HideAdditionalChambersDoor ) ); } void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onUpdate( uint32_t currTime ) From b7fcf6080cd4d1a9260ebce8ebaa40a069a0f4bd Mon Sep 17 00:00:00 2001 From: NotAdam Date: Mon, 31 Dec 2018 21:39:43 +1100 Subject: [PATCH 08/16] fix issue where items couldn't be removed from interior storeroom --- src/world/Manager/HousingMgr.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 8badd385..20dca94d 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1386,24 +1386,24 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p { auto& containers = getEstateInventory( terri.getLandIdent() ); - // validate the container id first - // we also need the idx of the container so we can get the slot offset - bool foundContainer = false; uint8_t containerIdx = 0; - for( auto cId : m_internalPlacedItemContainers ) + + if( isPlacedItemsInventory( static_cast< Common::InventoryType >( containerId ) ) ) { - if( containerId == cId ) + for( auto cId : m_internalPlacedItemContainers ) { - foundContainer = true; + if( containerId == cId ) + break; - break; + containerIdx++; } - - containerIdx++; } + else + containerIdx = -1; - if( !foundContainer ) - return false; + // its possible to remove an item from any container in basically all these remove functions + // eg, remove a permit and reuse it elsewhere + // I'm not going to bother fixing it for now, but worth noting for future reference auto needle = containers.find( containerId ); if( needle == containers.end() ) @@ -1457,8 +1457,11 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p } // despawn - auto arraySlot = ( containerIdx * 50 ) + slotId; - terri.removeHousingObject( arraySlot ); + if( containerIdx != -1 ) + { + auto arraySlot = ( containerIdx * 50 ) + slotId; + terri.removeHousingObject( arraySlot ); + } return true; } From a04d01be90903323aac5b8e6ee4c0b1c605fe811 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Mon, 31 Dec 2018 21:54:32 +1100 Subject: [PATCH 09/16] some housing cleanup and refactoring --- src/common/Common.h | 10 +++++----- src/world/Manager/HousingMgr.cpp | 16 ++++++++-------- src/world/Manager/HousingMgr.h | 4 ++-- src/world/Territory/HousingZone.cpp | 4 ++-- src/world/Territory/Land.cpp | 12 ++++++------ src/world/Territory/Land.h | 14 +++++++------- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 9363426d..f986821a 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -866,13 +866,13 @@ namespace Sapphire::Common Mansion }; - enum HouseState : uint8_t + enum HouseStatus : uint8_t { none, - forSale, - sold, - privateHouse, - fcHouse, + HouseForSale, + HouseSold, + HousePrivateEstate, + HouseFreeCompanyEstate, }; enum HouseIconAdd : uint8_t diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 20dca94d..fd4ab7ef 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -179,8 +179,8 @@ void Sapphire::World::Manager::HousingMgr::initLandCache() entry.m_landId = res->getUInt( "LandId" ); entry.m_type = static_cast< Common::LandType >( res->getUInt( "Type" ) ); - entry.m_size = res->getUInt8( "Size" ); - entry.m_status = res->getUInt8( "Status" ); + entry.m_size = static_cast< Common::HouseSize >( res->getUInt8( "Size" ) ); + entry.m_status = static_cast< Common::HouseStatus >( res->getUInt8( "Status" ) ); entry.m_currentPrice = res->getUInt64( "LandPrice" ); entry.m_updateTime = res->getUInt64( "UpdateTime" ); entry.m_ownerId = res->getUInt64( "OwnerId" ); @@ -365,7 +365,7 @@ Sapphire::LandPurchaseResult Sapphire::World::Manager::HousingMgr::purchaseLand( if( !pLand ) return LandPurchaseResult::ERR_INTERNAL; - if( pLand->getState() != HouseState::forSale ) + if( pLand->getStatus() != HouseStatus::HouseForSale ) return LandPurchaseResult::ERR_NOT_AVAILABLE; if( gilAvailable < plotPrice ) @@ -388,7 +388,7 @@ Sapphire::LandPurchaseResult Sapphire::World::Manager::HousingMgr::purchaseLand( player.removeCurrency( CurrencyType::Gil, plotPrice ); pLand->setOwnerId( player.getId() ); - pLand->setState( HouseState::sold ); + pLand->setStatus( HouseStatus::HouseSold ); pLand->setLandType( Common::LandType::Private ); player.setLandFlags( LandFlagsSlot::Private, 0x00, pLand->getLandIdent() ); @@ -437,7 +437,7 @@ bool Sapphire::World::Manager::HousingMgr::relinquishLand( Entity::Player& playe pLand->setCurrentPrice( pLand->getMaxPrice() ); pLand->setOwnerId( 0 ); - pLand->setState( HouseState::forSale ); + pLand->setStatus( HouseStatus::HouseForSale ); pLand->setLandType( Common::LandType::none ); pLand->updateLandDb(); @@ -477,11 +477,11 @@ void Sapphire::World::Manager::HousingMgr::sendWardLandInfo( Entity::Player& pla auto& entry = wardInfoPacket->data().houseInfoEntry[ i ]; - // retail always sends the house price in this packet, even after the house has been sold + // retail always sends the house price in this packet, even after the house has been HouseSold // so I guess we do the same entry.housePrice = land->getCurrentPrice(); - if( land->getState() == Common::HouseState::forSale ) + if( land->getStatus() == Common::HouseStatus::HouseForSale ) continue; if( auto house = land->getHouse() ) @@ -682,7 +682,7 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl createHouse( house ); - pLand->setState( HouseState::privateHouse ); + pLand->setStatus( HouseStatus::HousePrivateEstate ); pLand->setLandType( LandType::Private ); hZone->sendLandUpdate( plotNum ); diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index deb6c099..6b25ce57 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -31,8 +31,8 @@ namespace Sapphire::World::Manager uint16_t m_landId; Common::LandType m_type; - uint8_t m_size; - uint8_t m_status; + Common::HouseSize m_size; + Common::HouseStatus m_status; uint64_t m_currentPrice; diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 3814b471..9f79defa 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -220,7 +220,7 @@ void Sapphire::HousingZone::sendLandSet( Entity::Player& player ) auto& landData = landsetInitializePacket->data().land[ count ]; landData.plotSize = pLand->getSize(); - landData.houseState = pLand->getState(); + landData.houseState = pLand->getStatus(); landData.iconAddIcon = pLand->getSharing(); landData.fcId = pLand->getFcId(); landData.fcIcon = pLand->getFcIcon(); @@ -256,7 +256,7 @@ void Sapphire::HousingZone::sendLandUpdate( uint8_t landId ) auto& landData = landUpdatePacket->data().land; landData.plotSize = pLand->getSize(); - landData.houseState = pLand->getState(); + landData.houseState = pLand->getStatus(); landData.iconAddIcon = pLand->getSharing(); landData.fcId = pLand->getFcId(); landData.fcIcon = pLand->getFcIcon(); diff --git a/src/world/Territory/Land.cpp b/src/world/Territory/Land.cpp index 432b473b..28e63e8a 100644 --- a/src/world/Territory/Land.cpp +++ b/src/world/Territory/Land.cpp @@ -54,7 +54,7 @@ Sapphire::Land::Land( uint16_t territoryTypeId, uint8_t wardNum, uint8_t landId, Sapphire::Land::~Land() = default; -void Sapphire::Land::init( Common::LandType type, uint8_t size, uint8_t state, uint32_t currentPrice, +void Sapphire::Land::init( Common::LandType type, Common::HouseSize size, Common::HouseStatus state, uint32_t currentPrice, uint64_t ownerId, uint64_t houseId ) { m_type = type; @@ -84,12 +84,12 @@ uint32_t Sapphire::Land::getMaxPrice() const } //Primary State -void Sapphire::Land::setSize( uint8_t size ) +void Sapphire::Land::setSize( Common::HouseSize size ) { m_size = size; } -void Sapphire::Land::setState( uint8_t state ) +void Sapphire::Land::setStatus( Common::HouseStatus state ) { m_state = state; } @@ -104,12 +104,12 @@ void Sapphire::Land::setLandType( Common::LandType type ) m_type = type; } -uint8_t Sapphire::Land::getSize() const +Sapphire::Common::HouseSize Sapphire::Land::getSize() const { return m_size; } -uint8_t Sapphire::Land::getState() const +Sapphire::Common::HouseStatus Sapphire::Land::getStatus() const { return m_state; } @@ -227,7 +227,7 @@ void Sapphire::Land::updateLandDb() void Sapphire::Land::update( uint32_t currTime ) { - if( getState() == HouseState::forSale ) + if( getStatus() == HouseStatus::HouseForSale ) { if( m_nextDrop < currTime && m_minPrice < m_currentPrice ) { diff --git a/src/world/Territory/Land.h b/src/world/Territory/Land.h index f6af5f2a..8eecbb33 100644 --- a/src/world/Territory/Land.h +++ b/src/world/Territory/Land.h @@ -18,20 +18,20 @@ namespace Sapphire Land( uint16_t zoneId, uint8_t wardNum, uint8_t landId, uint32_t landSetId, Sapphire::Data::HousingLandSetPtr info, FrameworkPtr pFw ); virtual ~Land(); - void init( Common::LandType type, uint8_t size, uint8_t state, uint32_t currentPrice, uint64_t ownerId, uint64_t houseId ); + void init( Common::LandType type, Common::HouseSize size, Common::HouseStatus state, uint32_t currentPrice, uint64_t ownerId, uint64_t houseId ); using LandInventoryMap = std::unordered_map< uint16_t, ItemContainerPtr >; using InvMaxItemsPair = std::pair< uint16_t, uint16_t >; //Primary state - void setSize( uint8_t size ); - void setState( uint8_t state ); + void setSize( Common::HouseSize size ); + void setStatus( Common::HouseStatus state ); void setSharing( uint8_t state ); void setLandType( Common::LandType type ); //Gerneral - uint8_t getSize() const; - uint8_t getState() const; + Common::HouseSize getSize() const; + Common::HouseStatus getStatus() const; uint8_t getSharing() const; uint32_t getLandSetId() const; Common::LandType getLandType() const; @@ -71,8 +71,8 @@ namespace Sapphire Common::LandIdent m_landIdent; uint32_t m_landSetId; - uint8_t m_size; - uint8_t m_state; + Common::HouseSize m_size; + Common::HouseStatus m_state; Common::LandType m_type; uint8_t m_iconAddIcon; uint32_t m_fcId; // unclear, may be wrong From 1c890a43bf369563f35ebc97c3dc1920ea4837bf Mon Sep 17 00:00:00 2001 From: NotAdam Date: Mon, 31 Dec 2018 22:02:34 +1100 Subject: [PATCH 10/16] handle fc doors properly --- src/common/Common.h | 8 ++++---- src/world/Manager/HousingMgr.cpp | 12 ++++++------ .../Territory/Housing/HousingInteriorTerritory.cpp | 13 +++++++++---- src/world/Territory/Land.cpp | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index f986821a..77d29367 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -869,10 +869,10 @@ namespace Sapphire::Common enum HouseStatus : uint8_t { none, - HouseForSale, - HouseSold, - HousePrivateEstate, - HouseFreeCompanyEstate, + ForSale, + Sold, + PrivateEstate, + FreeCompanyEstate, }; enum HouseIconAdd : uint8_t diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index fd4ab7ef..8e0c01a6 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -365,7 +365,7 @@ Sapphire::LandPurchaseResult Sapphire::World::Manager::HousingMgr::purchaseLand( if( !pLand ) return LandPurchaseResult::ERR_INTERNAL; - if( pLand->getStatus() != HouseStatus::HouseForSale ) + if( pLand->getStatus() != HouseStatus::ForSale ) return LandPurchaseResult::ERR_NOT_AVAILABLE; if( gilAvailable < plotPrice ) @@ -388,7 +388,7 @@ Sapphire::LandPurchaseResult Sapphire::World::Manager::HousingMgr::purchaseLand( player.removeCurrency( CurrencyType::Gil, plotPrice ); pLand->setOwnerId( player.getId() ); - pLand->setStatus( HouseStatus::HouseSold ); + pLand->setStatus( HouseStatus::Sold ); pLand->setLandType( Common::LandType::Private ); player.setLandFlags( LandFlagsSlot::Private, 0x00, pLand->getLandIdent() ); @@ -437,7 +437,7 @@ bool Sapphire::World::Manager::HousingMgr::relinquishLand( Entity::Player& playe pLand->setCurrentPrice( pLand->getMaxPrice() ); pLand->setOwnerId( 0 ); - pLand->setStatus( HouseStatus::HouseForSale ); + pLand->setStatus( HouseStatus::ForSale ); pLand->setLandType( Common::LandType::none ); pLand->updateLandDb(); @@ -477,11 +477,11 @@ void Sapphire::World::Manager::HousingMgr::sendWardLandInfo( Entity::Player& pla auto& entry = wardInfoPacket->data().houseInfoEntry[ i ]; - // retail always sends the house price in this packet, even after the house has been HouseSold + // retail always sends the house price in this packet, even after the house has been Sold // so I guess we do the same entry.housePrice = land->getCurrentPrice(); - if( land->getStatus() == Common::HouseStatus::HouseForSale ) + if( land->getStatus() == Common::HouseStatus::ForSale ) continue; if( auto house = land->getHouse() ) @@ -682,7 +682,7 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl createHouse( house ); - pLand->setStatus( HouseStatus::HousePrivateEstate ); + pLand->setStatus( HouseStatus::PrivateEstate ); pLand->setLandType( LandType::Private ); hZone->sendLandUpdate( plotNum ); diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index 63fb581e..6bef748b 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -76,14 +76,19 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone player.queuePacket( indoorInitPacket ); + bool isFcHouse = pLand->getStatus() == Common::HouseStatus::PrivateEstate; auto yardPacketTotal = static_cast< uint8_t >( 2 + pLand->getSize() ); for( uint8_t yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ ) { auto objectInitPacket = makeZonePacket< Server::FFXIVIpcHousingObjectInitialize >( player.getId() ); memcpy( &objectInitPacket->data().landIdent, &m_landIdent, sizeof( Common::LandIdent ) ); - // todo: change this when FC houses become a thing - objectInitPacket->data().u1 = 2; // 2 = actrl 0x400 will hide the fc door, otherwise it will stay there + + if( isFcHouse ) + objectInitPacket->data().u1 = 2; // 2 = actrl 0x400 will hide the fc door, otherwise it will stay there + else + objectInitPacket->data().u1 = 0; + objectInitPacket->data().u2 = 100; objectInitPacket->data().packetNum = yardPacketNum; objectInitPacket->data().packetTotal = yardPacketTotal; @@ -94,8 +99,8 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone player.queuePacket( objectInitPacket ); } - // todo: if in fc house, don't send this - player.queuePacket( Server::makeActorControl143( player.getId(), Network::ActorControl::HideAdditionalChambersDoor ) ); + if( isFcHouse ) + player.queuePacket( Server::makeActorControl143( player.getId(), Network::ActorControl::HideAdditionalChambersDoor ) ); } void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onUpdate( uint32_t currTime ) diff --git a/src/world/Territory/Land.cpp b/src/world/Territory/Land.cpp index 28e63e8a..15411d24 100644 --- a/src/world/Territory/Land.cpp +++ b/src/world/Territory/Land.cpp @@ -227,7 +227,7 @@ void Sapphire::Land::updateLandDb() void Sapphire::Land::update( uint32_t currTime ) { - if( getStatus() == HouseStatus::HouseForSale ) + if( getStatus() == HouseStatus::ForSale ) { if( m_nextDrop < currTime && m_minPrice < m_currentPrice ) { From d421888a07cef6dc39669c4a3f5e408478c5b3aa Mon Sep 17 00:00:00 2001 From: NotAdam Date: Mon, 31 Dec 2018 22:45:39 +1100 Subject: [PATCH 11/16] fix storing items in the housing storerooms for real this time --- src/world/Manager/HousingMgr.cpp | 24 ++++++++++++++++-------- src/world/Manager/HousingMgr.h | 2 ++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 8e0c01a6..5fda5ef4 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -568,7 +568,7 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play if( !player.findFirstItemWithId( presetCatalogId, foundItem ) ) return false; - auto item = player.dropInventoryItem( foundItem.first, foundItem.second ); + auto item = getHousingItemFromPlayer( player, foundItem.first, foundItem.second ); if( !item ) return false; @@ -1002,12 +1002,10 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity containerId == InventoryType::Bag2 || containerId == InventoryType::Bag3 ) { - auto tmpItem = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); - if( !tmpItem ) + item = getHousingItemFromPlayer( player, static_cast< Common::InventoryType >( containerId ), slotId ); + if( !item ) return; - item = Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId(), framework() ); - // set params item->setPos( { Util::floatToUInt16( pos.x ), @@ -1074,7 +1072,7 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceItemInStore( Sapphire::Entity if( freeSlot == -1 ) return; - auto item = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + auto item = getHousingItemFromPlayer( player, static_cast< Common::InventoryType >( containerId ), slotId ); if( !item ) return; @@ -1097,7 +1095,7 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceItemInStore( Sapphire::Entity continue; } - auto item = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + auto item = getHousingItemFromPlayer( player, static_cast< Common::InventoryType >( containerId ), slotId ); if( !item ) return; @@ -1386,7 +1384,7 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p { auto& containers = getEstateInventory( terri.getLandIdent() ); - uint8_t containerIdx = 0; + int8_t containerIdx = 0; if( isPlacedItemsInventory( static_cast< Common::InventoryType >( containerId ) ) ) { @@ -1617,4 +1615,14 @@ bool Sapphire::World::Manager::HousingMgr::hasPermission( Sapphire::Entity::Play // todo: check perms here return false; +} + +Sapphire::Inventory::HousingItemPtr Sapphire::World::Manager::HousingMgr::getHousingItemFromPlayer( + Entity::Player& player, Common::InventoryType type, uint8_t slot ) +{ + auto tmpItem = player.dropInventoryItem( type, slot ); + if( !tmpItem ) + return nullptr; + + return Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId(), framework() ); } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 6b25ce57..8167efb9 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -185,6 +185,8 @@ namespace Sapphire::World::Manager private: + Inventory::HousingItemPtr getHousingItemFromPlayer( Entity::Player& player, Common::InventoryType type, uint8_t slot ); + ItemContainerPtr getFreeEstateInventorySlot( Common::LandIdent ident, Inventory::InventoryContainerPair& pair, Inventory::InventoryTypeList bagList ); From af7a7694339b50fc0d59ed90a6fb5f107eac9d2b Mon Sep 17 00:00:00 2001 From: NotAdam Date: Mon, 31 Dec 2018 23:20:36 +1100 Subject: [PATCH 12/16] start of marketboard implementation --- src/common/Network/PacketDef/Ipcs.h | 2 +- .../Network/PacketDef/Zone/ClientZoneDef.h | 13 +++++++++++ src/world/Manager/MarketMgr.cpp | 19 ++++++++++++++++ src/world/Manager/MarketMgr.h | 22 +++++++++++++++++++ src/world/Manager/PlayerMgr.h | 7 +++++- src/world/Network/GameConnection.h | 2 ++ src/world/Network/Handlers/PacketHandlers.cpp | 13 +++++++++++ src/world/ServerMgr.cpp | 10 +++++++++ 8 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/world/Manager/MarketMgr.cpp create mode 100644 src/world/Manager/MarketMgr.h diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index ede6ed36..40855781 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -267,7 +267,7 @@ namespace Sapphire::Network::Packets MarketBoardRequestItemInformation = 0x00FE, // updated 4.4 MarketBoardRequestItemListings = 0x00FF, // updated 4.4 - SearchMarketboard = 0x0103, // updated 4.3 + SearchMarketboard = 0x0103, // updated 4.4 ReqExamineFcInfo = 0x010F, // updated 4.1 FcInfoReqHandler = 0x011A, // updated 4.2 diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index e096fa8a..68b856b8 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -270,6 +270,19 @@ struct FFXIVIpcHousingUpdateObjectPosition : /* 001C */ uint32_t padding; }; +struct FFXIVIpcSearchMarketboard : + FFXIVIpcBasePacket< SearchMarketboard > +{ + /* 0000 */ uint32_t unk; + /* 0004 */ uint8_t unk2[2]; + /* 0006 */ uint8_t itemSearchCategory; + /* 0007 */ uint8_t shouldCheckClassJobId; // wat? seems only 1 there at least... + /* 0008 */ uint8_t maxEquipLevel; + /* 0009 */ uint8_t classJobId; + /* 000A */ char searchStr[40]; + /* 0032 */ uint16_t unk4[43]; +}; + } } } diff --git a/src/world/Manager/MarketMgr.cpp b/src/world/Manager/MarketMgr.cpp new file mode 100644 index 00000000..1769a6e8 --- /dev/null +++ b/src/world/Manager/MarketMgr.cpp @@ -0,0 +1,19 @@ +#include "MarketMgr.h" + +Sapphire::World::Manager::MarketMgr::MarketMgr( Sapphire::FrameworkPtr pFw ) : + BaseManager( pFw ) +{ + +} + +bool Sapphire::World::Manager::MarketMgr::init() +{ + return true; +} + +void Sapphire::World::Manager::MarketMgr::searchMarketboard( Entity::Player& player, + uint8_t itemSearchCategory, uint8_t maxEquipLevel, + uint8_t classJob ) +{ + +} \ No newline at end of file diff --git a/src/world/Manager/MarketMgr.h b/src/world/Manager/MarketMgr.h new file mode 100644 index 00000000..9c21c8ed --- /dev/null +++ b/src/world/Manager/MarketMgr.h @@ -0,0 +1,22 @@ +#ifndef SAPPHIRE_MARKETMGR_H +#define SAPPHIRE_MARKETMGR_H + +#include "ForwardsZone.h" +#include "BaseManager.h" + +namespace Sapphire::World::Manager +{ + class MarketMgr : public Manager::BaseManager + { + public: + explicit MarketMgr( FrameworkPtr pFw ); + + bool init(); + + void searchMarketboard( Entity::Player& player, uint8_t itemSearchCategory, uint8_t maxEquipLevel, uint8_t classJob ); + + }; +} + + +#endif //SAPPHIRE_MARKETMGR_H diff --git a/src/world/Manager/PlayerMgr.h b/src/world/Manager/PlayerMgr.h index 0b0cbd13..f7d08488 100644 --- a/src/world/Manager/PlayerMgr.h +++ b/src/world/Manager/PlayerMgr.h @@ -1,3 +1,6 @@ +#ifndef SAPPHIRE_PLAYERMGR_H +#define SAPPHIRE_PLAYERMGR_H + #include "ForwardsZone.h" #include "BaseManager.h" @@ -10,4 +13,6 @@ class PlayerMgr : public Manager::BaseManager void movePlayerToLandDestination( Sapphire::Entity::Player& player, uint32_t landId, uint16_t param = 0 ); }; -} \ No newline at end of file +} + +#endif // SAPPHIRE_PLAYERMGR_H \ No newline at end of file diff --git a/src/world/Network/GameConnection.h b/src/world/Network/GameConnection.h index dcdec9d1..c4984267 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -176,6 +176,8 @@ namespace Sapphire::Network DECLARE_HANDLER( reqMoveHousingItem ); + DECLARE_HANDLER( searchMarketboard ); + }; } diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index fa6543bf..580b0629 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -36,6 +36,7 @@ #include "Manager/DebugCommandMgr.h" #include "Manager/EventMgr.h" +#include "Manager/MarketMgr.h" #include "Action/Action.h" #include "Action/ActionTeleport.h" @@ -752,4 +753,16 @@ void Sapphire::Network::GameConnection::reqMoveHousingItem( FrameworkPtr pFw, housingMgr->reqMoveHousingItem( player, data.ident, data.slot, data.pos, data.rotation ); +} + +void Sapphire::Network::GameConnection::searchMarketboard( FrameworkPtr pFw, + const Sapphire::Network::Packets::FFXIVARR_PACKET_RAW& inPacket, + Entity::Player& player ) +{ + auto marketMgr = pFw->get< MarketMgr >(); + + const auto packet = ZoneChannelPacket< Client::FFXIVIpcSearchMarketboard >( inPacket ); + const auto& data = packet.data(); + + marketMgr->searchMarketboard( player, data.itemSearchCategory, data.maxEquipLevel, data.classJobId ); } \ No newline at end of file diff --git a/src/world/ServerMgr.cpp b/src/world/ServerMgr.cpp index cc89386a..316f6460 100644 --- a/src/world/ServerMgr.cpp +++ b/src/world/ServerMgr.cpp @@ -39,6 +39,7 @@ #include "Manager/InventoryMgr.h" #include "Manager/EventMgr.h" #include "Manager/ItemMgr.h" +#include "Manager/MarketMgr.h" using namespace Sapphire::World::Manager; @@ -160,6 +161,15 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] ) return; } + auto pMarketMgr = std::make_shared< Manager::MarketMgr >( framework() ); + framework()->set< Manager::MarketMgr >( pMarketMgr ); + + if( !pMarketMgr->init() ) + { + Logger::fatal( "Failed to setup market manager!" ); + return; + } + loadBNpcTemplates(); Network::HivePtr hive( new Network::Hive() ); From 50d1d9d4928de64e173f84795ad90838de477a01 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 1 Jan 2019 11:51:48 +1100 Subject: [PATCH 13/16] correctly send marketboard item list --- src/common/Network/PacketDef/Ipcs.h | 2 +- .../Network/PacketDef/Zone/ClientZoneDef.h | 20 +++- .../Network/PacketDef/Zone/ServerZoneDef.h | 5 +- src/world/Manager/MarketMgr.cpp | 106 +++++++++++++++++- src/world/Manager/MarketMgr.h | 35 +++++- src/world/Network/GameConnection.cpp | 4 + src/world/Network/GameConnection.h | 4 +- src/world/Network/Handlers/PacketHandlers.cpp | 20 +++- 8 files changed, 177 insertions(+), 19 deletions(-) diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index 40855781..c1875da3 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -266,8 +266,8 @@ namespace Sapphire::Network::Packets MarketBoardRequestItemInformation = 0x00FE, // updated 4.4 MarketBoardRequestItemListings = 0x00FF, // updated 4.4 + MarketBoardSearch = 0x0103, // updated 4.4 - SearchMarketboard = 0x0103, // updated 4.4 ReqExamineFcInfo = 0x010F, // updated 4.1 FcInfoReqHandler = 0x011A, // updated 4.2 diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 68b856b8..e312d790 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -237,8 +237,9 @@ struct FFXIVIpcSetSharedEstateSettings : struct FFXIVIpcMarketBoardRequestItemListings : FFXIVIpcBasePacket< MarketBoardRequestItemListings > { - /* 0000 */ uint32_t itemCatalogId; - /* 0004 */ uint32_t padding; + /* 0000 */ uint16_t padding1; + /* 0002 */ uint16_t itemCatalogId; + /* 0004 */ uint32_t padding2; }; struct FFXIVIpcReqPlaceHousingItem : @@ -270,11 +271,11 @@ struct FFXIVIpcHousingUpdateObjectPosition : /* 001C */ uint32_t padding; }; -struct FFXIVIpcSearchMarketboard : - FFXIVIpcBasePacket< SearchMarketboard > +struct FFXIVIpcMarketBoardSearch : + FFXIVIpcBasePacket< MarketBoardSearch > { - /* 0000 */ uint32_t unk; - /* 0004 */ uint8_t unk2[2]; + /* 0000 */ uint32_t startIdx; + /* 0004 */ uint16_t requestId; /* 0006 */ uint8_t itemSearchCategory; /* 0007 */ uint8_t shouldCheckClassJobId; // wat? seems only 1 there at least... /* 0008 */ uint8_t maxEquipLevel; @@ -283,6 +284,13 @@ struct FFXIVIpcSearchMarketboard : /* 0032 */ uint16_t unk4[43]; }; +struct FFXIVIpcMarketBoardRequestItemInformation : + FFXIVIpcBasePacket< MarketBoardRequestItemInformation > +{ + /* 0000 */ uint32_t catalogId; + /* 0000 */ uint32_t requestId; +}; + } } } diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 63ea03ba..2c5a8d8e 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1847,13 +1847,14 @@ struct FFXIVIpcMarketBoardSearchResult : struct MarketBoardItem { uint32_t itemCatalogId; - uint32_t quantity; + uint16_t quantity; + uint16_t demand; } items[20]; uint32_t itemIndexEnd; uint32_t padding1; uint32_t itemIndexStart; - uint32_t padding2; + uint32_t requestId; }; struct FFFXIVIpcMarketBoardItemListingCount : diff --git a/src/world/Manager/MarketMgr.cpp b/src/world/Manager/MarketMgr.cpp index 1769a6e8..b850f1bc 100644 --- a/src/world/Manager/MarketMgr.cpp +++ b/src/world/Manager/MarketMgr.cpp @@ -1,5 +1,17 @@ #include "MarketMgr.h" +#include +#include +#include + +#include +#include +#include + +#include "Actor/Player.h" + +using namespace Sapphire::Network::Packets; + Sapphire::World::Manager::MarketMgr::MarketMgr( Sapphire::FrameworkPtr pFw ) : BaseManager( pFw ) { @@ -8,12 +20,98 @@ Sapphire::World::Manager::MarketMgr::MarketMgr( Sapphire::FrameworkPtr pFw ) : bool Sapphire::World::Manager::MarketMgr::init() { + Logger::info( "MarketMgr: warming up marketable item cache..." ); + + // build item cache + auto exdData = framework()->get< Sapphire::Data::ExdDataGenerated >(); + auto idList = exdData->getItemIdList(); + + for( auto id : idList ) + { + auto item = exdData->get< Sapphire::Data::Item >( id ); + if( !item ) + continue; + + if( item->isUntradable ) + continue; + + MarketableItem cacheEntry {}; + cacheEntry.catalogId = id; + cacheEntry.itemSearchCategory = item->itemSearchCategory; + cacheEntry.maxEquipLevel = item->levelEquip; + cacheEntry.name = item->name; + cacheEntry.classJob = item->classJobUse; + + m_marketItemCache.push_back( std::move( cacheEntry ) ); + } + + Logger::info( "MarketMgr: Cached " + std::to_string( m_marketItemCache.size() ) + " marketable items" ); + return true; } -void Sapphire::World::Manager::MarketMgr::searchMarketboard( Entity::Player& player, - uint8_t itemSearchCategory, uint8_t maxEquipLevel, - uint8_t classJob ) +void Sapphire::World::Manager::MarketMgr::requestItemListings( Sapphire::Entity::Player& player, uint32_t catalogId, + uint32_t requestId ) { - + auto countPkt = makeZonePacket< Server::FFFXIVIpcMarketBoardItemListingCount >( player.getId() ); + countPkt->data().quantity = 1; + countPkt->data().itemCatalogId = catalogId; +} + + +void Sapphire::World::Manager::MarketMgr::searchMarketboard( Entity::Player& player, uint8_t itemSearchCategory, + uint8_t maxEquipLevel, uint8_t classJob, + const std::string_view& searchStr, uint32_t requestId, + uint32_t startIdx ) +{ + ItemSearchResultList resultList; + findItems( searchStr, itemSearchCategory, maxEquipLevel, classJob, resultList ); + + auto numResults = resultList.size(); + + if( startIdx > numResults ) + return; + + auto endIdx = std::min< size_t >( startIdx + 20, numResults ); + auto size = endIdx - startIdx; + + auto resultPkt = makeZonePacket< Server::FFXIVIpcMarketBoardSearchResult >( player.getId() ); + resultPkt->data().itemIndexStart = startIdx; + resultPkt->data().requestId = requestId; + + for( auto i = 0; i < resultList.size(); i++ ) + { + auto& item = resultList.at( startIdx + i ); + auto& data = resultPkt->data().items[ i ]; + + data.itemCatalogId = item.catalogId; + data.quantity = item.quantity; + data.demand = 69; + } + + if( size < 20 ) + resultPkt->data().itemIndexEnd = 0; + else + resultPkt->data().itemIndexEnd = startIdx + 20; + + player.queuePacket( resultPkt ); +} + +void Sapphire::World::Manager::MarketMgr::findItems( const std::string_view& searchStr, uint8_t itemSearchCat, + uint8_t maxEquipLevel, uint8_t classJob, + Sapphire::World::Manager::MarketMgr::ItemSearchResultList& resultList ) +{ + for( const auto& item : m_marketItemCache ) + { + if( item.itemSearchCategory != itemSearchCat ) + continue; + + if( maxEquipLevel > 0 && item.maxEquipLevel > maxEquipLevel ) + continue; + + if( classJob > 0 && item.classJob != classJob ) + continue; + + resultList.push_back( { item.catalogId, 1 } ); + } } \ No newline at end of file diff --git a/src/world/Manager/MarketMgr.h b/src/world/Manager/MarketMgr.h index 9c21c8ed..311c1e28 100644 --- a/src/world/Manager/MarketMgr.h +++ b/src/world/Manager/MarketMgr.h @@ -4,6 +4,8 @@ #include "ForwardsZone.h" #include "BaseManager.h" +#include + namespace Sapphire::World::Manager { class MarketMgr : public Manager::BaseManager @@ -13,7 +15,38 @@ namespace Sapphire::World::Manager bool init(); - void searchMarketboard( Entity::Player& player, uint8_t itemSearchCategory, uint8_t maxEquipLevel, uint8_t classJob ); + void searchMarketboard( Entity::Player& player, uint8_t itemSearchCategory, + uint8_t maxEquipLevel, uint8_t classJob, + const std::string_view& searchStr, uint32_t requestId, + uint32_t startIdx ); + + void requestItemListings( Entity::Player& player, uint32_t catalogId, uint32_t requestId ); + + private: + struct ItemSearchResult + { + uint32_t catalogId; + uint16_t quantity; + }; + + struct MarketableItem + { + uint32_t catalogId; + uint8_t itemSearchCategory; + uint8_t maxEquipLevel; + uint8_t classJob; + std::string name; + }; + + using ItemSearchResultList = std::vector< ItemSearchResult >; + using MarketableItemCacheList = std::vector< MarketableItem >; + + MarketableItemCacheList m_marketItemCache; + + + + void findItems( const std::string_view& searchStr, uint8_t itemSearchCat, uint8_t maxEquipLevel, uint8_t classJob, + ItemSearchResultList& resultList ); }; } diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index 8761647a..de524b87 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -123,6 +123,10 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::PerformNoteHandler, "PerformNoteHandler", &GameConnection::performNoteHandler ); + setZoneHandler( ClientZoneIpcType::MarketBoardSearch, "MarketBoardSearch", &GameConnection::marketBoardSearch ); + setZoneHandler( ClientZoneIpcType::MarketBoardRequestItemInformation, "MarketBoardRequestItemInformation", + &GameConnection::marketBoardRequestItemInfo ); + setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler ); } diff --git a/src/world/Network/GameConnection.h b/src/world/Network/GameConnection.h index c4984267..65901843 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -176,7 +176,9 @@ namespace Sapphire::Network DECLARE_HANDLER( reqMoveHousingItem ); - DECLARE_HANDLER( searchMarketboard ); + DECLARE_HANDLER( marketBoardSearch ); + + DECLARE_HANDLER( marketBoardRequestItemInfo ); }; diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index 580b0629..e08a566e 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -755,14 +755,26 @@ void Sapphire::Network::GameConnection::reqMoveHousingItem( FrameworkPtr pFw, } -void Sapphire::Network::GameConnection::searchMarketboard( FrameworkPtr pFw, - const Sapphire::Network::Packets::FFXIVARR_PACKET_RAW& inPacket, +void Sapphire::Network::GameConnection::marketBoardSearch( FrameworkPtr pFw, + const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) { auto marketMgr = pFw->get< MarketMgr >(); - const auto packet = ZoneChannelPacket< Client::FFXIVIpcSearchMarketboard >( inPacket ); + const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardSearch >( inPacket ); const auto& data = packet.data(); - marketMgr->searchMarketboard( player, data.itemSearchCategory, data.maxEquipLevel, data.classJobId ); + std::string_view searchStr( data.searchStr ); + + marketMgr->searchMarketboard( player, data.itemSearchCategory, data.maxEquipLevel, data.classJobId, data.searchStr, + data.requestId, data.startIdx ); +} + +void Sapphire::Network::GameConnection::marketBoardRequestItemInfo( FrameworkPtr pFw, + const Packets::FFXIVARR_PACKET_RAW& inPacket, + Entity::Player& player ) +{ + const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemInformation >( inPacket ); + + auto marketMgr = pFw->get< MarketMgr >(); } \ No newline at end of file From 717acba9cb3d16715cd58ba121ff3c3680024535 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 1 Jan 2019 14:19:44 +1100 Subject: [PATCH 14/16] fix oob error on market board result lists and correctly sort the items --- src/common/Network/PacketDef/Ipcs.h | 2 +- src/common/Network/PacketDef/Zone/ClientZoneDef.h | 4 ++-- src/world/Manager/MarketMgr.cpp | 10 +++++++++- src/world/Manager/MarketMgr.h | 1 + src/world/Network/GameConnection.cpp | 2 +- src/world/Network/Handlers/PacketHandlers.cpp | 2 +- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index c1875da3..bdfc08fb 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -264,7 +264,7 @@ namespace Sapphire::Network::Packets LinkshellListHandler = 0x00F4, // updated 4.3 - MarketBoardRequestItemInformation = 0x00FE, // updated 4.4 + MarketBoardRequestItemListingInfo = 0x00FE, // updated 4.4 MarketBoardRequestItemListings = 0x00FF, // updated 4.4 MarketBoardSearch = 0x0103, // updated 4.4 diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index e312d790..f4a057ad 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -284,8 +284,8 @@ struct FFXIVIpcMarketBoardSearch : /* 0032 */ uint16_t unk4[43]; }; -struct FFXIVIpcMarketBoardRequestItemInformation : - FFXIVIpcBasePacket< MarketBoardRequestItemInformation > +struct FFXIVIpcMarketBoardRequestItemListingInfo : + FFXIVIpcBasePacket< MarketBoardRequestItemListingInfo > { /* 0000 */ uint32_t catalogId; /* 0000 */ uint32_t requestId; diff --git a/src/world/Manager/MarketMgr.cpp b/src/world/Manager/MarketMgr.cpp index b850f1bc..e448ba16 100644 --- a/src/world/Manager/MarketMgr.cpp +++ b/src/world/Manager/MarketMgr.cpp @@ -10,6 +10,8 @@ #include "Actor/Player.h" +#include + using namespace Sapphire::Network::Packets; Sapphire::World::Manager::MarketMgr::MarketMgr( Sapphire::FrameworkPtr pFw ) : @@ -41,10 +43,16 @@ bool Sapphire::World::Manager::MarketMgr::init() cacheEntry.maxEquipLevel = item->levelEquip; cacheEntry.name = item->name; cacheEntry.classJob = item->classJobUse; + cacheEntry.itemLevel = item->levelItem; m_marketItemCache.push_back( std::move( cacheEntry ) ); } + std::sort( m_marketItemCache.begin(), m_marketItemCache.end(), []( const MarketableItem& a, const MarketableItem& b ) + { + return a.itemLevel > b.itemLevel; + } ); + Logger::info( "MarketMgr: Cached " + std::to_string( m_marketItemCache.size() ) + " marketable items" ); return true; @@ -79,7 +87,7 @@ void Sapphire::World::Manager::MarketMgr::searchMarketboard( Entity::Player& pla resultPkt->data().itemIndexStart = startIdx; resultPkt->data().requestId = requestId; - for( auto i = 0; i < resultList.size(); i++ ) + for( auto i = 0; i < size; i++ ) { auto& item = resultList.at( startIdx + i ); auto& data = resultPkt->data().items[ i ]; diff --git a/src/world/Manager/MarketMgr.h b/src/world/Manager/MarketMgr.h index 311c1e28..b50462a6 100644 --- a/src/world/Manager/MarketMgr.h +++ b/src/world/Manager/MarketMgr.h @@ -34,6 +34,7 @@ namespace Sapphire::World::Manager uint32_t catalogId; uint8_t itemSearchCategory; uint8_t maxEquipLevel; + uint16_t itemLevel; uint8_t classJob; std::string name; }; diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index de524b87..bb2f6697 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -124,7 +124,7 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::PerformNoteHandler, "PerformNoteHandler", &GameConnection::performNoteHandler ); setZoneHandler( ClientZoneIpcType::MarketBoardSearch, "MarketBoardSearch", &GameConnection::marketBoardSearch ); - setZoneHandler( ClientZoneIpcType::MarketBoardRequestItemInformation, "MarketBoardRequestItemInformation", + setZoneHandler( ClientZoneIpcType::MarketBoardRequestItemListingInfo, "MarketBoardRequestItemListingInfo", &GameConnection::marketBoardRequestItemInfo ); setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler ); diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index e08a566e..aa07a1d5 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -774,7 +774,7 @@ void Sapphire::Network::GameConnection::marketBoardRequestItemInfo( FrameworkPtr const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) { - const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemInformation >( inPacket ); + const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListingInfo >( inPacket ); auto marketMgr = pFw->get< MarketMgr >(); } \ No newline at end of file From cd19435876c87fbdcc1e00057b5faeb39ca1d03a Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 1 Jan 2019 17:29:06 +1100 Subject: [PATCH 15/16] somewhat working marketboard implementation --- .../Network/PacketDef/Zone/ServerZoneDef.h | 10 +++--- src/world/Manager/MarketMgr.cpp | 36 +++++++++++++++++-- src/world/Manager/MarketMgr.h | 4 ++- src/world/Network/GameConnection.cpp | 2 ++ src/world/Network/GameConnection.h | 2 ++ src/world/Network/Handlers/PacketHandlers.cpp | 13 +++++++ 6 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 2c5a8d8e..18618ab9 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1860,11 +1860,11 @@ struct FFXIVIpcMarketBoardSearchResult : struct FFFXIVIpcMarketBoardItemListingCount : FFXIVIpcBasePacket< MarketBoardItemListingCount > { - uint32_t itemCatalogId; - uint32_t unknown1; // does some shit if nonzero - uint16_t unknown2; - uint16_t quantity; // high/low u8s read separately? - uint32_t padding3; + uint32_t itemCatalogId; + uint32_t unknown1; // does some shit if nonzero + uint16_t requestId; + uint16_t quantity; // high/low u8s read separately? + uint32_t unknown3; }; struct FFXIVIpcMarketBoardItemListingHistory : diff --git a/src/world/Manager/MarketMgr.cpp b/src/world/Manager/MarketMgr.cpp index e448ba16..e1a6d3bd 100644 --- a/src/world/Manager/MarketMgr.cpp +++ b/src/world/Manager/MarketMgr.cpp @@ -58,12 +58,37 @@ bool Sapphire::World::Manager::MarketMgr::init() return true; } -void Sapphire::World::Manager::MarketMgr::requestItemListings( Sapphire::Entity::Player& player, uint32_t catalogId, - uint32_t requestId ) +void Sapphire::World::Manager::MarketMgr::requestItemListingInfo( Sapphire::Entity::Player& player, uint32_t catalogId, + uint32_t requestId ) { auto countPkt = makeZonePacket< Server::FFFXIVIpcMarketBoardItemListingCount >( player.getId() ); - countPkt->data().quantity = 1; + countPkt->data().quantity = 1 << 8; countPkt->data().itemCatalogId = catalogId; + countPkt->data().requestId = requestId; + + player.queuePacket( countPkt ); + + auto historyPkt = makeZonePacket< Server::FFXIVIpcMarketBoardItemListingHistory >( player.getId() ); + historyPkt->data().itemCatalogId = catalogId; + historyPkt->data().itemCatalogId2 = catalogId; + + memset( &historyPkt->data().listing, 0x0, sizeof( Server::FFXIVIpcMarketBoardItemListingHistory::MarketListing ) * 20 ); + + std::string name = "fix game"; + + for( int i = 0; i < 10; ++i ) + { + auto& listing = historyPkt->data().listing[ i ]; + + listing.itemCatalogId = catalogId; + listing.quantity = i; + listing.purchaseTime = time( nullptr ); + listing.salePrice = 500; + + strcpy( listing.sellerName, name.c_str() ); + } + + player.queuePacket( historyPkt ); } @@ -105,6 +130,11 @@ void Sapphire::World::Manager::MarketMgr::searchMarketboard( Entity::Player& pla player.queuePacket( resultPkt ); } +void Sapphire::World::Manager::MarketMgr::requestItemListings( Sapphire::Entity::Player& player, uint16_t catalogId ) +{ + +} + void Sapphire::World::Manager::MarketMgr::findItems( const std::string_view& searchStr, uint8_t itemSearchCat, uint8_t maxEquipLevel, uint8_t classJob, Sapphire::World::Manager::MarketMgr::ItemSearchResultList& resultList ) diff --git a/src/world/Manager/MarketMgr.h b/src/world/Manager/MarketMgr.h index b50462a6..328c9c12 100644 --- a/src/world/Manager/MarketMgr.h +++ b/src/world/Manager/MarketMgr.h @@ -20,7 +20,9 @@ namespace Sapphire::World::Manager const std::string_view& searchStr, uint32_t requestId, uint32_t startIdx ); - void requestItemListings( Entity::Player& player, uint32_t catalogId, uint32_t requestId ); + void requestItemListingInfo( Entity::Player& player, uint32_t catalogId, uint32_t requestId ); + + void requestItemListings( Entity::Player& player, uint16_t catalogId ); private: struct ItemSearchResult diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index bb2f6697..57e336f4 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -126,6 +126,8 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::MarketBoardSearch, "MarketBoardSearch", &GameConnection::marketBoardSearch ); setZoneHandler( ClientZoneIpcType::MarketBoardRequestItemListingInfo, "MarketBoardRequestItemListingInfo", &GameConnection::marketBoardRequestItemInfo ); + setZoneHandler( ClientZoneIpcType::MarketBoardRequestItemListings, "MarketBoardRequestItemListings", + &GameConnection::marketBoardRequestItemListings ); setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler ); diff --git a/src/world/Network/GameConnection.h b/src/world/Network/GameConnection.h index 65901843..72c800b2 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -180,6 +180,8 @@ namespace Sapphire::Network DECLARE_HANDLER( marketBoardRequestItemInfo ); + DECLARE_HANDLER( marketBoardRequestItemListings ); + }; } diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index aa07a1d5..d737bf8a 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -777,4 +777,17 @@ void Sapphire::Network::GameConnection::marketBoardRequestItemInfo( FrameworkPtr const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListingInfo >( inPacket ); auto marketMgr = pFw->get< MarketMgr >(); + + marketMgr->requestItemListingInfo( player, packet.data().catalogId, packet.data().requestId ); +} + +void Sapphire::Network::GameConnection::marketBoardRequestItemListings( FrameworkPtr pFw, + const Packets::FFXIVARR_PACKET_RAW& inPacket, + Entity::Player& player ) +{ + const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListings >( inPacket ); + + auto marketMgr = pFw->get< MarketMgr >(); + + marketMgr->requestItemListings( player, packet.data().itemCatalogId ); } \ No newline at end of file From 4673a8122e8351c0b8729353494b5bd4e0f4d1d1 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 1 Jan 2019 23:37:32 +1100 Subject: [PATCH 16/16] fix structs, disable market cache gen --- src/common/Network/PacketDef/Ipcs.h | 2 +- .../Network/PacketDef/Zone/ServerZoneDef.h | 10 +-- src/world/Manager/MarketMgr.cpp | 86 ++++++++++--------- 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index bdfc08fb..bca4b286 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -176,7 +176,7 @@ namespace Sapphire::Network::Packets DirectorVars = 0x01E1, // updated 4.4 - CFAvailableContents = 0x01FD, // updated 4.2 + CFAvailableContents = 0xF1FD, // updated 4.2 WeatherChange = 0x01FC, // updated 4.4 PlayerTitleList = 0x01FD, // updated 4.4 diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 18618ab9..e1f3980e 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1876,14 +1876,14 @@ struct FFXIVIpcMarketBoardItemListingHistory : struct MarketListing { uint32_t salePrice; - time_t purchaseTime; + uint32_t purchaseTime; uint32_t quantity; - uint16_t unknown1; - uint8_t unknown2; + uint8_t isHq; + uint8_t padding; + uint8_t onMannequin; - char sellerName[32]; + char buyerName[33]; - uint8_t unknown3; uint32_t itemCatalogId; } listing[20]; }; diff --git a/src/world/Manager/MarketMgr.cpp b/src/world/Manager/MarketMgr.cpp index e1a6d3bd..d18d28e1 100644 --- a/src/world/Manager/MarketMgr.cpp +++ b/src/world/Manager/MarketMgr.cpp @@ -22,38 +22,41 @@ Sapphire::World::Manager::MarketMgr::MarketMgr( Sapphire::FrameworkPtr pFw ) : bool Sapphire::World::Manager::MarketMgr::init() { - Logger::info( "MarketMgr: warming up marketable item cache..." ); - - // build item cache - auto exdData = framework()->get< Sapphire::Data::ExdDataGenerated >(); - auto idList = exdData->getItemIdList(); - - for( auto id : idList ) - { - auto item = exdData->get< Sapphire::Data::Item >( id ); - if( !item ) - continue; - - if( item->isUntradable ) - continue; - - MarketableItem cacheEntry {}; - cacheEntry.catalogId = id; - cacheEntry.itemSearchCategory = item->itemSearchCategory; - cacheEntry.maxEquipLevel = item->levelEquip; - cacheEntry.name = item->name; - cacheEntry.classJob = item->classJobUse; - cacheEntry.itemLevel = item->levelItem; - - m_marketItemCache.push_back( std::move( cacheEntry ) ); - } - - std::sort( m_marketItemCache.begin(), m_marketItemCache.end(), []( const MarketableItem& a, const MarketableItem& b ) - { - return a.itemLevel > b.itemLevel; - } ); - - Logger::info( "MarketMgr: Cached " + std::to_string( m_marketItemCache.size() ) + " marketable items" ); +// Logger::info( "MarketMgr: warming up marketable item cache..." ); +// +// // build item cache +// auto exdData = framework()->get< Sapphire::Data::ExdDataGenerated >(); +// auto idList = exdData->getItemIdList(); +// +// for( auto id : idList ) +// { +// if( id > 10000 ) +// break; +// +// auto item = exdData->get< Sapphire::Data::Item >( id ); +// if( !item ) +// continue; +// +// if( item->isUntradable ) +// continue; +// +// MarketableItem cacheEntry {}; +// cacheEntry.catalogId = id; +// cacheEntry.itemSearchCategory = item->itemSearchCategory; +// cacheEntry.maxEquipLevel = item->levelEquip; +// cacheEntry.name = item->name; +// cacheEntry.classJob = item->classJobUse; +// cacheEntry.itemLevel = item->levelItem; +// +// m_marketItemCache.push_back( std::move( cacheEntry ) ); +// } +// +// std::sort( m_marketItemCache.begin(), m_marketItemCache.end(), []( const MarketableItem& a, const MarketableItem& b ) +// { +// return a.itemLevel > b.itemLevel; +// } ); +// +// Logger::info( "MarketMgr: Cached " + std::to_string( m_marketItemCache.size() ) + " marketable items" ); return true; } @@ -72,20 +75,21 @@ void Sapphire::World::Manager::MarketMgr::requestItemListingInfo( Sapphire::Enti historyPkt->data().itemCatalogId = catalogId; historyPkt->data().itemCatalogId2 = catalogId; - memset( &historyPkt->data().listing, 0x0, sizeof( Server::FFXIVIpcMarketBoardItemListingHistory::MarketListing ) * 20 ); + std::string name = "fix game pls se :((("; - std::string name = "fix game"; - - for( int i = 0; i < 10; ++i ) + for( int i = 0; i < 10; i++ ) { auto& listing = historyPkt->data().listing[ i ]; listing.itemCatalogId = catalogId; - listing.quantity = i; + listing.quantity = i + 1; listing.purchaseTime = time( nullptr ); - listing.salePrice = 500; + listing.salePrice = 69420420; + listing.isHq = 1; + listing.onMannequin = 1; - strcpy( listing.sellerName, name.c_str() ); + + strcpy( listing.buyerName, name.c_str() ); } player.queuePacket( historyPkt ); @@ -119,7 +123,7 @@ void Sapphire::World::Manager::MarketMgr::searchMarketboard( Entity::Player& pla data.itemCatalogId = item.catalogId; data.quantity = item.quantity; - data.demand = 69; + data.demand = 420; } if( size < 20 ) @@ -132,7 +136,7 @@ void Sapphire::World::Manager::MarketMgr::searchMarketboard( Entity::Player& pla void Sapphire::World::Manager::MarketMgr::requestItemListings( Sapphire::Entity::Player& player, uint16_t catalogId ) { - + } void Sapphire::World::Manager::MarketMgr::findItems( const std::string_view& searchStr, uint8_t itemSearchCat,