1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-24 21:57:44 +00:00
sapphire/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp

623 lines
21 KiB
C++
Raw Normal View History

#include <boost/format.hpp>
2018-03-06 22:22:19 +01:00
#include <Common.h>
#include <Network/CommonNetwork.h>
#include <Network/GamePacketNew.h>
#include <Logging/Logger.h>
#include <Network/PacketContainer.h>
#include <Network/PacketDef/Chat/ServerChatDef.h>
#include <Database/DatabaseDef.h>
#include <unordered_map>
#include "Network/GameConnection.h"
2018-01-27 23:52:49 +01:00
#include "Zone/TerritoryMgr.h"
#include "Zone/Zone.h"
#include "Zone/ZonePosition.h"
#include "Network/PacketWrappers/InitUIPacket.h"
#include "Network/PacketWrappers/PingPacket.h"
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/PacketWrappers/ChatPacket.h"
#include "Network/PacketWrappers/ServerNoticePacket.h"
#include "Network/PacketWrappers/ActorControlPacket142.h"
#include "Network/PacketWrappers/ActorControlPacket143.h"
#include "Network/PacketWrappers/ActorControlPacket144.h"
#include "Network/PacketWrappers/EventStartPacket.h"
#include "Network/PacketWrappers/EventFinishPacket.h"
#include "Network/PacketWrappers/PlayerStateFlagsPacket.h"
#include "DebugCommand/DebugCommandHandler.h"
#include "Event/EventHelper.h"
#include "Action/Action.h"
#include "Action/ActionTeleport.h"
2017-08-08 13:53:47 +02:00
#include "Session.h"
#include "ServerZone.h"
#include "Forwards.h"
#include "Framework.h"
2017-10-27 00:10:13 +02:00
extern Core::Framework g_fw;
2017-08-08 13:53:47 +02:00
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
void Core::Network::GameConnection::fcInfoReqHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
2018-06-03 19:31:03 +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
}
void Core::Network::GameConnection::setSearchInfoHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
uint32_t inval = inPacket.getValAt< uint32_t >( 0x20 );
uint32_t inval1 = inPacket.getValAt< uint32_t >( 0x24 );
uint64_t status = inPacket.getValAt< uint64_t >( 0x20 );
2017-08-08 13:53:47 +02:00
uint8_t selectRegion = inPacket.getValAt< uint8_t >( 0x31 );
2017-08-08 13:53:47 +02:00
player.setSearchInfo( selectRegion, 0, inPacket.getStringAt( 0x32 ) );
2017-08-08 13:53:47 +02:00
player.setOnlineStatusMask( status );
2017-08-08 13:53:47 +02:00
if( player.isNewAdventurer() && !( inval & 0x01000000 ) )
2017-08-08 13:53:47 +02:00
// mark player as not new adventurer anymore
player.setNewAdventurer( false );
2017-08-08 13:53:47 +02:00
else if( inval & 0x01000000 )
// mark player as new adventurer
player.setNewAdventurer( true );
2017-08-08 13:53:47 +02:00
ZoneChannelPacket< FFXIVIpcSetOnlineStatus > statusPacket( player.getId() );
2017-08-08 13:53:47 +02:00
statusPacket.data().onlineStatusFlags = status;
queueOutPacket( statusPacket );
ZoneChannelPacket< FFXIVIpcSetSearchInfo > searchInfoPacket( player.getId() );
2017-08-08 13:53:47 +02:00
searchInfoPacket.data().onlineStatusFlags = status;
searchInfoPacket.data().selectRegion = player.getSearchSelectRegion();
strcpy( searchInfoPacket.data().searchMessage, player.getSearchMessage() );
2017-08-08 13:53:47 +02:00
queueOutPacket( searchInfoPacket );
player.sendToInRangeSet( ActorControlPacket142( player.getId(), SetStatusIcon,
static_cast< uint8_t >( player.getOnlineStatus() ) ), true );
2017-08-08 13:53:47 +02:00
}
void Core::Network::GameConnection::reqSearchInfoHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
ZoneChannelPacket< FFXIVIpcInitSearchInfo > searchInfoPacket( player.getId() );
searchInfoPacket.data().onlineStatusFlags = player.getOnlineStatusMask();
searchInfoPacket.data().selectRegion = player.getSearchSelectRegion();
strcpy( searchInfoPacket.data().searchMessage, player.getSearchMessage() );
2017-08-08 13:53:47 +02:00
queueOutPacket( searchInfoPacket );
}
void Core::Network::GameConnection::linkshellListHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
ZoneChannelPacket< FFXIVIpcLinkshellList > linkshellListPacket( player.getId() );
2017-08-08 13:53:47 +02:00
queueOutPacket( linkshellListPacket );
}
void Core::Network::GameConnection::updatePositionHandler( const Packets::GamePacket& 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() )
2017-08-08 13:53:47 +02:00
return;
struct testMov
{
uint32_t specialMovement : 23; // 0x00490FDA
uint32_t strafe : 7;
uint32_t moveBackward : 1;
uint32_t strafeRight : 1; // if 0, strafe left.
} IPC_OP_019A;
struct testMov1
{
uint16_t bit1 : 1; // 0x00490FDA
uint16_t bit2 : 1;
uint16_t bit3 : 1;
uint16_t bit4 : 1;
uint16_t bit5 : 1;
uint16_t bit6 : 1;
uint16_t bit7 : 1;
uint16_t bit8 : 1;
uint16_t bit9 : 1; // 0x00490FDA
uint16_t bit10 : 1;
uint16_t bit11 : 1;
uint16_t bit12 : 1;
uint16_t bit13 : 1;
uint16_t bit14 : 1;
uint16_t bit15 : 1;
uint16_t bit16 : 1;
} IPC_OP_019AB;
uint16_t flags = inPacket.getValAt<uint16_t>( 0x28 );
2017-08-08 13:53:47 +02:00
memcpy( &IPC_OP_019AB, &flags, 2 );
uint32_t flags1 = inPacket.getValAt<uint32_t>( 0x24 );
2017-08-08 13:53:47 +02:00
memcpy( &IPC_OP_019A, &flags1, 4 );
//g_log.Log(LoggingSeverity::debug, "" + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit1)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit2)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit3)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit4)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit5)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit6)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit7)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit8)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit9)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit10)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit11)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit12)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit13)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit14)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit15)
// + boost::lexical_cast<std::string>((int)IPC_OP_019AB.bit16)
// + " " + boost::lexical_cast<std::string>((int)flags));
//g_log.Log(LoggingSeverity::debug, "\n" + boost::lexical_cast<std::string>((int)IPC_OP_019A.specialMovement) + "\n"
// + boost::lexical_cast<std::string>((int)IPC_OP_019A.strafe) + "\n"
// + boost::lexical_cast<std::string>((int)IPC_OP_019A.moveBackward) + "\n"
// + boost::lexical_cast<std::string>((int)IPC_OP_019A.strafeRight));
//g_log.Log(LoggingSeverity::debug, pInPacket->toString());
//pInPacket->debugPrint();
bool bPosChanged = false;
if( ( player.getPos().x != inPacket.getValAt< float >( 0x2c ) ) ||
( player.getPos().y != inPacket.getValAt< float >( 0x30 ) ) ||
( player.getPos().z != inPacket.getValAt< float >( 0x34 ) ) )
2017-08-08 13:53:47 +02:00
bPosChanged = true;
if( !bPosChanged && player.getRot() == inPacket.getValAt< float >( 0x20 ) )
2017-08-08 13:53:47 +02:00
return;
player.setRot( inPacket.getValAt< float >( 0x20 ) );
player.setPos( inPacket.getValAt< float >( 0x2c ),
inPacket.getValAt< float >( 0x30 ),
inPacket.getValAt< float >( 0x34 ) );
2017-08-08 13:53:47 +02:00
if( ( player.getCurrentAction() != nullptr ) && bPosChanged )
player.getCurrentAction()->setInterrupted();
2017-08-08 13:53:47 +02:00
// if no one is in range, don't bother trying to send a position update
if( !player.hasInRangeActor() )
2017-08-08 13:53:47 +02:00
return;
uint8_t unk = inPacket.getValAt< uint8_t >( 0x29 );
2017-08-08 13:53:47 +02:00
uint16_t moveType = inPacket.getValAt< uint16_t >( 0x28 );
2017-08-08 13:53:47 +02:00
uint8_t unk1 = 0;
uint8_t unk2 = 0;
uint8_t unk3 = unk;
uint16_t unk4 = 0;
// HACK: This part is hackish, we need to find out what all theese things really do.
switch( moveType )
{
case MoveType::Strafe:
{
if( IPC_OP_019A.strafeRight == 1 )
unk1 = 0xbf;
else
unk1 = 0x5f;
unk4 = 0x3C;
break;
}
case 6:
{
unk1 = 0xFF;
unk2 = 0x06;
unk4 = 0x18;
break;
}
// case MoveType::Land:
// {
// unk1 = 0x7F;
// //unk2 = 0x40;
// unk4 = 0x3C;
// break;
// }
// case MoveType::Jump:
// {
// unk1 = 0x7F;
// if(unk == 0x01)
// {
// // unk2 = 0x20;
// //unk4 = 0x32;
// unk4 = 0x32;
// }
// else
// {
// // unk2 = 0xA0;
// unk4 = 0x3C;
// }
//
// break;
// }
// case MoveType::Fall:
// {
// unk1 = 0x7F;
// //unk2 = 0xA0;
// unk4 = 0x3C;
//
// break;
// }
default:
{
if( static_cast< int32_t >( IPC_OP_019A.moveBackward ) )
2017-08-08 13:53:47 +02:00
{
unk1 = 0xFF;
unk2 = 0x06;
unk4 = 0x18; // animation speed?
}
else
{
unk1 = 0x7F;
unk4 = 0x3C; // animation speed?
}
break;
}
}
MoveActorPacket movePacket( player, unk1, unk2, unk3, unk4 );
player.sendToInRangeSet( movePacket );
2017-08-08 13:53:47 +02:00
}
2017-10-06 00:13:29 +02:00
void Core::Network::GameConnection::reqEquipDisplayFlagsHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
{
player.setEquipDisplayFlags( inPacket.getValAt< uint8_t >( 0x20 ) );
player.sendDebug( "EquipDisplayFlag CHANGE: " + std::to_string( player.getEquipDisplayFlags() ) );
}
2017-08-08 13:53:47 +02:00
void Core::Network::GameConnection::zoneLineHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto pTeriMgr = g_fw.get< TerritoryMgr >();
uint32_t zoneLineId = inPacket.getValAt< uint32_t >( 0x20 );
2017-08-08 13:53:47 +02:00
player.sendDebug( "Walking ZoneLine " + std::to_string( zoneLineId ) );
2017-08-09 15:02:24 +02:00
auto pZone = player.getCurrentZone();
2017-08-08 13:53:47 +02:00
auto pLine = pTeriMgr->getTerritoryPosition( zoneLineId );
2017-08-08 13:53:47 +02:00
2017-11-28 00:09:36 +01:00
Common::FFXIVARR_POSITION3 targetPos{};
2017-08-08 13:53:47 +02:00
uint32_t targetZone;
float rotation = 0.0f;
if( pLine != nullptr )
{
player.sendDebug( "ZoneLine " + std::to_string( zoneLineId ) + " found." );
2017-08-08 13:53:47 +02:00
targetPos = pLine->getTargetPosition();
targetZone = pLine->getTargetZoneId();
rotation = pLine->getTargetRotation();
ZoneChannelPacket< FFXIVIpcPrepareZoning > preparePacket( player.getId() );
2017-08-08 13:53:47 +02:00
preparePacket.data().targetZone = targetZone;
//ActorControlPacket143 controlPacket( pPlayer, ActorControlType::DespawnZoneScreenMsg,
// 0x03, player.getId(), 0x01, targetZone );
player.queuePacket( preparePacket );
2017-08-08 13:53:47 +02:00
}
else
{
// No zoneline found, revert to last zone
player.sendUrgent( "ZoneLine " + std::to_string( zoneLineId ) + " not found." );
2017-08-08 13:53:47 +02:00
targetPos.x = 0;
targetPos.y = 0;
targetPos.z = 0;
2018-01-27 23:52:49 +01:00
targetZone = pZone->getTerritoryId();
2017-08-08 13:53:47 +02:00
}
player.performZoning( targetZone, targetPos, rotation);
2017-08-08 13:53:47 +02:00
}
void Core::Network::GameConnection::discoveryHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
uint32_t ref_position_id = inPacket.getValAt< uint32_t >( 0x20 );
2017-08-08 13:53:47 +02:00
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
auto pQR = pDb->query( "SELECT id, map_id, discover_id "
2017-10-27 00:10:13 +02:00
"FROM discoveryinfo "
"WHERE id = " + std::to_string( ref_position_id ) + ";" );
2017-08-08 13:53:47 +02:00
2017-10-27 00:10:13 +02:00
if( !pQR->next() )
2017-08-08 13:53:47 +02:00
{
player.sendNotice( "Discovery ref pos ID: " + std::to_string( ref_position_id ) + " not found. " );
2017-08-08 13:53:47 +02:00
return;
}
ZoneChannelPacket< FFXIVIpcDiscovery > discoveryPacket( player.getId() );
2017-10-27 00:10:13 +02:00
discoveryPacket.data().map_id = pQR->getUInt( 2 );
discoveryPacket.data().map_part_id = pQR->getUInt( 3 );
2017-08-08 13:53:47 +02:00
player.queuePacket( discoveryPacket );
player.sendNotice( "Discovery ref pos ID: " + std::to_string( ref_position_id ) );
2017-08-08 13:53:47 +02:00
player.discover( pQR->getUInt16( 2 ), pQR->getUInt16( 3 ) );
2017-08-08 13:53:47 +02:00
}
void Core::Network::GameConnection::playTimeHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
ZoneChannelPacket< FFXIVIpcPlayTime > playTimePacket( player.getId() );
playTimePacket.data().playTimeInMinutes = player.getPlayTime() / 60;
player.queuePacket( playTimePacket );
2017-08-08 13:53:47 +02:00
}
void Core::Network::GameConnection::initHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
// init handler means this is a login procedure
player.setIsLogin( true );
2017-08-08 13:53:47 +02:00
player.sendZonePackets();
2017-08-08 13:53:47 +02:00
}
void Core::Network::GameConnection::blackListHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
uint8_t count = inPacket.getValAt< uint8_t >( 0x21 );
2017-08-08 13:53:47 +02:00
ZoneChannelPacket< FFXIVIpcBlackList > blackListPacket( player.getId() );
2017-08-08 13:53:47 +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 );
}
void Core::Network::GameConnection::pingHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
int32_t inVal = inPacket.getValAt< int32_t >( 0x20 );
PingPacket pingPacket( player, inVal );
2017-08-08 13:53:47 +02:00
queueOutPacket( pingPacket );
player.setLastPing( static_cast< uint32_t >( time( nullptr ) ) );
2017-08-08 13:53:47 +02:00
}
void Core::Network::GameConnection::finishLoadingHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
player.getCurrentZone()->onFinishLoading( player );
2017-08-08 13:53:47 +02:00
// player is done zoning
player.setLoadingComplete( true );
2017-08-08 13:53:47 +02:00
// if this is a login event
if( player.isLogin() )
2017-08-08 13:53:47 +02:00
{
// fire the onLogin Event
player.onLogin();
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.getCurrentZone()->updateActorPosition(player);
2017-08-08 13:53:47 +02:00
}
void Core::Network::GameConnection::socialListHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
uint8_t type = inPacket.getValAt< uint8_t >( 0x2A );
uint8_t count = inPacket.getValAt< uint8_t >( 0x2B );
2017-08-08 13:53:47 +02:00
if( type == 0x02 )
{ // party list
ZoneChannelPacket< FFXIVIpcSocialList > listPacket( player.getId() );
2017-08-08 13:53:47 +02:00
listPacket.data().type = 2;
listPacket.data().sequence = count;
int32_t entrysizes = sizeof( listPacket.data().entries );
2017-08-08 13:53:47 +02:00
memset( listPacket.data().entries, 0, sizeof( listPacket.data().entries ) );
2018-01-27 23:52:49 +01:00
listPacket.data().entries[0].bytes[2] = player.getCurrentZone()->getTerritoryId();
2017-08-08 13:53:47 +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();
2018-01-27 23:52:49 +01:00
listPacket.data().entries[0].zoneId = player.getCurrentZone()->getTerritoryId();
2017-08-08 13:53:47 +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() ) );
2017-08-08 13:53:47 +02:00
// TODO: actually store and read language from somewhere
listPacket.data().entries[0].bytes1[0] = 0x01;//flags (lang)
// TODO: these flags need to be figured out
//listPacket.data().entries[0].bytes1[1] = 0x00;//flags
listPacket.data().entries[0].onlineStatusMask = player.getOnlineStatusMask();
2017-08-08 13:53:47 +02:00
queueOutPacket( listPacket );
}
else if( type == 0x0b )
{ // friend list
ZoneChannelPacket< FFXIVIpcSocialList > listPacket( player.getId() );
2017-08-08 13:53:47 +02:00
listPacket.data().type = 0x0B;
listPacket.data().sequence = count;
memset( listPacket.data().entries, 0, sizeof( listPacket.data().entries ) );
}
else if( type == 0x0e )
{ // player search result
// TODO: implement player search
}
}
void Core::Network::GameConnection::chatHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
auto pDebugCom = g_fw.get< DebugCommandHandler >();
std::string chatString( inPacket.getStringAt( 0x3a ) );
2017-08-08 13:53:47 +02:00
uint32_t sourceId = inPacket.getValAt< uint32_t >( 0x24 );
2017-08-08 13:53:47 +02:00
if( chatString.at( 0 ) == '!' )
2017-08-08 13:53:47 +02:00
{
// execute game console command
pDebugCom->execCommand( const_cast< char * >( chatString.c_str() ) + 1, player );
2017-08-08 13:53:47 +02:00
return;
}
ChatType chatType = static_cast< ChatType >( inPacket.getValAt< uint8_t >( 0x38 ) );
2017-08-08 13:53:47 +02:00
//ToDo, need to implement sending GM chat types.
ChatPacket chatPacket( player, chatType, chatString );
2017-08-08 13:53:47 +02:00
switch( chatType )
{
case ChatType::Say:
{
if (player.getGmRank() > 0)
chatPacket.data().chatType = ChatType::GMSay;
player.getCurrentZone()->queueOutPacketForRange( player, 50, chatPacket );
2017-08-08 13:53:47 +02:00
break;
}
case ChatType::Yell:
{
if( player.getGmRank() > 0 )
chatPacket.data().chatType = ChatType::GMYell;
player.getCurrentZone()->queueOutPacketForRange( player, 6000, chatPacket );
2017-08-08 13:53:47 +02:00
break;
}
case ChatType::Shout:
{
if( player.getGmRank() > 0 )
chatPacket.data().chatType = ChatType::GMShout;
player.getCurrentZone()->queueOutPacketForRange( player, 6000, chatPacket );
2017-08-08 13:53:47 +02:00
break;
}
default:
{
player.getCurrentZone()->queueOutPacketForRange( player, 50, chatPacket );
2017-08-08 13:53:47 +02:00
break;
}
}
}
// 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
void Core::Network::GameConnection::logoutHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-08-08 13:53:47 +02:00
{
ZoneChannelPacket< FFXIVIpcLogout > logoutPacket( player.getId() );
2017-08-08 13:53:47 +02:00
logoutPacket.data().flags1 = 0x02;
logoutPacket.data().flags2 = 0x2000;
queueOutPacket( logoutPacket );
player.setMarkedForRemoval();
}
void Core::Network::GameConnection::tellHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
{
std::string targetPcName = inPacket.getStringAt( 0x21 );
std::string msg = inPacket.getStringAt( 0x41 );
auto pZoneServer = g_fw.get< ServerZone >();
auto pSession = pZoneServer->getSession( targetPcName );
if( !pSession )
{
ChatChannelPacket< FFXIVIpcTellErrNotFound > tellErrPacket( player.getId() );
strcpy( tellErrPacket.data().receipientName, targetPcName.c_str() );
sendSinglePacket( tellErrPacket );
return;
}
auto pTargetPlayer = pSession->getPlayer();
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BetweenAreas ) )
{
// send error for player between areas
2017-08-23 23:58:14 +02:00
// TODO: implement me
return;
}
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BoundByDuty ) )
{
// send error for player bound by duty
2017-08-23 23:58:14 +02:00
// TODO: implement me
return;
}
if( pTargetPlayer->getOnlineStatus() == OnlineStatus::Busy )
{
// send error for player being busy
2017-08-23 23:58:14 +02:00
// TODO: implement me ( i've seen this done with packet type 67 i think )
return;
}
ChatChannelPacket< FFXIVIpcTell > tellPacket( player.getId() );
strcpy( tellPacket.data().msg, msg.c_str() );
strcpy( tellPacket.data().receipientName, player.getName().c_str() );
2017-08-23 23:58:14 +02:00
// TODO: do these have a meaning?
//tellPacket.data().u1 = 0x92CD7337;
//tellPacket.data().u2a = 0x2E;
//tellPacket.data().u2b = 0x40;
pTargetPlayer->queueChatPacket( tellPacket );
}
2017-11-22 00:29:42 +09:00
void Core::Network::GameConnection::performNoteHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
2017-11-22 00:29:42 +09:00
{
2017-12-09 13:55:55 +09:00
ZoneChannelPacket< FFXIVIpcPerformNote > performPacket( player.getId() );
2017-11-22 00:29:42 +09:00
2017-12-09 13:14:06 +09:00
auto inVal = inPacket.getDataAt( 0x20 );
2017-12-09 13:09:56 +09:00
memcpy( &performPacket.data().data[0], inVal, 32 );
2017-11-22 00:29:42 +09:00
player.sendToInRangeSet( performPacket );
2017-11-22 00:29:42 +09:00
}