Files
DarkflameServer/dChatServer/ChatIgnoreList.cpp
David Markowitz 6389876c6e feat: convert character ids to 64 bits (#1878)
* feat: convert character ids to 64 bits

remove all usages of the PERSISTENT bit with regards to storing of playerIDs on the server.  the bit does not exist and was a phantom in the first place.
Tested that a full playthrough of ag, ns and gf was still doable.  slash commands work, ugc works, friends works, ignore list works, properties work and have names, teaming works.
migrating an old mysql database works . need to test an old sqlite database

* fix sqlite migration

* remove nd specific column migration
2025-09-19 01:12:23 -05:00

170 lines
5.7 KiB
C++

#include "ChatIgnoreList.h"
#include "PlayerContainer.h"
#include "MessageType/Chat.h"
#include "BitStreamUtils.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 MessageType::Client type) {
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receivingPlayer);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, type);
}
void ChatIgnoreList::GetIgnoreList(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerId;
inStream.Read(playerId);
auto& receiver = Game::playerContainer.GetPlayerDataMutable(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, but is requesting it again.", playerId);
} else {
auto ignoreList = Database::Get()->GetIgnoreList(playerId);
if (ignoreList.empty()) {
LOG_DEBUG("Player %llu has no ignores", playerId);
return;
}
for (auto& ignoredPlayer : ignoreList) {
receiver.ignoredPlayers.emplace_back(ignoredPlayer.name, ignoredPlayer.id);
GeneralUtils::SetBit(receiver.ignoredPlayers.back().playerId, eObjectBits::CHARACTER);
}
}
CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver.playerID, MessageType::Client::GET_IGNORE_LIST_RESPONSE);
bitStream.Write<uint8_t>(false); // 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.GetPlayerDataMutable(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;
inStream.Read(toIgnoreName);
std::string toIgnoreStr = toIgnoreName.GetAsString();
CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver.playerID, MessageType::Client::ADD_IGNORE_RESPONSE);
// 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
const 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(playerId, ignoredPlayerId);
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::CHARACTER);
receiver.ignoredPlayers.emplace_back(toIgnoreStr, ignoredPlayerId);
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.GetPlayerDataMutable(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;
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(playerId, toRemove->playerId);
receiver.ignoredPlayers.erase(toRemove, receiver.ignoredPlayers.end());
CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver.playerID, MessageType::Client::REMOVE_IGNORE_RESPONSE);
bitStream.Write<int8_t>(0);
LUWString playerNameSend(removedIgnoreStr, 33);
bitStream.Write(playerNameSend);
Game::server->Send(bitStream, packet->systemAddress, false);
}