Merge pull request #1307 from DarkflameUniverse/985

feat: Implement ignore list
This commit is contained in:
Gie "Max" Vanommeslaeghe 2023-11-24 00:38:03 +01:00 committed by GitHub
commit af70f871cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 333 additions and 58 deletions

View File

@ -1,4 +1,5 @@
set(DCHATSERVER_SOURCES set(DCHATSERVER_SOURCES
"ChatIgnoreList.cpp"
"ChatPacketHandler.cpp" "ChatPacketHandler.cpp"
"PlayerContainer.cpp" "PlayerContainer.cpp"
) )

View File

@ -0,0 +1,173 @@
#include "ChatIgnoreList.h"
#include "PlayerContainer.h"
#include "eChatInternalMessageType.h"
#include "BitStreamUtils.h"
#include "PacketUtils.h"
#include "Game.h"
#include "Logger.h"
#include "eObjectBits.h"
#include "Database.h"
// A note to future readers, The client handles all the actual ignoring logic:
// not allowing teams, rejecting DMs, friends requets etc.
// The only thing not auto-handled is instance activities force joining the team on the server.
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) {
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receivingPlayer);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, type);
}
void ChatIgnoreList::GetIgnoreList(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerId;
inStream.Read(playerId);
auto* receiver = Game::playerContainer.GetPlayerData(playerId);
if (!receiver) {
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
return;
}
if (!receiver->ignoredPlayers.empty()) {
LOG_DEBUG("Player %llu already has an ignore list", playerId);
return;
}
auto ignoreList = Database::Get()->GetIgnoreList(static_cast<uint32_t>(playerId));
if (ignoreList.empty()) {
LOG_DEBUG("Player %llu has no ignores", playerId);
return;
}
for (auto& ignoredPlayer : ignoreList) {
receiver->ignoredPlayers.push_back(IgnoreData{ ignoredPlayer.id, ignoredPlayer.name });
GeneralUtils::SetBit(receiver->ignoredPlayers.back().playerId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(receiver->ignoredPlayers.back().playerId, eObjectBits::PERSISTENT);
}
CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::GET_IGNORE);
bitStream.Write<uint8_t>(false); // Probably is Is Free Trial, but we don't care about that
bitStream.Write<uint16_t>(0); // literally spacing due to struct alignment
bitStream.Write<uint16_t>(receiver->ignoredPlayers.size());
for (const auto& ignoredPlayer : receiver->ignoredPlayers) {
bitStream.Write(ignoredPlayer.playerId);
bitStream.Write(LUWString(ignoredPlayer.playerName, 36));
}
Game::server->Send(&bitStream, packet->systemAddress, false);
}
void ChatIgnoreList::AddIgnore(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerId;
inStream.Read(playerId);
auto* receiver = Game::playerContainer.GetPlayerData(playerId);
if (!receiver) {
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
return;
}
constexpr int32_t MAX_IGNORES = 32;
if (receiver->ignoredPlayers.size() > MAX_IGNORES) {
LOG_DEBUG("Player %llu has too many ignores", playerId);
return;
}
inStream.IgnoreBytes(4); // ignore some garbage zeros idk
LUWString toIgnoreName(33);
inStream.Read(toIgnoreName);
std::string toIgnoreStr = toIgnoreName.GetAsString();
CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::ADD_IGNORE);
// Check if the player exists
LWOOBJID ignoredPlayerId = LWOOBJID_EMPTY;
if (toIgnoreStr == receiver->playerName || toIgnoreStr.find("[GM]") == 0) {
LOG_DEBUG("Player %llu tried to ignore themselves", playerId);
bitStream.Write(ChatIgnoreList::AddResponse::GENERAL_ERROR);
} else if (std::count(receiver->ignoredPlayers.begin(), receiver->ignoredPlayers.end(), toIgnoreStr) > 0) {
LOG_DEBUG("Player %llu is already ignoring %s", playerId, toIgnoreStr.c_str());
bitStream.Write(ChatIgnoreList::AddResponse::ALREADY_IGNORED);
} else {
// Get the playerId falling back to query if not online
auto* playerData = Game::playerContainer.GetPlayerData(toIgnoreStr);
if (!playerData) {
// Fall back to query
auto player = Database::Get()->GetCharacterInfo(toIgnoreStr);
if (!player || player->name != toIgnoreStr) {
LOG_DEBUG("Player %s not found", toIgnoreStr.c_str());
} else {
ignoredPlayerId = player->id;
}
} else {
ignoredPlayerId = playerData->playerID;
}
if (ignoredPlayerId != LWOOBJID_EMPTY) {
Database::Get()->AddIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(ignoredPlayerId));
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::PERSISTENT);
receiver->ignoredPlayers.push_back(IgnoreData{ ignoredPlayerId, toIgnoreStr });
LOG_DEBUG("Player %llu is ignoring %s", playerId, toIgnoreStr.c_str());
bitStream.Write(ChatIgnoreList::AddResponse::SUCCESS);
} else {
bitStream.Write(ChatIgnoreList::AddResponse::PLAYER_NOT_FOUND);
}
}
LUWString playerNameSend(toIgnoreStr, 33);
bitStream.Write(playerNameSend);
bitStream.Write(ignoredPlayerId);
Game::server->Send(&bitStream, packet->systemAddress, false);
}
void ChatIgnoreList::RemoveIgnore(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerId;
inStream.Read(playerId);
auto* receiver = Game::playerContainer.GetPlayerData(playerId);
if (!receiver) {
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
return;
}
inStream.IgnoreBytes(4); // ignore some garbage zeros idk
LUWString removedIgnoreName(33);
inStream.Read(removedIgnoreName);
std::string removedIgnoreStr = removedIgnoreName.GetAsString();
auto toRemove = std::remove(receiver->ignoredPlayers.begin(), receiver->ignoredPlayers.end(), removedIgnoreStr);
if (toRemove == receiver->ignoredPlayers.end()) {
LOG_DEBUG("Player %llu is not ignoring %s", playerId, removedIgnoreStr.c_str());
return;
}
Database::Get()->RemoveIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(toRemove->playerId));
receiver->ignoredPlayers.erase(toRemove, receiver->ignoredPlayers.end());
CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::REMOVE_IGNORE);
bitStream.Write<int8_t>(0);
LUWString playerNameSend(removedIgnoreStr, 33);
bitStream.Write(playerNameSend);
Game::server->Send(&bitStream, packet->systemAddress, false);
}

View File

@ -0,0 +1,27 @@
#ifndef __CHATIGNORELIST__H__
#define __CHATIGNORELIST__H__
struct Packet;
#include <cstdint>
namespace ChatIgnoreList {
void GetIgnoreList(Packet* packet);
void AddIgnore(Packet* packet);
void RemoveIgnore(Packet* packet);
enum class Response : uint8_t {
ADD_IGNORE = 32,
REMOVE_IGNORE = 33,
GET_IGNORE = 34,
};
enum class AddResponse : uint8_t {
SUCCESS,
ALREADY_IGNORED,
PLAYER_NOT_FOUND,
GENERAL_ERROR,
};
};
#endif //!__CHATIGNORELIST__H__

View File

@ -19,15 +19,13 @@
#include "eClientMessageType.h" #include "eClientMessageType.h"
#include "eGameMessageType.h" #include "eGameMessageType.h"
extern PlayerContainer playerContainer;
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Get from the packet which player we want to do something with: //Get from the packet which player we want to do something with:
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = 0; LWOOBJID playerID = 0;
inStream.Read(playerID); inStream.Read(playerID);
auto player = playerContainer.GetPlayerData(playerID); auto player = Game::playerContainer.GetPlayerData(playerID);
if (!player) return; if (!player) return;
auto friendsList = Database::Get()->GetFriendsList(playerID); auto friendsList = Database::Get()->GetFriendsList(playerID);
@ -43,7 +41,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
fd.friendName = friendData.friendName; fd.friendName = friendData.friendName;
//Now check if they're online: //Now check if they're online:
auto fr = playerContainer.GetPlayerData(fd.friendID); auto fr = Game::playerContainer.GetPlayerData(fd.friendID);
if (fr) { if (fr) {
fd.isOnline = true; fd.isOnline = true;
@ -97,7 +95,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
char isBestFriendRequest{}; char isBestFriendRequest{};
inStream.Read(isBestFriendRequest); inStream.Read(isBestFriendRequest);
auto requestor = playerContainer.GetPlayerData(requestorPlayerID); auto requestor = Game::playerContainer.GetPlayerData(requestorPlayerID);
if (!requestor) { if (!requestor) {
LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str()); LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
return; return;
@ -107,7 +105,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN); SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
return; return;
}; };
std::unique_ptr<PlayerData> requestee(playerContainer.GetPlayerData(playerName)); std::unique_ptr<PlayerData> requestee(Game::playerContainer.GetPlayerData(playerName));
// Check if player is online first // Check if player is online first
if (isBestFriendRequest && !requestee) { if (isBestFriendRequest && !requestee) {
@ -175,7 +173,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
// Only do updates if there was a change in the bff status. // Only do updates if there was a change in the bff status.
if (oldBestFriendStatus != bestFriendStatus) { if (oldBestFriendStatus != bestFriendStatus) {
auto maxBestFriends = playerContainer.GetMaxNumberOfBestFriends(); auto maxBestFriends = Game::playerContainer.GetMaxNumberOfBestFriends();
if (requestee->countOfBestFriends >= maxBestFriends || requestor->countOfBestFriends >= maxBestFriends) { if (requestee->countOfBestFriends >= maxBestFriends || requestor->countOfBestFriends >= maxBestFriends) {
if (requestee->countOfBestFriends >= maxBestFriends) { if (requestee->countOfBestFriends >= maxBestFriends) {
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false); SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
@ -208,7 +206,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::WAITINGAPPROVAL, true, true); if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::WAITINGAPPROVAL, true, true);
} }
} else { } else {
auto maxFriends = playerContainer.GetMaxNumberOfFriends(); auto maxFriends = Game::playerContainer.GetMaxNumberOfFriends();
if (requestee->friends.size() >= maxFriends) { if (requestee->friends.size() >= maxFriends) {
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false); SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
} else if (requestor->friends.size() >= maxFriends) { } else if (requestor->friends.size() >= maxFriends) {
@ -232,8 +230,8 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
std::string friendName = PacketUtils::ReadString(0x15, packet, true); std::string friendName = PacketUtils::ReadString(0x15, packet, true);
//Now to try and find both of these: //Now to try and find both of these:
auto requestor = playerContainer.GetPlayerData(playerID); auto requestor = Game::playerContainer.GetPlayerData(playerID);
auto requestee = playerContainer.GetPlayerData(friendName); auto requestee = Game::playerContainer.GetPlayerData(friendName);
if (!requestor || !requestee) return; if (!requestor || !requestee) return;
eAddFriendResponseType serverResponseCode{}; eAddFriendResponseType serverResponseCode{};
@ -315,7 +313,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
Database::Get()->RemoveFriend(playerID, friendID); Database::Get()->RemoveFriend(playerID, friendID);
//Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended: //Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended:
auto goonA = playerContainer.GetPlayerData(playerID); auto goonA = Game::playerContainer.GetPlayerData(playerID);
if (goonA) { if (goonA) {
// Remove the friend from our list of friends // Remove the friend from our list of friends
for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) { for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) {
@ -328,7 +326,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
SendRemoveFriend(goonA, friendName, true); SendRemoveFriend(goonA, friendName, true);
} }
auto goonB = playerContainer.GetPlayerData(friendID); auto goonB = Game::playerContainer.GetPlayerData(friendID);
if (!goonB) return; if (!goonB) return;
// Do it again for other person // Do it again for other person
for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) { for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) {
@ -339,7 +337,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
} }
} }
std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID)); std::string goonAName = GeneralUtils::UTF16ToWTF8(Game::playerContainer.GetName(playerID));
SendRemoveFriend(goonB, goonAName, true); SendRemoveFriend(goonB, goonAName, true);
} }
@ -348,11 +346,11 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
auto* sender = playerContainer.GetPlayerData(playerID); auto* sender = Game::playerContainer.GetPlayerData(playerID);
if (sender == nullptr) return; if (sender == nullptr) return;
if (playerContainer.GetIsMuted(sender)) return; if (Game::playerContainer.GetIsMuted(sender)) return;
const auto senderName = std::string(sender->playerName.c_str()); const auto senderName = std::string(sender->playerName.c_str());
@ -367,12 +365,12 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
if (channel != 8) return; if (channel != 8) return;
auto* team = playerContainer.GetTeam(playerID); auto* team = Game::playerContainer.GetTeam(playerID);
if (team == nullptr) return; if (team == nullptr) return;
for (const auto memberId : team->memberIDs) { for (const auto memberId : team->memberIDs) {
auto* otherMember = playerContainer.GetPlayerData(memberId); auto* otherMember = Game::playerContainer.GetPlayerData(memberId);
if (otherMember == nullptr) return; if (otherMember == nullptr) return;
@ -406,11 +404,11 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
std::string message = PacketUtils::ReadString(0xAA, packet, true, 512); std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
//Get the bois: //Get the bois:
auto goonA = playerContainer.GetPlayerData(senderID); auto goonA = Game::playerContainer.GetPlayerData(senderID);
auto goonB = playerContainer.GetPlayerData(receiverName); auto goonB = Game::playerContainer.GetPlayerData(receiverName);
if (!goonA || !goonB) return; if (!goonA || !goonB) return;
if (playerContainer.GetIsMuted(goonA)) return; if (Game::playerContainer.GetIsMuted(goonA)) return;
std::string goonAName = goonA->playerName.c_str(); std::string goonAName = goonA->playerName.c_str();
std::string goonBName = goonB->playerName.c_str(); std::string goonBName = goonB->playerName.c_str();
@ -468,25 +466,25 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
inStream.Read(playerID); inStream.Read(playerID);
std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true); std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true);
auto* player = playerContainer.GetPlayerData(playerID); auto* player = Game::playerContainer.GetPlayerData(playerID);
if (player == nullptr) { if (player == nullptr) {
return; return;
} }
auto* team = playerContainer.GetTeam(playerID); auto* team = Game::playerContainer.GetTeam(playerID);
if (team == nullptr) { if (team == nullptr) {
team = playerContainer.CreateTeam(playerID); team = Game::playerContainer.CreateTeam(playerID);
} }
auto* other = playerContainer.GetPlayerData(invitedPlayer); auto* other = Game::playerContainer.GetPlayerData(invitedPlayer);
if (other == nullptr) { if (other == nullptr) {
return; return;
} }
if (playerContainer.GetTeam(other->playerID) != nullptr) { if (Game::playerContainer.GetTeam(other->playerID) != nullptr) {
return; return;
} }
@ -519,12 +517,12 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
return; return;
} }
auto* team = playerContainer.GetTeam(leaderID); auto* team = Game::playerContainer.GetTeam(leaderID);
if (team == nullptr) { if (team == nullptr) {
LOG("Failed to find team for leader (%llu)", leaderID); LOG("Failed to find team for leader (%llu)", leaderID);
team = playerContainer.GetTeam(playerID); team = Game::playerContainer.GetTeam(playerID);
} }
if (team == nullptr) { if (team == nullptr) {
@ -532,7 +530,7 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
return; return;
} }
playerContainer.AddMember(team, playerID); Game::playerContainer.AddMember(team, playerID);
} }
void ChatPacketHandler::HandleTeamLeave(Packet* packet) { void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
@ -542,12 +540,12 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
uint32_t size = 0; uint32_t size = 0;
inStream.Read(size); inStream.Read(size);
auto* team = playerContainer.GetTeam(playerID); auto* team = Game::playerContainer.GetTeam(playerID);
LOG("(%llu) leaving team", playerID); LOG("(%llu) leaving team", playerID);
if (team != nullptr) { if (team != nullptr) {
playerContainer.RemoveMember(team, playerID, false, false, true); Game::playerContainer.RemoveMember(team, playerID, false, false, true);
} }
} }
@ -560,24 +558,24 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str()); LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
auto* kicked = playerContainer.GetPlayerData(kickedPlayer); auto* kicked = Game::playerContainer.GetPlayerData(kickedPlayer);
LWOOBJID kickedId = LWOOBJID_EMPTY; LWOOBJID kickedId = LWOOBJID_EMPTY;
if (kicked != nullptr) { if (kicked != nullptr) {
kickedId = kicked->playerID; kickedId = kicked->playerID;
} else { } else {
kickedId = playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer)); kickedId = Game::playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
} }
if (kickedId == LWOOBJID_EMPTY) return; if (kickedId == LWOOBJID_EMPTY) return;
auto* team = playerContainer.GetTeam(playerID); auto* team = Game::playerContainer.GetTeam(playerID);
if (team != nullptr) { if (team != nullptr) {
if (team->leaderID != playerID || team->leaderID == kickedId) return; if (team->leaderID != playerID || team->leaderID == kickedId) return;
playerContainer.RemoveMember(team, kickedId, false, true, false); Game::playerContainer.RemoveMember(team, kickedId, false, true, false);
} }
} }
@ -590,16 +588,16 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str()); LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
auto* promoted = playerContainer.GetPlayerData(promotedPlayer); auto* promoted = Game::playerContainer.GetPlayerData(promotedPlayer);
if (promoted == nullptr) return; if (promoted == nullptr) return;
auto* team = playerContainer.GetTeam(playerID); auto* team = Game::playerContainer.GetTeam(playerID);
if (team != nullptr) { if (team != nullptr) {
if (team->leaderID != playerID) return; if (team->leaderID != playerID) return;
playerContainer.PromoteMember(team, promoted->playerID); Game::playerContainer.PromoteMember(team, promoted->playerID);
} }
} }
@ -613,16 +611,16 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet) {
char option; char option;
inStream.Read(option); inStream.Read(option);
auto* team = playerContainer.GetTeam(playerID); auto* team = Game::playerContainer.GetTeam(playerID);
if (team != nullptr) { if (team != nullptr) {
if (team->leaderID != playerID) return; if (team->leaderID != playerID) return;
team->lootFlag = option; team->lootFlag = option;
playerContainer.TeamStatusUpdate(team); Game::playerContainer.TeamStatusUpdate(team);
playerContainer.UpdateTeamsOnWorld(team, false); Game::playerContainer.UpdateTeamsOnWorld(team, false);
} }
} }
@ -631,18 +629,18 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
auto* team = playerContainer.GetTeam(playerID); auto* team = Game::playerContainer.GetTeam(playerID);
auto* data = playerContainer.GetPlayerData(playerID); auto* data = Game::playerContainer.GetPlayerData(playerID);
if (team != nullptr && data != nullptr) { if (team != nullptr && data != nullptr) {
if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) { if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) {
playerContainer.RemoveMember(team, playerID, false, false, true, true); Game::playerContainer.RemoveMember(team, playerID, false, false, true, true);
return; return;
} }
if (team->memberIDs.size() <= 1 && !team->local) { if (team->memberIDs.size() <= 1 && !team->local) {
playerContainer.DisbandTeam(team); Game::playerContainer.DisbandTeam(team);
return; return;
} }
@ -653,16 +651,16 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY); ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY);
} }
playerContainer.TeamStatusUpdate(team); Game::playerContainer.TeamStatusUpdate(team);
const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName); const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName);
for (const auto memberId : team->memberIDs) { for (const auto memberId : team->memberIDs) {
auto* otherMember = playerContainer.GetPlayerData(memberId); auto* otherMember = Game::playerContainer.GetPlayerData(memberId);
if (memberId == playerID) continue; if (memberId == playerID) continue;
const auto memberName = playerContainer.GetName(memberId); const auto memberName = Game::playerContainer.GetName(memberId);
if (otherMember != nullptr) { if (otherMember != nullptr) {
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID); ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
@ -670,7 +668,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0)); ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
} }
playerContainer.UpdateTeamsOnWorld(team, false); Game::playerContainer.UpdateTeamsOnWorld(team, false);
} }
} }

View File

@ -19,6 +19,7 @@
#include "eChatMessageType.h" #include "eChatMessageType.h"
#include "eChatInternalMessageType.h" #include "eChatInternalMessageType.h"
#include "eWorldMessageType.h" #include "eWorldMessageType.h"
#include "ChatIgnoreList.h"
#include "Game.h" #include "Game.h"
@ -34,14 +35,12 @@ namespace Game {
AssetManager* assetManager = nullptr; AssetManager* assetManager = nullptr;
bool shouldShutdown = false; bool shouldShutdown = false;
std::mt19937 randomEngine; std::mt19937 randomEngine;
PlayerContainer playerContainer;
} }
Logger* SetupLogger(); Logger* SetupLogger();
void HandlePacket(Packet* packet); void HandlePacket(Packet* packet);
PlayerContainer playerContainer;
int main(int argc, char** argv) { int main(int argc, char** argv) {
constexpr uint32_t chatFramerate = mediumFramerate; constexpr uint32_t chatFramerate = mediumFramerate;
constexpr uint32_t chatFrameDelta = mediumFrameDelta; constexpr uint32_t chatFrameDelta = mediumFrameDelta;
@ -108,7 +107,7 @@ int main(int argc, char** argv) {
Game::randomEngine = std::mt19937(time(0)); Game::randomEngine = std::mt19937(time(0));
playerContainer.Initialize(); Game::playerContainer.Initialize();
//Run it until server gets a kill message from Master: //Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now(); auto t = std::chrono::high_resolution_clock::now();
@ -200,19 +199,19 @@ void HandlePacket(Packet* packet) {
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) { if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
switch (static_cast<eChatInternalMessageType>(packet->data[3])) { switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION: case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
playerContainer.InsertPlayer(packet); Game::playerContainer.InsertPlayer(packet);
break; break;
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION: case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
playerContainer.RemovePlayer(packet); Game::playerContainer.RemovePlayer(packet);
break; break;
case eChatInternalMessageType::MUTE_UPDATE: case eChatInternalMessageType::MUTE_UPDATE:
playerContainer.MuteUpdate(packet); Game::playerContainer.MuteUpdate(packet);
break; break;
case eChatInternalMessageType::CREATE_TEAM: case eChatInternalMessageType::CREATE_TEAM:
playerContainer.CreateTeamServer(packet); Game::playerContainer.CreateTeamServer(packet);
break; break;
case eChatInternalMessageType::ANNOUNCEMENT: { case eChatInternalMessageType::ANNOUNCEMENT: {
@ -234,7 +233,15 @@ void HandlePacket(Packet* packet) {
break; break;
case eChatMessageType::GET_IGNORE_LIST: case eChatMessageType::GET_IGNORE_LIST:
LOG("Asked for ignore list, but is unimplemented right now."); ChatIgnoreList::GetIgnoreList(packet);
break;
case eChatMessageType::ADD_IGNORE:
ChatIgnoreList::AddIgnore(packet);
break;
case eChatMessageType::REMOVE_IGNORE:
ChatIgnoreList::RemoveIgnore(packet);
break; break;
case eChatMessageType::TEAM_GET_STATUS: case eChatMessageType::TEAM_GET_STATUS:

View File

@ -7,12 +7,26 @@
#include "dServer.h" #include "dServer.h"
#include <unordered_map> #include <unordered_map>
struct IgnoreData {
inline bool operator==(const std::string& other) const noexcept {
return playerName == other;
}
inline bool operator==(const LWOOBJID& other) const noexcept {
return playerId == other;
}
LWOOBJID playerId;
std::string playerName;
};
struct PlayerData { struct PlayerData {
LWOOBJID playerID; LWOOBJID playerID;
std::string playerName; std::string playerName;
SystemAddress sysAddr; SystemAddress sysAddr;
LWOZONEID zoneID; LWOZONEID zoneID;
std::vector<FriendData> friends; std::vector<FriendData> friends;
std::vector<IgnoreData> ignoredPlayers;
time_t muteExpire; time_t muteExpire;
uint8_t countOfBestFriends = 0; uint8_t countOfBestFriends = 0;
}; };

View File

@ -12,6 +12,7 @@ class AssetManager;
struct SystemAddress; struct SystemAddress;
class EntityManager; class EntityManager;
class dZoneManager; class dZoneManager;
class PlayerContainer;
namespace Game { namespace Game {
extern Logger* logger; extern Logger* logger;
@ -26,4 +27,5 @@ namespace Game {
extern bool shouldShutdown; extern bool shouldShutdown;
extern EntityManager* entityManager; extern EntityManager* entityManager;
extern dZoneManager* zoneManager; extern dZoneManager* zoneManager;
extern PlayerContainer playerContainer;
} }

View File

@ -21,6 +21,7 @@
#include "ICharInfo.h" #include "ICharInfo.h"
#include "IAccounts.h" #include "IAccounts.h"
#include "IActivityLog.h" #include "IActivityLog.h"
#include "IIgnoreList.h"
#include "IAccountsRewardCodes.h" #include "IAccountsRewardCodes.h"
namespace sql { namespace sql {
@ -39,7 +40,7 @@ class GameDatabase :
public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports, public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports,
public IPropertyContents, public IProperty, public IPetNames, public ICharXml, public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo, public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
public IAccounts, public IActivityLog, public IAccountsRewardCodes { public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList {
public: public:
virtual ~GameDatabase() = default; virtual ~GameDatabase() = default;
// TODO: These should be made private. // TODO: These should be made private.

View File

@ -0,0 +1,20 @@
#ifndef __IIGNORELIST__H__
#define __IIGNORELIST__H__
#include <cstdint>
#include <string>
#include <vector>
class IIgnoreList {
public:
struct Info {
std::string name;
uint32_t id;
};
virtual std::vector<Info> GetIgnoreList(const uint32_t playerId) = 0;
virtual void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) = 0;
virtual void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) = 0;
};
#endif //!__IIGNORELIST__H__

View File

@ -103,6 +103,9 @@ public:
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override; std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override; std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override; std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override; void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override; std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
private: private:

View File

@ -7,6 +7,7 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
"CharXml.cpp" "CharXml.cpp"
"CommandLog.cpp" "CommandLog.cpp"
"Friends.cpp" "Friends.cpp"
"IgnoreList.cpp"
"Leaderboard.cpp" "Leaderboard.cpp"
"Mail.cpp" "Mail.cpp"
"MigrationHistory.cpp" "MigrationHistory.cpp"

View File

@ -0,0 +1,22 @@
#include "MySQLDatabase.h"
std::vector<IIgnoreList::Info> MySQLDatabase::GetIgnoreList(const uint32_t playerId) {
auto result = ExecuteSelect("SELECT ci.name AS name, il.ignored_player_id AS ignore_id FROM ignore_list AS il JOIN charinfo AS ci ON il.ignored_player_id = ci.id WHERE il.player_id = ?", playerId);
std::vector<IIgnoreList::Info> ignoreList;
ignoreList.reserve(result->rowsCount());
while (result->next()) {
ignoreList.push_back(IIgnoreList::Info{ result->getString("name").c_str(), result->getUInt("ignore_id") });
}
return ignoreList;
}
void MySQLDatabase::AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
ExecuteInsert("INSERT IGNORE INTO ignore_list (player_id, ignored_player_id) VALUES (?, ?)", playerId, ignoredPlayerId);
}
void MySQLDatabase::RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
ExecuteDelete("DELETE FROM ignore_list WHERE player_id = ? AND ignored_player_id = ?", playerId, ignoredPlayerId);
}

View File

@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS ignore_list (
player_id BIGINT NOT NULL REFERENCES charinfo(id) ON DELETE CASCADE,
ignored_player_id BIGINT NOT NULL REFERENCES charinfo(id) ON DELETE CASCADE,
PRIMARY KEY (player_id, ignored_player_id)
);