mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 22:57:45 +00:00
Merge branch 'ThreePointOh' of https://github.com/SapphireMordred/Sapphire into ThreePointOh
This commit is contained in:
commit
7af6eda26e
18 changed files with 413 additions and 67 deletions
2
sql/migrations/20211201205038_FixFriendlistKey.sql
Normal file
2
sql/migrations/20211201205038_FixFriendlistKey.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE `charainfofriendlist`
|
||||
CHANGE COLUMN `CharacterId` `CharacterId` BIGINT NOT NULL DEFAULT 0 FIRST;
|
|
@ -268,6 +268,16 @@ void PlayerMinimal::saveAsNew()
|
|||
stmtSearchInfo->setUInt64( 1, m_characterId );
|
||||
g_charaDb.directExecute( stmtSearchInfo );
|
||||
|
||||
// Friend list related
|
||||
auto stmtFriendList = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_FRIENDLIST_INS );
|
||||
std::vector< uint8_t > friendIds( 1600, 0 );
|
||||
std::vector< uint8_t > inviteIds( 1600, 0 );
|
||||
|
||||
stmtFriendList->setUInt64( 1, m_characterId );
|
||||
stmtFriendList->setBinary( 2, friendIds );
|
||||
stmtFriendList->setBinary( 3, inviteIds );
|
||||
g_charaDb.directExecute( stmtFriendList );
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// SET UP INVENTORIES
|
||||
createInvDbContainer( InventoryType::Bag0 );
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Sapphire::Common
|
|||
const uint16_t MAX_PLAYER_LEVEL = 80;
|
||||
const uint8_t CURRENT_EXPANSION_ID = 3;
|
||||
|
||||
const uint8_t CLASSJOB_TOTAL = 38;
|
||||
const uint8_t CLASSJOB_TOTAL = 33;
|
||||
const uint8_t CLASSJOB_SLOTS = 20;
|
||||
|
||||
const uint8_t TOWN_COUNT = 6;
|
||||
|
@ -971,7 +971,7 @@ namespace Sapphire::Common
|
|||
InvincibilityIgnoreDamage,
|
||||
};
|
||||
|
||||
enum InviteType : int32_t
|
||||
enum HierarchyType : uint8_t
|
||||
{
|
||||
NONE_2 = 0x0,
|
||||
PCPARTY = 0x1,
|
||||
|
@ -984,6 +984,14 @@ namespace Sapphire::Common
|
|||
MAX_1 = 0xFF,
|
||||
};
|
||||
|
||||
enum HierarchyStatus : uint8_t
|
||||
{
|
||||
Invalid = 0,
|
||||
Added = 0x10,
|
||||
SentRequest = 0x20,
|
||||
ReceivedRequest = 0x30
|
||||
};
|
||||
|
||||
enum LinkshellHierarchy : int32_t
|
||||
{
|
||||
NONE_1 = 0x0,
|
||||
|
@ -994,13 +1002,17 @@ namespace Sapphire::Common
|
|||
MAX_0 = 0x7,
|
||||
};
|
||||
|
||||
|
||||
enum GroupEntryStatus : uint8_t
|
||||
union HierarchyData
|
||||
{
|
||||
Invalid = 0,
|
||||
Added = 0x10,
|
||||
SentRequest = 0x20,
|
||||
ReceivedRequest = 0x30
|
||||
uint64_t u64;
|
||||
|
||||
struct HierarchyPackedData {
|
||||
uint32_t dateAdded;
|
||||
uint8_t status;
|
||||
uint8_t type;
|
||||
uint8_t group;
|
||||
uint8_t unk;
|
||||
} data;
|
||||
};
|
||||
|
||||
/* 61719 */
|
||||
|
|
|
@ -83,6 +83,7 @@ namespace Sapphire::Network::Packets
|
|||
PcSearch = 0xEB,
|
||||
GetFcJoinRequestComment = 0xEC,
|
||||
InviteCancel = 0xED,
|
||||
SetFriendlistGroup = 0xEE,
|
||||
LinkshellJoin = 0xF0,
|
||||
LinkshellJoinOfficial = 0xF1,
|
||||
LinkshellLeave = 0xF2,
|
||||
|
|
|
@ -579,6 +579,18 @@ struct FFXIVIpcGetCommonlistDetail : FFXIVIpcBasePacket< GetCommonlistDetail >
|
|||
uint8_t ListType;
|
||||
};
|
||||
|
||||
struct FFXIVIpcFriendlistRemove : FFXIVIpcBasePacket< FriendlistRemove >
|
||||
{
|
||||
uint64_t TargetCharacterID;
|
||||
char TargetCharacterName[32];
|
||||
};
|
||||
|
||||
struct FFXIVIpcSetFriendlistGroup : FFXIVIpcBasePacket< SetFriendlistGroup >
|
||||
{
|
||||
uint64_t TargetCharacterID;
|
||||
uint8_t group;
|
||||
};
|
||||
|
||||
struct FFXIVIpcPcSearch : FFXIVIpcBasePacket< PcSearch >
|
||||
{
|
||||
uint64_t ClassID;
|
||||
|
|
|
@ -58,12 +58,17 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
|
|||
/**
|
||||
* Structural representation of the packet sent by the server
|
||||
* with a list of players ( party list | friend list | search results )
|
||||
* 3.0 Update: 64bit TerritoryID -> 32bit Timestamp, 32bit TerritoryID
|
||||
*/
|
||||
struct PlayerEntry
|
||||
{
|
||||
uint64_t CharacterID;
|
||||
uint64_t TerritoryID;
|
||||
uint32_t HierarchyID;
|
||||
uint32_t Timestamp;
|
||||
uint32_t TerritoryID;
|
||||
uint8_t HierarchyStatus;
|
||||
uint8_t HierarchyType;
|
||||
uint8_t HierarchyGroup;
|
||||
uint8_t HierarchyUnk;
|
||||
uint16_t TerritoryType;
|
||||
uint8_t GrandCompanyID;
|
||||
uint8_t Region;
|
||||
|
@ -144,6 +149,14 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
|
|||
char InviteName[32];
|
||||
};
|
||||
|
||||
struct FFXIVIpcFriendlistRemoveResult : FFXIVIpcBasePacket< FriendlistRemoveResult >
|
||||
{
|
||||
uint64_t RemovedCharacterID;
|
||||
uint32_t Result;
|
||||
uint8_t Identity;
|
||||
char RemovedCharacterName[32];
|
||||
};
|
||||
|
||||
struct FFXIVIpcGetFcStatusResult : FFXIVIpcBasePacket< GetFcStatusResult >
|
||||
{
|
||||
uint64_t FreeCompanyID;
|
||||
|
|
|
@ -2134,6 +2134,15 @@ void Sapphire::Entity::Player::setPartyId( uint64_t partyId )
|
|||
m_partyId = partyId;
|
||||
}
|
||||
|
||||
Sapphire::Entity::Player::FriendListIDVec& Sapphire::Entity::Player::getFriendListID()
|
||||
{
|
||||
return m_friendList;
|
||||
}
|
||||
Sapphire::Entity::Player::FriendListDataVec& Sapphire::Entity::Player::getFriendListData()
|
||||
{
|
||||
return m_friendInviteList;
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::setLastPcSearchResult( std::vector< uint32_t > result )
|
||||
{
|
||||
m_lastPcSearch = std::move( result );
|
||||
|
|
|
@ -799,6 +799,9 @@ namespace Sapphire::Entity
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using FriendListIDVec = std::array< uint64_t, 200 >;
|
||||
using FriendListDataVec = std::array< Common::HierarchyData, 200 >;
|
||||
|
||||
Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index );
|
||||
|
||||
void sendHuntingLog();
|
||||
|
@ -808,6 +811,9 @@ namespace Sapphire::Entity
|
|||
uint64_t getPartyId() const;
|
||||
void setPartyId( uint64_t partyId );
|
||||
|
||||
FriendListIDVec& getFriendListID();
|
||||
FriendListDataVec& getFriendListData();
|
||||
|
||||
uint64_t m_lastMoveTime{};
|
||||
uint8_t m_lastMoveflag{};
|
||||
bool m_falling;
|
||||
|
@ -963,8 +969,8 @@ namespace Sapphire::Entity
|
|||
|
||||
std::array< Common::HuntingLogEntry, 12 > m_huntingLogEntries{};
|
||||
|
||||
std::array< uint64_t, 200 > m_friendList{};
|
||||
std::array< uint64_t, 200 > m_friendInviteList{};
|
||||
FriendListIDVec m_friendList{};
|
||||
FriendListDataVec m_friendInviteList{};
|
||||
|
||||
uint64_t m_partyId;
|
||||
std::vector< uint32_t > m_lastPcSearch;
|
||||
|
|
|
@ -470,12 +470,12 @@ void Sapphire::Entity::Player::updateDbFriendList()
|
|||
auto stmt = db.getPreparedStatement( Db::CHARA_FRIENDLIST_UP );
|
||||
|
||||
std::vector< uint8_t > friendIds( 1600 );
|
||||
std::vector< uint8_t > InviteIds( 1600 );
|
||||
std::vector< uint8_t > inviteIds( 1600 );
|
||||
|
||||
memcpy( friendIds.data(), m_friendList.data(), 1600 );
|
||||
memcpy( InviteIds.data(), m_friendInviteList.data(), 1600 );
|
||||
memcpy( inviteIds.data(), m_friendInviteList.data(), 1600 );
|
||||
stmt->setBinary( 1, friendIds );
|
||||
stmt->setBinary( 2, InviteIds );
|
||||
stmt->setBinary( 2, inviteIds );
|
||||
stmt->setUInt64( 3, m_characterId );
|
||||
db.execute( stmt );
|
||||
}
|
||||
|
|
153
src/world/Manager/FriendListMgr.cpp
Normal file
153
src/world/Manager/FriendListMgr.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <Logging/Logger.h>
|
||||
#include <Service.h>
|
||||
#include <Util/Util.h>
|
||||
|
||||
#include "Actor/Player.h"
|
||||
#include "FriendListMgr.h"
|
||||
|
||||
bool Sapphire::World::Manager::FriendListMgr::onInviteCreate( Entity::Player& source, Entity::Player& target )
|
||||
{
|
||||
auto& sourceFL = source.getFriendListID();
|
||||
auto& targetFL = target.getFriendListID();
|
||||
|
||||
// check if player already has been invited or friends
|
||||
if( getEntryIndex( source, target.getCharacterId() ) != -1 )
|
||||
{
|
||||
// already invited/friends
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if there are slots available to allocate and get idx
|
||||
auto sourceIdx = getEntryIndex( source, 0 );
|
||||
auto targetIdx = getEntryIndex( target, 0 );
|
||||
|
||||
if( sourceIdx == -1 || targetIdx == -1 )
|
||||
{
|
||||
// todo: complain about having too many friends
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& sourceFLData = source.getFriendListData();
|
||||
auto& targetFLData = target.getFriendListData();
|
||||
|
||||
// add ID and data to arrays of both players
|
||||
sourceFL[ sourceIdx ] = target.getCharacterId();
|
||||
targetFL[ targetIdx ] = source.getCharacterId();
|
||||
|
||||
|
||||
Common::HierarchyData hierarchy;
|
||||
hierarchy.data.dateAdded = Common::Util::getTimeSeconds();
|
||||
hierarchy.data.group = 0;
|
||||
hierarchy.data.status = Common::HierarchyStatus::SentRequest; // set type for invite sender
|
||||
hierarchy.data.type = Common::HierarchyType::FRIENDLIST;
|
||||
|
||||
sourceFLData[ sourceIdx ] = hierarchy;
|
||||
|
||||
// set type for invite receiver
|
||||
hierarchy.data.status = Common::HierarchyStatus::ReceivedRequest;
|
||||
targetFLData[ targetIdx ] = hierarchy;
|
||||
|
||||
// force db update for friendlist
|
||||
source.updateDbFriendList();
|
||||
target.updateDbFriendList();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sapphire::World::Manager::FriendListMgr::onInviteAccept( Entity::Player& source, Entity::Player& target )
|
||||
{
|
||||
// accept friend invite
|
||||
auto sourceIdx = getEntryIndex( source, target.getCharacterId() );
|
||||
auto targetIdx = getEntryIndex( target, source.getCharacterId() );
|
||||
|
||||
if( sourceIdx == -1 || targetIdx == -1 )
|
||||
{
|
||||
// currently not friends
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& sourceFLData = source.getFriendListData();
|
||||
auto& targetFLData = target.getFriendListData();
|
||||
|
||||
sourceFLData[ sourceIdx ].data.status = Common::HierarchyStatus::Added;
|
||||
sourceFLData[ sourceIdx ].data.type = Common::HierarchyType::NONE_2;
|
||||
targetFLData[ targetIdx ].data.status = Common::HierarchyStatus::Added;
|
||||
targetFLData[ targetIdx ].data.type = Common::HierarchyType::NONE_2;
|
||||
|
||||
source.updateDbFriendList();
|
||||
target.updateDbFriendList();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sapphire::World::Manager::FriendListMgr::onInviteDecline( Entity::Player& source, Entity::Player& target )
|
||||
{
|
||||
// decline friend invite
|
||||
auto sourceIdx = getEntryIndex( source, target.getCharacterId() );
|
||||
auto targetIdx = getEntryIndex( target, source.getCharacterId() );
|
||||
|
||||
if( sourceIdx == -1 || targetIdx == -1 )
|
||||
{
|
||||
// currently not friends
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& sourceFL = source.getFriendListID();
|
||||
auto& targetFL = target.getFriendListID();
|
||||
|
||||
auto& sourceFLData = source.getFriendListData();
|
||||
auto& targetFLData = target.getFriendListData();
|
||||
|
||||
sourceFL[ sourceIdx ] = 0;
|
||||
targetFL[ targetIdx ] = 0;
|
||||
|
||||
sourceFLData[ sourceIdx ].u64 = 0;
|
||||
targetFLData[ targetIdx ].u64 = 0;
|
||||
|
||||
source.updateDbFriendList();
|
||||
target.updateDbFriendList();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sapphire::World::Manager::FriendListMgr::onRemoveFriend( Entity::Player& source, Entity::Player& target )
|
||||
{
|
||||
// remove friend
|
||||
// this not retail accurate - retail only removes source friendlist, but that also makes it more complicated for readding friend
|
||||
// this will simply remove the entry from both players
|
||||
|
||||
return onInviteDecline( source, target );
|
||||
}
|
||||
|
||||
bool Sapphire::World::Manager::FriendListMgr::onAssignGroup( Entity::Player& source, Entity::Player& target, uint8_t group )
|
||||
{
|
||||
// assign group to friend entry (to source only)
|
||||
auto sourceIdx = getEntryIndex( source, target.getCharacterId() );
|
||||
|
||||
if( sourceIdx == -1 )
|
||||
{
|
||||
// currently not friends
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& sourceFLData = source.getFriendListData();
|
||||
|
||||
sourceFLData[ sourceIdx ].data.group = group;
|
||||
|
||||
source.updateDbFriendList();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ptrdiff_t Sapphire::World::Manager::FriendListMgr::getEntryIndex( Entity::Player& source, uint64_t characterId )
|
||||
{
|
||||
auto& sourceFL = source.getFriendListID();
|
||||
auto sourceInvIt = std::find( std::begin( sourceFL ), std::end( sourceFL ), characterId );
|
||||
|
||||
// not found
|
||||
if( sourceInvIt == sourceFL.end() )
|
||||
return -1;
|
||||
|
||||
return sourceInvIt - std::begin( sourceFL );
|
||||
}
|
25
src/world/Manager/FriendListMgr.h
Normal file
25
src/world/Manager/FriendListMgr.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "ForwardsZone.h"
|
||||
|
||||
namespace Sapphire::World::Manager
|
||||
{
|
||||
class FriendListMgr
|
||||
{
|
||||
public:
|
||||
FriendListMgr() = default;
|
||||
|
||||
bool onInviteCreate( Entity::Player& source, Entity::Player& target );
|
||||
|
||||
bool onInviteAccept( Entity::Player& source, Entity::Player& target );
|
||||
bool onInviteDecline( Entity::Player& source, Entity::Player& target );
|
||||
|
||||
bool onRemoveFriend( Entity::Player& source, Entity::Player& target );
|
||||
bool onAssignGroup( Entity::Player& source, Entity::Player& target, uint8_t group );
|
||||
|
||||
private:
|
||||
ptrdiff_t getEntryIndex( Entity::Player& source, uint64_t characterId );
|
||||
};
|
||||
}
|
|
@ -141,6 +141,8 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH
|
|||
setZoneHandler( PcPartyKick, "PcPartyKick", &GameConnection::pcPartyKickHandler );
|
||||
setZoneHandler( PcPartyChangeLeader, "PcPartyChangeLeader", &GameConnection::pcPartyChangeLeaderHandler );
|
||||
|
||||
setZoneHandler( FriendlistRemove, "FriendlistRemove", &GameConnection::friendlistRemoveHandler );
|
||||
setZoneHandler( SetFriendlistGroup, "SetFriendlistGroup", &GameConnection::setFriendlistGroupHandler );
|
||||
}
|
||||
|
||||
Sapphire::Network::GameConnection::~GameConnection() = default;
|
||||
|
|
|
@ -217,6 +217,8 @@ namespace Sapphire::Network
|
|||
DECLARE_HANDLER( pcPartyKickHandler );
|
||||
DECLARE_HANDLER( pcPartyChangeLeaderHandler );
|
||||
|
||||
DECLARE_HANDLER( friendlistRemoveHandler );
|
||||
DECLARE_HANDLER( setFriendlistGroupHandler );
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -58,10 +58,9 @@ void Sapphire::Network::GameConnection::getCommonlistDetailHandler( const Packet
|
|||
|
||||
// serialize class data to packet
|
||||
|
||||
// todo: fix 28 (common::classjob count does not match packet size)
|
||||
auto classDataArr = pPlayer->getClassArray();
|
||||
|
||||
for( size_t i = 0; i < 28; ++i )
|
||||
for( size_t i = 0; i < Common::CLASSJOB_TOTAL; ++i )
|
||||
{
|
||||
resultPacket->data().ClassData[ i ].id = static_cast< uint16_t >( i );
|
||||
resultPacket->data().ClassData[ i ].level = classDataArr[ i ];
|
||||
|
@ -76,7 +75,8 @@ void Sapphire::Network::GameConnection::getCommonlistHandler( const Packets::FFX
|
|||
// TODO: possibly move lambda func to util
|
||||
auto& server = Common::Service< World::WorldServer >::ref();
|
||||
|
||||
auto generateEntries = [&]( const auto& idVec, size_t offset ) -> std::vector< PlayerEntry >
|
||||
// this func paginates any commonlist entry, associating them with online player data and hierarchy ID (optional)
|
||||
auto generateEntries = [&]( const auto& idVec, size_t offset, const std::vector< Common::HierarchyData >& hierarchyVec ) -> std::vector< PlayerEntry >
|
||||
{
|
||||
std::vector< PlayerEntry > entries;
|
||||
|
||||
|
@ -90,8 +90,8 @@ void Sapphire::Network::GameConnection::getCommonlistHandler( const Packets::FFX
|
|||
}
|
||||
|
||||
auto id = idVec[ i ];
|
||||
|
||||
auto pPlayer = server.getPlayer( id );
|
||||
|
||||
if( !pPlayer )
|
||||
continue;
|
||||
|
||||
|
@ -101,8 +101,14 @@ void Sapphire::Network::GameConnection::getCommonlistHandler( const Packets::FFX
|
|||
|
||||
if( isConnected )
|
||||
{
|
||||
entry.TerritoryType = pPlayer->getCurrentTerritory()->getTerritoryTypeId();
|
||||
entry.TerritoryID = pPlayer->getCurrentTerritory()->getTerritoryTypeId();
|
||||
// todo: fix odd teri nullptr on login for friendlist etc
|
||||
auto pTeri = pPlayer->getCurrentTerritory();
|
||||
if( pTeri )
|
||||
{
|
||||
entry.TerritoryType = pPlayer->getCurrentTerritory()->getTerritoryTypeId();
|
||||
entry.TerritoryID = pPlayer->getCurrentTerritory()->getTerritoryTypeId();
|
||||
}
|
||||
|
||||
entry.CurrentClassID = static_cast< uint8_t >( pPlayer->getClass() );
|
||||
entry.SelectClassID = static_cast< uint8_t >( pPlayer->getSearchSelectClass() );
|
||||
|
||||
|
@ -122,10 +128,20 @@ void Sapphire::Network::GameConnection::getCommonlistHandler( const Packets::FFX
|
|||
entry.CharacterID = pPlayer->getCharacterId();
|
||||
strcpy( entry.CharacterName, pPlayer->getName().c_str() );
|
||||
|
||||
if( hierarchyVec.size() > 0 )
|
||||
{
|
||||
auto hierarchy = hierarchyVec[ i ];
|
||||
|
||||
entry.Timestamp = hierarchy.data.dateAdded;
|
||||
entry.HierarchyStatus = hierarchy.data.status;
|
||||
entry.HierarchyType = hierarchy.data.type;
|
||||
entry.HierarchyGroup = hierarchy.data.group;
|
||||
entry.HierarchyUnk = hierarchy.data.unk;
|
||||
}
|
||||
|
||||
entries.emplace_back( entry );
|
||||
}
|
||||
|
||||
|
||||
return entries;
|
||||
};
|
||||
|
||||
|
@ -156,7 +172,7 @@ void Sapphire::Network::GameConnection::getCommonlistHandler( const Packets::FFX
|
|||
auto pParty = partyMgr.getParty( player.getPartyId() );
|
||||
assert( pParty );
|
||||
|
||||
page = generateEntries( pParty->MemberId, offset );
|
||||
page = generateEntries( pParty->MemberId, offset, {} );
|
||||
|
||||
// ensure first entry is the player requesting packet
|
||||
for( int i = 0; i < 8; ++i )
|
||||
|
@ -172,32 +188,17 @@ void Sapphire::Network::GameConnection::getCommonlistHandler( const Packets::FFX
|
|||
else
|
||||
{
|
||||
std::vector< uint32_t > soloParty = { player.getId() };
|
||||
page = generateEntries( soloParty, offset );
|
||||
page = generateEntries( soloParty, offset, {} );
|
||||
}
|
||||
}
|
||||
else if( data.ListType == 0x0b )
|
||||
{ // friend list
|
||||
/* listPacket->data().entries[ 0 ].TerritoryType = player.getCurrentTerritory()->getTerritoryTypeId();
|
||||
listPacket->data().entries[ 0 ].TerritoryID = player.getCurrentTerritory()->getTerritoryTypeId();
|
||||
listPacket->data().entries[ 0 ].CurrentClassID = static_cast< uint8_t >( player.getClass() );
|
||||
listPacket->data().entries[ 0 ].SelectClassID = static_cast< uint8_t >( player.getClass() );
|
||||
listPacket->data().entries[ 0 ].CharacterID = player.getContentId();
|
||||
listPacket->data().entries[ 0 ].CurrentLevel = player.getLevel();
|
||||
listPacket->data().entries[ 0 ].SelectLevel = player.getLevel();
|
||||
listPacket->data().entries[ 0 ].Identity = 1;
|
||||
auto& friendList = player.getFriendListID();
|
||||
auto& friendListData = player.getFriendListData();
|
||||
|
||||
strcpy( listPacket->data().entries[ 0 ].CharacterName, player.getName().c_str() );
|
||||
std::vector< Common::HierarchyData > hierarchyData( friendListData.begin(), friendListData.end() );
|
||||
|
||||
// GC icon
|
||||
listPacket->data().entries[ 0 ].GrandCompanyID = 2;
|
||||
// client language J = 0, E = 1, D = 2, F = 3
|
||||
listPacket->data().entries[ 0 ].Region = 1;
|
||||
// user language settings flag J = 1, E = 2, D = 4, F = 8
|
||||
listPacket->data().entries[ 0 ].SelectRegion = 1 + 2;
|
||||
listPacket->data().entries[ 0 ].OnlineStatus = player.getOnlineStatusMask();
|
||||
listPacket->data().entries[ 0 ].HierarchyID = 0x20;*/
|
||||
offset = 0;
|
||||
isLast = true;
|
||||
page = generateEntries( friendList, offset, hierarchyData );
|
||||
}
|
||||
else if( data.ListType == 0x0c )
|
||||
{ // linkshell
|
||||
|
@ -213,13 +214,13 @@ void Sapphire::Network::GameConnection::getCommonlistHandler( const Packets::FFX
|
|||
std::vector< uint64_t > memberVec;
|
||||
std::copy( memberSet.begin(), memberSet.end(), std::back_inserter( memberVec ) );
|
||||
|
||||
page = generateEntries( memberVec, offset );
|
||||
page = generateEntries( memberVec, offset, {} );
|
||||
}
|
||||
}
|
||||
else if( data.ListType == 0x0e )
|
||||
{ // player search result
|
||||
auto queryPlayers = player.getLastPcSearchResult();
|
||||
page = generateEntries( queryPlayers, offset );
|
||||
page = generateEntries( queryPlayers, offset, {} );
|
||||
}
|
||||
|
||||
// if we didn't manually terminate pagination (party, etc), check if we need to do so
|
||||
|
|
63
src/world/Network/Handlers/FriendListHandlers.cpp
Normal file
63
src/world/Network/Handlers/FriendListHandlers.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include <Common.h>
|
||||
#include <Network/CommonNetwork.h>
|
||||
#include <Network/GamePacket.h>
|
||||
|
||||
#include <Network/PacketContainer.h>
|
||||
#include <Exd/ExdData.h>
|
||||
#include <Service.h>
|
||||
#include <Network/PacketDef/Zone/ClientZoneDef.h>
|
||||
#include <Network/PacketDef/Zone/ServerZoneDef.h>
|
||||
|
||||
#include "Manager/FriendListMgr.h"
|
||||
|
||||
#include "Network/GameConnection.h"
|
||||
|
||||
#include "Actor/Player.h"
|
||||
#include "WorldServer.h"
|
||||
|
||||
using namespace Sapphire::Common;
|
||||
using namespace Sapphire::Network::Packets;
|
||||
using namespace Sapphire::Network::Packets::WorldPackets;
|
||||
using namespace Sapphire::World::Manager;
|
||||
|
||||
void Sapphire::Network::GameConnection::friendlistRemoveHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||
Entity::Player& player )
|
||||
{
|
||||
const auto packet = ZoneChannelPacket< Client::FFXIVIpcFriendlistRemove >( inPacket );
|
||||
const auto& data = packet.data();
|
||||
|
||||
auto& server = Common::Service< Sapphire::World::WorldServer >::ref();
|
||||
auto& flMgr = Common::Service< Sapphire::World::Manager::FriendListMgr >::ref();
|
||||
|
||||
auto target = server.getPlayer( data.TargetCharacterID );
|
||||
if( !target )
|
||||
return;
|
||||
|
||||
flMgr.onRemoveFriend( player, *target );
|
||||
|
||||
auto replyPacket = makeZonePacket< WorldPackets::Server::FFXIVIpcFriendlistRemoveResult >( player.getId() );
|
||||
auto& replyData = replyPacket->data();
|
||||
|
||||
replyData.RemovedCharacterID = target->getCharacterId();
|
||||
replyData.Identity = target->getGender();
|
||||
replyData.Result = 0;
|
||||
strcpy( replyData.RemovedCharacterName, target->getName().c_str() );
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), replyPacket );
|
||||
}
|
||||
|
||||
void Sapphire::Network::GameConnection::setFriendlistGroupHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||
Entity::Player& player )
|
||||
{
|
||||
const auto packet = ZoneChannelPacket< Client::FFXIVIpcSetFriendlistGroup >( inPacket );
|
||||
const auto& data = packet.data();
|
||||
|
||||
auto& server = Common::Service< Sapphire::World::WorldServer >::ref();
|
||||
auto& flMgr = Common::Service< Sapphire::World::Manager::FriendListMgr >::ref();
|
||||
|
||||
auto target = server.getPlayer( data.TargetCharacterID );
|
||||
if( !target )
|
||||
return;
|
||||
|
||||
flMgr.onAssignGroup( player, *target, data.group );
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include "Network/PacketWrappers/PlayerSetupPacket.h"
|
||||
#include "Network/PacketWrappers/InviteUpdatePacket.h"
|
||||
|
||||
#include "Manager/FriendListMgr.h"
|
||||
#include "Manager/PartyMgr.h"
|
||||
#include "Manager/PlayerMgr.h"
|
||||
|
||||
|
@ -55,7 +56,7 @@ void Sapphire::Network::GameConnection::inviteHandler( const Sapphire::Network::
|
|||
|
||||
switch( packet.data().AuthType )
|
||||
{
|
||||
case InviteType::PCPARTY:
|
||||
case HierarchyType::PCPARTY:
|
||||
{
|
||||
auto inviteResultPacket = makeZonePacket< WorldPackets::Server::FFXIVIpcInviteResult >( player.getId() );
|
||||
auto& data = inviteResultPacket->data();
|
||||
|
@ -71,7 +72,7 @@ void Sapphire::Network::GameConnection::inviteHandler( const Sapphire::Network::
|
|||
break;
|
||||
}
|
||||
|
||||
case InviteType::FRIENDLIST:
|
||||
case HierarchyType::FRIENDLIST:
|
||||
{
|
||||
auto inviteResultPacket = makeZonePacket< WorldPackets::Server::FFXIVIpcInviteResult >( player.getId() );
|
||||
auto& data = inviteResultPacket->data();
|
||||
|
@ -79,22 +80,31 @@ void Sapphire::Network::GameConnection::inviteHandler( const Sapphire::Network::
|
|||
strcpy( data.TargetName, packet.data().TargetName );
|
||||
server.queueForPlayer( player.getCharacterId(), inviteResultPacket );
|
||||
|
||||
auto invitePacket = std::make_shared< InviteUpdatePacket >( player, Common::Util::getTimeSeconds() + 30,
|
||||
auto invitePacket = std::make_shared< InviteUpdatePacket >( player, 0,
|
||||
packet.data().AuthType, 1,
|
||||
InviteUpdateType::NEW_INVITE );
|
||||
pSession->getZoneConnection()->queueOutPacket( invitePacket );
|
||||
|
||||
auto& flMgr = Common::Service< FriendListMgr >::ref();
|
||||
|
||||
// add support to adding offline players
|
||||
auto target = server.getPlayer( data.TargetName );
|
||||
if( !target )
|
||||
return;
|
||||
|
||||
flMgr.onInviteCreate( player, *target );
|
||||
|
||||
break;
|
||||
}
|
||||
case Common::InviteType::AUTOPARTY:
|
||||
case HierarchyType::AUTOPARTY:
|
||||
break;
|
||||
case Common::InviteType::FCCREATE:
|
||||
case HierarchyType::FCCREATE:
|
||||
break;
|
||||
case Common::InviteType::FREECOMPANY:
|
||||
case HierarchyType::FREECOMPANY:
|
||||
break;
|
||||
case Common::InviteType::FCJOINREQUEST:
|
||||
case HierarchyType::FCJOINREQUEST:
|
||||
break;
|
||||
case Common::InviteType::PARTYCANCEL:
|
||||
case HierarchyType::PARTYCANCEL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -108,19 +118,19 @@ void Sapphire::Network::GameConnection::inviteReplyHandler( const FFXIVARR_PACKE
|
|||
auto& server = Common::Service< Sapphire::World::WorldServer >::ref();
|
||||
auto pSession = server.getSession( data.InviteCharacterID );
|
||||
|
||||
auto& partyMgr = Common::Service< Sapphire::World::Manager::PartyMgr >::ref();
|
||||
|
||||
if( !pSession )
|
||||
return;
|
||||
|
||||
auto inviteReplyPacket = makeZonePacket< WorldPackets::Server::FFXIVIpcInviteReplyResult >( player.getId() );
|
||||
auto& inviteReplyData = inviteReplyPacket->data();
|
||||
inviteReplyData.Answer = data.Answer;
|
||||
|
||||
switch( data.AuthType )
|
||||
{
|
||||
case Common::InviteType::PCPARTY:
|
||||
case HierarchyType::PCPARTY:
|
||||
{
|
||||
auto inviteReplyPacket = makeZonePacket< WorldPackets::Server::FFXIVIpcInviteReplyResult >( player.getId() );
|
||||
auto& inviteReplyData = inviteReplyPacket->data();
|
||||
auto& partyMgr = Common::Service< Sapphire::World::Manager::PartyMgr >::ref();
|
||||
|
||||
inviteReplyData.Answer = data.Answer;
|
||||
uint8_t result;
|
||||
if( data.Answer == InviteReplyType::ACCEPT )
|
||||
{
|
||||
|
@ -142,17 +152,41 @@ void Sapphire::Network::GameConnection::inviteReplyHandler( const FFXIVARR_PACKE
|
|||
|
||||
break;
|
||||
}
|
||||
case Common::InviteType::FRIENDLIST:
|
||||
case HierarchyType::FRIENDLIST:
|
||||
{
|
||||
auto& flMgr = Common::Service< Sapphire::World::Manager::FriendListMgr >::ref();
|
||||
|
||||
uint8_t result;
|
||||
if( data.Answer == InviteReplyType::ACCEPT )
|
||||
{
|
||||
flMgr.onInviteAccept( player, *pSession->getPlayer() );
|
||||
result = InviteUpdateType::ACCEPT_INVITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
flMgr.onInviteDecline( player, *pSession->getPlayer() );
|
||||
result = InviteUpdateType::REJECT_INVITE;
|
||||
}
|
||||
|
||||
auto inviteUpPacket = std::make_shared< InviteUpdatePacket >( player, 0,
|
||||
data.AuthType, 1, result );
|
||||
pSession->getZoneConnection()->queueOutPacket( inviteUpPacket );
|
||||
|
||||
inviteReplyData.AuthType = data.AuthType;
|
||||
strcpy( inviteReplyData.InviteCharacterName, pSession->getPlayer()->getName().c_str() );
|
||||
server.queueForPlayer( player.getCharacterId(), inviteReplyPacket );
|
||||
|
||||
break;
|
||||
case Common::InviteType::AUTOPARTY:
|
||||
}
|
||||
case HierarchyType::AUTOPARTY:
|
||||
break;
|
||||
case Common::InviteType::FCCREATE:
|
||||
case HierarchyType::FCCREATE:
|
||||
break;
|
||||
case Common::InviteType::FREECOMPANY:
|
||||
case HierarchyType::FREECOMPANY:
|
||||
break;
|
||||
case Common::InviteType::FCJOINREQUEST:
|
||||
case HierarchyType::FCJOINREQUEST:
|
||||
break;
|
||||
case Common::InviteType::PARTYCANCEL:
|
||||
case HierarchyType::PARTYCANCEL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
#include "Manager/PartyMgr.h"
|
||||
|
||||
#include "Territory/InstanceContent.h"
|
||||
|
||||
#include "Network/GameConnection.h"
|
||||
|
||||
#include "Session.h"
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "Manager/ChatChannelMgr.h"
|
||||
#include "Manager/QuestMgr.h"
|
||||
#include "Manager/PartyMgr.h"
|
||||
#include "Manager/FriendListMgr.h"
|
||||
|
||||
#include "ContentFinder/ContentFinder.h"
|
||||
|
||||
|
@ -239,6 +240,7 @@ void Sapphire::World::WorldServer::run( int32_t argc, char* argv[] )
|
|||
auto pRNGMgr = std::make_shared< Manager::RNGMgr >();
|
||||
auto pQuestMgr = std::make_shared< Manager::QuestMgr >();
|
||||
auto pPartyMgr = std::make_shared< Manager::PartyMgr >();
|
||||
auto pFriendMgr = std::make_shared< Manager::FriendListMgr >();
|
||||
auto contentFinder = std::make_shared< ContentFinder >();
|
||||
|
||||
Common::Service< DebugCommandMgr >::set( pDebugCom );
|
||||
|
@ -250,6 +252,7 @@ void Sapphire::World::WorldServer::run( int32_t argc, char* argv[] )
|
|||
Common::Service< Manager::RNGMgr >::set( pRNGMgr );
|
||||
Common::Service< Manager::QuestMgr >::set( pQuestMgr );
|
||||
Common::Service< Manager::PartyMgr >::set( pPartyMgr );
|
||||
Common::Service< Manager::FriendListMgr >::set( pFriendMgr );
|
||||
Common::Service< ContentFinder >::set( contentFinder );
|
||||
|
||||
auto& exdData = Common::Service< Sapphire::Data::ExdData >::ref();
|
||||
|
|
Loading…
Add table
Reference in a new issue