2018-03-06 22:22:19 +01:00
|
|
|
#include <Common.h>
|
2019-02-06 11:12:29 +01:00
|
|
|
#include <Vector3.cpp>
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Network/CommonNetwork.h>
|
2019-03-08 15:34:38 +01:00
|
|
|
#include <Network/GamePacket.h>
|
2018-06-23 21:38:04 +02:00
|
|
|
#include <Network/CommonActorControl.h>
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Logging/Logger.h>
|
|
|
|
#include <Network/PacketContainer.h>
|
|
|
|
#include <Network/PacketDef/Chat/ServerChatDef.h>
|
|
|
|
#include <Database/DatabaseDef.h>
|
2018-07-07 00:10:16 +02:00
|
|
|
#include <Util/Util.h>
|
2018-03-09 10:19:38 +01:00
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
#include <datReader/DatCategories/bg/LgbTypes.h>
|
2020-01-06 20:19:42 +11:00
|
|
|
#include <datReader/DatCategories/bg/lgb.h>
|
2019-10-21 23:24:26 +02:00
|
|
|
|
2018-02-28 10:26:03 +01:00
|
|
|
#include <unordered_map>
|
2018-07-06 23:36:50 +10:00
|
|
|
#include <Network/PacketDef/Zone/ClientZoneDef.h>
|
2018-07-07 00:10:16 +02:00
|
|
|
#include <Logging/Logger.h>
|
2020-02-29 22:30:10 +11:00
|
|
|
#include <Service.h>
|
2018-07-07 00:10:16 +02:00
|
|
|
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Network/GameConnection.h"
|
|
|
|
|
2019-07-21 22:33:33 +10:00
|
|
|
#include "Territory/Territory.h"
|
2018-12-01 00:27:16 +11:00
|
|
|
#include "Territory/HousingZone.h"
|
|
|
|
#include "Territory/Land.h"
|
|
|
|
#include "Territory/ZonePosition.h"
|
|
|
|
#include "Territory/House.h"
|
2019-10-21 23:24:26 +02:00
|
|
|
#include "Territory/InstanceObjectCache.h"
|
2017-12-08 15:38:25 +01:00
|
|
|
|
2019-06-20 14:48:24 +10:00
|
|
|
#include "Network/PacketWrappers/PlayerSetupPacket.h"
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Network/PacketWrappers/PingPacket.h"
|
|
|
|
#include "Network/PacketWrappers/MoveActorPacket.h"
|
|
|
|
#include "Network/PacketWrappers/ChatPacket.h"
|
|
|
|
#include "Network/PacketWrappers/ServerNoticePacket.h"
|
2019-10-09 18:14:53 +02:00
|
|
|
#include "Network/PacketWrappers/ActorControlPacket.h"
|
|
|
|
#include "Network/PacketWrappers/ActorControlSelfPacket.h"
|
|
|
|
#include "Network/PacketWrappers/ActorControlTargetPacket.h"
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Network/PacketWrappers/EventStartPacket.h"
|
|
|
|
#include "Network/PacketWrappers/EventFinishPacket.h"
|
|
|
|
#include "Network/PacketWrappers/PlayerStateFlagsPacket.h"
|
|
|
|
|
2018-12-22 22:25:03 +01:00
|
|
|
#include "Manager/DebugCommandMgr.h"
|
2018-12-23 03:53:08 +01:00
|
|
|
#include "Manager/EventMgr.h"
|
2018-12-31 23:20:36 +11:00
|
|
|
#include "Manager/MarketMgr.h"
|
2019-01-19 21:20:23 -02:00
|
|
|
#include "Manager/TerritoryMgr.h"
|
|
|
|
#include "Manager/HousingMgr.h"
|
|
|
|
#include "Manager/RNGMgr.h"
|
2018-03-02 07:22:25 -03:00
|
|
|
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Action/Action.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-03-02 07:22:25 -03:00
|
|
|
#include "Session.h"
|
2018-11-20 21:32:13 +01:00
|
|
|
#include "ServerMgr.h"
|
2018-03-02 07:22:25 -03:00
|
|
|
#include "Forwards.h"
|
2017-10-27 00:10:13 +02:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
using namespace Sapphire::Common;
|
|
|
|
using namespace Sapphire::Network::Packets;
|
|
|
|
using namespace Sapphire::Network::Packets::Server;
|
|
|
|
using namespace Sapphire::Network::ActorControl;
|
2018-12-01 00:27:16 +11:00
|
|
|
using namespace Sapphire::World::Manager;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::fcInfoReqHandler( const Sapphire::Network::Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
// TODO: use new packet struct for this
|
|
|
|
//GamePacketPtr pPe( new GamePacket( 0xDD, 0x78, player.getId(), player.getId() ) );
|
|
|
|
//pPe->setValAt< uint8_t >( 0x48, 0x01 );
|
|
|
|
//queueOutPacket( pPe );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::setSearchInfoHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcSetSearchInfo >( inPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-10-14 23:31:52 +11:00
|
|
|
const auto inval = packet.data().status1;
|
|
|
|
const auto inval1 = packet.data().status2;
|
|
|
|
const auto status = packet.data().status;
|
|
|
|
const auto selectRegion = packet.data().language;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
player.setSearchInfo( selectRegion, 0, packet.data().searchComment );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
player.setOnlineStatusMask( status );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( player.isNewAdventurer() && !( inval & 0x01000000 ) )
|
|
|
|
// mark player as not new adventurer anymore
|
|
|
|
player.setNewAdventurer( false );
|
|
|
|
else if( inval & 0x01000000 )
|
|
|
|
// mark player as new adventurer
|
|
|
|
player.setNewAdventurer( true );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
statusPacket->data().onlineStatusFlags = status;
|
|
|
|
queueOutPacket( statusPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
searchInfoPacket->data().onlineStatusFlags = status;
|
|
|
|
searchInfoPacket->data().selectRegion = player.getSearchSelectRegion();
|
|
|
|
strcpy( searchInfoPacket->data().searchMessage, player.getSearchMessage() );
|
|
|
|
queueOutPacket( searchInfoPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-10-09 18:42:25 +02:00
|
|
|
player.sendToInRangeSet( makeActorControl( player.getId(), SetStatusIcon,
|
|
|
|
static_cast< uint8_t >( player.getOnlineStatus() ) ), true );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::reqSearchInfoHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto searchInfoPacket = makeZonePacket< FFXIVIpcInitSearchInfo >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
searchInfoPacket->data().onlineStatusFlags = player.getOnlineStatusMask();
|
|
|
|
searchInfoPacket->data().selectRegion = player.getSearchSelectRegion();
|
|
|
|
strcpy( searchInfoPacket->data().searchMessage, player.getSearchMessage() );
|
|
|
|
queueOutPacket( searchInfoPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::reqExamineSearchCommentHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2018-09-10 14:34:24 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
auto targetId = *reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x10 ] );
|
2020-02-29 22:30:10 +11:00
|
|
|
auto& serverMgr = Common::Service< World::ServerMgr >::ref();
|
|
|
|
auto pSession = serverMgr.getSession( targetId );
|
2018-09-10 14:34:24 +01:00
|
|
|
|
2019-01-04 22:37:01 +11:00
|
|
|
Logger::debug( "reqExamineSearchCommentHandler: {0}", targetId );
|
2018-09-10 14:34:24 +01:00
|
|
|
|
|
|
|
if( pSession )
|
|
|
|
{
|
|
|
|
auto pPlayer = pSession->getPlayer();
|
|
|
|
|
|
|
|
if( pPlayer )
|
|
|
|
{
|
2018-09-25 01:24:50 +10:00
|
|
|
if( pPlayer->isActingAsGm() || pPlayer->getZoneId() != player.getZoneId() )
|
|
|
|
return;
|
2018-09-25 01:11:14 +10:00
|
|
|
|
2018-09-10 14:34:24 +01:00
|
|
|
// retail sends the requester's id as both (isForSelf)
|
2019-07-29 22:22:45 +10:00
|
|
|
auto searchInfoPacket = makeZonePacket< FFXIVIpcExamineSearchComment >( player.getId() );
|
2018-09-10 14:34:24 +01:00
|
|
|
searchInfoPacket->data().charId = targetId;
|
|
|
|
strcpy( searchInfoPacket->data().searchComment, pPlayer->getSearchMessage() );
|
|
|
|
player.queuePacket( searchInfoPacket );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::reqExamineFcInfo( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-09-10 14:34:24 +01:00
|
|
|
Entity::Player& player )
|
|
|
|
{
|
|
|
|
|
|
|
|
auto targetId = *reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x18 ] );
|
2020-02-29 22:30:10 +11:00
|
|
|
|
|
|
|
auto& serverMgr = Common::Service< World::ServerMgr >::ref();
|
|
|
|
auto pSession = serverMgr.getSession( targetId );
|
2018-09-10 14:34:24 +01:00
|
|
|
|
2019-01-04 22:37:01 +11:00
|
|
|
Logger::debug( "reqExamineFcInfo: {0}", targetId );
|
2018-09-10 14:34:24 +01:00
|
|
|
|
|
|
|
if( pSession )
|
|
|
|
{
|
|
|
|
auto pPlayer = pSession->getPlayer();
|
|
|
|
|
|
|
|
if( pPlayer )
|
|
|
|
{
|
2018-09-25 01:24:50 +10:00
|
|
|
if( pPlayer->isActingAsGm() || pPlayer->getZoneId() != player.getZoneId() )
|
|
|
|
return;
|
2018-09-25 01:11:14 +10:00
|
|
|
|
2018-09-10 14:34:24 +01:00
|
|
|
// retail sends the requester's id as both (isForSelf)
|
2019-07-29 22:22:45 +10:00
|
|
|
auto examineFcInfoPacket = makeZonePacket< FFXIVIpcExamineFreeCompanyInfo >( player.getId() );
|
2018-09-10 14:34:24 +01:00
|
|
|
examineFcInfoPacket->data().charId = targetId;
|
|
|
|
// todo: populate with fc info
|
|
|
|
|
|
|
|
player.queuePacket( examineFcInfoPacket );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::linkshellListHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto linkshellListPacket = makeZonePacket< FFXIVIpcLinkshellList >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
queueOutPacket( linkshellListPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::updatePositionHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
// if the player is marked for zoning we no longer want to update his pos
|
|
|
|
if( player.isMarkedForZoning() )
|
|
|
|
return;
|
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto updatePositionPacket = ZoneChannelPacket< Client::FFXIVIpcUpdatePosition >( inPacket );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-02-06 08:49:57 +01:00
|
|
|
bool bPosChanged = true;
|
|
|
|
if( updatePositionPacket.data().position == player.getPos() )
|
|
|
|
bPosChanged = false;
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-02-06 08:49:57 +01:00
|
|
|
//if( !bPosChanged && player.getRot() == updatePositionPacket.data().rotation )
|
|
|
|
//return;
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-02-06 08:49:57 +01:00
|
|
|
player.setRot( updatePositionPacket.data().rotation );
|
|
|
|
player.setPos( updatePositionPacket.data().position );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
if( ( player.getCurrentAction() != nullptr ) && bPosChanged )
|
2019-02-10 21:21:34 +11:00
|
|
|
player.getCurrentAction()->setInterrupted( Common::ActionInterruptType::RegularInterrupt );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
// if no one is in range, don't bother trying to send a position update
|
|
|
|
if( !player.hasInRangeActor() )
|
|
|
|
return;
|
|
|
|
|
2019-02-06 08:49:57 +01:00
|
|
|
auto clientAnimationType = updatePositionPacket.data().clientAnimationType;
|
|
|
|
auto animationState = updatePositionPacket.data().animationState;
|
|
|
|
auto animationType = updatePositionPacket.data().animationType;
|
|
|
|
auto headRotation = updatePositionPacket.data().headPosition;
|
2019-02-06 18:51:51 +01:00
|
|
|
uint8_t orgAnimationType = animationType;
|
2019-02-06 09:27:30 +01:00
|
|
|
uint8_t unknownRotation = 0;
|
2019-02-06 08:49:57 +01:00
|
|
|
uint16_t animationSpeed = MoveSpeed::Walk;
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-02-06 08:49:57 +01:00
|
|
|
animationType |= clientAnimationType;
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-02-06 09:38:31 +01:00
|
|
|
if( animationType & MoveType::Strafing )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-02-06 08:49:57 +01:00
|
|
|
if( animationType & MoveType::Walking )
|
|
|
|
headRotation = 0xFF;
|
|
|
|
else if( headRotation < 0x7F )
|
|
|
|
headRotation += 0x7F;
|
|
|
|
else if( headRotation > 0x7F )
|
|
|
|
headRotation -= 0x7F;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2019-02-06 08:49:57 +01:00
|
|
|
if( animationType == MoveType::Running )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-02-06 08:49:57 +01:00
|
|
|
headRotation = 0x7F;
|
|
|
|
animationSpeed = MoveSpeed::Run;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2019-02-06 09:27:30 +01:00
|
|
|
if( animationType & MoveType::Jumping )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-02-06 18:51:51 +01:00
|
|
|
if( animationState == MoveState::LeaveCollision )
|
|
|
|
{
|
|
|
|
if( orgAnimationType & clientAnimationType )
|
|
|
|
animationType += 0x10;
|
|
|
|
else
|
|
|
|
animationType += 0x04;
|
|
|
|
}
|
|
|
|
if( animationState == MoveState::StartFalling )
|
2019-02-06 08:49:57 +01:00
|
|
|
player.m_falling = true;
|
2019-02-06 18:51:51 +01:00
|
|
|
if( animationState == MoveState::EnterCollision )
|
|
|
|
{
|
|
|
|
animationType = 2;
|
|
|
|
player.m_falling = false;
|
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
|
2019-02-06 08:49:57 +01:00
|
|
|
if( player.m_falling )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-02-06 08:49:57 +01:00
|
|
|
animationType += 0x10;
|
2019-02-06 09:27:30 +01:00
|
|
|
unknownRotation = 0x7F;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-02-06 18:51:51 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint64_t currentTime = Util::getTimeMs();
|
2018-07-07 00:10:16 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
player.m_lastMoveTime = currentTime;
|
2019-02-06 08:49:57 +01:00
|
|
|
player.m_lastMoveflag = animationType;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-02-06 18:51:51 +01:00
|
|
|
auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, animationType, animationState, animationSpeed, unknownRotation );
|
|
|
|
player.sendToInRangeSet( movePacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
void
|
2020-03-01 01:00:57 +11:00
|
|
|
Sapphire::Network::GameConnection::reqEquipDisplayFlagsHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-10-05 20:24:58 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
player.setEquipDisplayFlags( inPacket.data[ 0x10 ] );
|
2018-05-17 20:46:11 +02:00
|
|
|
|
2019-01-05 12:32:10 +01:00
|
|
|
player.sendDebug( "EquipDisplayFlag CHANGE: {0}", player.getEquipDisplayFlags() );
|
2017-10-05 20:24:58 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::zoneLineHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcZoneLineHandler >( inPacket );
|
2018-10-14 23:31:52 +11:00
|
|
|
const auto zoneLineId = packet.data().zoneLineId;
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
|
|
|
|
auto& instanceObjectCache = Common::Service< InstanceObjectCache >::ref();
|
2019-10-21 23:24:26 +02:00
|
|
|
auto tInfo = player.getCurrentTerritory()->getTerritoryTypeInfo();
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pExitRange = instanceObjectCache.getExitRange( player.getTerritoryTypeId(), zoneLineId );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
Common::FFXIVARR_POSITION3 targetPos{};
|
|
|
|
uint32_t targetZone;
|
2019-10-27 08:26:48 +01:00
|
|
|
float rotation = 0.0f;
|
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
if( pExitRange )
|
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pPopRange = instanceObjectCache.getPopRange( pExitRange->data.destTerritoryType,
|
|
|
|
pExitRange->data.destInstanceObjectId );
|
2019-10-21 23:24:26 +02:00
|
|
|
if( pPopRange )
|
|
|
|
{
|
2019-10-22 22:34:34 +02:00
|
|
|
targetZone = pExitRange->data.destTerritoryType;
|
2019-10-28 22:18:23 +01:00
|
|
|
rotation = pPopRange->header.transform.rotation.y;
|
2019-10-21 23:24:26 +02:00
|
|
|
targetPos = Common::FFXIVARR_POSITION3 { pPopRange->header.transform.translation.x,
|
|
|
|
pPopRange->header.transform.translation.y,
|
|
|
|
pPopRange->header.transform.translation.z };
|
|
|
|
|
|
|
|
player.sendDebug( "ZoneLine #{0} found.", zoneLineId );
|
|
|
|
|
|
|
|
auto preparePacket = makeZonePacket< FFXIVIpcPrepareZoning >( player.getId() );
|
2019-10-22 22:34:34 +02:00
|
|
|
preparePacket->data().targetZone = pExitRange->data.destTerritoryType;
|
2019-10-21 23:24:26 +02:00
|
|
|
|
|
|
|
player.queuePacket( preparePacket );
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
player.sendDebug( "Walking ZoneLine#{0}", zoneLineId );
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
player.performZoning( targetZone, targetPos, rotation );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::discoveryHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& instanceObjectCache = Common::Service< InstanceObjectCache >::ref();
|
2019-10-21 23:24:26 +02:00
|
|
|
auto tInfo = player.getCurrentTerritory()->getTerritoryTypeInfo();
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcDiscoveryHandler >( inPacket );
|
2018-10-14 23:31:52 +11:00
|
|
|
const auto positionRef = packet.data().positionRef;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pRefInfo = instanceObjectCache.getMapRange( player.getTerritoryTypeId(), positionRef );
|
2018-03-09 10:19:38 +01:00
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
player.sendDebug( "Discovery ref pos id#{0}", positionRef );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-10-21 23:24:26 +02:00
|
|
|
if( pRefInfo )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-10-21 23:24:26 +02:00
|
|
|
auto discoveryPacket = makeZonePacket< FFXIVIpcDiscovery >( player.getId() );
|
|
|
|
discoveryPacket->data().mapId = tInfo->map;
|
2019-10-22 22:34:34 +02:00
|
|
|
discoveryPacket->data().mapPartId = pRefInfo->data.discoveryIndex;
|
2019-10-21 23:24:26 +02:00
|
|
|
player.queuePacket( discoveryPacket );
|
2019-10-22 22:34:34 +02:00
|
|
|
player.discover( tInfo->map, pRefInfo->data.discoveryIndex );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::playTimeHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto playTimePacket = makeZonePacket< FFXIVIpcPlayTime >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
playTimePacket->data().playTimeInMinutes = player.getPlayTime() / 60;
|
|
|
|
player.queuePacket( playTimePacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::initHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
// init handler means this is a login procedure
|
|
|
|
player.setIsLogin( true );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
player.sendZonePackets();
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::blackListHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
uint8_t count = inPacket.data[ 0x11 ];
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
auto blackListPacket = makeZonePacket< FFXIVIpcBlackList >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
blackListPacket->data().sequence = count;
|
|
|
|
// TODO: Fill with actual blacklist data
|
|
|
|
//blackListPacket.data().entry[0].contentId = 1;
|
|
|
|
//sprintf( blackListPacket.data().entry[0].name, "Test Test" );
|
|
|
|
queueOutPacket( blackListPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::pingHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcPingHandler >( inPacket );
|
2018-06-18 23:03:39 +02:00
|
|
|
|
2018-10-25 12:44:51 +11:00
|
|
|
queueOutPacket( std::make_shared< Server::PingPacket >( player, packet.data().timestamp ) );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-06-02 00:34:22 +10:00
|
|
|
player.setLastPing( Common::Util::getTimeSeconds() );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::finishLoadingHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-11-06 23:36:34 +01:00
|
|
|
player.sendQuestInfo();
|
2018-11-10 19:00:13 +01:00
|
|
|
|
|
|
|
// TODO: load and save this data instead of hardcoding
|
2019-07-29 22:22:45 +10:00
|
|
|
auto gcPacket = makeZonePacket< FFXIVGCAffiliation >( player.getId() );
|
2018-11-10 19:00:13 +01:00
|
|
|
gcPacket->data().gcId = player.getGc();
|
|
|
|
gcPacket->data().gcRank[ 0 ] = player.getGcRankArray()[ 0 ];
|
|
|
|
gcPacket->data().gcRank[ 1 ] = player.getGcRankArray()[ 1 ];
|
|
|
|
gcPacket->data().gcRank[ 2 ] = player.getGcRankArray()[ 2 ];
|
|
|
|
player.queuePacket( gcPacket );
|
|
|
|
|
2019-07-21 22:50:11 +10:00
|
|
|
player.getCurrentTerritory()->onFinishLoading( player );
|
2018-02-07 00:00:48 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// player is done zoning
|
|
|
|
player.setLoadingComplete( true );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// if this is a login event
|
|
|
|
if( player.isLogin() )
|
|
|
|
{
|
|
|
|
// fire the onLogin Event
|
|
|
|
player.onLogin();
|
|
|
|
player.setIsLogin( false );
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// spawn the player for himself
|
|
|
|
player.spawn( player.getAsPlayer() );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-04-24 19:24:04 +09:00
|
|
|
player.gaugeClear();
|
|
|
|
player.sendActorGauge();
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// notify the zone of a change in position to force an "inRangeActor" update
|
2019-07-21 22:50:11 +10:00
|
|
|
player.getCurrentTerritory()->updateActorPosition( player );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::socialListHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint8_t type = inPacket.data[ 0x1A ];
|
|
|
|
uint8_t count = inPacket.data[ 0x1B ];
|
|
|
|
|
2020-01-03 05:07:55 +09:00
|
|
|
if( type == 1 )
|
2018-08-29 21:40:59 +02:00
|
|
|
{ // party list
|
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
auto listPacket = makeZonePacket< FFXIVIpcSocialList >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-01-03 05:07:55 +09:00
|
|
|
listPacket->data().type = 1;
|
2018-08-29 21:40:59 +02:00
|
|
|
listPacket->data().sequence = count;
|
|
|
|
|
|
|
|
int32_t entrysizes = sizeof( listPacket->data().entries );
|
|
|
|
memset( listPacket->data().entries, 0, sizeof( listPacket->data().entries ) );
|
|
|
|
|
2019-07-21 22:50:11 +10:00
|
|
|
listPacket->data().entries[ 0 ].bytes[ 2 ] = player.getCurrentTerritory()->getTerritoryTypeId();
|
2018-08-29 21:40:59 +02:00
|
|
|
listPacket->data().entries[ 0 ].bytes[ 3 ] = 0x80;
|
|
|
|
listPacket->data().entries[ 0 ].bytes[ 4 ] = 0x02;
|
|
|
|
listPacket->data().entries[ 0 ].bytes[ 6 ] = 0x3B;
|
|
|
|
listPacket->data().entries[ 0 ].bytes[ 11 ] = 0x10;
|
|
|
|
listPacket->data().entries[ 0 ].classJob = static_cast< uint8_t >( player.getClass() );
|
|
|
|
listPacket->data().entries[ 0 ].contentId = player.getContentId();
|
|
|
|
listPacket->data().entries[ 0 ].level = player.getLevel();
|
2019-07-21 22:50:11 +10:00
|
|
|
listPacket->data().entries[ 0 ].zoneId = player.getCurrentTerritory()->getTerritoryTypeId();
|
2018-08-29 21:40:59 +02:00
|
|
|
listPacket->data().entries[ 0 ].zoneId1 = 0x0100;
|
|
|
|
// TODO: no idea what this does
|
|
|
|
//listPacket.data().entries[0].one = 1;
|
|
|
|
|
|
|
|
memcpy( listPacket->data().entries[ 0 ].name, player.getName().c_str(), strlen( player.getName().c_str() ) );
|
|
|
|
|
2020-01-03 05:07:55 +09:00
|
|
|
// GC icon
|
|
|
|
listPacket->data().entries[ 0 ].bytes1[ 0 ] = 2;
|
|
|
|
// client language J = 0, E = 1, D = 2, F = 3
|
|
|
|
listPacket->data().entries[ 0 ].bytes1[ 1 ] = 1;
|
|
|
|
// user language settings flag J = 1, E = 2, D = 4, F = 8
|
|
|
|
listPacket->data().entries[ 0 ].bytes1[ 2 ] = 1 + 2;
|
2018-08-29 21:40:59 +02:00
|
|
|
listPacket->data().entries[ 0 ].onlineStatusMask = player.getOnlineStatusMask();
|
|
|
|
|
|
|
|
queueOutPacket( listPacket );
|
|
|
|
|
|
|
|
}
|
2020-01-03 05:07:55 +09:00
|
|
|
else if( type == 2 )
|
2018-08-29 21:40:59 +02:00
|
|
|
{ // friend list
|
2019-07-29 22:22:45 +10:00
|
|
|
auto listPacket = makeZonePacket< FFXIVIpcSocialList >( player.getId() );
|
2020-01-03 05:07:55 +09:00
|
|
|
listPacket->data().type = 2;
|
2018-08-29 21:40:59 +02:00
|
|
|
listPacket->data().sequence = count;
|
|
|
|
memset( listPacket->data().entries, 0, sizeof( listPacket->data().entries ) );
|
|
|
|
|
|
|
|
}
|
|
|
|
else if( type == 0x0e )
|
|
|
|
{ // player search result
|
|
|
|
// TODO: implement player search
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::chatHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& debugCommandMgr = Common::Service< DebugCommandMgr >::ref();
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcChatHandler >( inPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( packet.data().message[ 0 ] == '!' )
|
|
|
|
{
|
|
|
|
// execute game console command
|
2020-03-01 01:00:57 +11:00
|
|
|
debugCommandMgr.execCommand( const_cast< char* >( packet.data().message ) + 1, player );
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto chatType = packet.data().chatType;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
//ToDo, need to implement sending GM chat types.
|
2018-10-25 12:44:51 +11:00
|
|
|
auto chatPacket = std::make_shared< Server::ChatPacket >( player, chatType, packet.data().message );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
switch( chatType )
|
|
|
|
{
|
|
|
|
case ChatType::Say:
|
|
|
|
{
|
|
|
|
if( player.isActingAsGm() )
|
|
|
|
chatPacket->data().chatType = ChatType::GMSay;
|
2018-04-18 21:00:20 +10:00
|
|
|
|
2019-07-21 22:50:11 +10:00
|
|
|
player.getCurrentTerritory()->queuePacketForRange( player, 50, chatPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
break;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
case ChatType::Yell:
|
|
|
|
{
|
2018-07-01 21:33:37 +10:00
|
|
|
if( player.isActingAsGm() )
|
2018-08-29 21:40:59 +02:00
|
|
|
chatPacket->data().chatType = ChatType::GMYell;
|
2018-04-18 21:00:20 +10:00
|
|
|
|
2019-07-21 22:50:11 +10:00
|
|
|
player.getCurrentTerritory()->queuePacketForRange( player, 6000, chatPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
break;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
case ChatType::Shout:
|
|
|
|
{
|
2018-07-01 21:33:37 +10:00
|
|
|
if( player.isActingAsGm() )
|
2018-08-29 21:40:59 +02:00
|
|
|
chatPacket->data().chatType = ChatType::GMShout;
|
2018-04-18 21:00:20 +10:00
|
|
|
|
2019-07-21 22:50:11 +10:00
|
|
|
player.getCurrentTerritory()->queuePacketForRange( player, 6000, chatPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
break;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2019-07-21 22:50:11 +10:00
|
|
|
player.getCurrentTerritory()->queuePacketForRange( player, 50, chatPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
break;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: this handler needs to be improved for timed logout, also the session should be instantly removed
|
|
|
|
// currently we wait for the session to just time out after logout, this can be a problem is the user tries to
|
|
|
|
// log right back in.
|
|
|
|
// Also the packet needs to be converted to an ipc structure
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::logoutHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto logoutPacket = makeZonePacket< FFXIVIpcLogout >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
logoutPacket->data().flags1 = 0x02;
|
|
|
|
logoutPacket->data().flags2 = 0x2000;
|
|
|
|
queueOutPacket( logoutPacket );
|
2017-11-14 23:55:38 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
player.setMarkedForRemoval();
|
2017-08-22 21:36:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::tellHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-08-22 21:36:20 +02:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcTellHandler >( inPacket );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-02-29 22:30:10 +11:00
|
|
|
auto& serverMgr = Common::Service< World::ServerMgr >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-02-29 22:30:10 +11:00
|
|
|
auto pSession = serverMgr.getSession( packet.data().targetPCName );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
if( !pSession )
|
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto tellErrPacket = makeZonePacket< FFXIVIpcTellErrNotFound >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
strcpy( tellErrPacket->data().receipientName, packet.data().targetPCName );
|
|
|
|
sendSinglePacket( tellErrPacket );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pTargetPlayer = pSession->getPlayer();
|
|
|
|
|
|
|
|
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BetweenAreas ) )
|
|
|
|
{
|
|
|
|
// send error for player between areas
|
|
|
|
// TODO: implement me
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-31 13:13:46 +11:00
|
|
|
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BoundByDuty ) && !player.isActingAsGm() )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
// send error for player bound by duty
|
|
|
|
// TODO: implement me
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-31 13:13:46 +11:00
|
|
|
if( pTargetPlayer->getOnlineStatus() == OnlineStatus::Busy && !player.isActingAsGm() )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
// send error for player being busy
|
|
|
|
// TODO: implement me ( i've seen this done with packet type 67 i think )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto tellPacket = makeChatPacket< FFXIVIpcTell >( player.getId() );
|
|
|
|
strcpy( tellPacket->data().msg, packet.data().message );
|
|
|
|
strcpy( tellPacket->data().receipientName, player.getName().c_str() );
|
2019-01-12 22:53:16 +01:00
|
|
|
// TODO: world id from server
|
|
|
|
tellPacket->data().contentId = player.getContentId();
|
|
|
|
tellPacket->data().worldId = 67;
|
2019-01-31 13:13:46 +11:00
|
|
|
|
2019-01-06 02:03:33 +01:00
|
|
|
if( player.isActingAsGm() )
|
|
|
|
{
|
2019-01-31 13:13:46 +11:00
|
|
|
tellPacket->data().flags |= TellFlags::GmTellMsg;
|
2019-01-06 02:03:33 +01:00
|
|
|
}
|
2017-08-22 21:36:20 +02:00
|
|
|
|
2019-01-31 13:13:46 +11:00
|
|
|
pTargetPlayer->queueChatPacket( tellPacket );
|
2017-09-23 00:45:30 +09:00
|
|
|
}
|
2017-11-22 00:29:42 +09:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::performNoteHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2017-11-22 00:29:42 +09:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
auto performPacket = makeZonePacket< FFXIVIpcPerformNote >( player.getId() );
|
2018-08-29 21:40:59 +02:00
|
|
|
memcpy( &performPacket->data().data[ 0 ], &inPacket.data[ 0x10 ], 32 );
|
|
|
|
player.sendToInRangeSet( performPacket );
|
2017-11-22 00:29:42 +09:00
|
|
|
}
|
2018-11-11 14:27:39 +01:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::landRenameHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2018-11-11 14:27:39 +01:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcRenameLandHandler >( inPacket );
|
2018-11-11 14:27:39 +01:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& housingMgr = Common::Service< HousingMgr >::ref();
|
2018-11-12 08:32:30 +01:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto landSetId = housingMgr.toLandSetId( packet.data().ident.territoryTypeId, packet.data().ident.wardNum );
|
2018-11-28 21:59:28 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto pZone = housingMgr.getHousingZoneByLandSetId( landSetId );
|
2018-11-28 21:59:28 +11:00
|
|
|
if( !pZone )
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto pLand = pZone->getLand( packet.data().ident.landId );
|
2018-11-12 08:32:30 +01:00
|
|
|
if( !pLand )
|
|
|
|
return;
|
|
|
|
|
2018-11-28 00:05:57 +11:00
|
|
|
// todo: check perms for fc houses and shit
|
2018-12-19 16:03:35 +11:00
|
|
|
if( pLand->getOwnerId() != player.getId() )
|
2018-11-28 00:05:57 +11:00
|
|
|
return;
|
|
|
|
|
|
|
|
auto pHouse = pLand->getHouse();
|
|
|
|
if( pHouse )
|
|
|
|
pHouse->setHouseName( packet.data().houseName );
|
|
|
|
|
|
|
|
// todo: this packet is weird, retail sends it with some unknown shit at the start but it doesn't seem to do anything
|
2019-07-29 22:22:45 +10:00
|
|
|
auto nameUpdatePacket = makeZonePacket< Server::FFXIVIpcLandUpdateHouseName >( player.getId() );
|
2018-11-28 00:05:57 +11:00
|
|
|
memcpy( &nameUpdatePacket->data().houseName, &packet.data().houseName, sizeof( packet.data().houseName ) );
|
|
|
|
|
|
|
|
// todo: who does this get sent to? just the person who renamed it?
|
|
|
|
player.queuePacket( nameUpdatePacket );
|
2018-11-12 08:32:30 +01:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::buildPresetHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2018-11-12 08:32:30 +01:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcBuildPresetHandler >( inPacket );
|
2018-11-12 08:32:30 +01:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& housingMgr = Common::Service< HousingMgr >::ref();
|
|
|
|
housingMgr.buildPresetEstate( player, packet.data().plotNum, packet.data().itemId );
|
2018-11-11 14:27:39 +01:00
|
|
|
}
|
2018-11-28 21:59:28 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::housingUpdateGreetingHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-11-29 16:55:48 +01:00
|
|
|
Entity::Player& player )
|
2018-11-28 21:59:28 +11:00
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcHousingUpdateHouseGreeting >( inPacket );
|
2018-11-28 21:59:28 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& housingMgr = Common::Service< HousingMgr >::ref();
|
2018-11-28 21:59:28 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
housingMgr.updateEstateGreeting( player, packet.data().ident, std::string( packet.data().greeting ) );
|
2018-11-28 21:59:28 +11:00
|
|
|
}
|
2018-12-26 18:11:18 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::reqPlaceHousingItem( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-12-26 18:11:18 +11:00
|
|
|
Entity::Player& player )
|
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& housingMgr = Common::Service< HousingMgr >::ref();
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcReqPlaceHousingItem >( inPacket );
|
2018-12-26 18:11:18 +11:00
|
|
|
const auto& data = packet.data();
|
|
|
|
|
2018-12-30 21:26:32 +11:00
|
|
|
if( data.shouldPlaceItem == 1 )
|
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
housingMgr.reqPlaceHousingItem( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId,
|
2018-12-30 21:26:32 +11:00
|
|
|
data.position, data.rotation );
|
|
|
|
}
|
|
|
|
else
|
2020-03-01 01:00:57 +11:00
|
|
|
housingMgr.reqPlaceItemInStore( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId );
|
2018-12-30 21:26:32 +11:00
|
|
|
|
2018-12-27 15:52:48 +11:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::reqMoveHousingItem( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-12-27 15:52:48 +11:00
|
|
|
Entity::Player& player )
|
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& housingMgr = Common::Service< HousingMgr >::ref();
|
2018-12-27 15:52:48 +11:00
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcHousingUpdateObjectPosition >( inPacket );
|
2018-12-27 15:52:48 +11:00
|
|
|
const auto& data = packet.data();
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
housingMgr.reqMoveHousingItem( player, data.ident, data.slot, data.pos, data.rotation );
|
2018-12-31 23:20:36 +11:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::marketBoardSearch( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2018-12-31 23:20:36 +11:00
|
|
|
Entity::Player& player )
|
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& marketMgr = Common::Service< MarketMgr >::ref();
|
2018-12-31 23:20:36 +11:00
|
|
|
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardSearch >( inPacket );
|
2018-12-31 23:20:36 +11:00
|
|
|
const auto& data = packet.data();
|
|
|
|
|
2019-01-01 11:51:48 +11:00
|
|
|
std::string_view searchStr( data.searchStr );
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
marketMgr.searchMarketboard( player, data.itemSearchCategory, data.maxEquipLevel, data.classJobId, data.searchStr,
|
2019-01-01 11:51:48 +11:00
|
|
|
data.requestId, data.startIdx );
|
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::marketBoardRequestItemInfo( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2019-01-01 11:51:48 +11:00
|
|
|
Entity::Player& player )
|
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListingInfo >( inPacket );
|
2019-01-01 11:51:48 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& marketMgr = Common::Service< MarketMgr >::ref();
|
2019-01-01 17:29:06 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
marketMgr.requestItemListingInfo( player, packet.data().catalogId, packet.data().requestId );
|
2019-01-01 17:29:06 +11:00
|
|
|
}
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
void Sapphire::Network::GameConnection::marketBoardRequestItemListings( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
2019-01-01 17:29:06 +11:00
|
|
|
Entity::Player& player )
|
|
|
|
{
|
2019-07-29 22:22:45 +10:00
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListings >( inPacket );
|
2019-01-01 17:29:06 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& marketMgr = Common::Service< MarketMgr >::ref();
|
2019-01-01 17:29:06 +11:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
marketMgr.requestItemListings( player, packet.data().itemCatalogId );
|
2019-03-08 15:34:38 +01:00
|
|
|
}
|
2020-06-15 08:34:10 +09:00
|
|
|
|
|
|
|
void Sapphire::Network::GameConnection::worldInteractionhandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
|
|
|
Entity::Player& player )
|
|
|
|
{
|
|
|
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcWorldInteractionHandler >( inPacket );
|
|
|
|
auto action = packet.data().action;
|
|
|
|
player.sendDebug( "WorldInteraction {}", action );
|
|
|
|
if( action == 0x1F5 )
|
|
|
|
{
|
|
|
|
auto emote = packet.data().param1;
|
|
|
|
if( emote == 0x32 || emote == 0x33 ) // "/sit"
|
|
|
|
{
|
|
|
|
auto param4 = packet.data().param4;
|
|
|
|
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
|
|
|
auto emoteData = exdData.get< Data::Emote >( emote );
|
|
|
|
|
|
|
|
if( !emoteData )
|
|
|
|
return;
|
|
|
|
|
|
|
|
player.setPos( packet.data().position );
|
|
|
|
if( emote == 0x32 && player.hasInRangeActor() )
|
|
|
|
{
|
|
|
|
auto setpos = makeZonePacket< FFXIVIpcActorSetPos >( player.getId() );
|
|
|
|
setpos->data().r16 = param4;
|
|
|
|
setpos->data().waitForLoad = 18;
|
|
|
|
setpos->data().unknown1 = emote == 0x32 ? 1 : 2;
|
|
|
|
setpos->data().x = packet.data().position.x;
|
|
|
|
setpos->data().y = packet.data().position.y;
|
|
|
|
setpos->data().z = packet.data().position.z;
|
|
|
|
player.sendToInRangeSet( setpos, false );
|
|
|
|
}
|
|
|
|
player.sendToInRangeSet( makeActorControlTarget( player.getId(), ActorControl::ActorControlType::Emote, emote, 0, 0, param4, 0xE0000000 ), true );
|
|
|
|
|
|
|
|
if( emote == 0x32 && emoteData->emoteMode != 0 )
|
|
|
|
{
|
|
|
|
player.setStance( Common::Stance::Passive );
|
|
|
|
player.setAutoattack( false );
|
|
|
|
player.setPersistentEmote( emoteData->emoteMode );
|
|
|
|
player.setStatus( Common::ActorStatus::EmoteMode );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( action == 0x1F8 )
|
|
|
|
{
|
|
|
|
if( player.getPersistentEmote() > 0 )
|
|
|
|
{
|
|
|
|
auto param2 = packet.data().param2;
|
|
|
|
|
|
|
|
player.setPos( packet.data().position );
|
|
|
|
if( player.hasInRangeActor() )
|
|
|
|
{
|
|
|
|
auto setpos = makeZonePacket< FFXIVIpcActorSetPos >( player.getId() );
|
|
|
|
setpos->data().r16 = param2;
|
|
|
|
setpos->data().waitForLoad = 18;
|
|
|
|
setpos->data().unknown1 = 2;
|
|
|
|
setpos->data().x = packet.data().position.x;
|
|
|
|
setpos->data().y = packet.data().position.y;
|
|
|
|
setpos->data().z = packet.data().position.z;
|
|
|
|
player.sendToInRangeSet( setpos, false );
|
|
|
|
}
|
|
|
|
|
|
|
|
player.setPersistentEmote( 0 );
|
|
|
|
player.emoteInterrupt();
|
|
|
|
player.setStatus( Common::ActorStatus::Idle );
|
|
|
|
auto pSetStatusPacket = makeActorControl( player.getId(), SetStatus, static_cast< uint8_t >( Common::ActorStatus::Idle ) );
|
|
|
|
player.sendToInRangeSet( pSetStatusPacket );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|