diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index 4f38f3ed..6e584ede 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -194,6 +194,15 @@ namespace Sapphire::Network::Packets EventPlay128 = 0x038A, // updated 5.35 hotfix EventPlay255 = 0x034B, // updated 5.35 hotfix + EventYield = 0x037D, // updated 5.35 hotfix + //EventYield4 = 0x0000, + //EventYield8 = 0x0000, + //EventYield16 = 0x0000, + //EventYield32 = 0x0000, + //EventYield64 = 0x0000, + //EventYield128 = 0x0000, + //EventYield255 = 0x0000, + EventStart = 0x009A, // updated 5.35 hotfix EventFinish = 0x007E, // updated 5.35 hotfix @@ -374,7 +383,7 @@ namespace Sapphire::Network::Packets OutOfRangeEventHandler = 0x0319, // updated 5.35 hotfix EnterTeriEventHandler = 0x0192, // updated 5.35 hotfix ShopEventHandler = 0x01F6, // updated 5.35 hotfix - + EventYieldHandler = 0x0128, // updated 5.35 hotfix ReturnEventHandler = 0x02B4, // updated 5.35 hotfix TradeReturnEventHandler = 0x00A4, // updated 5.35 hotfix TradeMultipleReturnEventHander = 0x035C, // updated 5.35 hotfix @@ -387,6 +396,7 @@ namespace Sapphire::Network::Packets LandRenameHandler = 0x0155, // updated 5.35 hotfix HousingUpdateHouseGreeting = 0x02EA, // updated 5.35 hotfix HousingUpdateObjectPosition = 0x00D5, // updated 5.35 hotfix + HousingEditExterior = 0x0098, // updated 5.35 hotfix SetSharedEstateSettings = 0x017B, // updated 5.0 diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 19b4fff5..678a20f2 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -426,6 +426,18 @@ struct FFXIVIpcDive : uint32_t padding; }; +struct FFXIVIpcHousingEditExterior : + FFXIVIpcBasePacket< HousingEditExterior > +{ + uint16_t landId; + uint8_t unknown[6]; + uint8_t removeFlag; + uint8_t unknown2; + uint16_t container[9]; + uint16_t slot[9]; + uint16_t padding; +}; + } #endif //_CORE_NETWORK_PACKETS_ZONE_CLIENT_IPC_H diff --git a/src/world/Inventory/ItemContainer.cpp b/src/world/Inventory/ItemContainer.cpp index 46bedfb5..c150f1fd 100644 --- a/src/world/Inventory/ItemContainer.cpp +++ b/src/world/Inventory/ItemContainer.cpp @@ -92,7 +92,10 @@ Sapphire::ItemPtr Sapphire::ItemContainer::getItem( uint8_t slotId ) void Sapphire::ItemContainer::setItem( uint8_t slotId, ItemPtr pItem ) { if( slotId > m_size ) + { + Logger::error( "Slot out of range {0}", slotId ); return; + } m_itemMap[ slotId ] = pItem; } diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 9cd612bb..ae4228eb 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -702,10 +702,12 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl pLand->updateLandDb(); - // start house built event + // start house built event - disabled because it fucks your audio device // 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 ); + //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.setLandFlags( LandFlagsSlot::Private, EstateBuilt, ident ); player.sendLandFlagsSlot( LandFlagsSlot::Private ); @@ -903,6 +905,8 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { assert( house ); + house->clearModelCache(); + auto& containers = getEstateInventory( house->getLandIdent() ); auto extContainer = containers.find( static_cast< uint16_t >( InventoryType::HousingExteriorAppearance ) ); @@ -1627,3 +1631,59 @@ Sapphire::Inventory::HousingItemPtr Sapphire::World::Manager::HousingMgr::getHou return Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId() ); } + +void Sapphire::World::Manager::HousingMgr::editExterior( Sapphire::Entity::Player& player, uint16_t plot, std::vector< uint16_t > containerList, std::vector< uint8_t> slotList, uint8_t removeFlag ) +{ + auto terri = std::dynamic_pointer_cast< HousingZone >( player.getCurrentTerritory() ); + if( !terri ) + return; + + auto land = terri->getLand( static_cast< uint8_t >( plot ) ); + if( !land ) + return; + + if( !hasPermission( player, *land, 0 ) ) + return; + + auto& exteriorAppearenceContainer = getEstateInventory( land->getLandIdent() )[ InventoryType::HousingExteriorAppearance ]; + + auto& invMgr = Service< InventoryMgr >::ref(); + + for( int i = 0; i < 9; i++ ) + { + auto container = containerList.at( i ); + auto slot = slotList.at( i ); + if( container == 0x270F || slot == 0xFF ) + { + if( i >= 5 ) + { + auto removed = ( ( removeFlag >> ( i - 5 ) ) & 1 ) > 0; + if( removed ) + { + auto oldItem = exteriorAppearenceContainer->getItem( i ); + if( oldItem ) + { + exteriorAppearenceContainer->removeItem( i ); + invMgr.removeItemFromHousingContainer( land->getLandIdent(), exteriorAppearenceContainer->getId(), i ); + player.addItem( oldItem, false, false, false ); + } + } + } + continue; + } + auto item = getHousingItemFromPlayer( player, static_cast< Sapphire::Common::InventoryType >( container ), slot ); + if( item ) + { + auto oldItem = exteriorAppearenceContainer->getItem( i ); + exteriorAppearenceContainer->setItem( i, item ); + if( oldItem ) + { + player.insertInventoryItem( static_cast< Sapphire::Common::InventoryType >( container ), slot, oldItem ); + } + } + } + invMgr.sendInventoryContainer( player, exteriorAppearenceContainer ); + invMgr.saveHousingContainer( land->getLandIdent(), exteriorAppearenceContainer ); + updateHouseModels( land->getHouse() ); + std::dynamic_pointer_cast< HousingZone >( player.getCurrentTerritory() )->sendLandUpdate( plot ); +} \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index b810354f..17dff202 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -181,6 +181,8 @@ namespace Sapphire::World::Manager bool hasPermission( Entity::Player& player, Land& land, uint32_t permission ); + void editExterior( Sapphire::Entity::Player& player, uint16_t plot, std::vector< uint16_t > containerList, std::vector< uint8_t > slotList, uint8_t removeFlag ); + private: Inventory::HousingItemPtr getHousingItemFromPlayer( Entity::Player& player, Common::InventoryType type, uint8_t slot ); diff --git a/src/world/Manager/InventoryMgr.cpp b/src/world/Manager/InventoryMgr.cpp index b4c3759e..722100d7 100644 --- a/src/world/Manager/InventoryMgr.cpp +++ b/src/world/Manager/InventoryMgr.cpp @@ -143,15 +143,15 @@ void Sapphire::World::Manager::InventoryMgr::updateHousingItemPosition( Sapphire stmt->setUInt64( 1, item->getUId() ); - stmt->setUInt( 2, pos.x ); - stmt->setUInt( 3, pos.y ); - stmt->setUInt( 4, pos.z ); - stmt->setInt( 5, rot ); + stmt->setDouble( 2, static_cast< double >( pos.x ) ); + stmt->setDouble( 3, static_cast< double >( pos.y ) ); + stmt->setDouble( 4, static_cast< double >( pos.z ) ); + stmt->setDouble( 5, static_cast< double >( rot ) ); - stmt->setUInt( 6, pos.x ); - stmt->setUInt( 7, pos.y ); - stmt->setUInt( 8, pos.z ); - stmt->setInt( 9, rot ); + stmt->setDouble( 6, static_cast< double >( pos.x ) ); + stmt->setDouble( 7, static_cast< double >( pos.y ) ); + stmt->setDouble( 8, static_cast< double >( pos.z ) ); + stmt->setDouble( 9, static_cast< double >( rot ) ); db.execute( stmt ); } diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 7997cdc4..50711549 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -540,6 +540,7 @@ void Sapphire::World::Manager::TerritoryMgr::updateTerritoryInstances( uint64_t // remove zone from maps m_territorySet.erase( zone ); + m_guIdToTerritoryPtrMap.erase( zone->getGuId() ); it = m_landIdentToTerritoryPtrMap.erase( it ); } else @@ -627,14 +628,27 @@ bool Sapphire::World::Manager::TerritoryMgr::movePlayer( TerritoryPtr pZone, Sap // mark character as zoning in progress pPlayer->setLoadingComplete( false ); + bool zoneChanged = true; if( pPlayer->getLastPing() != 0 && pPlayer->getCurrentTerritory() ) - pPlayer->getCurrentTerritory()->removeActor( pPlayer ); + { + zoneChanged = pPlayer->getCurrentTerritory()->getGuId() != pZone->getGuId(); + if( zoneChanged ) + pPlayer->getCurrentTerritory()->removeActor( pPlayer ); + } - pPlayer->setCurrentZone( pZone ); - pZone->pushActor( pPlayer ); + if( zoneChanged ) + { + pPlayer->setCurrentZone( pZone ); + pZone->pushActor( pPlayer ); - // map player to instanceId so it can be tracked. - m_playerIdToInstanceMap[ pPlayer->getId() ] = pZone->getGuId(); + // map player to instanceId so it can be tracked. + m_playerIdToInstanceMap[ pPlayer->getId() ] = pZone->getGuId(); + } + else + { + pPlayer->removeFromInRange(); + pPlayer->clearInRangeSet(); + } pPlayer->sendZonePackets(); diff --git a/src/world/Network/GameConnection.cpp b/src/world/Network/GameConnection.cpp index 82b401ee..95ac30c4 100644 --- a/src/world/Network/GameConnection.cpp +++ b/src/world/Network/GameConnection.cpp @@ -90,6 +90,7 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH setZoneHandler( ClientZoneIpcType::ReqPlaceHousingItem, "ReqPlaceHousingItem", &GameConnection::reqPlaceHousingItem ); setZoneHandler( ClientZoneIpcType::HousingUpdateObjectPosition, "HousingUpdateObjectPosition", &GameConnection::reqMoveHousingItem ); + setZoneHandler( ClientZoneIpcType::HousingEditExterior, "HousingEditExterior", &GameConnection::housingEditExterior ); 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 8a3aabc0..84c9a1c0 100644 --- a/src/world/Network/GameConnection.h +++ b/src/world/Network/GameConnection.h @@ -181,6 +181,8 @@ namespace Sapphire::Network DECLARE_HANDLER( reqMoveHousingItem ); + DECLARE_HANDLER( housingEditExterior ); + DECLARE_HANDLER( marketBoardSearch ); DECLARE_HANDLER( marketBoardRequestItemInfo ); diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index af472089..35fd8b10 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -691,6 +691,23 @@ void Sapphire::Network::GameConnection::reqMoveHousingItem( const Packets::FFXIV housingMgr.reqMoveHousingItem( player, data.ident, data.slot, data.pos, data.rotation ); } +void Sapphire::Network::GameConnection::housingEditExterior( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) +{ + auto& housingMgr = Common::Service< HousingMgr >::ref(); + const auto packet = ZoneChannelPacket< Client::FFXIVIpcHousingEditExterior >( inPacket ); + + std::vector< uint16_t > containerList; + std::vector< uint8_t > slotList; + for( int i = 0; i < 9; i++ ) + { + auto container = packet.data().container[i]; + containerList.push_back( container ); + slotList.push_back( container != 0x270F ? static_cast< uint8_t >( packet.data().slot[i] ) : 0xFF ); + } + + housingMgr.editExterior( player, packet.data().landId, containerList, slotList, packet.data().removeFlag ); +} + void Sapphire::Network::GameConnection::marketBoardSearch( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) { diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index c5f44bc6..518021dc 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -64,6 +64,11 @@ Sapphire::House::ExteriorModelsArray const& Sapphire::House::getHouseModels() co return m_exteriorModelCache; } +void Sapphire::House::clearModelCache() +{ + m_exteriorModelCache.fill( std::make_pair( 0, 0 ) ); +} + const std::string& Sapphire::House::getHouseName() const { return m_estateName; diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index 9a3a3da0..6d195cd0 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -41,6 +41,8 @@ namespace Sapphire ExteriorModelsArray const& getHouseModels() const; + void clearModelCache(); + void updateHouseDb(); void setHasAetheryte( bool hasAetheryte ); diff --git a/src/world/Territory/Land.cpp b/src/world/Territory/Land.cpp index fe7f8771..bb16550c 100644 --- a/src/world/Territory/Land.cpp +++ b/src/world/Territory/Land.cpp @@ -240,5 +240,20 @@ void Sapphire::Land::update( uint64_t tickCount ) Sapphire::Land::InvMaxItemsPair Sapphire::Land::getInventoryItemMax() const { - return std::make_pair( m_maxPlacedExternalItems, m_maxPlacedInternalItems ); + switch( m_size ) + { + case HouseSize::Cottage: + { + return std::make_pair( 20, 200 ); + } + case HouseSize::House: + { + return std::make_pair( 30, 300 ); + } + case HouseSize::Mansion: + { + return std::make_pair( 40, 400 ); + } + } + assert( false ); } diff --git a/src/world/Territory/Land.h b/src/world/Territory/Land.h index 48f696e2..4cd2f522 100644 --- a/src/world/Territory/Land.h +++ b/src/world/Territory/Land.h @@ -86,10 +86,6 @@ namespace Sapphire Sapphire::HousePtr m_pHouse; - //item storage - uint16_t m_maxPlacedExternalItems; - uint16_t m_maxPlacedInternalItems; - //price uint32_t m_initPrice; uint32_t m_nextDrop;