diff --git a/src/common/Database/ZoneDbConnection.cpp b/src/common/Database/ZoneDbConnection.cpp index 0cf393a3..9e65a82f 100644 --- a/src/common/Database/ZoneDbConnection.cpp +++ b/src/common/Database/ZoneDbConnection.cpp @@ -291,6 +291,10 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements() "UPDATE house SET BuildTime = ?, Aetheryte = ?, Comment = ?, HouseName = ?, Endorsements = ? WHERE HouseId = ?;", CONNECTION_BOTH ); + prepareStatement( HOUSING_HOUSE_DEL, + "DELETE from house WHERE HouseId = ?;", + CONNECTION_BOTH ); + prepareStatement( LAND_INV_SEL_ALL, "SELECT houseiteminventory.*, charaglobalitem.catalogId, charaglobalitem.stain, charaglobalitem.CharacterId, " "landplaceditems.PosX, landplaceditems.PosY, landplaceditems.PosZ, landplaceditems.Rotation " diff --git a/src/world/Inventory/ItemContainer.cpp b/src/world/Inventory/ItemContainer.cpp index 16ca0785..6fe010e0 100644 --- a/src/world/Inventory/ItemContainer.cpp +++ b/src/world/Inventory/ItemContainer.cpp @@ -86,6 +86,9 @@ Sapphire::ItemPtr Sapphire::ItemContainer::getItem( uint16_t slotId ) return nullptr; } + if( m_itemMap.find( slotId ) == m_itemMap.end() ) + return nullptr; + return m_itemMap[ slotId ]; } diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 05a91324..8c58308d 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -680,6 +680,14 @@ void HousingMgr::createHouse( Sapphire::HousePtr house ) const db.execute( stmt ); } +void HousingMgr::deleteHouse( Sapphire::HousePtr house ) const +{ + auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref(); + auto stmt = db.getPreparedStatement( Db::HOUSING_HOUSE_DEL ); + stmt->setUInt( 1, house->getId() ); + db.execute( stmt ); +} + void HousingMgr::buildPresetEstate( Entity::Player& player, HousingZone& zone, uint8_t plotNum, uint32_t presetCatalogId ) { auto& server = Common::Service< World::WorldServer >::ref(); @@ -1691,3 +1699,67 @@ Inventory::HousingItemPtr HousingMgr::getHousingItemFromPlayer( Entity::Player& return Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId() ); } + +void HousingMgr::removeHouse( Entity::Player& player, uint16_t plot ) +{ + auto& teriMgr = Common::Service< TerritoryMgr >::ref(); + auto pZone = teriMgr.getTerritoryByGuId( player.getTerritoryId() ); + if( !pZone ) + return; + auto terri = std::dynamic_pointer_cast< HousingZone >( pZone ); + if( !terri ) + return; + + auto land = terri->getLand( static_cast< uint8_t >( plot ) ); + if( !land || !land->getHouse() ) + return; + + if( !hasPermission( player, *land, 0 ) ) + return; + + auto& interiorContainer = getEstateInventory( land->getLandIdent() )[ Common::InventoryType::HousingInteriorAppearance ]; + auto& invMgr = Common::Service< InventoryMgr >::ref(); + + std::unordered_map< Common::InventoryType, ItemContainerPtr > changedContainerSet = {}; + + for( int i = 0; i < interiorContainer->getMaxSize(); i++ ) + { + auto item = interiorContainer->getItem( i ); + if( !item ) + continue; + + Inventory::InventoryContainerPair freeSlotPair; + auto freeContainer = getFreeEstateInventorySlot( land->getLandIdent(), freeSlotPair, m_internalStoreroomContainers ); + if ( !freeContainer ) + { + // not sure what to do + interiorContainer->removeItem( i, true ); + } + else + { + interiorContainer->removeItem( i, false ); + freeContainer->setItem( freeSlotPair.second , item ); + changedContainerSet[ freeSlotPair.first ] = freeContainer; + } + } + + invMgr.sendInventoryContainer( player, interiorContainer ); + invMgr.saveHousingContainer( land->getLandIdent(), interiorContainer ); + for( auto entry : changedContainerSet ) + { + invMgr.sendInventoryContainer( player, entry.second ); + invMgr.saveHousingContainer( land->getLandIdent(), entry.second ); + } + + deleteHouse( land->getHouse() ); + land->setHouse( nullptr ); + + land->setStatus( Common::HouseStatus::Sold ); + land->updateLandDb(); + terri->sendLandUpdate( plot ); + + player.setLandFlags( Common::LandFlagsSlot::Private, 0, land->getLandIdent() ); + + terri->removeEstateEntranceEObj( plot ); + return; +} diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index ca147440..9d0da9b3 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -178,6 +178,8 @@ namespace Sapphire::World::Manager bool hasPermission( Entity::Player& player, Land& land, uint32_t permission ); + void removeHouse( Entity::Player& player, uint16_t plot ); + private: Inventory::HousingItemPtr getHousingItemFromPlayer( Entity::Player& player, Common::InventoryType type, uint8_t slot ); @@ -269,6 +271,15 @@ namespace Sapphire::World::Manager */ void createHouse( HousePtr house ) const; + /*! + * @brief Deletes a house + * + * 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 deleteHouse( HousePtr house ) const; + /*! * @brief Gets the next available house id * @return The next available house id diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index 4bf294f7..6714207d 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -98,6 +98,8 @@ void InventoryMgr::saveHousingContainer( Common::LandIdent ident, ItemContainerP for( auto& item : container->getItemMap() ) { + if( !item.second ) + continue; saveHousingContainerItem( u64ident, container->getId(), item.first, item.second->getUId() ); } } diff --git a/src/world/Network/Handlers/PacketCommandHandler.cpp b/src/world/Network/Handlers/PacketCommandHandler.cpp index 4d05bd2b..ee1d7991 100644 --- a/src/world/Network/Handlers/PacketCommandHandler.cpp +++ b/src/world/Network/Handlers/PacketCommandHandler.cpp @@ -763,6 +763,14 @@ void Sapphire::Network::GameConnection::commandHandler( const Packets::FFXIVARR_ break; } + case PacketCommand::HOUSING_LOCK_LAND_BY_BREAK: + { + auto& housingMgr = Service< HousingMgr >::ref(); + housingMgr.removeHouse( player, static_cast< uint16_t >( param11 ) ); + + break; + } + /* case PacketCommand::RequestLandInventory: { uint8_t plot = ( param12 & 0xFF ); diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 798f33d1..d573fa3d 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -308,6 +308,23 @@ Sapphire::Entity::EventObjectPtr Sapphire::HousingZone::registerEstateEntranceEO return eObj; } +void Sapphire::HousingZone::removeEstateEntranceEObj( uint8_t landId ) +{ + auto land = getLand( landId ); + assert( land ); + + for( auto entry : m_eventObjects ) + { + auto eObj = entry.second; + if( eObj->getHousingLink() == static_cast< uint32_t >( landId ) << 8 ) + { + removeActor( eObj ); + m_eventObjects.erase( entry.first ); + break; + } + } +} + void Sapphire::HousingZone::updateYardObjects( Sapphire::Common::LandIdent ident ) { auto& housingMgr = Common::Service< World::Manager::HousingMgr >::ref(); diff --git a/src/world/Territory/HousingZone.h b/src/world/Territory/HousingZone.h index f304ab40..943ccc54 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -52,6 +52,7 @@ namespace Sapphire Sapphire::LandPtr getLand( uint8_t id ); Entity::EventObjectPtr registerEstateEntranceEObj( uint8_t landId ); + void removeEstateEntranceEObj( uint8_t landId ); void updateYardObjects( Common::LandIdent ident ); void spawnYardObject( uint8_t landId, uint16_t slotId, Sapphire::Inventory::HousingItem& item );