1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-26 14:37:44 +00:00
sapphire/src/world/Territory/HousingZone.cpp

389 lines
11 KiB
C++
Raw Normal View History

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>
2018-07-15 23:59:15 +02:00
#include <Network/GamePacketNew.h>
#include <Network/PacketDef/Zone/ServerZoneDef.h>
#include "Actor/Player.h"
2018-11-01 00:18:19 +01:00
#include "Actor/Actor.h"
#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"
#include "Manager/HousingMgr.h"
2018-07-15 23:59:15 +02:00
#include "Framework.h"
extern Sapphire::Framework g_fw;
2018-07-15 23:59:15 +02:00
using namespace Sapphire::Common;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::Server;
using namespace Sapphire::World::Manager;
2018-07-15 23:59:15 +02:00
Sapphire::HousingZone::HousingZone( uint8_t wardNum,
uint16_t territoryTypeId,
2018-07-16 11:58:25 +02:00
uint32_t guId,
const std::string& internalName,
2018-07-16 12:37:04 +02:00
const std::string& contentName ) :
Zone( territoryTypeId, guId, internalName, contentName ),
2018-11-04 23:47:10 +01:00
m_wardNum( wardNum ),
m_territoryTypeId( territoryTypeId ),
m_landSetId( ( static_cast< uint32_t >( territoryTypeId ) << 16 ) | wardNum )
2018-07-15 23:59:15 +02:00
{
}
bool Sapphire::HousingZone::init()
2018-07-15 23:59:15 +02:00
{
2018-11-04 23:47:10 +01:00
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
{
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-26 00:43:27 +11:00
uint32_t housingIndex = 0;
if( m_territoryTypeId == 339 )
2018-11-04 23:47:10 +01:00
housingIndex = 0;
else if( m_territoryTypeId == 340 )
2018-11-04 23:47:10 +01:00
housingIndex = 1;
else if( m_territoryTypeId == 341 )
2018-11-04 23:47:10 +01:00
housingIndex = 2;
else if( m_territoryTypeId == 641 )
2018-11-04 23:47:10 +01:00
housingIndex = 3;
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
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;
}
auto housingMgr = g_fw.get< World::Manager::HousingMgr >();
auto landCache = housingMgr->getLandCacheMap();
// make sure the landset exists
auto landSetCache = landCache.find( m_landSetId );
if( landSetCache == landCache.end() )
{
g_fw.get< Sapphire::Logger >()->fatal( "LandSet " + std::to_string( m_landSetId ) + " is missing from the land cache." );
return false;
}
2018-07-15 23:59:15 +02:00
// init the lands
for( HousingMgr::LandCacheEntry& entry : landSetCache->second )
{
auto land = make_Land( m_territoryTypeId, getWardNum(), entry.m_landId, m_landSetId, info );
// 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,
entry.m_estateComment );
2018-12-22 15:58:54 +11:00
housingMgr->updateHouseModels( house );
2018-12-22 15:58:54 +11:00
land->setHouse( house );
}
land->init( entry.m_type, entry.m_size, entry.m_status, entry.m_currentPrice, entry.m_ownerId, entry.m_houseId );
m_landPtrMap[ entry.m_landId ] = land;
2018-07-15 23:59:15 +02: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
// add items to yard object array
auto& inventory = housingMgr->getEstateInventory( land->getLandIdent() );
auto& externalContainer = inventory[ InventoryType::HousingExteriorPlacedItems ];
auto arrayBounds = m_yardObjectArrayBounds[ entry.m_landId ];
uint8_t yardMapIndex = entry.m_landId <= 29 ? 0 : 1;
for( auto& item : externalContainer->getItemMap() )
{
Common::YardObject obj{};
auto housingItem = std::dynamic_pointer_cast< Inventory::HousingItem >( item.second );
assert( housingItem );
auto pos = housingItem->getPos();
obj.itemId = housingItem->getAdditionalData();
obj.itemRotation = housingItem->getRot();
obj.pos_x = Util::floatToUInt16( pos.x );
obj.pos_y = Util::floatToUInt16( pos.y );
obj.pos_z = Util::floatToUInt16( pos.z );
2018-12-26 01:05:28 +11:00
auto idx = item.first + arrayBounds.first;
m_yardObjects[ yardMapIndex ][ idx ] = obj;
2018-12-26 00:43:27 +11:00
}
}
return true;
2018-07-15 23:59:15 +02:00
}
Sapphire::HousingZone::~HousingZone() = default;
void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player )
2018-07-15 23:59:15 +02:00
{
auto pLog = g_fw.get< Logger >();
2018-11-05 23:39:08 +01:00
pLog->debug(
"HousingZone::onPlayerZoneIn: Zone#" + std::to_string( getGuId() ) + "|" + std::to_string( getTerritoryTypeId() ) +
", Entity#" + std::to_string( player.getId() ) );
2018-07-15 23:59:15 +02:00
2018-12-25 23:43:39 +11:00
auto isInSubdivision = isPlayerSubInstance( player ) ? true : false;
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-12-22 15:58:54 +11:00
auto housingObjectInit = makeZonePacket< FFXIVIpcHousingObjectInitialize >( player.getId() );
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-25 23:43:39 +11:00
auto yardObjectSize = sizeof( Common::YardObject );
auto& objects = m_yardObjects[ isInSubdivision ? 1 : 0 ];
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-07-15 23:59:15 +02: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;
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-01 00:18:19 +01:00
}
2018-07-15 23:59:15 +02:00
void Sapphire::HousingZone::sendLandSet( Entity::Player& player )
2018-11-01 00:18:19 +01:00
{
2018-11-01 23:56:43 +01: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
for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); ++i, ++count )
2018-11-01 00:18:19 +01:00
{
auto pLand = getLand( i );
// todo: move this and sendLandUpdate building logic to its own function
auto& landData = landsetInitializePacket->data().land[ count ];
landData.plotSize = pLand->getSize();
landData.houseState = pLand->getState();
landData.iconAddIcon = pLand->getSharing();
landData.fcId = pLand->getFcId();
landData.fcIcon = pLand->getFcIcon();
landData.fcIconColor = pLand->getFcColor();
if( auto house = pLand->getHouse() )
{
landData.flags = 1;
2018-12-22 15:58:54 +11:00
auto& parts = house->getHouseModels();
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-07-15 23:59:15 +02:00
2018-11-01 00:18:19 +01:00
player.queuePacket( landsetInitializePacket );
}
void Sapphire::HousingZone::sendLandUpdate( uint8_t landId )
2018-11-07 11:56:49 +01:00
{
auto pLand = getLand( landId );
2018-11-07 11:56:49 +01:00
for( const auto& playerIt : m_playerMap )
{
auto pPlayer = playerIt.second;
auto landUpdatePacket = makeZonePacket< FFXIVIpcLandUpdate >( pPlayer->getId() );
2018-11-26 23:15:42 +01:00
landUpdatePacket->data().landIdent.landId = landId;
auto& landData = landUpdatePacket->data().land;
landData.plotSize = pLand->getSize();
landData.houseState = pLand->getState();
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() )
{
landData.flags = 1;
2018-12-22 15:58:54 +11:00
auto& parts = house->getHouseModels();
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 );
}
}
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
}
void Sapphire::HousingZone::onUpdate( uint32_t currTime )
2018-11-01 00:18:19 +01:00
{
for( auto pLandItr : m_landPtrMap )
2018-11-01 00:18:19 +01:00
{
pLandItr.second->update( currTime );
2018-11-01 00:18:19 +01:00
}
2018-07-15 23:59:15 +02:00
}
uint8_t Sapphire::HousingZone::getWardNum() const
2018-11-04 23:47:10 +01:00
{
return m_wardNum;
}
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
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-25 23:43:39 +11:00
Sapphire::Entity::EventObjectPtr Sapphire::HousingZone::registerEstateEntranceEObj( uint8_t landId )
{
2018-12-25 23:43:39 +11:00
auto land = getLand( landId );
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 );
eObj->setScale( 1.f );
registerEObj( eObj );
return eObj;
2018-12-26 00:43:27 +11:00
}
void Sapphire::HousingZone::updateYardObjects( Sapphire::Common::LandIdent ident )
{
auto housingMgr = g_fw.get< World::Manager::HousingMgr >();
auto& landStorage = housingMgr->getEstateInventory( ident );
auto yardContainer = landStorage[ InventoryType::HousingExteriorPlacedItems ];
for( const auto& item : yardContainer->getItemMap() )
{
}
2018-12-26 18:11:18 +11:00
}
void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, Inventory::HousingItemPtr item )
{
auto bounds = m_yardObjectArrayBounds[ landId ];
auto offset = bounds.first + slotId;
Common::YardObject obj {};
obj.itemId = item->getAdditionalData();
obj.itemRotation = item->getRot();
auto pos = item->getPos();
obj.pos_x = Util::floatToUInt16( pos.x );
obj.pos_y = Util::floatToUInt16( pos.y );
obj.pos_z = Util::floatToUInt16( pos.z );
// link obj
uint8_t yardMapIndex = landId <= 29 ? 0 : 1;
m_yardObjects[ yardMapIndex ][ offset ] = obj;
// spawn obj in zone
for( const auto& player : m_playerMap )
{
auto packet = makeZonePacket< Server::FFXIVIpcYardObjectSpawn >( player.second->getId() );
packet->data().landSetId = landId;
packet->data().objectArray = slotId;
packet->data().object = obj;
player.second->queuePacket( packet );
}
}