2018-03-06 22:22:19 +01:00
|
|
|
#include <Common.h>
|
|
|
|
#include <Network/CommonNetwork.h>
|
|
|
|
#include <Util/Util.h>
|
|
|
|
#include <Logging/Logger.h>
|
2018-06-28 00:07:07 +02:00
|
|
|
#include <utility>
|
2018-06-02 13:38:00 +02:00
|
|
|
|
|
|
|
#include <Network/Acceptor.h>
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Network/PacketContainer.h>
|
|
|
|
#include <Network/GamePacketParser.h>
|
2020-02-29 22:30:10 +11:00
|
|
|
#include <Service.h>
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-07-21 22:33:33 +10:00
|
|
|
#include "Territory/Territory.h"
|
2018-03-02 07:22:25 -03:00
|
|
|
|
2019-06-20 14:48:24 +10:00
|
|
|
#include "Network/PacketWrappers/PlayerSetupPacket.h"
|
2018-03-02 07:22:25 -03:00
|
|
|
|
|
|
|
#include "GameConnection.h"
|
2021-11-27 00:53:57 +01:00
|
|
|
#include "WorldServer.h"
|
2018-03-02 07:22:25 -03:00
|
|
|
#include "Session.h"
|
2017-12-08 15:38:25 +01:00
|
|
|
#include "Forwards.h"
|
2017-08-18 17:16:15 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
#include "Manager/PlayerMgr.h"
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
using namespace Sapphire::Common;
|
2021-11-27 00:53:57 +01:00
|
|
|
using namespace Sapphire::World::Manager;
|
|
|
|
using namespace Sapphire::Network;
|
2018-11-29 16:55:48 +01:00
|
|
|
using namespace Sapphire::Network::Packets;
|
2021-11-27 00:53:57 +01:00
|
|
|
using namespace Sapphire::Network::Packets::WorldPackets;
|
|
|
|
using namespace Sapphire::Network::Packets::WorldPackets::Client;
|
|
|
|
using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pHive,
|
2020-03-01 01:00:57 +11:00
|
|
|
Sapphire::Network::AcceptorPtr pAcceptor ) :
|
2021-11-27 00:53:57 +01:00
|
|
|
Connection( std::move( pHive ) ),
|
|
|
|
m_pAcceptor( std::move( pAcceptor ) ),
|
2018-11-29 16:55:48 +01:00
|
|
|
m_conType( ConnectionType::None )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
auto setZoneHandler = [ = ]( uint16_t opcode, std::string handlerName, GameConnection::Handler pHandler )
|
|
|
|
{
|
|
|
|
m_zoneHandlerMap[ opcode ] = pHandler;
|
2021-11-27 00:53:57 +01:00
|
|
|
m_zoneHandlerStrMap[ opcode ] = std::move( handlerName );
|
2018-08-29 21:40:59 +02:00
|
|
|
};
|
2017-08-22 21:36:20 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto setChatHandler = [ = ]( uint16_t opcode, std::string handlerName, GameConnection::Handler pHandler )
|
|
|
|
{
|
|
|
|
m_chatHandlerMap[ opcode ] = pHandler;
|
2021-11-27 00:53:57 +01:00
|
|
|
m_chatHandlerStrMap[ opcode ] = std::move( handlerName );
|
2018-08-29 21:40:59 +02:00
|
|
|
};
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( Sync, "syncHandler", &GameConnection::syncHandler );
|
|
|
|
setZoneHandler( ClientZoneIpcType::Login, "loginHandler", &GameConnection::loginHandler );
|
|
|
|
setZoneHandler( ChatHandler, "ChatHandler", &GameConnection::chatHandler );
|
|
|
|
setZoneHandler( JoinChatChannel, "JoinChatChannel", &GameConnection::joinChatChannelHandler );
|
|
|
|
|
|
|
|
setZoneHandler( SetLanguage, "SetLanguage", &GameConnection::setLanguageHandler );
|
|
|
|
|
|
|
|
setZoneHandler( StartLogoutCountdown, "StartLogoutCountdown", &GameConnection::logoutHandler );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( SetProfile, "SetProfile", &GameConnection::setProfileHandler );
|
|
|
|
setZoneHandler( GetProfile, "GetProfile", &GameConnection::getProfileHandler );
|
|
|
|
setZoneHandler( GetSearchComment, "GetSearchComment", &GameConnection::getSearchCommentHandler );
|
|
|
|
setZoneHandler( PcSearch, "PcSearch", &GameConnection::pcSearchHandler );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( GetCommonlist, "GetCommonlist", &GameConnection::getCommonlistHandler );
|
|
|
|
setZoneHandler( GetCommonlistDetail, "GetCommonlistDetail", &GameConnection::getCommonlistDetailHandler );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( GetLinkshellList, "GetLinkshellList", &GameConnection::linkshellListHandler );
|
|
|
|
setZoneHandler( LinkshellJoin, "LinkshellJoin", &GameConnection::linkshellJoinHandler );
|
2021-12-09 23:38:23 +01:00
|
|
|
setZoneHandler( LinkshellKick, "LinkshellKick", &GameConnection::linkshellKickHandler );
|
2021-12-12 15:56:45 +01:00
|
|
|
setZoneHandler( LinkshellLeave, "LinkshellLeave", &GameConnection::linkshellLeaveHandler );
|
|
|
|
setZoneHandler( LinkshellChangeMaster, "LinkshellChangeMaster", &GameConnection::linkshellChangeMasterHandler );
|
|
|
|
setZoneHandler( LinkshellJoinOfficial, "LinkshellJoinOfficial", &GameConnection::linkshellJoinOfficialHandler );
|
2021-12-12 13:06:15 +01:00
|
|
|
setZoneHandler( LinkshellAddLeader, "LinkshellAddLeader", &GameConnection::linkshellAddLeaderHandler );
|
|
|
|
setZoneHandler( LinkshellRemoveLeader, "LinkshellRemoveLeader", &GameConnection::linkshellRemoveLeaderHandler );
|
|
|
|
setZoneHandler( LinkshellDeclineLeader, "LinkshellDeclineLeader", &GameConnection::linkshellDeclineLeaderHandler );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( ReqExamineFcInfo, "ReqExamineFcInfo", &GameConnection::reqExamineFcInfo );
|
|
|
|
setZoneHandler( ZoneJump, "ZoneJump", &GameConnection::zoneJumpHandler );
|
|
|
|
setZoneHandler( Command, "Command", &GameConnection::commandHandler );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( NewDiscovery, "NewDiscovery", &GameConnection::newDiscoveryHandler );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( ActionRequest, "ActionRequest", &GameConnection::actionRequest );
|
|
|
|
setZoneHandler( SelectGroundActionRequest, "SelectGroundActionRequest", &GameConnection::selectGroundActionRequest );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( GMCommand, "GMCommand", &GameConnection::gmCommandHandler );
|
|
|
|
setZoneHandler( GMCommandName, "GMCommandName", &GameConnection::gmCommandNameHandler );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( Move, "Move", &GameConnection::moveHandler );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( ClientItemOperation, "ItemOperation", &GameConnection::itemOperation );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2023-01-25 12:07:23 +01:00
|
|
|
setZoneHandler( BuildPresetHandler, "BuildPresetHandler", &GameConnection::buildPresetHandler );
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( ClientZoneIpcType::HousingHouseName, "HousingHouseName", &GameConnection::landRenameHandler );
|
|
|
|
setZoneHandler( ClientZoneIpcType::HousingGreeting, "HousingUpdateHouseGreeting", &GameConnection::housingUpdateGreetingHandler );
|
|
|
|
setZoneHandler( HousingPlaceYardItem, "HousingPlaceYardItem", &GameConnection::reqPlaceHousingItem );
|
|
|
|
setZoneHandler( HousingExteriorChange, "HousingExteriorChange", &GameConnection::reqMoveHousingItem );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( StartTalkEvent, "StartTalkEvent", &GameConnection::eventHandlerTalk );
|
|
|
|
setZoneHandler( StartEmoteEvent, "StartEmoteEvent", &GameConnection::eventHandlerEmote );
|
|
|
|
setZoneHandler( StartWithinRangeEvent, "StartWithinRangeEvent", &GameConnection::eventHandlerWithinRange );
|
|
|
|
setZoneHandler( StartOutsideRangeEvent, "StartOutsideRangeEvent", &GameConnection::eventHandlerOutsideRange );
|
|
|
|
setZoneHandler( StartEnterTerritoryEvent, "StartEnterTerritoryEvent", &GameConnection::eventHandlerEnterTerritory );
|
2018-11-28 21:59:28 +11:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( ReturnEventSceneHeader, "ReturnEventSceneHeader", &GameConnection::returnEventSceneHeader );
|
|
|
|
setZoneHandler( ReturnEventScene2, "ReturnEventScene2", &GameConnection::returnEventScene2 );
|
|
|
|
setZoneHandler( ReturnEventScene4, "ReturnEventScene4", &GameConnection::returnEventScene4 );
|
|
|
|
setZoneHandler( ReturnEventScene8, "ReturnEventScene8", &GameConnection::returnEventScene8 );
|
|
|
|
setZoneHandler( ReturnEventScene16, "ReturnEventScene16", &GameConnection::returnEventScene16 );
|
|
|
|
setZoneHandler( ReturnEventScene32, "ReturnEventScene32", &GameConnection::returnEventScene32 );
|
|
|
|
setZoneHandler( ReturnEventScene64, "ReturnEventScene64", &GameConnection::returnEventScene64 );
|
|
|
|
setZoneHandler( ReturnEventScene128, "ReturnEventScene128", &GameConnection::returnEventScene128 );
|
|
|
|
setZoneHandler( ReturnEventScene255, "ReturnEventScene255", &GameConnection::returnEventScene255 );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-12-13 00:44:42 +01:00
|
|
|
setZoneHandler( YieldEventSceneHeader, "YieldEventSceneHeader", &GameConnection::yieldEventSceneHeader );
|
|
|
|
setZoneHandler( YieldEventScene2, "YieldEventScene2", &GameConnection::yieldEventScene2 );
|
|
|
|
setZoneHandler( YieldEventScene4, "YieldEventScene4", &GameConnection::yieldEventScene4 );
|
|
|
|
setZoneHandler( YieldEventScene8, "YieldEventScene8", &GameConnection::yieldEventScene8 );
|
|
|
|
setZoneHandler( YieldEventScene16, "YieldEventScene16", &GameConnection::yieldEventScene16 );
|
|
|
|
setZoneHandler( YieldEventScene32, "YieldEventScene32", &GameConnection::yieldEventScene32 );
|
|
|
|
setZoneHandler( YieldEventScene64, "YieldEventScene64", &GameConnection::yieldEventScene64 );
|
|
|
|
setZoneHandler( YieldEventScene128, "YieldEventScene128", &GameConnection::yieldEventScene128 );
|
|
|
|
setZoneHandler( YieldEventScene255, "YieldEventScene255", &GameConnection::yieldEventScene255 );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( StartUIEvent, "StartUIEvent", &GameConnection::startUiEvent );
|
2017-08-23 23:58:14 +02:00
|
|
|
|
2021-12-02 22:58:36 +01:00
|
|
|
setZoneHandler( YieldEventSceneString8, "YieldEventSceneString8", &GameConnection::yieldEventString );
|
|
|
|
setZoneHandler( YieldEventSceneString16, "YieldEventSceneString16", &GameConnection::yieldEventString );
|
|
|
|
setZoneHandler( YieldEventSceneString32, "YieldEventSceneString32", &GameConnection::yieldEventString );
|
2018-11-22 00:04:26 +01:00
|
|
|
|
2021-12-12 23:26:12 +01:00
|
|
|
setZoneHandler( YieldEventSceneIntAndString, "YieldEventSceneIntAndString", &GameConnection::yieldEventSceneIntAndString );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( RequestPenalties, "RequestPenalties", &GameConnection::cfRequestPenalties );
|
2023-01-22 10:06:21 +01:00
|
|
|
setZoneHandler( RequestBonus, "RequestBonus", &GameConnection::requestBonus );
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( FindContent, "FindContent", &GameConnection::findContent );
|
|
|
|
setZoneHandler( Find5Contents, "Find5Contents", &GameConnection::find5Contents );
|
|
|
|
setZoneHandler( FindContentAsRandom, "FindContentAsRandom", &GameConnection::findContentAsRandom );
|
|
|
|
setZoneHandler( CFCommenceHandler, "CFDutyAccepted", &GameConnection::cfDutyAccepted );
|
|
|
|
setZoneHandler( CancelFindContent, "CancelFindContent", &GameConnection::cancelFindContent );
|
|
|
|
setZoneHandler( AcceptContent, "AcceptContent", &GameConnection::acceptContent );
|
2017-08-12 23:20:26 +09:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( ClientZoneIpcType::Config, "Config", &GameConnection::configHandler );
|
2017-08-12 23:20:26 +09:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( CatalogSearch, "CatalogSearch", &GameConnection::catalogSearch );
|
2022-02-18 02:24:18 +01:00
|
|
|
|
|
|
|
setZoneHandler( GearSetEquip, "GearSetEquip", &GameConnection::gearSetEquip );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( MarketBoardRequestItemListingInfo, "MarketBoardRequestItemListingInfo", &GameConnection::marketBoardRequestItemInfo );
|
|
|
|
setZoneHandler( MarketBoardRequestItemListings, "MarketBoardRequestItemListings", &GameConnection::marketBoardRequestItemListings );
|
2017-11-22 00:29:42 +09:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setChatHandler( ClientChatIpcType::ChatTo, "ChatTo", &GameConnection::tellHandler );
|
|
|
|
setChatHandler( ClientChatIpcType::ChatToChannel, "ChatToChannel", &GameConnection::chatToChannelHandler );
|
2017-08-22 21:36:20 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( GetFcStatus, "GetFcStatus", &GameConnection::getFcStatus );
|
|
|
|
setZoneHandler( GetFcProfile, "GetFcProfile", &GameConnection::getFcProfile );
|
2019-01-01 11:51:48 +11:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( GetRequestItemList, "GetRequestItemList", &GameConnection::getRequestItemListHandler );
|
2020-06-15 08:34:10 +09:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
setZoneHandler( Invite, "Invite", &GameConnection::inviteHandler );
|
|
|
|
setZoneHandler( InviteReply, "InviteReply", &GameConnection::inviteReplyHandler );
|
|
|
|
|
|
|
|
setZoneHandler( PcPartyLeave, "PcPartyLeave", &GameConnection::pcPartyLeaveHandler );
|
|
|
|
setZoneHandler( PcPartyDisband, "PcPartyDisband", &GameConnection::pcPartyDisbandHandler );
|
|
|
|
setZoneHandler( PcPartyKick, "PcPartyKick", &GameConnection::pcPartyKickHandler );
|
|
|
|
setZoneHandler( PcPartyChangeLeader, "PcPartyChangeLeader", &GameConnection::pcPartyChangeLeaderHandler );
|
2017-08-22 21:36:20 +02:00
|
|
|
|
2021-12-01 21:30:12 -03:00
|
|
|
setZoneHandler( FriendlistRemove, "FriendlistRemove", &GameConnection::friendlistRemoveHandler );
|
|
|
|
setZoneHandler( SetFriendlistGroup, "SetFriendlistGroup", &GameConnection::setFriendlistGroupHandler );
|
2021-12-05 00:04:11 +01:00
|
|
|
|
2021-12-13 22:36:29 -03:00
|
|
|
setZoneHandler( GetBlacklist, "GetBlacklist", &GameConnection::getBlacklistHandler );
|
|
|
|
setZoneHandler( BlacklistAdd, "BlacklistAdd", &GameConnection::blacklistAddHandler );
|
|
|
|
setZoneHandler( BlacklistRemove, "BlacklistRemove", &GameConnection::blacklistRemoveHandler );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
Sapphire::Network::GameConnection::~GameConnection() = default;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
|
|
|
|
// overwrite the parents onConnect for our game socket needs
|
2019-03-08 09:43:56 +01:00
|
|
|
void Sapphire::Network::GameConnection::onAccept( const std::string& host, uint16_t port )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
GameConnectionPtr connection( new GameConnection( m_hive, m_pAcceptor ) );
|
2019-03-08 09:43:56 +01:00
|
|
|
m_pAcceptor->accept( connection );
|
2021-11-27 00:53:57 +01:00
|
|
|
Logger::info( "Connect from {0}:{1}", m_socket.remote_endpoint().address().to_string(), m_socket.remote_endpoint().port() );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-08 09:43:56 +01:00
|
|
|
void Sapphire::Network::GameConnection::onDisconnect()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2021-12-22 23:17:35 +01:00
|
|
|
if( m_pSession )
|
|
|
|
Logger::debug( "[{0}] Disconnect", m_pSession->getId() );
|
|
|
|
else
|
|
|
|
Logger::debug( "Disconnect of lost session." );
|
2021-11-27 00:53:57 +01:00
|
|
|
m_pSession.reset();
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2019-03-08 09:43:56 +01:00
|
|
|
void Sapphire::Network::GameConnection::onRecv( std::vector< uint8_t >& buffer )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-03-24 22:12:36 +11:00
|
|
|
m_packets.insert( std::end( m_packets ), std::begin( buffer ), std::end( buffer ) );
|
2018-08-29 21:40:59 +02:00
|
|
|
// This is assumed packet always start with valid FFXIVARR_PACKET_HEADER for now.
|
|
|
|
Packets::FFXIVARR_PACKET_HEADER packetHeader{};
|
2019-03-20 09:15:57 +01:00
|
|
|
const auto headerResult = Packets::getHeader( m_packets, 0, packetHeader );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2019-03-24 22:12:36 +11:00
|
|
|
if( headerResult == Incomplete )
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
|
|
|
|
2019-03-24 22:12:36 +11:00
|
|
|
if( headerResult == Malformed )
|
|
|
|
{
|
|
|
|
Logger::info( "Dropping connection due to malformed packet header." );
|
|
|
|
disconnect();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Dissect packet list
|
|
|
|
std::vector< Packets::FFXIVARR_PACKET_RAW > packetList;
|
2019-03-20 09:15:57 +01:00
|
|
|
const auto packetResult = Packets::getPackets( m_packets, sizeof( struct FFXIVARR_PACKET_HEADER ),
|
2018-08-29 21:40:59 +02:00
|
|
|
packetHeader, packetList );
|
|
|
|
|
2019-03-24 22:12:36 +11:00
|
|
|
if( packetResult == Incomplete )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( packetResult == Malformed )
|
|
|
|
{
|
|
|
|
Logger::info( "Dropping connection due to malformed packets." );
|
|
|
|
disconnect();
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
2019-03-24 22:12:36 +11:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
// Handle it
|
|
|
|
handlePackets( packetHeader, packetList );
|
2019-03-20 09:15:57 +01:00
|
|
|
m_packets.clear();
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2019-03-08 09:43:56 +01:00
|
|
|
void Sapphire::Network::GameConnection::onError( const asio::error_code& error )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-01-04 22:37:01 +11:00
|
|
|
Logger::debug( "GameConnection ERROR: {0}", error.message() );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::queueInPacket( Sapphire::Network::Packets::FFXIVARR_PACKET_RAW inPacket )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
m_inQueue.push( inPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::queueOutPacket( Sapphire::Network::Packets::FFXIVPacketBasePtr outPacket )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
m_outQueue.push( outPacket );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::Network::GameConnection::queueOutPacket( std::vector< Packets::FFXIVPacketBasePtr > vector )
|
|
|
|
{
|
|
|
|
for( auto& packet : vector )
|
|
|
|
{
|
|
|
|
m_outQueue.push( packet );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::handleZonePacket( Sapphire::Network::Packets::FFXIVARR_PACKET_RAW& pPacket )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2021-12-06 00:39:22 +01:00
|
|
|
uint16_t opcode = Util::getOpCode( pPacket );
|
2018-08-29 21:40:59 +02:00
|
|
|
auto it = m_zoneHandlerMap.find( opcode );
|
|
|
|
|
|
|
|
if( it != m_zoneHandlerMap.end() )
|
|
|
|
{
|
|
|
|
auto itStr = m_zoneHandlerStrMap.find( opcode );
|
|
|
|
std::string name = itStr != m_zoneHandlerStrMap.end() ? itStr->second : "unknown";
|
|
|
|
// dont display packet notification if it is a ping or pos update, don't want the spam
|
2021-11-27 00:53:57 +01:00
|
|
|
if( opcode != Sync && opcode != Client::Move )
|
|
|
|
Logger::debug( "[{0}] Zone IPC : {1} ( {2:04X} )", m_pSession->getId(), name, opcode );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
( this->*( it->second ) )( pPacket, *m_pSession->getPlayer() );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto packetName = zonePacketToString( opcode );
|
|
|
|
auto player = m_pSession->getPlayer();
|
|
|
|
PlayerMgr::sendUrgent( *player, "Unimplemented zone IPC: {} ({:04X}) len: {}", packetName, opcode, pPacket.data.size() );
|
2019-04-07 13:27:56 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
Logger::debug( "[{}] Unimplemented World IPC : {} ({:04X})", m_pSession->getId(), packetName, opcode );
|
|
|
|
|
|
|
|
Logger::debug(
|
|
|
|
"Dump:\n{0}",
|
|
|
|
Util::binaryToHexDump( const_cast< uint8_t* >( &pPacket.data[ 0 ] ),
|
|
|
|
static_cast< uint16_t >( pPacket.segHdr.size - 0x10 ) )
|
|
|
|
);
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-22 21:36:20 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::handleChatPacket( Sapphire::Network::Packets::FFXIVARR_PACKET_RAW& pPacket )
|
2017-08-22 21:36:20 +02:00
|
|
|
{
|
2021-12-06 00:39:22 +01:00
|
|
|
uint16_t opcode = Util::getOpCode( pPacket );
|
2018-08-29 21:40:59 +02:00
|
|
|
auto it = m_chatHandlerMap.find( opcode );
|
|
|
|
|
|
|
|
if( it != m_chatHandlerMap.end() )
|
|
|
|
{
|
|
|
|
auto itStr = m_chatHandlerStrMap.find( opcode );
|
|
|
|
std::string name = itStr != m_chatHandlerStrMap.end() ? itStr->second : "unknown";
|
|
|
|
// dont display packet notification if it is a ping or pos update, don't want the spam
|
|
|
|
|
2019-01-04 22:48:09 +11:00
|
|
|
Logger::debug( "[{0}] Handling Chat IPC : {1} ( {2:04X} )", m_pSession->getId(), name, opcode );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
( this->*( it->second ) )( pPacket, *m_pSession->getPlayer() );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-01-04 22:48:09 +11:00
|
|
|
Logger::debug( "[{0}] Undefined Chat IPC : Unknown ( {1:04X} )", m_pSession->getId(), opcode );
|
2021-11-27 00:53:57 +01:00
|
|
|
|
|
|
|
Logger::debug(
|
|
|
|
"Dump:\n{0}",
|
|
|
|
Util::binaryToHexDump( const_cast< uint8_t* >( &pPacket.data[ 0 ] ),
|
|
|
|
static_cast< uint16_t >( pPacket.segHdr.size ) )
|
|
|
|
);
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-22 21:36:20 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::handlePacket( Sapphire::Network::Packets::FFXIVARR_PACKET_RAW& pPacket )
|
2017-08-22 21:36:20 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !m_pSession )
|
|
|
|
return;
|
2017-08-22 21:36:20 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
switch( m_conType )
|
|
|
|
{
|
|
|
|
case Network::ConnectionType::Zone:
|
|
|
|
handleZonePacket( pPacket );
|
|
|
|
break;
|
2017-08-22 21:36:20 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
case Network::ConnectionType::Chat:
|
|
|
|
handleChatPacket( pPacket );
|
|
|
|
break;
|
2018-08-23 23:19:25 +10:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::sendPackets( Packets::PacketContainer* pPacket )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > sendBuffer;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
pPacket->fillSendBuffer( sendBuffer );
|
2019-03-08 09:43:56 +01:00
|
|
|
send( sendBuffer );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::processInQueue()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
// handle the incoming game packets
|
|
|
|
while( m_inQueue.size() )
|
|
|
|
{
|
|
|
|
auto pPacket = m_inQueue.pop();
|
|
|
|
handlePacket( pPacket );
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::processOutQueue()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
if( m_outQueue.size() < 1 )
|
|
|
|
return;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
size_t totalSize = 0;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// create a new packet container
|
|
|
|
PacketContainer pRP = PacketContainer( m_pSession->getId() );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// get next packet off the queue
|
|
|
|
while( auto pPacket = m_outQueue.pop() )
|
|
|
|
{
|
|
|
|
if( pPacket->getSize() == 0 )
|
|
|
|
{
|
2018-12-23 03:53:08 +01:00
|
|
|
Logger::debug( "end of packet set" );
|
2018-08-29 21:40:59 +02:00
|
|
|
break;
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
pRP.addPacket( pPacket );
|
|
|
|
totalSize += pPacket->getSize();
|
2018-11-25 23:20:56 +11:00
|
|
|
|
|
|
|
// todo: figure out a good max set size and make it configurable
|
2019-01-15 18:20:21 +11:00
|
|
|
if( totalSize > 10000 )
|
2018-11-25 23:20:56 +11:00
|
|
|
break;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( totalSize > 0 )
|
|
|
|
sendPackets( &pRP );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::sendSinglePacket( Sapphire::Network::Packets::FFXIVPacketBasePtr pPacket )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
PacketContainer pRP = PacketContainer();
|
|
|
|
pRP.addPacket( pPacket );
|
|
|
|
sendPackets( &pRP );
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::injectPacket( const std::string& packetpath, Sapphire::Entity::Player& player )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
|
|
|
|
2018-12-23 03:53:08 +01:00
|
|
|
char packet[ 0x11570 ];
|
2018-08-29 21:40:59 +02:00
|
|
|
memset( packet, 0, 0x11570 );
|
|
|
|
|
|
|
|
// get the packet name / path from the command arguments
|
|
|
|
FILE* fp = nullptr;
|
|
|
|
fp = fopen( packetpath.c_str(), "rb" );
|
|
|
|
if( fp == nullptr )
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
PlayerMgr::sendDebug( player, "Packet {0} not found!", packetpath );
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read the packet into the buffer
|
|
|
|
fseek( fp, 0, SEEK_END );
|
2018-12-23 03:53:08 +01:00
|
|
|
auto size = static_cast< size_t >( ftell( fp ) );
|
2018-08-29 21:40:59 +02:00
|
|
|
rewind( fp );
|
|
|
|
if( fread( packet, sizeof( char ), size, fp ) != size )
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
PlayerMgr::sendDebug( player, "Packet {0} did not read full size: {1}", packetpath, size );
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
fclose( fp );
|
|
|
|
|
|
|
|
// cycle through the packet entries and queue each one
|
|
|
|
for( int32_t k = 0x18; k < size; )
|
|
|
|
{
|
|
|
|
uint32_t tmpId = player.getId();
|
|
|
|
// replace ids in the entryheader if needed
|
|
|
|
if( !memcmp( packet + k + 0x04, packet + k + 0x08, 4 ) )
|
|
|
|
{
|
|
|
|
memcpy( packet + k + 0x04, &tmpId, 4 );
|
|
|
|
memcpy( packet + k + 0x08, &tmpId, 4 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
memcpy( packet + k + 0x08, &tmpId, 4 );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint16_t pSize = *reinterpret_cast< uint16_t* >( packet + k );
|
|
|
|
// queue packet to the session
|
|
|
|
if( pSize == 0 )
|
2017-11-01 22:24:50 -07:00
|
|
|
return;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
queueOutPacket( FFXIVPacketBasePtr( new FFXIVRawPacket( packet + k, pSize ) ) );
|
2018-07-04 22:13:06 +10:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
k += ( pSize );
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Network::GameConnection::handlePackets( const Sapphire::Network::Packets::FFXIVARR_PACKET_HEADER& ipcHeader,
|
|
|
|
const std::vector< Sapphire::Network::Packets::FFXIVARR_PACKET_RAW >& packetData )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& server = Common::Service< World::WorldServer >::ref();
|
2019-01-19 21:20:23 -02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// if a session is set, update the last time it recieved a game packet
|
|
|
|
if( m_pSession )
|
|
|
|
m_pSession->updateLastDataTime();
|
|
|
|
|
|
|
|
for( auto inPacket : packetData )
|
|
|
|
{
|
|
|
|
switch( inPacket.segHdr.type )
|
|
|
|
{
|
2018-07-06 21:53:35 +10:00
|
|
|
case SEGMENTTYPE_SESSIONINIT:
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-12-26 11:09:15 +03:00
|
|
|
char* id = reinterpret_cast< char* >( &( inPacket.data[ 4 ] ) );
|
2021-11-27 00:53:57 +01:00
|
|
|
uint32_t entityId = std::stoul( id );
|
2018-10-25 12:44:51 +11:00
|
|
|
auto pCon = std::static_pointer_cast< GameConnection, Connection >( shared_from_this() );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
// try to retrieve the session for this id
|
2021-11-27 00:53:57 +01:00
|
|
|
auto session = server.getSession( entityId );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
if( !session )
|
|
|
|
{
|
2019-01-04 22:37:01 +11:00
|
|
|
Logger::info( "[{0}] Session not registered, creating", id );
|
2018-08-29 21:40:59 +02:00
|
|
|
// return;
|
2021-11-27 00:53:57 +01:00
|
|
|
if( !server.createSession( entityId ) )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-03-08 09:43:56 +01:00
|
|
|
disconnect();
|
2017-10-06 12:54:03 +02:00
|
|
|
return;
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
session = server.getSession( entityId );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
//TODO: Catch more things in lobby and send real errors
|
2021-11-27 00:53:57 +01:00
|
|
|
else if( !session->isValid() || ( session->getPlayer() && session->getLastPing() != 0 ) )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2019-01-04 22:37:01 +11:00
|
|
|
Logger::error( "[{0}] Session INVALID, disconnecting", id );
|
2019-03-08 09:43:56 +01:00
|
|
|
disconnect();
|
2018-08-29 21:40:59 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if not set, set the session for this connection
|
|
|
|
if( !m_pSession && session )
|
|
|
|
m_pSession = session;
|
|
|
|
|
2018-10-25 12:44:51 +11:00
|
|
|
auto pe = std::make_shared< FFXIVRawPacket >( 0x07, 0x18, 0, 0 );
|
2022-01-20 21:37:14 +01:00
|
|
|
*reinterpret_cast< unsigned int* >( &pe->data()[ 0 ] ) = 0xE0001027;
|
2019-12-26 11:09:15 +03:00
|
|
|
*reinterpret_cast< unsigned int* >( &pe->data()[ 4 ] ) = Common::Util::getTimeSeconds();
|
2018-08-29 21:40:59 +02:00
|
|
|
sendSinglePacket( pe );
|
|
|
|
|
|
|
|
// main connection, assinging it to the session
|
|
|
|
if( ipcHeader.connectionType == ConnectionType::Zone )
|
|
|
|
{
|
2018-10-25 12:44:51 +11:00
|
|
|
auto pe1 = std::make_shared< FFXIVRawPacket >( 0x02, 0x38, 0, 0 );
|
2021-11-27 00:53:57 +01:00
|
|
|
*reinterpret_cast< unsigned int* >( &pe1->data()[ 0 ] ) = entityId;
|
2022-01-20 21:37:14 +01:00
|
|
|
*reinterpret_cast< unsigned int* >( &pe1->data()[ 0x20 ] ) = entityId;
|
|
|
|
*reinterpret_cast< unsigned int* >( &pe1->data()[ 0x24 ] ) = Common::Util::getTimeSeconds();
|
|
|
|
*reinterpret_cast< unsigned int* >( &pe1->data()[ 0x0C ] ) = Common::Util::getTimeSeconds();
|
|
|
|
*reinterpret_cast< unsigned int* >( &pe1->data()[ 0x1C ] ) = Common::Util::getTimeSeconds();
|
|
|
|
*reinterpret_cast< unsigned int* >( &pe1->data()[ 0x18 ] ) = Common::Util::getTimeSeconds();
|
2018-08-29 21:40:59 +02:00
|
|
|
sendSinglePacket( pe1 );
|
2019-07-21 22:33:33 +10:00
|
|
|
Logger::info( "[{0}] Setting session for world connection", id );
|
2018-08-29 21:40:59 +02:00
|
|
|
session->setZoneConnection( pCon );
|
|
|
|
}
|
|
|
|
// chat connection, assinging it to the session
|
|
|
|
else if( ipcHeader.connectionType == ConnectionType::Chat )
|
|
|
|
{
|
2018-10-25 12:44:51 +11:00
|
|
|
auto pe2 = std::make_shared< FFXIVRawPacket >( 0x02, 0x38, 0, 0 );
|
2021-11-27 00:53:57 +01:00
|
|
|
*reinterpret_cast< unsigned int* >( &pe2->data()[ 0 ] ) = entityId;
|
2018-08-29 21:40:59 +02:00
|
|
|
sendSinglePacket( pe2 );
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto pe3 = std::make_shared< FFXIVRawPacket >( 0x03, 0x28, entityId, entityId );
|
2019-12-26 11:09:15 +03:00
|
|
|
*reinterpret_cast< unsigned short* >( &pe3->data()[ 2 ] ) = 0x02;
|
2018-08-29 21:40:59 +02:00
|
|
|
sendSinglePacket( pe3 );
|
|
|
|
|
2019-01-04 22:37:01 +11:00
|
|
|
Logger::info( "[{0}] Setting session for chat connection", id );
|
2018-08-29 21:40:59 +02:00
|
|
|
session->setChatConnection( pCon );
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
}
|
2018-07-06 21:53:35 +10:00
|
|
|
case SEGMENTTYPE_IPC: // game packet
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
queueInPacket( inPacket );
|
|
|
|
break;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
2018-07-06 21:53:35 +10:00
|
|
|
case SEGMENTTYPE_KEEPALIVE: // keep alive
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2019-12-26 11:09:15 +03:00
|
|
|
uint32_t id = *reinterpret_cast< uint32_t* >( &inPacket.data[ 0 ] );
|
|
|
|
uint32_t timeStamp = *reinterpret_cast< uint32_t* >( &inPacket.data[ 4 ] );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-10-25 12:44:51 +11:00
|
|
|
auto pe4 = std::make_shared< FFXIVRawPacket >( 0x08, 0x18, 0, 0 );
|
2019-12-26 11:09:15 +03:00
|
|
|
*reinterpret_cast< unsigned int* >( &pe4->data()[ 0 ] ) = id;
|
2022-01-16 19:40:21 +01:00
|
|
|
*reinterpret_cast< unsigned int* >( &pe4->data()[ 4 ] ) = Util::getTimeSeconds();
|
2018-08-29 21:40:59 +02:00
|
|
|
sendSinglePacket( pe4 );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
break;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
case 8:
|
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
break;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
|
|
|
|
const char* Sapphire::Network::GameConnection::zonePacketToString( uint32_t opcode )
|
|
|
|
{
|
|
|
|
switch( opcode )
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
return "unknown client IPC";
|
|
|
|
|
|
|
|
case Sync:
|
|
|
|
return "Sync";
|
|
|
|
|
|
|
|
case ClientZoneIpcType::Login:
|
|
|
|
return "Login";
|
|
|
|
|
|
|
|
case ChatHandler:
|
|
|
|
return "ChatHandler";
|
|
|
|
|
|
|
|
case SetLanguage:
|
|
|
|
return "SetLanguage";
|
|
|
|
|
|
|
|
case Invite:
|
|
|
|
return "Invite";
|
|
|
|
|
|
|
|
case InviteReply:
|
|
|
|
return "InviteReply";
|
|
|
|
|
|
|
|
case GetCommonlist:
|
|
|
|
return "GetCommonlist";
|
|
|
|
|
|
|
|
case GetCommonlistDetail:
|
|
|
|
return "GetCommonlistDetail";
|
|
|
|
|
|
|
|
case SetProfile:
|
|
|
|
return "SetProfile";
|
|
|
|
|
|
|
|
case GetProfile:
|
|
|
|
return "GetProfile";
|
|
|
|
|
|
|
|
case GetSearchComment:
|
|
|
|
return "GetSearchComment";
|
|
|
|
|
|
|
|
case PartyRecruitAdd:
|
|
|
|
return "PartyRecruitAdd";
|
|
|
|
|
|
|
|
case JoinChatChannel:
|
|
|
|
return "JoinChatChannel";
|
|
|
|
|
|
|
|
case LeaveChatChannel:
|
|
|
|
return "LeaveChatChannel";
|
|
|
|
|
|
|
|
case PartyRecruitRemove:
|
|
|
|
return "PartyRecruitRemove";
|
|
|
|
|
|
|
|
case PartyRecruitSearch:
|
|
|
|
return "PartyRecruitSearch";
|
|
|
|
|
|
|
|
case GetRecruitSearchList:
|
|
|
|
return "GetRecruitSearchList";
|
|
|
|
|
|
|
|
case GetRecruitDetail:
|
|
|
|
return "GetRecruitDetail";
|
|
|
|
|
|
|
|
case InviteReplyRecruitParty:
|
|
|
|
return "InviteReplyRecruitParty";
|
|
|
|
|
|
|
|
case PartyRecruitEdit:
|
|
|
|
return "PartyRecruitEdit";
|
|
|
|
|
|
|
|
case GetPurposeLevel:
|
|
|
|
return "GetPurposeLevel";
|
|
|
|
|
|
|
|
case AddRequestItem:
|
|
|
|
return "AddRequestItem";
|
|
|
|
|
|
|
|
case RemoveRequestItem:
|
|
|
|
return "RemoveRequestItem";
|
|
|
|
|
|
|
|
case PcPartyLeave:
|
|
|
|
return "PcPartyLeave";
|
|
|
|
|
|
|
|
case PcPartyDisband:
|
|
|
|
return "PcPartyDisband";
|
|
|
|
|
|
|
|
case PcPartyKick:
|
|
|
|
return "PcPartyKick";
|
|
|
|
|
|
|
|
case PcPartyChangeLeader:
|
|
|
|
return "PcPartyChangeLeader";
|
|
|
|
|
|
|
|
case GetRequestItem:
|
|
|
|
return "GetRequestItem";
|
|
|
|
|
|
|
|
case BlacklistAdd:
|
|
|
|
return "BlacklistAdd";
|
|
|
|
|
|
|
|
case BlacklistRemove:
|
|
|
|
return "BlacklistRemove";
|
|
|
|
|
|
|
|
case GetBlacklist:
|
|
|
|
return "GetBlacklist";
|
|
|
|
|
|
|
|
case GetRequestItemList:
|
|
|
|
return "GetRequestItemList";
|
|
|
|
|
|
|
|
case SendReadyCheck:
|
|
|
|
return "SendReadyCheck";
|
|
|
|
|
|
|
|
case FriendlistRemove:
|
|
|
|
return "FriendlistRemove";
|
|
|
|
|
|
|
|
case ReplyReadyCheck:
|
|
|
|
return "ReplyReadyCheck";
|
|
|
|
|
|
|
|
case GetPartyRecruitCount:
|
|
|
|
return "GetPartyRecruitCount";
|
|
|
|
|
|
|
|
case FcAddJoinRequest:
|
|
|
|
return "FcAddJoinRequest";
|
|
|
|
|
|
|
|
case FcRemoveJoinRequest:
|
|
|
|
return "FcRemoveJoinRequest";
|
|
|
|
|
|
|
|
case PcSearch:
|
|
|
|
return "PcSearch";
|
|
|
|
|
|
|
|
case GetFcJoinRequestComment:
|
|
|
|
return "GetFcJoinRequestComment";
|
|
|
|
|
|
|
|
case InviteCancel:
|
|
|
|
return "InviteCancel";
|
|
|
|
|
|
|
|
case LinkshellJoin:
|
|
|
|
return "LinkshellJoin";
|
|
|
|
|
|
|
|
case LinkshellJoinOfficial:
|
|
|
|
return "LinkshellJoinOfficial";
|
|
|
|
|
|
|
|
case LinkshellLeave:
|
|
|
|
return "LinkshellLeave";
|
|
|
|
|
|
|
|
case LinkshellChangeMaster:
|
|
|
|
return "LinkshellChangeMaster";
|
|
|
|
|
|
|
|
case LinkshellKick:
|
|
|
|
return "LinkshellKick";
|
|
|
|
|
|
|
|
case GetLinkshellList:
|
|
|
|
return "GetLinkshellList";
|
|
|
|
|
|
|
|
case LinkshellAddLeader:
|
|
|
|
return "LinkshellAddLeader";
|
|
|
|
|
|
|
|
case LinkshellRemoveLeader:
|
|
|
|
return "LinkshellRemoveLeader";
|
|
|
|
|
|
|
|
case LinkshellDeclineLeader:
|
|
|
|
return "LinkshellDeclineLeader";
|
|
|
|
|
|
|
|
case LetterSendMessage:
|
|
|
|
return "LetterSendMessage";
|
|
|
|
|
|
|
|
case LetterRemoveMessage:
|
|
|
|
return "LetterRemoveMessage";
|
|
|
|
|
|
|
|
case GetLetterMessage:
|
|
|
|
return "GetLetterMessage";
|
|
|
|
|
|
|
|
case GetLetterMessageDetail:
|
|
|
|
return "GetLetterMessageDetail";
|
|
|
|
|
|
|
|
case LetterMoveAppendItem:
|
|
|
|
return "LetterMoveAppendItem";
|
|
|
|
|
|
|
|
case CheckGiftMail:
|
|
|
|
return "CheckGiftMail";
|
|
|
|
|
|
|
|
case ItemSearch:
|
|
|
|
return "ItemSearch";
|
|
|
|
|
|
|
|
case GetItemSearchList:
|
|
|
|
return "GetItemSearchList";
|
|
|
|
|
|
|
|
case GetRetainerList:
|
|
|
|
return "GetRetainerList";
|
|
|
|
|
|
|
|
case BuyMarketRetainer:
|
|
|
|
return "BuyMarketRetainer";
|
|
|
|
|
|
|
|
case GetRetainerSalesHistory:
|
|
|
|
return "GetRetainerSalesHistory";
|
|
|
|
|
|
|
|
case CatalogSearch:
|
|
|
|
return "CatalogSearch";
|
|
|
|
|
|
|
|
case FreeCompanyLeave:
|
|
|
|
return "FreeCompanyLeave";
|
|
|
|
|
|
|
|
case FreeCompanyKick:
|
|
|
|
return "FreeCompanyKick";
|
|
|
|
|
|
|
|
case FcSetHierarchyName:
|
|
|
|
return "FcSetHierarchyName";
|
|
|
|
|
|
|
|
case FcSetAuthorityList:
|
|
|
|
return "FcSetAuthorityList";
|
|
|
|
|
|
|
|
case FcMoveHierarchyMember:
|
|
|
|
return "FcMoveHierarchyMember";
|
|
|
|
|
|
|
|
case FcAddHierarchy:
|
|
|
|
return "FcAddHierarchy";
|
|
|
|
|
|
|
|
case FcRemoveHierarchy:
|
|
|
|
return "FcRemoveHierarchy";
|
|
|
|
|
|
|
|
case FcSortHierarchy:
|
|
|
|
return "FcSortHierarchy";
|
|
|
|
|
|
|
|
case GetFcStatus:
|
|
|
|
return "GetFcStatus";
|
|
|
|
|
|
|
|
case FcForceDisband:
|
|
|
|
return "FcForceDisband";
|
|
|
|
|
|
|
|
case GetFcInviteList:
|
|
|
|
return "GetFcInviteList";
|
|
|
|
|
|
|
|
case GetFcProfile:
|
|
|
|
return "GetFcProfile";
|
|
|
|
|
|
|
|
case GetFcHeader:
|
|
|
|
return "GetFcHeader";
|
|
|
|
|
|
|
|
case SetCompanyBoard:
|
|
|
|
return "SetCompanyBoard";
|
|
|
|
|
|
|
|
case GetCompanyBoard:
|
|
|
|
return "GetCompanyBoard";
|
|
|
|
|
|
|
|
case GetFcHierarchy:
|
|
|
|
return "GetFcHierarchy";
|
|
|
|
|
|
|
|
case FcChangeMaster:
|
|
|
|
return "FcChangeMaster";
|
|
|
|
|
|
|
|
case GetFcActivityList:
|
|
|
|
return "GetFcActivityList";
|
|
|
|
|
|
|
|
case SetCompanyMotto:
|
|
|
|
return "SetCompanyMotto";
|
|
|
|
|
|
|
|
case GetCompanyMotto:
|
|
|
|
return "GetCompanyMotto";
|
|
|
|
|
|
|
|
case GetFcParams:
|
|
|
|
return "GetFcParams";
|
|
|
|
|
|
|
|
case SetCrestID:
|
|
|
|
return "SetCrestID";
|
|
|
|
|
|
|
|
case BuyFcAction:
|
|
|
|
return "BuyFcAction";
|
|
|
|
|
|
|
|
case FcActionCommand:
|
|
|
|
return "FcActionCommand";
|
|
|
|
|
|
|
|
case GetFcAction:
|
|
|
|
return "GetFcAction";
|
|
|
|
|
|
|
|
case SetFcMemo:
|
|
|
|
return "SetFcMemo";
|
|
|
|
|
|
|
|
case GetFcMemo:
|
|
|
|
return "GetFcMemo";
|
|
|
|
|
|
|
|
case InfoGMCommand:
|
|
|
|
return "InfoGMCommand";
|
|
|
|
|
|
|
|
case DebugInfoCommand:
|
|
|
|
return "DebugInfoCommand";
|
|
|
|
|
|
|
|
case RequestSyncTag:
|
|
|
|
return "RequestSyncTag";
|
|
|
|
|
|
|
|
case ZoneJump:
|
|
|
|
return "ZoneJump";
|
|
|
|
|
|
|
|
case Command:
|
|
|
|
return "Command";
|
|
|
|
|
|
|
|
case PhysicalBonus:
|
|
|
|
return "PhysicalBonus";
|
|
|
|
|
|
|
|
case NewDiscovery:
|
|
|
|
return "NewDiscovery";
|
|
|
|
|
|
|
|
case TargetPosCommand:
|
|
|
|
return "TargetPosCommand";
|
|
|
|
|
|
|
|
case ActionRequest:
|
|
|
|
return "ActionRequest";
|
|
|
|
|
|
|
|
case GMCommand:
|
|
|
|
return "GMCommand";
|
|
|
|
|
|
|
|
case GMCommandName:
|
|
|
|
return "GMCommandName";
|
|
|
|
|
|
|
|
case SelectGroundActionRequest:
|
|
|
|
return "SelectGroundActionRequest";
|
|
|
|
|
|
|
|
case Move:
|
|
|
|
return "Move";
|
|
|
|
|
|
|
|
case GMCommandBuddyName:
|
|
|
|
return "GMCommandBuddyName";
|
|
|
|
|
|
|
|
case GMCommandNameBuddyName:
|
|
|
|
return "GMCommandNameBuddyName";
|
|
|
|
|
|
|
|
case RequestStorageItems:
|
|
|
|
return "RequestStorageItems";
|
|
|
|
|
|
|
|
case ExchangeAttachedInactiveMateria:
|
|
|
|
return "ExchangeAttachedInactiveMateria";
|
|
|
|
|
|
|
|
case RetainerCustomize:
|
|
|
|
return "RetainerCustomize";
|
|
|
|
|
|
|
|
case ClientItemOperation:
|
|
|
|
return "ClientItemOperation";
|
|
|
|
|
|
|
|
case GearSetEquip:
|
|
|
|
return "GearSetEquip";
|
|
|
|
|
|
|
|
case HousingExteriorChange:
|
|
|
|
return "HousingExteriorChange";
|
|
|
|
|
|
|
|
case HousingPlaceYardItem:
|
|
|
|
return "HousingPlaceYardItem";
|
|
|
|
|
|
|
|
case HousingInteriorChange:
|
|
|
|
return "HousingInteriorChange";
|
|
|
|
|
|
|
|
case ClientZoneIpcType::TradeCommand:
|
|
|
|
return "TradeCommand";
|
|
|
|
|
|
|
|
case TreasureCheckCommand:
|
|
|
|
return "TreasureCheckCommand";
|
|
|
|
|
|
|
|
case SelectLootAction:
|
|
|
|
return "SelectLootAction";
|
|
|
|
|
|
|
|
case OpenTreasureWithKey:
|
|
|
|
return "OpenTreasureWithKey";
|
|
|
|
|
|
|
|
case StartTalkEvent:
|
|
|
|
return "StartTalkEvent";
|
|
|
|
|
|
|
|
case StartEmoteEvent:
|
|
|
|
return "StartEmoteEvent";
|
|
|
|
|
|
|
|
case StartWithinRangeEvent:
|
|
|
|
return "StartWithinRangeEvent";
|
|
|
|
|
|
|
|
case StartOutsideRangeEvent:
|
|
|
|
return "StartOutsideRangeEvent";
|
|
|
|
|
|
|
|
case StartEnterTerritoryEvent:
|
|
|
|
return "StartEnterTerritoryEvent";
|
|
|
|
|
|
|
|
case StartActionResultEvent:
|
|
|
|
return "StartActionResultEvent";
|
|
|
|
|
|
|
|
case StartUIEvent:
|
|
|
|
return "StartUIEvent";
|
|
|
|
|
|
|
|
case StartSayEvent:
|
|
|
|
return "StartSayEvent";
|
|
|
|
|
|
|
|
case ReturnEventSceneHeader:
|
|
|
|
return "ReturnEventSceneHeader";
|
|
|
|
|
|
|
|
case ReturnEventScene2:
|
|
|
|
return "ReturnEventScene2";
|
|
|
|
|
|
|
|
case ReturnEventScene4:
|
|
|
|
return "ReturnEventScene4";
|
|
|
|
|
|
|
|
case ReturnEventScene8:
|
|
|
|
return "ReturnEventScene8";
|
|
|
|
|
|
|
|
case ReturnEventScene16:
|
|
|
|
return "ReturnEventScene16";
|
|
|
|
|
|
|
|
case ReturnEventScene32:
|
|
|
|
return "ReturnEventScene32";
|
|
|
|
|
|
|
|
case ReturnEventScene64:
|
|
|
|
return "ReturnEventScene64";
|
|
|
|
|
|
|
|
case ReturnEventScene128:
|
|
|
|
return "ReturnEventScene128";
|
|
|
|
|
|
|
|
case ReturnEventScene255:
|
|
|
|
return "ReturnEventScene255";
|
|
|
|
|
|
|
|
case YieldEventSceneHeader:
|
|
|
|
return "YieldEventSceneHeader";
|
|
|
|
|
|
|
|
case YieldEventScene2:
|
|
|
|
return "YieldEventScene2";
|
|
|
|
|
|
|
|
case YieldEventScene4:
|
|
|
|
return "YieldEventScene4";
|
|
|
|
|
|
|
|
case YieldEventScene8:
|
|
|
|
return "YieldEventScene8";
|
|
|
|
|
|
|
|
case YieldEventScene16:
|
|
|
|
return "YieldEventScene16";
|
|
|
|
|
|
|
|
case YieldEventScene32:
|
|
|
|
return "YieldEventScene32";
|
|
|
|
|
|
|
|
case YieldEventScene64:
|
|
|
|
return "YieldEventScene64";
|
|
|
|
|
|
|
|
case YieldEventScene128:
|
|
|
|
return "YieldEventScene128";
|
|
|
|
|
|
|
|
case YieldEventScene255:
|
|
|
|
return "YieldEventScene255";
|
|
|
|
|
|
|
|
case YieldEventSceneStringHeader:
|
|
|
|
return "YieldEventSceneStringHeader";
|
|
|
|
|
|
|
|
case YieldEventSceneString8:
|
|
|
|
return "YieldEventSceneString8";
|
|
|
|
|
|
|
|
case YieldEventSceneString16:
|
|
|
|
return "YieldEventSceneString16";
|
|
|
|
|
|
|
|
case YieldEventSceneString32:
|
|
|
|
return "YieldEventSceneString32";
|
|
|
|
|
|
|
|
case YieldEventSceneIntAndString:
|
|
|
|
return "YieldEventSceneIntAndString";
|
|
|
|
|
|
|
|
case ClientZoneIpcType::DebugNull:
|
|
|
|
return "DebugNull";
|
|
|
|
|
|
|
|
case DebugCommand:
|
|
|
|
return "DebugCommand";
|
|
|
|
|
|
|
|
case DebugBnpcControl:
|
|
|
|
return "DebugBnpcControl";
|
|
|
|
|
|
|
|
case DebugMessage:
|
|
|
|
return "DebugMessage";
|
|
|
|
|
|
|
|
case FindContent:
|
|
|
|
return "FindContent";
|
|
|
|
|
|
|
|
case DebugFinishContent:
|
|
|
|
return "DebugFinishContent";
|
|
|
|
|
|
|
|
case AcceptContent:
|
|
|
|
return "AcceptContent";
|
|
|
|
|
|
|
|
case CancelFindContent:
|
|
|
|
return "CancelFindContent";
|
|
|
|
|
|
|
|
case Find5Contents:
|
|
|
|
return "Find5Contents";
|
|
|
|
|
|
|
|
case ClientZoneIpcType::FindContentAsRandom:
|
|
|
|
return "FindContentAsRandom";
|
|
|
|
|
|
|
|
case ChocoboTaxiPathEnd:
|
|
|
|
return "ChocoboTaxiPathEnd";
|
|
|
|
|
|
|
|
case ChocoboTaxiSetStep:
|
|
|
|
return "ChocoboTaxiSetStep";
|
|
|
|
|
|
|
|
case ChocoboTaxiUnmount:
|
|
|
|
return "ChocoboTaxiUnmount";
|
|
|
|
|
|
|
|
case ClientZoneIpcType::Config:
|
|
|
|
return "Config";
|
|
|
|
|
|
|
|
case StartLogoutCountdown:
|
|
|
|
return "StartLogoutCountdown";
|
|
|
|
|
|
|
|
case ClientZoneIpcType::CancelLogoutCountdown:
|
|
|
|
return "CancelLogoutCountdown";
|
|
|
|
|
|
|
|
case FateDebugCommand:
|
|
|
|
return "FateDebugCommand";
|
|
|
|
|
|
|
|
case ContentAction:
|
|
|
|
return "ContentAction";
|
|
|
|
|
|
|
|
case RequestPenalties:
|
|
|
|
return "RequestPenalties";
|
|
|
|
|
|
|
|
case Logout:
|
|
|
|
return "Logout";
|
|
|
|
|
|
|
|
case ClientZoneIpcType::HousingHouseName:
|
|
|
|
return "HousingHouseName";
|
|
|
|
|
|
|
|
case ClientZoneIpcType::HousingGreeting:
|
|
|
|
return "HousingGreeting";
|
|
|
|
|
|
|
|
case HousingChangeLayout:
|
|
|
|
return "HousingChangeLayout";
|
|
|
|
|
|
|
|
case VoteKickStart:
|
|
|
|
return "VoteKickStart";
|
|
|
|
|
|
|
|
case MVPRequest:
|
|
|
|
return "MVPRequest";
|
|
|
|
|
|
|
|
case HousingChangeLayoutMulti:
|
|
|
|
return "HousingChangeLayoutMulti";
|
|
|
|
|
|
|
|
case ConfusionApproachEnd:
|
|
|
|
return "ConfusionApproachEnd";
|
|
|
|
|
|
|
|
case ConfusionTurnEnd:
|
|
|
|
return "ConfusionTurnEnd";
|
|
|
|
|
|
|
|
case MovePvP:
|
|
|
|
return "MovePvP";
|
|
|
|
|
|
|
|
case CFCommenceHandler:
|
|
|
|
return "CFCommenceHandler";
|
|
|
|
|
|
|
|
case MarketBoardRequestItemListingInfo:
|
|
|
|
return "MarketBoardRequestItemListingInfo";
|
|
|
|
|
|
|
|
case MarketBoardRequestItemListings:
|
|
|
|
return "MarketBoardRequestItemListings";
|
|
|
|
|
|
|
|
case ReqExamineFcInfo:
|
|
|
|
return "ReqExamineFcInfo";
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|