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

790 lines
29 KiB
C++
Raw Normal View History

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>
#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>
#include <Util/Util.h>
#include <datReader/DatCategories/bg/LgbTypes.h>
2020-01-06 20:19:42 +11:00
#include <datReader/DatCategories/bg/lgb.h>
#include <unordered_map>
#include <Network/PacketDef/Zone/ClientZoneDef.h>
#include <Logging/Logger.h>
2020-02-29 22:30:10 +11:00
#include <Service.h>
#include "Network/GameConnection.h"
2019-07-21 22:33:33 +10:00
#include "Territory/Territory.h"
#include "Territory/HousingZone.h"
#include "Territory/Land.h"
#include "Territory/ZonePosition.h"
#include "Territory/House.h"
#include "Territory/InstanceObjectCache.h"
#include "Linkshell/Linkshell.h"
#include "Network/PacketWrappers/PlayerSetupPacket.h"
#include "Network/PacketWrappers/PingPacket.h"
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/PacketWrappers/ChatPacket.h"
#include "Network/PacketWrappers/ServerNoticePacket.h"
#include "Network/PacketWrappers/ActorControlPacket.h"
#include "Network/PacketWrappers/ActorControlSelfPacket.h"
#include "Network/PacketWrappers/ActorControlTargetPacket.h"
#include "Network/PacketWrappers/EventStartPacket.h"
#include "Network/PacketWrappers/EventFinishPacket.h"
#include "Network/PacketWrappers/PlayerStateFlagsPacket.h"
#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"
#include "Manager/TerritoryMgr.h"
#include "Manager/HousingMgr.h"
#include "Manager/RNGMgr.h"
#include "Manager/ChatChannelMgr.h"
#include "Manager/QuestMgr.h"
#include "Manager/LinkshellMgr.h"
#include "Manager/PartyMgr.h"
#include "Manager/PlayerMgr.h"
#include "Action/Action.h"
2017-08-08 13:53:47 +02:00
#include "Session.h"
#include "WorldServer.h"
#include "Forwards.h"
2017-10-27 00:10:13 +02:00
using namespace Sapphire::Common;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::WorldPackets::Server;
using namespace Sapphire::Network::Packets::WorldPackets::Client;
using namespace Sapphire::Network::Packets::WorldPackets;
using namespace Sapphire::Network::ActorControl;
using namespace Sapphire::World::Manager;
2017-08-08 13:53:47 +02:00
void Sapphire::Network::GameConnection::setProfileHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
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
player.setOnlineStatusCustomMask( packet.data().OnlineStatus );
const auto status = player.getOnlineStatusCustomMask() | player.getOnlineStatusMask();
const auto selectRegion = packet.data().Region;
2017-08-08 13:53:47 +02:00
player.setSearchInfo( selectRegion, 0, packet.data().SearchComment );
2017-08-08 13:53:47 +02:00
if( player.isNewAdventurer() && !( status & ( static_cast< uint64_t >( 1 ) << static_cast< uint8_t >( OnlineStatus::NewAdventurer ) ) ) )
// mark player as not new adventurer anymore
player.setNewAdventurer( false );
else if( status & ( static_cast< uint64_t >( 1 ) << static_cast< uint8_t >( OnlineStatus::NewAdventurer ) ) )
// 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() );
statusPacket->data().onlineStatusFlags = status;
queueOutPacket( statusPacket );
2017-08-08 13:53:47 +02:00
auto searchInfoPacket = makeZonePacket< WorldPackets::Server::FFXIVIpcSetProfileResult >( player.getId() );
searchInfoPacket->data().OnlineStatus = status;
searchInfoPacket->data().Region = player.getSearchSelectRegion();
searchInfoPacket->data().SelectClassID = packet.data().SelectClassID;
searchInfoPacket->data().CurrentSelectClassID = packet.data().CurrentSelectClassID;
strcpy( searchInfoPacket->data().SearchComment, 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
}
void Sapphire::Network::GameConnection::getProfileHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto searchInfoPacket = makeZonePacket< FFXIVIpcGetProfileResult >( player.getId() );
searchInfoPacket->data().OnlineStatus = player.getOnlineStatusMask() | player.getOnlineStatusCustomMask();
searchInfoPacket->data().Region = player.getSearchSelectRegion();
strcpy( searchInfoPacket->data().SearchComment, player.getSearchMessage() );
queueOutPacket( searchInfoPacket );
2017-08-08 13:53:47 +02:00
}
void Sapphire::Network::GameConnection::getSearchCommentHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
auto targetId = *reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x10 ] );
auto& server = Common::Service< World::WorldServer >::ref();
auto pSession = server.getSession( targetId );
Logger::debug( "getSearchCommentHandler: {0}", targetId );
if( pSession )
{
auto pPlayer = pSession->getPlayer();
if( pPlayer )
{
2018-09-25 01:24:50 +10:00
if( pPlayer->isActingAsGm() || pPlayer->getZoneId() != player.getZoneId() )
return;
// retail sends the requester's id as both (isForSelf)
2019-07-29 22:22:45 +10:00
auto searchInfoPacket = makeZonePacket< FFXIVIpcExamineSearchComment >( player.getId() );
searchInfoPacket->data().charId = targetId;
strcpy( searchInfoPacket->data().searchComment, pPlayer->getSearchMessage() );
server.queueForPlayer( player.getCharacterId(), searchInfoPacket );
}
}
}
2020-03-01 01:00:57 +11:00
void Sapphire::Network::GameConnection::reqExamineFcInfo( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
auto targetId = *reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x18 ] );
2020-02-29 22:30:10 +11:00
auto& server = Common::Service< World::WorldServer >::ref();
auto pSession = server.getSession( targetId );
Logger::debug( "reqExamineFcInfo: {0}", targetId );
if( pSession )
{
auto pPlayer = pSession->getPlayer();
if( pPlayer )
{
2018-09-25 01:24:50 +10:00
if( pPlayer->isActingAsGm() || pPlayer->getZoneId() != player.getZoneId() )
return;
// retail sends the requester's id as both (isForSelf)
2019-07-29 22:22:45 +10:00
auto examineFcInfoPacket = makeZonePacket< FFXIVIpcExamineFreeCompanyInfo >( player.getId() );
examineFcInfoPacket->data().charId = targetId;
// todo: populate with fc info
server.queueForPlayer( player.getCharacterId(), examineFcInfoPacket );
}
}
}
2020-03-01 01:00:57 +11:00
void Sapphire::Network::GameConnection::linkshellListHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto linkshellListPacket = makeZonePacket< FFXIVIpcGetLinkshellListResult >( player.getId() );
auto& lsMgr = Common::Service< LinkshellMgr >::ref();
auto& ccMgr = Common::Service< ChatChannelMgr >::ref();
auto lsVec = lsMgr.getPlayerLinkshells( player );
for( int i = 0; i < lsVec.size(); ++i )
{
auto pLs = lsVec[ i ];
linkshellListPacket->data().LinkshellList[ i ].LinkshellID = pLs->getId();
linkshellListPacket->data().LinkshellList[ i ].ChannelID = pLs->getChatChannel();
linkshellListPacket->data().LinkshellList[ i ].HierarchyID = player.getId(); // unknown - possibly FC related
strcpy( linkshellListPacket->data().LinkshellList[ i ].LinkshellName, pLs->getName().c_str() );
}
queueOutPacket( linkshellListPacket );
2017-08-08 13:53:47 +02:00
}
void Sapphire::Network::GameConnection::linkshellJoinHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
const auto lsJoinPacket = ZoneChannelPacket< Client::FFXIVIpcLinkshellJoin >( inPacket );
auto& lsMgr = Common::Service< LinkshellMgr >::ref();
auto& server = Common::Service< World::WorldServer >::ref();
auto invitedPlayer = server.getSession( lsJoinPacket.data().MemberCharacterName );
auto lsPtr = lsMgr.getLinkshellById( lsJoinPacket.data().LinkshellID );
if( !invitedPlayer || !lsPtr )
return Logger::warn( "Failed to invite player to linkshell - session/linkshell not found!" );
lsPtr->addInvite( invitedPlayer->getPlayer()->getCharacterId() );
// TODO: send inv packets
}
void Sapphire::Network::GameConnection::joinChatChannelHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
const auto joinChannelPacket = ZoneChannelPacket< Client::FFXIVIpcJoinChatChannel >( inPacket );
const uint64_t channelIdReq = joinChannelPacket.data().ChannelID;
auto& chatChannelMgr = Common::Service< ChatChannelMgr >::ref();
if( !chatChannelMgr.isChannelValid( joinChannelPacket.data().ChannelID ) )
return Logger::warn( "Failed to join chat channel - Invalid chat channel specified!" );
chatChannelMgr.addPlayerToChannel( joinChannelPacket.data().ChannelID, player );
auto chatChannelResultPacket = makeZonePacket< FFXIVIpcChatChannelResult >( player.getId() );
chatChannelResultPacket->data().ChannelID = channelIdReq;
chatChannelResultPacket->data().TargetCharacterID = player.getId();
chatChannelResultPacket->data().CommunityID = player.getCharacterId();
chatChannelResultPacket->data().UpPacketNo = 0; // todo: define behavior
chatChannelResultPacket->data().Result = 0; // todo: define behavior
queueOutPacket( chatChannelResultPacket );
auto joinChannelResultPacket = makeChatPacket< Packets::Server::FFXIVJoinChannelResult >( player.getId() );
joinChannelResultPacket->data().channelID = channelIdReq;
joinChannelResultPacket->data().characterID = player.getId();
joinChannelResultPacket->data().result = 0;
auto& server = Common::Service< World::WorldServer >::ref();
auto pSession = server.getSession( player.getCharacterId() );
if( !pSession )
{
Logger::error( std::string( __FUNCTION__ ) + ": Session not found for player#{}", player.getCharacterId() );
return;
}
pSession->getChatConnection()->queueOutPacket( joinChannelResultPacket );
}
void Sapphire::Network::GameConnection::moveHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +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 );
auto& data = updatePositionPacket.data();
2019-02-06 08:49:57 +01:00
bool bPosChanged = true;
if( data.pos.x == player.getPos().x && data.pos.y == player.getPos().y && data.pos.z == player.getPos().z )
2019-02-06 08:49:57 +01:00
bPosChanged = false;
//if( !bPosChanged && player.getRot() == data.rotation )
2019-02-06 08:49:57 +01:00
//return;
player.setRot( data.dir );
player.setPos( { data.pos.x, data.pos.y, data.pos.z } );
if( ( player.getCurrentAction() != nullptr ) && bPosChanged )
player.getCurrentAction()->setInterrupted( Common::ActionInterruptType::RegularInterrupt );
// if no one is in range, don't bother trying to send a position update
if( !player.hasInRangeActor() )
return;
auto clientAnimationType = data.flag;
auto animationState = data.flag;
auto animationType = data.flag2;
auto headRotation = data.flag_unshared;
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;
2019-02-06 08:49:57 +01:00
animationType |= clientAnimationType;
2019-02-06 09:38:31 +01:00
if( animationType & MoveType::Strafing )
{
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;
}
2019-02-06 08:49:57 +01:00
if( animationType == MoveType::Running )
{
2019-02-06 08:49:57 +01:00
headRotation = 0x7F;
animationSpeed = MoveSpeed::Run;
}
2019-02-06 09:27:30 +01:00
if( animationType & MoveType::Jumping )
{
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;
if( animationState == MoveState::EnterCollision )
{
animationType = 2;
player.m_falling = false;
}
}
2019-02-06 08:49:57 +01:00
if( player.m_falling )
{
2019-02-06 08:49:57 +01:00
animationType += 0x10;
2019-02-06 09:27:30 +01:00
unknownRotation = 0x7F;
}
2017-08-08 13:53:47 +02:00
uint64_t currentTime = Util::getTimeMs();
player.m_lastMoveTime = currentTime;
2019-02-06 08:49:57 +01:00
player.m_lastMoveflag = animationType;
2017-08-08 13:53:47 +02:00
//auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, animationType, animationState, animationSpeed, unknownRotation );
auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, data.flag, data.flag2, animationSpeed, unknownRotation );
player.sendToInRangeSet( movePacket );
2017-08-08 13:53:47 +02:00
}
void
Sapphire::Network::GameConnection::configHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
const auto packet = ZoneChannelPacket< Client::FFXIVIpcConfig >( inPacket );
player.setEquipDisplayFlags( packet.data().flag );
Service< World::Manager::PlayerMgr >::ref().onEquipDisplayFlagsChanged( player );
}
2017-08-08 13:53:47 +02:00
void Sapphire::Network::GameConnection::zoneJumpHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
const auto packet = ZoneChannelPacket< Client::FFXIVIpcZoneJump >( inPacket );
auto& data = packet.data();
const auto exitBoxId = data.ExitBox;
2020-03-01 01:00:57 +11:00
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
auto& instanceObjectCache = Common::Service< InstanceObjectCache >::ref();
auto& server = Common::Service< World::WorldServer >::ref();
auto tInfo = player.getCurrentTerritory()->getTerritoryTypeInfo();
auto pExitRange = instanceObjectCache.getExitRange( player.getTerritoryTypeId(), exitBoxId );
Common::FFXIVARR_POSITION3 targetPos{};
Common::FFXIVARR_POSITION3 targetRot{};
uint32_t targetZone;
float rotation = 0.0f;
if( pExitRange )
{
2020-03-01 01:00:57 +11:00
auto pPopRange = instanceObjectCache.getPopRange( pExitRange->data.destTerritoryType,
pExitRange->data.destInstanceObjectId );
if( pPopRange )
{
2019-10-22 22:34:34 +02:00
targetZone = pExitRange->data.destTerritoryType;
targetPos = Common::FFXIVARR_POSITION3 { pPopRange->header.transform.translation.x,
pPopRange->header.transform.translation.y,
pPopRange->header.transform.translation.z };
targetRot = Common::FFXIVARR_POSITION3 { pPopRange->header.transform.rotation.x,
pPopRange->header.transform.rotation.y,
pPopRange->header.transform.rotation.z };
rotation = Util::eulerToDirection( targetRot );
PlayerMgr::sendDebug( player, "ZoneLine #{0} found. Rotation: {1} {2} {3} - {4}", exitBoxId,
pPopRange->header.transform.rotation.x,
pPopRange->header.transform.rotation.y,
pPopRange->header.transform.rotation.z,
rotation );
auto preparePacket = makeZonePacket< FFXIVIpcPrepareZoning >( player.getId() );
2019-10-22 22:34:34 +02:00
preparePacket->data().targetZone = pExitRange->data.destTerritoryType;
server.queueForPlayer( player.getCharacterId(), preparePacket );
}
}
PlayerMgr::sendDebug( player, "Walking ZoneLine#{0}", exitBoxId );
player.performZoning( targetZone, targetPos, rotation );
2017-08-08 13:53:47 +02:00
}
void Sapphire::Network::GameConnection::newDiscoveryHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto& server = Common::Service< World::WorldServer >::ref();
2020-03-01 01:00:57 +11:00
auto& instanceObjectCache = Common::Service< InstanceObjectCache >::ref();
auto tInfo = player.getCurrentTerritory()->getTerritoryTypeInfo();
const auto packet = ZoneChannelPacket< Client::FFXIVIpcNewDiscovery >( inPacket );
const auto layoutId = packet.data().LayoutId;
2017-08-08 13:53:47 +02:00
auto pRefInfo = instanceObjectCache.getMapRange( player.getTerritoryTypeId(), layoutId );
PlayerMgr::sendDebug( player, "Discovery ref pos id#{0}", layoutId );
2017-08-08 13:53:47 +02:00
if( pRefInfo )
{
auto discoveryPacket = makeZonePacket< FFXIVIpcDiscoveryReply >( player.getId() );
discoveryPacket->data().mapId = tInfo->data().Map;
2019-10-22 22:34:34 +02:00
discoveryPacket->data().mapPartId = pRefInfo->data.discoveryIndex;
server.queueForPlayer( player.getCharacterId(), discoveryPacket );
player.discover( tInfo->data().Map, pRefInfo->data.discoveryIndex );
}
2017-08-08 13:53:47 +02:00
}
2021-12-01 01:03:36 +01:00
void Sapphire::Network::GameConnection::loginHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref();
// init handler means this is a login procedure
player.setIsLogin( true );
teriMgr.joinWorld( player );
2017-08-08 13:53:47 +02:00
}
2021-12-01 01:03:36 +01:00
void Sapphire::Network::GameConnection::getBlacklistHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
const auto packet = ZoneChannelPacket< Client::FFXIVIpcGetBlacklist >( inPacket );
auto& data = packet.data();
auto blackListPacket = makeZonePacket< FFXIVIpcGetBlacklistResult >( player.getId() );
blackListPacket->data().Index = data.NextIndex;
blackListPacket->data().RequestKey = data.RequestKey;
2017-08-08 13:53:47 +02:00
// TODO: Fill with actual blacklist data
//blackListPacket.data().entry[0].contentId = 1;
//sprintf( blackListPacket.data().entry[0].name, "Test Test" );
2017-08-08 13:53:47 +02:00
queueOutPacket( blackListPacket );
2017-08-08 13:53:47 +02:00
}
void Sapphire::Network::GameConnection::syncHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto& server = Common::Service< World::WorldServer >::ref();
2019-07-29 22:22:45 +10:00
const auto packet = ZoneChannelPacket< Client::FFXIVIpcPingHandler >( inPacket );
auto& data = packet.data();
queueOutPacket( std::make_shared< WorldPackets::Server::PingPacket >( player, data.clientTimeValue ) );
auto pSession = server.getSession( player.getCharacterId() );
if( !pSession )
return;
2017-08-08 13:53:47 +02:00
pSession->setLastPing( Common::Util::getTimeSeconds() );
2017-08-08 13:53:47 +02:00
}
void Sapphire::Network::GameConnection::setLanguageHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto& questMgr = Common::Service< World::Manager::QuestMgr >::ref();
questMgr.sendQuestsInfo( player );
auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref();
/* // TODO: load and save this data instead of hardcoding
auto gcPacket = makeZonePacket< FFXIVGCAffiliation >( player.getId() );
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 );*/
2018-11-10 19:00:13 +01:00
player.getCurrentTerritory()->onFinishLoading( player );
// player is done zoning
player.setLoadingComplete( true );
2017-08-08 13:53:47 +02:00
// if this is a login event
if( player.isLogin() )
{
// fire the onLogin Event
playerMgr.onLogin( player );
player.setIsLogin( false );
}
2017-08-08 13:53:47 +02:00
// spawn the player for himself
player.spawn( player.getAsPlayer() );
2017-08-08 13:53:47 +02:00
// notify the zone of a change in position to force an "inRangeActor" update
player.getCurrentTerritory()->updateActorPosition( player );
2017-08-08 13:53:47 +02:00
}
void Sapphire::Network::GameConnection::pcSearchHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
const auto packet = ZoneChannelPacket< Client::FFXIVIpcPcSearch >( inPacket );
auto& data = packet.data();
2017-08-08 13:53:47 +02:00
// TODO: implement player search
auto& server = Common::Service< World::WorldServer >::ref();
bool isLastName = data.CharacterName[ 0 ] == ' ';
std::string queryName = data.CharacterName;
if( !isLastName )
queryName += " ";
// on lastName, client automatically adds a space to first character - no need to manually add space
auto queryPlayers = server.searchSessionByName( queryName );
// store result in player - we don't map out query keys to data yet
std::vector< uint32_t > entityIdVec;
for( const auto pSession : queryPlayers )
{
if( !pSession )
continue;
entityIdVec.emplace_back( pSession->getPlayer()->getId() );
}
player.setLastPcSearchResult( entityIdVec );
// send amount of results found - client requires this to "enable" displaying new queries
auto pcSearchResultPacket = makeZonePacket< FFXIVIpcPcSearchResult >( player.getId() );
pcSearchResultPacket->data().ResultCount = static_cast< int16_t >( entityIdVec.size() );
2017-08-08 13:53:47 +02:00
queueOutPacket( pcSearchResultPacket );
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,
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 );
auto& data = packet.data();
2017-08-08 13:53:47 +02:00
if( data.message[ 0 ] == '!' )
{
// execute game console command
debugCommandMgr.execCommand( const_cast< char* >( data.message ) + 1, player );
return;
}
2017-08-08 13:53:47 +02:00
auto chatType = packet.data().chatType;
2017-08-08 13:53:47 +02:00
//ToDo, need to implement sending GM chat types.
auto chatPacket = std::make_shared< WorldPackets::Server::ChatPacket >( player, chatType, data.message );
2017-08-08 13:53:47 +02:00
switch( chatType )
{
case ChatType::Say:
{
if( player.isActingAsGm() )
chatPacket->data().type = static_cast< uint16_t >( ChatType::GMSay );
player.getCurrentTerritory()->queuePacketForRange( player, 50.f, chatPacket );
2017-08-08 13:53:47 +02:00
break;
}
case ChatType::Yell:
{
if( player.isActingAsGm() )
chatPacket->data().type = static_cast< uint16_t >( ChatType::GMYell );
player.getCurrentTerritory()->queuePacketForRange( player, 6000.f, chatPacket );
2017-08-08 13:53:47 +02:00
break;
}
case ChatType::Shout:
{
if( player.isActingAsGm() )
chatPacket->data().type = static_cast< uint16_t >( ChatType::GMShout );
player.getCurrentTerritory()->queuePacketForRange( player, 6000.f, chatPacket );
2017-08-08 13:53:47 +02:00
break;
}
default:
{
player.getCurrentTerritory()->queuePacketForRange( player, 50.f, chatPacket );
2017-08-08 13:53:47 +02:00
break;
}
}
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,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto logoutPacket = makeZonePacket< FFXIVIpcEnableLogout >( player.getId() );
logoutPacket->data().content = 0x02;
// logoutPacket->data().flags2 = 0x2000;
queueOutPacket( logoutPacket );
player.setMarkedForRemoval();
}
2020-03-01 01:00:57 +11:00
void Sapphire::Network::GameConnection::tellHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
const auto packet = ZoneChannelPacket< Client::FFXIVIpcChatTo >( inPacket );
auto& data = packet.data();
auto& server = Common::Service< World::WorldServer >::ref();
auto pSession = server.getSession( data.toName );
if( !pSession )
{
auto tellErrPacket = makeZonePacket< Packets::Server::FFXIVIpcTellNotFound >( player.getId() );
strcpy( tellErrPacket->data().toName, data.toName );
sendSinglePacket( tellErrPacket );
return;
}
auto pTargetPlayer = pSession->getPlayer();
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BetweenAreas ) )
{
// send error for player between areas
// TODO: implement me
return;
}
auto pSessionSource = server.getSession( player.getCharacterId() );
if( !pSession )
{
Logger::error( std::string( __FUNCTION__ ) + ": Session not found for player#{}", player.getCharacterId() );
return;
}
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BoundByDuty ) && !player.isActingAsGm() )
{
auto boundPacket = makeChatPacket< Packets::Server::FFXIVRecvFinderStatus >( player.getId() );
strcpy( boundPacket->data().toName, data.toName );
pSessionSource->getChatConnection()->queueOutPacket( boundPacket );
return;
}
if( pTargetPlayer->getOnlineStatus() == OnlineStatus::Busy && !player.isActingAsGm() )
{
auto busyPacket = makeChatPacket< Packets::Server::FFXIVRecvBusyStatus >( player.getId() );
strcpy( busyPacket->data().toName, data.toName );
pSessionSource->getChatConnection()->queueOutPacket( busyPacket );
2018-11-28 21:59:28 +11:00
return;
}
2018-11-28 21:59:28 +11:00
auto tellPacket = makeChatPacket< Packets::Server::FFXIVChatFrom >( player.getId() );
strcpy( tellPacket->data().message, data.message );
strcpy( tellPacket->data().fromName, player.getName().c_str() );
tellPacket->data().fromCharacterID = player.getCharacterId();
2018-12-26 18:11:18 +11:00
if( player.isActingAsGm() )
{
tellPacket->data().type |= ChatFromType::GmTellMsg; //TODO: Is there an enum for this? or is it only GM?
}
pSession->getChatConnection()->queueOutPacket( tellPacket );
}
void Sapphire::Network::GameConnection::chatToChannelHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
const auto packet = ChatChannelPacket< Client::FFXIVIpcChatToChannel >( inPacket );
auto& data = packet.data();
auto& chatChannelMgr = Common::Service< ChatChannelMgr >::ref();
std::string message = std::string( data.message );
2018-12-31 23:20:36 +11:00
chatChannelMgr.sendMessageToChannel( data.channelID, player, message );
}
void Sapphire::Network::GameConnection::catalogSearch( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2018-12-31 23:20:36 +11:00
{
2020-03-01 01:00:57 +11:00
auto& marketMgr = Common::Service< MarketMgr >::ref();
2018-12-31 23:20:36 +11:00
const auto packet = ZoneChannelPacket< Client::FFXIVIpcCatalogSearch >( inPacket );
2018-12-31 23:20:36 +11:00
const auto& data = packet.data();
marketMgr.searchMarketboard(
player,
data.SearchCategory,
data.MaxLevel,
data.ClassJob,
data.ItemName,
data.RequestKey,
data.NextIndex
);
2019-01-01 11:51:48 +11:00
}
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();
2020-03-01 01:00:57 +11:00
marketMgr.requestItemListingInfo( player, packet.data().catalogId, packet.data().requestId );
}
2020-03-01 01:00:57 +11:00
void Sapphire::Network::GameConnection::marketBoardRequestItemListings( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
2019-07-29 22:22:45 +10:00
const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListings >( inPacket );
2020-03-01 01:00:57 +11:00
auto& marketMgr = Common::Service< MarketMgr >::ref();
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::getFcStatus( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2020-06-15 08:34:10 +09:00
{
}
void Sapphire::Network::GameConnection::getFcProfile( const Sapphire::Network::Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
const auto packet = ZoneChannelPacket< Client::FFXIVIpcGetFcProfile >( inPacket );
auto& server = Common::Service< World::WorldServer >::ref();
auto resultPacket = makeZonePacket< WorldPackets::Server::FFXIVIpcGetFcProfileResult >( player.getId() );
resultPacket->data().TargetCharacterID = packet.data().TargetCharacterID;
resultPacket->data().TargetEntityID = packet.data().TargetEntityID;
// haha test code
resultPacket->data().FreeCompanyID = 1;
resultPacket->data().CrestID = 0x0001000100010001;
resultPacket->data().LandID = Common::INVALID_GAME_OBJECT_ID64;
resultPacket->data().OnlineMemberCount = 69;
resultPacket->data().TotalMemberCount = 420;
resultPacket->data().JoinRequestCount = 69;
resultPacket->data().FcRank = 1;
resultPacket->data().FcStatus = 1;
resultPacket->data().FcRole = 1;
resultPacket->data().FcActivity = 1;
resultPacket->data().GrandCompanyID = 1;
resultPacket->data().CreateDate = 1587305592;
resultPacket->data().Reputation = 500;
resultPacket->data().FcActiveTimeFlag = 0xFF;
resultPacket->data().FcJoinRequestFlag = 0xFF;
strcpy( resultPacket->data().MasterCharacterName, "Biggus Dickus" );
strcpy( resultPacket->data().FcTag, "Wang" );
strcpy( resultPacket->data().FreeCompanyName, "Test FC" );
strcpy( resultPacket->data().CompanyMotto, "nobody here but us chickens" );
server.queueForPlayer( player.getCharacterId(), resultPacket );
2020-11-14 06:15:10 +09:00
}
void Sapphire::Network::GameConnection::getRequestItemListHandler(
const Sapphire::Network::Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
2020-11-14 06:15:10 +09:00
{
}