mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-11-03 22:21:59 +00:00 
			
		
		
		
	Merge pull request #1307 from DarkflameUniverse/985
feat: Implement ignore list
This commit is contained in:
		@@ -1,4 +1,5 @@
 | 
			
		||||
set(DCHATSERVER_SOURCES
 | 
			
		||||
	"ChatIgnoreList.cpp"
 | 
			
		||||
	"ChatPacketHandler.cpp"
 | 
			
		||||
	"PlayerContainer.cpp"
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										173
									
								
								dChatServer/ChatIgnoreList.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								dChatServer/ChatIgnoreList.cpp
									
									
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								dChatServer/ChatIgnoreList.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								dChatServer/ChatIgnoreList.h
									
									
									
									
									
										Normal 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__
 | 
			
		||||
@@ -19,15 +19,13 @@
 | 
			
		||||
#include "eClientMessageType.h"
 | 
			
		||||
#include "eGameMessageType.h"
 | 
			
		||||
 | 
			
		||||
extern PlayerContainer playerContainer;
 | 
			
		||||
 | 
			
		||||
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
 | 
			
		||||
	//Get from the packet which player we want to do something with:
 | 
			
		||||
	CINSTREAM_SKIP_HEADER;
 | 
			
		||||
	LWOOBJID playerID = 0;
 | 
			
		||||
	inStream.Read(playerID);
 | 
			
		||||
 | 
			
		||||
	auto player = playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	auto player = Game::playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	if (!player) return;
 | 
			
		||||
 | 
			
		||||
	auto friendsList = Database::Get()->GetFriendsList(playerID);
 | 
			
		||||
@@ -43,7 +41,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
 | 
			
		||||
		fd.friendName = friendData.friendName;
 | 
			
		||||
 | 
			
		||||
		//Now check if they're online:
 | 
			
		||||
		auto fr = playerContainer.GetPlayerData(fd.friendID);
 | 
			
		||||
		auto fr = Game::playerContainer.GetPlayerData(fd.friendID);
 | 
			
		||||
 | 
			
		||||
		if (fr) {
 | 
			
		||||
			fd.isOnline = true;
 | 
			
		||||
@@ -97,7 +95,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
 | 
			
		||||
	char isBestFriendRequest{};
 | 
			
		||||
	inStream.Read(isBestFriendRequest);
 | 
			
		||||
 | 
			
		||||
	auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
 | 
			
		||||
	auto requestor = Game::playerContainer.GetPlayerData(requestorPlayerID);
 | 
			
		||||
	if (!requestor) {
 | 
			
		||||
		LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
 | 
			
		||||
		return;
 | 
			
		||||
@@ -107,7 +105,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
 | 
			
		||||
		SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
 | 
			
		||||
		return;
 | 
			
		||||
	};
 | 
			
		||||
	std::unique_ptr<PlayerData> requestee(playerContainer.GetPlayerData(playerName));
 | 
			
		||||
	std::unique_ptr<PlayerData> requestee(Game::playerContainer.GetPlayerData(playerName));
 | 
			
		||||
 | 
			
		||||
	// Check if player is online first
 | 
			
		||||
	if (isBestFriendRequest && !requestee) {
 | 
			
		||||
@@ -175,7 +173,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
 | 
			
		||||
 | 
			
		||||
		// Only do updates if there was a change in the bff status.
 | 
			
		||||
		if (oldBestFriendStatus != bestFriendStatus) {
 | 
			
		||||
			auto maxBestFriends = playerContainer.GetMaxNumberOfBestFriends();
 | 
			
		||||
			auto maxBestFriends = Game::playerContainer.GetMaxNumberOfBestFriends();
 | 
			
		||||
			if (requestee->countOfBestFriends >= maxBestFriends || requestor->countOfBestFriends >= maxBestFriends) {
 | 
			
		||||
				if (requestee->countOfBestFriends >= maxBestFriends) {
 | 
			
		||||
					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);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		auto maxFriends = playerContainer.GetMaxNumberOfFriends();
 | 
			
		||||
		auto maxFriends = Game::playerContainer.GetMaxNumberOfFriends();
 | 
			
		||||
		if (requestee->friends.size() >= maxFriends) {
 | 
			
		||||
			SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
 | 
			
		||||
		} else if (requestor->friends.size() >= maxFriends) {
 | 
			
		||||
@@ -232,8 +230,8 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
 | 
			
		||||
	std::string friendName = PacketUtils::ReadString(0x15, packet, true);
 | 
			
		||||
 | 
			
		||||
	//Now to try and find both of these:
 | 
			
		||||
	auto requestor = playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	auto requestee = playerContainer.GetPlayerData(friendName);
 | 
			
		||||
	auto requestor = Game::playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	auto requestee = Game::playerContainer.GetPlayerData(friendName);
 | 
			
		||||
	if (!requestor || !requestee) return;
 | 
			
		||||
 | 
			
		||||
	eAddFriendResponseType serverResponseCode{};
 | 
			
		||||
@@ -315,7 +313,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
 | 
			
		||||
	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:
 | 
			
		||||
	auto goonA = playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	auto goonA = Game::playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	if (goonA) {
 | 
			
		||||
		// Remove the friend from our list of friends
 | 
			
		||||
		for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) {
 | 
			
		||||
@@ -328,7 +326,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
 | 
			
		||||
		SendRemoveFriend(goonA, friendName, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto goonB = playerContainer.GetPlayerData(friendID);
 | 
			
		||||
	auto goonB = Game::playerContainer.GetPlayerData(friendID);
 | 
			
		||||
	if (!goonB) return;
 | 
			
		||||
	// Do it again for other person
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -348,11 +346,11 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
 | 
			
		||||
	LWOOBJID playerID = LWOOBJID_EMPTY;
 | 
			
		||||
	inStream.Read(playerID);
 | 
			
		||||
 | 
			
		||||
	auto* sender = playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	auto* sender = Game::playerContainer.GetPlayerData(playerID);
 | 
			
		||||
 | 
			
		||||
	if (sender == nullptr) return;
 | 
			
		||||
 | 
			
		||||
	if (playerContainer.GetIsMuted(sender)) return;
 | 
			
		||||
	if (Game::playerContainer.GetIsMuted(sender)) return;
 | 
			
		||||
 | 
			
		||||
	const auto senderName = std::string(sender->playerName.c_str());
 | 
			
		||||
 | 
			
		||||
@@ -367,12 +365,12 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
 | 
			
		||||
 | 
			
		||||
	if (channel != 8) return;
 | 
			
		||||
 | 
			
		||||
	auto* team = playerContainer.GetTeam(playerID);
 | 
			
		||||
	auto* team = Game::playerContainer.GetTeam(playerID);
 | 
			
		||||
 | 
			
		||||
	if (team == nullptr) return;
 | 
			
		||||
 | 
			
		||||
	for (const auto memberId : team->memberIDs) {
 | 
			
		||||
		auto* otherMember = playerContainer.GetPlayerData(memberId);
 | 
			
		||||
		auto* otherMember = Game::playerContainer.GetPlayerData(memberId);
 | 
			
		||||
 | 
			
		||||
		if (otherMember == nullptr) return;
 | 
			
		||||
 | 
			
		||||
@@ -406,11 +404,11 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
 | 
			
		||||
	std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
 | 
			
		||||
 | 
			
		||||
	//Get the bois:
 | 
			
		||||
	auto goonA = playerContainer.GetPlayerData(senderID);
 | 
			
		||||
	auto goonB = playerContainer.GetPlayerData(receiverName);
 | 
			
		||||
	auto goonA = Game::playerContainer.GetPlayerData(senderID);
 | 
			
		||||
	auto goonB = Game::playerContainer.GetPlayerData(receiverName);
 | 
			
		||||
	if (!goonA || !goonB) return;
 | 
			
		||||
 | 
			
		||||
	if (playerContainer.GetIsMuted(goonA)) return;
 | 
			
		||||
	if (Game::playerContainer.GetIsMuted(goonA)) return;
 | 
			
		||||
 | 
			
		||||
	std::string goonAName = goonA->playerName.c_str();
 | 
			
		||||
	std::string goonBName = goonB->playerName.c_str();
 | 
			
		||||
@@ -468,25 +466,25 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
 | 
			
		||||
	inStream.Read(playerID);
 | 
			
		||||
	std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true);
 | 
			
		||||
 | 
			
		||||
	auto* player = playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	auto* player = Game::playerContainer.GetPlayerData(playerID);
 | 
			
		||||
 | 
			
		||||
	if (player == nullptr) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto* team = playerContainer.GetTeam(playerID);
 | 
			
		||||
	auto* team = Game::playerContainer.GetTeam(playerID);
 | 
			
		||||
 | 
			
		||||
	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) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (playerContainer.GetTeam(other->playerID) != nullptr) {
 | 
			
		||||
	if (Game::playerContainer.GetTeam(other->playerID) != nullptr) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -519,12 +517,12 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto* team = playerContainer.GetTeam(leaderID);
 | 
			
		||||
	auto* team = Game::playerContainer.GetTeam(leaderID);
 | 
			
		||||
 | 
			
		||||
	if (team == nullptr) {
 | 
			
		||||
		LOG("Failed to find team for leader (%llu)", leaderID);
 | 
			
		||||
 | 
			
		||||
		team = playerContainer.GetTeam(playerID);
 | 
			
		||||
		team = Game::playerContainer.GetTeam(playerID);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (team == nullptr) {
 | 
			
		||||
@@ -532,7 +530,7 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	playerContainer.AddMember(team, playerID);
 | 
			
		||||
	Game::playerContainer.AddMember(team, playerID);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
 | 
			
		||||
@@ -542,12 +540,12 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
 | 
			
		||||
	uint32_t size = 0;
 | 
			
		||||
	inStream.Read(size);
 | 
			
		||||
 | 
			
		||||
	auto* team = playerContainer.GetTeam(playerID);
 | 
			
		||||
	auto* team = Game::playerContainer.GetTeam(playerID);
 | 
			
		||||
 | 
			
		||||
	LOG("(%llu) leaving team", playerID);
 | 
			
		||||
 | 
			
		||||
	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());
 | 
			
		||||
 | 
			
		||||
	auto* kicked = playerContainer.GetPlayerData(kickedPlayer);
 | 
			
		||||
	auto* kicked = Game::playerContainer.GetPlayerData(kickedPlayer);
 | 
			
		||||
 | 
			
		||||
	LWOOBJID kickedId = LWOOBJID_EMPTY;
 | 
			
		||||
 | 
			
		||||
	if (kicked != nullptr) {
 | 
			
		||||
		kickedId = kicked->playerID;
 | 
			
		||||
	} else {
 | 
			
		||||
		kickedId = playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
 | 
			
		||||
		kickedId = Game::playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (kickedId == LWOOBJID_EMPTY) return;
 | 
			
		||||
 | 
			
		||||
	auto* team = playerContainer.GetTeam(playerID);
 | 
			
		||||
	auto* team = Game::playerContainer.GetTeam(playerID);
 | 
			
		||||
 | 
			
		||||
	if (team != nullptr) {
 | 
			
		||||
		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());
 | 
			
		||||
 | 
			
		||||
	auto* promoted = playerContainer.GetPlayerData(promotedPlayer);
 | 
			
		||||
	auto* promoted = Game::playerContainer.GetPlayerData(promotedPlayer);
 | 
			
		||||
 | 
			
		||||
	if (promoted == nullptr) return;
 | 
			
		||||
 | 
			
		||||
	auto* team = playerContainer.GetTeam(playerID);
 | 
			
		||||
	auto* team = Game::playerContainer.GetTeam(playerID);
 | 
			
		||||
 | 
			
		||||
	if (team != nullptr) {
 | 
			
		||||
		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;
 | 
			
		||||
	inStream.Read(option);
 | 
			
		||||
 | 
			
		||||
	auto* team = playerContainer.GetTeam(playerID);
 | 
			
		||||
	auto* team = Game::playerContainer.GetTeam(playerID);
 | 
			
		||||
 | 
			
		||||
	if (team != nullptr) {
 | 
			
		||||
		if (team->leaderID != playerID) return;
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
	inStream.Read(playerID);
 | 
			
		||||
 | 
			
		||||
	auto* team = playerContainer.GetTeam(playerID);
 | 
			
		||||
	auto* data = playerContainer.GetPlayerData(playerID);
 | 
			
		||||
	auto* team = Game::playerContainer.GetTeam(playerID);
 | 
			
		||||
	auto* data = Game::playerContainer.GetPlayerData(playerID);
 | 
			
		||||
 | 
			
		||||
	if (team != nullptr && data != nullptr) {
 | 
			
		||||
		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;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (team->memberIDs.size() <= 1 && !team->local) {
 | 
			
		||||
			playerContainer.DisbandTeam(team);
 | 
			
		||||
			Game::playerContainer.DisbandTeam(team);
 | 
			
		||||
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
@@ -653,16 +651,16 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
 | 
			
		||||
			ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		playerContainer.TeamStatusUpdate(team);
 | 
			
		||||
		Game::playerContainer.TeamStatusUpdate(team);
 | 
			
		||||
 | 
			
		||||
		const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName);
 | 
			
		||||
 | 
			
		||||
		for (const auto memberId : team->memberIDs) {
 | 
			
		||||
			auto* otherMember = playerContainer.GetPlayerData(memberId);
 | 
			
		||||
			auto* otherMember = Game::playerContainer.GetPlayerData(memberId);
 | 
			
		||||
 | 
			
		||||
			if (memberId == playerID) continue;
 | 
			
		||||
 | 
			
		||||
			const auto memberName = playerContainer.GetName(memberId);
 | 
			
		||||
			const auto memberName = Game::playerContainer.GetName(memberId);
 | 
			
		||||
 | 
			
		||||
			if (otherMember != nullptr) {
 | 
			
		||||
				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));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		playerContainer.UpdateTeamsOnWorld(team, false);
 | 
			
		||||
		Game::playerContainer.UpdateTeamsOnWorld(team, false);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include "eChatMessageType.h"
 | 
			
		||||
#include "eChatInternalMessageType.h"
 | 
			
		||||
#include "eWorldMessageType.h"
 | 
			
		||||
#include "ChatIgnoreList.h"
 | 
			
		||||
 | 
			
		||||
#include "Game.h"
 | 
			
		||||
 | 
			
		||||
@@ -34,14 +35,12 @@ namespace Game {
 | 
			
		||||
	AssetManager* assetManager = nullptr;
 | 
			
		||||
	bool shouldShutdown = false;
 | 
			
		||||
	std::mt19937 randomEngine;
 | 
			
		||||
	PlayerContainer playerContainer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Logger* SetupLogger();
 | 
			
		||||
void HandlePacket(Packet* packet);
 | 
			
		||||
 | 
			
		||||
PlayerContainer playerContainer;
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv) {
 | 
			
		||||
	constexpr uint32_t chatFramerate = mediumFramerate;
 | 
			
		||||
	constexpr uint32_t chatFrameDelta = mediumFrameDelta;
 | 
			
		||||
@@ -108,7 +107,7 @@ int main(int argc, char** argv) {
 | 
			
		||||
	
 | 
			
		||||
	Game::randomEngine = std::mt19937(time(0));
 | 
			
		||||
 | 
			
		||||
	playerContainer.Initialize();
 | 
			
		||||
	Game::playerContainer.Initialize();
 | 
			
		||||
 | 
			
		||||
	//Run it until server gets a kill message from Master:
 | 
			
		||||
	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) {
 | 
			
		||||
		switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
 | 
			
		||||
		case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
 | 
			
		||||
			playerContainer.InsertPlayer(packet);
 | 
			
		||||
			Game::playerContainer.InsertPlayer(packet);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
 | 
			
		||||
			playerContainer.RemovePlayer(packet);
 | 
			
		||||
			Game::playerContainer.RemovePlayer(packet);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case eChatInternalMessageType::MUTE_UPDATE:
 | 
			
		||||
			playerContainer.MuteUpdate(packet);
 | 
			
		||||
			Game::playerContainer.MuteUpdate(packet);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case eChatInternalMessageType::CREATE_TEAM:
 | 
			
		||||
			playerContainer.CreateTeamServer(packet);
 | 
			
		||||
			Game::playerContainer.CreateTeamServer(packet);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case eChatInternalMessageType::ANNOUNCEMENT: {
 | 
			
		||||
@@ -234,7 +233,15 @@ void HandlePacket(Packet* packet) {
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
		case eChatMessageType::TEAM_GET_STATUS:
 | 
			
		||||
 
 | 
			
		||||
@@ -7,12 +7,26 @@
 | 
			
		||||
#include "dServer.h"
 | 
			
		||||
#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 {
 | 
			
		||||
	LWOOBJID playerID;
 | 
			
		||||
	std::string playerName;
 | 
			
		||||
	SystemAddress sysAddr;
 | 
			
		||||
	LWOZONEID zoneID;
 | 
			
		||||
	std::vector<FriendData> friends;
 | 
			
		||||
	std::vector<IgnoreData> ignoredPlayers;
 | 
			
		||||
	time_t muteExpire;
 | 
			
		||||
	uint8_t countOfBestFriends = 0;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ class AssetManager;
 | 
			
		||||
struct SystemAddress;
 | 
			
		||||
class EntityManager;
 | 
			
		||||
class dZoneManager;
 | 
			
		||||
class PlayerContainer;
 | 
			
		||||
 | 
			
		||||
namespace Game {
 | 
			
		||||
	extern Logger* logger;
 | 
			
		||||
@@ -26,4 +27,5 @@ namespace Game {
 | 
			
		||||
	extern bool shouldShutdown;
 | 
			
		||||
	extern EntityManager* entityManager;
 | 
			
		||||
	extern dZoneManager* zoneManager;
 | 
			
		||||
	extern PlayerContainer playerContainer;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
#include "ICharInfo.h"
 | 
			
		||||
#include "IAccounts.h"
 | 
			
		||||
#include "IActivityLog.h"
 | 
			
		||||
#include "IIgnoreList.h"
 | 
			
		||||
#include "IAccountsRewardCodes.h"
 | 
			
		||||
 | 
			
		||||
namespace sql {
 | 
			
		||||
@@ -39,7 +40,7 @@ class GameDatabase :
 | 
			
		||||
	public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports,
 | 
			
		||||
	public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
 | 
			
		||||
	public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
 | 
			
		||||
	public IAccounts, public IActivityLog, public IAccountsRewardCodes {
 | 
			
		||||
	public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList {
 | 
			
		||||
public:
 | 
			
		||||
	virtual ~GameDatabase() = default;
 | 
			
		||||
	// TODO: These should be made private.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								dDatabase/GameDatabase/ITables/IIgnoreList.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								dDatabase/GameDatabase/ITables/IIgnoreList.h
									
									
									
									
									
										Normal 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__
 | 
			
		||||
@@ -103,6 +103,9 @@ public:
 | 
			
		||||
	std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
 | 
			
		||||
	std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) 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;
 | 
			
		||||
	std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
 | 
			
		||||
private:
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
 | 
			
		||||
	"CharXml.cpp"
 | 
			
		||||
	"CommandLog.cpp"
 | 
			
		||||
	"Friends.cpp"
 | 
			
		||||
	"IgnoreList.cpp"
 | 
			
		||||
	"Leaderboard.cpp"
 | 
			
		||||
	"Mail.cpp"
 | 
			
		||||
	"MigrationHistory.cpp"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								dDatabase/GameDatabase/MySQL/Tables/IgnoreList.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								dDatabase/GameDatabase/MySQL/Tables/IgnoreList.cpp
									
									
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								migrations/dlu/13_ignore_list.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								migrations/dlu/13_ignore_list.sql
									
									
									
									
									
										Normal 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)
 | 
			
		||||
);
 | 
			
		||||
		Reference in New Issue
	
	Block a user