From d0d776161be99990a6b970dbc2d59e28531c6711 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sat, 22 Dec 2018 21:20:12 +1100 Subject: [PATCH 01/40] show error messages in the event of an invalid house appearance inv --- src/world/Manager/HousingMgr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 50138589..1be326fd 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -683,6 +683,10 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr house->setHousePart( static_cast< Common::HousePartSlot >( item.first ), getItemData( item.second->getId() ) ); } } + else + { + g_fw.get< Logger >()->error( "Plot " + std::to_string( house->getLandIdent().landId ) + " has an invalid inventory configuration for outdoor appearance." ); + } auto intContainer = containers.find( static_cast< uint16_t >( InventoryType::HousingInteriorAppearance ) ); if( intContainer != containers.end() ) @@ -692,4 +696,8 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr house->setHouseInteriorPart( static_cast< Common::HousingInteriorSlot >( item.first ), getItemData( item.second->getId() ) ); } } + else + { + g_fw.get< Logger >()->error( "Plot " + std::to_string( house->getLandIdent().landId ) + " has an invalid inventory configuration for indoor appearance." ); + } } From b9fe2b33f9ae3a6f8b856c4542f77bfa612f0dbc Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sat, 22 Dec 2018 23:33:38 +1100 Subject: [PATCH 02/40] refactor housepart to housemodel --- src/world/Manager/HousingMgr.cpp | 5 ++- src/world/Territory/House.cpp | 12 +++--- src/world/Territory/House.h | 12 +++--- .../Housing/HousingInteriorTerritory.cpp | 3 +- src/world/Territory/Land.cpp | 42 ++++++++++++------- 5 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 1be326fd..cb4ff6f7 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -680,7 +680,7 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { for( auto& item : extContainer->second->getItemMap() ) { - house->setHousePart( static_cast< Common::HousePartSlot >( item.first ), getItemData( item.second->getId() ) ); + house->setHouseModel( static_cast< Common::HousePartSlot >( item.first ), getItemData( item.second->getId() ) ); } } else @@ -693,7 +693,8 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { for( auto& item : intContainer->second->getItemMap() ) { - house->setHouseInteriorPart( static_cast< Common::HousingInteriorSlot >( item.first ), getItemData( item.second->getId() ) ); + house->setHouseInteriorModel( static_cast< Common::HousingInteriorSlot >( item.first ), + getItemData( item.second->getId() ) ); } } else diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index 404f9f47..ebacabe0 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -60,32 +60,32 @@ uint32_t Sapphire::House::getHouseId() const return m_houseId; } -uint8_t Sapphire::House::getHousePartColor( Common::HousePartSlot slot ) const +uint8_t Sapphire::House::getHouseModelColor( Common::HousePartSlot slot ) const { return m_houseModelsCache[ slot ].second; } -uint32_t Sapphire::House::getHouseInteriorPart( Common::HousingInteriorSlot slot ) const +uint32_t Sapphire::House::getHouseInteriorModel( Common::HousingInteriorSlot slot ) const { return m_houseInteriorModels[ slot ]; } -void Sapphire::House::setHousePart( Common::HousePartSlot slot, uint32_t id ) +void Sapphire::House::setHouseModel( Common::HousePartSlot slot, uint32_t id ) { m_houseModelsCache[ slot ].first = id; } -void Sapphire::House::setHousePartColor( Common::HousePartSlot slot, uint32_t id ) +void Sapphire::House::setHouseModelColor( Common::HousePartSlot slot, uint32_t id ) { m_houseModelsCache[ slot ].second = id; } -void Sapphire::House::setHouseInteriorPart( Common::HousingInteriorSlot slot, uint32_t id ) +void Sapphire::House::setHouseInteriorModel( Common::HousingInteriorSlot slot, uint32_t id ) { m_houseInteriorModels[ slot ] = id; } -uint32_t Sapphire::House::getHousePart( Common::HousePartSlot slot ) const +uint32_t Sapphire::House::getHouseModel( Common::HousePartSlot slot ) const { return m_houseModelsCache[ slot ].first; } diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index f4c71817..c45e30db 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -31,12 +31,12 @@ namespace Sapphire void setHouseGreeting( const std::string& greeting ); //functions - void setHousePart( Common::HousePartSlot slot, uint32_t id ); - void setHousePartColor( Common::HousePartSlot slot, uint32_t id ); - void setHouseInteriorPart( Common::HousingInteriorSlot slot, uint32_t id ); - uint32_t getHousePart( Common::HousePartSlot slot ) const; - uint8_t getHousePartColor( Common::HousePartSlot slot ) const; - uint32_t getHouseInteriorPart( Common::HousingInteriorSlot slot ) const; + void setHouseModel( Common::HousePartSlot slot, uint32_t id ); + void setHouseModelColor( Common::HousePartSlot slot, uint32_t id ); + void setHouseInteriorModel( Common::HousingInteriorSlot slot, uint32_t id ); + uint32_t getHouseModel( Common::HousePartSlot slot ) const; + uint8_t getHouseModelColor( Common::HousePartSlot slot ) const; + uint32_t getHouseInteriorModel( Common::HousingInteriorSlot slot ) const; HouseModelsArray const& getHouseModels() const; diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index da5c399d..e1b87f46 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -68,7 +68,8 @@ void Housing::HousingInteriorTerritory::onPlayerZoneIn( Entity::Player& player ) for( auto i = 0; i < 10; i++ ) { - indoorInitPacket->data().indoorItems[ i ] = pHouse->getHouseInteriorPart( static_cast< Common::HousingInteriorSlot >( i ) ); + indoorInitPacket->data().indoorItems[ i ] = pHouse->getHouseInteriorModel( + static_cast< Common::HousingInteriorSlot >( i ) ); } diff --git a/src/world/Territory/Land.cpp b/src/world/Territory/Land.cpp index 4a1d075a..aaa4ef63 100644 --- a/src/world/Territory/Land.cpp +++ b/src/world/Territory/Land.cpp @@ -313,21 +313,35 @@ bool Sapphire::Land::setPreset( uint32_t itemId ) } - getHouse()->setHousePart( Common::HousePartSlot::ExteriorRoof, convertItemIdToHousingItemId( housingPreset->exteriorRoof ) ); - getHouse()->setHousePart( Common::HousePartSlot::ExteriorWall, convertItemIdToHousingItemId( housingPreset->exteriorWall ) ); - getHouse()->setHousePart( Common::HousePartSlot::ExteriorWindow, convertItemIdToHousingItemId( housingPreset->exteriorWindow ) ); - getHouse()->setHousePart( Common::HousePartSlot::ExteriorDoor, convertItemIdToHousingItemId( housingPreset->exteriorDoor ) ); + getHouse()->setHouseModel( Common::HousePartSlot::ExteriorRoof, + convertItemIdToHousingItemId( housingPreset->exteriorRoof ) ); + getHouse()->setHouseModel( Common::HousePartSlot::ExteriorWall, + convertItemIdToHousingItemId( housingPreset->exteriorWall ) ); + getHouse()->setHouseModel( Common::HousePartSlot::ExteriorWindow, + convertItemIdToHousingItemId( housingPreset->exteriorWindow ) ); + getHouse()->setHouseModel( Common::HousePartSlot::ExteriorDoor, + convertItemIdToHousingItemId( housingPreset->exteriorDoor ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorWall, convertItemIdToHousingItemId( housingPreset->interiorWall ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorFloor, convertItemIdToHousingItemId( housingPreset->interiorFlooring ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorLight, convertItemIdToHousingItemId( housingPreset->interiorLighting ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorWall_Attic, convertItemIdToHousingItemId( housingPreset->otherFloorWall ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorFloor_Attic, convertItemIdToHousingItemId( housingPreset->otherFloorFlooring ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorLight_Attic, convertItemIdToHousingItemId( housingPreset->otherFloorLighting ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorWall_Basement, convertItemIdToHousingItemId( housingPreset->basementWall ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorFloor_Basement, convertItemIdToHousingItemId( housingPreset->basementFlooring ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorLight_Basement, convertItemIdToHousingItemId( housingPreset->basementLighting ) ); - getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorLight_Mansion, convertItemIdToHousingItemId( housingPreset->mansionLighting ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall, + convertItemIdToHousingItemId( housingPreset->interiorWall ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor, + convertItemIdToHousingItemId( housingPreset->interiorFlooring ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight, + convertItemIdToHousingItemId( housingPreset->interiorLighting ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall_Attic, + convertItemIdToHousingItemId( housingPreset->otherFloorWall ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor_Attic, + convertItemIdToHousingItemId( housingPreset->otherFloorFlooring ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Attic, + convertItemIdToHousingItemId( housingPreset->otherFloorLighting ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall_Basement, + convertItemIdToHousingItemId( housingPreset->basementWall ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor_Basement, + convertItemIdToHousingItemId( housingPreset->basementFlooring ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Basement, + convertItemIdToHousingItemId( housingPreset->basementLighting ) ); + getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Mansion, + convertItemIdToHousingItemId( housingPreset->mansionLighting ) ); return true; From ce5389098518f6b7473b0bd31c11d6c90232147a Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sat, 22 Dec 2018 23:39:07 +1100 Subject: [PATCH 03/40] cleanup old house cols from db schema --- bin/sql/schema/schema.sql | 3 --- 1 file changed, 3 deletions(-) diff --git a/bin/sql/schema/schema.sql b/bin/sql/schema/schema.sql index 185d0225..0b3cfba4 100644 --- a/bin/sql/schema/schema.sql +++ b/bin/sql/schema/schema.sql @@ -404,9 +404,6 @@ CREATE TABLE `house` ( `Comment` binary(193) DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', `HouseName` binary(23) DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', `Endorsements` bigint(20) DEFAULT NULL, - `HousePartModels` binary(32) DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', - `HousePartColours` binary(8) DEFAULT '\0\0\0\0\0\0\0\0', - `HouseInteriorModels` binary(40) DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', `UPDATE_DATE` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(`HouseId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; From 50ddcbb1805b2871d2fe8043f4f14d8d7f7ae80c Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 23 Dec 2018 15:23:22 +1100 Subject: [PATCH 04/40] cleanup and simplify model cache logic for houses --- src/world/Manager/HousingMgr.cpp | 9 +-- src/world/Manager/HousingMgr.h | 2 +- src/world/Territory/House.cpp | 56 +++++++----------- src/world/Territory/House.h | 17 +++--- .../Housing/HousingInteriorTerritory.cpp | 2 +- src/world/Territory/HousingZone.cpp | 2 +- src/world/Territory/Land.cpp | 58 +++++++++---------- 7 files changed, 67 insertions(+), 79 deletions(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index cb4ff6f7..683d5eb2 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -662,7 +662,7 @@ Sapphire::World::Manager::HousingMgr::ContainerIdToContainerMap& return getEstateInventory( u64ident ); } -void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr house ) +void Sapphire::World::Manager::HousingMgr::updateHouseModelsFromDb( Sapphire::HousePtr house ) { assert( house ); @@ -680,7 +680,8 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { for( auto& item : extContainer->second->getItemMap() ) { - house->setHouseModel( static_cast< Common::HousePartSlot >( item.first ), getItemData( item.second->getId() ) ); + house->setExteriorModel( static_cast< Common::HousePartSlot >( item.first ), + getItemData( item.second->getId() ), item.second->getStain() ); } } else @@ -693,8 +694,8 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { for( auto& item : intContainer->second->getItemMap() ) { - house->setHouseInteriorModel( static_cast< Common::HousingInteriorSlot >( item.first ), - getItemData( item.second->getId() ) ); + house->setInteriorModel( static_cast< Common::HousingInteriorSlot >( item.first ), + getItemData( item.second->getId() ) ); } } else diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index d0c59a6c..73884044 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -97,7 +97,7 @@ namespace Sapphire::World::Manager * * @param house The house to update the models for */ - void updateHouseModels( HousePtr house ); + void updateHouseModelsFromDb( HousePtr house ); /*! * @brief Sends the house inventory for the specified type to a player. diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index ebacabe0..09802a5f 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -20,9 +20,7 @@ Sapphire::House::House( uint32_t houseId, uint32_t landSetId, Common::LandIdent m_landIdent( ident ), m_estateName( estateName ), m_estateComment( estateComment ) -{ - -} +{} Sapphire::House::~House() = default; @@ -60,39 +58,9 @@ uint32_t Sapphire::House::getHouseId() const return m_houseId; } -uint8_t Sapphire::House::getHouseModelColor( Common::HousePartSlot slot ) const -{ - return m_houseModelsCache[ slot ].second; -} - -uint32_t Sapphire::House::getHouseInteriorModel( Common::HousingInteriorSlot slot ) const -{ - return m_houseInteriorModels[ slot ]; -} - -void Sapphire::House::setHouseModel( Common::HousePartSlot slot, uint32_t id ) -{ - m_houseModelsCache[ slot ].first = id; -} - -void Sapphire::House::setHouseModelColor( Common::HousePartSlot slot, uint32_t id ) -{ - m_houseModelsCache[ slot ].second = id; -} - -void Sapphire::House::setHouseInteriorModel( Common::HousingInteriorSlot slot, uint32_t id ) -{ - m_houseInteriorModels[ slot ] = id; -} - -uint32_t Sapphire::House::getHouseModel( Common::HousePartSlot slot ) const -{ - return m_houseModelsCache[ slot ].first; -} - Sapphire::House::HouseModelsArray const& Sapphire::House::getHouseModels() const { - return m_houseModelsCache; + return m_exteriorModelCache; } const std::string& Sapphire::House::getHouseName() const @@ -117,4 +85,24 @@ void Sapphire::House::setHouseName( const std::string& name ) m_estateName = name; updateHouseDb(); +} + +void Sapphire::House::setExteriorModel( Sapphire::Common::HousePartSlot slot, uint32_t modelId, uint16_t stain ) +{ + m_exteriorModelCache[ slot ] = std::make_pair( modelId, stain ); +} + +Sapphire::House::HousePart Sapphire::House::getExteriorModel( Sapphire::Common::HousePartSlot slot ) +{ + return m_exteriorModelCache[ slot ]; +} + +void Sapphire::House::setInteriorModel( Sapphire::Common::HousingInteriorSlot slot, uint32_t modelId ) +{ + m_interiorModelCache[ slot ] = modelId; +} + +uint32_t Sapphire::House::getInteriorModel( Sapphire::Common::HousingInteriorSlot slot ) +{ + return m_interiorModelCache[ slot ]; } \ No newline at end of file diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index c45e30db..ce73088b 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -16,7 +16,7 @@ namespace Sapphire const std::string& estateComment ); virtual ~House(); - using HousePart = std::pair< uint32_t, uint8_t >; + using HousePart = std::pair< uint32_t, uint16_t >; using HouseModelsArray = std::array< HousePart, 8 >; //gerneral @@ -31,12 +31,11 @@ namespace Sapphire void setHouseGreeting( const std::string& greeting ); //functions - void setHouseModel( Common::HousePartSlot slot, uint32_t id ); - void setHouseModelColor( Common::HousePartSlot slot, uint32_t id ); - void setHouseInteriorModel( Common::HousingInteriorSlot slot, uint32_t id ); - uint32_t getHouseModel( Common::HousePartSlot slot ) const; - uint8_t getHouseModelColor( Common::HousePartSlot slot ) const; - uint32_t getHouseInteriorModel( Common::HousingInteriorSlot slot ) const; + void setExteriorModel( Common::HousePartSlot slot, uint32_t modelId, uint16_t stain ); + HousePart getExteriorModel( Common::HousePartSlot slot ); + + void setInteriorModel( Common::HousingInteriorSlot slot, uint32_t modelId ); + uint32_t getInteriorModel( Common::HousingInteriorSlot slot ); HouseModelsArray const& getHouseModels() const; @@ -49,8 +48,8 @@ namespace Sapphire uint64_t m_buildTime; - HouseModelsArray m_houseModelsCache; - uint32_t m_houseInteriorModels[10]; + HouseModelsArray m_exteriorModelCache; + uint32_t m_interiorModelCache[10]; std::string m_estateComment; std::string m_estateName; diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index e1b87f46..f7487ee6 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -68,7 +68,7 @@ void Housing::HousingInteriorTerritory::onPlayerZoneIn( Entity::Player& player ) for( auto i = 0; i < 10; i++ ) { - indoorInitPacket->data().indoorItems[ i ] = pHouse->getHouseInteriorModel( + indoorInitPacket->data().indoorItems[ i ] = pHouse->getInteriorModel( static_cast< Common::HousingInteriorSlot >( i ) ); } diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 075059e2..9e9d6e51 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -85,7 +85,7 @@ bool Sapphire::HousingZone::init() { auto house = make_House( entry.m_houseId, m_landSetId, land->getLandIdent(), entry.m_estateName, entry.m_estateComment ); - housingMgr->updateHouseModels( house ); + housingMgr->updateHouseModelsFromDb( house ); land->setHouse( house ); } diff --git a/src/world/Territory/Land.cpp b/src/world/Territory/Land.cpp index aaa4ef63..9aed4973 100644 --- a/src/world/Territory/Land.cpp +++ b/src/world/Territory/Land.cpp @@ -313,35 +313,35 @@ bool Sapphire::Land::setPreset( uint32_t itemId ) } - getHouse()->setHouseModel( Common::HousePartSlot::ExteriorRoof, - convertItemIdToHousingItemId( housingPreset->exteriorRoof ) ); - getHouse()->setHouseModel( Common::HousePartSlot::ExteriorWall, - convertItemIdToHousingItemId( housingPreset->exteriorWall ) ); - getHouse()->setHouseModel( Common::HousePartSlot::ExteriorWindow, - convertItemIdToHousingItemId( housingPreset->exteriorWindow ) ); - getHouse()->setHouseModel( Common::HousePartSlot::ExteriorDoor, - convertItemIdToHousingItemId( housingPreset->exteriorDoor ) ); - - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall, - convertItemIdToHousingItemId( housingPreset->interiorWall ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor, - convertItemIdToHousingItemId( housingPreset->interiorFlooring ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight, - convertItemIdToHousingItemId( housingPreset->interiorLighting ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall_Attic, - convertItemIdToHousingItemId( housingPreset->otherFloorWall ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor_Attic, - convertItemIdToHousingItemId( housingPreset->otherFloorFlooring ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Attic, - convertItemIdToHousingItemId( housingPreset->otherFloorLighting ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall_Basement, - convertItemIdToHousingItemId( housingPreset->basementWall ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor_Basement, - convertItemIdToHousingItemId( housingPreset->basementFlooring ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Basement, - convertItemIdToHousingItemId( housingPreset->basementLighting ) ); - getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Mansion, - convertItemIdToHousingItemId( housingPreset->mansionLighting ) ); +// getHouse()->setHouseModel( Common::HousePartSlot::ExteriorRoof, +// convertItemIdToHousingItemId( housingPreset->exteriorRoof ) ); +// getHouse()->setHouseModel( Common::HousePartSlot::ExteriorWall, +// convertItemIdToHousingItemId( housingPreset->exteriorWall ) ); +// getHouse()->setHouseModel( Common::HousePartSlot::ExteriorWindow, +// convertItemIdToHousingItemId( housingPreset->exteriorWindow ) ); +// getHouse()->setHouseModel( Common::HousePartSlot::ExteriorDoor, +// convertItemIdToHousingItemId( housingPreset->exteriorDoor ) ); +// +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall, +// convertItemIdToHousingItemId( housingPreset->interiorWall ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor, +// convertItemIdToHousingItemId( housingPreset->interiorFlooring ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight, +// convertItemIdToHousingItemId( housingPreset->interiorLighting ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall_Attic, +// convertItemIdToHousingItemId( housingPreset->otherFloorWall ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor_Attic, +// convertItemIdToHousingItemId( housingPreset->otherFloorFlooring ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Attic, +// convertItemIdToHousingItemId( housingPreset->otherFloorLighting ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall_Basement, +// convertItemIdToHousingItemId( housingPreset->basementWall ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor_Basement, +// convertItemIdToHousingItemId( housingPreset->basementFlooring ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Basement, +// convertItemIdToHousingItemId( housingPreset->basementLighting ) ); +// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Mansion, +// convertItemIdToHousingItemId( housingPreset->mansionLighting ) ); return true; From 2c426b5059afa37292b2e61f391b89712542ed31 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 23 Dec 2018 19:13:30 +1100 Subject: [PATCH 05/40] housing inventories work, parts are loaded from db now plus a shitload of cleanup and refactoring --- bin/sql/schema/schema.sql | 12 +- src/common/Common.h | 4 +- src/common/Database/ZoneDbConnection.cpp | 13 +- src/world/Manager/HousingMgr.cpp | 149 +++++++++++++++++++---- src/world/Manager/HousingMgr.h | 35 +++++- src/world/Manager/InventoryMgr.cpp | 67 ++++++++++ src/world/Manager/InventoryMgr.h | 49 ++++++++ src/world/Territory/House.cpp | 4 +- src/world/Territory/House.h | 4 +- src/world/Territory/HousingZone.cpp | 2 +- src/world/Territory/Land.cpp | 84 +------------ src/world/Territory/Land.h | 3 + 12 files changed, 303 insertions(+), 123 deletions(-) diff --git a/bin/sql/schema/schema.sql b/bin/sql/schema/schema.sql index 0b3cfba4..fba65de1 100644 --- a/bin/sql/schema/schema.sql +++ b/bin/sql/schema/schema.sql @@ -527,13 +527,15 @@ CREATE TABLE `landset` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `houseiteminventory` ( - `LandIdent` BIGINT(20) UNSIGNED NOT NULL, - `ContainerId` INT(10) UNSIGNED NOT NULL, - `ItemId` INT(20) NOT NULL, - `SlotId` INT(10) UNSIGNED NOT NULL, - INDEX `landIdent` (`landIdent`) + `LandIdent` BIGINT(20) UNSIGNED NOT NULL, + `ContainerId` INT(10) UNSIGNED NOT NULL, + `SlotId` INT(10) UNSIGNED NOT NULL, + `ItemId` INT(20) NOT NULL, + PRIMARY KEY (`LandIdent`, `ContainerId`, `SlotId`), + INDEX `landIdent` (`LandIdent`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; + CREATE TABLE `spawngroup` ( `id` int(10) NOT NULL AUTO_INCREMENT, `territoryTypeId` int(5) NOT NULL, diff --git a/src/common/Common.h b/src/common/Common.h index 96e46fc8..b44c67c3 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -248,7 +248,7 @@ namespace Sapphire::Common // housing exterior containers HousingOutdoorPlacedItems = 25001, - HousingOutdoorAppearance = 25000, + HousingExteriorAppearance = 25000, HousingOutdoorStoreroom = 27000, @@ -769,7 +769,7 @@ namespace Sapphire::Common MountSkill = 0xD, }; - enum HousePartSlot + enum HouseExteriorSlot { ExteriorRoof, ExteriorWall, diff --git a/src/common/Database/ZoneDbConnection.cpp b/src/common/Database/ZoneDbConnection.cpp index a19f32d9..e1d66758 100644 --- a/src/common/Database/ZoneDbConnection.cpp +++ b/src/common/Database/ZoneDbConnection.cpp @@ -172,7 +172,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements() /// ITEM GLOBAL prepareStatement( CHARA_ITEMGLOBAL_INS, - "INSERT INTO charaglobalitem ( CharacterId, ItemId, catalogId, UPDATE_DATE ) VALUES ( ?, ?, ?, NOW() );", + "INSERT INTO charaglobalitem ( CharacterId, ItemId, catalogId, stack, UPDATE_DATE ) VALUES ( ?, ?, ?, ?, NOW() );", CONNECTION_BOTH ); /// BNPC TEMPLATES @@ -222,6 +222,17 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements() "ON land.HouseId = house.HouseId;", CONNECTION_SYNC ); + prepareStatement( LAND_INV_UP, + "INSERT INTO houseiteminventory ( LandIdent, ContainerId, SlotId, ItemId ) " + "VALUES ( ?, ?, ?, ? ) " + "ON DUPLICATE KEY UPDATE ItemId = ?;", + CONNECTION_BOTH ); + + prepareStatement( LAND_INV_DEL, + "DELETE FROM houseiteminventory " + "WHERE LandIdent = ? AND ContainerId = ? AND SlotId = ?;", + CONNECTION_BOTH ); + /*prepareStatement( LAND_INS, "INSERT INTO land ( LandSetId ) VALUES ( ? );", CONNECTION_BOTH ); diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 683d5eb2..7680128e 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -91,13 +91,13 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories() while( res->next() ) { //uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t model2, bool isHq - uint64_t ident = res->getUInt64( "LandIdent" ); - uint16_t containerId = res->getUInt16( "ContainerId" ); - uint64_t itemId = res->getUInt64( "ItemId" ); - uint16_t slot = res->getUInt16( "SlotId" ); - uint32_t catalogId = res->getUInt( "catalogId" ); - uint8_t stain = res->getUInt8( "stain" ); - uint64_t characterId = res->getUInt64( "CharacterId" ); + auto ident = res->getUInt64( "LandIdent" ); + auto containerId = res->getUInt16( "ContainerId" ); + auto itemId = res->getUInt64( "ItemId" ); + auto slot = res->getUInt16( "SlotId" ); + auto catalogId = res->getUInt( "catalogId" ); + auto stain = res->getUInt8( "stain" ); + auto characterId = res->getUInt64( "CharacterId" ); auto item = make_Item( itemId, catalogId, 0, 0, 0 ); item->setStain( stain ); @@ -162,6 +162,17 @@ void Sapphire::World::Manager::HousingMgr::loadLandCache() } } +uint64_t Sapphire::World::Manager::HousingMgr::getNextHouseId() +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); + auto pQR = pDb->query( "SELECT MAX( HouseId ) FROM house" ); + + if( !pQR->next() ) + return 0; + + return pQR->getUInt64( 1 ) + 1; +} + uint32_t Sapphire::World::Manager::HousingMgr::toLandSetId( uint16_t territoryTypeId, uint8_t wardId ) const { return ( static_cast< uint32_t >( territoryTypeId ) << 16 ) | wardId; @@ -430,6 +441,86 @@ void Sapphire::World::Manager::HousingMgr::sendEstateGreeting( Entity::Player& p player.queuePacket( greetingPacket ); } +bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& player, LandPtr land, uint32_t presetCatalogId ) +{ + auto house = land->getHouse(); + assert( house ); + + auto itemMax = land->getInventoryItemMax(); + + // type, maxSize, tableName, isMultiStorage + auto intContainer = make_ItemContainer( InventoryType::HousingInteriorAppearance, itemMax.second, "houseiteminventory", true ); + auto extContainer = make_ItemContainer( InventoryType::HousingExteriorAppearance, itemMax.first, "houseiteminventory", true ); + + // add containers to inv collection + auto& houseInventory = getEstateInventory( house->getLandIdent() ); + houseInventory[ InventoryType::HousingInteriorAppearance ] = intContainer; + houseInventory[ InventoryType::HousingExteriorAppearance ] = extContainer; + + auto exdData = g_fw.get< Sapphire::Data::ExdDataGenerated >(); + auto preset = exdData->get< Sapphire::Data::HousingPreset >( getItemAdditionalData( presetCatalogId ) ); + if( !preset ) + return false; + + // high iq shit + auto invMap = std::map< uint16_t, std::map< uint32_t, int32_t > > + { + // external + { + InventoryType::HousingExteriorAppearance, + { + { HouseExteriorSlot::ExteriorRoof, preset->exteriorRoof }, + { HouseExteriorSlot::ExteriorWall, preset->exteriorWall }, + { HouseExteriorSlot::ExteriorWindow, preset->exteriorWindow }, + { HouseExteriorSlot::ExteriorDoor, preset->exteriorDoor } + } + }, + + // internal + { + InventoryType::HousingInteriorAppearance, + { + // lobby/middle floor + { HousingInteriorSlot::InteriorWall, preset->interiorWall }, + { HousingInteriorSlot::InteriorFloor, preset->interiorFlooring }, + { HousingInteriorSlot::InteriorLight, preset->interiorLighting }, + + // attic + { HousingInteriorSlot::InteriorWall_Attic, preset->otherFloorWall }, + { HousingInteriorSlot::InteriorFloor_Attic, preset->otherFloorFlooring }, + { HousingInteriorSlot::InteriorLight_Attic, preset->otherFloorLighting }, + + // basement + { HousingInteriorSlot::InteriorWall_Basement, preset->basementWall }, + { HousingInteriorSlot::InteriorFloor_Basement, preset->basementFlooring }, + { HousingInteriorSlot::InteriorLight_Basement, preset->basementLighting }, + } + } + }; + + auto invMgr = g_fw.get< InventoryMgr >(); + + // create and link items + for( auto& destContainer : invMap ) + { + auto container = houseInventory[ destContainer.first ]; + + for( auto& item : destContainer.second ) + { + auto pItem = invMgr->createItem( player, item.second ); + + container->setItem( item.first, pItem ); + } + + invMgr->saveHousingContainer( land->getLandIdent(), container ); + } + + // lift off + updateHouseModels( house ); + + return true; +} + void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetItem ) { auto hZone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); @@ -447,7 +538,15 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl // todo: check if permit is in inventory and remove one - if( !pLand->setPreset( presetItem ) ) + // create house + auto ident = pLand->getLandIdent(); + auto house = make_House( getNextHouseId(), pLand->getLandSetId(), ident, + "Estate #" + std::to_string( ident.landId + 1 ), "" ); + + pLand->setHouse( house ); + + // create inventory items + if( !initHouseModels( player, pLand, presetItem ) ) return; pLand->setState( HouseState::privateHouse ); @@ -465,7 +564,7 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl player.eventStart( player.getId(), 0x000B0095, Event::EventHandler::EventType::Housing, 1, 1 ); player.playScene( 0x000B0095, 0, SET_BASE | HIDE_HOTBAR , 0, 1, plotNum, nullptr ); - player.setLandFlags( LandFlagsSlot::Private, EstateBuilt, pLand->getLandIdent() ); + player.setLandFlags( LandFlagsSlot::Private, EstateBuilt, ident ); player.sendLandFlagsSlot( LandFlagsSlot::Private ); hZone->registerHouseEntranceEObj( plotNum ); @@ -647,11 +746,7 @@ Sapphire::World::Manager::HousingMgr::LandIdentToInventoryContainerMap& Sapphire::World::Manager::HousingMgr::ContainerIdToContainerMap& Sapphire::World::Manager::HousingMgr::getEstateInventory( uint64_t ident ) { - auto map = m_estateInventories.find( ident ); - - assert( map != m_estateInventories.end() ); - - return map->second; + return m_estateInventories[ ident ]; } Sapphire::World::Manager::HousingMgr::ContainerIdToContainerMap& @@ -662,26 +757,19 @@ Sapphire::World::Manager::HousingMgr::ContainerIdToContainerMap& return getEstateInventory( u64ident ); } -void Sapphire::World::Manager::HousingMgr::updateHouseModelsFromDb( Sapphire::HousePtr house ) +void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr house ) { assert( house ); - auto getItemData = []( uint32_t itemId ) - { - auto pExdData = g_fw.get< Data::ExdDataGenerated >(); - auto info = pExdData->get< Sapphire::Data::Item >( itemId ); - return info->additionalData; - }; + auto& containers = getEstateInventory( house->getLandIdent() ); - auto containers = getEstateInventory( house->getLandIdent() ); - - auto extContainer = containers.find( static_cast< uint16_t >( InventoryType::HousingOutdoorAppearance ) ); + auto extContainer = containers.find( static_cast< uint16_t >( InventoryType::HousingExteriorAppearance ) ); if( extContainer != containers.end() ) { for( auto& item : extContainer->second->getItemMap() ) { - house->setExteriorModel( static_cast< Common::HousePartSlot >( item.first ), - getItemData( item.second->getId() ), item.second->getStain() ); + house->setExteriorModel( static_cast< Common::HouseExteriorSlot >( item.first ), + getItemAdditionalData( item.second->getId() ), item.second->getStain() ); } } else @@ -695,7 +783,7 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModelsFromDb( Sapphire::Ho for( auto& item : intContainer->second->getItemMap() ) { house->setInteriorModel( static_cast< Common::HousingInteriorSlot >( item.first ), - getItemData( item.second->getId() ) ); + getItemAdditionalData( item.second->getId() ) ); } } else @@ -703,3 +791,10 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModelsFromDb( Sapphire::Ho g_fw.get< Logger >()->error( "Plot " + std::to_string( house->getLandIdent().landId ) + " has an invalid inventory configuration for indoor appearance." ); } } + +uint32_t Sapphire::World::Manager::HousingMgr::getItemAdditionalData( uint32_t catalogId ) +{ + auto pExdData = g_fw.get< Data::ExdDataGenerated >(); + auto info = pExdData->get< Sapphire::Data::Item >( catalogId ); + return info->additionalData; +} \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 73884044..4cd07a57 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -18,6 +18,10 @@ namespace Sapphire::World::Manager public: + /*! + * @brief Structure that is generated and filled on world launch. Used to store housing data during init + * so we don't need to query them individually. + */ struct LandCacheEntry { // land table @@ -97,7 +101,7 @@ namespace Sapphire::World::Manager * * @param house The house to update the models for */ - void updateHouseModelsFromDb( HousePtr house ); + void updateHouseModels( HousePtr house ); /*! * @brief Sends the house inventory for the specified type to a player. @@ -131,10 +135,39 @@ namespace Sapphire::World::Manager * @return A map containing container ids to ItemContainerPtr */ ContainerIdToContainerMap& getEstateInventory( Common::LandIdent ident ); + + /** + * @brief Sets up inventories and spawns the base items for the house appearance + * @param land The house to update + */ + bool initHouseModels( Entity::Player& player, LandPtr land, uint32_t presetCatalogId ); + + private: + /*! + * @brief Gets the next available house id + * @return The next available house id + */ + uint64_t getNextHouseId(); + + /*! + * @brief Loads all the land entries from the database and caches them to speed up housing territory init + */ void loadLandCache(); + + /*! + * @brief Loads all the inventories for every estate on the world and sets up their containers + * @return True if it was successful + */ bool loadEstateInventories(); + /*! + * @brief Gets the additionalData field from item.exd for an item + * @param catalogId The item id to lookup in item.exd + * @return The additionalData field from item.exd + */ + uint32_t getItemAdditionalData( uint32_t catalogId ); + LandSetLandCacheMap m_landCache; LandIdentToInventoryContainerMap m_estateInventories; diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index 6529d617..c813a571 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -4,9 +4,17 @@ #include "Actor/Player.h" #include "Inventory/ItemContainer.h" #include "Inventory/Item.h" +#include "Inventory/ItemUtil.h" #include #include +#include +#include + +#include "Framework.h" + +extern Sapphire::Framework g_fw; + using namespace Sapphire::Network::Packets; void Sapphire::World::Manager::InventoryMgr::sendInventoryContainer( Sapphire::Entity::Player& player, @@ -55,4 +63,63 @@ void Sapphire::World::Manager::InventoryMgr::sendInventoryContainer( Sapphire::E containerInfoPacket->data().containerId = container->getId(); player.queuePacket( containerInfoPacket ); +} + +Sapphire::ItemPtr Sapphire::World::Manager::InventoryMgr::createItem( Entity::Player& player, + uint32_t catalogId, uint32_t quantity ) +{ + auto pExdData = g_fw.get< Data::ExdDataGenerated >(); + auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); + auto itemInfo = pExdData->get< Sapphire::Data::Item >( catalogId ); + + if( !itemInfo ) + return nullptr; + + auto item = make_Item( Items::Util::getNextUId(), catalogId, + itemInfo->modelMain, itemInfo->modelSub ); + + item->setStackSize( std::max< uint32_t >( 1, quantity ) ); + + auto stmt = pDb->getPreparedStatement( Db::CHARA_ITEMGLOBAL_INS ); + + stmt->setUInt( 1, player.getId() ); + stmt->setUInt( 2, item->getUId() ); + stmt->setUInt( 3, item->getId() ); + stmt->setUInt( 4, item->getStackSize() ); + + pDb->execute( stmt ); + + return item; +} + +void Sapphire::World::Manager::InventoryMgr::saveHousingContainer( Common::LandIdent ident, + Sapphire::ItemContainerPtr container ) +{ + auto u64ident = *reinterpret_cast< uint64_t* >( &ident ); + + for( auto& item : container->getItemMap() ) + { + saveHousingContainerItem( u64ident, container->getId(), item.first, item.second->getUId() ); + } +} + +void Sapphire::World::Manager::InventoryMgr::saveHousingContainerItem( uint64_t ident, + uint16_t containerId, uint16_t slotId, + uint64_t itemId ) +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); + + auto stmt = pDb->getPreparedStatement( Db::LAND_INV_UP ); + // LandIdent, ContainerId, SlotId, ItemId, ItemId + + stmt->setUInt64( 1, ident ); + stmt->setUInt( 2, containerId ); + stmt->setUInt( 3, slotId ); + stmt->setUInt64( 4, itemId ); + + // see query, we have to pass itemid in twice + // the second time is for the ON DUPLICATE KEY UPDATE condition + stmt->setUInt64( 5, itemId ); + + pDb->execute( stmt ); } \ No newline at end of file diff --git a/src/world/Manager/InventoryMgr.h b/src/world/Manager/InventoryMgr.h index 26fae576..c22c5342 100644 --- a/src/world/Manager/InventoryMgr.h +++ b/src/world/Manager/InventoryMgr.h @@ -9,7 +9,56 @@ namespace Sapphire::World::Manager class InventoryMgr { public: + /*! + * @brief Sends an item container to a player + * + * This does no checks on the container itself. You can send another players inventory to a different + * player if you so wish - not that you should + * + * Automagically manages inventory packet sequencing. + * + * @param player The player to send the container to + * @param container The container to send to the player + */ void sendInventoryContainer( Sapphire::Entity::Player& player, Sapphire::ItemContainerPtr container ); + + /*! + * @brief Creates an item, saves it to the global item table and returns a ptr to the created item + * @param player The player that will 'own' the item + * @param catalogId The ID for the item, see item.exd + * @param quantity how much item to make + * @return An ItemPtr to the newly created item + */ + Sapphire::ItemPtr createItem( Entity::Player& player, uint32_t catalogId, uint32_t quantity = 1 ); + + /*! + * @brief Commits a housing containers contents to the db + * @param ident The identity of the owner of the container + * @param container The container to save to the db + */ + void saveHousingContainer( Common::LandIdent ident, Sapphire::ItemContainerPtr container ); + + /*! + * @brief Update an item in the db + * @param item The item to commit to the db + */ + void updateItem( Sapphire::ItemPtr item ); + + private: + /*! + * @brief Saves an individual item to the db. + * + * This will create a new row in the event the slot doesn't exist in the db, otherwise this + * will overwrite the itemid in the existing row. + * + * @param ident + * @param containerId + * @param slotId + * @param itemId + */ + void saveHousingContainerItem( uint64_t ident, + uint16_t containerId, uint16_t slotId, + uint64_t itemId ); }; } diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index 09802a5f..34718ff7 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -87,12 +87,12 @@ void Sapphire::House::setHouseName( const std::string& name ) updateHouseDb(); } -void Sapphire::House::setExteriorModel( Sapphire::Common::HousePartSlot slot, uint32_t modelId, uint16_t stain ) +void Sapphire::House::setExteriorModel( Sapphire::Common::HouseExteriorSlot slot, uint32_t modelId, uint16_t stain ) { m_exteriorModelCache[ slot ] = std::make_pair( modelId, stain ); } -Sapphire::House::HousePart Sapphire::House::getExteriorModel( Sapphire::Common::HousePartSlot slot ) +Sapphire::House::HousePart Sapphire::House::getExteriorModel( Sapphire::Common::HouseExteriorSlot slot ) { return m_exteriorModelCache[ slot ]; } diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index ce73088b..d0a0e5a3 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -31,8 +31,8 @@ namespace Sapphire void setHouseGreeting( const std::string& greeting ); //functions - void setExteriorModel( Common::HousePartSlot slot, uint32_t modelId, uint16_t stain ); - HousePart getExteriorModel( Common::HousePartSlot slot ); + 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 ); diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 9e9d6e51..075059e2 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -85,7 +85,7 @@ bool Sapphire::HousingZone::init() { auto house = make_House( entry.m_houseId, m_landSetId, land->getLandIdent(), entry.m_estateName, entry.m_estateComment ); - housingMgr->updateHouseModelsFromDb( house ); + housingMgr->updateHouseModels( house ); land->setHouse( house ); } diff --git a/src/world/Territory/Land.cpp b/src/world/Territory/Land.cpp index 9aed4973..3e0abc1b 100644 --- a/src/world/Territory/Land.cpp +++ b/src/world/Territory/Land.cpp @@ -88,25 +88,6 @@ void Sapphire::Land::init( Common::LandType type, uint8_t size, uint8_t state, u default: break; } - - // init item containers -// auto setupContainer = [ this ]( InventoryType type, uint16_t maxSize ) -// { -// m_landInventoryMap[ type ] = make_ItemContainer( type, maxSize, "houseiteminventory", true, true ); -// }; -// -// setupContainer( InventoryType::HousingOutdoorAppearance, 8 ); -// setupContainer( InventoryType::HousingOutdoorPlacedItems, m_maxPlacedExternalItems ); -// setupContainer( InventoryType::HousingOutdoorStoreroom, m_maxPlacedExternalItems ); -// -// setupContainer( InventoryType::HousingInteriorAppearance, 9 ); -// -// // nb: so we're going to store these internally in one container because SE is fucked in the head -// // but when an inventory is requested, we will split them into groups of 50 -// setupContainer( InventoryType::HousingInteriorPlacedItems1, m_maxPlacedInternalItems ); -// setupContainer( InventoryType::HousingInteriorStoreroom1, m_maxPlacedInternalItems ); -// -// loadItemContainerContents(); } uint32_t Sapphire::Land::convertItemIdToHousingItemId( uint32_t itemId ) @@ -281,68 +262,7 @@ void Sapphire::Land::update( uint32_t currTime ) } } -uint32_t Sapphire::Land::getNextHouseId() +Sapphire::Land::InvMaxItemsPair Sapphire::Land::getInventoryItemMax() const { - auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); - auto pQR = pDb->query( "SELECT MAX( HouseId ) FROM house" ); - - if( !pQR->next() ) - return 0; - - return pQR->getUInt( 1 ) + 1; -} - -bool Sapphire::Land::setPreset( uint32_t itemId ) -{ - auto housingItemId = convertItemIdToHousingItemId( itemId ); - - auto exdData = g_fw.get< Sapphire::Data::ExdDataGenerated >(); - if( !exdData ) - return false; - - auto housingPreset = exdData->get< Sapphire::Data::HousingPreset >( housingItemId ); - if( !housingPreset ) - return false; - - if( !getHouse() ) - { - // todo: i guess we'd create a house here? - auto newId = getNextHouseId(); - - m_pHouse = make_House( newId, getLandSetId(), getLandIdent(), "Estate #" + std::to_string( m_landIdent.landId + 1 ), "" ); - } - - -// getHouse()->setHouseModel( Common::HousePartSlot::ExteriorRoof, -// convertItemIdToHousingItemId( housingPreset->exteriorRoof ) ); -// getHouse()->setHouseModel( Common::HousePartSlot::ExteriorWall, -// convertItemIdToHousingItemId( housingPreset->exteriorWall ) ); -// getHouse()->setHouseModel( Common::HousePartSlot::ExteriorWindow, -// convertItemIdToHousingItemId( housingPreset->exteriorWindow ) ); -// getHouse()->setHouseModel( Common::HousePartSlot::ExteriorDoor, -// convertItemIdToHousingItemId( housingPreset->exteriorDoor ) ); -// -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall, -// convertItemIdToHousingItemId( housingPreset->interiorWall ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor, -// convertItemIdToHousingItemId( housingPreset->interiorFlooring ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight, -// convertItemIdToHousingItemId( housingPreset->interiorLighting ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall_Attic, -// convertItemIdToHousingItemId( housingPreset->otherFloorWall ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor_Attic, -// convertItemIdToHousingItemId( housingPreset->otherFloorFlooring ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Attic, -// convertItemIdToHousingItemId( housingPreset->otherFloorLighting ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorWall_Basement, -// convertItemIdToHousingItemId( housingPreset->basementWall ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorFloor_Basement, -// convertItemIdToHousingItemId( housingPreset->basementFlooring ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Basement, -// convertItemIdToHousingItemId( housingPreset->basementLighting ) ); -// getHouse()->setHouseInteriorModel( Common::HousingInteriorSlot::InteriorLight_Mansion, -// convertItemIdToHousingItemId( housingPreset->mansionLighting ) ); - - - return true; + return std::make_pair( m_maxPlacedExternalItems, m_maxPlacedInternalItems ); } \ No newline at end of file diff --git a/src/world/Territory/Land.h b/src/world/Territory/Land.h index 19977e77..e80ff593 100644 --- a/src/world/Territory/Land.h +++ b/src/world/Territory/Land.h @@ -20,6 +20,7 @@ namespace Sapphire void init( Common::LandType type, uint8_t size, uint8_t 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 ); @@ -61,6 +62,8 @@ namespace Sapphire void setLandTag( uint8_t slot, uint8_t tag ); uint8_t getLandTag( uint8_t slot ); + InvMaxItemsPair getInventoryItemMax() const; + private: uint32_t convertItemIdToHousingItemId( uint32_t itemId ); uint32_t getNextHouseId(); From 24520a84915e250f69d9fe2bb27d983ae9038391 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 23 Dec 2018 20:54:21 +1100 Subject: [PATCH 06/40] more refactoring + sql --- src/common/Database/ZoneDbConnection.cpp | 2 +- src/world/Manager/HousingMgr.cpp | 14 ++++++++++++++ src/world/Manager/HousingMgr.h | 1 + src/world/Territory/House.cpp | 2 +- src/world/Territory/House.h | 2 +- src/world/Territory/Land.cpp | 2 +- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/common/Database/ZoneDbConnection.cpp b/src/common/Database/ZoneDbConnection.cpp index e1d66758..fe8c90e9 100644 --- a/src/common/Database/ZoneDbConnection.cpp +++ b/src/common/Database/ZoneDbConnection.cpp @@ -193,7 +193,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements() /// HOUSING prepareStatement( HOUSING_HOUSE_INS, - "INSERT INTO house ( LandSetId, HouseId ) VALUES ( ?, ? );", + "INSERT INTO house ( LandSetId, HouseId, HouseName ) VALUES ( ?, ?, ? );", CONNECTION_BOTH ); prepareStatement( HOUSING_HOUSE_UP, diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 7680128e..f1c4c0f5 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -521,6 +521,20 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play return true; } +void Sapphire::World::Manager::HousingMgr::createHouse( Sapphire::HousePtr house ) const +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); + + auto stmt = pDb->getPreparedStatement( Db::HOUSING_HOUSE_INS ); + // LandSetId, HouseId, HouseName + + stmt->setUInt( 1, house->getLandSetId() ); + stmt->setUInt( 2, house->getId() ); + stmt->setString( 3, house->getHouseName() ); + + pDb->execute( stmt ); +} + void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetItem ) { auto hZone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 4cd07a57..6fcf53b7 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -142,6 +142,7 @@ namespace Sapphire::World::Manager */ bool initHouseModels( Entity::Player& player, LandPtr land, uint32_t presetCatalogId ); + void createHouse( HousePtr house ) const; private: /*! diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index 34718ff7..4e5d3855 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -53,7 +53,7 @@ Sapphire::Common::LandIdent Sapphire::House::getLandIdent() const return m_landIdent; } -uint32_t Sapphire::House::getHouseId() const +uint32_t Sapphire::House::getId() const { return m_houseId; } diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index d0a0e5a3..b307ecd6 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -22,7 +22,7 @@ namespace Sapphire //gerneral uint32_t getLandSetId() const; Common::LandIdent getLandIdent() const; - uint32_t getHouseId() const; + uint32_t getId() const; const std::string& getHouseName() const; void setHouseName( const std::string& name ); diff --git a/src/world/Territory/Land.cpp b/src/world/Territory/Land.cpp index 3e0abc1b..c2e3af65 100644 --- a/src/world/Territory/Land.cpp +++ b/src/world/Territory/Land.cpp @@ -232,7 +232,7 @@ void Sapphire::Land::updateLandDb() uint32_t houseId = 0; if( getHouse() ) - houseId = getHouse()->getHouseId(); + houseId = getHouse()->getId(); // todo: change to prepared statement auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); From b77d4e6ff36243a7d36977acabf51f4206bd2bd7 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 23 Dec 2018 21:00:00 +1100 Subject: [PATCH 07/40] save a newly created house to the db correctly --- src/world/Manager/HousingMgr.cpp | 2 ++ src/world/Manager/HousingMgr.h | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index f1c4c0f5..fd294cef 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -563,6 +563,8 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl if( !initHouseModels( player, pLand, presetItem ) ) return; + createHouse( house ); + pLand->setState( HouseState::privateHouse ); pLand->setLandType( LandType::Private ); hZone->sendLandUpdate( plotNum ); diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 6fcf53b7..82f01262 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -142,9 +142,17 @@ namespace Sapphire::World::Manager */ bool initHouseModels( Entity::Player& player, LandPtr land, uint32_t presetCatalogId ); + private: + + /*! + * @brief Creates a house and saves the minimum amount required to persist a house through restarts. + * + * Any other changes will be covered by the usual saving logic and can be safely ignored here. + * + * @param house The house to create in the house table + */ void createHouse( HousePtr house ) const; - private: /*! * @brief Gets the next available house id * @return The next available house id From b4e0c2a40647f5f1921428affa272735736f4ef1 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 23 Dec 2018 22:43:35 +1100 Subject: [PATCH 08/40] use HousingItem instead of Item for housing inventories --- src/common/Database/ZoneDbConnection.cpp | 7 +++++-- src/world/ForwardsZone.h | 5 +++++ src/world/Inventory/HousingItem.cpp | 25 ++++++++++++++++++++++++ src/world/Inventory/HousingItem.h | 25 ++++++++++++++++++++++++ src/world/Manager/HousingMgr.cpp | 24 +++++++++++------------ src/world/Manager/InventoryMgr.cpp | 2 +- 6 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 src/world/Inventory/HousingItem.cpp create mode 100644 src/world/Inventory/HousingItem.h diff --git a/src/common/Database/ZoneDbConnection.cpp b/src/common/Database/ZoneDbConnection.cpp index fe8c90e9..4fa47ceb 100644 --- a/src/common/Database/ZoneDbConnection.cpp +++ b/src/common/Database/ZoneDbConnection.cpp @@ -201,10 +201,13 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements() CONNECTION_BOTH ); prepareStatement( LAND_INV_SEL_ALL, - "SELECT houseiteminventory.*, charaglobalitem.catalogId, charaglobalitem.stain, charaglobalitem.CharacterId " + "SELECT houseiteminventory.*, charaglobalitem.catalogId, charaglobalitem.stain, charaglobalitem.CharacterId, " + "landplaceditems.PosX, landplaceditems.PosY, landplaceditems.PosZ, landplaceditems.Rotation " "FROM houseiteminventory " "LEFT JOIN charaglobalitem " - "ON houseiteminventory.ItemId = charaglobalitem.itemId;", + "ON houseiteminventory.ItemId = charaglobalitem.itemId " + "LEFT JOIN landplaceditems " + "ON houseiteminventory.ItemId = landplaceditems.ItemId;", CONNECTION_BOTH ); prepareStatement( LAND_INV_SEL_HOUSE, diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index 585eb46c..82ad0e04 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -35,6 +35,11 @@ namespace World::Territory::Housing TYPE_FORWARD( HousingInteriorTerritory ); } +namespace Inventory +{ +TYPE_FORWARD( HousingItem ); +} + namespace World::Manager { TYPE_FORWARD( HousingMgr ); diff --git a/src/world/Inventory/HousingItem.cpp b/src/world/Inventory/HousingItem.cpp new file mode 100644 index 00000000..2b32736e --- /dev/null +++ b/src/world/Inventory/HousingItem.cpp @@ -0,0 +1,25 @@ +#include "HousingItem.h" + +Sapphire::Inventory::HousingItem::HousingItem( uint64_t uId, uint32_t catalogId ) : + Sapphire::Item( uId, catalogId, 0, 0, false ) +{ } + +float Sapphire::Inventory::HousingItem::getRot() const +{ + return m_rotation; +} + +void Sapphire::Inventory::HousingItem::setRot( float rot ) +{ + m_rotation = rot; +} + +Sapphire::Common::FFXIVARR_POSITION3 Sapphire::Inventory::HousingItem::getPos() const +{ + return m_position; +} + +void Sapphire::Inventory::HousingItem::setPos( Sapphire::Common::FFXIVARR_POSITION3 pos ) +{ + m_position = pos; +} \ No newline at end of file diff --git a/src/world/Inventory/HousingItem.h b/src/world/Inventory/HousingItem.h new file mode 100644 index 00000000..83fa20e3 --- /dev/null +++ b/src/world/Inventory/HousingItem.h @@ -0,0 +1,25 @@ +#ifndef SAPPHIRE_HOUSINGITEM_H +#define SAPPHIRE_HOUSINGITEM_H + +#include "Item.h" + +namespace Sapphire::Inventory +{ + class HousingItem : public Item + { + public: + HousingItem( uint64_t uId, uint32_t catalogId ); + + void setRot( float rot ); + float getRot() const; + + void setPos( Common::FFXIVARR_POSITION3 pos ); + Common::FFXIVARR_POSITION3 getPos() const; + + private: + Common::FFXIVARR_POSITION3 m_position; + float m_rotation; + }; +} + +#endif //SAPPHIRE_HOUSINGITEM_H diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index fd294cef..e62f87ec 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -25,7 +25,7 @@ #include "ServerMgr.h" #include "Territory/House.h" #include "InventoryMgr.h" -#include "Inventory/Item.h" +#include "Inventory/HousingItem.h" #include "Inventory/ItemContainer.h" using namespace Sapphire::Common; @@ -91,15 +91,15 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories() while( res->next() ) { //uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t model2, bool isHq - auto ident = res->getUInt64( "LandIdent" ); - auto containerId = res->getUInt16( "ContainerId" ); - auto itemId = res->getUInt64( "ItemId" ); - auto slot = res->getUInt16( "SlotId" ); - auto catalogId = res->getUInt( "catalogId" ); - auto stain = res->getUInt8( "stain" ); - auto characterId = res->getUInt64( "CharacterId" ); + auto ident = res->getUInt64( "LandIdent" ); + auto containerId = res->getUInt16( "ContainerId" ); + auto itemId = res->getUInt64( "ItemId" ); + auto slot = res->getUInt16( "SlotId" ); + auto catalogId = res->getUInt( "catalogId" ); + auto stain = res->getUInt8( "stain" ); + auto characterId = res->getUInt64( "CharacterId" ); - auto item = make_Item( itemId, catalogId, 0, 0, 0 ); + auto item = Inventory::make_HousingItem( itemId, catalogId ); item->setStain( stain ); // todo: need to set the owner character id on the item @@ -739,12 +739,10 @@ void Sapphire::World::Manager::HousingMgr::sendEstateInventory( Entity::Player& if( targetLand->getOwnerId() != player.getId() ) return; - auto container = getEstateInventory( targetLand->getLandIdent() )[ inventoryType ]; - if( !container ) - return; + auto& containers = getEstateInventory( targetLand->getLandIdent() ); auto invMgr = g_fw.get< Manager::InventoryMgr >(); - invMgr->sendInventoryContainer( player, container ); + invMgr->sendInventoryContainer( player, containers[ inventoryType ] ); } const Sapphire::World::Manager::HousingMgr::LandSetLandCacheMap& diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index c813a571..e81b79e0 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -83,7 +83,7 @@ Sapphire::ItemPtr Sapphire::World::Manager::InventoryMgr::createItem( Entity::Pl auto stmt = pDb->getPreparedStatement( Db::CHARA_ITEMGLOBAL_INS ); stmt->setUInt( 1, player.getId() ); - stmt->setUInt( 2, item->getUId() ); + stmt->setUInt64( 2, item->getUId() ); stmt->setUInt( 3, item->getId() ); stmt->setUInt( 4, item->getStackSize() ); From 5ed8281f966598ce98bf7e805554c0cc6e1f8fff Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 23 Dec 2018 23:46:49 +1100 Subject: [PATCH 09/40] update schema --- bin/sql/schema/schema.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bin/sql/schema/schema.sql b/bin/sql/schema/schema.sql index fba65de1..83d777fd 100644 --- a/bin/sql/schema/schema.sql +++ b/bin/sql/schema/schema.sql @@ -563,3 +563,14 @@ CREATE TABLE `zonepositions` ( `radius` int(11) NOT NULL DEFAULT '2', PRIMARY KEY(`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; + +CREATE TABLE `landplaceditems` ( + `ItemId` INT(20) UNSIGNED NOT NULL, + `PosX` FLOAT NOT NULL, + `PosY` FLOAT NOT NULL, + `PosZ` FLOAT NOT NULL, + `Rotation` INT(10) NOT NULL, + PRIMARY KEY (`ItemId`) +) +COLLATE='latin1_swedish_ci' ENGINE=InnoDB; + From 068b840c0ae8fdc963bdf43f52cf635edc1816a2 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 25 Dec 2018 20:11:41 +1100 Subject: [PATCH 10/40] fix an issue where multiple items could get created at the same time subsequently, they would get the same itemid and this would fail --- src/common/Database/ZoneDbConnection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Database/ZoneDbConnection.cpp b/src/common/Database/ZoneDbConnection.cpp index 4fa47ceb..807fe35a 100644 --- a/src/common/Database/ZoneDbConnection.cpp +++ b/src/common/Database/ZoneDbConnection.cpp @@ -173,7 +173,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements() /// ITEM GLOBAL prepareStatement( CHARA_ITEMGLOBAL_INS, "INSERT INTO charaglobalitem ( CharacterId, ItemId, catalogId, stack, UPDATE_DATE ) VALUES ( ?, ?, ?, ?, NOW() );", - CONNECTION_BOTH ); + CONNECTION_SYNC ); /// BNPC TEMPLATES prepareStatement( ZONE_SEL_BNPCTEMPLATES, From 56d78e8c3d01bd5999127bbb3e004c716e9fcbdc Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 25 Dec 2018 20:11:59 +1100 Subject: [PATCH 11/40] fix prepared statement missing a param --- src/api/PlayerMinimal.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/PlayerMinimal.cpp b/src/api/PlayerMinimal.cpp index 1c12470d..c8932f51 100644 --- a/src/api/PlayerMinimal.cpp +++ b/src/api/PlayerMinimal.cpp @@ -409,6 +409,7 @@ void PlayerMinimal::insertDbGlobalItem( uint32_t itemId, uint64_t uniqueId ) con stmtItemGlobal->setInt( 1, m_id ); stmtItemGlobal->setInt64( 2, uniqueId ); stmtItemGlobal->setInt( 3, itemId ); + stmtItemGlobal->setInt( 4, 1 ); // stack of 1 g_charaDb.directExecute( stmtItemGlobal ); } From d9dd3a5114dfa8968694ab3312d96ad109617137 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 25 Dec 2018 20:12:24 +1100 Subject: [PATCH 12/40] minor refactoring, move some more stuff out of land and into housingmgr --- src/world/Manager/HousingMgr.cpp | 55 ++++++++++++++++++++++++++++++-- src/world/Manager/HousingMgr.h | 12 ++++++- src/world/Territory/Land.cpp | 18 ----------- 3 files changed, 64 insertions(+), 21 deletions(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index e62f87ec..5ea6d1e1 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -48,7 +48,7 @@ bool Sapphire::World::Manager::HousingMgr::init() // 18 wards per territory, 4 territories m_landCache.reserve( 18 * 4 ); - loadLandCache(); + initLandCache(); log->debug( "HousingMgr: Checking land counts" ); @@ -103,6 +103,18 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories() item->setStain( stain ); // todo: need to set the owner character id on the item + // set world pos on item if its in an placed item container + if( isPlacedItemsInventory( static_cast< Common::InventoryType >( containerId ) ) ) + { + item->setPos( { + res->getFloat( "PosX" ), + res->getFloat( "PosY" ), + res->getFloat( "PosZ" ) + } ); + + item->setRot( res->getFloat( "Rotation" ) ); + } + ContainerIdToContainerMap& estateInv = m_estateInventories[ ident ]; // check if containerId exists @@ -127,8 +139,9 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories() return true; } -void Sapphire::World::Manager::HousingMgr::loadLandCache() +void Sapphire::World::Manager::HousingMgr::initLandCache() { + auto log = g_fw.get< Sapphire::Logger >(); auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); auto stmt = pDb->getPreparedStatement( Db::LAND_SEL_ALL ); @@ -159,6 +172,33 @@ void Sapphire::World::Manager::HousingMgr::loadLandCache() entry.m_endorsements = res->getUInt64( "Endorsements" ); m_landCache[ entry.m_landSetId ].push_back( entry ); + + uint16_t maxExternalItems = 0; + uint16_t maxInternalItems = 0; + + // init inventory containers + switch( entry.m_size ) + { + case HouseSize::Cottage: + maxExternalItems = 20; + maxInternalItems = 200; + break; + case HouseSize::House: + maxExternalItems = 30; + maxInternalItems = 300; + break; + case HouseSize::Mansion: + maxExternalItems = 40; + maxInternalItems = 400; + break; + default: + // this should never ever happen, if it does the db is fucked + log->error( "HousingMgr: Plot " + std::to_string( entry.m_landId ) + " in landset " + std::to_string( entry.m_landSetId ) + + " has an invalid land size, defaulting to cottage." ); + maxExternalItems = 20; + maxInternalItems = 200; + break; + } } } @@ -811,4 +851,15 @@ uint32_t Sapphire::World::Manager::HousingMgr::getItemAdditionalData( uint32_t c auto pExdData = g_fw.get< Data::ExdDataGenerated >(); auto info = pExdData->get< Sapphire::Data::Item >( catalogId ); return info->additionalData; +} + +bool Sapphire::World::Manager::HousingMgr::isPlacedItemsInventory( Sapphire::Common::InventoryType type ) +{ + return type == InventoryType::HousingOutdoorPlacedItems || + type == InventoryType::HousingInteriorPlacedItems1 || + type == InventoryType::HousingInteriorPlacedItems2 || + type == InventoryType::HousingInteriorPlacedItems3 || + type == InventoryType::HousingInteriorPlacedItems4 || + type == InventoryType::HousingInteriorPlacedItems5 || + type == InventoryType::HousingInteriorPlacedItems6; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 82f01262..08deb2ac 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -162,7 +162,7 @@ namespace Sapphire::World::Manager /*! * @brief Loads all the land entries from the database and caches them to speed up housing territory init */ - void loadLandCache(); + void initLandCache(); /*! * @brief Loads all the inventories for every estate on the world and sets up their containers @@ -177,6 +177,16 @@ namespace Sapphire::World::Manager */ uint32_t getItemAdditionalData( uint32_t catalogId ); + /*! + * @brief Checks whether an estate inventory contains items that are placed and have a world position + * + * Eg, any item inside the 'placed' items container _should_ have a world position and can be spawned. + * + * @param type The inventory type that contains items + * @return true if contains items that would have a world position + */ + bool isPlacedItemsInventory( Common::InventoryType type ); + LandSetLandCacheMap m_landCache; LandIdentToInventoryContainerMap m_estateInventories; diff --git a/src/world/Territory/Land.cpp b/src/world/Territory/Land.cpp index c2e3af65..e9d6fa5a 100644 --- a/src/world/Territory/Land.cpp +++ b/src/world/Territory/Land.cpp @@ -70,24 +70,6 @@ void Sapphire::Land::init( Common::LandType type, uint8_t size, uint8_t state, u m_mapMarkerPosition.y = info->y; m_mapMarkerPosition.z = info->z; } - - switch( m_size ) - { - case HouseSize::Cottage: - m_maxPlacedExternalItems = 20; - m_maxPlacedInternalItems = 200; - break; - case HouseSize::House: - m_maxPlacedExternalItems = 30; - m_maxPlacedInternalItems = 300; - break; - case HouseSize::Mansion: - m_maxPlacedExternalItems = 40; - m_maxPlacedInternalItems = 400; - break; - default: - break; - } } uint32_t Sapphire::Land::convertItemIdToHousingItemId( uint32_t itemId ) From a66b9372009bbdd588da92b8bb65e98d470c6ddf Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 25 Dec 2018 21:05:13 +1100 Subject: [PATCH 13/40] create all estate inventories on launch --- src/common/Common.h | 8 +- src/world/Manager/HousingMgr.cpp | 85 ++++++++++++++----- src/world/Manager/HousingMgr.h | 7 +- .../Network/Handlers/ClientTriggerHandler.cpp | 4 +- 4 files changed, 76 insertions(+), 28 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index b44c67c3..caed668e 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -225,13 +225,15 @@ namespace Sapphire::Common // housing interior containers HousingInteriorAppearance = 25002, - // 50 in each container max, 300 slots max + // 50 in each container max, 400 slots max HousingInteriorPlacedItems1 = 25003, HousingInteriorPlacedItems2 = 25004, HousingInteriorPlacedItems3 = 25005, HousingInteriorPlacedItems4 = 25006, HousingInteriorPlacedItems5 = 25007, HousingInteriorPlacedItems6 = 25008, + HousingInteriorPlacedItems7 = 25009, + HousingInteriorPlacedItems8 = 25010, // 50 max per container, 400 slots max // slot limit increased 'temporarily' for relocation for all estates @@ -247,9 +249,9 @@ namespace Sapphire::Common // housing exterior containers - HousingOutdoorPlacedItems = 25001, + HousingExteriorPlacedItems = 25001, HousingExteriorAppearance = 25000, - HousingOutdoorStoreroom = 27000, + HousingExteriorStoreroom = 27000, }; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 5ea6d1e1..44dfc5c3 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -35,7 +35,18 @@ using namespace Sapphire::Network::Packets::Server; extern Sapphire::Framework g_fw; -Sapphire::World::Manager::HousingMgr::HousingMgr() = default; +Sapphire::World::Manager::HousingMgr::HousingMgr() +{ + m_containerMap[ 0 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + m_containerMap[ 1 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + m_containerMap[ 2 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + m_containerMap[ 3 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + m_containerMap[ 4 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + m_containerMap[ 5 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + m_containerMap[ 6 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + m_containerMap[ 7 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); +} + Sapphire::World::Manager::HousingMgr::~HousingMgr() = default; bool Sapphire::World::Manager::HousingMgr::init() @@ -117,19 +128,11 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories() ContainerIdToContainerMap& estateInv = m_estateInventories[ ident ]; - // check if containerId exists + // check if containerId exists, it always should - if it doesn't, something went wrong auto container = estateInv.find( containerId ); - if( container == estateInv.end() ) - { - // create container - // todo: how to handle this max slot stuff? override it on land init? - auto ic = make_ItemContainer( containerId, 400, "houseiteminventory", true ); - ic->setItem( slot, item ); + assert( container != estateInv.end() ); - estateInv[ containerId ] = ic; - } - else - container->second->setItem( slot, item ); + container->second->setItem( slot, item ); itemCount++; } @@ -153,7 +156,7 @@ void Sapphire::World::Manager::HousingMgr::initLandCache() // land stuff entry.m_landSetId = res->getUInt64( "LandSetId" ); - entry.m_landId = res->getUInt64( "LandId" ); + entry.m_landId = res->getUInt( "LandId" ); entry.m_type = static_cast< Common::LandType >( res->getUInt( "Type" ) ); entry.m_size = res->getUInt8( "Size" ); @@ -180,25 +183,63 @@ void Sapphire::World::Manager::HousingMgr::initLandCache() switch( entry.m_size ) { case HouseSize::Cottage: - maxExternalItems = 20; - maxInternalItems = 200; + entry.m_maxPlacedExternalItems = 20; + entry.m_maxPlacedInternalItems = 200; break; case HouseSize::House: - maxExternalItems = 30; - maxInternalItems = 300; + entry.m_maxPlacedExternalItems = 30; + entry.m_maxPlacedInternalItems = 300; break; case HouseSize::Mansion: - maxExternalItems = 40; - maxInternalItems = 400; + entry.m_maxPlacedExternalItems = 40; + entry.m_maxPlacedInternalItems = 400; break; default: // this should never ever happen, if it does the db is fucked log->error( "HousingMgr: Plot " + std::to_string( entry.m_landId ) + " in landset " + std::to_string( entry.m_landSetId ) + " has an invalid land size, defaulting to cottage." ); - maxExternalItems = 20; - maxInternalItems = 200; + entry.m_maxPlacedExternalItems = 20; + entry.m_maxPlacedInternalItems = 200; break; } + + // setup containers + // todo: this is pretty garbage + Common::LandIdent ident; + ident.territoryTypeId = entry.m_landSetId >> 16; + ident.wardNum = entry.m_landSetId & 0xFFFF; + ident.landId = entry.m_landId; + ident.worldId = 67; + + auto& containers = getEstateInventory( ident ); + + auto makeContainer = [ &containers ]( Common::InventoryType type, uint16_t size ) + { + containers[ type ] = make_ItemContainer( type, size, "houseiteminventory", true ); + }; + + uint16_t count = 0; + for( int i = 0; i < 8; ++i ) + { + if( count >= entry.m_maxPlacedInternalItems ) + break; + + auto& pair = m_containerMap[ i ]; + + makeContainer( pair.first, 50 ); + makeContainer( pair.second, 50 ); + + count += 50; + } + + // exterior + makeContainer( InventoryType::HousingExteriorPlacedItems, entry.m_maxPlacedExternalItems ); + makeContainer( InventoryType::HousingExteriorStoreroom, entry.m_maxPlacedExternalItems ); + + // fixed containers + makeContainer( InventoryType::HousingInteriorAppearance, 10 ); + makeContainer( InventoryType::HousingExteriorAppearance, 8 ); + } } @@ -855,7 +896,7 @@ uint32_t Sapphire::World::Manager::HousingMgr::getItemAdditionalData( uint32_t c bool Sapphire::World::Manager::HousingMgr::isPlacedItemsInventory( Sapphire::Common::InventoryType type ) { - return type == InventoryType::HousingOutdoorPlacedItems || + return type == InventoryType::HousingExteriorPlacedItems || type == InventoryType::HousingInteriorPlacedItems1 || type == InventoryType::HousingInteriorPlacedItems2 || type == InventoryType::HousingInteriorPlacedItems3 || diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 08deb2ac..8413f8e2 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -26,7 +26,7 @@ namespace Sapphire::World::Manager { // land table uint64_t m_landSetId; - uint64_t m_landId; + uint16_t m_landId; Common::LandType m_type; uint8_t m_size; @@ -46,6 +46,9 @@ namespace Sapphire::World::Manager uint64_t m_buildTime; uint64_t m_endorsements; + + uint16_t m_maxPlacedExternalItems; + uint16_t m_maxPlacedInternalItems; }; /*! @@ -190,6 +193,8 @@ namespace Sapphire::World::Manager LandSetLandCacheMap m_landCache; LandIdentToInventoryContainerMap m_estateInventories; + std::array< std::pair< Common::InventoryType, Common::InventoryType >, 8 > m_containerMap; + }; } diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index e61e168d..157739eb 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -430,9 +430,9 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX if( !housingMgr ) break; - uint16_t inventoryType = Common::InventoryType::HousingOutdoorPlacedItems; + uint16_t inventoryType = Common::InventoryType::HousingExteriorPlacedItems; if( param2 == 1 ) - inventoryType = Common::InventoryType::HousingOutdoorStoreroom; + inventoryType = Common::InventoryType::HousingExteriorStoreroom; housingMgr->sendEstateInventory( player, inventoryType, plot ); From 0a4c8b37d721e343b28f1dbd66fb3f95082ba690 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 25 Dec 2018 21:40:02 +1100 Subject: [PATCH 14/40] Fix items being created incorrectly for small plots --- src/world/Manager/HousingMgr.cpp | 4 ++++ src/world/Manager/InventoryMgr.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 44dfc5c3..6fed6521 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -588,6 +588,10 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play for( auto& item : destContainer.second ) { + // small houses attic is just 0, ignore them + if( item.second == 0 ) + continue; + auto pItem = invMgr->createItem( player, item.second ); container->setItem( item.first, pItem ); diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index e81b79e0..deca4b48 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -87,7 +87,7 @@ Sapphire::ItemPtr Sapphire::World::Manager::InventoryMgr::createItem( Entity::Pl stmt->setUInt( 3, item->getId() ); stmt->setUInt( 4, item->getStackSize() ); - pDb->execute( stmt ); + pDb->directExecute( stmt ); return item; } From b624237731d7f5c3075cdcaca949c988126b97c8 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 25 Dec 2018 21:53:05 +1100 Subject: [PATCH 15/40] remove model params from item constructor --- src/common/Common.h | 2 +- src/world/Actor/PlayerSql.cpp | 5 +---- src/world/Inventory/HousingItem.cpp | 2 +- src/world/Inventory/Item.cpp | 6 +++--- src/world/Inventory/Item.h | 2 +- src/world/Inventory/ItemUtil.cpp | 6 +----- src/world/Manager/InventoryMgr.cpp | 3 +-- 7 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index caed668e..5fb1a59c 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -249,8 +249,8 @@ namespace Sapphire::Common // housing exterior containers - HousingExteriorPlacedItems = 25001, HousingExteriorAppearance = 25000, + HousingExteriorPlacedItems = 25001, HousingExteriorStoreroom = 27000, diff --git a/src/world/Actor/PlayerSql.cpp b/src/world/Actor/PlayerSql.cpp index 136ddd40..1aeb33ee 100644 --- a/src/world/Actor/PlayerSql.cpp +++ b/src/world/Actor/PlayerSql.cpp @@ -580,10 +580,7 @@ Sapphire::ItemPtr Sapphire::Entity::Player::createItem( uint32_t catalogId, uint uint8_t flags = 0; - ItemPtr pItem = make_Item( Items::Util::getNextUId(), - catalogId, - itemInfo->modelMain, - itemInfo->modelSub ); + ItemPtr pItem = make_Item( Items::Util::getNextUId(), catalogId ); pItem->setStackSize( quantity ); diff --git a/src/world/Inventory/HousingItem.cpp b/src/world/Inventory/HousingItem.cpp index 2b32736e..139e5e94 100644 --- a/src/world/Inventory/HousingItem.cpp +++ b/src/world/Inventory/HousingItem.cpp @@ -1,7 +1,7 @@ #include "HousingItem.h" Sapphire::Inventory::HousingItem::HousingItem( uint64_t uId, uint32_t catalogId ) : - Sapphire::Item( uId, catalogId, 0, 0, false ) + Sapphire::Item( uId, catalogId, false ) { } float Sapphire::Inventory::HousingItem::getRot() const diff --git a/src/world/Inventory/Item.cpp b/src/world/Inventory/Item.cpp index 5421f355..c3199ef5 100644 --- a/src/world/Inventory/Item.cpp +++ b/src/world/Inventory/Item.cpp @@ -7,11 +7,9 @@ extern Sapphire::Framework g_fw; -Sapphire::Item::Item( uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t model2, bool isHq ) : +Sapphire::Item::Item( uint64_t uId, uint32_t catalogId, bool isHq ) : m_id( catalogId ), m_uId( uId ), - m_model1( model1 ), - m_model2( model2 ), m_isHq( isHq ), m_stain( 0 ), m_durability( 30000 ) @@ -22,6 +20,8 @@ Sapphire::Item::Item( uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_ m_delayMs = itemInfo->delayms; m_physicalDmg = itemInfo->damagePhys; m_magicalDmg = itemInfo->damageMag; + m_model1 = itemInfo->modelMain; + m_model2 = itemInfo->modelSub; 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->itemUICategory ); diff --git a/src/world/Inventory/Item.h b/src/world/Inventory/Item.h index e5babd3d..6d30012c 100644 --- a/src/world/Inventory/Item.h +++ b/src/world/Inventory/Item.h @@ -10,7 +10,7 @@ namespace Sapphire { public: - Item( uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t model2, bool isHq = false ); + Item( uint64_t uId, uint32_t catalogId, bool isHq = false ); ~Item() = default; diff --git a/src/world/Inventory/ItemUtil.cpp b/src/world/Inventory/ItemUtil.cpp index bb036828..6d896b9c 100644 --- a/src/world/Inventory/ItemUtil.cpp +++ b/src/world/Inventory/ItemUtil.cpp @@ -132,11 +132,7 @@ Sapphire::ItemPtr Sapphire::Items::Util::loadItem( uint64_t uId ) auto itemInfo = pExdData->get< Sapphire::Data::Item >( itemRes->getUInt( 1 ) ); bool isHq = itemRes->getUInt( 3 ) == 1; - ItemPtr pItem = make_Item( uId, - itemRes->getUInt( 1 ), - itemInfo->modelMain, - itemInfo->modelSub, - isHq ); + ItemPtr pItem = make_Item( uId, itemRes->getUInt( 1 ), isHq ); pItem->setStackSize( itemRes->getUInt( 2 ) ); diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index deca4b48..b9339b0c 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -75,8 +75,7 @@ Sapphire::ItemPtr Sapphire::World::Manager::InventoryMgr::createItem( Entity::Pl if( !itemInfo ) return nullptr; - auto item = make_Item( Items::Util::getNextUId(), catalogId, - itemInfo->modelMain, itemInfo->modelSub ); + auto item = make_Item( Items::Util::getNextUId(), catalogId ); item->setStackSize( std::max< uint32_t >( 1, quantity ) ); From e0aa6550ae040c0152a80946f8241479338cda26 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 25 Dec 2018 22:59:13 +1100 Subject: [PATCH 16/40] force stack to 1 for housing items --- src/world/Manager/HousingMgr.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 6fed6521..f37f2cc4 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -112,6 +112,7 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories() auto item = Inventory::make_HousingItem( itemId, catalogId ); item->setStain( stain ); + item->setStackSize( 1 ); // todo: need to set the owner character id on the item // set world pos on item if its in an placed item container From fab6a273544c63882d4719a1de18a008018fb3b7 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Tue, 25 Dec 2018 23:43:39 +1100 Subject: [PATCH 17/40] spawn housing objects on zone in --- src/world/Inventory/Item.cpp | 6 ++++++ src/world/Inventory/Item.h | 4 ++++ src/world/Manager/HousingMgr.cpp | 2 +- src/world/Territory/HousingZone.cpp | 23 ++++++++++++++++------- src/world/Territory/HousingZone.h | 9 ++++++++- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/world/Inventory/Item.cpp b/src/world/Inventory/Item.cpp index c3199ef5..ac2016e8 100644 --- a/src/world/Inventory/Item.cpp +++ b/src/world/Inventory/Item.cpp @@ -27,6 +27,7 @@ Sapphire::Item::Item( uint64_t uId, uint32_t catalogId, bool isHq ) : m_category = static_cast< Common::ItemUICategory >( itemInfo->itemUICategory ); m_itemLevel = itemInfo->levelItem; m_maxStackSize = itemInfo->stackSize; + m_additionalData = itemInfo->additionalData; } float Sapphire::Item::getAutoAttackDmg() const @@ -154,3 +155,8 @@ void Sapphire::Item::setStain( uint16_t stain ) { m_stain = stain; } + +uint32_t Sapphire::Item::getAdditionalData() const +{ + return m_additionalData; +} diff --git a/src/world/Inventory/Item.h b/src/world/Inventory/Item.h index 6d30012c..a5980ba5 100644 --- a/src/world/Inventory/Item.h +++ b/src/world/Inventory/Item.h @@ -62,6 +62,8 @@ namespace Sapphire uint16_t getStain() const; void setStain( uint16_t stain ); + uint32_t getAdditionalData() const; + protected: uint32_t m_id; @@ -88,6 +90,8 @@ namespace Sapphire uint16_t m_durability; uint16_t m_stain; + uint32_t m_additionalData; + }; } diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index f37f2cc4..2ad42b83 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -669,7 +669,7 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl player.setLandFlags( LandFlagsSlot::Private, EstateBuilt, ident ); player.sendLandFlagsSlot( LandFlagsSlot::Private ); - hZone->registerHouseEntranceEObj( plotNum ); + hZone->registerEstateEntranceEObj( plotNum ); } void Sapphire::World::Manager::HousingMgr::requestEstateRename( Entity::Player& player, const Common::LandIdent ident ) diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 075059e2..f480282e 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -94,7 +94,7 @@ bool Sapphire::HousingZone::init() m_landPtrMap[ entry.m_landId ] = land; if( entry.m_houseId > 0 ) - registerHouseEntranceEObj( entry.m_landId ); + registerEstateEntranceEObj( entry.m_landId ); } return true; @@ -109,6 +109,8 @@ void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player ) "HousingZone::onPlayerZoneIn: Zone#" + std::to_string( getGuId() ) + "|" + std::to_string( getTerritoryTypeId() ) + ", Entity#" + std::to_string( player.getId() ) ); + auto isInSubdivision = isPlayerSubInstance( player ) ? true : false; + uint32_t yardPacketNum; uint32_t yardPacketTotal = 8; @@ -122,14 +124,21 @@ void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player ) housingObjectInit->data().packetNum = yardPacketNum; housingObjectInit->data().packetTotal = yardPacketTotal; - //TODO: Add Objects here + auto yardObjectSize = sizeof( Common::YardObject ); + + auto& objects = m_yardObjects[ isInSubdivision ? 1 : 0 ]; + + memcpy( &housingObjectInit->data().object, objects.data() + ( yardObjectSize * yardPacketNum ), + yardObjectSize * 100 ); player.queuePacket( housingObjectInit ); } auto landSetMap = makeZonePacket< FFXIVIpcLandSetMap >( player.getId() ); - landSetMap->data().subdivision = !isPlayerSubInstance( player ) ? 2 : 1; - uint8_t startIndex = !isPlayerSubInstance( player ) ? 0 : 30; + landSetMap->data().subdivision = isInSubdivision ? 1 : 2; + + uint8_t startIndex = isInSubdivision ? 30 : 0; + for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); i++, count++ ) { landSetMap->data().landInfo[ count ].status = 1; @@ -252,13 +261,13 @@ Sapphire::LandPtr Sapphire::HousingZone::getLand( uint8_t id ) return it->second; } -Sapphire::Entity::EventObjectPtr Sapphire::HousingZone::registerHouseEntranceEObj( uint8_t plotId ) +Sapphire::Entity::EventObjectPtr Sapphire::HousingZone::registerEstateEntranceEObj( uint8_t landId ) { - auto land = getLand( plotId ); + auto land = getLand( landId ); assert( land ); auto eObj = Entity::make_EventObject( getNextEObjId(), 2002737, 0, 4, land->getMapMarkerPosition(), 0.f, "entrance" ); - eObj->setHousingLink( plotId << 8 ); + eObj->setHousingLink( landId << 8 ); eObj->setScale( 1.f ); registerEObj( eObj ); diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index 3868f31a..84464182 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -50,15 +50,22 @@ namespace Sapphire uint32_t getLandSetId() const; Sapphire::LandPtr getLand( uint8_t id ); - Entity::EventObjectPtr registerHouseEntranceEObj( uint8_t plotId ); + Entity::EventObjectPtr registerEstateEntranceEObj( uint8_t landId ); private: using LandPtrMap = std::unordered_map< uint8_t, Sapphire::LandPtr >; + using YardObjectArray = std::array< Common::YardObject, 800 >; + using YardObjectMap = std::map< uint8_t, YardObjectArray >; + + using YardObjectArrayBoundsPair = std::pair< uint16_t, uint16_t >; + const uint32_t m_landSetMax = 18; LandPtrMap m_landPtrMap; uint8_t m_wardNum; uint32_t m_landSetId; uint32_t m_territoryTypeId; + + YardObjectMap m_yardObjects; }; } From 99d52f18f1c9f7103b30c341e95edf1faf40247f Mon Sep 17 00:00:00 2001 From: NotAdam Date: Wed, 26 Dec 2018 00:43:27 +1100 Subject: [PATCH 18/40] yard object spawning (mostly) working --- src/world/Inventory/HousingItem.cpp | 4 +- src/world/Inventory/HousingItem.h | 7 +-- src/world/Inventory/Item.h | 2 +- src/world/Manager/HousingMgr.cpp | 2 +- src/world/Territory/HousingZone.cpp | 84 ++++++++++++++++++++++++++++- src/world/Territory/HousingZone.h | 14 +++++ 6 files changed, 104 insertions(+), 9 deletions(-) diff --git a/src/world/Inventory/HousingItem.cpp b/src/world/Inventory/HousingItem.cpp index 139e5e94..3ab655e2 100644 --- a/src/world/Inventory/HousingItem.cpp +++ b/src/world/Inventory/HousingItem.cpp @@ -4,12 +4,12 @@ Sapphire::Inventory::HousingItem::HousingItem( uint64_t uId, uint32_t catalogId Sapphire::Item( uId, catalogId, false ) { } -float Sapphire::Inventory::HousingItem::getRot() const +uint16_t Sapphire::Inventory::HousingItem::getRot() const { return m_rotation; } -void Sapphire::Inventory::HousingItem::setRot( float rot ) +void Sapphire::Inventory::HousingItem::setRot( uint16_t rot ) { m_rotation = rot; } diff --git a/src/world/Inventory/HousingItem.h b/src/world/Inventory/HousingItem.h index 83fa20e3..d1536834 100644 --- a/src/world/Inventory/HousingItem.h +++ b/src/world/Inventory/HousingItem.h @@ -9,16 +9,17 @@ namespace Sapphire::Inventory { public: HousingItem( uint64_t uId, uint32_t catalogId ); + virtual ~HousingItem() = default; - void setRot( float rot ); - float getRot() const; + void setRot( uint16_t rot ); + uint16_t getRot() const; void setPos( Common::FFXIVARR_POSITION3 pos ); Common::FFXIVARR_POSITION3 getPos() const; private: Common::FFXIVARR_POSITION3 m_position; - float m_rotation; + uint16_t m_rotation; }; } diff --git a/src/world/Inventory/Item.h b/src/world/Inventory/Item.h index a5980ba5..f2b17ad1 100644 --- a/src/world/Inventory/Item.h +++ b/src/world/Inventory/Item.h @@ -12,7 +12,7 @@ namespace Sapphire public: Item( uint64_t uId, uint32_t catalogId, bool isHq = false ); - ~Item() = default; + virtual ~Item() = default; uint32_t getId() const; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 2ad42b83..1d49544e 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -124,7 +124,7 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories() res->getFloat( "PosZ" ) } ); - item->setRot( res->getFloat( "Rotation" ) ); + item->setRot( res->getUInt( "Rotation" ) ); } ContainerIdToContainerMap& estateInv = m_estateInventories[ ident ]; diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index f480282e..bcfc6dc1 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -12,6 +12,8 @@ #include "Actor/EventObject.h" #include "Land.h" #include "House.h" +#include "Inventory/HousingItem.h" +#include "Inventory/ItemContainer.h" #include "Forwards.h" #include "HousingZone.h" @@ -51,7 +53,7 @@ bool Sapphire::HousingZone::init() } - int housingIndex; + uint32_t housingIndex = 0; if( m_territoryTypeId == 339 ) housingIndex = 0; else if( m_territoryTypeId == 340 ) @@ -64,6 +66,44 @@ bool Sapphire::HousingZone::init() auto pExdData = g_fw.get< Data::ExdDataGenerated >(); auto info = pExdData->get< Sapphire::Data::HousingLandSet >( housingIndex ); + // build yard objects array indices + int16_t cursor = -1; + uint16_t index = 0; + for( const auto size : info->plotSize ) + { + uint16_t itemMax = 0; + switch( size ) + { + case 0: + itemMax = 20; + break; + + case 1: + itemMax = 30; + break; + + case 2: + itemMax = 40; + break; + } + + int16_t start = cursor + 1; + int16_t end = cursor + itemMax; + + m_yardObjectArrayBounds[ index++ ] = std::make_pair( start, end ); + + // reset cursor for subdivision + if( index == 30 ) + { + cursor = -1; + + continue; + } + + cursor += itemMax; + } + + auto housingMgr = g_fw.get< World::Manager::HousingMgr >(); auto landCache = housingMgr->getLandCacheMap(); @@ -83,7 +123,8 @@ bool Sapphire::HousingZone::init() // setup house if( entry.m_houseId ) { - auto house = make_House( entry.m_houseId, m_landSetId, land->getLandIdent(), entry.m_estateName, entry.m_estateComment ); + auto house = make_House( entry.m_houseId, m_landSetId, land->getLandIdent(), entry.m_estateName, + entry.m_estateComment ); housingMgr->updateHouseModels( house ); land->setHouse( house ); @@ -95,6 +136,32 @@ bool Sapphire::HousingZone::init() if( entry.m_houseId > 0 ) registerEstateEntranceEObj( entry.m_landId ); + + // add items to yard object array + auto& inventory = housingMgr->getEstateInventory( land->getLandIdent() ); + auto& externalContainer = inventory[ InventoryType::HousingExteriorPlacedItems ]; + + auto arrayBounds = m_yardObjectArrayBounds[ entry.m_landId ]; + uint8_t yardMapIndex = entry.m_landId <= 29 ? 0 : 1; + + for( auto& item : externalContainer->getItemMap() ) + { + Common::YardObject obj{}; + + auto housingItem = std::dynamic_pointer_cast< Inventory::HousingItem >( item.second ); + assert( housingItem ); + + auto pos = housingItem->getPos(); + + obj.itemId = housingItem->getAdditionalData(); + obj.itemRotation = housingItem->getRot(); + + obj.pos_x = Util::floatToUInt16( pos.x ); + obj.pos_y = Util::floatToUInt16( pos.y ); + obj.pos_z = Util::floatToUInt16( pos.z ); + + m_yardObjects[ yardMapIndex ][ item.first + arrayBounds.first ] = obj; + } } return true; @@ -273,4 +340,17 @@ Sapphire::Entity::EventObjectPtr Sapphire::HousingZone::registerEstateEntranceEO registerEObj( eObj ); return eObj; +} + +void Sapphire::HousingZone::updateYardObjects( Sapphire::Common::LandIdent ident ) +{ + auto housingMgr = g_fw.get< World::Manager::HousingMgr >(); + auto& landStorage = housingMgr->getEstateInventory( ident ); + + auto yardContainer = landStorage[ InventoryType::HousingExteriorPlacedItems ]; + + for( const auto& item : yardContainer->getItemMap() ) + { + + } } \ No newline at end of file diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index 84464182..e5d913f0 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -52,13 +52,26 @@ namespace Sapphire Entity::EventObjectPtr registerEstateEntranceEObj( uint8_t landId ); + void updateYardObjects( Common::LandIdent ident ); + private: using LandPtrMap = std::unordered_map< uint8_t, Sapphire::LandPtr >; using YardObjectArray = std::array< Common::YardObject, 800 >; using YardObjectMap = std::map< uint8_t, YardObjectArray >; + /*! + * @brief Maps the start and end index of the yard object array for a specific plot + * + * pair.first = start index + * pair.second = end index + */ using YardObjectArrayBoundsPair = std::pair< uint16_t, uint16_t >; + /*! + * @brief Maps each plot to a YardObjectArrayBoundsPair to the start/end index of the yard object array. + */ + using YardObjectArrayBoundsArray = std::array< YardObjectArrayBoundsPair, 60 >; + const uint32_t m_landSetMax = 18; LandPtrMap m_landPtrMap; uint8_t m_wardNum; @@ -66,6 +79,7 @@ namespace Sapphire uint32_t m_territoryTypeId; YardObjectMap m_yardObjects; + YardObjectArrayBoundsArray m_yardObjectArrayBounds; }; } From e00883286c34dbd85624850964d55e571632a7c0 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Wed, 26 Dec 2018 01:05:28 +1100 Subject: [PATCH 19/40] not much point using a map --- src/world/Territory/HousingZone.cpp | 3 ++- src/world/Territory/HousingZone.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index bcfc6dc1..ee426ffc 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -160,7 +160,8 @@ bool Sapphire::HousingZone::init() obj.pos_y = Util::floatToUInt16( pos.y ); obj.pos_z = Util::floatToUInt16( pos.z ); - m_yardObjects[ yardMapIndex ][ item.first + arrayBounds.first ] = obj; + auto idx = item.first + arrayBounds.first; + m_yardObjects[ yardMapIndex ][ idx ] = obj; } } diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index e5d913f0..79b2836b 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -57,7 +57,7 @@ namespace Sapphire private: using LandPtrMap = std::unordered_map< uint8_t, Sapphire::LandPtr >; using YardObjectArray = std::array< Common::YardObject, 800 >; - using YardObjectMap = std::map< uint8_t, YardObjectArray >; + using YardObjectSubdivisionArray = std::array< YardObjectArray, 2 >; /*! * @brief Maps the start and end index of the yard object array for a specific plot @@ -78,7 +78,7 @@ namespace Sapphire uint32_t m_landSetId; uint32_t m_territoryTypeId; - YardObjectMap m_yardObjects; + YardObjectSubdivisionArray m_yardObjects; YardObjectArrayBoundsArray m_yardObjectArrayBounds; }; From da8b86b1a02dd77c43d2d8f6a53c5296553eec79 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Wed, 26 Dec 2018 01:08:54 +1100 Subject: [PATCH 20/40] housing yard objects spawn from the db now --- src/world/Territory/HousingZone.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index ee426ffc..99bcddc9 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -196,8 +196,7 @@ void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player ) auto& objects = m_yardObjects[ isInSubdivision ? 1 : 0 ]; - memcpy( &housingObjectInit->data().object, objects.data() + ( yardObjectSize * yardPacketNum ), - yardObjectSize * 100 ); + memcpy( &housingObjectInit->data().object, objects.data() + ( yardPacketNum * 100 ), yardObjectSize * 100 ); player.queuePacket( housingObjectInit ); } From 0aba5c8d2d7114ce817e48c250b36100ed8f1934 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Wed, 26 Dec 2018 13:37:13 +1100 Subject: [PATCH 21/40] fix msvc builds and cleanup some warnings --- src/common/Network/GamePacketNew.h | 2 +- src/common/Network/PacketContainer.cpp | 2 +- src/world/Manager/HousingMgr.h | 1 + src/world/Territory/HousingZone.h | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/common/Network/GamePacketNew.h b/src/common/Network/GamePacketNew.h index 7cc943c6..0bb8a078 100644 --- a/src/common/Network/GamePacketNew.h +++ b/src/common/Network/GamePacketNew.h @@ -169,7 +169,7 @@ namespace Sapphire::Network::Packets // Set the values of static fields. // The size must be the sum of the segment header and the content - m_segHdr.size = sizeof( FFXIVARR_PACKET_SEGMENT_HEADER ) + getContentSize(); + m_segHdr.size = static_cast< uint32_t >( sizeof( FFXIVARR_PACKET_SEGMENT_HEADER ) + getContentSize() ); m_segHdr.type = getSegmentType(); } diff --git a/src/common/Network/PacketContainer.cpp b/src/common/Network/PacketContainer.cpp index 02a42c93..a61c38c0 100644 --- a/src/common/Network/PacketContainer.cpp +++ b/src/common/Network/PacketContainer.cpp @@ -24,7 +24,7 @@ void Sapphire::Network::Packets::PacketContainer::addPacket( Sapphire::Network:: { m_entryList.push_back( entry ); - m_ipcHdr.size += entry->getSize(); + m_ipcHdr.size += static_cast< uint32_t >( entry->getSize() ); m_ipcHdr.count++; } diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 8413f8e2..311b58b4 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -5,6 +5,7 @@ #include "Territory/HousingZone.h" #include #include +#include namespace Sapphire::Data { diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index 79b2836b..f3e88fc9 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -4,6 +4,8 @@ #include "Zone.h" #include "Forwards.h" +#include + namespace Sapphire { enum class LandPurchaseResult From b50c501946dbb830b98752b34896d71a468e7f79 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Wed, 26 Dec 2018 18:11:18 +1100 Subject: [PATCH 22/40] add external housing object placing --- src/common/Database/ZoneDbConnection.cpp | 11 ++ src/common/Database/ZoneDbConnection.h | 2 + src/common/Network/PacketDef/Ipcs.h | 3 + .../Network/PacketDef/Zone/ClientZoneDef.h | 16 +++ .../Network/PacketDef/Zone/ServerZoneDef.h | 6 +- src/world/Actor/Player.h | 2 + src/world/Actor/PlayerInventory.cpp | 35 ++++- src/world/Inventory/ItemContainer.cpp | 8 +- src/world/Inventory/ItemContainer.h | 4 +- src/world/Manager/HousingMgr.cpp | 120 +++++++++++++++++- src/world/Manager/HousingMgr.h | 5 + src/world/Manager/InventoryMgr.cpp | 50 ++++++-- src/world/Manager/InventoryMgr.h | 13 ++ src/world/Network/GameConnection.cpp | 1 + src/world/Network/GameConnection.h | 2 + src/world/Network/Handlers/PacketHandlers.cpp | 11 ++ src/world/Territory/HousingZone.cpp | 33 +++++ src/world/Territory/HousingZone.h | 1 + 18 files changed, 300 insertions(+), 23 deletions(-) diff --git a/src/common/Database/ZoneDbConnection.cpp b/src/common/Database/ZoneDbConnection.cpp index 807fe35a..d708ecd9 100644 --- a/src/common/Database/ZoneDbConnection.cpp +++ b/src/common/Database/ZoneDbConnection.cpp @@ -236,6 +236,17 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements() "WHERE LandIdent = ? AND ContainerId = ? AND SlotId = ?;", CONNECTION_BOTH ); + prepareStatement( LAND_INV_UP_ITEMPOS, + "INSERT INTO landplaceditems ( ItemId, PosX, PosY, PosZ, Rotation ) " + "VALUES ( ?, ?, ?, ?, ? ) " + "ON DUPLICATE KEY UPDATE PosX = ?, PosY = ?, PosZ = ?, Rotation = ?;", + CONNECTION_BOTH ); + + prepareStatement( LAND_INV_DEL_ITEMPOS, + "DELETE FROM landplaceditems " + "WHERE ItemId = ?;", + CONNECTION_BOTH ); + /*prepareStatement( LAND_INS, "INSERT INTO land ( LandSetId ) VALUES ( ? );", CONNECTION_BOTH ); diff --git a/src/common/Database/ZoneDbConnection.h b/src/common/Database/ZoneDbConnection.h index 179993d9..fa2458e3 100644 --- a/src/common/Database/ZoneDbConnection.h +++ b/src/common/Database/ZoneDbConnection.h @@ -91,6 +91,8 @@ namespace Sapphire::Db LAND_INV_SEL_HOUSE, LAND_INV_DEL, LAND_INV_UP, + LAND_INV_UP_ITEMPOS, + LAND_INV_DEL_ITEMPOS, MAX_STATEMENTS diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index 51a4c4bf..0273dc17 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -294,6 +294,8 @@ namespace Sapphire::Network::Packets InventoryModifyHandler = 0x0142, // updated 4.4 + ReqPlaceHousingItem = 0x145, // updated 4.4 + BuildPresetHandler = 0x014A, // updated 4.4 TalkEventHandler = 0x014B, // updated 4.4 EmoteEventHandler = 0x014C, // updated 4.4 @@ -311,6 +313,7 @@ namespace Sapphire::Network::Packets LandRenameHandler = 0x0171, // updated 4.4 HousingUpdateHouseGreeting = 0x0172, // updated 4.4 + HousingUpdateObjectRotation = 0x0173, // updated 4.4 SetSharedEstateSettings = 0x0177, // updated 4.4 diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index b2b33033..2cf8c863 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -240,6 +240,22 @@ struct FFXIVIpcMarketBoardRequestItemListings : /* 0004 */ uint32_t padding; }; +struct FFXIVIpcReqPlaceHousingItem : + FFXIVIpcBasePacket< ReqPlaceHousingItem > +{ + /* 0000 */ uint16_t landId; // 0 when plot 0 or inside an estate + /* 0002 */ uint16_t unknown1; + /* 0004 */ uint32_t unknown2; + /* 0008 */ uint16_t sourceInvContainerId; + /* 000A */ uint16_t sourceInvSlotId; + + /* 000C */ Common::FFXIVARR_POSITION3 position; + /* 0018 */ float rotation; + + /* 001C */ uint32_t unknown3; // always 1? + /* 0020 */ uint32_t unknown4[2]; // always 0 it looks like +}; + } } } diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 8c7768a9..d359ae6c 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1684,11 +1684,7 @@ struct FFXIVIpcYardObjectSpawn : FFXIVIpcBasePacket uint8_t landSetId; uint8_t objectArray; uint16_t unknown1; - uint32_t itemId; - uint16_t itemRotation; - uint16_t pos_x; - uint16_t pos_y; - uint16_t pos_z; + Common::YardObject object; }; struct FFXIVIpcYardObjectMove : FFXIVIpcBasePacket diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index b0c8b1cf..e620359f 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -919,6 +919,8 @@ namespace Sapphire::Entity void setActiveLand( uint8_t land, uint8_t ward ); Common::ActiveLand getActiveLand() const; + Sapphire::ItemPtr dropInventoryItem( Common::InventoryType type, uint16_t slotId ); + ////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/world/Actor/PlayerInventory.cpp b/src/world/Actor/PlayerInventory.cpp index 67545381..d908cbcf 100644 --- a/src/world/Actor/PlayerInventory.cpp +++ b/src/world/Actor/PlayerInventory.cpp @@ -754,7 +754,7 @@ void Sapphire::Entity::Player::swapItem( uint16_t fromInventoryId, uint8_t fromS void Sapphire::Entity::Player::discardItem( uint16_t fromInventoryId, uint8_t fromSlotId ) { // i am not entirely sure how this should be generated or if it even is important for us... - uint32_t transactionId = 1; + uint32_t transactionId = getNextInventorySequence(); auto fromItem = m_storageMap[ fromInventoryId ]->getItem( fromSlotId ); @@ -869,3 +869,36 @@ uint32_t Sapphire::Entity::Player::getNextInventorySequence() { return m_inventorySequence++; } + +Sapphire::ItemPtr Sapphire::Entity::Player::dropInventoryItem( Sapphire::Common::InventoryType type, uint16_t slotId ) +{ + auto& container = m_storageMap[ type ]; + + auto item = container->getItem( slotId ); + if( !item ) + return nullptr; + + // unlink item + container->removeItem( slotId ); + updateContainer( type, slotId, nullptr ); + + auto seq = getNextInventorySequence(); + + // send inv update + auto invTransPacket = makeZonePacket< FFXIVIpcInventoryTransaction >( getId() ); + invTransPacket->data().transactionId = seq; + invTransPacket->data().ownerId = getId(); + invTransPacket->data().storageId = type; + invTransPacket->data().catalogId = item->getId(); + invTransPacket->data().stackSize = item->getStackSize(); + invTransPacket->data().slotId = slotId; + invTransPacket->data().type = 7; + queuePacket( invTransPacket ); + + auto invTransFinPacket = makeZonePacket< FFXIVIpcInventoryTransactionFinish >( getId() ); + invTransFinPacket->data().transactionId = seq; + invTransFinPacket->data().transactionId1 = seq; + queuePacket( invTransFinPacket ); + + return item; +} \ No newline at end of file diff --git a/src/world/Inventory/ItemContainer.cpp b/src/world/Inventory/ItemContainer.cpp index 3328a4f9..53b8a02e 100644 --- a/src/world/Inventory/ItemContainer.cpp +++ b/src/world/Inventory/ItemContainer.cpp @@ -12,12 +12,12 @@ extern Sapphire::Framework g_fw; Sapphire::ItemContainer::ItemContainer( uint16_t storageId, uint16_t maxSize, const std::string& tableName, - bool isMultiStorage, bool isPersistentStorage ) : + bool isMultiStorage, bool removeItemOnContainerRemoval ) : m_id( storageId ), m_size( maxSize ), m_tableName( tableName ), m_bMultiStorage( isMultiStorage ), - m_isPersistentStorage( isPersistentStorage ) + m_removeItemOnContainerRemove( removeItemOnContainerRemoval ) { } @@ -45,7 +45,7 @@ void Sapphire::ItemContainer::removeItem( uint16_t slotId ) if( it != m_itemMap.end() ) { - if( m_isPersistentStorage ) + if( m_removeItemOnContainerRemove ) pDb->execute( "DELETE FROM charaglobalitem WHERE itemId = " + std::to_string( it->second->getUId() ) ); m_itemMap.erase( it ); @@ -118,7 +118,7 @@ bool Sapphire::ItemContainer::isMultiStorage() const bool Sapphire::ItemContainer::isPersistentStorage() const { - return m_isPersistentStorage; + return m_removeItemOnContainerRemove; } diff --git a/src/world/Inventory/ItemContainer.h b/src/world/Inventory/ItemContainer.h index 295fa51a..321077c0 100644 --- a/src/world/Inventory/ItemContainer.h +++ b/src/world/Inventory/ItemContainer.h @@ -15,7 +15,7 @@ namespace Sapphire public: ItemContainer( uint16_t storageId, uint16_t maxSize, const std::string& tableName, bool isMultiStorage, - bool isPersistentStorage = true ); + bool removeItemOnContainerRemoval = true ); ~ItemContainer(); @@ -48,7 +48,7 @@ namespace Sapphire uint16_t m_size; std::string m_tableName; bool m_bMultiStorage; - bool m_isPersistentStorage; + bool m_removeItemOnContainerRemove; ItemMap m_itemMap; Entity::PlayerPtr m_pOwner; }; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 1d49544e..91ccc0f7 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -27,6 +27,7 @@ #include "InventoryMgr.h" #include "Inventory/HousingItem.h" #include "Inventory/ItemContainer.h" +#include "Util/UtilMath.h" using namespace Sapphire::Common; using namespace Sapphire::Network; @@ -216,7 +217,7 @@ void Sapphire::World::Manager::HousingMgr::initLandCache() auto makeContainer = [ &containers ]( Common::InventoryType type, uint16_t size ) { - containers[ type ] = make_ItemContainer( type, size, "houseiteminventory", true ); + containers[ type ] = make_ItemContainer( type, size, "houseiteminventory", false ); }; uint16_t count = 0; @@ -901,11 +902,126 @@ uint32_t Sapphire::World::Manager::HousingMgr::getItemAdditionalData( uint32_t c bool Sapphire::World::Manager::HousingMgr::isPlacedItemsInventory( Sapphire::Common::InventoryType type ) { - return type == InventoryType::HousingExteriorPlacedItems || + return type == InventoryType::HousingExteriorPlacedItems || type == InventoryType::HousingInteriorPlacedItems1 || type == InventoryType::HousingInteriorPlacedItems2 || type == InventoryType::HousingInteriorPlacedItems3 || type == InventoryType::HousingInteriorPlacedItems4 || type == InventoryType::HousingInteriorPlacedItems5 || type == InventoryType::HousingInteriorPlacedItems6; +} + +void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity::Player& player, uint16_t landId, + uint16_t containerId, uint16_t slotId, + Sapphire::Common::FFXIVARR_POSITION3 pos, + float rotation ) +{ + // retail process is: + // - unlink item from current container + // - add it to destination container + // - resend container + // - send spawn packet + // - send actrl 3f3, all params are 0 + + LandPtr land; + bool isOutside = false; + + // inside housing territory + if( auto zone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ) ) + { + land = zone->getLand( landId ); + + isOutside = true; + } + // inside house + 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->getIdent(); + auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); + + land = getHousingZoneByLandSetId( landSet )->getLand( landId ); + } + // wtf? + else + return; + + if( !land ) + return; + + // todo: add proper permissions checks + if( land->getOwnerId() != player.getId() ) + return; + + player.sendDebug( "got item place request: "); + player.sendDebug( " - item: c: " + std::to_string( containerId ) + ", s: " + std::to_string( slotId ) ); + + // unlink item + Inventory::HousingItemPtr item; + + if( containerId == InventoryType::Bag0 || + containerId == InventoryType::Bag1 || + containerId == InventoryType::Bag2 || + containerId == InventoryType::Bag3 ) + { + auto tmpItem = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + + item = Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId() ); + + // set params + item->setPos( pos ); + item->setRot( Util::floatToUInt16Rot( rotation ) ); + } + else + { + player.sendUrgent( "The inventory you are using to place an item is not supported." ); + return; + } + + auto ident = land->getLandIdent(); + + if( isOutside ) + { + if( !placeExternalItem( player, item, ident ) ) + player.sendUrgent( "An internal error occurred when placing the item." ); + } + else + { + player.sendUrgent( "you can't place internal items (yet)" ); + return; + } +} + +bool Sapphire::World::Manager::HousingMgr::placeExternalItem( Entity::Player& player, + Inventory::HousingItemPtr item, + Common::LandIdent ident ) +{ + auto invMgr = g_fw.get< InventoryMgr >(); + + auto& container = getEstateInventory( ident )[ InventoryType::HousingExteriorPlacedItems ]; + + auto freeSlot = container->getFreeSlot(); + + // todo: what happens when this fails? at the moment the player will just lose the item + if( freeSlot == -1 ) + return false; + + // add item to inv + container->setItem( freeSlot, item ); + + // we need to save the item again as removing it from the container on the player will remove it from charaglobalitem + // todo: this needs to be handled a bit better as it might be possible to overwrite another item that is created in the meantime + invMgr->saveItem( player, item ); + + invMgr->sendInventoryContainer( player, container ); + invMgr->saveHousingContainer( ident, container ); + invMgr->updateHousingItemPosition( item ); + + // add to zone and spawn + auto zone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); + + zone->spawnYardObject( ident.landId, freeSlot, item ); + + return true; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 311b58b4..a4291814 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -146,8 +146,13 @@ namespace Sapphire::World::Manager */ bool initHouseModels( Entity::Player& player, LandPtr land, uint32_t presetCatalogId ); + void reqPlaceHousingItem( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId, + Common::FFXIVARR_POSITION3 pos, float rotation ); + private: + bool placeExternalItem( Entity::Player& player, Inventory::HousingItemPtr item, Common::LandIdent ident ); + /*! * @brief Creates a house and saves the minimum amount required to persist a house through restarts. * diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index b9339b0c..4aacb24d 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -3,7 +3,7 @@ #include #include "Actor/Player.h" #include "Inventory/ItemContainer.h" -#include "Inventory/Item.h" +#include "Inventory/HousingItem.h" #include "Inventory/ItemUtil.h" #include #include @@ -79,14 +79,7 @@ Sapphire::ItemPtr Sapphire::World::Manager::InventoryMgr::createItem( Entity::Pl item->setStackSize( std::max< uint32_t >( 1, quantity ) ); - auto stmt = pDb->getPreparedStatement( Db::CHARA_ITEMGLOBAL_INS ); - - stmt->setUInt( 1, player.getId() ); - stmt->setUInt64( 2, item->getUId() ); - stmt->setUInt( 3, item->getId() ); - stmt->setUInt( 4, item->getStackSize() ); - - pDb->directExecute( stmt ); + saveItem( player, item ); return item; } @@ -121,4 +114,43 @@ void Sapphire::World::Manager::InventoryMgr::saveHousingContainerItem( uint64_t stmt->setUInt64( 5, itemId ); pDb->execute( stmt ); +} + +void Sapphire::World::Manager::InventoryMgr::updateHousingItemPosition( Sapphire::Inventory::HousingItemPtr item ) +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); + + auto stmt = pDb->getPreparedStatement( Db::LAND_INV_UP_ITEMPOS ); + // ItemId, PosX, PosY, PosZ, Rotation, PosX, PosY, PosZ, Rotation + + auto pos = item->getPos(); + auto rot = item->getRot(); + + stmt->setUInt64( 1, item->getUId() ); + + stmt->setDouble( 2, pos.x ); + stmt->setDouble( 3, pos.y ); + stmt->setDouble( 4, pos.z ); + + stmt->setInt( 5, rot ); + + stmt->setDouble( 6, pos.x ); + stmt->setDouble( 7, pos.y ); + stmt->setDouble( 8, pos.z ); + stmt->setInt( 9, rot ); + + pDb->execute( stmt ); +} + +void Sapphire::World::Manager::InventoryMgr::saveItem( Sapphire::Entity::Player& player, Sapphire::ItemPtr item ) +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); + auto stmt = pDb->getPreparedStatement( Db::CHARA_ITEMGLOBAL_INS ); + + stmt->setUInt( 1, player.getId() ); + stmt->setUInt64( 2, item->getUId() ); + stmt->setUInt( 3, item->getId() ); + stmt->setUInt( 4, item->getStackSize() ); + + pDb->directExecute( stmt ); } \ No newline at end of file diff --git a/src/world/Manager/InventoryMgr.h b/src/world/Manager/InventoryMgr.h index c22c5342..466ff563 100644 --- a/src/world/Manager/InventoryMgr.h +++ b/src/world/Manager/InventoryMgr.h @@ -44,6 +44,19 @@ namespace Sapphire::World::Manager */ void updateItem( Sapphire::ItemPtr item ); + /*! + * @brief Updates the position/rotation of a housing object + * @param item The item to update + */ + void updateHousingItemPosition( Sapphire::Inventory::HousingItemPtr item ); + + /*! + * @brief Saves an item to the global item table + * @param player The player which owns the item + * @param item The item to save + */ + void saveItem( Entity::Player& player, ItemPtr item ); + private: /*! * @brief Saves an individual item to the db. diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index 25c42c9b..cf16b7db 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -88,6 +88,7 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::LandRenameHandler, "LandRenameHandler", &GameConnection::landRenameHandler ); setZoneHandler( ClientZoneIpcType::HousingUpdateHouseGreeting, "HousingUpdateHouseGreeting", &GameConnection::housingUpdateGreetingHandler ); + setZoneHandler( ClientZoneIpcType::ReqPlaceHousingItem, "ReqPlaceHousingItem", &GameConnection::reqPlaceHousingItem ); setZoneHandler( ClientZoneIpcType::TalkEventHandler, "EventHandlerTalk", &GameConnection::eventHandlerTalk ); setZoneHandler( ClientZoneIpcType::EmoteEventHandler, "EventHandlerEmote", &GameConnection::eventHandlerEmote ); diff --git a/src/world/Network/GameConnection.h b/src/world/Network/GameConnection.h index 3efbdde5..60710546 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -171,6 +171,8 @@ namespace Sapphire::Network DECLARE_HANDLER( tellHandler ); + DECLARE_HANDLER( reqPlaceHousingItem ); + }; } diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index 1d3f394a..e3207a63 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -705,3 +705,14 @@ void Sapphire::Network::GameConnection::housingUpdateGreetingHandler( const Pack pHousingMgr->updateEstateGreeting( player, packet.data().ident, std::string( packet.data().greeting ) ); } + +void Sapphire::Network::GameConnection::reqPlaceHousingItem( const Packets::FFXIVARR_PACKET_RAW& inPacket, + Entity::Player& player ) +{ + auto housingMgr = g_fw.get< HousingMgr >(); + 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 ); +} \ No newline at end of file diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 99bcddc9..a1bbfb6d 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -353,4 +353,37 @@ void Sapphire::HousingZone::updateYardObjects( Sapphire::Common::LandIdent ident { } +} + +void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, Inventory::HousingItemPtr item ) +{ + auto bounds = m_yardObjectArrayBounds[ landId ]; + auto offset = bounds.first + slotId; + + Common::YardObject obj {}; + + obj.itemId = item->getAdditionalData(); + obj.itemRotation = item->getRot(); + + auto pos = item->getPos(); + + obj.pos_x = Util::floatToUInt16( pos.x ); + obj.pos_y = Util::floatToUInt16( pos.y ); + obj.pos_z = Util::floatToUInt16( pos.z ); + + // link obj + uint8_t yardMapIndex = landId <= 29 ? 0 : 1; + m_yardObjects[ yardMapIndex ][ offset ] = obj; + + // spawn obj in zone + for( const auto& player : m_playerMap ) + { + auto packet = makeZonePacket< Server::FFXIVIpcYardObjectSpawn >( player.second->getId() ); + + packet->data().landSetId = landId; + packet->data().objectArray = slotId; + packet->data().object = obj; + + player.second->queuePacket( packet ); + } } \ No newline at end of file diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index f3e88fc9..8b14f711 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -55,6 +55,7 @@ namespace Sapphire Entity::EventObjectPtr registerEstateEntranceEObj( uint8_t landId ); void updateYardObjects( Common::LandIdent ident ); + void spawnYardObject( uint8_t landId, uint16_t slotId, Sapphire::Inventory::HousingItemPtr item ); private: using LandPtrMap = std::unordered_map< uint8_t, Sapphire::LandPtr >; From 7da03ef6f0ee90cf0518d12cf5434c201183b902 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Wed, 26 Dec 2018 19:22:30 +1100 Subject: [PATCH 23/40] handle item positions better & some minor cleanup/refactoring --- bin/sql/schema/schema.sql | 6 +- src/common/Common.h | 11 ++- src/world/Inventory/HousingItem.cpp | 4 +- src/world/Inventory/HousingItem.h | 6 +- src/world/Manager/HousingMgr.cpp | 84 ++++++++++++++++--- src/world/Manager/HousingMgr.h | 15 ++++ src/world/Manager/InventoryMgr.cpp | 13 ++- .../Housing/HousingInteriorTerritory.cpp | 2 +- .../Housing/HousingInteriorTerritory.h | 2 +- src/world/Territory/HousingZone.cpp | 19 ++--- 10 files changed, 116 insertions(+), 46 deletions(-) diff --git a/bin/sql/schema/schema.sql b/bin/sql/schema/schema.sql index 83d777fd..cdaa247e 100644 --- a/bin/sql/schema/schema.sql +++ b/bin/sql/schema/schema.sql @@ -566,9 +566,9 @@ CREATE TABLE `zonepositions` ( CREATE TABLE `landplaceditems` ( `ItemId` INT(20) UNSIGNED NOT NULL, - `PosX` FLOAT NOT NULL, - `PosY` FLOAT NOT NULL, - `PosZ` FLOAT NOT NULL, + `PosX` INT(10) NOT NULL, + `PosY` INT(10) NOT NULL, + `PosZ` INT(10) NOT NULL, `Rotation` INT(10) NOT NULL, PRIMARY KEY (`ItemId`) ) diff --git a/src/common/Common.h b/src/common/Common.h index 5fb1a59c..8a86bde6 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -26,6 +26,13 @@ namespace Sapphire::Common float z; }; + struct FFXIVARR_POSITION3_U16 + { + uint16_t x; + uint16_t y; + uint16_t z; + }; + struct ActiveLand { uint8_t ward; @@ -848,9 +855,7 @@ namespace Sapphire::Common { uint32_t itemId; uint16_t itemRotation; - uint16_t pos_x; - uint16_t pos_y; - uint16_t pos_z; + Common::FFXIVARR_POSITION3_U16 pos; }; enum HouseSize : uint8_t diff --git a/src/world/Inventory/HousingItem.cpp b/src/world/Inventory/HousingItem.cpp index 3ab655e2..265c26de 100644 --- a/src/world/Inventory/HousingItem.cpp +++ b/src/world/Inventory/HousingItem.cpp @@ -14,12 +14,12 @@ void Sapphire::Inventory::HousingItem::setRot( uint16_t rot ) m_rotation = rot; } -Sapphire::Common::FFXIVARR_POSITION3 Sapphire::Inventory::HousingItem::getPos() const +Sapphire::Common::FFXIVARR_POSITION3_U16 Sapphire::Inventory::HousingItem::getPos() const { return m_position; } -void Sapphire::Inventory::HousingItem::setPos( Sapphire::Common::FFXIVARR_POSITION3 pos ) +void Sapphire::Inventory::HousingItem::setPos( Sapphire::Common::FFXIVARR_POSITION3_U16 pos ) { m_position = pos; } \ No newline at end of file diff --git a/src/world/Inventory/HousingItem.h b/src/world/Inventory/HousingItem.h index d1536834..d4fbe368 100644 --- a/src/world/Inventory/HousingItem.h +++ b/src/world/Inventory/HousingItem.h @@ -14,11 +14,11 @@ namespace Sapphire::Inventory void setRot( uint16_t rot ); uint16_t getRot() const; - void setPos( Common::FFXIVARR_POSITION3 pos ); - Common::FFXIVARR_POSITION3 getPos() const; + void setPos( Common::FFXIVARR_POSITION3_U16 pos ); + Common::FFXIVARR_POSITION3_U16 getPos() const; private: - Common::FFXIVARR_POSITION3 m_position; + Common::FFXIVARR_POSITION3_U16 m_position; uint16_t m_rotation; }; } diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 91ccc0f7..a9593901 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -120,12 +120,12 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories() if( isPlacedItemsInventory( static_cast< Common::InventoryType >( containerId ) ) ) { item->setPos( { - res->getFloat( "PosX" ), - res->getFloat( "PosY" ), - res->getFloat( "PosZ" ) + res->getUInt16( "PosX" ), + res->getUInt16( "PosY" ), + res->getUInt16( "PosZ" ) } ); - item->setRot( res->getUInt( "Rotation" ) ); + item->setRot( res->getUInt16( "Rotation" ) ); } ContainerIdToContainerMap& estateInv = m_estateInventories[ ident ]; @@ -800,7 +800,7 @@ void Sapphire::World::Manager::HousingMgr::sendEstateInventory( Entity::Player& if( !internalZone ) return; - auto ident = internalZone->getIdent(); + auto ident = internalZone->getLandIdent(); auto landSetId = toLandSetId( ident.territoryTypeId, ident.wardNum ); auto exteriorZone = getHousingZoneByLandSetId( landSetId ); @@ -933,12 +933,16 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity isOutside = true; } - // inside house - else if( auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ) ) + // otherwise, inside a house. landId is 0 when inside a plot + else if( landId == 0 ) { + auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); + if( !zone ) + return; + // todo: this whole process is retarded and needs to be fixed // perhaps maintain a list of estates by ident inside housingmgr? - auto ident = zone->getIdent(); + auto ident = zone->getLandIdent(); auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); land = getHousingZoneByLandSetId( landSet )->getLand( landId ); @@ -954,9 +958,6 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity if( land->getOwnerId() != player.getId() ) return; - player.sendDebug( "got item place request: "); - player.sendDebug( " - item: c: " + std::to_string( containerId ) + ", s: " + std::to_string( slotId ) ); - // unlink item Inventory::HousingItemPtr item; @@ -970,7 +971,12 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity item = Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId() ); // set params - item->setPos( pos ); + item->setPos( { + Util::floatToUInt16( pos.x ), + Util::floatToUInt16( pos.y ), + Util::floatToUInt16( pos.z ) + } ); + item->setRot( Util::floatToUInt16Rot( rotation ) ); } else @@ -1020,8 +1026,62 @@ bool Sapphire::World::Manager::HousingMgr::placeExternalItem( Entity::Player& pl // add to zone and spawn auto zone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); + assert( zone ); zone->spawnYardObject( ident.landId, freeSlot, item ); + return true; +} + +bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& player, + Inventory::HousingItemPtr item ) +{ + auto invMgr = g_fw.get< InventoryMgr >(); + + auto containers = { + InventoryType::HousingInteriorPlacedItems1, + InventoryType::HousingInteriorPlacedItems2, + InventoryType::HousingInteriorPlacedItems3, + InventoryType::HousingInteriorPlacedItems4, + InventoryType::HousingInteriorPlacedItems5, + InventoryType::HousingInteriorPlacedItems6, + InventoryType::HousingInteriorPlacedItems7, + InventoryType::HousingInteriorPlacedItems8, + }; + + auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); + assert( zone ); + + auto ident = zone->getLandIdent(); + + // find first free container + uint8_t containerIdx = 0; + for( auto containerId : containers ) + { + auto& container = getEstateInventory( ident )[ containerId ]; + + auto freeSlot = container->getFreeSlot(); + if( freeSlot == -1 ) + { + containerIdx++; + continue; + } + + // 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 + // todo: unsure as to whether we need to resend every container or just the one we edit - we'll see how this goes + invMgr->sendInventoryContainer( player, container ); + invMgr->saveHousingContainer( ident, container ); + invMgr->updateHousingItemPosition( item ); + + break; + } + + return true; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index a4291814..f9191c06 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -151,8 +151,23 @@ namespace Sapphire::World::Manager private: + /*! + * @brief Processes the spawning and linking of a newly placed housing item for external items + * @param player The player who is placing the item + * @param item The item that we're placing + * @param ident The land that is going to own the item + * @return true if the item was placed successfully, false if there's no free container slots to place it + */ bool placeExternalItem( Entity::Player& player, Inventory::HousingItemPtr item, Common::LandIdent ident ); + /*! + * @brief Processing the spawning and linking of a newly placed item for interior items + * @param player The player who is placing the item + * @param item The item that we're placing + * @return true if the item was placed successfully, false if there's no free spots to place it + */ + bool placeInteriorItem( Entity::Player& player, Inventory::HousingItemPtr item ); + /*! * @brief Creates a house and saves the minimum amount required to persist a house through restarts. * diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index 4aacb24d..f5b59620 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -128,15 +128,14 @@ void Sapphire::World::Manager::InventoryMgr::updateHousingItemPosition( Sapphire stmt->setUInt64( 1, item->getUId() ); - stmt->setDouble( 2, pos.x ); - stmt->setDouble( 3, pos.y ); - stmt->setDouble( 4, pos.z ); - + stmt->setUInt( 2, pos.x ); + stmt->setUInt( 3, pos.y ); + stmt->setUInt( 4, pos.z ); stmt->setInt( 5, rot ); - stmt->setDouble( 6, pos.x ); - stmt->setDouble( 7, pos.y ); - stmt->setDouble( 8, pos.z ); + stmt->setUInt( 6, pos.x ); + stmt->setUInt( 7, pos.y ); + stmt->setUInt( 8, pos.z ); stmt->setInt( 9, rot ); pDb->execute( stmt ); diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index f7487ee6..f1044efa 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -105,7 +105,7 @@ uint32_t Housing::HousingInteriorTerritory::getLastActivityTime() const return m_lastActivityTime; } -const Common::LandIdent Housing::HousingInteriorTerritory::getIdent() const +const Common::LandIdent Housing::HousingInteriorTerritory::getLandIdent() const { return m_landIdent; } \ No newline at end of file diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.h b/src/world/Territory/Housing/HousingInteriorTerritory.h index f8287df8..153e3604 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.h +++ b/src/world/Territory/Housing/HousingInteriorTerritory.h @@ -20,7 +20,7 @@ namespace Sapphire::World::Territory::Housing uint32_t getLastActivityTime() const; - const Common::LandIdent getIdent() const; + const Common::LandIdent getLandIdent() const; private: Common::LandIdent m_landIdent; diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index a1bbfb6d..414e927a 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -142,7 +142,7 @@ bool Sapphire::HousingZone::init() auto& externalContainer = inventory[ InventoryType::HousingExteriorPlacedItems ]; auto arrayBounds = m_yardObjectArrayBounds[ entry.m_landId ]; - uint8_t yardMapIndex = entry.m_landId <= 29 ? 0 : 1; + auto yardMapIndex = entry.m_landId <= 29 ? 0 : 1; for( auto& item : externalContainer->getItemMap() ) { @@ -151,14 +151,9 @@ bool Sapphire::HousingZone::init() auto housingItem = std::dynamic_pointer_cast< Inventory::HousingItem >( item.second ); assert( housingItem ); - auto pos = housingItem->getPos(); - obj.itemId = housingItem->getAdditionalData(); obj.itemRotation = housingItem->getRot(); - - obj.pos_x = Util::floatToUInt16( pos.x ); - obj.pos_y = Util::floatToUInt16( pos.y ); - obj.pos_z = Util::floatToUInt16( pos.z ); + obj.pos = housingItem->getPos(); auto idx = item.first + arrayBounds.first; m_yardObjects[ yardMapIndex ][ idx ] = obj; @@ -365,14 +360,10 @@ void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, In obj.itemId = item->getAdditionalData(); obj.itemRotation = item->getRot(); - auto pos = item->getPos(); - - obj.pos_x = Util::floatToUInt16( pos.x ); - obj.pos_y = Util::floatToUInt16( pos.y ); - obj.pos_z = Util::floatToUInt16( pos.z ); + obj.pos = item->getPos(); // link obj - uint8_t yardMapIndex = landId <= 29 ? 0 : 1; + auto yardMapIndex = landId <= 29 ? 0 : 1; m_yardObjects[ yardMapIndex ][ offset ] = obj; // spawn obj in zone @@ -381,7 +372,7 @@ void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, In auto packet = makeZonePacket< Server::FFXIVIpcYardObjectSpawn >( player.second->getId() ); packet->data().landSetId = landId; - packet->data().objectArray = slotId; + packet->data().objectArray = static_cast< uint8_t >( slotId ); packet->data().object = obj; player.second->queuePacket( packet ); From d2386968327219845af1c88b03045c4482187257 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Wed, 26 Dec 2018 22:39:00 +1100 Subject: [PATCH 24/40] spawn internal house items from db --- .../Network/PacketDef/Zone/ServerZoneDef.h | 2 +- src/world/Manager/HousingMgr.cpp | 23 +++- src/world/Manager/HousingMgr.h | 7 ++ .../Housing/HousingInteriorTerritory.cpp | 117 ++++++++++++++---- .../Housing/HousingInteriorTerritory.h | 7 ++ src/world/Territory/HousingZone.cpp | 39 +++--- 6 files changed, 145 insertions(+), 50 deletions(-) diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index d359ae6c..75ea7041 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1681,7 +1681,7 @@ struct FFXIVIpcLandSetInitialize : FFXIVIpcBasePacket< LandSetInitialize > struct FFXIVIpcYardObjectSpawn : FFXIVIpcBasePacket { - uint8_t landSetId; + uint8_t landId; uint8_t objectArray; uint16_t unknown1; Common::YardObject object; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index a9593901..0f481cd2 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1038,7 +1038,7 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl { auto invMgr = g_fw.get< InventoryMgr >(); - auto containers = { + auto containerIds = { InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorPlacedItems2, InventoryType::HousingInteriorPlacedItems3, @@ -1056,7 +1056,7 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl // find first free container uint8_t containerIdx = 0; - for( auto containerId : containers ) + for( auto containerId : containerIds ) { auto& container = getEstateInventory( ident )[ containerId ]; @@ -1079,9 +1079,24 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl invMgr->saveHousingContainer( ident, container ); invMgr->updateHousingItemPosition( item ); - break; + auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); + assert( zone ); + + zone->spawnYardObject( containerIdx, freeSlot, item ); + + return true; } + return false; +} - return true; +Sapphire::Common::YardObject Sapphire::World::Manager::HousingMgr::getYardObjectForItem( Inventory::HousingItemPtr item ) const +{ + Sapphire::Common::YardObject obj {}; + + obj.pos = item->getPos(); + obj.itemRotation = item->getRot(); + obj.itemId = item->getAdditionalData(); + + return obj; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index f9191c06..e7bc4251 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -149,6 +149,13 @@ namespace Sapphire::World::Manager void reqPlaceHousingItem( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId, Common::FFXIVARR_POSITION3 pos, float rotation ); + /*! + * @brief Returns the equivalent YardObject for a HousingItem + * @param item The item to convert into a YardObject + * @return The resultant YardObject + */ + Common::YardObject getYardObjectForItem( Inventory::HousingItemPtr item ) const; + private: /*! diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index f1044efa..a99daaed 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -13,6 +13,8 @@ #include "Manager/HousingMgr.h" #include "Territory/Land.h" #include "Territory/House.h" +#include "Inventory/ItemContainer.h" +#include "Inventory/HousingItem.h" #include "Forwards.h" #include "HousingInteriorTerritory.h" @@ -28,27 +30,27 @@ using namespace Sapphire::World::Manager; using namespace Sapphire; using namespace Sapphire::World::Territory; -Housing::HousingInteriorTerritory::HousingInteriorTerritory( Common::LandIdent ident, uint16_t territoryTypeId, - uint32_t guId, - const std::string& internalName, - const std::string& contentName ) : +Sapphire::World::Territory::Housing::HousingInteriorTerritory::HousingInteriorTerritory( Common::LandIdent ident, + uint16_t territoryTypeId, + uint32_t guId, + const std::string& internalName, + const std::string& contentName ) : Zone( territoryTypeId, guId, internalName, contentName ), m_landIdent( ident ) { m_lastActivityTime = static_cast< uint32_t >( Util::getTimeSeconds() ); } -Housing::HousingInteriorTerritory::~HousingInteriorTerritory() -{ +Housing::HousingInteriorTerritory::~HousingInteriorTerritory() = default; +bool Sapphire::World::Territory::Housing::HousingInteriorTerritory::init() +{ + updateYardObjects(); + + return true; } -bool Housing::HousingInteriorTerritory::init() -{ - return false; -} - -void Housing::HousingInteriorTerritory::onPlayerZoneIn( Entity::Player& player ) +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZoneIn( Entity::Player& player ) { auto pHousingMgr = g_fw.get< HousingMgr >(); auto pLog = g_fw.get< Logger >(); @@ -56,7 +58,7 @@ void Housing::HousingInteriorTerritory::onPlayerZoneIn( Entity::Player& player ) "HousingInteriorTerritory::onPlayerZoneIn: Zone#" + std::to_string( getGuId() ) + "|" + std::to_string( getTerritoryTypeId() ) + ", Entity#" + std::to_string( player.getId() ) ); - auto indoorInitPacket = makeZonePacket< FFXIVIpcHousingIndoorInitialize >( player.getId() ); + auto indoorInitPacket = makeZonePacket< Server::FFXIVIpcHousingIndoorInitialize >( player.getId() ); indoorInitPacket->data().u1 = 0; indoorInitPacket->data().u2 = 0; indoorInitPacket->data().u3 = 0; @@ -72,40 +74,109 @@ void Housing::HousingInteriorTerritory::onPlayerZoneIn( Entity::Player& player ) static_cast< Common::HousingInteriorSlot >( i ) ); } - - uint32_t yardPacketNum; - uint32_t yardPacketTotal = 2 + pLand->getSize(); - player.queuePacket( indoorInitPacket ); - for( yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ ) + auto yardPacketTotal = static_cast< uint8_t >( 2 + pLand->getSize() ); + for( uint8_t yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ ) { - auto objectInitPacket = makeZonePacket< FFXIVIpcHousingObjectInitialize >( player.getId() ); + auto objectInitPacket = makeZonePacket< Server::FFXIVIpcHousingObjectInitialize >( player.getId() ); memcpy( &objectInitPacket->data().landIdent, &m_landIdent, sizeof( Common::LandIdent ) ); objectInitPacket->data().u1 = 0; objectInitPacket->data().u2 = 100; objectInitPacket->data().packetNum = yardPacketNum; objectInitPacket->data().packetTotal = yardPacketTotal; - //TODO: Add Objects here + auto yardObjectSize = sizeof( Common::YardObject ); + memcpy( &objectInitPacket->data().object, m_yardObjects.data() + ( yardPacketNum * 100 ), yardObjectSize * 100 ); player.queuePacket( objectInitPacket ); } } -void Housing::HousingInteriorTerritory::onUpdate( uint32_t currTime ) +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onUpdate( uint32_t currTime ) { if( m_playerMap.size() > 0 ) m_lastActivityTime = currTime; } -uint32_t Housing::HousingInteriorTerritory::getLastActivityTime() const +uint32_t Sapphire::World::Territory::Housing::HousingInteriorTerritory::getLastActivityTime() const { return m_lastActivityTime; } -const Common::LandIdent Housing::HousingInteriorTerritory::getLandIdent() const +const Common::LandIdent Sapphire::World::Territory::Housing::HousingInteriorTerritory::getLandIdent() const { return m_landIdent; +} + +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateYardObjects() +{ + auto housingMgr = g_fw.get< Manager::HousingMgr >(); + + auto containerIds = { + InventoryType::HousingInteriorPlacedItems1, + InventoryType::HousingInteriorPlacedItems2, + InventoryType::HousingInteriorPlacedItems3, + InventoryType::HousingInteriorPlacedItems4, + InventoryType::HousingInteriorPlacedItems5, + InventoryType::HousingInteriorPlacedItems6, + InventoryType::HousingInteriorPlacedItems7, + InventoryType::HousingInteriorPlacedItems8, + }; + + // zero out the array + // there's some really weird behaviour where *some* values will cause the linkshell invite notification to pop up + // for some reason + Common::YardObject obj {}; + memset( &obj, 0x0, sizeof( Common::YardObject ) ); + m_yardObjects.fill( obj ); + + auto containers = housingMgr->getEstateInventory( getLandIdent() ); + + uint8_t containerIdx = 0; + for( auto containerId : containerIds ) + { + auto container = containers.find( containerId ); + if( container == containers.end() ) + // no more containers left + break; + + for( const auto& item : container->second->getItemMap() ) + { + auto housingItem = std::dynamic_pointer_cast< Inventory::HousingItem >( item.second ); + assert( housingItem ); + + auto offset = item.first + ( containerIdx * 50 ); + + auto obj = housingMgr->getYardObjectForItem( housingItem ); + + m_yardObjects[ offset ] = obj; + } + + containerIdx++; + } +} + +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnYardObject( uint8_t containerIdx, + uint16_t slot, + Inventory::HousingItemPtr item ) +{ + auto housingMgr = g_fw.get< Manager::HousingMgr >(); + + auto offset = ( containerIdx * 50 ) + slot; + auto obj = housingMgr->getYardObjectForItem( item ); + + m_yardObjects[ offset ] = obj; + +// for( const auto& player : m_playerMap ) +// { +// auto packet = makeZonePacket< Server::FFXIVIpcYardObjectSpawn >( player.second->getId() ); +// +// packet->data().landSetId = 0; +// packet->data().objectArray = static_cast< uint8_t >( offset ); +// packet->data().object = obj; +// +// player.second->queuePacket( packet ); +// } } \ No newline at end of file diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.h b/src/world/Territory/Housing/HousingInteriorTerritory.h index 153e3604..12bcc233 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.h +++ b/src/world/Territory/Housing/HousingInteriorTerritory.h @@ -1,5 +1,7 @@ #include "ForwardsZone.h" #include "Territory/Zone.h" +#include "Common.h" +#include namespace Sapphire::World::Territory::Housing { @@ -22,8 +24,13 @@ namespace Sapphire::World::Territory::Housing const Common::LandIdent getLandIdent() const; + void updateYardObjects(); + void spawnYardObject( uint8_t containerIdx, uint16_t slot, Inventory::HousingItemPtr item ); + private: Common::LandIdent m_landIdent; uint32_t m_lastActivityTime; + + std::array< Sapphire::Common::YardObject, 400 > m_yardObjects; }; } \ No newline at end of file diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 414e927a..d7ff7e08 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -103,6 +103,14 @@ bool Sapphire::HousingZone::init() cursor += itemMax; } + // zero out the yard obj arrays so we don't leak memory like SE does :^) + Common::YardObject obj {}; + memset( &obj, 0x0, sizeof( Common::YardObject ) ); + + for( auto& arr : m_yardObjects ) + { + arr.fill( obj ); + } auto housingMgr = g_fw.get< World::Manager::HousingMgr >(); auto landCache = housingMgr->getLandCacheMap(); @@ -137,27 +145,7 @@ bool Sapphire::HousingZone::init() if( entry.m_houseId > 0 ) registerEstateEntranceEObj( entry.m_landId ); - // add items to yard object array - auto& inventory = housingMgr->getEstateInventory( land->getLandIdent() ); - auto& externalContainer = inventory[ InventoryType::HousingExteriorPlacedItems ]; - - auto arrayBounds = m_yardObjectArrayBounds[ entry.m_landId ]; - auto yardMapIndex = entry.m_landId <= 29 ? 0 : 1; - - for( auto& item : externalContainer->getItemMap() ) - { - Common::YardObject obj{}; - - auto housingItem = std::dynamic_pointer_cast< Inventory::HousingItem >( item.second ); - assert( housingItem ); - - obj.itemId = housingItem->getAdditionalData(); - obj.itemRotation = housingItem->getRot(); - obj.pos = housingItem->getPos(); - - auto idx = item.first + arrayBounds.first; - m_yardObjects[ yardMapIndex ][ idx ] = obj; - } + updateYardObjects( land->getLandIdent() ); } return true; @@ -344,9 +332,16 @@ void Sapphire::HousingZone::updateYardObjects( Sapphire::Common::LandIdent ident auto yardContainer = landStorage[ InventoryType::HousingExteriorPlacedItems ]; + auto arrayBounds = m_yardObjectArrayBounds[ ident.landId ]; + auto yardMapIndex = ident.landId <= 29 ? 0 : 1; + for( const auto& item : yardContainer->getItemMap() ) { + auto housingItem = std::dynamic_pointer_cast< Inventory::HousingItem >( item.second ); + assert( housingItem ); + auto idx = item.first + arrayBounds.first; + m_yardObjects[ yardMapIndex ][ idx ] = housingMgr->getYardObjectForItem( housingItem ); } } @@ -371,7 +366,7 @@ void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, In { auto packet = makeZonePacket< Server::FFXIVIpcYardObjectSpawn >( player.second->getId() ); - packet->data().landSetId = landId; + packet->data().landId = landId; packet->data().objectArray = static_cast< uint8_t >( slotId ); packet->data().object = obj; From 2dcc6e460c6cfbe887d1e8d8620c177d491fcc46 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 27 Dec 2018 00:36:47 +1100 Subject: [PATCH 25/40] add internal housing item placement --- src/common/Network/PacketDef/Ipcs.h | 1 + .../Network/PacketDef/Zone/ServerZoneDef.h | 13 ++++++++++ src/world/Manager/HousingMgr.cpp | 14 ++++------- .../Network/Handlers/ClientTriggerHandler.cpp | 2 ++ .../Housing/HousingInteriorTerritory.cpp | 24 +++++++++++-------- .../Housing/HousingInteriorTerritory.h | 2 +- 6 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index 0273dc17..c4c82786 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -201,6 +201,7 @@ namespace Sapphire::Network::Packets HousingShowEstateGuestAccess = 0x022A, // updated 4.4 HousingObjectInitialize = 0x022C, // updated 4.4 + HousingInternalObjectSpawn = 0x22D, // updated 4.4 HousingWardInfo = 0x022F, // updated 4.4 YardObjectMove = 0x0230, // updated 4.4 diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 75ea7041..2f039202 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1711,6 +1711,19 @@ struct FFXIVIpcHousingObjectInitialize : FFXIVIpcBasePacket< HousingObjectInitia uint32_t unknown4; //unused }; +struct FFXIVIpcHousingInternalObjectSpawn : FFXIVIpcBasePacket< HousingInternalObjectSpawn > +{ + uint16_t containerId; + uint8_t containerOffset; + uint8_t pad1; + + uint16_t itemId; + uint8_t unk2; + uint8_t pad2; + uint16_t rotation; + Common::FFXIVARR_POSITION3_U16 pos; +}; + struct FFXIVIpcHousingIndoorInitialize : FFXIVIpcBasePacket< HousingIndoorInitialize > { uint16_t u1; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 0f481cd2..34737379 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -934,18 +934,14 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity isOutside = true; } // otherwise, inside a house. landId is 0 when inside a plot - else if( landId == 0 ) + else if( auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ) ) { - auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); - if( !zone ) - return; - // 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( landId ); + land = getHousingZoneByLandSetId( landSet )->getLand( ident.landId ); } // wtf? else @@ -994,8 +990,8 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity } else { - player.sendUrgent( "you can't place internal items (yet)" ); - return; + if( !placeInteriorItem( player, item ) ) + player.sendUrgent( "An internal error occurred when placing the item." ); } } @@ -1082,7 +1078,7 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); assert( zone ); - zone->spawnYardObject( containerIdx, freeSlot, item ); + zone->spawnYardObject( containerIdx, freeSlot, containerId, item ); return true; } diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index 157739eb..092c47a0 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -448,6 +448,8 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX if( !housingMgr ) break; + + // housingMgr->sendHousingInventory( player, Common::InventoryType::HousingInd, 255 ); break; diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index a99daaed..bba2adaf 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -160,6 +160,7 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateYardOb void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnYardObject( uint8_t containerIdx, uint16_t slot, + uint16_t containerType, Inventory::HousingItemPtr item ) { auto housingMgr = g_fw.get< Manager::HousingMgr >(); @@ -169,14 +170,17 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnYardObj m_yardObjects[ offset ] = obj; -// for( const auto& player : m_playerMap ) -// { -// auto packet = makeZonePacket< Server::FFXIVIpcYardObjectSpawn >( player.second->getId() ); -// -// packet->data().landSetId = 0; -// packet->data().objectArray = static_cast< uint8_t >( offset ); -// packet->data().object = obj; -// -// player.second->queuePacket( packet ); -// } + for( const auto& player : m_playerMap ) + { + auto objectSpawnPkt = makeZonePacket< Server::FFXIVIpcHousingInternalObjectSpawn >( player.second->getId() ); + + objectSpawnPkt->data().containerId = containerType; + objectSpawnPkt->data().containerOffset = slot; + + objectSpawnPkt->data().itemId = item->getAdditionalData() & 0xFFFF; + objectSpawnPkt->data().rotation = item->getRot(); + objectSpawnPkt->data().pos = item->getPos(); + + player.second->queuePacket( objectSpawnPkt ); + } } \ No newline at end of file diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.h b/src/world/Territory/Housing/HousingInteriorTerritory.h index 12bcc233..07c69040 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.h +++ b/src/world/Territory/Housing/HousingInteriorTerritory.h @@ -25,7 +25,7 @@ namespace Sapphire::World::Territory::Housing const Common::LandIdent getLandIdent() const; void updateYardObjects(); - void spawnYardObject( uint8_t containerIdx, uint16_t slot, Inventory::HousingItemPtr item ); + void spawnYardObject( uint8_t containerIdx, uint16_t slot, uint16_t containerType, Inventory::HousingItemPtr item ); private: Common::LandIdent m_landIdent; From a0616207a346cf04ba78889c552d74e58fa02d05 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 27 Dec 2018 01:09:33 +1100 Subject: [PATCH 26/40] correctly send inventories when using internal furnishings menu --- src/world/Manager/HousingMgr.cpp | 51 +++++++++++++++++++ src/world/Manager/HousingMgr.h | 7 +++ .../Network/Handlers/ClientTriggerHandler.cpp | 12 ++--- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 34737379..2162a577 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1095,4 +1095,55 @@ Sapphire::Common::YardObject Sapphire::World::Manager::HousingMgr::getYardObject obj.itemId = item->getAdditionalData(); return obj; +} + +void Sapphire::World::Manager::HousingMgr::sendInternalEstateInventoryBatch( Sapphire::Entity::Player& player, + bool storeroom ) +{ + auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); + if( !zone ) + return; + + std::vector< uint16_t > containerIds; + + if( !storeroom ) + { + containerIds = { + InventoryType::HousingInteriorPlacedItems1, + InventoryType::HousingInteriorPlacedItems2, + InventoryType::HousingInteriorPlacedItems3, + InventoryType::HousingInteriorPlacedItems4, + InventoryType::HousingInteriorPlacedItems5, + InventoryType::HousingInteriorPlacedItems6, + InventoryType::HousingInteriorPlacedItems7, + InventoryType::HousingInteriorPlacedItems8, + }; + } + else + { + containerIds = { + InventoryType::HousingInteriorStoreroom1, + InventoryType::HousingInteriorStoreroom2, + InventoryType::HousingInteriorStoreroom3, + InventoryType::HousingInteriorStoreroom4, + InventoryType::HousingInteriorStoreroom5, + InventoryType::HousingInteriorStoreroom6, + InventoryType::HousingInteriorStoreroom7, + InventoryType::HousingInteriorStoreroom8, + }; + } + + // todo: perms check + + auto invMgr = g_fw.get< Manager::InventoryMgr >(); + auto& containers = getEstateInventory( zone->getLandIdent() ); + + for( auto containerId : containerIds ) + { + auto container = containers.find( containerId ); + if( container == containers.end() ) + break; + + invMgr->sendInventoryContainer( player, container->second ); + } } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index e7bc4251..93fd8f40 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -114,6 +114,13 @@ namespace Sapphire::World::Manager */ void sendEstateInventory( Entity::Player& player, uint16_t inventoryType, uint8_t plotNum ); + /*! + * @brief Sends all the available internal inventories in one go. Used to initially populate the menu. + * @param player The player to send the containers to + * @param storeroom True if we should send the storeroom, false we send the placed items + */ + void sendInternalEstateInventoryBatch( Entity::Player& player, bool storeroom = false ); + /*! * @brief Get the land & house data that was cached on world startup. * @return diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index 092c47a0..0140b78d 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -440,17 +440,17 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX } case ClientTriggerType::RequestEstateInventory: { - // only sent if param1 is 1, because the client sends this with 0 when you open the ui for whatever reason - if( param1 != 1 ) - return; - auto housingMgr = g_fw.get< HousingMgr >(); if( !housingMgr ) break; + // param1 = 1 - storeroom + // param1 = 0 - placed items - - // housingMgr->sendHousingInventory( player, Common::InventoryType::HousingInd, 255 ); + if( param1 == 1 ) + housingMgr->sendInternalEstateInventoryBatch( player, true ); + else + housingMgr->sendInternalEstateInventoryBatch( player ); break; } From 6fb1f90b46249c0dadceac566ce1faf18d4ceb3f Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 27 Dec 2018 13:33:29 +1100 Subject: [PATCH 27/40] cleanup container lists in housingmgr --- src/world/Manager/HousingMgr.cpp | 67 ++++++++++++++------------------ src/world/Manager/HousingMgr.h | 5 +++ 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 2162a577..2971830f 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -46,6 +46,30 @@ Sapphire::World::Manager::HousingMgr::HousingMgr() m_containerMap[ 5 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); m_containerMap[ 6 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); m_containerMap[ 7 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + + m_internalPlacedItemContainers = + { + InventoryType::HousingInteriorPlacedItems1, + InventoryType::HousingInteriorPlacedItems2, + InventoryType::HousingInteriorPlacedItems3, + InventoryType::HousingInteriorPlacedItems4, + InventoryType::HousingInteriorPlacedItems5, + InventoryType::HousingInteriorPlacedItems6, + InventoryType::HousingInteriorPlacedItems7, + InventoryType::HousingInteriorPlacedItems8, + }; + + m_internalStoreroomContainers = + { + InventoryType::HousingInteriorStoreroom1, + InventoryType::HousingInteriorStoreroom2, + InventoryType::HousingInteriorStoreroom3, + InventoryType::HousingInteriorStoreroom4, + InventoryType::HousingInteriorStoreroom5, + InventoryType::HousingInteriorStoreroom6, + InventoryType::HousingInteriorStoreroom7, + InventoryType::HousingInteriorStoreroom8, + }; } Sapphire::World::Manager::HousingMgr::~HousingMgr() = default; @@ -1034,17 +1058,6 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl { auto invMgr = g_fw.get< InventoryMgr >(); - auto containerIds = { - InventoryType::HousingInteriorPlacedItems1, - InventoryType::HousingInteriorPlacedItems2, - InventoryType::HousingInteriorPlacedItems3, - InventoryType::HousingInteriorPlacedItems4, - InventoryType::HousingInteriorPlacedItems5, - InventoryType::HousingInteriorPlacedItems6, - InventoryType::HousingInteriorPlacedItems7, - InventoryType::HousingInteriorPlacedItems8, - }; - auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); assert( zone ); @@ -1052,7 +1065,7 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl // find first free container uint8_t containerIdx = 0; - for( auto containerId : containerIds ) + for( auto containerId : m_internalPlacedItemContainers ) { auto& container = getEstateInventory( ident )[ containerId ]; @@ -1104,34 +1117,12 @@ void Sapphire::World::Manager::HousingMgr::sendInternalEstateInventoryBatch( Sap if( !zone ) return; - std::vector< uint16_t > containerIds; + InventoryTypeList containerIds; - if( !storeroom ) - { - containerIds = { - InventoryType::HousingInteriorPlacedItems1, - InventoryType::HousingInteriorPlacedItems2, - InventoryType::HousingInteriorPlacedItems3, - InventoryType::HousingInteriorPlacedItems4, - InventoryType::HousingInteriorPlacedItems5, - InventoryType::HousingInteriorPlacedItems6, - InventoryType::HousingInteriorPlacedItems7, - InventoryType::HousingInteriorPlacedItems8, - }; - } + if( storeroom ) + containerIds = m_internalStoreroomContainers; else - { - containerIds = { - InventoryType::HousingInteriorStoreroom1, - InventoryType::HousingInteriorStoreroom2, - InventoryType::HousingInteriorStoreroom3, - InventoryType::HousingInteriorStoreroom4, - InventoryType::HousingInteriorStoreroom5, - InventoryType::HousingInteriorStoreroom6, - InventoryType::HousingInteriorStoreroom7, - InventoryType::HousingInteriorStoreroom8, - }; - } + containerIds = m_internalPlacedItemContainers; // todo: perms check diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 93fd8f40..4506fe1c 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -66,6 +66,8 @@ namespace Sapphire::World::Manager */ using LandIdentToInventoryContainerMap = std::unordered_map< uint64_t, ContainerIdToContainerMap >; + using InventoryTypeList = std::vector< Common::InventoryType >; + HousingMgr(); virtual ~HousingMgr(); @@ -228,6 +230,9 @@ namespace Sapphire::World::Manager LandSetLandCacheMap m_landCache; LandIdentToInventoryContainerMap m_estateInventories; + InventoryTypeList m_internalPlacedItemContainers; + InventoryTypeList m_internalStoreroomContainers; + std::array< std::pair< Common::InventoryType, Common::InventoryType >, 8 > m_containerMap; }; From 8aed0e7979a67f468fc1aa6ed90f7f6407dce651 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 27 Dec 2018 15:52:48 +1100 Subject: [PATCH 28/40] fix container handling issue where they were created incorrectly --- src/common/Network/PacketDef/Ipcs.h | 2 +- .../Network/PacketDef/Zone/ClientZoneDef.h | 13 ++++++ src/world/Manager/HousingMgr.cpp | 45 +++++++++++++++---- src/world/Manager/HousingMgr.h | 5 +++ src/world/Network/GameConnection.cpp | 2 + src/world/Network/GameConnection.h | 2 + src/world/Network/Handlers/PacketHandlers.cpp | 12 +++++ 7 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index c4c82786..62522203 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -314,7 +314,7 @@ namespace Sapphire::Network::Packets LandRenameHandler = 0x0171, // updated 4.4 HousingUpdateHouseGreeting = 0x0172, // updated 4.4 - HousingUpdateObjectRotation = 0x0173, // updated 4.4 + HousingUpdateObjectPosition = 0x0173, // updated 4.4 SetSharedEstateSettings = 0x0177, // updated 4.4 diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 2cf8c863..011fd400 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -256,6 +256,19 @@ struct FFXIVIpcReqPlaceHousingItem : /* 0020 */ uint32_t unknown4[2]; // always 0 it looks like }; +struct FFXIVIpcHousingUpdateObjectPosition : + FFXIVIpcBasePacket< HousingUpdateObjectPosition > +{ + /* 0000 */ Common::LandIdent ident; + /* 0008 */ uint16_t slot; + /* 000A */ uint16_t containerId; + + /* 000C */ Common::FFXIVARR_POSITION3 pos; + /* 0018 */ float rotation; + + /* 001C */ uint32_t padding; +}; + } } } diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 2971830f..c41094ca 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -39,13 +39,13 @@ extern Sapphire::Framework g_fw; Sapphire::World::Manager::HousingMgr::HousingMgr() { m_containerMap[ 0 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); - m_containerMap[ 1 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); - m_containerMap[ 2 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); - m_containerMap[ 3 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); - m_containerMap[ 4 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); - m_containerMap[ 5 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); - m_containerMap[ 6 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); - m_containerMap[ 7 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems1, InventoryType::HousingInteriorStoreroom1 ); + m_containerMap[ 1 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems2, InventoryType::HousingInteriorStoreroom2 ); + m_containerMap[ 2 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems3, InventoryType::HousingInteriorStoreroom3 ); + m_containerMap[ 3 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems4, InventoryType::HousingInteriorStoreroom4 ); + m_containerMap[ 4 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems5, InventoryType::HousingInteriorStoreroom5 ); + m_containerMap[ 5 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems6, InventoryType::HousingInteriorStoreroom6 ); + m_containerMap[ 6 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems7, InventoryType::HousingInteriorStoreroom7 ); + m_containerMap[ 7 ] = std::make_pair( InventoryType::HousingInteriorPlacedItems8, InventoryType::HousingInteriorStoreroom8 ); m_internalPlacedItemContainers = { @@ -247,7 +247,7 @@ void Sapphire::World::Manager::HousingMgr::initLandCache() uint16_t count = 0; for( int i = 0; i < 8; ++i ) { - if( count >= entry.m_maxPlacedInternalItems ) + if( count > entry.m_maxPlacedInternalItems ) break; auto& pair = m_containerMap[ i ]; @@ -978,6 +978,9 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity if( land->getOwnerId() != player.getId() ) return; + // todo: check item position and make sure it's not outside the plot + // retail uses a radius based check + // unlink item Inventory::HousingItemPtr item; @@ -1063,12 +1066,17 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl auto ident = zone->getLandIdent(); + auto& containers = getEstateInventory( ident ); + // find first free container uint8_t containerIdx = 0; for( auto containerId : m_internalPlacedItemContainers ) { - auto& container = getEstateInventory( ident )[ containerId ]; + auto needle = containers.find( containerId ); + if( needle == containers.end() ) + continue; + auto container = needle->second; auto freeSlot = container->getFreeSlot(); if( freeSlot == -1 ) { @@ -1137,4 +1145,23 @@ void Sapphire::World::Manager::HousingMgr::sendInternalEstateInventoryBatch( Sap invMgr->sendInventoryContainer( player, container->second ); } +} + +void Sapphire::World::Manager::HousingMgr::reqMoveHousingItem( Entity::Player& player, + Common::LandIdent ident, uint16_t slot, + uint16_t container, + Common::FFXIVARR_POSITION3 pos, float rot ) +{ + auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); + auto land = getHousingZoneByLandSetId( landSet )->getLand( ident.landId ); + + if( !land ) + return; + + // todo: proper perms checks + if( land->getOwnerId() != player.getId() ) + return; + + // update item in db + } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 4506fe1c..14ca5009 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -165,6 +165,11 @@ namespace Sapphire::World::Manager */ Common::YardObject getYardObjectForItem( Inventory::HousingItemPtr item ) const; + + void reqMoveHousingItem( Entity::Player& player, Common::LandIdent ident, uint16_t slot, + uint16_t container, Common::FFXIVARR_POSITION3 pos, float rot ); + + private: /*! diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index cf16b7db..7530d2b5 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -89,6 +89,8 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::HousingUpdateHouseGreeting, "HousingUpdateHouseGreeting", &GameConnection::housingUpdateGreetingHandler ); setZoneHandler( ClientZoneIpcType::ReqPlaceHousingItem, "ReqPlaceHousingItem", &GameConnection::reqPlaceHousingItem ); + setZoneHandler( ClientZoneIpcType::HousingUpdateObjectPosition, "HousingUpdateObjectPosition", + &GameConnection::reqMoveHousingItem ); setZoneHandler( ClientZoneIpcType::TalkEventHandler, "EventHandlerTalk", &GameConnection::eventHandlerTalk ); setZoneHandler( ClientZoneIpcType::EmoteEventHandler, "EventHandlerEmote", &GameConnection::eventHandlerEmote ); diff --git a/src/world/Network/GameConnection.h b/src/world/Network/GameConnection.h index 60710546..b6fa0738 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -173,6 +173,8 @@ namespace Sapphire::Network DECLARE_HANDLER( reqPlaceHousingItem ); + DECLARE_HANDLER( reqMoveHousingItem ); + }; } diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index e3207a63..daab3cdb 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -715,4 +715,16 @@ void Sapphire::Network::GameConnection::reqPlaceHousingItem( const Packets::FFXI housingMgr->reqPlaceHousingItem( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId, data.position, data.rotation ); +} + +void Sapphire::Network::GameConnection::reqMoveHousingItem( const Packets::FFXIVARR_PACKET_RAW& inPacket, + Entity::Player& player ) +{ + auto housingMgr = g_fw.get< HousingMgr >(); + + const auto packet = ZoneChannelPacket< Client::FFXIVIpcHousingUpdateObjectPosition >( inPacket ); + const auto& data = packet.data(); + + housingMgr->reqMoveHousingItem( player, data.ident, data.slot, data.containerId, data.pos, data.rotation ); + } \ No newline at end of file From 858b243e3be29c62bfea79e914a9226d78e05f14 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 27 Dec 2018 17:12:01 +1100 Subject: [PATCH 29/40] internal item rotation/movement done --- src/common/Network/CommonActorControl.h | 9 +++ .../Network/PacketDef/Zone/ClientZoneDef.h | 2 +- src/world/Manager/HousingMgr.cpp | 72 ++++++++++++++++++- src/world/Manager/HousingMgr.h | 35 ++++++++- src/world/Network/Handlers/PacketHandlers.cpp | 2 +- .../Housing/HousingInteriorTerritory.cpp | 12 ++++ .../Housing/HousingInteriorTerritory.h | 1 + 7 files changed, 128 insertions(+), 5 deletions(-) diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 0f0eda35..8d6e9ea1 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -215,6 +215,15 @@ enum ActorControlType : uint16_t ShowBuildPresetUI = 0x3E9, BuildPresetResponse = 0x3ED, + /*! + * param1 = identity shit + * u16 1 - container id + * u16 2 - plot id + * param2 = item shit + * u16 1 - slot + */ + HousingItemMoveConfirm = 0x3F9, + /*! * param1 = outdoor furnishings * u8 0 - relocation available, 1 = available diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 011fd400..d42e21ed 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -261,7 +261,7 @@ struct FFXIVIpcHousingUpdateObjectPosition : { /* 0000 */ Common::LandIdent ident; /* 0008 */ uint16_t slot; - /* 000A */ uint16_t containerId; + /* 000A */ uint16_t unk; /* 000C */ Common::FFXIVARR_POSITION3 pos; /* 0018 */ float rotation; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index c41094ca..3713c83f 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1149,7 +1149,6 @@ void Sapphire::World::Manager::HousingMgr::sendInternalEstateInventoryBatch( Sap void Sapphire::World::Manager::HousingMgr::reqMoveHousingItem( Entity::Player& player, Common::LandIdent ident, uint16_t slot, - uint16_t container, Common::FFXIVARR_POSITION3 pos, float rot ) { auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); @@ -1162,6 +1161,75 @@ void Sapphire::World::Manager::HousingMgr::reqMoveHousingItem( Entity::Player& p if( land->getOwnerId() != player.getId() ) return; - // update item in db + // todo: what happens when either of these fail? how does the server let the client know that the moment failed + // as is, if it does fail, the client will be locked and unable to move any item until reentering the territory + if( auto terri = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ) ) + { + moveInternalItem( player, ident, *terri, slot, pos, rot ); + } + else if( auto terri = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ) ) + { + moveExternalItem( player, ident, slot, pos, rot ); + } +} +bool Sapphire::World::Manager::HousingMgr::moveInternalItem( Entity::Player& player, Common::LandIdent ident, + Territory::Housing::HousingInteriorTerritory& terri, uint16_t slot, + Common::FFXIVARR_POSITION3 pos, float rot ) +{ + auto containerIdx = static_cast< uint16_t >( slot / 50 ); + auto slotIdx = slot % 50; + + uint16_t containerId = 0; + try + { + containerId = m_internalPlacedItemContainers.at( containerIdx ); + } + catch( const std::out_of_range& ex ) + { + return false; + } + + auto& containers = getEstateInventory( ident ); + + auto needle = containers.find( containerId ); + if( needle == containers.end() ) + return false; + + auto container = needle->second; + + auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slotIdx ) ); + if( !item ) + return false; + + item->setPos( { + Util::floatToUInt16( pos.x ), + Util::floatToUInt16( pos.y ), + Util::floatToUInt16( pos.z ) + } ); + + item->setRot( Util::floatToUInt16Rot( rot ) ); + + // save + auto invMgr = g_fw.get< InventoryMgr >(); + invMgr->updateHousingItemPosition( item ); + + terri.updateObjectPosition( slot, item->getPos(), item->getRot() ); + + // send confirmation to player + uint32_t param1 = ( ident.landId << 16 ) | containerId; + + player.queuePacket( Server::makeActorControl143( player.getId(), ActorControl::HousingItemMoveConfirm, param1, slotIdx ) ); + + // todo: update it for other players?? + + return true; +} + +bool Sapphire::World::Manager::HousingMgr::moveExternalItem( Entity::Player& player, + Common::LandIdent ident, uint16_t slot, + Common::FFXIVARR_POSITION3 pos, float rot ) +{ + + return true; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 14ca5009..9fe6dd42 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -167,11 +167,44 @@ namespace Sapphire::World::Manager void reqMoveHousingItem( Entity::Player& player, Common::LandIdent ident, uint16_t slot, - uint16_t container, Common::FFXIVARR_POSITION3 pos, float rot ); + Common::FFXIVARR_POSITION3 pos, float rot ); private: + /*! + * @brief Processes the movement of an item placed in a HousingZone + * + * This assumes that the player has permission to move the item. + * + * @param player The player who placed the item + * @param ident The ident of the land that the item belongs to + * @param containerIdx The index of the container + * @param slot The slot of the item + * @param pos The new position + * @param rot The new rotation + * @return + */ + bool moveExternalItem( Entity::Player& player, Common::LandIdent ident, uint16_t slot, + Common::FFXIVARR_POSITION3 pos, float rot ); + + /*! + * @brief Processes the movement of an item placed inside a HousingInteriorTerritory + * + * This assumes that the player has permission to move the item. + * + * @param player The player who placed the item + * @param ident The ident of the land that the item belongs to + * @param slot The index of the container + * @param slotIdx The slot of the item + * @param pos The new position + * @param rot The new rotation + * @return + */ + bool moveInternalItem( Entity::Player& player, Common::LandIdent ident, + Territory::Housing::HousingInteriorTerritory& terri, uint16_t slot, + Common::FFXIVARR_POSITION3 pos, float rot ); + /*! * @brief Processes the spawning and linking of a newly placed housing item for external items * @param player The player who is placing the item diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index daab3cdb..3dc5b303 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -725,6 +725,6 @@ void Sapphire::Network::GameConnection::reqMoveHousingItem( const Packets::FFXIV const auto packet = ZoneChannelPacket< Client::FFXIVIpcHousingUpdateObjectPosition >( inPacket ); const auto& data = packet.data(); - housingMgr->reqMoveHousingItem( player, data.ident, data.slot, data.containerId, data.pos, data.rotation ); + housingMgr->reqMoveHousingItem( player, data.ident, data.slot, data.pos, data.rotation ); } \ No newline at end of file diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index bba2adaf..60e147c7 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -183,4 +183,16 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnYardObj player.second->queuePacket( objectSpawnPkt ); } +} + +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateObjectPosition( uint16_t slot, + Sapphire::Common::FFXIVARR_POSITION3_U16 pos, + uint16_t rot ) +{ + auto& obj = m_yardObjects[ slot ]; + + obj.pos = pos; + obj.itemRotation = rot; + + // todo: how does this update on other clients? } \ No newline at end of file diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.h b/src/world/Territory/Housing/HousingInteriorTerritory.h index 07c69040..d928cd27 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.h +++ b/src/world/Territory/Housing/HousingInteriorTerritory.h @@ -26,6 +26,7 @@ namespace Sapphire::World::Territory::Housing void updateYardObjects(); void spawnYardObject( uint8_t containerIdx, uint16_t slot, uint16_t containerType, Inventory::HousingItemPtr item ); + void updateObjectPosition( uint16_t slot, Common::FFXIVARR_POSITION3_U16 pos, uint16_t rot ); private: Common::LandIdent m_landIdent; From 851446f4d8be6ebbc847d1cdc724faab150e6bc9 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 27 Dec 2018 22:28:31 +1100 Subject: [PATCH 30/40] a bit of refactoring, partially working yard item movement --- src/common/Common.h | 2 +- src/common/Network/CommonActorControl.h | 6 ++ .../Network/PacketDef/Zone/ServerZoneDef.h | 14 ++-- src/world/Manager/HousingMgr.cpp | 65 ++++++++++++++----- src/world/Manager/HousingMgr.h | 4 +- .../Housing/HousingInteriorTerritory.cpp | 34 +++++----- .../Housing/HousingInteriorTerritory.h | 9 +-- src/world/Territory/HousingZone.cpp | 41 +++++++++--- src/world/Territory/HousingZone.h | 5 +- 9 files changed, 123 insertions(+), 57 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 8a86bde6..d777a9e2 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -851,7 +851,7 @@ namespace Sapphire::Common uint32_t unkown1; //12 }; - struct YardObject + struct HousingObject { uint32_t itemId; uint16_t itemRotation; diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 8d6e9ea1..6873140c 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -215,6 +215,11 @@ enum ActorControlType : uint16_t ShowBuildPresetUI = 0x3E9, BuildPresetResponse = 0x3ED, + /*! + * param1 = object array index + */ + RemoveInteriorHousingItem = 0x3F1, + /*! * param1 = identity shit * u16 1 - container id @@ -223,6 +228,7 @@ enum ActorControlType : uint16_t * u16 1 - slot */ HousingItemMoveConfirm = 0x3F9, + OpenEstateSettingsUI = 0x3FF, /*! * param1 = outdoor furnishings diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 2f039202..5a406ee8 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1679,22 +1679,20 @@ struct FFXIVIpcLandSetInitialize : FFXIVIpcBasePacket< LandSetInitialize > LandStruct land[ 30 ]; }; -struct FFXIVIpcYardObjectSpawn : FFXIVIpcBasePacket +struct FFXIVIpcYardObjectSpawn : FFXIVIpcBasePacket< YardObjectSpawn > { uint8_t landId; uint8_t objectArray; uint16_t unknown1; - Common::YardObject object; + Common::HousingObject object; }; -struct FFXIVIpcYardObjectMove : FFXIVIpcBasePacket +struct FFXIVIpcYardObjectMove : FFXIVIpcBasePacket< YardObjectMove > { uint16_t itemRotation; uint8_t objectArray; - uint8_t landSetId; - uint16_t pos_x; - uint16_t pos_y; - uint16_t pos_z; + uint8_t landId; + Common::FFXIVARR_POSITION3_U16 pos; uint16_t unknown1; uint16_t unknown2; uint16_t unknown3; @@ -1707,7 +1705,7 @@ struct FFXIVIpcHousingObjectInitialize : FFXIVIpcBasePacket< HousingObjectInitia uint8_t packetNum; uint8_t packetTotal; uint8_t u2; //Outdoor 0 / Indoor 100(?) - Common::YardObject object[100]; + Common::HousingObject object[100]; uint32_t unknown4; //unused }; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 3713c83f..aea73e84 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1010,16 +1010,17 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity auto ident = land->getLandIdent(); + bool status = false; + if( isOutside ) - { - if( !placeExternalItem( player, item, ident ) ) - player.sendUrgent( "An internal error occurred when placing the item." ); - } + status = placeExternalItem( player, item, ident ); else - { - if( !placeInteriorItem( player, item ) ) - player.sendUrgent( "An internal error occurred when placing the item." ); - } + status = placeInteriorItem( player, item ); + + if( status ) + player.queuePacket( Server::makeActorControl143( player.getId(), 0x3f3 ) ); + else + player.sendUrgent( "An internal error occurred when placing the item." ); } bool Sapphire::World::Manager::HousingMgr::placeExternalItem( Entity::Player& player, @@ -1051,7 +1052,7 @@ bool Sapphire::World::Manager::HousingMgr::placeExternalItem( Entity::Player& pl auto zone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); assert( zone ); - zone->spawnYardObject( ident.landId, freeSlot, item ); + zone->spawnYardObject( ident.landId, freeSlot, *item ); return true; } @@ -1099,7 +1100,7 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); assert( zone ); - zone->spawnYardObject( containerIdx, freeSlot, containerId, item ); + zone->spawnHousingObject( containerIdx, freeSlot, containerId, item ); return true; } @@ -1107,9 +1108,9 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl return false; } -Sapphire::Common::YardObject Sapphire::World::Manager::HousingMgr::getYardObjectForItem( Inventory::HousingItemPtr item ) const +Sapphire::Common::HousingObject Sapphire::World::Manager::HousingMgr::getYardObjectForItem( Inventory::HousingItemPtr item ) const { - Sapphire::Common::YardObject obj {}; + Sapphire::Common::HousingObject obj {}; obj.pos = item->getPos(); obj.itemRotation = item->getRot(); @@ -1169,7 +1170,7 @@ void Sapphire::World::Manager::HousingMgr::reqMoveHousingItem( Entity::Player& p } else if( auto terri = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ) ) { - moveExternalItem( player, ident, slot, pos, rot ); + moveExternalItem( player, ident, slot, *terri, pos, rot ); } } @@ -1214,7 +1215,7 @@ bool Sapphire::World::Manager::HousingMgr::moveInternalItem( Entity::Player& pla auto invMgr = g_fw.get< InventoryMgr >(); invMgr->updateHousingItemPosition( item ); - terri.updateObjectPosition( slot, item->getPos(), item->getRot() ); + terri.updateHousingObjectPosition( slot, item->getPos(), item->getRot() ); // send confirmation to player uint32_t param1 = ( ident.landId << 16 ) | containerId; @@ -1228,8 +1229,42 @@ bool Sapphire::World::Manager::HousingMgr::moveInternalItem( Entity::Player& pla bool Sapphire::World::Manager::HousingMgr::moveExternalItem( Entity::Player& player, Common::LandIdent ident, uint16_t slot, - Common::FFXIVARR_POSITION3 pos, float rot ) + Sapphire::HousingZone& terri, Common::FFXIVARR_POSITION3 pos, + float rot ) { + auto land = terri.getLand( ident.landId ); + + // todo: add proper perms check + if( land->getOwnerId() != player.getId() ) + return false; + + auto& containers = getEstateInventory( ident ); + auto needle = containers.find( InventoryType::HousingExteriorPlacedItems ); + if( needle == containers.end() ) + return false; + + auto container = needle->second; + + auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slot ) ); + if( !item ) + return false; + + item->setPos( { + Util::floatToUInt16( pos.x ), + Util::floatToUInt16( pos.y ), + Util::floatToUInt16( pos.z ) + } ); + + item->setRot( Util::floatToUInt16Rot( rot ) ); + + auto invMgr = g_fw.get< InventoryMgr >(); + invMgr->updateHousingItemPosition( item ); + + terri.updateYardObjectPos( slot, ident.landId, *item ); + + // todo: something is sent to the player here to indicate the move has finished successfully + // currently they can move one item and then can't move any more + return true; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 9fe6dd42..5fc3dc56 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -163,7 +163,7 @@ namespace Sapphire::World::Manager * @param item The item to convert into a YardObject * @return The resultant YardObject */ - Common::YardObject getYardObjectForItem( Inventory::HousingItemPtr item ) const; + Common::HousingObject getYardObjectForItem( Inventory::HousingItemPtr item ) const; void reqMoveHousingItem( Entity::Player& player, Common::LandIdent ident, uint16_t slot, @@ -186,7 +186,7 @@ namespace Sapphire::World::Manager * @return */ bool moveExternalItem( Entity::Player& player, Common::LandIdent ident, uint16_t slot, - Common::FFXIVARR_POSITION3 pos, float rot ); + Sapphire::HousingZone& terri, Common::FFXIVARR_POSITION3 pos, float rot ); /*! * @brief Processes the movement of an item placed inside a HousingInteriorTerritory diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index 60e147c7..064ba620 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -45,7 +45,7 @@ Housing::HousingInteriorTerritory::~HousingInteriorTerritory() = default; bool Sapphire::World::Territory::Housing::HousingInteriorTerritory::init() { - updateYardObjects(); + updateHousingObjects(); return true; } @@ -86,8 +86,8 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone objectInitPacket->data().packetNum = yardPacketNum; objectInitPacket->data().packetTotal = yardPacketTotal; - auto yardObjectSize = sizeof( Common::YardObject ); - memcpy( &objectInitPacket->data().object, m_yardObjects.data() + ( yardPacketNum * 100 ), yardObjectSize * 100 ); + auto yardObjectSize = sizeof( Common::HousingObject ); + memcpy( &objectInitPacket->data().object, m_housingObjects.data() + ( yardPacketNum * 100 ), yardObjectSize * 100 ); player.queuePacket( objectInitPacket ); } @@ -110,7 +110,7 @@ const Common::LandIdent Sapphire::World::Territory::Housing::HousingInteriorTerr return m_landIdent; } -void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateYardObjects() +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousingObjects() { auto housingMgr = g_fw.get< Manager::HousingMgr >(); @@ -128,9 +128,9 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateYardOb // zero out the array // there's some really weird behaviour where *some* values will cause the linkshell invite notification to pop up // for some reason - Common::YardObject obj {}; - memset( &obj, 0x0, sizeof( Common::YardObject ) ); - m_yardObjects.fill( obj ); + Common::HousingObject obj {}; + memset( &obj, 0x0, sizeof( Common::HousingObject ) ); + m_housingObjects.fill( obj ); auto containers = housingMgr->getEstateInventory( getLandIdent() ); @@ -151,24 +151,24 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateYardOb auto obj = housingMgr->getYardObjectForItem( housingItem ); - m_yardObjects[ offset ] = obj; + m_housingObjects[ offset ] = obj; } containerIdx++; } } -void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnYardObject( uint8_t containerIdx, - uint16_t slot, - uint16_t containerType, - Inventory::HousingItemPtr item ) +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnHousingObject( uint8_t containerIdx, + uint16_t slot, + uint16_t containerType, + Inventory::HousingItemPtr item ) { auto housingMgr = g_fw.get< Manager::HousingMgr >(); auto offset = ( containerIdx * 50 ) + slot; auto obj = housingMgr->getYardObjectForItem( item ); - m_yardObjects[ offset ] = obj; + m_housingObjects[ offset ] = obj; for( const auto& player : m_playerMap ) { @@ -185,11 +185,11 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnYardObj } } -void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateObjectPosition( uint16_t slot, - Sapphire::Common::FFXIVARR_POSITION3_U16 pos, - uint16_t rot ) +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousingObjectPosition( uint16_t slot, + Sapphire::Common::FFXIVARR_POSITION3_U16 pos, + uint16_t rot ) { - auto& obj = m_yardObjects[ slot ]; + auto& obj = m_housingObjects[ slot ]; obj.pos = pos; obj.itemRotation = rot; diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.h b/src/world/Territory/Housing/HousingInteriorTerritory.h index d928cd27..f77fc49a 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.h +++ b/src/world/Territory/Housing/HousingInteriorTerritory.h @@ -24,14 +24,15 @@ namespace Sapphire::World::Territory::Housing const Common::LandIdent getLandIdent() const; - void updateYardObjects(); - void spawnYardObject( uint8_t containerIdx, uint16_t slot, uint16_t containerType, Inventory::HousingItemPtr item ); - void updateObjectPosition( uint16_t slot, Common::FFXIVARR_POSITION3_U16 pos, uint16_t rot ); + void updateHousingObjects(); + void spawnHousingObject( uint8_t containerIdx, uint16_t slot, uint16_t containerType, + Inventory::HousingItemPtr item ); + void updateHousingObjectPosition( uint16_t slot, Common::FFXIVARR_POSITION3_U16 pos, uint16_t rot ); private: Common::LandIdent m_landIdent; uint32_t m_lastActivityTime; - std::array< Sapphire::Common::YardObject, 400 > m_yardObjects; + std::array< Sapphire::Common::HousingObject, 400 > m_housingObjects; }; } \ No newline at end of file diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index d7ff7e08..07bac271 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -104,8 +104,8 @@ bool Sapphire::HousingZone::init() } // zero out the yard obj arrays so we don't leak memory like SE does :^) - Common::YardObject obj {}; - memset( &obj, 0x0, sizeof( Common::YardObject ) ); + Common::HousingObject obj {}; + memset( &obj, 0x0, sizeof( Common::HousingObject ) ); for( auto& arr : m_yardObjects ) { @@ -175,7 +175,7 @@ void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player ) housingObjectInit->data().packetNum = yardPacketNum; housingObjectInit->data().packetTotal = yardPacketTotal; - auto yardObjectSize = sizeof( Common::YardObject ); + auto yardObjectSize = sizeof( Common::HousingObject ); auto& objects = m_yardObjects[ isInSubdivision ? 1 : 0 ]; @@ -345,17 +345,17 @@ void Sapphire::HousingZone::updateYardObjects( Sapphire::Common::LandIdent ident } } -void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, Inventory::HousingItemPtr item ) +void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, Inventory::HousingItem& item ) { auto bounds = m_yardObjectArrayBounds[ landId ]; auto offset = bounds.first + slotId; - Common::YardObject obj {}; + Common::HousingObject obj {}; - obj.itemId = item->getAdditionalData(); - obj.itemRotation = item->getRot(); + obj.itemId = item.getAdditionalData(); + obj.itemRotation = item.getRot(); - obj.pos = item->getPos(); + obj.pos = item.getPos(); // link obj auto yardMapIndex = landId <= 29 ? 0 : 1; @@ -370,6 +370,31 @@ void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, In packet->data().objectArray = static_cast< uint8_t >( slotId ); packet->data().object = obj; + player.second->queuePacket( packet ); + } +} + +void Sapphire::HousingZone::updateYardObjectPos( uint16_t slot, uint16_t landId, Inventory::HousingItem& item ) +{ + auto bounds = m_yardObjectArrayBounds[ landId ]; + auto offset = bounds.first + slot; + auto yardMapIndex = landId <= 29 ? 0 : 1; + + auto& obj = m_yardObjects[ yardMapIndex ][ offset ]; + + obj.itemRotation = item.getRot(); + obj.pos = item.getPos(); + + for( const auto& player : m_playerMap ) + { + auto packet = makeZonePacket< Server::FFXIVIpcYardObjectMove >( player.second->getId() ); + + packet->data().itemRotation = item.getRot(); + packet->data().pos = item.getPos(); + + packet->data().landId = landId; + packet->data().objectArray = slot; + player.second->queuePacket( packet ); } } \ No newline at end of file diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index 8b14f711..b8295afe 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -55,11 +55,12 @@ namespace Sapphire Entity::EventObjectPtr registerEstateEntranceEObj( uint8_t landId ); void updateYardObjects( Common::LandIdent ident ); - void spawnYardObject( uint8_t landId, uint16_t slotId, Sapphire::Inventory::HousingItemPtr item ); + void spawnYardObject( uint8_t landId, uint16_t slotId, Sapphire::Inventory::HousingItem& item ); + void updateYardObjectPos( uint16_t slot, uint16_t landId, Inventory::HousingItem& item ); private: using LandPtrMap = std::unordered_map< uint8_t, Sapphire::LandPtr >; - using YardObjectArray = std::array< Common::YardObject, 800 >; + using YardObjectArray = std::array< Common::HousingObject, 800 >; using YardObjectSubdivisionArray = std::array< YardObjectArray, 2 >; /*! From e4513a3243ecf4e0f45192c666d10639428768eb Mon Sep 17 00:00:00 2001 From: NotAdam Date: Thu, 27 Dec 2018 23:48:55 +1100 Subject: [PATCH 31/40] fix issue where yard items couldn't be moved properly --- src/common/Network/CommonActorControl.h | 5 +++++ src/world/Manager/HousingMgr.cpp | 6 +++--- src/world/Territory/HousingZone.cpp | 7 ++++++- src/world/Territory/HousingZone.h | 3 ++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 6873140c..965d816a 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -215,6 +215,11 @@ enum ActorControlType : uint16_t ShowBuildPresetUI = 0x3E9, BuildPresetResponse = 0x3ED, + /*! + * param1 = object array index + */ + RemoveExteriorHousingItem = 0x3EF, + /*! * param1 = object array index */ diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index aea73e84..1fe8071f 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1260,10 +1260,10 @@ bool Sapphire::World::Manager::HousingMgr::moveExternalItem( Entity::Player& pla auto invMgr = g_fw.get< InventoryMgr >(); invMgr->updateHousingItemPosition( item ); - terri.updateYardObjectPos( slot, ident.landId, *item ); + terri.updateYardObjectPos( player, slot, ident.landId, *item ); - // todo: something is sent to the player here to indicate the move has finished successfully - // currently they can move one item and then can't move any more + uint32_t param1 = ( ident.landId << 16 ) | InventoryType::HousingExteriorPlacedItems; + player.queuePacket( Server::makeActorControl143( player.getId(), ActorControl::HousingItemMoveConfirm, param1, slot ) ); return true; diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 07bac271..2aaa3b90 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -374,7 +374,8 @@ void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, In } } -void Sapphire::HousingZone::updateYardObjectPos( uint16_t slot, uint16_t landId, Inventory::HousingItem& item ) +void Sapphire::HousingZone::updateYardObjectPos( Entity::Player& sourcePlayer, uint16_t slot, uint16_t landId, + Inventory::HousingItem& item ) { auto bounds = m_yardObjectArrayBounds[ landId ]; auto offset = bounds.first + slot; @@ -387,6 +388,10 @@ void Sapphire::HousingZone::updateYardObjectPos( uint16_t slot, uint16_t landId, for( const auto& player : m_playerMap ) { + // don't send it from the origin player, it already has the position from the move request + if( player.second->getId() == sourcePlayer.getId() ) + continue; + auto packet = makeZonePacket< Server::FFXIVIpcYardObjectMove >( player.second->getId() ); packet->data().itemRotation = item.getRot(); diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index b8295afe..aac75ca0 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -56,7 +56,8 @@ namespace Sapphire void updateYardObjects( Common::LandIdent ident ); void spawnYardObject( uint8_t landId, uint16_t slotId, Sapphire::Inventory::HousingItem& item ); - void updateYardObjectPos( uint16_t slot, uint16_t landId, Inventory::HousingItem& item ); + void updateYardObjectPos( Entity::Player& sourcePlayer, uint16_t slot, uint16_t landId, + Inventory::HousingItem& item ); private: using LandPtrMap = std::unordered_map< uint8_t, Sapphire::LandPtr >; From 298b31512cb0a898c5058d12285995e200946375 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 02:17:29 +1100 Subject: [PATCH 32/40] base implementation of moving housing items back to player inventory only works for internal items atm --- src/common/Network/CommonActorControl.h | 1 + .../Network/PacketDef/Zone/ClientZoneDef.h | 3 +- src/world/Actor/Player.h | 6 + src/world/Actor/PlayerInventory.cpp | 34 ++++++ src/world/Manager/HousingMgr.cpp | 111 +++++++++++++++++- src/world/Manager/HousingMgr.h | 36 +++++- src/world/Manager/InventoryMgr.cpp | 28 +++++ src/world/Manager/InventoryMgr.h | 14 +++ .../Network/Handlers/ClientTriggerHandler.cpp | 16 ++- .../Housing/HousingInteriorTerritory.cpp | 14 +++ .../Housing/HousingInteriorTerritory.h | 1 + 11 files changed, 256 insertions(+), 8 deletions(-) diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 965d816a..5cce81d3 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -333,6 +333,7 @@ enum ActorControlType : uint16_t RequestWardLandInfo = 0x453, RequestLandRelinquish = 0x454, RequestLandInventory = 0x0458, + RequestHousingItemRemove = 0x0459, RequestEstateRename = 0x45A, RequestEstateEditGreeting = 0x45B, RequestEstateGreeting = 0x45C, // sends FFXIVIpcHousingEstateGreeting in return diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index d42e21ed..87867f0a 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -41,7 +41,8 @@ struct FFXIVIpcClientTrigger : /* 0004 */ uint32_t param11; /* 0008 */ uint32_t param12; /* 000C */ uint32_t param2; - /* 0010 */ char unk_10[8]; + /* 0010 */ uint32_t housingParam; // todo: param4? + /* 0014 */ char unk_14[4]; /* 0018 */ uint64_t param3; }; diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index e620359f..3a59f726 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -365,6 +365,12 @@ namespace Sapphire::Entity Common::GearModelSlot equipSlotToModelSlot( Common::GearSetSlot slot ); + using InventoryContainerPair = std::pair< Common::InventoryType, uint8_t >; + + bool getFreeInventoryContainerSlot( Entity::Player::InventoryContainerPair& containerPair ) const; + + void insertInventoryItem( Common::InventoryType type, uint16_t slot, const Sapphire::ItemPtr item ); + /*! * Collect real item handins from container * @param itemIds a vector of each catalog id to collect diff --git a/src/world/Actor/PlayerInventory.cpp b/src/world/Actor/PlayerInventory.cpp index d908cbcf..850c45e2 100644 --- a/src/world/Actor/PlayerInventory.cpp +++ b/src/world/Actor/PlayerInventory.cpp @@ -901,4 +901,38 @@ Sapphire::ItemPtr Sapphire::Entity::Player::dropInventoryItem( Sapphire::Common: queuePacket( invTransFinPacket ); return item; +} + +bool Sapphire::Entity::Player::getFreeInventoryContainerSlot( Entity::Player::InventoryContainerPair& containerPair ) const +{ + for( auto bagId : { Bag0, Bag1, Bag2, Bag3 } ) + { + auto needle = m_storageMap.find( bagId ); + if( needle == m_storageMap.end() ) + continue; + + auto& container = needle->second; + + for( uint16_t idx = 0; idx < container->getMaxSize(); idx++ ) + { + auto item = container->getItem( idx ); + if( !item ) + { + containerPair = std::make_pair( bagId, idx ); + return true; + } + } + } + + return false; +} + +void Sapphire::Entity::Player::insertInventoryItem( Sapphire::Common::InventoryType type, uint16_t slot, + const Sapphire::ItemPtr item ) +{ + auto& container = m_storageMap[ type ]; + container->setItem( slot, item ); + + auto slotUpdate = std::make_shared< UpdateInventorySlotPacket >( getId(), slot, type, *item ); + queuePacket( slotUpdate ); } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 1fe8071f..7d47d347 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1126,6 +1126,8 @@ void Sapphire::World::Manager::HousingMgr::sendInternalEstateInventoryBatch( Sap if( !zone ) return; + // todo: perms check + InventoryTypeList containerIds; if( storeroom ) @@ -1133,8 +1135,6 @@ void Sapphire::World::Manager::HousingMgr::sendInternalEstateInventoryBatch( Sap else containerIds = m_internalPlacedItemContainers; - // todo: perms check - auto invMgr = g_fw.get< Manager::InventoryMgr >(); auto& containers = getEstateInventory( zone->getLandIdent() ); @@ -1267,4 +1267,111 @@ bool Sapphire::World::Manager::HousingMgr::moveExternalItem( Entity::Player& pla return true; +} + +void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entity::Player& player, uint16_t plot, + uint16_t containerId, uint16_t slot, + bool sendToStoreroom ) +{ + if( auto terri = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ) ) + { + auto ident = terri->getLandIdent(); + auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); + auto land = getHousingZoneByLandSetId( landSet )->getLand( ident.landId ); + + if( !land ) + return; + + // todo: proper perms checks + if( land->getOwnerId() != player.getId() ) + return; + + removeInternalItem( player, *terri, containerId, slot, sendToStoreroom ); + } + else if( auto terri = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ) ) + { + auto land = terri->getLand( plot ); + if( !land ) + return; + + if( land->getOwnerId() != player.getId() ) + return; + + removeExternalItem( player, *terri, containerId, slot, sendToStoreroom ); + } +} + +bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& player, + Territory::Housing::HousingInteriorTerritory& terri, + uint16_t containerId, uint16_t slotId, + bool sendToStoreroom ) +{ + auto& containers = getEstateInventory( terri.getLandIdent() ); + + // validate the container id first + bool foundContainer = false; + uint8_t containerIdx = 0; + for( auto cId : m_internalPlacedItemContainers ) + { + if( containerId == cId ) + { + foundContainer = true; + + break; + } + + containerIdx++; + } + + if( !foundContainer ) + return false; + + auto needle = containers.find( containerId ); + if( needle == containers.end() ) + return false; + + auto container = needle->second; + + auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slotId ) ); + if( !item ) + return false; + + item->setStackSize( 1 ); + + if( !sendToStoreroom ) + { + // make sure the player has a free inv slot first + Entity::Player::InventoryContainerPair containerPair; + if( !player.getFreeInventoryContainerSlot( containerPair ) ) + return false; + + auto invMgr = g_fw.get< InventoryMgr >(); + + + // remove it from housing inventory + container->removeItem( slotId ); + invMgr->sendInventoryContainer( player, container ); + invMgr->removeHousingItemPosition( *item ); + invMgr->removeItemFromHousingContainer( terri.getLandIdent(), containerId, slotId ); + + // add to player inv + player.insertInventoryItem( containerPair.first, containerPair.second, item ); + + // todo: set item as bound/unsellable/untradable + + // despawn + auto arraySlot = ( containerIdx * 50 ) + slotId; + + terri.removeHousingObject( arraySlot ); + } + + return true; +} + +bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& player, + HousingZone& terri, + uint16_t containerId, uint16_t slotId, + bool sendToStoreroom ) +{ + } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 5fc3dc56..53c42362 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -170,12 +170,40 @@ namespace Sapphire::World::Manager Common::FFXIVARR_POSITION3 pos, float rot ); + void reqRemoveHousingItem( Sapphire::Entity::Player& player, uint16_t plot, + uint16_t containerId, uint16_t slot, + bool sendToStoreroom ); + private: + /*! + * + * @param player + * @param terri + * @param containerId + * @param slotId + * @param sendToStoreroom + * @return + */ + bool removeInternalItem( Entity::Player& player, Territory::Housing::HousingInteriorTerritory& terri, + uint16_t containerId, uint16_t slotId, bool sendToStoreroom ); + + /*! + * + * @param player + * @param terri + * @param containerId + * @param slotId + * @param sendToStoreroom + * @return + */ + bool removeExternalItem( Entity::Player& player, HousingZone& terri, + uint16_t containerId, uint16_t slotId, bool sendToStoreroom ); + /*! * @brief Processes the movement of an item placed in a HousingZone * - * This assumes that the player has permission to move the item. + * This function assumes that the player has permission to move the item. * * @param player The player who placed the item * @param ident The ident of the land that the item belongs to @@ -183,7 +211,7 @@ namespace Sapphire::World::Manager * @param slot The slot of the item * @param pos The new position * @param rot The new rotation - * @return + * @return true if moved successfully */ bool moveExternalItem( Entity::Player& player, Common::LandIdent ident, uint16_t slot, Sapphire::HousingZone& terri, Common::FFXIVARR_POSITION3 pos, float rot ); @@ -191,7 +219,7 @@ namespace Sapphire::World::Manager /*! * @brief Processes the movement of an item placed inside a HousingInteriorTerritory * - * This assumes that the player has permission to move the item. + * This function assumes that the player has permission to move the item. * * @param player The player who placed the item * @param ident The ident of the land that the item belongs to @@ -199,7 +227,7 @@ namespace Sapphire::World::Manager * @param slotIdx The slot of the item * @param pos The new position * @param rot The new rotation - * @return + * @return true if moved successfully */ bool moveInternalItem( Entity::Player& player, Common::LandIdent ident, Territory::Housing::HousingInteriorTerritory& terri, uint16_t slot, diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index f5b59620..81c117e0 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -95,6 +95,23 @@ void Sapphire::World::Manager::InventoryMgr::saveHousingContainer( Common::LandI } } +void Sapphire::World::Manager::InventoryMgr::removeItemFromHousingContainer( Sapphire::Common::LandIdent ident, + uint16_t containerId, + uint16_t slotId ) +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); + + auto stmt = pDb->getPreparedStatement( Db::LAND_INV_DEL ); + + auto u64ident = *reinterpret_cast< uint64_t* >( &ident ); + + stmt->setUInt64( 1, u64ident ); + stmt->setUInt( 2, containerId ); + stmt->setUInt( 3, slotId ); + + pDb->directExecute( stmt ); +} + void Sapphire::World::Manager::InventoryMgr::saveHousingContainerItem( uint64_t ident, uint16_t containerId, uint16_t slotId, uint64_t itemId ) @@ -141,6 +158,17 @@ void Sapphire::World::Manager::InventoryMgr::updateHousingItemPosition( Sapphire pDb->execute( stmt ); } +void Sapphire::World::Manager::InventoryMgr::removeHousingItemPosition( Sapphire::Inventory::HousingItem& item ) +{ + auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); + + auto stmt = pDb->getPreparedStatement( Db::LAND_INV_DEL_ITEMPOS ); + + stmt->setUInt64( 1, item.getUId() ); + + pDb->directExecute( stmt ); +} + void Sapphire::World::Manager::InventoryMgr::saveItem( Sapphire::Entity::Player& player, Sapphire::ItemPtr item ) { auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); diff --git a/src/world/Manager/InventoryMgr.h b/src/world/Manager/InventoryMgr.h index 466ff563..b98170c7 100644 --- a/src/world/Manager/InventoryMgr.h +++ b/src/world/Manager/InventoryMgr.h @@ -38,6 +38,14 @@ namespace Sapphire::World::Manager */ void saveHousingContainer( Common::LandIdent ident, Sapphire::ItemContainerPtr container ); + /*! + * @brief Unlinks an item from the housing container in the db + * @param ident The identity of the estate that owns the item + * @param containerId The container the item is in + * @param slotId The slot the item is in + */ + void removeItemFromHousingContainer( Common::LandIdent ident, uint16_t containerId, uint16_t slotId ); + /*! * @brief Update an item in the db * @param item The item to commit to the db @@ -50,6 +58,12 @@ namespace Sapphire::World::Manager */ void updateHousingItemPosition( Sapphire::Inventory::HousingItemPtr item ); + /*! + * @brief Removes the position/rotation from a housing object + * @param item The item to remove the position from. + */ + void removeHousingItemPosition( Sapphire::Inventory::HousingItem& item ); + /*! * @brief Saves an item to the global item table * @param player The player which owns the item diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index 0140b78d..18841020 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -79,12 +79,14 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX const auto param12 = packet.data().param12; const auto param2 = packet.data().param2; const auto param3 = packet.data().param3; + const auto housingParam = packet.data().housingParam; pLog->debug( "[" + std::to_string( m_pSession->getId() ) + "] Incoming action: " + Util::intToHexString( static_cast< uint32_t >( commandId & 0xFFFF ), 4 ) + "\nparam1: " + Util::intToHexString( static_cast< uint64_t >( param1 & 0xFFFFFFFFFFFFFFF ), 16 ) + "\nparam2: " + Util::intToHexString( static_cast< uint32_t >( param2 & 0xFFFFFFFF ), 8 ) + - "\nparam3: " + Util::intToHexString( static_cast< uint64_t >( param3 & 0xFFFFFFFFFFFFFFF ), 16 ) + "\nparam3: " + Util::intToHexString( static_cast< uint64_t >( param3 & 0xFFFFFFFFFFFFFFF ), 16 ) + + "\nhousingParam: " + Util::intToHexString( static_cast< uint32_t >( housingParam & 0xFFFFFFFF ), 8 ) ); @@ -454,6 +456,18 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX break; } + case ClientTriggerType::RequestHousingItemRemove: + { + auto housingMgr = g_fw.get< HousingMgr >(); + + auto slot = housingParam & 0xFF; + auto sendToStoreroom = ( housingParam >> 16 ) != 0; + + //player, plot, containerId, slot, sendToStoreroom + housingMgr->reqRemoveHousingItem( player, param12, param2, slot, sendToStoreroom ); + + break; + } default: { diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index 064ba620..b1be765a 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "Actor/Player.h" #include "Actor/Actor.h" @@ -195,4 +197,16 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousin obj.itemRotation = rot; // todo: how does this update on other clients? +} + +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::removeHousingObject( uint16_t slot ) +{ + memset( m_housingObjects.data() + slot, 0x0, sizeof( Common::HousingObject ) ); + + for( const auto& player : m_playerMap ) + { + auto pkt = Server::makeActorControl143( player.second->getId(), Network::ActorControl::RemoveInteriorHousingItem, slot ); + + player.second->queuePacket( pkt ); + } } \ No newline at end of file diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.h b/src/world/Territory/Housing/HousingInteriorTerritory.h index f77fc49a..3fda4add 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.h +++ b/src/world/Territory/Housing/HousingInteriorTerritory.h @@ -28,6 +28,7 @@ namespace Sapphire::World::Territory::Housing void spawnHousingObject( uint8_t containerIdx, uint16_t slot, uint16_t containerType, Inventory::HousingItemPtr item ); void updateHousingObjectPosition( uint16_t slot, Common::FFXIVARR_POSITION3_U16 pos, uint16_t rot ); + void removeHousingObject( uint16_t slot ); private: Common::LandIdent m_landIdent; From 3d9a90cbb7b6c6fdc42d7aca509c53dd0f7eefd7 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 10:17:05 +1100 Subject: [PATCH 33/40] fix removed housing items being orphaned after relogging --- src/world/Actor/PlayerInventory.cpp | 4 ++-- src/world/Manager/HousingMgr.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/world/Actor/PlayerInventory.cpp b/src/world/Actor/PlayerInventory.cpp index 850c45e2..95bd52fb 100644 --- a/src/world/Actor/PlayerInventory.cpp +++ b/src/world/Actor/PlayerInventory.cpp @@ -930,9 +930,9 @@ bool Sapphire::Entity::Player::getFreeInventoryContainerSlot( Entity::Player::In void Sapphire::Entity::Player::insertInventoryItem( Sapphire::Common::InventoryType type, uint16_t slot, const Sapphire::ItemPtr item ) { - auto& container = m_storageMap[ type ]; - container->setItem( slot, item ); + updateContainer( type, slot, item ); auto slotUpdate = std::make_shared< UpdateInventorySlotPacket >( getId(), slot, type, *item ); queuePacket( slotUpdate ); + } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 7d47d347..7e576b4e 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -241,7 +241,7 @@ void Sapphire::World::Manager::HousingMgr::initLandCache() auto makeContainer = [ &containers ]( Common::InventoryType type, uint16_t size ) { - containers[ type ] = make_ItemContainer( type, size, "houseiteminventory", false ); + containers[ type ] = make_ItemContainer( type, size, "houseiteminventory", false, false ); }; uint16_t count = 0; @@ -1358,7 +1358,7 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p player.insertInventoryItem( containerPair.first, containerPair.second, item ); // todo: set item as bound/unsellable/untradable - + // despawn auto arraySlot = ( containerIdx * 50 ) + slotId; From 49c6049531eb61b6ff3135792e778176455b7884 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 11:49:12 +1100 Subject: [PATCH 34/40] items can be removed from the estate and moved to storeroom/inventory --- src/common/Network/CommonActorControl.h | 3 +- .../Network/PacketDef/Zone/ClientZoneDef.h | 2 +- src/world/Actor/Player.h | 4 +- src/world/Actor/PlayerInventory.cpp | 2 +- src/world/ForwardsZone.h | 2 + src/world/Inventory/HousingItem.cpp | 4 +- src/world/Manager/HousingMgr.cpp | 116 +++++++++++++++--- src/world/Manager/HousingMgr.h | 15 +-- .../Network/Handlers/ClientTriggerHandler.cpp | 8 +- src/world/Territory/HousingZone.cpp | 19 +++ src/world/Territory/HousingZone.h | 1 + 11 files changed, 142 insertions(+), 34 deletions(-) diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 5cce81d3..170c23e3 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -216,7 +216,8 @@ enum ActorControlType : uint16_t BuildPresetResponse = 0x3ED, /*! - * param1 = object array index + * param1 = u16 landid + * u16 slotid */ RemoveExteriorHousingItem = 0x3EF, diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 87867f0a..4af1d691 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -41,7 +41,7 @@ struct FFXIVIpcClientTrigger : /* 0004 */ uint32_t param11; /* 0008 */ uint32_t param12; /* 000C */ uint32_t param2; - /* 0010 */ uint32_t housingParam; // todo: param4? + /* 0010 */ uint32_t param4; // todo: really? /* 0014 */ char unk_14[4]; /* 0018 */ uint64_t param3; }; diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 3a59f726..2289d197 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -365,9 +365,7 @@ namespace Sapphire::Entity Common::GearModelSlot equipSlotToModelSlot( Common::GearSetSlot slot ); - using InventoryContainerPair = std::pair< Common::InventoryType, uint8_t >; - - bool getFreeInventoryContainerSlot( Entity::Player::InventoryContainerPair& containerPair ) const; + bool getFreeInventoryContainerSlot( Inventory::InventoryContainerPair& containerPair ) const; void insertInventoryItem( Common::InventoryType type, uint16_t slot, const Sapphire::ItemPtr item ); diff --git a/src/world/Actor/PlayerInventory.cpp b/src/world/Actor/PlayerInventory.cpp index 95bd52fb..21547da4 100644 --- a/src/world/Actor/PlayerInventory.cpp +++ b/src/world/Actor/PlayerInventory.cpp @@ -903,7 +903,7 @@ Sapphire::ItemPtr Sapphire::Entity::Player::dropInventoryItem( Sapphire::Common: return item; } -bool Sapphire::Entity::Player::getFreeInventoryContainerSlot( Entity::Player::InventoryContainerPair& containerPair ) const +bool Sapphire::Entity::Player::getFreeInventoryContainerSlot( Inventory::InventoryContainerPair& containerPair ) const { for( auto bagId : { Bag0, Bag1, Bag2, Bag3 } ) { diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index 82ad0e04..6d689826 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -37,6 +37,8 @@ TYPE_FORWARD( HousingInteriorTerritory ); namespace Inventory { +using InventoryContainerPair = std::pair< Common::InventoryType, uint8_t >; +using InventoryTypeList = std::vector< Common::InventoryType >; TYPE_FORWARD( HousingItem ); } diff --git a/src/world/Inventory/HousingItem.cpp b/src/world/Inventory/HousingItem.cpp index 265c26de..b0134125 100644 --- a/src/world/Inventory/HousingItem.cpp +++ b/src/world/Inventory/HousingItem.cpp @@ -2,7 +2,9 @@ Sapphire::Inventory::HousingItem::HousingItem( uint64_t uId, uint32_t catalogId ) : Sapphire::Item( uId, catalogId, false ) -{ } +{ + m_stackSize = 1; +} uint16_t Sapphire::Inventory::HousingItem::getRot() const { diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 7e576b4e..ef3e68c9 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1092,7 +1092,6 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl invMgr->saveItem( player, item ); // resend container - // todo: unsure as to whether we need to resend every container or just the one we edit - we'll see how this goes invMgr->sendInventoryContainer( player, container ); invMgr->saveHousingContainer( ident, container ); invMgr->updateHousingItemPosition( item ); @@ -1128,7 +1127,7 @@ void Sapphire::World::Manager::HousingMgr::sendInternalEstateInventoryBatch( Sap // todo: perms check - InventoryTypeList containerIds; + Inventory::InventoryTypeList containerIds; if( storeroom ) containerIds = m_internalStoreroomContainers; @@ -1297,7 +1296,7 @@ void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entit if( land->getOwnerId() != player.getId() ) return; - removeExternalItem( player, *terri, containerId, slot, sendToStoreroom ); + removeExternalItem( player, *terri, *land, slot, sendToStoreroom ); } } @@ -1336,18 +1335,15 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p if( !item ) return false; - item->setStackSize( 1 ); - if( !sendToStoreroom ) { // make sure the player has a free inv slot first - Entity::Player::InventoryContainerPair containerPair; + Inventory::InventoryContainerPair containerPair; if( !player.getFreeInventoryContainerSlot( containerPair ) ) return false; auto invMgr = g_fw.get< InventoryMgr >(); - // remove it from housing inventory container->removeItem( slotId ); invMgr->sendInventoryContainer( player, container ); @@ -1358,20 +1354,108 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p player.insertInventoryItem( containerPair.first, containerPair.second, item ); // todo: set item as bound/unsellable/untradable - - // despawn - auto arraySlot = ( containerIdx * 50 ) + slotId; - - terri.removeHousingObject( arraySlot ); } + else + { + ItemContainerPtr freeContainer; + Inventory::InventoryContainerPair freeSlotPair; + freeContainer = getFreeEstateInventorySlot( terri.getLandIdent(), freeSlotPair, m_internalStoreroomContainers ); + + if( !freeContainer ) + return false; + + auto invMgr = g_fw.get< InventoryMgr >(); + + container->removeItem( slotId ); + invMgr->sendInventoryContainer( player, container ); + invMgr->removeHousingItemPosition( *item ); + invMgr->removeItemFromHousingContainer( terri.getLandIdent(), containerId, slotId ); + + freeContainer->setItem( slotId, item ); + invMgr->sendInventoryContainer( player, freeContainer ); + invMgr->saveHousingContainer( terri.getLandIdent(), freeContainer ); + } + + // despawn + auto arraySlot = ( containerIdx * 50 ) + slotId; + terri.removeHousingObject( arraySlot ); return true; } -bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& player, - HousingZone& terri, - uint16_t containerId, uint16_t slotId, - bool sendToStoreroom ) +bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& player, HousingZone& terri, Land& land, + uint16_t slotId, bool sendToStoreroom ) { + auto& containers = getEstateInventory( land.getLandIdent() ); + auto& placedContainer = containers[ InventoryType::HousingExteriorPlacedItems ]; + + auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( placedContainer->getItem( slotId ) ); + if( !item ) + return false; + + auto invMgr = g_fw.get< InventoryMgr >(); + + if( sendToStoreroom ) + { + auto& storeroomContainer = containers[ InventoryType::HousingExteriorStoreroom ]; + auto freeSlot = storeroomContainer->getFreeSlot(); + + if( freeSlot == -1 ) + return false; + + placedContainer->removeItem( slotId ); + invMgr->sendInventoryContainer( player, placedContainer ); + invMgr->removeHousingItemPosition( *item ); + invMgr->removeItemFromHousingContainer( land.getLandIdent(), placedContainer->getId(), slotId ); + + storeroomContainer->setItem( freeSlot, item ); + invMgr->sendInventoryContainer( player, storeroomContainer ); + invMgr->saveHousingContainer( land.getLandIdent(), storeroomContainer ); + } + else + { + Inventory::InventoryContainerPair containerPair; + if( !player.getFreeInventoryContainerSlot( containerPair ) ) + return false; + + // remove from housing inv + placedContainer->removeItem( slotId ); + invMgr->sendInventoryContainer( player, placedContainer ); + invMgr->removeHousingItemPosition( *item ); + invMgr->removeItemFromHousingContainer( land.getLandIdent(), placedContainer->getId(), slotId ); + + // add to player inv + player.insertInventoryItem( containerPair.first, containerPair.second, item ); + } + + terri.despawnYardObject( land.getLandIdent().landId, slotId ); + + return true; +} + +Sapphire::ItemContainerPtr Sapphire::World::Manager::HousingMgr::getFreeEstateInventorySlot( Common::LandIdent ident, + Inventory::InventoryContainerPair& pair, + Inventory::InventoryTypeList bagList ) +{ + auto& estateContainers = getEstateInventory( ident ); + + for( auto bag : bagList ) + { + auto needle = estateContainers.find( bag ); + if( needle == estateContainers.end() ) + continue; + + auto container = needle->second; + + auto freeSlot = container->getFreeSlot(); + + if( freeSlot == -1 ) + continue; + + pair = std::make_pair( bag, freeSlot ); + return container; + } + + return nullptr; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 53c42362..804420e2 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -66,8 +66,6 @@ namespace Sapphire::World::Manager */ using LandIdentToInventoryContainerMap = std::unordered_map< uint64_t, ContainerIdToContainerMap >; - using InventoryTypeList = std::vector< Common::InventoryType >; - HousingMgr(); virtual ~HousingMgr(); @@ -176,6 +174,10 @@ namespace Sapphire::World::Manager private: + ItemContainerPtr getFreeEstateInventorySlot( Common::LandIdent ident, + Inventory::InventoryContainerPair& pair, + Inventory::InventoryTypeList bagList ); + /*! * * @param player @@ -192,13 +194,12 @@ namespace Sapphire::World::Manager * * @param player * @param terri - * @param containerId * @param slotId * @param sendToStoreroom * @return */ - bool removeExternalItem( Entity::Player& player, HousingZone& terri, - uint16_t containerId, uint16_t slotId, bool sendToStoreroom ); + bool removeExternalItem( Entity::Player& player, HousingZone& terri, Land& land, + uint16_t slotId, bool sendToStoreroom ); /*! * @brief Processes the movement of an item placed in a HousingZone @@ -296,8 +297,8 @@ namespace Sapphire::World::Manager LandSetLandCacheMap m_landCache; LandIdentToInventoryContainerMap m_estateInventories; - InventoryTypeList m_internalPlacedItemContainers; - InventoryTypeList m_internalStoreroomContainers; + Inventory::InventoryTypeList m_internalPlacedItemContainers; + Inventory::InventoryTypeList m_internalStoreroomContainers; std::array< std::pair< Common::InventoryType, Common::InventoryType >, 8 > m_containerMap; diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index 18841020..5c9cee52 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -79,14 +79,14 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX const auto param12 = packet.data().param12; const auto param2 = packet.data().param2; const auto param3 = packet.data().param3; - const auto housingParam = packet.data().housingParam; + const auto param4 = packet.data().param4; pLog->debug( "[" + std::to_string( m_pSession->getId() ) + "] Incoming action: " + Util::intToHexString( static_cast< uint32_t >( commandId & 0xFFFF ), 4 ) + "\nparam1: " + Util::intToHexString( static_cast< uint64_t >( param1 & 0xFFFFFFFFFFFFFFF ), 16 ) + "\nparam2: " + Util::intToHexString( static_cast< uint32_t >( param2 & 0xFFFFFFFF ), 8 ) + "\nparam3: " + Util::intToHexString( static_cast< uint64_t >( param3 & 0xFFFFFFFFFFFFFFF ), 16 ) + - "\nhousingParam: " + Util::intToHexString( static_cast< uint32_t >( housingParam & 0xFFFFFFFF ), 8 ) + "\nparam4: " + Util::intToHexString( static_cast< uint32_t >( param4 & 0xFFFFFFFF ), 8 ) ); @@ -460,8 +460,8 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { auto housingMgr = g_fw.get< HousingMgr >(); - auto slot = housingParam & 0xFF; - auto sendToStoreroom = ( housingParam >> 16 ) != 0; + auto slot = param4 & 0xFF; + auto sendToStoreroom = ( param4 >> 16 ) != 0; //player, plot, containerId, slot, sendToStoreroom housingMgr->reqRemoveHousingItem( player, param12, param2, slot, sendToStoreroom ); diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 2aaa3b90..829f5ddf 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "Actor/Player.h" #include "Actor/Actor.h" @@ -402,4 +404,21 @@ void Sapphire::HousingZone::updateYardObjectPos( Entity::Player& sourcePlayer, u player.second->queuePacket( packet ); } +} + +void Sapphire::HousingZone::despawnYardObject( uint16_t landId, uint16_t slot ) +{ + auto bounds = m_yardObjectArrayBounds[ landId ]; + auto offset = bounds.first + slot; + auto yardMapIndex = landId <= 29 ? 0 : 1; + + memset( &m_yardObjects[ yardMapIndex ][ offset ], 0x00, sizeof( Common::HousingObject ) ); + + for( const auto& player : m_playerMap ) + { + auto param = ( landId << 16 ) | slot; + auto pkt = Server::makeActorControl143( player.second->getId(), Network::ActorControl::RemoveExteriorHousingItem, param ); + + player.second->queuePacket( pkt ); + } } \ No newline at end of file diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index aac75ca0..8cfcef73 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -58,6 +58,7 @@ namespace Sapphire void spawnYardObject( uint8_t landId, uint16_t slotId, Sapphire::Inventory::HousingItem& item ); void updateYardObjectPos( Entity::Player& sourcePlayer, uint16_t slot, uint16_t landId, Inventory::HousingItem& item ); + void despawnYardObject( uint16_t landId, uint16_t slot ); private: using LandPtrMap = std::unordered_map< uint8_t, Sapphire::LandPtr >; From c5d06025a05c6227f20dcee0ac07670b68759a2c Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 15:48:13 +1100 Subject: [PATCH 35/40] send spiritbond with inventory items --- src/world/Inventory/HousingItem.cpp | 1 + src/world/Inventory/Item.cpp | 13 ++++++++++++- src/world/Inventory/Item.h | 4 ++++ src/world/Manager/InventoryMgr.cpp | 4 ++-- src/world/Network/Handlers/ClientTriggerHandler.cpp | 1 - .../PacketWrappers/UpdateInventorySlotPacket.h | 2 +- 6 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/world/Inventory/HousingItem.cpp b/src/world/Inventory/HousingItem.cpp index b0134125..99f903ff 100644 --- a/src/world/Inventory/HousingItem.cpp +++ b/src/world/Inventory/HousingItem.cpp @@ -4,6 +4,7 @@ Sapphire::Inventory::HousingItem::HousingItem( uint64_t uId, uint32_t catalogId Sapphire::Item( uId, catalogId, false ) { m_stackSize = 1; + m_spiritBond = 1; } uint16_t Sapphire::Inventory::HousingItem::getRot() const diff --git a/src/world/Inventory/Item.cpp b/src/world/Inventory/Item.cpp index ac2016e8..98c546b7 100644 --- a/src/world/Inventory/Item.cpp +++ b/src/world/Inventory/Item.cpp @@ -12,7 +12,8 @@ Sapphire::Item::Item( uint64_t uId, uint32_t catalogId, bool isHq ) : m_uId( uId ), m_isHq( isHq ), m_stain( 0 ), - m_durability( 30000 ) + m_durability( 30000 ), + m_spiritBond( 0 ) { auto pExdData = g_fw.get< Data::ExdDataGenerated >(); auto itemInfo = pExdData->get< Sapphire::Data::Item >( catalogId ); @@ -160,3 +161,13 @@ uint32_t Sapphire::Item::getAdditionalData() const { return m_additionalData; } + +uint16_t Sapphire::Item::getSpiritbond() const +{ + return m_spiritBond; +} + +void Sapphire::Item::setSpiritbond( uint16_t spiritbond ) +{ + m_spiritBond = spiritbond; +} diff --git a/src/world/Inventory/Item.h b/src/world/Inventory/Item.h index f2b17ad1..018956b9 100644 --- a/src/world/Inventory/Item.h +++ b/src/world/Inventory/Item.h @@ -64,6 +64,9 @@ namespace Sapphire uint32_t getAdditionalData() const; + void setSpiritbond( uint16_t spiritbond ); + uint16_t getSpiritbond() const; + protected: uint32_t m_id; @@ -89,6 +92,7 @@ namespace Sapphire uint16_t m_itemLevel; uint16_t m_durability; uint16_t m_stain; + uint16_t m_spiritBond; uint32_t m_additionalData; diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index 81c117e0..7405a0eb 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -49,8 +49,8 @@ void Sapphire::World::Manager::InventoryMgr::sendInventoryContainer( Sapphire::E itemInfoPacket->data().quantity = itM->second->getStackSize(); itemInfoPacket->data().catalogId = itM->second->getId(); itemInfoPacket->data().condition = itM->second->getDurability(); - itemInfoPacket->data().spiritBond = 0; - itemInfoPacket->data().hqFlag = itM->second->isHq() ? 1 : 0; + itemInfoPacket->data().spiritBond = itM->second->getSpiritbond(); + itemInfoPacket->data().hqFlag = static_cast< uint8_t >( itM->second->isHq() ? 1 : 0 ); itemInfoPacket->data().stain = itM->second->getStain(); player.queuePacket( itemInfoPacket ); diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index 5c9cee52..ee915f0d 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -427,7 +427,6 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX { uint8_t plot = ( param12 & 0xFF ); - auto housingMgr = g_fw.get< HousingMgr >(); if( !housingMgr ) break; diff --git a/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h b/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h index 312b7abf..1dbe2474 100644 --- a/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h +++ b/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h @@ -33,7 +33,7 @@ namespace Sapphire::Network::Packets::Server m_data.signatureId = 0; m_data.hqFlag = item.isHq() ? 1 : 0; m_data.condition = 60000; // 200% - m_data.spiritBond = 0; + m_data.spiritBond = item.getSpiritbond(); m_data.color = 0; m_data.glamourCatalogId = 0; m_data.materia1 = 0; From 3b37d14d64a799e00375be89e7db869518358f1b Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 17:12:24 +1100 Subject: [PATCH 36/40] maybe fix an issue where a container wouldn't get read properly also some extra item crap --- src/common/Network/CommonActorControl.h | 1 + src/common/Network/PacketDef/Zone/ClientZoneDef.h | 2 +- src/world/Inventory/HousingItem.cpp | 1 + src/world/Inventory/Item.cpp | 13 ++++++++++++- src/world/Inventory/Item.h | 4 ++++ src/world/Manager/HousingMgr.cpp | 7 +++++-- src/world/Manager/InventoryMgr.cpp | 1 + src/world/Network/Handlers/ClientTriggerHandler.cpp | 4 +++- .../PacketWrappers/UpdateInventorySlotPacket.h | 2 +- 9 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 170c23e3..5f5f615d 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -344,6 +344,7 @@ enum ActorControlType : uint16_t RequestHousingItemUI = 0x463, RequestSharedEstateSettings = 0x46F, UpdateEstateLightingLevel = 0x471, + HousingItemSelectedInUI = 0x47E, CompanionAction = 0x6A4, CompanionSetBarding = 0x6A5, diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 4af1d691..12b452dd 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -42,7 +42,7 @@ struct FFXIVIpcClientTrigger : /* 0008 */ uint32_t param12; /* 000C */ uint32_t param2; /* 0010 */ uint32_t param4; // todo: really? - /* 0014 */ char unk_14[4]; + /* 0014 */ uint32_t param5; /* 0018 */ uint64_t param3; }; diff --git a/src/world/Inventory/HousingItem.cpp b/src/world/Inventory/HousingItem.cpp index 99f903ff..15352dab 100644 --- a/src/world/Inventory/HousingItem.cpp +++ b/src/world/Inventory/HousingItem.cpp @@ -5,6 +5,7 @@ Sapphire::Inventory::HousingItem::HousingItem( uint64_t uId, uint32_t catalogId { m_stackSize = 1; m_spiritBond = 1; + m_reservedFlag = 1092616192; // wat? } uint16_t Sapphire::Inventory::HousingItem::getRot() const diff --git a/src/world/Inventory/Item.cpp b/src/world/Inventory/Item.cpp index 98c546b7..d8af0f17 100644 --- a/src/world/Inventory/Item.cpp +++ b/src/world/Inventory/Item.cpp @@ -13,7 +13,8 @@ Sapphire::Item::Item( uint64_t uId, uint32_t catalogId, bool isHq ) : m_isHq( isHq ), m_stain( 0 ), m_durability( 30000 ), - m_spiritBond( 0 ) + m_spiritBond( 0 ), + m_reservedFlag( 0 ) { auto pExdData = g_fw.get< Data::ExdDataGenerated >(); auto itemInfo = pExdData->get< Sapphire::Data::Item >( catalogId ); @@ -171,3 +172,13 @@ void Sapphire::Item::setSpiritbond( uint16_t spiritbond ) { m_spiritBond = spiritbond; } + +uint32_t Sapphire::Item::getReservedFlag() const +{ + return m_reservedFlag; +} + +void Sapphire::Item::setReservedFlag( uint32_t flag ) +{ + m_reservedFlag = flag; +} \ No newline at end of file diff --git a/src/world/Inventory/Item.h b/src/world/Inventory/Item.h index 018956b9..34fa02f7 100644 --- a/src/world/Inventory/Item.h +++ b/src/world/Inventory/Item.h @@ -67,6 +67,9 @@ namespace Sapphire void setSpiritbond( uint16_t spiritbond ); uint16_t getSpiritbond() const; + void setReservedFlag( uint32_t flag ); + uint32_t getReservedFlag() const; + protected: uint32_t m_id; @@ -93,6 +96,7 @@ namespace Sapphire uint16_t m_durability; uint16_t m_stain; uint16_t m_spiritBond; + uint32_t m_reservedFlag; uint32_t m_additionalData; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index ef3e68c9..ea86382c 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -851,9 +851,12 @@ void Sapphire::World::Manager::HousingMgr::sendEstateInventory( Entity::Player& return; auto& containers = getEstateInventory( targetLand->getLandIdent() ); + auto needle = containers.find( inventoryType ); + if( needle == containers.end() ) + return; auto invMgr = g_fw.get< Manager::InventoryMgr >(); - invMgr->sendInventoryContainer( player, containers[ inventoryType ] ); + invMgr->sendInventoryContainer( player, needle->second ); } const Sapphire::World::Manager::HousingMgr::LandSetLandCacheMap& @@ -1430,7 +1433,7 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p } terri.despawnYardObject( land.getLandIdent().landId, slotId ); - + return true; } diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index 7405a0eb..5c960f35 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -50,6 +50,7 @@ void Sapphire::World::Manager::InventoryMgr::sendInventoryContainer( Sapphire::E itemInfoPacket->data().catalogId = itM->second->getId(); itemInfoPacket->data().condition = itM->second->getDurability(); itemInfoPacket->data().spiritBond = itM->second->getSpiritbond(); + itemInfoPacket->data().reservedFlag = itM->second->getReservedFlag(); itemInfoPacket->data().hqFlag = static_cast< uint8_t >( itM->second->isHq() ? 1 : 0 ); itemInfoPacket->data().stain = itM->second->getStain(); diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index ee915f0d..df9409f4 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -80,13 +80,15 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX const auto param2 = packet.data().param2; const auto param3 = packet.data().param3; const auto param4 = packet.data().param4; + const auto param5 = packet.data().param5; pLog->debug( "[" + std::to_string( m_pSession->getId() ) + "] Incoming action: " + Util::intToHexString( static_cast< uint32_t >( commandId & 0xFFFF ), 4 ) + "\nparam1: " + Util::intToHexString( static_cast< uint64_t >( param1 & 0xFFFFFFFFFFFFFFF ), 16 ) + "\nparam2: " + Util::intToHexString( static_cast< uint32_t >( param2 & 0xFFFFFFFF ), 8 ) + "\nparam3: " + Util::intToHexString( static_cast< uint64_t >( param3 & 0xFFFFFFFFFFFFFFF ), 16 ) + - "\nparam4: " + Util::intToHexString( static_cast< uint32_t >( param4 & 0xFFFFFFFF ), 8 ) + "\nparam4: " + Util::intToHexString( static_cast< uint32_t >( param4 & 0xFFFFFFFF ), 8 ) + + "\nparam5: " + Util::intToHexString( static_cast< uint32_t >( param5 & 0xFFFFFFFF ), 8 ) ); diff --git a/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h b/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h index 1dbe2474..4f10459a 100644 --- a/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h +++ b/src/world/Network/PacketWrappers/UpdateInventorySlotPacket.h @@ -29,7 +29,7 @@ namespace Sapphire::Network::Packets::Server m_data.slot = slot; m_data.quantity = item.getStackSize(); m_data.catalogId = item.getId(); - m_data.reservedFlag = 0; // no idea + m_data.reservedFlag = item.getReservedFlag(); // no idea m_data.signatureId = 0; m_data.hqFlag = item.isHq() ? 1 : 0; m_data.condition = 60000; // 200% From dd5a899c1dd12e383a4aecf45faefab903bafe40 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 18:45:08 +1100 Subject: [PATCH 37/40] add internal/external estate remodelling menus --- src/common/Common.h | 1 + src/common/Network/CommonActorControl.h | 7 ++ src/world/Manager/HousingMgr.cpp | 70 ++++++++++++++++++- src/world/Manager/HousingMgr.h | 4 ++ .../Network/Handlers/ClientTriggerHandler.cpp | 16 +++++ 5 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index d777a9e2..fdb52426 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -780,6 +780,7 @@ namespace Sapphire::Common enum HouseExteriorSlot { + HousePermit, ExteriorRoof, ExteriorWall, ExteriorWindow, diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 5f5f615d..9c03d685 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -213,6 +213,11 @@ enum ActorControlType : uint16_t // Housing ShowHousingItemUI = 0x3F7, ShowBuildPresetUI = 0x3E9, + /*! + * param1 = plot id + */ + ShowEstateExternalAppearanceUI = 0x3EA, + ShowEstateInternalAppearanceUI = 0x3EB, BuildPresetResponse = 0x3ED, /*! @@ -327,6 +332,8 @@ enum ActorControlType : uint16_t SetEstateLightingLevel = 0x40B, // param1 = light level 0 - 5 maps to UI val 5-0 RequestHousingBuildPreset = 0x44C, + RequestEstateExteriorRemodel = 0x044D, // param11 = land id + RequestEstateInteriorRemodel = 0x44E, RequestEstateHallRemoval = 0x44F, RequestBuildPreset = 0x450, // no idea what this is, it gets sent with BuildPresetHandler and has the plot id in param1 RequestLandSignFree = 0x451, diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index ea86382c..c51e7640 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -264,7 +264,7 @@ void Sapphire::World::Manager::HousingMgr::initLandCache() // fixed containers makeContainer( InventoryType::HousingInteriorAppearance, 10 ); - makeContainer( InventoryType::HousingExteriorAppearance, 8 ); + makeContainer( InventoryType::HousingExteriorAppearance, 9 ); } } @@ -896,7 +896,15 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { for( auto& item : extContainer->second->getItemMap() ) { - house->setExteriorModel( static_cast< Common::HouseExteriorSlot >( item.first ), + // in the Slot array, the first slot is actually the permit + // but the models array starts from the 2nd entry of the enum + // so we skip the first one, and then any subsequent entries is slotid - 1 + + auto slotId = item.first - 1; + if( slotId < 0 ) + continue; + + house->setExteriorModel( static_cast< Common::HouseExteriorSlot >( slotId ), getItemAdditionalData( item.second->getId() ), item.second->getStain() ); } } @@ -1461,4 +1469,62 @@ Sapphire::ItemContainerPtr Sapphire::World::Manager::HousingMgr::getFreeEstateIn } return nullptr; +} + +void Sapphire::World::Manager::HousingMgr::reqEstateExteriorRemodel( Sapphire::Entity::Player& player, uint16_t plot ) +{ + auto terri = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); + if( !terri ) + return; + + auto land = terri->getLand( plot ); + if( !land ) + return; + + // todo: proper perms checks + if( land->getOwnerId() != player.getId() ) + return; + + auto& inv = getEstateInventory( land->getLandIdent() ); + auto needle = inv.find( InventoryType::HousingExteriorAppearance ); + if( needle == inv.end() ) + return; + + auto invMgr = g_fw.get< InventoryMgr >(); + + invMgr->sendInventoryContainer( player, needle->second ); + + auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateExternalAppearanceUI, plot ); + player.queuePacket( pkt ); + +} + +void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::Entity::Player& player ) +{ + auto terri = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ); + if( !terri ) + return; + + auto ident = terri->getLandIdent(); + auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); + auto land = getHousingZoneByLandSetId( landSet )->getLand( ident.landId ); + + if( !land ) + return; + + // todo: proper perms checks + if( land->getOwnerId() != player.getId() ) + return; + + auto& inv = getEstateInventory( land->getLandIdent() ); + auto needle = inv.find( InventoryType::HousingInteriorAppearance ); + if( needle == inv.end() ) + return; + + auto invMgr = g_fw.get< InventoryMgr >(); + + invMgr->sendInventoryContainer( player, needle->second ); + + auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateInternalAppearanceUI ); + player.queuePacket( pkt ); } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 804420e2..512a7a05 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -172,6 +172,10 @@ namespace Sapphire::World::Manager uint16_t containerId, uint16_t slot, bool sendToStoreroom ); + void reqEstateExteriorRemodel( Entity::Player& player, uint16_t plot ); + + void reqEstateInteriorRemodel( Entity::Player& player ); + private: ItemContainerPtr getFreeEstateInventorySlot( Common::LandIdent ident, diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index df9409f4..28249ee8 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -469,6 +469,22 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX break; } + case ClientTriggerType::RequestEstateExteriorRemodel: + { + auto housingMgr = g_fw.get< HousingMgr >(); + + housingMgr->reqEstateExteriorRemodel( player, param11 ); + + break; + } + case ClientTriggerType::RequestEstateInteriorRemodel: + { + auto housingMgr = g_fw.get< HousingMgr >(); + + housingMgr->reqEstateInteriorRemodel( player ); + + break; + } default: { From e81a666258d1fa4003b33c6402ec9ef115351587 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 19:45:04 +1100 Subject: [PATCH 38/40] return player to parent housing zone if logged out inside house --- src/world/Actor/PlayerSql.cpp | 11 +++++++++++ src/world/Manager/TerritoryMgr.cpp | 11 ++++++++++- src/world/Manager/TerritoryMgr.h | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/world/Actor/PlayerSql.cpp b/src/world/Actor/PlayerSql.cpp index 1aeb33ee..4f834d95 100644 --- a/src/world/Actor/PlayerSql.cpp +++ b/src/world/Actor/PlayerSql.cpp @@ -84,6 +84,17 @@ bool Sapphire::Entity::Player::load( uint32_t charId, SessionPtr pSession ) pCurrZone = pTeriMgr->getZoneByTerritoryTypeId( zoneId ); } } + else if( pTeriMgr->isInternalEstateTerritory( zoneId ) ) + { + // todo: this needs to go to the area just outside of the plot door + pCurrZone = pTeriMgr->getZoneByLandSetId( m_prevTerritoryId ); + + zoneId = m_prevTerritoryTypeId; + m_pos.x = m_prevPos.x; + m_pos.y = m_prevPos.y; + m_pos.z = m_prevPos.z; + setRot( m_prevRot ); + } else if( pTeriMgr->isHousingTerritory( zoneId ) ) { pCurrZone = pTeriMgr->getZoneByLandSetId( m_territoryId ); diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index cd1a2301..f1f5ea63 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -106,11 +106,20 @@ bool Sapphire::World::Manager::TerritoryMgr::isPrivateTerritory( uint32_t territ return pTeri->territoryIntendedUse == TerritoryIntendedUse::OpeningArea || pTeri->territoryIntendedUse == TerritoryIntendedUse::Inn || - pTeri->territoryIntendedUse == TerritoryIntendedUse::HousingPrivateArea || pTeri->territoryIntendedUse == TerritoryIntendedUse::JailArea || pTeri->territoryIntendedUse == TerritoryIntendedUse::MSQPrivateArea; } +bool Sapphire::World::Manager::TerritoryMgr::isInternalEstateTerritory( uint32_t territoryTypeId ) const +{ + auto pTeri = getTerritoryDetail( territoryTypeId ); + + if( !pTeri ) + return false; + + return pTeri->territoryIntendedUse == TerritoryIntendedUse::HousingPrivateArea; +} + bool Sapphire::World::Manager::TerritoryMgr::isDefaultTerritory( uint32_t territoryTypeId ) const { auto pTeri = getTerritoryDetail( territoryTypeId ); diff --git a/src/world/Manager/TerritoryMgr.h b/src/world/Manager/TerritoryMgr.h index 794c87af..68fc1243 100644 --- a/src/world/Manager/TerritoryMgr.h +++ b/src/world/Manager/TerritoryMgr.h @@ -87,6 +87,13 @@ namespace Sapphire::World::Manager /*! returns true if the territoryType in question is not a private zone */ bool isPrivateTerritory( uint32_t territoryTypeId ) const; + /*! + * @brief Checks if a territory type is an internal housing area + * @param territoryTypeId The territory to test + * @return true if it is a housing area, false if not + */ + bool isInternalEstateTerritory( uint32_t territoryTypeId ) const; + /*! returns true if the territoryType is a default non-instanced zone */ bool isDefaultTerritory( uint32_t territoryTypeId ) const; From 34e9ba131ee1ed196bacd98ca2f281b6fd3b385d Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 20:10:07 +1100 Subject: [PATCH 39/40] fix items not being able to be removed from external storeroom --- src/world/Manager/HousingMgr.cpp | 28 ++++++++++++------- src/world/Manager/HousingMgr.h | 3 +- .../Network/Handlers/ClientTriggerHandler.cpp | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index c51e7640..b267ad3a 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1307,7 +1307,9 @@ void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entit if( land->getOwnerId() != player.getId() ) return; - removeExternalItem( player, *terri, *land, slot, sendToStoreroom ); + auto containerType = static_cast< Common::InventoryType >( containerId ); + + removeExternalItem( player, *terri, *land, containerType, slot, sendToStoreroom ); } } @@ -1319,6 +1321,7 @@ 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 ) @@ -1395,13 +1398,18 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p } bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& player, HousingZone& terri, Land& land, - uint16_t slotId, bool sendToStoreroom ) + Common::InventoryType containerType, uint16_t slotId, + bool sendToStoreroom ) { auto& containers = getEstateInventory( land.getLandIdent() ); - auto& placedContainer = containers[ InventoryType::HousingExteriorPlacedItems ]; + auto needle = containers.find( containerType ); + if( needle == containers.end() ) + return false; - auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( placedContainer->getItem( slotId ) ); + auto& sourceContainer = needle->second; + + auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( sourceContainer->getItem( slotId ) ); if( !item ) return false; @@ -1415,10 +1423,10 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p if( freeSlot == -1 ) return false; - placedContainer->removeItem( slotId ); - invMgr->sendInventoryContainer( player, placedContainer ); + sourceContainer->removeItem( slotId ); + invMgr->sendInventoryContainer( player, sourceContainer ); invMgr->removeHousingItemPosition( *item ); - invMgr->removeItemFromHousingContainer( land.getLandIdent(), placedContainer->getId(), slotId ); + invMgr->removeItemFromHousingContainer( land.getLandIdent(), sourceContainer->getId(), slotId ); storeroomContainer->setItem( freeSlot, item ); invMgr->sendInventoryContainer( player, storeroomContainer ); @@ -1431,10 +1439,10 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p return false; // remove from housing inv - placedContainer->removeItem( slotId ); - invMgr->sendInventoryContainer( player, placedContainer ); + sourceContainer->removeItem( slotId ); + invMgr->sendInventoryContainer( player, sourceContainer ); invMgr->removeHousingItemPosition( *item ); - invMgr->removeItemFromHousingContainer( land.getLandIdent(), placedContainer->getId(), slotId ); + invMgr->removeItemFromHousingContainer( land.getLandIdent(), sourceContainer->getId(), slotId ); // add to player inv player.insertInventoryItem( containerPair.first, containerPair.second, item ); diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 512a7a05..273ec484 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -203,7 +203,8 @@ namespace Sapphire::World::Manager * @return */ bool removeExternalItem( Entity::Player& player, HousingZone& terri, Land& land, - uint16_t slotId, bool sendToStoreroom ); + Common::InventoryType containerType, uint16_t slotId, + bool sendToStoreroom ); /*! * @brief Processes the movement of an item placed in a HousingZone diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index 28249ee8..44b309e4 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -464,7 +464,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX auto slot = param4 & 0xFF; auto sendToStoreroom = ( param4 >> 16 ) != 0; - //player, plot, containerId, slot, sendToStoreroom + //player, plot, containerId, slot, sendToStoreroom housingMgr->reqRemoveHousingItem( player, param12, param2, slot, sendToStoreroom ); break; From 0ca7b4815e8c6b3c5a8de206440c7c94c77494bb Mon Sep 17 00:00:00 2001 From: NotAdam Date: Fri, 28 Dec 2018 22:50:46 +1100 Subject: [PATCH 40/40] add interior housing object movement updates --- src/common/Network/PacketDef/Ipcs.h | 2 +- .../Network/PacketDef/Zone/ServerZoneDef.h | 2 +- src/world/Manager/HousingMgr.cpp | 2 +- .../Housing/HousingInteriorTerritory.cpp | 22 +++++++++++++++++-- .../Housing/HousingInteriorTerritory.h | 3 ++- src/world/Territory/HousingZone.cpp | 2 +- 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index 62522203..ede6ed36 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -204,7 +204,7 @@ namespace Sapphire::Network::Packets HousingInternalObjectSpawn = 0x22D, // updated 4.4 HousingWardInfo = 0x022F, // updated 4.4 - YardObjectMove = 0x0230, // updated 4.4 + HousingObjectMove = 0x0230, // updated 4.4 SharedEstateSettingsResponse = 0x023C, // updated 4.4 diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 5a406ee8..40cd48a3 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1687,7 +1687,7 @@ struct FFXIVIpcYardObjectSpawn : FFXIVIpcBasePacket< YardObjectSpawn > Common::HousingObject object; }; -struct FFXIVIpcYardObjectMove : FFXIVIpcBasePacket< YardObjectMove > +struct FFXIVIpcHousingObjectMove : FFXIVIpcBasePacket< HousingObjectMove > { uint16_t itemRotation; uint8_t objectArray; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index b267ad3a..f9a91042 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -1225,7 +1225,7 @@ bool Sapphire::World::Manager::HousingMgr::moveInternalItem( Entity::Player& pla auto invMgr = g_fw.get< InventoryMgr >(); invMgr->updateHousingItemPosition( item ); - terri.updateHousingObjectPosition( slot, item->getPos(), item->getRot() ); + terri.updateHousingObjectPosition( player, slot, item->getPos(), item->getRot() ); // send confirmation to player uint32_t param1 = ( ident.landId << 16 ) | containerId; diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index b1be765a..d54ce928 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -187,8 +187,9 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnHousing } } -void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousingObjectPosition( uint16_t slot, - Sapphire::Common::FFXIVARR_POSITION3_U16 pos, +void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousingObjectPosition( Entity::Player& sourcePlayer, + uint16_t slot, + Common::FFXIVARR_POSITION3_U16 pos, uint16_t rot ) { auto& obj = m_housingObjects[ slot ]; @@ -197,6 +198,23 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousin obj.itemRotation = rot; // todo: how does this update on other clients? + + for( const auto& player : m_playerMap ) + { + if( player.second->getId() == sourcePlayer.getId() ) + continue; + + auto moveObjPkt = makeZonePacket< Server::FFXIVIpcHousingObjectMove >( player.second->getId() ); + + moveObjPkt->data().itemRotation = obj.itemRotation; + moveObjPkt->data().pos = obj.pos; + + // todo: how does this work when an item is in a slot >50 or u8 max? my guess is landid is the container index, but not sure... + moveObjPkt->data().objectArray = static_cast< uint8_t >( slot % 50 ); + moveObjPkt->data().landId = static_cast< uint8_t >( slot / 50 ); + + player.second->queuePacket( moveObjPkt ); + } } void Sapphire::World::Territory::Housing::HousingInteriorTerritory::removeHousingObject( uint16_t slot ) diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.h b/src/world/Territory/Housing/HousingInteriorTerritory.h index 3fda4add..8d1450a8 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.h +++ b/src/world/Territory/Housing/HousingInteriorTerritory.h @@ -27,7 +27,8 @@ namespace Sapphire::World::Territory::Housing void updateHousingObjects(); void spawnHousingObject( uint8_t containerIdx, uint16_t slot, uint16_t containerType, Inventory::HousingItemPtr item ); - void updateHousingObjectPosition( uint16_t slot, Common::FFXIVARR_POSITION3_U16 pos, uint16_t rot ); + void updateHousingObjectPosition( + Entity::Player& sourcePlayer, uint16_t slot, Sapphire::Common::FFXIVARR_POSITION3_U16 pos, uint16_t rot ); void removeHousingObject( uint16_t slot ); private: diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 829f5ddf..615fa69c 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -394,7 +394,7 @@ void Sapphire::HousingZone::updateYardObjectPos( Entity::Player& sourcePlayer, u if( player.second->getId() == sourcePlayer.getId() ) continue; - auto packet = makeZonePacket< Server::FFXIVIpcYardObjectMove >( player.second->getId() ); + auto packet = makeZonePacket< Server::FFXIVIpcHousingObjectMove >( player.second->getId() ); packet->data().itemRotation = item.getRot(); packet->data().pos = item.getPos();