mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-25 11:07:45 +00:00
Implement party just enough to gpose.
This commit is contained in:
parent
d60b68cfa2
commit
e80d51ff72
11 changed files with 761 additions and 55 deletions
|
@ -367,7 +367,7 @@ namespace Sapphire::Network::ActorControl
|
||||||
AllotAttribute = 0x135,
|
AllotAttribute = 0x135,
|
||||||
|
|
||||||
ClearFieldMarkers = 0x13A,
|
ClearFieldMarkers = 0x13A,
|
||||||
CameraMode = 0x13B, // param12, 1 = camera mode enable, 0 = disable
|
CameraMode = 0x13B, // param11, 1 = enable, 0 = disable
|
||||||
CharaNameReq = 0x13D, // requests character name by content id
|
CharaNameReq = 0x13D, // requests character name by content id
|
||||||
HuntingLogDetails = 0x194,
|
HuntingLogDetails = 0x194,
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace Sapphire::Network::Packets
|
||||||
LogMessage = 0x00D0,
|
LogMessage = 0x00D0,
|
||||||
|
|
||||||
Chat = 0x0161, // updated 5.25
|
Chat = 0x0161, // updated 5.25
|
||||||
|
PartyChat = 0x0065, // updated 5.25
|
||||||
|
|
||||||
WorldVisitList = 0xF0FE, // added 4.5
|
WorldVisitList = 0xF0FE, // added 4.5
|
||||||
|
|
||||||
|
@ -145,7 +146,7 @@ namespace Sapphire::Network::Packets
|
||||||
ActorCast = 0x00C4, // updated 5.25
|
ActorCast = 0x00C4, // updated 5.25
|
||||||
SomeCustomiseChangePacketProbably = 0x00CD, // added 5.18
|
SomeCustomiseChangePacketProbably = 0x00CD, // added 5.18
|
||||||
|
|
||||||
PartyList = 0x0287, // updated 5.18
|
PartyList = 0x01B7, // updated 5.25
|
||||||
HateRank = 0x012E, // updated 5.25
|
HateRank = 0x012E, // updated 5.25
|
||||||
HateList = 0x02C4, // updated 5.25
|
HateList = 0x02C4, // updated 5.25
|
||||||
ObjectSpawn = 0x00D2, // updated 5.25
|
ObjectSpawn = 0x00D2, // updated 5.25
|
||||||
|
@ -228,6 +229,13 @@ namespace Sapphire::Network::Packets
|
||||||
|
|
||||||
EquipDisplayFlags = 0x010D, // updated 5.25
|
EquipDisplayFlags = 0x010D, // updated 5.25
|
||||||
|
|
||||||
|
ShopMessage = 0x00C1, // updated 5.25
|
||||||
|
LootMessage = 0x00B1, // updated 5.25
|
||||||
|
SocialInviteMessage = 0x02F0, // updated 5.25
|
||||||
|
SocialInviteMessage2 = 0x026E, // updated 5.25
|
||||||
|
SocialInviteResponseMessage = 0x0117, // updated 5.25
|
||||||
|
PartyMessage = 0x0284, // updated 5.25
|
||||||
|
|
||||||
/// Housing //////////////////////////////////////
|
/// Housing //////////////////////////////////////
|
||||||
|
|
||||||
LandSetInitialize = 0x0234, // updated 5.0
|
LandSetInitialize = 0x0234, // updated 5.0
|
||||||
|
@ -304,6 +312,7 @@ namespace Sapphire::Network::Packets
|
||||||
CreateCrossWorldLS = 0x00AF, // updated 4.3
|
CreateCrossWorldLS = 0x00AF, // updated 4.3
|
||||||
|
|
||||||
ChatHandler = 0x0189, // updated 5.25
|
ChatHandler = 0x0189, // updated 5.25
|
||||||
|
PartyChatHandler = 0x0065, // update 5.25
|
||||||
|
|
||||||
SocialListHandler = 0x0371, // updated 5.25
|
SocialListHandler = 0x0371, // updated 5.25
|
||||||
SetSearchInfoHandler = 0x00FA, // updated 5.25
|
SetSearchInfoHandler = 0x00FA, // updated 5.25
|
||||||
|
@ -380,8 +389,13 @@ namespace Sapphire::Network::Packets
|
||||||
PerformNoteHandler = 0x029B, // updated 4.3
|
PerformNoteHandler = 0x029B, // updated 4.3
|
||||||
|
|
||||||
WorldInteractionHandler = 0x0285, // updated 5.25
|
WorldInteractionHandler = 0x0285, // updated 5.25
|
||||||
ShopMessage = 0x00C1, // updated 5.25
|
|
||||||
LootMessage = 0x00B1, // updated 5.25
|
SocialInviteHandler = 0x02BA, // updated 5.25
|
||||||
|
SocialInviteResponseHandler = 0x02C7, // updated 5.25
|
||||||
|
PartySetLeaderHandler = 0x02A5, // updated 5.25
|
||||||
|
LeavePartyHandler = 0x00C0, // updated 5.25
|
||||||
|
KickPartyMemberHandler = 0x0188, // update 5.25
|
||||||
|
DisbandPartyHandler = 0x0336, // update 5.25
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -207,6 +207,13 @@ struct FFXIVIpcChatHandler :
|
||||||
/* 001A */ char message[1012];
|
/* 001A */ char message[1012];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcPartyChatHandler :
|
||||||
|
FFXIVIpcBasePacket< ChatHandler >
|
||||||
|
{
|
||||||
|
uint64_t unknown;
|
||||||
|
char message[1024];
|
||||||
|
};
|
||||||
|
|
||||||
struct FFXIVIpcShopEventHandler :
|
struct FFXIVIpcShopEventHandler :
|
||||||
FFXIVIpcBasePacket< ShopEventHandler >
|
FFXIVIpcBasePacket< ShopEventHandler >
|
||||||
{
|
{
|
||||||
|
@ -355,6 +362,61 @@ struct FFXIVIpcWorldInteractionHandler :
|
||||||
Common::FFXIVARR_POSITION3 position;
|
Common::FFXIVARR_POSITION3 position;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcSocialInviteHandler :
|
||||||
|
FFXIVIpcBasePacket< SocialInviteHandler >
|
||||||
|
{
|
||||||
|
uint64_t unknown;
|
||||||
|
uint8_t p1;
|
||||||
|
uint8_t p2;
|
||||||
|
uint8_t socialType;
|
||||||
|
char name[32];
|
||||||
|
uint8_t padding[5];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcSocialInviteResponseHandler :
|
||||||
|
FFXIVIpcBasePacket< SocialInviteResponseHandler >
|
||||||
|
{
|
||||||
|
uint64_t contentId;
|
||||||
|
uint8_t p1;
|
||||||
|
uint8_t p2;
|
||||||
|
uint8_t socialType;
|
||||||
|
uint8_t response;
|
||||||
|
uint32_t unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcPartySetLeaderHandler :
|
||||||
|
FFXIVIpcBasePacket< PartySetLeaderHandler >
|
||||||
|
{
|
||||||
|
uint64_t contentId;
|
||||||
|
uint8_t p1;
|
||||||
|
uint8_t p2;
|
||||||
|
char name[32];
|
||||||
|
uint8_t padding[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcLeavePartyHandler :
|
||||||
|
FFXIVIpcBasePacket< LeavePartyHandler >
|
||||||
|
{
|
||||||
|
uint64_t empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcKickPartyMemberHander :
|
||||||
|
FFXIVIpcBasePacket< KickPartyMemberHandler >
|
||||||
|
{
|
||||||
|
uint64_t contentId;
|
||||||
|
uint8_t p1;
|
||||||
|
uint8_t p2;
|
||||||
|
char name[32];
|
||||||
|
uint8_t padding[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcDisbandPartyHandler :
|
||||||
|
FFXIVIpcBasePacket< DisbandPartyHandler >
|
||||||
|
{
|
||||||
|
uint64_t empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //_CORE_NETWORK_PACKETS_ZONE_CLIENT_IPC_H
|
#endif //_CORE_NETWORK_PACKETS_ZONE_CLIENT_IPC_H
|
||||||
|
|
|
@ -46,6 +46,19 @@ namespace Sapphire::Network::Packets::Server
|
||||||
char msg[1012];
|
char msg[1012];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcPartyChat : FFXIVIpcBasePacket< PartyChat >
|
||||||
|
{
|
||||||
|
uint64_t unknown;
|
||||||
|
uint64_t contentId;
|
||||||
|
uint32_t charaId;
|
||||||
|
uint8_t u1;
|
||||||
|
uint8_t u2;
|
||||||
|
uint8_t u3;
|
||||||
|
char name[32];
|
||||||
|
char message[1024];
|
||||||
|
uint8_t padding;
|
||||||
|
};
|
||||||
|
|
||||||
struct FFXIVIpcChatBanned : FFXIVIpcBasePacket< ChatBanned >
|
struct FFXIVIpcChatBanned : FFXIVIpcBasePacket< ChatBanned >
|
||||||
{
|
{
|
||||||
uint8_t padding[4]; // I was not sure reinterpreting ZST is valid behavior in C++.
|
uint8_t padding[4]; // I was not sure reinterpreting ZST is valid behavior in C++.
|
||||||
|
@ -2078,6 +2091,83 @@ namespace Sapphire::Network::Packets::Server
|
||||||
uint32_t param7;
|
uint32_t param7;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcSocialInviteMessage : FFXIVIpcBasePacket< SocialInviteMessage >
|
||||||
|
{
|
||||||
|
uint64_t contentId;
|
||||||
|
uint32_t expireTime;
|
||||||
|
uint8_t p1;
|
||||||
|
uint8_t p2;
|
||||||
|
uint8_t socialType;
|
||||||
|
uint8_t padding;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t unknown4;
|
||||||
|
char name[32];
|
||||||
|
uint8_t padding2[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcSocialInviteMessage2 : FFXIVIpcBasePacket< SocialInviteMessage2 >
|
||||||
|
{
|
||||||
|
uint64_t contentId;
|
||||||
|
uint32_t unknown3;
|
||||||
|
uint8_t p1;
|
||||||
|
uint8_t p2;
|
||||||
|
uint8_t socialType;
|
||||||
|
uint8_t padding;
|
||||||
|
char name[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcSocialInviteResponseMessage : FFXIVIpcBasePacket< SocialInviteResponseMessage >
|
||||||
|
{
|
||||||
|
uint64_t contentId;
|
||||||
|
uint32_t unknown3;
|
||||||
|
uint8_t u1AlwaysOne;
|
||||||
|
uint8_t response;
|
||||||
|
uint8_t u2AlwaysOne;
|
||||||
|
char name[32];
|
||||||
|
uint8_t padding;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcPartyList : FFXIVIpcBasePacket< PartyList >
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
char name[32];
|
||||||
|
uint64_t contentId;
|
||||||
|
uint32_t charaId;
|
||||||
|
uint32_t u1;
|
||||||
|
uint32_t u2;
|
||||||
|
uint32_t hp;
|
||||||
|
uint32_t maxHp;
|
||||||
|
uint16_t mp;
|
||||||
|
uint16_t maxMp;
|
||||||
|
uint16_t u3;
|
||||||
|
uint16_t zoneId;
|
||||||
|
uint8_t gposeSelectable;
|
||||||
|
uint8_t classId;
|
||||||
|
uint8_t u5;
|
||||||
|
uint8_t level;
|
||||||
|
uint8_t otherData[368];
|
||||||
|
} member[8];
|
||||||
|
uint64_t someContentId1;
|
||||||
|
uint64_t someContentId2;
|
||||||
|
uint8_t leaderIndex;
|
||||||
|
uint8_t partySize;
|
||||||
|
uint16_t padding1;
|
||||||
|
uint32_t padding2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcPartyMessage : FFXIVIpcBasePacket< PartyMessage >
|
||||||
|
{
|
||||||
|
uint64_t leaderContentId;
|
||||||
|
uint64_t memberContentId;
|
||||||
|
uint8_t u1;
|
||||||
|
uint8_t u2;
|
||||||
|
uint16_t type;
|
||||||
|
uint8_t partySize; // ?
|
||||||
|
char leaderName[32];
|
||||||
|
char memberName[32];
|
||||||
|
uint8_t padding[3];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*_CORE_NETWORK_PACKETS_SERVER_IPC_H*/
|
#endif /*_CORE_NETWORK_PACKETS_SERVER_IPC_H*/
|
||||||
|
|
|
@ -232,6 +232,10 @@ Sapphire::Common::OnlineStatus Sapphire::Entity::Player::getOnlineStatus() const
|
||||||
void Sapphire::Entity::Player::setOnlineStatusMask( uint64_t status )
|
void Sapphire::Entity::Player::setOnlineStatusMask( uint64_t status )
|
||||||
{
|
{
|
||||||
m_onlineStatus = status;
|
m_onlineStatus = status;
|
||||||
|
sendToInRangeSet( makeActorControl( getId(), SetStatusIcon, static_cast< uint8_t >( getOnlineStatus() ) ), true );
|
||||||
|
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( getId() );
|
||||||
|
statusPacket->data().onlineStatusFlags = status;
|
||||||
|
queuePacket( statusPacket );
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Sapphire::Entity::Player::getOnlineStatusMask() const
|
uint64_t Sapphire::Entity::Player::getOnlineStatusMask() const
|
||||||
|
@ -1047,7 +1051,6 @@ bool Sapphire::Entity::Player::hasStateFlag( Common::PlayerStateFlag flag ) cons
|
||||||
|
|
||||||
void Sapphire::Entity::Player::setStateFlag( Common::PlayerStateFlag flag )
|
void Sapphire::Entity::Player::setStateFlag( Common::PlayerStateFlag flag )
|
||||||
{
|
{
|
||||||
auto prevOnlineStatus = getOnlineStatus();
|
|
||||||
int32_t iFlag = static_cast< uint32_t >( flag );
|
int32_t iFlag = static_cast< uint32_t >( flag );
|
||||||
|
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
|
@ -1056,13 +1059,6 @@ void Sapphire::Entity::Player::setStateFlag( Common::PlayerStateFlag flag )
|
||||||
|
|
||||||
m_stateFlags[ index ] |= value;
|
m_stateFlags[ index ] |= value;
|
||||||
sendStateFlags();
|
sendStateFlags();
|
||||||
|
|
||||||
auto newOnlineStatus = getOnlineStatus();
|
|
||||||
|
|
||||||
if( prevOnlineStatus != newOnlineStatus )
|
|
||||||
sendToInRangeSet( makeActorControl( getId(), SetStatusIcon,
|
|
||||||
static_cast< uint8_t >( getOnlineStatus() ) ), true );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Player::setStateFlags( std::vector< Common::PlayerStateFlag > flags )
|
void Sapphire::Entity::Player::setStateFlags( std::vector< Common::PlayerStateFlag > flags )
|
||||||
|
@ -1083,8 +1079,6 @@ void Sapphire::Entity::Player::unsetStateFlag( Common::PlayerStateFlag flag )
|
||||||
if( !hasStateFlag( flag ) )
|
if( !hasStateFlag( flag ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto prevOnlineStatus = getOnlineStatus();
|
|
||||||
|
|
||||||
int32_t iFlag = static_cast< uint32_t >( flag );
|
int32_t iFlag = static_cast< uint32_t >( flag );
|
||||||
|
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
|
@ -1093,11 +1087,6 @@ void Sapphire::Entity::Player::unsetStateFlag( Common::PlayerStateFlag flag )
|
||||||
|
|
||||||
m_stateFlags[ index ] ^= value;
|
m_stateFlags[ index ] ^= value;
|
||||||
sendStateFlags();
|
sendStateFlags();
|
||||||
|
|
||||||
auto newOnlineStatus = getOnlineStatus();
|
|
||||||
|
|
||||||
if( prevOnlineStatus != newOnlineStatus )
|
|
||||||
sendToInRangeSet( makeActorControl( getId(), SetStatusIcon, static_cast< uint8_t >( getOnlineStatus() ) ), true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Player::update( uint64_t tickCount )
|
void Sapphire::Entity::Player::update( uint64_t tickCount )
|
||||||
|
@ -2269,6 +2258,218 @@ void Sapphire::Entity::Player::clearBuyBackMap()
|
||||||
m_shopBuyBackMap.clear();
|
m_shopBuyBackMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::isPartyLeader()
|
||||||
|
{
|
||||||
|
if( !m_partyLeader )
|
||||||
|
return false;
|
||||||
|
return m_partyLeader->getId() == getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::isInParty()
|
||||||
|
{
|
||||||
|
return m_partyLeader != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sapphire::Entity::PlayerPtr Sapphire::Entity::Player::getPartyLeader()
|
||||||
|
{
|
||||||
|
return m_partyLeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::createEmptyParty()
|
||||||
|
{
|
||||||
|
if( m_partyLeader )
|
||||||
|
return false;
|
||||||
|
m_partyLeader = getAsPlayer();
|
||||||
|
m_partyMemberList.clear();
|
||||||
|
m_partyMemberList.push_back( m_partyLeader );
|
||||||
|
setOnlineStatusMask( 0x0000803000000000ui64 );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::disbandParty()
|
||||||
|
{
|
||||||
|
if( isPartyLeader() )
|
||||||
|
{
|
||||||
|
for( auto member : m_partyMemberList )
|
||||||
|
{
|
||||||
|
if( member->getId() == getId() )
|
||||||
|
continue;
|
||||||
|
member->m_partyLeader = nullptr;
|
||||||
|
member->setOnlineStatusMask( 0x0000800000000000ui64 );
|
||||||
|
member->clearPartyList();
|
||||||
|
}
|
||||||
|
m_partyLeader = nullptr;
|
||||||
|
clearPartyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sapphire::Entity::PlayerPtr Sapphire::Entity::Player::getPartyInvitationSender()
|
||||||
|
{
|
||||||
|
return m_partyInvitationSender;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::setPartyInvitationSender( PlayerPtr sender )
|
||||||
|
{
|
||||||
|
m_partyInvitationSender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::addPartyMember( PlayerPtr member )
|
||||||
|
{
|
||||||
|
if( !isPartyLeader() || member->isInParty() || getPartySize() >= 8 )
|
||||||
|
return false;
|
||||||
|
m_partyMemberList.push_back( member );
|
||||||
|
member->m_partyLeader = m_partyLeader;
|
||||||
|
member->setOnlineStatusMask( 0x0000802000000000ui64 );
|
||||||
|
sendPartyListToParty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::removePartyMember( PlayerPtr member )
|
||||||
|
{
|
||||||
|
if( member->isInParty() && member->getPartyLeader()->getId() == getId() )
|
||||||
|
{
|
||||||
|
if( member->getId() == member->getPartyLeader()->getId() )
|
||||||
|
{
|
||||||
|
Entity::PlayerPtr nextLeader = nullptr;
|
||||||
|
for( auto it = m_partyMemberList.begin(); it != m_partyMemberList.end(); it++ )
|
||||||
|
{
|
||||||
|
if( !( *it )->isPartyLeader() )
|
||||||
|
{
|
||||||
|
nextLeader = *it;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !nextLeader )
|
||||||
|
{
|
||||||
|
disbandParty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
changePartyLeader( nextLeader );
|
||||||
|
return nextLeader->removePartyMember( member );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool flag = false;
|
||||||
|
for( auto it = m_partyMemberList.begin(); it != m_partyMemberList.end(); it++ )
|
||||||
|
{
|
||||||
|
if( ( *it )->getId() == member->getId() )
|
||||||
|
{
|
||||||
|
m_partyMemberList.erase( it );
|
||||||
|
member->m_partyLeader = nullptr;
|
||||||
|
member->setOnlineStatusMask( 0x0000800000000000ui64 );
|
||||||
|
member->clearPartyList();
|
||||||
|
flag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( flag )
|
||||||
|
{
|
||||||
|
sendPartyListToParty();
|
||||||
|
if( getPartySize() == 1 )
|
||||||
|
{
|
||||||
|
m_partyLeader = nullptr;
|
||||||
|
m_partyMemberList.clear();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::changePartyLeader( PlayerPtr newLeader )
|
||||||
|
{
|
||||||
|
if( !isPartyLeader() || !newLeader->isInParty() || newLeader->getPartyLeader()->getId() != getId() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for( auto it = m_partyMemberList.begin(); it != m_partyMemberList.end(); it++ )
|
||||||
|
{
|
||||||
|
if( ( *it )->getId() == newLeader->getId() )
|
||||||
|
{
|
||||||
|
newLeader->m_partyMemberList = m_partyMemberList;
|
||||||
|
m_partyMemberList.clear();
|
||||||
|
for( auto m : newLeader->m_partyMemberList )
|
||||||
|
{
|
||||||
|
m->m_partyLeader = newLeader;
|
||||||
|
}
|
||||||
|
newLeader->setOnlineStatusMask( 0x0000803000000000ui64 );
|
||||||
|
setOnlineStatusMask( 0x0000802000000000ui64 );
|
||||||
|
newLeader->sendPartyListToParty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Sapphire::Entity::Player::getPartySize()
|
||||||
|
{
|
||||||
|
if( isInParty() )
|
||||||
|
{
|
||||||
|
return m_partyMemberList.size();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::sendPartyListToParty()
|
||||||
|
{
|
||||||
|
assert( isPartyLeader() );
|
||||||
|
FFXIVIpcPartyList partyList = {};
|
||||||
|
int i = 0;
|
||||||
|
int leaderIndex = 0;
|
||||||
|
for( auto member : m_partyMemberList )
|
||||||
|
{
|
||||||
|
assert( i < 8 );
|
||||||
|
|
||||||
|
memcpy( partyList.member[ i ].name, member->getName().c_str(), member->getName().length() + 1 );
|
||||||
|
partyList.member[ i ].contentId = member->getContentId();
|
||||||
|
partyList.member[ i ].charaId = member->getId();
|
||||||
|
partyList.member[ i ].u1 = 0xE0000000;
|
||||||
|
partyList.member[ i ].u2 = 0xE0000000;
|
||||||
|
partyList.member[ i ].hp = member->getHp();
|
||||||
|
partyList.member[ i ].maxHp = member->getMaxHp();
|
||||||
|
partyList.member[ i ].mp = member->getMp();
|
||||||
|
partyList.member[ i ].maxMp = 10000;
|
||||||
|
partyList.member[ i ].u3 = 0x44;
|
||||||
|
partyList.member[ i ].zoneId = member->getCurrentTerritory()->getTerritoryTypeId();
|
||||||
|
partyList.member[ i ].gposeSelectable = 1;
|
||||||
|
partyList.member[ i ].classId = static_cast< uint8_t >( member->getClass() );
|
||||||
|
partyList.member[ i ].level = member->getLevel();
|
||||||
|
if( member->isPartyLeader() )
|
||||||
|
leaderIndex = i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
partyList.someContentId1 = 0x0044000000000001ui64;
|
||||||
|
partyList.someContentId2 = 0x0044000100000001ui64;
|
||||||
|
partyList.leaderIndex = leaderIndex;
|
||||||
|
partyList.partySize = getPartySize();
|
||||||
|
|
||||||
|
for( auto member : m_partyMemberList )
|
||||||
|
{
|
||||||
|
auto packet = makeZonePacket< FFXIVIpcPartyList >( member->getId() );
|
||||||
|
memcpy( &packet->data().member[ 0 ], &partyList, sizeof( partyList ) );
|
||||||
|
member->queuePacket( packet );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::clearPartyList()
|
||||||
|
{
|
||||||
|
assert( !isInParty() );
|
||||||
|
auto packet = makeZonePacket< FFXIVIpcPartyList >( getId() );
|
||||||
|
queuePacket( packet );
|
||||||
|
m_partyMemberList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::foreachPartyMember( std::function< void( PlayerPtr member ) > callback )
|
||||||
|
{
|
||||||
|
if( !isPartyLeader() || !callback )
|
||||||
|
return;
|
||||||
|
for( auto member : m_partyMemberList )
|
||||||
|
{
|
||||||
|
callback( member );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Player::gaugeClear()
|
void Sapphire::Entity::Player::gaugeClear()
|
||||||
{
|
{
|
||||||
std::memset( &m_gauge, 0, sizeof( m_gauge ) );
|
std::memset( &m_gauge, 0, sizeof( m_gauge ) );
|
||||||
|
|
|
@ -990,8 +990,29 @@ namespace Sapphire::Entity
|
||||||
void sendActorGauge();
|
void sendActorGauge();
|
||||||
void gaugeSetRaw( uint8_t* pData );
|
void gaugeSetRaw( uint8_t* pData );
|
||||||
|
|
||||||
|
// party
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
private:
|
||||||
|
PlayerPtr m_partyLeader;
|
||||||
|
PlayerPtr m_partyInvitationSender;
|
||||||
|
std::vector< PlayerPtr > m_partyMemberList;
|
||||||
|
void clearPartyList();
|
||||||
|
void sendPartyListToParty();
|
||||||
|
public:
|
||||||
|
bool isPartyLeader();
|
||||||
|
bool isInParty();
|
||||||
|
bool createEmptyParty();
|
||||||
|
void disbandParty();
|
||||||
|
PlayerPtr getPartyLeader();
|
||||||
|
PlayerPtr getPartyInvitationSender();
|
||||||
|
void setPartyInvitationSender( PlayerPtr sender );
|
||||||
|
bool addPartyMember( PlayerPtr member );
|
||||||
|
bool removePartyMember( PlayerPtr member );
|
||||||
|
bool changePartyLeader( PlayerPtr newLeader );
|
||||||
|
uint8_t getPartySize();
|
||||||
|
void foreachPartyMember( std::function< void( PlayerPtr member ) > callback);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index );
|
Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index );
|
||||||
|
|
||||||
void sendHuntingLog();
|
void sendHuntingLog();
|
||||||
|
|
|
@ -134,7 +134,14 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH
|
||||||
setZoneHandler( ClientZoneIpcType::WorldInteractionHandler, "WorldInteractionHandler", &GameConnection::worldInteractionhandler );
|
setZoneHandler( ClientZoneIpcType::WorldInteractionHandler, "WorldInteractionHandler", &GameConnection::worldInteractionhandler );
|
||||||
|
|
||||||
setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler );
|
setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler );
|
||||||
|
setChatHandler( ClientZoneIpcType::PartyChatHandler, "PartyChatHandler", &GameConnection::partyChatHandler );
|
||||||
|
|
||||||
|
setZoneHandler( ClientZoneIpcType::SocialInviteHandler, "SocialInviteHandler", &GameConnection::socialInviteHandler );
|
||||||
|
setZoneHandler( ClientZoneIpcType::SocialInviteResponseHandler, "SocialInviteResponseHandler", &GameConnection::socialInviteResponseHandler );
|
||||||
|
setZoneHandler( ClientZoneIpcType::PartySetLeaderHandler, "PartySetLeaderHandler", &GameConnection::partySetLeaderHandler );
|
||||||
|
setZoneHandler( ClientZoneIpcType::LeavePartyHandler, "LeavePartyHandler", &GameConnection::leavePartyHandler );
|
||||||
|
setZoneHandler( ClientZoneIpcType::KickPartyMemberHandler, "KickPartyMemberHandler", &GameConnection::kickPartyMemberHandler );
|
||||||
|
setZoneHandler( ClientZoneIpcType::DisbandPartyHandler, "DisbandPartyHandler", &GameConnection::disbandPartyHandler );
|
||||||
}
|
}
|
||||||
|
|
||||||
Sapphire::Network::GameConnection::~GameConnection() = default;
|
Sapphire::Network::GameConnection::~GameConnection() = default;
|
||||||
|
|
|
@ -121,6 +121,8 @@ namespace Sapphire::Network
|
||||||
|
|
||||||
DECLARE_HANDLER( chatHandler );
|
DECLARE_HANDLER( chatHandler );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( partyChatHandler );
|
||||||
|
|
||||||
DECLARE_HANDLER( zoneLineHandler );
|
DECLARE_HANDLER( zoneLineHandler );
|
||||||
|
|
||||||
DECLARE_HANDLER( clientTriggerHandler );
|
DECLARE_HANDLER( clientTriggerHandler );
|
||||||
|
@ -189,6 +191,17 @@ namespace Sapphire::Network
|
||||||
|
|
||||||
DECLARE_HANDLER( worldInteractionhandler );
|
DECLARE_HANDLER( worldInteractionhandler );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( socialInviteHandler );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( socialInviteResponseHandler );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( partySetLeaderHandler );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( leavePartyHandler );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( kickPartyMemberHandler );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( disbandPartyHandler );
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,7 +494,18 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX
|
||||||
player.sendDebug( "event battle level sync: {0}, ilevel sync?: {1}", param12, param2 );
|
player.sendDebug( "event battle level sync: {0}, ilevel sync?: {1}", param12, param2 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ClientTriggerType::CameraMode:
|
||||||
|
{
|
||||||
|
if( param11 == 1 )
|
||||||
|
{
|
||||||
|
player.setOnlineStatusMask( player.getOnlineStatusMask() | 0x0000000000040000ui64 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player.setOnlineStatusMask( player.getOnlineStatusMask() & 0xFFFFFFFFFFFBFFFFui64 );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
Logger::debug( "[{0}] Unhandled action: {1:04X}", m_pSession->getId(), commandId );
|
Logger::debug( "[{0}] Unhandled action: {1:04X}", m_pSession->getId(), commandId );
|
||||||
|
|
|
@ -256,19 +256,12 @@ void Sapphire::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACK
|
||||||
{
|
{
|
||||||
targetPlayer->setOnlineStatusMask( param1 );
|
targetPlayer->setOnlineStatusMask( param1 );
|
||||||
|
|
||||||
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( player.getId() );
|
|
||||||
statusPacket->data().onlineStatusFlags = param1;
|
|
||||||
queueOutPacket( statusPacket );
|
|
||||||
|
|
||||||
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
|
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
|
||||||
searchInfoPacket->data().onlineStatusFlags = param1;
|
searchInfoPacket->data().onlineStatusFlags = param1;
|
||||||
searchInfoPacket->data().selectRegion = targetPlayer->getSearchSelectRegion();
|
searchInfoPacket->data().selectRegion = targetPlayer->getSearchSelectRegion();
|
||||||
strcpy( searchInfoPacket->data().searchMessage, targetPlayer->getSearchMessage() );
|
strcpy( searchInfoPacket->data().searchMessage, targetPlayer->getSearchMessage() );
|
||||||
targetPlayer->queuePacket( searchInfoPacket );
|
targetPlayer->queuePacket( searchInfoPacket );
|
||||||
|
|
||||||
targetPlayer->sendToInRangeSet( makeActorControl( player.getId(), SetStatusIcon,
|
|
||||||
static_cast< uint8_t >( player.getOnlineStatus() ) ),
|
|
||||||
true );
|
|
||||||
player.sendNotice( "Icon for {0} was set to {1}", targetPlayer->getName(), param1 );
|
player.sendNotice( "Icon for {0} was set to {1}", targetPlayer->getName(), param1 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,18 +87,11 @@ void Sapphire::Network::GameConnection::setSearchInfoHandler( const Packets::FFX
|
||||||
// mark player as new adventurer
|
// mark player as new adventurer
|
||||||
player.setNewAdventurer( true );
|
player.setNewAdventurer( true );
|
||||||
|
|
||||||
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( player.getId() );
|
|
||||||
statusPacket->data().onlineStatusFlags = status;
|
|
||||||
queueOutPacket( statusPacket );
|
|
||||||
|
|
||||||
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
|
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
|
||||||
searchInfoPacket->data().onlineStatusFlags = status;
|
searchInfoPacket->data().onlineStatusFlags = status;
|
||||||
searchInfoPacket->data().selectRegion = player.getSearchSelectRegion();
|
searchInfoPacket->data().selectRegion = player.getSearchSelectRegion();
|
||||||
strcpy( searchInfoPacket->data().searchMessage, player.getSearchMessage() );
|
strcpy( searchInfoPacket->data().searchMessage, player.getSearchMessage() );
|
||||||
queueOutPacket( searchInfoPacket );
|
queueOutPacket( searchInfoPacket );
|
||||||
|
|
||||||
player.sendToInRangeSet( makeActorControl( player.getId(), SetStatusIcon,
|
|
||||||
static_cast< uint8_t >( player.getOnlineStatus() ) ), true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Network::GameConnection::reqSearchInfoHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
void Sapphire::Network::GameConnection::reqSearchInfoHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||||
|
@ -437,31 +430,47 @@ void Sapphire::Network::GameConnection::socialListHandler( const Packets::FFXIVA
|
||||||
int32_t entrysizes = sizeof( listPacket->data().entries );
|
int32_t entrysizes = sizeof( listPacket->data().entries );
|
||||||
memset( listPacket->data().entries, 0, sizeof( listPacket->data().entries ) );
|
memset( listPacket->data().entries, 0, sizeof( listPacket->data().entries ) );
|
||||||
|
|
||||||
listPacket->data().entries[ 0 ].bytes[ 2 ] = player.getCurrentTerritory()->getTerritoryTypeId();
|
auto fillEntryAt = [ &listPacket ]( int i, Entity::PlayerPtr nextPlayer )
|
||||||
listPacket->data().entries[ 0 ].bytes[ 3 ] = 0x80;
|
{
|
||||||
listPacket->data().entries[ 0 ].bytes[ 4 ] = 0x02;
|
listPacket->data().entries[ i ].bytes[ 2 ] = nextPlayer->getCurrentTerritory()->getTerritoryTypeId();
|
||||||
listPacket->data().entries[ 0 ].bytes[ 6 ] = 0x3B;
|
listPacket->data().entries[ i ].bytes[ 3 ] = 0x80;
|
||||||
listPacket->data().entries[ 0 ].bytes[ 11 ] = 0x10;
|
listPacket->data().entries[ i ].bytes[ 4 ] = 0x02;
|
||||||
listPacket->data().entries[ 0 ].classJob = static_cast< uint8_t >( player.getClass() );
|
listPacket->data().entries[ i ].bytes[ 6 ] = 0x3B;
|
||||||
listPacket->data().entries[ 0 ].contentId = player.getContentId();
|
listPacket->data().entries[ i ].bytes[ 8 ] = nextPlayer->isPartyLeader() ? 1 : 0;
|
||||||
listPacket->data().entries[ 0 ].level = player.getLevel();
|
listPacket->data().entries[ i ].bytes[ 11 ] = 0x10;
|
||||||
listPacket->data().entries[ 0 ].zoneId = player.getCurrentTerritory()->getTerritoryTypeId();
|
listPacket->data().entries[ i ].classJob = static_cast< uint8_t >( nextPlayer->getClass() );
|
||||||
listPacket->data().entries[ 0 ].zoneId1 = 0x0100;
|
listPacket->data().entries[ i ].contentId = nextPlayer->getContentId();
|
||||||
// TODO: no idea what this does
|
listPacket->data().entries[ i ].level = nextPlayer->getLevel();
|
||||||
//listPacket.data().entries[0].one = 1;
|
listPacket->data().entries[ i ].zoneId = nextPlayer->getCurrentTerritory()->getTerritoryTypeId();
|
||||||
|
listPacket->data().entries[ i ].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() ) );
|
memcpy( listPacket->data().entries[ i ].name, nextPlayer->getName().c_str(), strlen( nextPlayer->getName().c_str() ) );
|
||||||
|
|
||||||
// GC icon
|
// GC icon
|
||||||
listPacket->data().entries[ 0 ].bytes1[ 0 ] = 2;
|
listPacket->data().entries[ i ].bytes1[ 0 ] = 2;
|
||||||
// client language J = 0, E = 1, D = 2, F = 3
|
// client language J = 0, E = 1, D = 2, F = 3
|
||||||
listPacket->data().entries[ 0 ].bytes1[ 1 ] = 1;
|
listPacket->data().entries[ i ].bytes1[ 1 ] = 1;
|
||||||
// user language settings flag J = 1, E = 2, D = 4, F = 8
|
// user language settings flag J = 1, E = 2, D = 4, F = 8
|
||||||
listPacket->data().entries[ 0 ].bytes1[ 2 ] = 1 + 2;
|
listPacket->data().entries[ i ].bytes1[ 2 ] = 1 + 2;
|
||||||
listPacket->data().entries[ 0 ].onlineStatusMask = player.getOnlineStatusMask();
|
listPacket->data().entries[ i ].onlineStatusMask = nextPlayer->getOnlineStatusMask();
|
||||||
|
};
|
||||||
|
auto nextPlayer = player.getAsPlayer();
|
||||||
|
fillEntryAt( 0, nextPlayer );
|
||||||
|
if( player.isInParty() )
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
player.getPartyLeader()->foreachPartyMember( [ &player, &fillEntryAt, &i ]( auto m )
|
||||||
|
{
|
||||||
|
if( m->getId() == player.getId() )
|
||||||
|
return;
|
||||||
|
fillEntryAt( i, m );
|
||||||
|
i++;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
queueOutPacket( listPacket );
|
queueOutPacket( listPacket );
|
||||||
|
|
||||||
}
|
}
|
||||||
else if( type == 2 )
|
else if( type == 2 )
|
||||||
{ // friend list
|
{ // friend list
|
||||||
|
@ -478,6 +487,34 @@ void Sapphire::Network::GameConnection::socialListHandler( const Packets::FFXIVA
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::partyChatHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||||
|
{
|
||||||
|
// proper party chat packet not working, <se.x> won't work with this workaround
|
||||||
|
if( !player.isInParty() )
|
||||||
|
return;
|
||||||
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcPartyChatHandler >( inPacket );
|
||||||
|
//FFXIVIpcPartyChat chat = {};
|
||||||
|
//chat.unknown = packet.data().unknown;
|
||||||
|
//chat.contentId = player.getContentId();
|
||||||
|
//chat.charaId = player.getId();
|
||||||
|
//chat.u1 = 0x44;
|
||||||
|
//memcpy( chat.name, player.getName().c_str(), player.getName().length() + 1 );
|
||||||
|
//memcpy( chat.message, packet.data().message, sizeof( chat.message ) );
|
||||||
|
auto leader = player.getPartyLeader();
|
||||||
|
leader->foreachPartyMember( [ &packet, &player/*, chat*/ ]( auto m )
|
||||||
|
{
|
||||||
|
if( player.getId() == m->getId() )
|
||||||
|
return;
|
||||||
|
//auto pChat = makeZonePacket< FFXIVIpcPartyChat >( m->getId() );
|
||||||
|
//memcpy( &pChat->data(), &chat, sizeof( chat ) );
|
||||||
|
//m->queuePacket( pChat );
|
||||||
|
|
||||||
|
/* workaround */
|
||||||
|
auto chatPacket = std::make_shared< Server::ChatPacket >( player, ChatType::Party, packet.data().message );
|
||||||
|
m->queuePacket( chatPacket );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
void Sapphire::Network::GameConnection::chatHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
void Sapphire::Network::GameConnection::chatHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||||
Entity::Player& player )
|
Entity::Player& player )
|
||||||
{
|
{
|
||||||
|
@ -793,3 +830,260 @@ void Sapphire::Network::GameConnection::worldInteractionhandler( const Packets::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::socialInviteHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||||
|
{
|
||||||
|
const auto packetIn = ZoneChannelPacket< Client::FFXIVIpcSocialInviteHandler >( inPacket );
|
||||||
|
switch( packetIn.data().socialType )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
if( player.isInParty() && !player.isPartyLeader() )
|
||||||
|
return;
|
||||||
|
std::string name( packetIn.data().name );
|
||||||
|
auto& serverMgr = Common::Service< Sapphire::World::ServerMgr >::ref();
|
||||||
|
auto session = serverMgr.getSession( name );
|
||||||
|
if( session )
|
||||||
|
{
|
||||||
|
auto targetPlayer = session->getPlayer();
|
||||||
|
if( targetPlayer->isInParty() )
|
||||||
|
return;
|
||||||
|
auto packet1 = makeZonePacket< FFXIVIpcSocialInviteMessage2 >( player.getId() );
|
||||||
|
packet1->data().contentId = targetPlayer->getContentId();
|
||||||
|
packet1->data().p1 = packetIn.data().p1;
|
||||||
|
packet1->data().p2 = packetIn.data().p2;
|
||||||
|
packet1->data().socialType = packetIn.data().socialType;
|
||||||
|
memcpy( packet1->data().name, targetPlayer->getName().c_str(), targetPlayer->getName().length() + 1 );
|
||||||
|
player.queuePacket( packet1 );
|
||||||
|
|
||||||
|
auto packet2 = makeZonePacket< FFXIVIpcSocialInviteMessage >( targetPlayer->getId() );
|
||||||
|
packet2->data().contentId = player.getContentId();
|
||||||
|
packet2->data().expireTime = Common::Util::getTimeSeconds() + 30;
|
||||||
|
packet2->data().p1 = packetIn.data().p1;
|
||||||
|
packet2->data().p2 = packetIn.data().p2;
|
||||||
|
packet2->data().socialType = packetIn.data().socialType;
|
||||||
|
packet2->data().type = 1;
|
||||||
|
packet2->data().unknown4 = 1;
|
||||||
|
memcpy( packet2->data().name, player.getName().c_str(), player.getName().length() + 1 );
|
||||||
|
targetPlayer->queuePacket( packet2 );
|
||||||
|
|
||||||
|
targetPlayer->setPartyInvitationSender( player.getAsPlayer() );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::socialInviteResponseHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||||
|
{
|
||||||
|
const auto packetIn = ZoneChannelPacket< Client::FFXIVIpcSocialInviteResponseHandler >( inPacket );
|
||||||
|
switch( packetIn.data().socialType )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
if( player.isInParty() || !player.getPartyInvitationSender() )
|
||||||
|
return;
|
||||||
|
auto response = packetIn.data().response;
|
||||||
|
auto sender = player.getPartyInvitationSender();
|
||||||
|
player.setPartyInvitationSender( nullptr );
|
||||||
|
auto packet1 = makeZonePacket< FFXIVIpcSocialInviteResponseMessage >( player.getId() );
|
||||||
|
packet1->data().contentId = sender->getContentId();
|
||||||
|
packet1->data().u1AlwaysOne = 1;
|
||||||
|
packet1->data().response = response;
|
||||||
|
packet1->data().u2AlwaysOne = 1;
|
||||||
|
memcpy( packet1->data().name, sender->getName().c_str(), sender->getName().length() + 1 );
|
||||||
|
player.queuePacket( packet1 );
|
||||||
|
if( response == 1 && ( !sender->isInParty() || sender->getPartyLeader()->getId() == sender->getId() ) )
|
||||||
|
{
|
||||||
|
if( !sender->isInParty() )
|
||||||
|
{
|
||||||
|
if( !sender->createEmptyParty() )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto member = player.getAsPlayer();
|
||||||
|
if( sender->addPartyMember( member ) )
|
||||||
|
{
|
||||||
|
FFXIVIpcPartyMessage msg = {};
|
||||||
|
msg.leaderContentId = sender->getContentId();
|
||||||
|
msg.memberContentId = player.getContentId();
|
||||||
|
msg.u1 = 1;
|
||||||
|
msg.type = 1;
|
||||||
|
msg.partySize = sender->getPartySize();
|
||||||
|
memcpy( msg.leaderName, sender->getName().c_str(), sender->getName().length() + 1 );
|
||||||
|
memcpy( msg.memberName, player.getName().c_str(), player.getName().length() + 1 );
|
||||||
|
sender->foreachPartyMember( [ msg ]( auto m )
|
||||||
|
{
|
||||||
|
auto packetMsg = makeZonePacket< FFXIVIpcPartyMessage >( m->getId() );
|
||||||
|
memcpy( &packetMsg->data(), &msg, sizeof( msg ) );
|
||||||
|
m->queuePacket( packetMsg );
|
||||||
|
} );
|
||||||
|
|
||||||
|
auto packet2 = makeZonePacket< FFXIVIpcSocialInviteMessage >( sender->getId() );
|
||||||
|
packet2->data().contentId = player.getContentId();
|
||||||
|
packet2->data().expireTime = Common::Util::getTimeSeconds() + 30;
|
||||||
|
packet2->data().p1 = packetIn.data().p1;
|
||||||
|
packet2->data().p2 = packetIn.data().p2;
|
||||||
|
packet2->data().socialType = packetIn.data().socialType;
|
||||||
|
packet2->data().type = 4;
|
||||||
|
memcpy( packet2->data().name, player.getName().c_str(), player.getName().length() + 1 );
|
||||||
|
sender->queuePacket( packet2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto packet2 = makeZonePacket< FFXIVIpcSocialInviteMessage >( sender->getId() );
|
||||||
|
packet2->data().contentId = player.getContentId();
|
||||||
|
packet2->data().expireTime = Common::Util::getTimeSeconds() + 30;
|
||||||
|
packet2->data().p1 = packetIn.data().p1;
|
||||||
|
packet2->data().p2 = packetIn.data().p2;
|
||||||
|
packet2->data().socialType = packetIn.data().socialType;
|
||||||
|
packet2->data().type = 5;
|
||||||
|
memcpy( packet2->data().name, player.getName().c_str(), player.getName().length() + 1 );
|
||||||
|
sender->queuePacket( packet2 );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::partySetLeaderHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||||
|
{
|
||||||
|
if( !player.isPartyLeader() )
|
||||||
|
return;
|
||||||
|
const auto packetIn = ZoneChannelPacket< Client::FFXIVIpcPartySetLeaderHandler >( inPacket );
|
||||||
|
Sapphire::Entity::PlayerPtr newLeader = nullptr;
|
||||||
|
player.foreachPartyMember( [ &packetIn, &newLeader ]( auto m )
|
||||||
|
{
|
||||||
|
if( m->getContentId() == packetIn.data().contentId )
|
||||||
|
{
|
||||||
|
newLeader = m;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
if( newLeader && player.changePartyLeader( newLeader ) )
|
||||||
|
{
|
||||||
|
FFXIVIpcPartyMessage msg = {};
|
||||||
|
msg.leaderContentId = player.getContentId();
|
||||||
|
msg.memberContentId = newLeader->getContentId();
|
||||||
|
msg.type = 2;
|
||||||
|
msg.u1 = 1;
|
||||||
|
msg.partySize = newLeader->getPartySize();
|
||||||
|
memcpy( msg.leaderName, player.getName().c_str(), player.getName().length() + 1 );
|
||||||
|
memcpy( msg.memberName, newLeader->getName().c_str(), newLeader->getName().length() + 1 );
|
||||||
|
newLeader->foreachPartyMember( [ msg ] ( auto m )
|
||||||
|
{
|
||||||
|
auto packetMsg = makeZonePacket< FFXIVIpcPartyMessage >( m->getId() );
|
||||||
|
memcpy( &packetMsg->data(), &msg, sizeof( msg ) );
|
||||||
|
m->queuePacket( packetMsg );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::leavePartyHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||||
|
{
|
||||||
|
if( !player.isInParty() )
|
||||||
|
return;
|
||||||
|
auto leader = player.getPartyLeader();
|
||||||
|
if( leader->getPartySize() <= 2 )
|
||||||
|
{
|
||||||
|
FFXIVIpcPartyMessage msg = {};
|
||||||
|
msg.leaderContentId = leader->getContentId();
|
||||||
|
msg.type = 3;
|
||||||
|
leader->foreachPartyMember( [ msg ] ( auto m )
|
||||||
|
{
|
||||||
|
auto packetMsg = makeZonePacket< FFXIVIpcPartyMessage >( m->getId() );
|
||||||
|
memcpy( &packetMsg->data(), &msg, sizeof( msg ) );
|
||||||
|
m->queuePacket( packetMsg );
|
||||||
|
} );
|
||||||
|
leader->disbandParty();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FFXIVIpcPartyMessage msg = {};
|
||||||
|
msg.memberContentId = player.getContentId();
|
||||||
|
leader->foreachPartyMember( [ &player, &leader, &msg ] ( auto m )
|
||||||
|
{
|
||||||
|
if( m->getId() == player.getId() )
|
||||||
|
{
|
||||||
|
msg.leaderContentId = leader->getContentId();
|
||||||
|
msg.type = 5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg.leaderContentId = 0;
|
||||||
|
msg.type = 4;
|
||||||
|
}
|
||||||
|
auto packetMsg = makeZonePacket< FFXIVIpcPartyMessage >( m->getId() );
|
||||||
|
memcpy( &packetMsg->data(), &msg, sizeof( msg ) );
|
||||||
|
m->queuePacket( packetMsg );
|
||||||
|
} );
|
||||||
|
leader->removePartyMember( player.getAsPlayer() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::kickPartyMemberHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||||
|
{
|
||||||
|
if( !player.isPartyLeader() )
|
||||||
|
return;
|
||||||
|
const auto packetIn = ZoneChannelPacket< Client::FFXIVIpcKickPartyMemberHander >( inPacket );
|
||||||
|
Sapphire::Entity::PlayerPtr toKick = nullptr;
|
||||||
|
player.foreachPartyMember( [ &packetIn, &toKick ]( auto m )
|
||||||
|
{
|
||||||
|
if( m->getContentId() == packetIn.data().contentId )
|
||||||
|
{
|
||||||
|
toKick = m;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
if( toKick )
|
||||||
|
{
|
||||||
|
if( player.getPartySize() <= 2 )
|
||||||
|
{
|
||||||
|
FFXIVIpcPartyMessage msg = {};
|
||||||
|
msg.leaderContentId = player.getContentId();
|
||||||
|
msg.type = 3;
|
||||||
|
player.foreachPartyMember( [ msg ] ( auto m )
|
||||||
|
{
|
||||||
|
auto packetMsg = makeZonePacket< FFXIVIpcPartyMessage >( m->getId() );
|
||||||
|
memcpy( &packetMsg->data(), &msg, sizeof( msg ) );
|
||||||
|
m->queuePacket( packetMsg );
|
||||||
|
} );
|
||||||
|
player.disbandParty();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FFXIVIpcPartyMessage msg = {};
|
||||||
|
msg.leaderContentId = player.getContentId();
|
||||||
|
msg.memberContentId = toKick->getContentId();
|
||||||
|
player.foreachPartyMember( [ &toKick, &msg ] ( auto m )
|
||||||
|
{
|
||||||
|
if( m->getId() == toKick->getId() )
|
||||||
|
{
|
||||||
|
msg.type = 5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg.type = 4;
|
||||||
|
}
|
||||||
|
auto packetMsg = makeZonePacket< FFXIVIpcPartyMessage >( m->getId() );
|
||||||
|
memcpy( &packetMsg->data(), &msg, sizeof( msg ) );
|
||||||
|
m->queuePacket( packetMsg );
|
||||||
|
} );
|
||||||
|
player.removePartyMember( toKick );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::disbandPartyHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||||
|
{
|
||||||
|
if( !player.isPartyLeader() )
|
||||||
|
return;
|
||||||
|
FFXIVIpcPartyMessage msg = {};
|
||||||
|
msg.leaderContentId = player.getContentId();
|
||||||
|
msg.type = 3;
|
||||||
|
player.foreachPartyMember( [ msg ] ( auto m )
|
||||||
|
{
|
||||||
|
auto packetMsg = makeZonePacket< FFXIVIpcPartyMessage >( m->getId() );
|
||||||
|
memcpy( &packetMsg->data(), &msg, sizeof( msg ) );
|
||||||
|
m->queuePacket( packetMsg );
|
||||||
|
} );
|
||||||
|
player.disbandParty();
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue