From df3515f4742b9271899fad2329e5624e6acb7b40 Mon Sep 17 00:00:00 2001
From: David Markowitz <EmosewaMC@gmail.com>
Date: Sat, 18 Nov 2023 03:55:12 -0800
Subject: [PATCH] IgnoreList: Add and Populate fully working

---
 dChatServer/CMakeLists.txt     |   1 +
 dChatServer/ChatIgnoreList.cpp | 121 +++++++++++++++++++++++++++++++++
 dChatServer/ChatIgnoreList.h   |  11 +++
 dChatServer/ChatServer.cpp     |   7 +-
 dChatServer/PlayerContainer.h  |  14 ++++
 5 files changed, 153 insertions(+), 1 deletion(-)
 create mode 100644 dChatServer/ChatIgnoreList.cpp
 create mode 100644 dChatServer/ChatIgnoreList.h

diff --git a/dChatServer/CMakeLists.txt b/dChatServer/CMakeLists.txt
index 9a47803d..34d58a3a 100644
--- a/dChatServer/CMakeLists.txt
+++ b/dChatServer/CMakeLists.txt
@@ -1,4 +1,5 @@
 set(DCHATSERVER_SOURCES
+	"ChatIgnoreList.cpp"
 	"ChatPacketHandler.cpp"
 	"PlayerContainer.cpp"
 )
diff --git a/dChatServer/ChatIgnoreList.cpp b/dChatServer/ChatIgnoreList.cpp
new file mode 100644
index 00000000..a84c3cda
--- /dev/null
+++ b/dChatServer/ChatIgnoreList.cpp
@@ -0,0 +1,121 @@
+#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"
+
+extern PlayerContainer playerContainer;
+
+enum IgnoreReponse : uint8_t {
+	AddIgnoreResponse = 32,
+	GetIgnoreListResponse = 34,
+};
+
+void ChatIgnoreList::GetIgnoreList(Packet* packet) {
+	LOG_DEBUG("Getting ignore list");
+
+	CINSTREAM_SKIP_HEADER;
+	LWOOBJID playerId;
+	inStream.Read(playerId);
+
+	auto* receiver = playerContainer.GetPlayerData(playerId);
+	if (!receiver) {
+		LOG("Tried to get ignore list, but player %llu not found in container", playerId);
+		return;
+	}
+
+	CBITSTREAM;
+	BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
+	bitStream.Write(receiver->playerID);
+
+	//portion that will get routed:
+	BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, IgnoreReponse::GetIgnoreListResponse);
+	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);
+}
+
+// Remove from ignore list and response
+// Not much else to do with editing the list, maybe more messages are needed for refreshes or something
+// but you can only add or remove from the list, and you only request the list on world start so pretty small file
+// After the above all work, move to implement the actual ignore functionality in the chat server
+enum class IgnoreResponse : uint8_t {
+	SUCCESS,
+	ALREADY_IGNORED,
+	PLAYER_NOT_FOUND,
+	GENERAL_ERROR,
+};
+
+void ChatIgnoreList::AddIgnore(Packet* packet) {
+	LOG_DEBUG("Adding ignore");
+
+	CINSTREAM_SKIP_HEADER;
+	LWOOBJID playerId;
+	inStream.Read(playerId);
+
+	auto* receiver = 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 toIgnoreName(33);
+	inStream.Read(toIgnoreName);
+	std::string toIgnoreStr = toIgnoreName.GetAsString();
+
+	CBITSTREAM;
+	BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
+	bitStream.Write(receiver->playerID);
+
+	//portion that will get routed:
+	BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, IgnoreReponse::AddIgnoreResponse);
+
+	// 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(IgnoreResponse::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(IgnoreResponse::ALREADY_IGNORED);
+	} else {
+		auto* playerData = 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());
+
+				bitStream.Write(IgnoreResponse::PLAYER_NOT_FOUND);
+			} else {
+				ignoredPlayerId = player->id;
+				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(IgnoreResponse::SUCCESS);
+			}
+		}
+	}
+
+	LUWString playerNameSend(toIgnoreStr, 33);
+	bitStream.Write(playerNameSend);
+	bitStream.Write(ignoredPlayerId);
+
+	Game::server->Send(&bitStream, packet->systemAddress, false);
+}
diff --git a/dChatServer/ChatIgnoreList.h b/dChatServer/ChatIgnoreList.h
new file mode 100644
index 00000000..48170369
--- /dev/null
+++ b/dChatServer/ChatIgnoreList.h
@@ -0,0 +1,11 @@
+#ifndef __CHATIGNORELIST__H__
+#define __CHATIGNORELIST__H__
+
+struct Packet;
+
+namespace ChatIgnoreList {
+	void GetIgnoreList(Packet* packet);
+	void AddIgnore(Packet* packet);
+};
+
+#endif  //!__CHATIGNORELIST__H__
diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp
index b41ad4ec..6671b047 100644
--- a/dChatServer/ChatServer.cpp
+++ b/dChatServer/ChatServer.cpp
@@ -19,6 +19,7 @@
 #include "eChatMessageType.h"
 #include "eChatInternalMessageType.h"
 #include "eWorldMessageType.h"
+#include "ChatIgnoreList.h"
 
 #include "Game.h"
 
@@ -234,7 +235,11 @@ 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::TEAM_GET_STATUS:
diff --git a/dChatServer/PlayerContainer.h b/dChatServer/PlayerContainer.h
index d055ed95..51bff6c1 100644
--- a/dChatServer/PlayerContainer.h
+++ b/dChatServer/PlayerContainer.h
@@ -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;
 };