1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-04 17:57:47 +00:00
sapphire/src/world/Manager/BlacklistMgr.cpp

226 lines
6.4 KiB
C++

#include <algorithm>
#include <iterator>
#include <Logging/Logger.h>
#include <Service.h>
#include <Util/Util.h>
#include <Network/PacketDef/Zone/ServerZoneDef.h>
#include <Network/PacketContainer.h>
#include "Actor/Player.h"
#include "BlacklistMgr.h"
#include "FriendListMgr.h"
#include "WorldServer.h"
using namespace Sapphire::Common;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::WorldPackets;
bool Sapphire::World::Manager::BlacklistMgr::onAddCharacter( Entity::Player& source, const std::string& targetName )
{
// add target to blacklist
auto& server = Common::Service< Sapphire::World::WorldServer >::ref();
auto pTarget = server.getPlayer( targetName );
if( !pTarget )
{
// target doesn't exist in server player table
sendAddResultPacket( source, pTarget, 0x7 );
return false;
}
auto& target = *pTarget;
if( source.getCharacterId() == target.getCharacterId() )
{
// can't add self to blacklist
sendAddResultPacket( source, pTarget, 0x7 );
return false;
}
if( isBlacklisted( source, target ) )
{
// target already added to blacklist
sendAddResultPacket( source, pTarget, 0x7 );
return false;
}
// get next available slot in blacklist
auto sourceIdx = getEntryIndex( source, 0 );
if( sourceIdx == -1 )
{
// no slots left in blacklist (max capacity)
return false;
}
// add target ID to blacklist
auto& sourceBL = source.getBlacklistID();
sourceBL[sourceIdx] = target.getCharacterId();
source.updateDbBlacklist();
sendAddResultPacket( source, pTarget, 0 );
// check if player is friends with target
auto& flMgr = Common::Service< Sapphire::World::Manager::FriendListMgr >::ref();
if( flMgr.isFriend( source, target ) )
flMgr.onRemoveFriend( source, target );
return true;
}
bool Sapphire::World::Manager::BlacklistMgr::onRemoveCharacter( Entity::Player& source, const std::string& targetName )
{
// remove target from blacklist
auto& server = Common::Service< Sapphire::World::WorldServer >::ref();
uint32_t result = 0;
auto pTarget = server.getPlayer( targetName );
if( !pTarget )
{
// target doesn't exist in server player table
sendRemoveResultPacket( source, pTarget, 0x7 );
return false;
}
auto& target = *pTarget;
auto sourceIdx = getEntryIndex( source, target.getCharacterId() );
if( !isBlacklisted( source, target ) )
{
// target not in blacklist
sendRemoveResultPacket( source, pTarget, 0x7 );
return false;
}
// set target slot to 0
auto& sourceBL = source.getBlacklistID();
sourceBL[sourceIdx] = 0;
source.updateDbBlacklist();
sendRemoveResultPacket( source, pTarget, 0 );
return true;
}
bool Sapphire::World::Manager::BlacklistMgr::onGetBlacklistPage( Entity::Player& source, uint8_t key, uint8_t nextIdx )
{
// this function will handle client side indexing and paginate blacklist entries
// it'll also be called multiple times sequentially until there are no more entries left (id == 0)
auto& server = Common::Service< Sapphire::World::WorldServer >::ref();
std::vector< Server::BlacklistCharacter > entries;
// blacklist entries are sent in pages of 20
const size_t itemsPerPage = 20;
// get array offset/last page sent from client packet
auto offset = nextIdx;
auto& idVec = source.getBlacklistID();
for( size_t i = offset; i < offset + itemsPerPage; ++i )
{
if( idVec.size() <= i )
{
break;
}
auto id = idVec[ i ];
auto pPlayer = server.getPlayer( id );
if( !pPlayer )
continue;
// build our packet entry for current iterated id
Server::BlacklistCharacter entry{};
entry.CharacterID = pPlayer->getCharacterId();
strcpy( entry.CharacterName, pPlayer->getName().c_str() );
// add to current page
entries.emplace_back( entry );
}
// if the page is empty, then we've reached the last page
bool isLast = entries.empty();
// configure paging state for client so that it knows whether to request more entries or not
auto blacklistPacket = makeZonePacket< Server::FFXIVIpcGetBlacklistResult >( source.getId() );
blacklistPacket->data().Index = offset;
blacklistPacket->data().NextIndex = isLast ? 0 : nextIdx + itemsPerPage;
blacklistPacket->data().RequestKey = key;
memcpy( &blacklistPacket->data().Blacklist[ 0 ], entries.data(), sizeof( Server::BlacklistCharacter ) * entries.size() );
server.queueForPlayer( source.getCharacterId(), blacklistPacket );
return true;
}
bool Sapphire::World::Manager::BlacklistMgr::isBlacklisted( Entity::Player& source, Entity::Player& target ) const
{
return getEntryIndex( source, target.getCharacterId() ) != -1;
}
ptrdiff_t Sapphire::World::Manager::BlacklistMgr::getEntryIndex( Entity::Player& source, uint64_t characterId ) const
{
auto& sourceBL = source.getBlacklistID();
auto sourceBlIt = std::find( std::begin( sourceBL ), std::end( sourceBL ), characterId );
// not found
if( sourceBlIt == sourceBL.end() )
return -1;
return sourceBlIt - std::begin( sourceBL );
}
void Sapphire::World::Manager::BlacklistMgr::sendAddResultPacket( Entity::Player& source, Entity::PlayerPtr pTarget, uint32_t result )
{
auto& server = Common::Service< Sapphire::World::WorldServer >::ref();
auto resultPacket = makeZonePacket< Server::FFXIVIpcBlacklistAddResult >( source.getId() );
if( pTarget )
{
Server::BlacklistCharacter blChar;
blChar.CharacterID = pTarget->getCharacterId();
strcpy( blChar.CharacterName, pTarget->getName().c_str() );
resultPacket->data().AddedCharacter = blChar;
resultPacket->data().Identity = pTarget->getGender();
}
resultPacket->data().Result = result;
server.queueForPlayer( source.getCharacterId(), resultPacket );
}
void Sapphire::World::Manager::BlacklistMgr::sendRemoveResultPacket( Entity::Player& source, Entity::PlayerPtr pTarget, uint32_t result )
{
auto& server = Common::Service< Sapphire::World::WorldServer >::ref();
auto resultPacket = makeZonePacket< Server::FFXIVIpcBlacklistRemoveResult >( source.getId() );
if( pTarget )
{
Server::BlacklistCharacter blChar;
blChar.CharacterID = pTarget->getCharacterId();
strcpy( blChar.CharacterName, pTarget->getName().c_str() );
resultPacket->data().RemovedCharacter = blChar;
resultPacket->data().Identity = pTarget->getGender();
}
resultPacket->data().Result = result;
server.queueForPlayer( source.getCharacterId(), resultPacket );
}