From 79ed3d63d979caf534e31ea0852a073aee140b69 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 17:44:03 +1100 Subject: [PATCH 1/5] #448 - remove deed on build --- src/common/Common.h | 2 +- src/world/Actor/Player.h | 2 +- src/world/Actor/PlayerInventory.cpp | 21 ++++++++++ src/world/Manager/HousingMgr.cpp | 41 ++++++++++++------- src/world/Manager/HousingMgr.h | 2 +- src/world/Territory/House.cpp | 4 +- src/world/Territory/House.h | 4 +- .../Housing/HousingInteriorTerritory.cpp | 2 +- 8 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 29296509..9363426d 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -791,7 +791,7 @@ namespace Sapphire::Common ExteriorFence }; - enum HousingInteriorSlot + enum HouseInteriorSlot { InteriorWall, InteriorFloor, diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index ce11587c..2721bba2 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -916,7 +916,7 @@ namespace Sapphire::Entity uint32_t getNextInventorySequence(); - void send(); + bool findFirstItemWithId( uint32_t catalogId, Inventory::InventoryContainerPair& location ); uint8_t getFreeSlotsInBags(); diff --git a/src/world/Actor/PlayerInventory.cpp b/src/world/Actor/PlayerInventory.cpp index d0b9cf82..df42dc8d 100644 --- a/src/world/Actor/PlayerInventory.cpp +++ b/src/world/Actor/PlayerInventory.cpp @@ -932,4 +932,25 @@ void Sapphire::Entity::Player::insertInventoryItem( Sapphire::Common::InventoryT auto slotUpdate = std::make_shared< UpdateInventorySlotPacket >( getId(), slot, type, *item ); queuePacket( slotUpdate ); +} + +bool Sapphire::Entity::Player::findFirstItemWithId( uint32_t catalogId, + Inventory::InventoryContainerPair& location ) +{ + for( auto bagId : { Bag0, Bag1, Bag2, Bag3 } ) + { + auto& container = m_storageMap[ bagId ]; + + for( const auto& item : container->getItemMap() ) + { + if( item.second->getId() != catalogId ) + continue; + + location = std::make_pair( bagId, item.first ); + + return true; + } + } + + return false; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index b14ac88b..1d3d079b 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -564,6 +564,18 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play if( !preset ) return false; + // remove preset item + Inventory::InventoryContainerPair foundItem; + if( !player.findFirstItemWithId( presetCatalogId, foundItem ) ) + return false; + + auto item = player.dropInventoryItem( foundItem.first, foundItem.second ); + if( !item ) + return false; + + // move preset item into ext appearance container + houseInventory[ InventoryType::HousingExteriorAppearance ]->setItem( HouseExteriorSlot::HousePermit, item ); + // high iq shit auto invMap = std::map< uint16_t, std::map< uint32_t, int32_t > > { @@ -583,19 +595,19 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play InventoryType::HousingInteriorAppearance, { // lobby/middle floor - { HousingInteriorSlot::InteriorWall, preset->interiorWall }, - { HousingInteriorSlot::InteriorFloor, preset->interiorFlooring }, - { HousingInteriorSlot::InteriorLight, preset->interiorLighting }, + { HouseInteriorSlot::InteriorWall, preset->interiorWall }, + { HouseInteriorSlot::InteriorFloor, preset->interiorFlooring }, + { HouseInteriorSlot::InteriorLight, preset->interiorLighting }, // attic - { HousingInteriorSlot::InteriorWall_Attic, preset->otherFloorWall }, - { HousingInteriorSlot::InteriorFloor_Attic, preset->otherFloorFlooring }, - { HousingInteriorSlot::InteriorLight_Attic, preset->otherFloorLighting }, + { HouseInteriorSlot::InteriorWall_Attic, preset->otherFloorWall }, + { HouseInteriorSlot::InteriorFloor_Attic, preset->otherFloorFlooring }, + { HouseInteriorSlot::InteriorLight_Attic, preset->otherFloorLighting }, // basement - { HousingInteriorSlot::InteriorWall_Basement, preset->basementWall }, - { HousingInteriorSlot::InteriorFloor_Basement, preset->basementFlooring }, - { HousingInteriorSlot::InteriorLight_Basement, preset->basementLighting }, + { HouseInteriorSlot::InteriorWall_Basement, preset->basementWall }, + { HouseInteriorSlot::InteriorFloor_Basement, preset->basementFlooring }, + { HouseInteriorSlot::InteriorLight_Basement, preset->basementLighting }, } } }; @@ -641,7 +653,7 @@ void Sapphire::World::Manager::HousingMgr::createHouse( Sapphire::HousePtr house pDb->execute( stmt ); } -void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetItem ) +void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetCatalogId ) { auto hZone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ); @@ -656,8 +668,6 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl if( pLand->getOwnerId() != player.getId() ) return; - // todo: check if permit is in inventory and remove one - // create house auto ident = pLand->getLandIdent(); auto house = make_House( getNextHouseId(), pLand->getLandSetId(), ident, @@ -666,8 +676,11 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl pLand->setHouse( house ); // create inventory items - if( !initHouseModels( player, pLand, presetItem ) ) + if( !initHouseModels( player, pLand, presetCatalogId ) ) + { + pLand->setHouse( nullptr ); return; + } createHouse( house ); @@ -913,7 +926,7 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr { for( auto& item : intContainer->second->getItemMap() ) { - house->setInteriorModel( static_cast< Common::HousingInteriorSlot >( item.first ), + house->setInteriorModel( static_cast< Common::HouseInteriorSlot >( item.first ), getItemAdditionalData( item.second->getId() ) ); } } diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 9dd0bd23..4f2a6898 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -91,7 +91,7 @@ namespace Sapphire::World::Manager bool relinquishLand( Entity::Player& player, uint8_t plot ); - void buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetItem ); + void buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetCatalogId ); void requestEstateRename( Entity::Player& player, const Common::LandIdent ident ); diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index 396e763e..fe08783d 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -96,12 +96,12 @@ Sapphire::House::HousePart Sapphire::House::getExteriorModel( Sapphire::Common:: return m_exteriorModelCache[ slot ]; } -void Sapphire::House::setInteriorModel( Sapphire::Common::HousingInteriorSlot slot, uint32_t modelId ) +void Sapphire::House::setInteriorModel( Sapphire::Common::HouseInteriorSlot slot, uint32_t modelId ) { m_interiorModelCache[ slot ] = modelId; } -uint32_t Sapphire::House::getInteriorModel( Sapphire::Common::HousingInteriorSlot slot ) +uint32_t Sapphire::House::getInteriorModel( Sapphire::Common::HouseInteriorSlot slot ) { return m_interiorModelCache[ slot ]; } diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index 3229e0e0..21d3ea86 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -34,8 +34,8 @@ namespace Sapphire void setExteriorModel( Common::HouseExteriorSlot slot, uint32_t modelId, uint16_t stain ); HousePart getExteriorModel( Common::HouseExteriorSlot slot ); - void setInteriorModel( Common::HousingInteriorSlot slot, uint32_t modelId ); - uint32_t getInteriorModel( Common::HousingInteriorSlot slot ); + void setInteriorModel( Common::HouseInteriorSlot slot, uint32_t modelId ); + uint32_t getInteriorModel( Common::HouseInteriorSlot slot ); HouseModelsArray const& getHouseModels() const; diff --git a/src/world/Territory/Housing/HousingInteriorTerritory.cpp b/src/world/Territory/Housing/HousingInteriorTerritory.cpp index dddbd86d..1ad7b57e 100644 --- a/src/world/Territory/Housing/HousingInteriorTerritory.cpp +++ b/src/world/Territory/Housing/HousingInteriorTerritory.cpp @@ -71,7 +71,7 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone for( auto i = 0; i < 10; i++ ) { indoorInitPacket->data().indoorItems[ i ] = pHouse->getInteriorModel( - static_cast< Common::HousingInteriorSlot >( i ) ); + static_cast< Common::HouseInteriorSlot >( i ) ); } player.queuePacket( indoorInitPacket ); From 4d35888b278b7f1055d58f099527e4ca77413226 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 18:48:45 +1100 Subject: [PATCH 2/5] #448 - Place character correctly on entering a house --- .../common/eobj/HousingEstateEntrance.cpp | 41 ++++++++++++++++--- src/world/Actor/Player.cpp | 27 ++++++++++++ src/world/Actor/Player.h | 3 ++ src/world/Manager/TerritoryMgr.cpp | 8 ++-- src/world/Manager/TerritoryMgr.h | 2 +- 5 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/scripts/common/eobj/HousingEstateEntrance.cpp b/src/scripts/common/eobj/HousingEstateEntrance.cpp index a576bc19..7461ef1e 100644 --- a/src/scripts/common/eobj/HousingEstateEntrance.cpp +++ b/src/scripts/common/eobj/HousingEstateEntrance.cpp @@ -4,6 +4,7 @@ #include "Actor/EventObject.h" #include "Territory/HousingZone.h" #include "Manager/TerritoryMgr.h" +#include "Territory/Land.h" #include "Framework.h" using namespace Sapphire; @@ -19,8 +20,6 @@ public: void onTalk( uint32_t eventId, Entity::Player& player, Entity::EventObject& eobj ) override { - player.sendDebug( "Found plot entrance for plot: " + std::to_string( eobj.getHousingLink() >> 8 ) ); - player.playScene( eventId, 0, 0, [this, eobj]( Entity::Player& player, const Event::SceneResult& result ) { // param2 == 1 when player wants to enter house @@ -42,15 +41,45 @@ public: ident.worldId = 67; auto internalZone = terriMgr->findOrCreateHousingInterior( ident ); - if( internalZone ) + if( !internalZone ) { - player.sendDebug( "created zone with guid: " + std::to_string( internalZone->getGuId() ) + "\nname: " + internalZone->getName() ); + // an error occurred during event movement + // lol + player.sendLogMessage( 1311 ); + player.eventFinish( result.eventId, 1 ); + return; } player.eventFinish( result.eventId, 1 ); - player.setPos( { 0.f, 0.f, 0.f } ); - player.setInstance( internalZone ); + Common::FFXIVARR_POSITION3 pos {}; + + auto land = zone->getLand( eobj.getHousingLink() >> 8 ); + if( !land ) + return; + + switch( land->getSize() ) + { + case 0: + { + pos = { 0.1321167f, 0.f, 2.746273f }; + break; + } + case 1: + { + pos = { 1.337722f, 0.f, 3.995964f }; + break; + } + case 2: + { + pos = { 0.07214607f, 0.f, 8.217761f }; + break; + } + default: + return; + } + + player.setInstance( internalZone, pos ); } ); } }; \ No newline at end of file diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 33bcb871..5696a8a0 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -459,6 +459,33 @@ bool Sapphire::Entity::Player::setInstance( ZonePtr instance ) return true; } +bool Sapphire::Entity::Player::setInstance( ZonePtr instance, Common::FFXIVARR_POSITION3 pos ) +{ + if( !instance ) + return false; + + m_onEnterEventDone = false; + + auto pTeriMgr = m_pFw->get< TerritoryMgr >(); + auto currentZone = getCurrentZone(); + + m_prevPos = m_pos; + m_prevRot = m_rot; + m_prevTerritoryTypeId = currentZone->getTerritoryTypeId(); + m_prevTerritoryId = getTerritoryId(); + + if( pTeriMgr->movePlayer( instance, getAsPlayer() ) ) + { + m_pos = pos; + + sendZonePackets(); + + return true; + } + + return false; +} + bool Sapphire::Entity::Player::exitInstance() { auto pTeriMgr = m_pFw->get< TerritoryMgr >(); diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 2721bba2..218b27f9 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -482,6 +482,9 @@ namespace Sapphire::Entity /*! sets the players instance & initiates zoning process */ bool setInstance( ZonePtr instance ); + /*! sets the players instance & initiates zoning process */ + bool setInstance( Sapphire::ZonePtr instance, Sapphire::Common::FFXIVARR_POSITION3 pos ); + /*! returns the player to their position before zoning into an instance */ bool exitInstance(); diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 575c60b7..9e260c61 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -287,7 +287,7 @@ Sapphire::ZonePtr Sapphire::World::Manager::TerritoryMgr::createInstanceContent( pTeri->name, pInstanceContent->name, instanceContentId, framework() ); pZone->init(); - m_instanceContentToInstanceMap[ instanceContentId ][ pZone->getGuId() ] = pZone; + m_instanceContentIdToInstanceMap[ instanceContentId ][ pZone->getGuId() ] = pZone; m_instanceIdToZonePtrMap[ pZone->getGuId() ] = pZone; m_instanceZoneSet.insert( pZone ); @@ -381,7 +381,7 @@ bool Sapphire::World::Manager::TerritoryMgr::removeTerritoryInstance( uint32_t i if( isInstanceContentTerritory( pZone->getTerritoryTypeId() ) ) { auto instance = std::dynamic_pointer_cast< InstanceContent >( pZone ); - m_instanceContentToInstanceMap[ instance->getInstanceContentId() ].erase( pZone->getGuId() ); + m_instanceContentIdToInstanceMap[ instance->getInstanceContentId() ].erase( pZone->getGuId() ); } else m_territoryTypeIdToInstanceGuidMap[ pZone->getTerritoryTypeId() ].erase( pZone->getGuId() ); @@ -486,8 +486,8 @@ void Sapphire::World::Manager::TerritoryMgr::updateTerritoryInstances( uint32_t Sapphire::World::Manager::TerritoryMgr::InstanceIdList Sapphire::World::Manager::TerritoryMgr::getInstanceContentIdList( uint16_t instanceContentId ) const { std::vector< uint32_t > idList; - auto zoneMap = m_instanceContentToInstanceMap.find( instanceContentId ); - if( zoneMap == m_instanceContentToInstanceMap.end() ) + auto zoneMap = m_instanceContentIdToInstanceMap.find( instanceContentId ); + if( zoneMap == m_instanceContentIdToInstanceMap.end() ) return idList; for( auto& entry : zoneMap->second ) diff --git a/src/world/Manager/TerritoryMgr.h b/src/world/Manager/TerritoryMgr.h index b32c9fcb..1905b7f6 100644 --- a/src/world/Manager/TerritoryMgr.h +++ b/src/world/Manager/TerritoryMgr.h @@ -176,7 +176,7 @@ namespace Sapphire::World::Manager LandSetIdToZonePtrMap m_landSetIdToZonePtrMap; /*! map holding actual instances of InstanceContent */ - InstanceContentIdToInstanceMap m_instanceContentToInstanceMap; + InstanceContentIdToInstanceMap m_instanceContentIdToInstanceMap; /*! flat map for easier lookup of instances by guid */ InstanceIdToZonePtrMap m_instanceIdToZonePtrMap; From aa70c9775f9a3e637ee9cff31e84fb6b8f42403b Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 20:24:20 +1100 Subject: [PATCH 3/5] minor refactoring and zero out model cache arrays on init --- src/world/Territory/House.cpp | 7 +++++-- src/world/Territory/House.h | 10 ++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/world/Territory/House.cpp b/src/world/Territory/House.cpp index fe08783d..def91bc6 100644 --- a/src/world/Territory/House.cpp +++ b/src/world/Territory/House.cpp @@ -19,7 +19,10 @@ Sapphire::House::House( uint32_t houseId, uint32_t landSetId, Common::LandIdent m_estateName( estateName ), m_estateComment( estateComment ), m_pFw( pFw ) -{} +{ + m_interiorModelCache.fill( 0 ); + m_exteriorModelCache.fill( std::make_pair( 0, 0 ) ); +} Sapphire::House::~House() = default; @@ -57,7 +60,7 @@ uint32_t Sapphire::House::getId() const return m_houseId; } -Sapphire::House::HouseModelsArray const& Sapphire::House::getHouseModels() const +Sapphire::House::ExteriorModelsArray const& Sapphire::House::getHouseModels() const { return m_exteriorModelCache; } diff --git a/src/world/Territory/House.h b/src/world/Territory/House.h index 21d3ea86..1fa0ca43 100644 --- a/src/world/Territory/House.h +++ b/src/world/Territory/House.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace Sapphire { @@ -17,7 +18,8 @@ namespace Sapphire virtual ~House(); using HousePart = std::pair< uint32_t, uint16_t >; - using HouseModelsArray = std::array< HousePart, 8 >; + using ExteriorModelsArray = std::array< HousePart, 8 >; + using InteriorModelsArray = std::array< uint32_t, 10 >; //gerneral uint32_t getLandSetId() const; @@ -37,7 +39,7 @@ namespace Sapphire void setInteriorModel( Common::HouseInteriorSlot slot, uint32_t modelId ); uint32_t getInteriorModel( Common::HouseInteriorSlot slot ); - HouseModelsArray const& getHouseModels() const; + ExteriorModelsArray const& getHouseModels() const; void updateHouseDb(); @@ -52,8 +54,8 @@ namespace Sapphire uint64_t m_buildTime; bool m_hasAetheryte; - HouseModelsArray m_exteriorModelCache; - uint32_t m_interiorModelCache[10]; + ExteriorModelsArray m_exteriorModelCache; + InteriorModelsArray m_interiorModelCache; std::string m_estateComment; std::string m_estateName; From 8964d23246b6e7fb20513ce31de9ca0d589f9ff3 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 20:26:03 +1100 Subject: [PATCH 4/5] fix eobj id allocation skipping every nth index --- src/world/Territory/Zone.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/world/Territory/Zone.cpp b/src/world/Territory/Zone.cpp index 699a1dfd..1a3a5745 100644 --- a/src/world/Territory/Zone.cpp +++ b/src/world/Territory/Zone.cpp @@ -714,7 +714,6 @@ void Sapphire::Zone::registerEObj( Entity::EventObjectPtr object ) if( !object ) return; - object->setId( getNextEObjId() ); pushActor( object ); m_eventObjects[ object->getId() ] = object; From 4d501b4eb25b72ebb518cad014fd028d110dfb47 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sun, 30 Dec 2018 21:26:32 +1100 Subject: [PATCH 5/5] fix issue where items couldn't be placed in storeroom from inv --- src/common/Logging/Logger.cpp | 10 ++ src/common/Logging/Logger.h | 4 + .../Network/PacketDef/Zone/ClientZoneDef.h | 2 +- src/world/Manager/HousingMgr.cpp | 133 ++++++++++++++---- src/world/Manager/HousingMgr.h | 4 + src/world/Network/Handlers/PacketHandlers.cpp | 10 +- 6 files changed, 130 insertions(+), 33 deletions(-) diff --git a/src/common/Logging/Logger.cpp b/src/common/Logging/Logger.cpp index 1a599551..c051e946 100644 --- a/src/common/Logging/Logger.cpp +++ b/src/common/Logging/Logger.cpp @@ -58,6 +58,11 @@ namespace Sapphire spdlog::get( "logger" )->error( text ); } + void Logger::warn( const std::string& text ) + { + spdlog::get( "logger" )->warn( text ); + } + void Logger::info( const std::string& text ) { spdlog::get( "logger" )->info( text ); @@ -73,4 +78,9 @@ namespace Sapphire spdlog::get( "logger" )->critical( text ); } + void Logger::trace( const std::string& text ) + { + spdlog::get( "logger" )->trace( text ); + } + } diff --git a/src/common/Logging/Logger.h b/src/common/Logging/Logger.h index 876fadc3..b716e319 100644 --- a/src/common/Logging/Logger.h +++ b/src/common/Logging/Logger.h @@ -20,12 +20,16 @@ namespace Sapphire static void error( const std::string& text ); + static void warn( const std::string& text ); + static void info( const std::string& text ); static void debug( const std::string& text ); static void fatal( const std::string& text ); + static void trace( const std::string& text ); + }; } diff --git a/src/common/Network/PacketDef/Zone/ClientZoneDef.h b/src/common/Network/PacketDef/Zone/ClientZoneDef.h index 12b452dd..e096fa8a 100644 --- a/src/common/Network/PacketDef/Zone/ClientZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ClientZoneDef.h @@ -253,7 +253,7 @@ struct FFXIVIpcReqPlaceHousingItem : /* 000C */ Common::FFXIVARR_POSITION3 position; /* 0018 */ float rotation; - /* 001C */ uint32_t unknown3; // always 1? + /* 001C */ uint32_t shouldPlaceItem; // 1 if placing an item, 0 if placing in store /* 0020 */ uint32_t unknown4[2]; // always 0 it looks like }; diff --git a/src/world/Manager/HousingMgr.cpp b/src/world/Manager/HousingMgr.cpp index 1d3d079b..8badd385 100644 --- a/src/world/Manager/HousingMgr.cpp +++ b/src/world/Manager/HousingMgr.cpp @@ -416,11 +416,10 @@ bool Sapphire::World::Manager::HousingMgr::relinquishLand( Entity::Player& playe auto pLand = pHousing->getLand( plot ); auto plotMaxPrice = pLand->getCurrentPrice(); - auto landOwnerId = pLand->getOwnerId(); // can't relinquish when you are not the owner // TODO: actually use permissions here for FC houses - if( landOwnerId != player.getId() ) + if( !hasPermission( player, *pLand, 0 ) ) { auto msgPkt = makeActorControl143( player.getId(), ActorControl::LogMsg, 3304, 0 ); player.queuePacket( msgPkt ); @@ -664,8 +663,7 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl if( !pLand ) return; - // todo: when doing FC houses, look up the type from the original purchase and check perms from FC and set state accordingly - if( pLand->getOwnerId() != player.getId() ) + if( !hasPermission( player, *pLand, 0 ) ) return; // create house @@ -763,8 +761,7 @@ void Sapphire::World::Manager::HousingMgr::updateEstateGreeting( Entity::Player& if( !land ) return; - // todo: implement proper permissions checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto house = land->getHouse(); @@ -789,8 +786,7 @@ void Sapphire::World::Manager::HousingMgr::requestEstateEditGuestAccess( Entity: if( !land ) return; - // todo: add proper permission check - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto packet = makeZonePacket< Server::FFXIVIpcHousingShowEstateGuestAccess >( player.getId() ); @@ -854,8 +850,7 @@ void Sapphire::World::Manager::HousingMgr::sendEstateInventory( Entity::Player& if( !targetLand ) return; - // todo: add proper permissions checks - if( targetLand->getOwnerId() != player.getId() ) + if( !hasPermission( player, *targetLand, 0 ) ) return; auto& containers = getEstateInventory( targetLand->getLandIdent() ); @@ -993,12 +988,11 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity if( !land ) return; - // todo: add proper permissions checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; // todo: check item position and make sure it's not outside the plot - // retail uses a radius based check + // anecdotal evidence on reddit seems to imply retail uses a radius based check // unlink item Inventory::HousingItemPtr item; @@ -1009,6 +1003,8 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity containerId == InventoryType::Bag3 ) { auto tmpItem = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + if( !tmpItem ) + return; item = Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId(), framework() ); @@ -1042,6 +1038,76 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity player.sendUrgent( "An internal error occurred when placing the item." ); } +void Sapphire::World::Manager::HousingMgr::reqPlaceItemInStore( Sapphire::Entity::Player& player, uint16_t landId, + uint16_t containerId, uint16_t slotId ) +{ + LandPtr land; + bool isOutside = false; + + if( auto zone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ) ) + { + land = zone->getLand( landId ); + isOutside = true; + } + else if( auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ) ) + { + // todo: this whole process is retarded and needs to be fixed + // perhaps maintain a list of estates by ident inside housingmgr? + auto ident = zone->getLandIdent(); + auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum ); + + land = getHousingZoneByLandSetId( landSet )->getLand( ident.landId ); + } + + if( !hasPermission( player, *land, 0 ) ) + return; + + auto invMgr = framework()->get< InventoryMgr >(); + auto ident = land->getLandIdent(); + auto& containers = getEstateInventory( ident ); + + if( isOutside ) + { + auto& container = containers[ InventoryType::HousingExteriorStoreroom ]; + + auto freeSlot = container->getFreeSlot(); + if( freeSlot == -1 ) + return; + + auto item = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + if( !item ) + return; + + container->setItem( freeSlot, item ); + invMgr->sendInventoryContainer( player, container ); + invMgr->saveHousingContainer( ident, container ); + } + else + { + for( auto houseContainer : m_internalStoreroomContainers ) + { + auto needle = containers.find( houseContainer ); + if( needle == containers.end() ) + continue; + + auto container = needle->second; + auto freeSlot = container->getFreeSlot(); + if( freeSlot == -1 ) + { + continue; + } + + auto item = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId ); + if( !item ) + return; + + container->setItem( freeSlot, item ); + invMgr->sendInventoryContainer( player, container ); + invMgr->saveHousingContainer( ident, container ); + } + } +} + bool Sapphire::World::Manager::HousingMgr::placeExternalItem( Entity::Player& player, Inventory::HousingItemPtr item, Common::LandIdent ident ) @@ -1107,9 +1173,6 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl // have a free slot container->setItem( freeSlot, item ); - // todo: see comment above in placeExternalItem where the same func is called - invMgr->saveItem( player, item ); - // resend container invMgr->sendInventoryContainer( player, container ); invMgr->saveHousingContainer( ident, container ); @@ -1176,8 +1239,7 @@ void Sapphire::World::Manager::HousingMgr::reqMoveHousingItem( Entity::Player& p if( !land ) return; - // todo: proper perms checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; // todo: what happens when either of these fail? how does the server let the client know that the moment failed @@ -1250,8 +1312,7 @@ bool Sapphire::World::Manager::HousingMgr::moveExternalItem( Entity::Player& pla { auto land = terri.getLand( ident.landId ); - // todo: add proper perms check - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return false; auto& containers = getEstateInventory( ident ); @@ -1298,8 +1359,7 @@ void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entit if( !land ) return; - // todo: proper perms checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; removeInternalItem( player, *terri, containerId, slot, sendToStoreroom ); @@ -1310,7 +1370,7 @@ void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entit if( !land ) return; - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto containerType = static_cast< Common::InventoryType >( containerId ); @@ -1419,11 +1479,13 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p if( !item ) return false; + bool shouldDespawnItem = containerType != InventoryType::HousingExteriorStoreroom; + auto invMgr = framework()->get< InventoryMgr >(); if( sendToStoreroom ) { - auto& storeroomContainer = containers[ InventoryType::HousingExteriorStoreroom ]; + auto& storeroomContainer = containers[ containerType ]; auto freeSlot = storeroomContainer->getFreeSlot(); if( freeSlot == -1 ) @@ -1431,8 +1493,8 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p sourceContainer->removeItem( slotId ); invMgr->sendInventoryContainer( player, sourceContainer ); - invMgr->removeHousingItemPosition( *item ); invMgr->removeItemFromHousingContainer( land.getLandIdent(), sourceContainer->getId(), slotId ); + invMgr->removeHousingItemPosition( *item ); storeroomContainer->setItem( freeSlot, item ); invMgr->sendInventoryContainer( player, storeroomContainer ); @@ -1454,7 +1516,8 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p player.insertInventoryItem( containerPair.first, containerPair.second, item ); } - terri.despawnYardObject( land.getLandIdent().landId, slotId ); + if( shouldDespawnItem ) + terri.despawnYardObject( land.getLandIdent().landId, slotId ); return true; } @@ -1495,8 +1558,7 @@ void Sapphire::World::Manager::HousingMgr::reqEstateExteriorRemodel( Sapphire::E if( !land ) return; - // todo: proper perms checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto& inv = getEstateInventory( land->getLandIdent() ); @@ -1526,8 +1588,7 @@ void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::E if( !land ) return; - // todo: proper perms checks - if( land->getOwnerId() != player.getId() ) + if( !hasPermission( player, *land, 0 ) ) return; auto& inv = getEstateInventory( land->getLandIdent() ); @@ -1541,4 +1602,16 @@ void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::E auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateInternalAppearanceUI ); player.queuePacket( pkt ); +} + +bool Sapphire::World::Manager::HousingMgr::hasPermission( Sapphire::Entity::Player& player, Sapphire::Land& land, + uint32_t permission ) +{ + // todo: proper perms checks pls + if( land.getOwnerId() == player.getId() ) + return true; + + // todo: check perms here + + return false; } \ No newline at end of file diff --git a/src/world/Manager/HousingMgr.h b/src/world/Manager/HousingMgr.h index 4f2a6898..deb6c099 100644 --- a/src/world/Manager/HousingMgr.h +++ b/src/world/Manager/HousingMgr.h @@ -159,6 +159,8 @@ namespace Sapphire::World::Manager void reqPlaceHousingItem( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId, Common::FFXIVARR_POSITION3 pos, float rotation ); + void reqPlaceItemInStore( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId ); + /*! * @brief Returns the equivalent YardObject for a HousingItem * @param item The item to convert into a YardObject @@ -179,6 +181,8 @@ namespace Sapphire::World::Manager void reqEstateInteriorRemodel( Entity::Player& player ); + bool hasPermission( Entity::Player& player, Land& land, uint32_t permission ); + private: ItemContainerPtr getFreeEstateInventorySlot( Common::LandIdent ident, diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index a41ed334..fa6543bf 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -731,8 +731,14 @@ void Sapphire::Network::GameConnection::reqPlaceHousingItem( FrameworkPtr pFw, const auto packet = ZoneChannelPacket< Client::FFXIVIpcReqPlaceHousingItem >( inPacket ); const auto& data = packet.data(); - housingMgr->reqPlaceHousingItem( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId, - data.position, data.rotation ); + if( data.shouldPlaceItem == 1 ) + { + housingMgr->reqPlaceHousingItem( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId, + data.position, data.rotation ); + } + else + housingMgr->reqPlaceItemInStore( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId ); + } void Sapphire::Network::GameConnection::reqMoveHousingItem( FrameworkPtr pFw,