2018-07-15 23:59:15 +02:00
|
|
|
#include <Common.h>
|
|
|
|
#include <Logging/Logger.h>
|
|
|
|
#include <Util/Util.h>
|
|
|
|
#include <Util/UtilMath.h>
|
2018-11-01 00:18:19 +01:00
|
|
|
#include <Database/DatabaseDef.h>
|
2018-11-04 23:47:10 +01:00
|
|
|
#include <Exd/ExdDataGenerated.h>
|
2019-03-08 15:34:38 +01:00
|
|
|
#include <Network/GamePacket.h>
|
2018-07-15 23:59:15 +02:00
|
|
|
#include <Network/PacketDef/Zone/ServerZoneDef.h>
|
2019-10-09 18:14:53 +02:00
|
|
|
#include <Network/PacketWrappers/ActorControlSelfPacket.h>
|
2018-12-28 11:49:12 +11:00
|
|
|
#include <Network/CommonActorControl.h>
|
2018-07-15 23:59:15 +02:00
|
|
|
|
|
|
|
#include "Actor/Player.h"
|
2018-11-01 00:18:19 +01:00
|
|
|
#include "Actor/Actor.h"
|
2018-11-30 22:52:08 +11:00
|
|
|
#include "Actor/EventObject.h"
|
2018-11-01 23:56:43 +01:00
|
|
|
#include "Land.h"
|
2018-11-25 01:55:53 +11:00
|
|
|
#include "House.h"
|
2018-12-26 00:43:27 +11:00
|
|
|
#include "Inventory/HousingItem.h"
|
|
|
|
#include "Inventory/ItemContainer.h"
|
2018-07-15 23:59:15 +02:00
|
|
|
|
|
|
|
#include "Forwards.h"
|
|
|
|
#include "HousingZone.h"
|
2018-12-01 00:27:16 +11:00
|
|
|
#include "Manager/HousingMgr.h"
|
2018-07-15 23:59:15 +02:00
|
|
|
#include "Framework.h"
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
using namespace Sapphire::Common;
|
|
|
|
using namespace Sapphire::Network::Packets;
|
|
|
|
using namespace Sapphire::Network::Packets::Server;
|
2018-12-01 00:27:16 +11:00
|
|
|
using namespace Sapphire::World::Manager;
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
Sapphire::HousingZone::HousingZone( uint8_t wardNum,
|
2018-12-29 00:53:52 +01:00
|
|
|
uint16_t territoryTypeId,
|
|
|
|
uint32_t guId,
|
|
|
|
const std::string& internalName,
|
|
|
|
const std::string& contentName,
|
|
|
|
FrameworkPtr pFw ) :
|
2019-07-21 22:33:33 +10:00
|
|
|
Territory( territoryTypeId, guId, internalName, contentName, pFw ),
|
2018-11-04 23:47:10 +01:00
|
|
|
m_wardNum( wardNum ),
|
2018-12-02 15:32:22 +11:00
|
|
|
m_territoryTypeId( territoryTypeId ),
|
2018-12-29 00:53:52 +01:00
|
|
|
m_landSetId( ( static_cast< uint32_t >( territoryTypeId ) << 16 ) | wardNum ),
|
|
|
|
m_pFw( pFw )
|
2018-07-15 23:59:15 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
bool Sapphire::HousingZone::init()
|
2018-07-15 23:59:15 +02:00
|
|
|
{
|
2018-11-04 23:47:10 +01:00
|
|
|
|
2018-12-29 00:53:52 +01:00
|
|
|
auto pDb = m_pFw->get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
|
2018-11-04 23:47:10 +01:00
|
|
|
{
|
2018-12-22 00:48:43 +11:00
|
|
|
auto res = pDb->query( "SELECT * FROM landset WHERE landsetid = " + std::to_string( m_landSetId ) );
|
|
|
|
if( !res->next() )
|
|
|
|
{
|
|
|
|
pDb->directExecute( "INSERT INTO landset ( landsetid ) VALUES ( " + std::to_string( m_landSetId ) + " );" );
|
|
|
|
}
|
2018-11-04 23:47:10 +01:00
|
|
|
}
|
|
|
|
|
2018-12-22 00:48:43 +11:00
|
|
|
|
2018-11-04 23:47:10 +01:00
|
|
|
int housingIndex;
|
2018-12-02 15:32:22 +11:00
|
|
|
if( m_territoryTypeId == 339 )
|
2018-11-04 23:47:10 +01:00
|
|
|
housingIndex = 0;
|
2018-12-02 15:32:22 +11:00
|
|
|
else if( m_territoryTypeId == 340 )
|
2018-11-04 23:47:10 +01:00
|
|
|
housingIndex = 1;
|
2018-12-02 15:32:22 +11:00
|
|
|
else if( m_territoryTypeId == 341 )
|
2018-11-04 23:47:10 +01:00
|
|
|
housingIndex = 2;
|
2018-12-02 15:32:22 +11:00
|
|
|
else if( m_territoryTypeId == 641 )
|
2018-11-04 23:47:10 +01:00
|
|
|
housingIndex = 3;
|
|
|
|
|
2018-12-29 00:53:52 +01:00
|
|
|
auto pExdData = m_pFw->get< Data::ExdDataGenerated >();
|
2018-11-29 16:55:48 +01:00
|
|
|
auto info = pExdData->get< Sapphire::Data::HousingLandSet >( housingIndex );
|
2018-11-04 23:47:10 +01:00
|
|
|
|
2018-12-26 00:43:27 +11:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2018-12-26 22:39:00 +11:00
|
|
|
// zero out the yard obj arrays so we don't leak memory like SE does :^)
|
2018-12-27 22:28:31 +11:00
|
|
|
Common::HousingObject obj {};
|
|
|
|
memset( &obj, 0x0, sizeof( Common::HousingObject ) );
|
2018-12-26 22:39:00 +11:00
|
|
|
|
|
|
|
for( auto& arr : m_yardObjects )
|
|
|
|
{
|
|
|
|
arr.fill( obj );
|
|
|
|
}
|
2018-12-26 00:43:27 +11:00
|
|
|
|
2018-12-29 13:05:13 +11:00
|
|
|
auto housingMgr = m_pFw->get< World::Manager::HousingMgr >();
|
2018-12-22 12:00:03 +11:00
|
|
|
auto landCache = housingMgr->getLandCacheMap();
|
2018-12-22 00:48:43 +11:00
|
|
|
|
2018-12-22 12:00:03 +11:00
|
|
|
// make sure the landset exists
|
|
|
|
auto landSetCache = landCache.find( m_landSetId );
|
|
|
|
if( landSetCache == landCache.end() )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-01-04 22:37:01 +11:00
|
|
|
Logger::fatal( "LandSet {0} is missing from the land cache.", m_landSetId );
|
2018-12-22 12:00:03 +11:00
|
|
|
return false;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-12-22 12:00:03 +11:00
|
|
|
// init the lands
|
2018-12-22 14:35:42 +11:00
|
|
|
for( HousingMgr::LandCacheEntry& entry : landSetCache->second )
|
2018-12-22 00:48:43 +11:00
|
|
|
{
|
2018-12-29 12:43:03 +11:00
|
|
|
auto land = make_Land( m_territoryTypeId, getWardNum(), entry.m_landId, m_landSetId, info, m_pFw );
|
2018-12-22 14:35:42 +11:00
|
|
|
|
|
|
|
// setup house
|
|
|
|
if( entry.m_houseId )
|
|
|
|
{
|
2018-12-26 00:43:27 +11:00
|
|
|
auto house = make_House( entry.m_houseId, m_landSetId, land->getLandIdent(), entry.m_estateName,
|
2018-12-29 13:05:13 +11:00
|
|
|
entry.m_estateComment, m_pFw );
|
2018-12-22 15:58:54 +11:00
|
|
|
|
2018-12-23 19:13:30 +11:00
|
|
|
housingMgr->updateHouseModels( house );
|
2018-12-22 15:58:54 +11:00
|
|
|
land->setHouse( house );
|
2018-12-22 14:35:42 +11:00
|
|
|
}
|
|
|
|
|
2018-12-22 12:00:03 +11:00
|
|
|
land->init( entry.m_type, entry.m_size, entry.m_status, entry.m_currentPrice, entry.m_ownerId, entry.m_houseId );
|
2018-12-22 00:48:43 +11:00
|
|
|
|
2018-12-22 12:00:03 +11:00
|
|
|
m_landPtrMap[ entry.m_landId ] = land;
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-12-22 12:00:03 +11:00
|
|
|
if( entry.m_houseId > 0 )
|
2018-12-25 23:43:39 +11:00
|
|
|
registerEstateEntranceEObj( entry.m_landId );
|
2018-12-26 00:43:27 +11:00
|
|
|
|
2018-12-26 22:39:00 +11:00
|
|
|
updateYardObjects( land->getLandIdent() );
|
2018-12-22 00:48:43 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2018-07-15 23:59:15 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player )
|
2018-07-15 23:59:15 +02:00
|
|
|
{
|
2019-07-21 22:33:33 +10:00
|
|
|
Logger::debug( "HousingZone::onPlayerZoneIn: Territory#{0}|{1}, Entity#{2}",
|
2019-01-04 22:37:01 +11:00
|
|
|
getGuId(), getTerritoryTypeId(), player.getId() );
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-12-25 23:43:39 +11:00
|
|
|
auto isInSubdivision = isPlayerSubInstance( player ) ? true : false;
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint32_t yardPacketNum;
|
|
|
|
uint32_t yardPacketTotal = 8;
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-11-04 23:47:10 +01:00
|
|
|
sendLandSet( player );
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-11-01 00:18:19 +01:00
|
|
|
for( yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto housingObjectInit = makeZonePacket< FFXIVIpcHousingObjectInitialize >( player.getId() );
|
2018-12-22 15:58:54 +11:00
|
|
|
memset( &housingObjectInit->data().landIdent, 0xFF, sizeof( Common::LandIdent ) );
|
|
|
|
housingObjectInit->data().u1 = 0xFF;
|
|
|
|
housingObjectInit->data().packetNum = yardPacketNum;
|
|
|
|
housingObjectInit->data().packetTotal = yardPacketTotal;
|
2018-11-01 00:18:19 +01:00
|
|
|
|
2018-12-27 22:28:31 +11:00
|
|
|
auto yardObjectSize = sizeof( Common::HousingObject );
|
2018-12-25 23:43:39 +11:00
|
|
|
|
|
|
|
auto& objects = m_yardObjects[ isInSubdivision ? 1 : 0 ];
|
|
|
|
|
2018-12-26 01:08:54 +11:00
|
|
|
memcpy( &housingObjectInit->data().object, objects.data() + ( yardPacketNum * 100 ), yardObjectSize * 100 );
|
2018-11-01 00:18:19 +01:00
|
|
|
|
2018-12-22 15:58:54 +11:00
|
|
|
player.queuePacket( housingObjectInit );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
auto landSetMap = makeZonePacket< FFXIVIpcLandSetMap >( player.getId() );
|
2018-12-25 23:43:39 +11:00
|
|
|
landSetMap->data().subdivision = isInSubdivision ? 1 : 2;
|
|
|
|
|
|
|
|
uint8_t startIndex = isInSubdivision ? 30 : 0;
|
|
|
|
|
2018-11-06 23:25:37 +01:00
|
|
|
for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); i++, count++ )
|
|
|
|
{
|
|
|
|
landSetMap->data().landInfo[ count ].status = 1;
|
|
|
|
}
|
2018-11-10 19:00:13 +01:00
|
|
|
|
2018-11-19 09:40:44 +01:00
|
|
|
player.queuePacket( landSetMap );
|
2018-11-06 23:25:37 +01:00
|
|
|
|
2018-11-01 00:18:19 +01:00
|
|
|
}
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::HousingZone::sendLandSet( Entity::Player& player )
|
2018-11-01 00:18:19 +01:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto landsetInitializePacket = makeZonePacket< FFXIVIpcLandSetInitialize >( player.getId() );
|
2018-07-16 12:37:04 +02:00
|
|
|
|
2018-11-26 23:15:42 +01:00
|
|
|
landsetInitializePacket->data().landIdent.wardNum = m_wardNum;
|
|
|
|
//landsetInitializePacket->data().landIdent.landSetId = m_landSetId;
|
|
|
|
landsetInitializePacket->data().landIdent.territoryTypeId = m_territoryTypeId;
|
2018-11-01 00:18:19 +01:00
|
|
|
//TODO: get current WorldId
|
2018-11-26 23:15:42 +01:00
|
|
|
landsetInitializePacket->data().landIdent.worldId = 67;
|
2018-12-22 15:58:54 +11:00
|
|
|
landsetInitializePacket->data().subInstance = !isPlayerSubInstance( player ) ? 1 : 2;
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-12-22 15:58:54 +11:00
|
|
|
uint8_t startIndex = !isPlayerSubInstance( player ) ? 0 : 30;
|
2018-11-04 23:47:10 +01:00
|
|
|
|
2018-11-14 09:22:17 +01:00
|
|
|
for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); ++i, ++count )
|
2018-11-01 00:18:19 +01:00
|
|
|
{
|
2018-11-15 12:40:02 +01:00
|
|
|
auto pLand = getLand( i );
|
2018-11-26 17:56:29 +11:00
|
|
|
|
|
|
|
// todo: move this and sendLandUpdate building logic to its own function
|
|
|
|
auto& landData = landsetInitializePacket->data().land[ count ];
|
|
|
|
|
|
|
|
landData.plotSize = pLand->getSize();
|
2018-12-31 21:54:32 +11:00
|
|
|
landData.houseState = pLand->getStatus();
|
2018-11-26 17:56:29 +11:00
|
|
|
landData.iconAddIcon = pLand->getSharing();
|
|
|
|
landData.fcId = pLand->getFcId();
|
|
|
|
landData.fcIcon = pLand->getFcIcon();
|
|
|
|
landData.fcIconColor = pLand->getFcColor();
|
|
|
|
|
|
|
|
if( auto house = pLand->getHouse() )
|
|
|
|
{
|
2018-11-30 22:52:08 +11:00
|
|
|
landData.flags = 1;
|
|
|
|
|
2018-12-22 15:58:54 +11:00
|
|
|
auto& parts = house->getHouseModels();
|
2018-11-26 17:56:29 +11:00
|
|
|
|
|
|
|
for( auto i = 0; i != parts.size(); i++ )
|
|
|
|
{
|
2018-11-26 23:32:22 +11:00
|
|
|
landData.housePart[ i ] = parts[ i ].first;
|
|
|
|
landData.houseColour[ i ] = parts[ i ].second;
|
2018-11-26 17:56:29 +11:00
|
|
|
}
|
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2018-07-15 23:59:15 +02:00
|
|
|
|
2018-11-01 00:18:19 +01:00
|
|
|
player.queuePacket( landsetInitializePacket );
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::HousingZone::sendLandUpdate( uint8_t landId )
|
2018-11-07 11:56:49 +01:00
|
|
|
{
|
2018-11-15 22:30:59 +01:00
|
|
|
auto pLand = getLand( landId );
|
2018-11-07 11:56:49 +01:00
|
|
|
for( const auto& playerIt : m_playerMap )
|
|
|
|
{
|
|
|
|
auto pPlayer = playerIt.second;
|
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
auto landUpdatePacket = makeZonePacket< FFXIVIpcLandUpdate >( pPlayer->getId() );
|
2018-11-26 23:15:42 +01:00
|
|
|
landUpdatePacket->data().landIdent.landId = landId;
|
2018-11-26 17:56:29 +11:00
|
|
|
|
|
|
|
auto& landData = landUpdatePacket->data().land;
|
|
|
|
|
|
|
|
landData.plotSize = pLand->getSize();
|
2018-12-31 21:54:32 +11:00
|
|
|
landData.houseState = pLand->getStatus();
|
2018-11-26 17:56:29 +11:00
|
|
|
landData.iconAddIcon = pLand->getSharing();
|
|
|
|
landData.fcId = pLand->getFcId();
|
|
|
|
landData.fcIcon = pLand->getFcIcon();
|
|
|
|
landData.fcIconColor = pLand->getFcColor();
|
|
|
|
|
2018-11-07 11:56:49 +01:00
|
|
|
|
2018-11-25 01:55:53 +11:00
|
|
|
if( auto house = pLand->getHouse() )
|
|
|
|
{
|
2018-11-30 22:52:08 +11:00
|
|
|
landData.flags = 1;
|
|
|
|
|
2018-12-22 15:58:54 +11:00
|
|
|
auto& parts = house->getHouseModels();
|
2018-11-26 17:56:29 +11:00
|
|
|
|
|
|
|
for( auto i = 0; i != parts.size(); i++ )
|
2018-11-25 01:55:53 +11:00
|
|
|
{
|
2018-11-26 23:32:22 +11:00
|
|
|
landData.housePart[ i ] = parts[ i ].first;
|
|
|
|
landData.houseColour[ i ] = parts[ i ].second;
|
2018-11-25 01:55:53 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-07 11:56:49 +01:00
|
|
|
pPlayer->queuePacket( landUpdatePacket );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
bool Sapphire::HousingZone::isPlayerSubInstance( Entity::Player& player )
|
2018-11-01 00:18:19 +01:00
|
|
|
{
|
|
|
|
return player.getPos().x < -15000.0f; //ToDo: get correct pos
|
|
|
|
}
|
|
|
|
|
2019-04-04 23:29:52 +02:00
|
|
|
void Sapphire::HousingZone::onUpdate( uint64_t tickCount )
|
2018-11-01 00:18:19 +01:00
|
|
|
{
|
2018-11-15 12:40:02 +01:00
|
|
|
for( auto pLandItr : m_landPtrMap )
|
2018-11-01 00:18:19 +01:00
|
|
|
{
|
2019-04-04 23:29:52 +02:00
|
|
|
pLandItr.second->update( tickCount );
|
2018-11-01 00:18:19 +01:00
|
|
|
}
|
2018-07-15 23:59:15 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
uint8_t Sapphire::HousingZone::getWardNum() const
|
2018-11-04 23:47:10 +01:00
|
|
|
{
|
|
|
|
return m_wardNum;
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
uint32_t Sapphire::HousingZone::getLandSetId() const
|
2018-07-15 23:59:15 +02:00
|
|
|
{
|
2018-11-01 23:56:43 +01:00
|
|
|
return m_landSetId;
|
2018-07-15 23:59:15 +02:00
|
|
|
}
|
2018-11-01 00:18:19 +01:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
Sapphire::LandPtr Sapphire::HousingZone::getLand( uint8_t id )
|
2018-11-01 00:18:19 +01:00
|
|
|
{
|
2018-11-01 23:56:43 +01:00
|
|
|
auto it = m_landPtrMap.find( id );
|
|
|
|
if( it == m_landPtrMap.end() )
|
2018-11-01 00:18:19 +01:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return it->second;
|
2018-12-07 20:36:52 +11:00
|
|
|
}
|
|
|
|
|
2018-12-25 23:43:39 +11:00
|
|
|
Sapphire::Entity::EventObjectPtr Sapphire::HousingZone::registerEstateEntranceEObj( uint8_t landId )
|
2018-12-07 20:36:52 +11:00
|
|
|
{
|
2018-12-25 23:43:39 +11:00
|
|
|
auto land = getLand( landId );
|
2018-12-07 20:36:52 +11:00
|
|
|
assert( land );
|
|
|
|
|
|
|
|
auto eObj = Entity::make_EventObject( getNextEObjId(), 2002737, 0, 4, land->getMapMarkerPosition(), 0.f, "entrance" );
|
2018-12-25 23:43:39 +11:00
|
|
|
eObj->setHousingLink( landId << 8 );
|
2018-12-07 20:36:52 +11:00
|
|
|
eObj->setScale( 1.f );
|
|
|
|
|
|
|
|
registerEObj( eObj );
|
|
|
|
|
|
|
|
return eObj;
|
2018-12-26 00:43:27 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::HousingZone::updateYardObjects( Sapphire::Common::LandIdent ident )
|
|
|
|
{
|
2018-12-29 13:05:13 +11:00
|
|
|
auto housingMgr = m_pFw->get< World::Manager::HousingMgr >();
|
2018-12-26 00:43:27 +11:00
|
|
|
auto& landStorage = housingMgr->getEstateInventory( ident );
|
|
|
|
|
|
|
|
auto yardContainer = landStorage[ InventoryType::HousingExteriorPlacedItems ];
|
|
|
|
|
2018-12-26 22:39:00 +11:00
|
|
|
auto arrayBounds = m_yardObjectArrayBounds[ ident.landId ];
|
|
|
|
auto yardMapIndex = ident.landId <= 29 ? 0 : 1;
|
|
|
|
|
2018-12-26 00:43:27 +11:00
|
|
|
for( const auto& item : yardContainer->getItemMap() )
|
|
|
|
{
|
2018-12-26 22:39:00 +11:00
|
|
|
auto housingItem = std::dynamic_pointer_cast< Inventory::HousingItem >( item.second );
|
|
|
|
assert( housingItem );
|
2018-12-26 00:43:27 +11:00
|
|
|
|
2018-12-26 22:39:00 +11:00
|
|
|
auto idx = item.first + arrayBounds.first;
|
|
|
|
m_yardObjects[ yardMapIndex ][ idx ] = housingMgr->getYardObjectForItem( housingItem );
|
2018-12-26 00:43:27 +11:00
|
|
|
}
|
2018-12-26 18:11:18 +11:00
|
|
|
}
|
|
|
|
|
2018-12-27 22:28:31 +11:00
|
|
|
void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, Inventory::HousingItem& item )
|
2018-12-26 18:11:18 +11:00
|
|
|
{
|
|
|
|
auto bounds = m_yardObjectArrayBounds[ landId ];
|
|
|
|
auto offset = bounds.first + slotId;
|
|
|
|
|
2018-12-27 22:28:31 +11:00
|
|
|
Common::HousingObject obj {};
|
2018-12-26 18:11:18 +11:00
|
|
|
|
2018-12-27 22:28:31 +11:00
|
|
|
obj.itemId = item.getAdditionalData();
|
2019-01-10 20:38:27 +11:00
|
|
|
obj.rotation = item.getRot();
|
2018-12-26 18:11:18 +11:00
|
|
|
|
2018-12-27 22:28:31 +11:00
|
|
|
obj.pos = item.getPos();
|
2018-12-26 18:11:18 +11:00
|
|
|
|
|
|
|
// link obj
|
2018-12-26 19:22:30 +11:00
|
|
|
auto yardMapIndex = landId <= 29 ? 0 : 1;
|
2018-12-26 18:11:18 +11:00
|
|
|
m_yardObjects[ yardMapIndex ][ offset ] = obj;
|
|
|
|
|
|
|
|
// spawn obj in zone
|
|
|
|
for( const auto& player : m_playerMap )
|
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto packet = makeZonePacket< Server::FFXIVIpcYardObjectSpawn >( player.second->getId() );
|
2018-12-26 18:11:18 +11:00
|
|
|
|
2018-12-26 22:39:00 +11:00
|
|
|
packet->data().landId = landId;
|
2018-12-26 19:22:30 +11:00
|
|
|
packet->data().objectArray = static_cast< uint8_t >( slotId );
|
2018-12-26 18:11:18 +11:00
|
|
|
packet->data().object = obj;
|
|
|
|
|
2018-12-27 22:28:31 +11:00
|
|
|
player.second->queuePacket( packet );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-27 23:48:55 +11:00
|
|
|
void Sapphire::HousingZone::updateYardObjectPos( Entity::Player& sourcePlayer, uint16_t slot, uint16_t landId,
|
|
|
|
Inventory::HousingItem& item )
|
2018-12-27 22:28:31 +11:00
|
|
|
{
|
|
|
|
auto bounds = m_yardObjectArrayBounds[ landId ];
|
|
|
|
auto offset = bounds.first + slot;
|
|
|
|
auto yardMapIndex = landId <= 29 ? 0 : 1;
|
|
|
|
|
|
|
|
auto& obj = m_yardObjects[ yardMapIndex ][ offset ];
|
|
|
|
|
2019-01-10 20:38:27 +11:00
|
|
|
obj.rotation = item.getRot();
|
2018-12-27 22:28:31 +11:00
|
|
|
obj.pos = item.getPos();
|
|
|
|
|
|
|
|
for( const auto& player : m_playerMap )
|
|
|
|
{
|
2018-12-27 23:48:55 +11:00
|
|
|
// don't send it from the origin player, it already has the position from the move request
|
|
|
|
if( player.second->getId() == sourcePlayer.getId() )
|
|
|
|
continue;
|
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
auto packet = makeZonePacket< Server::FFXIVIpcHousingObjectMove >( player.second->getId() );
|
2018-12-27 22:28:31 +11:00
|
|
|
|
|
|
|
packet->data().itemRotation = item.getRot();
|
|
|
|
packet->data().pos = item.getPos();
|
|
|
|
|
|
|
|
packet->data().landId = landId;
|
|
|
|
packet->data().objectArray = slot;
|
|
|
|
|
2018-12-26 18:11:18 +11:00
|
|
|
player.second->queuePacket( packet );
|
|
|
|
}
|
2018-12-28 11:49:12 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
2019-03-08 15:34:38 +01:00
|
|
|
}
|