From 3624b4374fb03c57bff61c2bd00f5b750aa5d4d5 Mon Sep 17 00:00:00 2001 From: collett Date: Thu, 26 Jan 2023 20:06:27 +0900 Subject: [PATCH] Handle house removing. Also restored the house building scene, might still crash sound device though. --- src/common/Database/ZoneDbConnection.cpp | 4 + src/world/Inventory/ItemContainer.cpp | 3 + src/world/Manager/HousingMgr.cpp | 79 +++++++++++++++++-- src/world/Manager/HousingMgr.h | 4 + src/world/Manager/InventoryMgr.cpp | 3 + .../Network/Handlers/ClientTriggerHandler.cpp | 8 ++ src/world/Territory/HousingZone.cpp | 17 ++++ src/world/Territory/HousingZone.h | 1 + 8 files changed, 114 insertions(+), 5 deletions(-) diff --git a/src/common/Database/ZoneDbConnection.cpp b/src/common/Database/ZoneDbConnection.cpp index a6ecb50c..cf1020c0 100644 --- a/src/common/Database/ZoneDbConnection.cpp +++ b/src/common/Database/ZoneDbConnection.cpp @@ -257,6 +257,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 c150f1fd..ddbece5b 100644 --- a/src/world/Inventory/ItemContainer.cpp +++ b/src/world/Inventory/ItemContainer.cpp @@ -85,6 +85,9 @@ Sapphire::ItemPtr Sapphire::ItemContainer::getItem( uint8_t slotId ) Logger::error( "Slot out of range {0}", 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 3e98a7f7..a99daaa3 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -662,6 +662,14 @@ void Sapphire::World::Manager::HousingMgr::createHouse( Sapphire::HousePtr house db.execute( stmt ); } +void Sapphire::World::Manager::HousingMgr::deleteHouse( Sapphire::HousePtr house ) const +{ + auto& db = Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref(); + auto stmt = db.getPreparedStatement( Db::HOUSING_HOUSE_DEL ); + stmt->setUInt( 1, house->getId() ); + db.execute( stmt ); +} + void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetCatalogId ) { auto hZone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentTerritory() ); @@ -702,12 +710,10 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl pLand->updateLandDb(); - // start house built event - disabled because it fucks your audio device + // start house built event // CmnDefHousingBuildHouse_00149 - //player.eventStart( player.getId(), 0x000B0095, Event::EventHandler::EventType::Housing, 1, 1 ); - //player.playScene( 0x000B0095, 0, static_cast< uint32_t >( SET_BASE | HIDE_HOTBAR ) , 0, 1, plotNum, nullptr ); - // instead we do a fake zone to unlock the client - Common::Service< TerritoryMgr >::ref().movePlayer( player.getCurrentTerritory(), player.getAsPlayer() ); + player.eventStart( player.getId(), 0x000B0095, Event::EventHandler::EventType::Housing, 1, 1 ); + player.playScene( 0x000B0095, 0, static_cast< uint32_t >( SET_BASE | HIDE_HOTBAR ) , 0, 1, plotNum, nullptr ); player.setLandFlags( LandFlagsSlot::Private, EstateBuilt, ident ); player.sendLandFlagsSlot( LandFlagsSlot::Private ); @@ -1688,4 +1694,67 @@ void Sapphire::World::Manager::HousingMgr::editAppearance( bool isInterior, Sapp { terri->sendLandUpdate( landIdent.landId ); } +} + +void Sapphire::World::Manager::HousingMgr::removeHouse( Entity::Player& player, uint16_t plot ) +{ + auto terri = std::dynamic_pointer_cast< HousingZone >( player.getCurrentTerritory() ); + 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() )[ InventoryType::HousingInteriorAppearance ]; + auto& invMgr = Service< InventoryMgr >::ref(); + + std::unordered_map< 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( HouseStatus::Sold ); + land->updateLandDb(); + terri->sendLandUpdate( plot ); + + player.setLandFlags( LandFlagsSlot::Private, 0, land->getLandIdent() ); + + terri->removeEstateEntranceEObj( plot ); + + // missing reply for ClientTrigger RequestEstateHallRemoval + + return; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 1984a16c..9fd8c215 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -183,6 +183,8 @@ namespace Sapphire::World::Manager void editAppearance( bool isInterior, Sapphire::Entity::Player& player, const Common::LandIdent landIdent, std::vector< uint16_t > containerList, std::vector< uint8_t > slotList, uint8_t removeFlag ); + void removeHouse( Entity::Player& player, uint16_t plot ); + private: Inventory::HousingItemPtr getHousingItemFromPlayer( Entity::Player& player, Common::InventoryType type, uint8_t slot ); @@ -274,6 +276,8 @@ namespace Sapphire::World::Manager */ void createHouse( HousePtr house ) const; + 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 722100d7..7a17defa 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -89,6 +89,9 @@ void Sapphire::World::Manager::InventoryMgr::saveHousingContainer( Common::LandI 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/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index c2bedc37..ef520bdc 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -475,6 +475,14 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX break; } + case ClientTriggerType::RequestEstateHallRemoval: + { + auto& housingMgr = Common::Service< HousingMgr >::ref(); + + housingMgr.removeHouse( player, static_cast< uint16_t >( param11 ) ); + + break; + } case ClientTriggerType::UpdateEstateGuestAccess: { auto canTeleport = ( param2 & 0xFF ) == 1; diff --git a/src/world/Territory/HousingZone.cpp b/src/world/Territory/HousingZone.cpp index 8443da8e..09ecf467 100644 --- a/src/world/Territory/HousingZone.cpp +++ b/src/world/Territory/HousingZone.cpp @@ -321,6 +321,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() == 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 112a452a..ee2712b4 100644 --- a/src/world/Territory/HousingZone.h +++ b/src/world/Territory/HousingZone.h @@ -53,6 +53,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 );