From 1332d580df3ccfa717026c55d5c296f317756e9a Mon Sep 17 00:00:00 2001 From: Maru Date: Tue, 5 Dec 2017 04:13:13 -0200 Subject: [PATCH] Insane copypaste work!11!one --- .../Server_Common/Network/PacketDef/Ipcs.h | 3 +- .../Network/PacketDef/Zone/ServerZoneDef.h | 29 ++- src/servers/Server_Zone/Actor/Player.cpp | 27 ++ src/servers/Server_Zone/Actor/Player.h | 4 + .../Server_Zone/Network/GameConnection.h | 1 + .../Network/Handlers/PacketHandlers.cpp | 239 ++++++++++++++++-- 6 files changed, 277 insertions(+), 26 deletions(-) diff --git a/src/servers/Server_Common/Network/PacketDef/Ipcs.h b/src/servers/Server_Common/Network/PacketDef/Ipcs.h index 82ec4da7..04ea3d49 100644 --- a/src/servers/Server_Common/Network/PacketDef/Ipcs.h +++ b/src/servers/Server_Common/Network/PacketDef/Ipcs.h @@ -58,7 +58,8 @@ namespace Packets { SocialRequestError = 0x00AD, Playtime = 0x00B7, // updated 4.1 CFRegistered = 0x00B8, // updated 4.1 - SocialRequestResponse = 0x00BB, // updated 4.1 + SocialRequestResponse = 0x00BC, // updated 4.1 + SocialRequestReceive = 0x00BD, SocialList = 0x00BE, // updated 4.1 UpdateSearchInfo = 0x10BB, InitSearchInfo = 0x00C1, // updated 4.1 diff --git a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h index 77991860..701176ab 100644 --- a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h @@ -89,7 +89,7 @@ struct PlayerEntry { uint8_t searchComment; // bool char bytes1[6]; uint64_t onlineStatusMask; - uint8_t classJob; + Common::ClassJob classJob; uint8_t padding; uint16_t level; uint16_t padding2; @@ -98,8 +98,31 @@ struct PlayerEntry { char fcTag[9]; }; +struct FFXIVIpcSocialRequestReceive : FFXIVIpcBasePacket +{ + uint32_t actorId; // actor id of player which initiated request + uint16_t unknown; + uint16_t unknown2; + uint32_t timestamp; // must be greater than current time + uint8_t unknown3; + uint8_t unknown4; // Very likely cross-world related + Common::SocialCategory category; // 1 - party invite, 2 - friends request, 3 - ??, 4 - fc signature request, 5 - fc invite, + uint8_t unknown5; + Common::SocialRequestAction action; // 0 - ??, 1 - received, 2 - canceled, 4 - friend accept/fc sign/fc join, 5 - refuse fc petition/decline invite + uint8_t unknown6; + char name[0x20]; + uint16_t unknown7; + uint16_t unknown8; + uint16_t unknown9; +}; + struct FFXIVIpcSocialRequestError : FFXIVIpcBasePacket { + uint32_t messageId; // if 0 then type's message is used (type must 2/4/5 or it wont print) + Common::SocialCategory category; // 2 - friend request, 4 - fc petition, 5 - fc invitation, anything else and wont print + uint8_t unknown; // possibly padding + char name[0x20]; + uint8_t unknown3[2]; // probably padding }; @@ -107,8 +130,8 @@ struct FFXIVIpcSocialRequestResponse : FFXIVIpcBasePacket { uint64_t contentId; uint32_t unknown; - uint8_t category; // Common::SocialCategory - uint8_t response; // Common::SocialRequestResponse + Common::SocialCategory category; // Common::SocialCategory + Common::SocialRequestResponse response; // Common::SocialRequestResponse char name[0x20]; uint16_t padding; }; diff --git a/src/servers/Server_Zone/Actor/Player.cpp b/src/servers/Server_Zone/Actor/Player.cpp index 2caab4b3..6ad05126 100644 --- a/src/servers/Server_Zone/Actor/Player.cpp +++ b/src/servers/Server_Zone/Actor/Player.cpp @@ -900,6 +900,33 @@ Core::Entity::ActorPtr Core::Entity::Player::lookupTargetById( uint64_t targetId return targetActor; } +Core::Network::Packets::Server::PlayerEntry Core::Entity::Player::generatePlayerEntry() +{ + Core::Network::Packets::Server::PlayerEntry entry = {}; + + entry.bytes[2] = getCurrentZone()->getId(); + entry.bytes[3] = 0x80; + entry.bytes[4] = 0x02; + entry.bytes[6] = 0x3B; + entry.bytes[11] = 0x10; + entry.classJob = getClass(); + entry.contentId = getContentId(); + entry.level = getLevel(); + entry.zoneId = getCurrentZone()->getId(); + entry.grandCompany = getGc(); + memcpy( &entry.fcTag[0], "Meme", 9 ); + entry.clientLanguage = 2; + entry.knownLanguages = 0x0F; + // TODO: no idea what this does - me neither + //listPacket.data().entries[0].one = 1; + + memcpy( entry.name, getName().c_str(), strlen( getName().c_str() ) ); + + entry.onlineStatusMask = getOnlineStatusMask(); + + return entry; +} + void Core::Entity::Player::setLastPing( uint32_t ping ) { m_lastPing = ping; diff --git a/src/servers/Server_Zone/Actor/Player.h b/src/servers/Server_Zone/Actor/Player.h index 4688e5a5..9039c10c 100644 --- a/src/servers/Server_Zone/Actor/Player.h +++ b/src/servers/Server_Zone/Actor/Player.h @@ -4,6 +4,7 @@ #include "src/servers/Server_Zone/Forwards.h" #include +#include #include "Actor.h" #include "src/servers/Server_Zone/Inventory/Inventory.h" @@ -480,6 +481,9 @@ public: void sendUrgent( const std::string& message ); void sendDebug( const std::string& message ); + /*! generates a player entry used for lists (social, etc) */ + Core::Network::Packets::Server::PlayerEntry generatePlayerEntry(); + // Player Battle Handling ////////////////////////////////////////////////////////////////////////////////////////////////////// void onMobAggro( BattleNpcPtr pBNpc ); diff --git a/src/servers/Server_Zone/Network/GameConnection.h b/src/servers/Server_Zone/Network/GameConnection.h index 97332266..9ca1ff9e 100644 --- a/src/servers/Server_Zone/Network/GameConnection.h +++ b/src/servers/Server_Zone/Network/GameConnection.h @@ -89,6 +89,7 @@ public: DECLARE_HANDLER( initHandler ); DECLARE_HANDLER( finishLoadingHandler ); DECLARE_HANDLER( blackListHandler ); + DECLARE_HANDLER( socialReqResponseHandler ); DECLARE_HANDLER( socialReqSendHandler ); DECLARE_HANDLER( socialListHandler ); DECLARE_HANDLER( linkshellListHandler ); diff --git a/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp b/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp index 96f4a58c..096488d4 100644 --- a/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp +++ b/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp @@ -444,25 +444,7 @@ void Core::Network::GameConnection::socialListHandler( const Packets::GamePacket int32_t entrysizes = sizeof( listPacket.data().entries ); memset( listPacket.data().entries, 0, sizeof( listPacket.data().entries ) ); - listPacket.data().entries[0].bytes[2] = pPlayer->getCurrentZone()->getId(); - 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 >( pPlayer->getClass() ); - listPacket.data().entries[0].contentId = pPlayer->getContentId(); - listPacket.data().entries[0].level = pPlayer->getLevel(); - listPacket.data().entries[0].zoneId = pPlayer->getCurrentZone()->getId(); - listPacket.data().entries[0].grandCompany = pPlayer->getGc(); - memcpy( &listPacket.data().entries[0].fcTag[0], "Sapphire", sizeof( "Sapphire" ) ); - listPacket.data().entries[0].clientLanguage = 2; - listPacket.data().entries[0].knownLanguages = 0x0F; - // TODO: no idea what this does - //listPacket.data().entries[0].one = 1; - - memcpy( listPacket.data().entries[0].name, pPlayer->getName().c_str(), strlen( pPlayer->getName().c_str() ) ); - - listPacket.data().entries[0].onlineStatusMask = pPlayer->getOnlineStatusMask(); + listPacket.data().entries[0] = pPlayer->generatePlayerEntry(); queueOutPacket( listPacket ); @@ -474,6 +456,29 @@ void Core::Network::GameConnection::socialListHandler( const Packets::GamePacket listPacket.data().type = 0x0B; listPacket.data().sequence = count; memset( listPacket.data().entries, 0, sizeof( listPacket.data().entries ) ); + + // todo: for now.. just grab all actors in range and add them in. just replace logic later by using manager + + uint8_t i = 0; + + for( auto actor : pPlayer->getInRangeActors() ) + { + auto pFriend = actor->getAsPlayer(); + if( pFriend ) + { + listPacket.data().entries[i] = pFriend->generatePlayerEntry(); + i++; + } + + // todo: remove this branch entirely when using manager. physically hurts + if( i >= 200 ) + { + break; + } + + } + + queueOutPacket( listPacket ); } else if( type == 0x0e ) @@ -483,10 +488,200 @@ void Core::Network::GameConnection::socialListHandler( const Packets::GamePacket } -void Core::Network::GameConnection::socialReqSendHandler(const Packets::GamePacket& inPacket, - Entity::PlayerPtr pPlayer) +void Core::Network::GameConnection::socialReqResponseHandler( const Packets::GamePacket& inPacket, + Entity::PlayerPtr pPlayer ) { - g_log.debug("send"); + auto targetId = inPacket.getValAt< uint32_t >( 0x20 ); + auto category = inPacket.getValAt< Common::SocialCategory >( 0x28 ); + auto action = inPacket.getValAt< Common::SocialRequestAction >( 0x29 ); + + ZoneChannelPacket< FFXIVIpcSocialRequestError > info( targetId, pPlayer->getId() ); + ZoneChannelPacket< FFXIVIpcSocialRequestResponse > response( targetId, pPlayer->getId() ); + + info.data().category = category; + response.data().category = category; + + //auto pQR = g_database.query( "SELECT Name FROM dbchara WHERE CharacterId = " + to_string( targetId ) ); + auto name = pPlayer->getName(); + /* + if( pQR->getRowCount() > 0 ) + { + name = pQR->fetch()->getString(); + } + else + { + // todo: enumerate these messages + std::array< uint32_t, 5> categoryError = { 0, + 320, // Unable to process party command. + 310, // Unable to process friend list command. + 3035, // Unable to reply. Free company invite invalid. // todo: find actual message + 3035, // Unable to reply. Free company invite invalid. + }; + + response.data().messageId = categoryError[category]; + response.data().category = category; // client only uses messageId if this is 1 for some reason + pPlayer->queuePacket( response ); + return; + }*/ + + g_log.debug( std::to_string( static_cast( action ) ) ); + + auto pSession = g_serverZone.getSession( targetId ); + + // todo: notify both inviter/invitee with 0x00CB packet + + if( pSession ) + { + g_log.debug( std::to_string(static_cast(action)) ); + } + response.data().response = Common::SocialRequestResponse::Accept; + memcpy( &( response.data().name ), name.c_str(), 32 ); + pPlayer->queuePacket( response ); +} + +void Core::Network::GameConnection::socialReqSendHandler( const Packets::GamePacket& inPacket, + Entity::PlayerPtr pPlayer ) +{ + // todo: handle all social request packets here + auto category = inPacket.getValAt< Common::SocialCategory >( 0x20 ); + auto name = std::string( inPacket.getStringAt( 0x21 ) ); + + auto pSession = g_serverZone.getSession( name ); + + // only the requester needs the response + ZoneChannelPacket< FFXIVIpcSocialRequestError > response( pPlayer->getId() ); + memcpy( &( response.data().name ), name.c_str(), 32 ); + + // todo: enumerate log messages + response.data().messageId = 319; // That name does not exist. Please confirm the spelling. + response.data().category = category; + + // todo: enumerate and move each of these cases into their classes? + if( pSession ) + { + bool successful = false; + Entity::PlayerPtr pRecipient = pSession->getPlayer(); + + std::array typeVar{ "", "PartyInvite", "FriendInvite", "FreeCompanyPetition", "FreeCompanyInvite" }; + + // todo: proper handling of invites already sent + // todo: move this to world server + // check if an invite has already been sent by me + /* + if( pRecipient->getTempVariable( typeVar[category] + "Id" ) ) + { + if( pRecipient->getTempVariable( typeVar[category] + "Id" ) == pPlayer->getId() ) + { + response.data().messageId = 328; // That player has already been invited. + pPlayer->queuePacket( response ); + } + return; + }*/ + + if( pRecipient->getId() == pPlayer->getId() ) + { + response.data().messageId = 321; // Unable to invite. + } + + switch( category ) + { + // party invite + case Core::Common::SocialCategory::Party: + { + /* + if( pRecipient->getParty() ) + { + response.data().messageId = 326; // That player is already in another party. + } + else if( pRecipient->getTempVariable( "PartyInviteId" ) == pPlayer->getId() ) + { + response.data().messageId = 328; // That player has already been invited. + } + else if( pPlayer->getParty() && pPlayer->getParty()->getPartyMemberCount() >= pPlayer->getParty()->getType() ) + { + response.data().messageId = 329; // Unable to invite. The party is full. + }*/ + if( !pRecipient->isLoadingComplete() ) // || pRecipient->getDuty() ) + { + response.data().messageId = 331; // Unable to invite. That player is currently bound by duty or in a different area. + } + else if( pRecipient->getOnlineStatus() == Common::OnlineStatus::Busy ) + { + response.data().messageId = 334; // Unable to send party invite. Player's online status is set to Busy. + } + else if( pRecipient->getOnlineStatus() == Common::OnlineStatus::ViewingCutscene ) + { + response.data().messageId = 336; // Unable to invite. That player is currently watching a cutscene. + } + else + { + successful = true; + } + // response.data().messageId = 62; // declines the party invite. + } + break; + + case Common::SocialCategory::Friends: + { + // todo: check if already on friends list or invite pending + /* + if( pPlayer->getFriendList()->find(name) ) + { + response.data().messageId = 312; // That player is already a friend or has been sent a request. + } + else if( pRecipient->getFriendList()->getSize() >= 200 ) + { + response.data().messageId = 314; // Unable to send friend request. The other player's friend list is full. + } + else if( pPlayer->getFriendList()->getSize() >= 200 ) + { + response.data().messageId = 313; // Your friend list is full. + } + */ + successful = true; + } + break; + + default: + break; + } + + if( successful ) + { + ZoneChannelPacket< FFXIVIpcSocialRequestReceive > packet( pPlayer->getId(), pRecipient->getId() ); + + std::array typeMessage{ 0, + 1, // You invite to a party. + 10, // You send a friend request to . + 1884, // You invite to your free company. + 3044, // Free company petition signature request sent to + }; + + // TODO: confirm the timers on retail + auto expireTime = time( nullptr ) + 120; + + // todo: fix this for cross zone parties (move to world server) + /* + pRecipient->setTempVariable( typeVar[category] + "Id", pPlayer->getId() ); + pRecipient->setTempVariable( typeVar[category] + "Timer", expireTime );*/ + + packet.data().actorId = pPlayer->getId(); + packet.data().category = category; + packet.data().action = Core::Common::SocialRequestAction::Invite; + packet.data().unknown3 = 80; + packet.data().unknown = 46; + packet.data().unknown2 = 64; + memcpy( &( packet.data().name ), pPlayer->getName().c_str(), 32 ); + + pRecipient->queuePacket( packet ); + pRecipient->sendDebug( "ding ding" ); + response.data().messageId = typeMessage[category]; + } + } + + pPlayer->queuePacket( response ); + // todo: handle party, friend request + g_log.debug("sent to " + name); } void Core::Network::GameConnection::chatHandler( const Packets::GamePacket& inPacket,