From 4dc48198abbb5926022e16e8d1eebbbaf1c8fe3b Mon Sep 17 00:00:00 2001 From: Kamil Date: Sat, 5 Dec 2020 01:29:08 +0100 Subject: [PATCH] Implement player blocking --- src/BuddyManager.cpp | 83 +++++++++++++++++++++++++++++++++++++++----- src/BuddyManager.hpp | 1 + src/Database.cpp | 76 ++++++++++++++++++++++++++++++++++++---- src/Database.hpp | 4 +++ src/Player.hpp | 1 + 5 files changed, 150 insertions(+), 15 deletions(-) diff --git a/src/BuddyManager.cpp b/src/BuddyManager.cpp index 624f447..4a4b8f3 100644 --- a/src/BuddyManager.cpp +++ b/src/BuddyManager.cpp @@ -21,6 +21,7 @@ void BuddyManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE, reqBuddyMenuchat); REGISTER_SHARD_PACKET(P_CL2FE_REQ_GET_BUDDY_STATE, reqPktGetBuddyState); REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_BUDDY_BLOCK, reqBuddyBlock); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_PC_BLOCK, reqPlayerBlock); REGISTER_SHARD_PACKET(P_CL2FE_REQ_REMOVE_BUDDY, reqBuddyDelete); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_BUDDY_WARP, reqBuddyWarp); // @@ -68,7 +69,7 @@ void BuddyManager::refreshBuddyList(CNSocket* sock) { Database::getPlayer(&buddyPlayerData, buddyID); if (buddyPlayerData.iID == 0) continue; - buddyInfo.bBlocked = 0; + buddyInfo.bBlocked = plr->isBuddyBlocked[i]; buddyInfo.bFreeChat = 1; buddyInfo.iGender = buddyPlayerData.PCStyle.iGender; buddyInfo.iID = buddyID; @@ -382,16 +383,72 @@ void BuddyManager::reqBuddyBlock(CNSocket* sock, CNPacketData* data) { return; // malformed packet sP_CL2FE_REQ_SET_BUDDY_BLOCK* pkt = (sP_CL2FE_REQ_SET_BUDDY_BLOCK*)data->buf; + Player* plr = PlayerManager::getPlayer(sock); + // sanity checks + if (pkt->iBuddySlot < 0 || pkt->iBuddySlot >= 50 || plr->buddyIDs[pkt->iBuddySlot] != pkt->iBuddyPCUID) + return; + + // save in DB + Database::removeBuddyship(plr->iID, pkt->iBuddyPCUID); + Database::addBlock(plr->iID, pkt->iBuddyPCUID); + + // save serverside + // since ID is already in the array, just set it to blocked + plr->isBuddyBlocked[pkt->iBuddySlot] = true; + + // send response INITSTRUCT(sP_FE2CL_REP_SET_BUDDY_BLOCK_SUCC, resp); - resp.iBuddyPCUID = pkt->iBuddyPCUID; resp.iBuddySlot = pkt->iBuddySlot; - - // TODO: handle this? - sock->sendPacket((void*)&resp, P_FE2CL_REP_SET_BUDDY_BLOCK_SUCC, sizeof(sP_FE2CL_REP_SET_BUDDY_BLOCK_SUCC)); + // notify the other player he isn't a buddy anymore + INITSTRUCT(sP_FE2CL_REP_REMOVE_BUDDY_SUCC, otherResp); + CNSocket* otherSock = PlayerManager::getSockFromID(pkt->iBuddyPCUID); + if (otherSock == nullptr) + return; // other player isn't online, no broadcast needed + Player* otherPlr = PlayerManager::getPlayer(otherSock); + // search for the slot with the requesting player's ID + otherResp.iBuddyPCUID = plr->PCStyle.iPC_UID; + for (int i = 0; i < 50; i++) { + if (otherPlr->buddyIDs[i] == plr->PCStyle.iPC_UID) { + // remove buddy + otherPlr->buddyIDs[i] = 0; + // broadcast + otherResp.iBuddySlot = i; + otherSock->sendPacket((void*)&otherResp, P_FE2CL_REP_REMOVE_BUDDY_SUCC, sizeof(sP_FE2CL_REP_REMOVE_BUDDY_SUCC)); + return; + } + } +} + +// block non-buddy +void BuddyManager::reqPlayerBlock(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_SET_PC_BLOCK)) + return; + + sP_CL2FE_REQ_SET_PC_BLOCK* pkt = (sP_CL2FE_REQ_SET_PC_BLOCK*)data->buf; + + Player* plr = PlayerManager::getPlayer(sock); + int buddySlot = getAvailableBuddySlot(plr); + if (buddySlot == -1) + return; + + // save in DB + Database::addBlock(plr->iID, pkt->iBlock_PCUID); + + // save serverside + plr->buddyIDs[buddySlot] = pkt->iBlock_PCUID; + plr->isBuddyBlocked[buddySlot] = true; + + // send response + INITSTRUCT(sP_FE2CL_REP_SET_PC_BLOCK_SUCC, resp); + resp.iBlock_ID = pkt->iBlock_ID; + resp.iBlock_PCUID = pkt->iBlock_PCUID; + resp.iBuddySlot = buddySlot; + + sock->sendPacket((void*)&resp, P_FE2CL_REP_SET_PC_BLOCK_SUCC, sizeof(sP_FE2CL_REP_SET_PC_BLOCK_SUCC)); } // Deleting the buddy @@ -399,6 +456,7 @@ void BuddyManager::reqBuddyDelete(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_REMOVE_BUDDY)) return; // malformed packet + // note! this packet is used both for removing buddies and blocks sP_CL2FE_REQ_REMOVE_BUDDY* pkt = (sP_CL2FE_REQ_REMOVE_BUDDY*)data->buf; Player* plr = PlayerManager::getPlayer(sock); @@ -407,13 +465,22 @@ void BuddyManager::reqBuddyDelete(CNSocket* sock, CNPacketData* data) { INITSTRUCT(sP_FE2CL_REP_REMOVE_BUDDY_SUCC, resp); resp.iBuddyPCUID = pkt->iBuddyPCUID; resp.iBuddySlot = pkt->iBuddySlot; - if (pkt->iBuddySlot < 0 || pkt->iBuddySlot >= 50) + if (pkt->iBuddySlot < 0 || pkt->iBuddySlot >= 50 || plr->buddyIDs[pkt->iBuddySlot] != pkt->iBuddyPCUID) return; // sanity check - plr->buddyIDs[resp.iBuddySlot] = 0; - sock->sendPacket((void*)&resp, P_FE2CL_REP_REMOVE_BUDDY_SUCC, sizeof(sP_FE2CL_REP_REMOVE_BUDDY_SUCC)); + bool wasBlocked = plr->isBuddyBlocked[resp.iBuddySlot]; + plr->buddyIDs[resp.iBuddySlot] = 0; + plr->isBuddyBlocked[resp.iBuddySlot] = false; + + sock->sendPacket((void*)&resp, P_FE2CL_REP_REMOVE_BUDDY_SUCC, sizeof(sP_FE2CL_REP_REMOVE_BUDDY_SUCC)); + // remove record from db Database::removeBuddyship(plr->PCStyle.iPC_UID, pkt->iBuddyPCUID); + // try this too + Database::removeBlock(plr->PCStyle.iPC_UID, pkt->iBuddyPCUID); + + if (wasBlocked) + return; // remove buddy on their side, reusing the struct CNSocket* otherSock = PlayerManager::getSockFromID(pkt->iBuddyPCUID); diff --git a/src/BuddyManager.hpp b/src/BuddyManager.hpp index 7aad42e..a78a2cb 100644 --- a/src/BuddyManager.hpp +++ b/src/BuddyManager.hpp @@ -31,6 +31,7 @@ namespace BuddyManager { // Blocking/removing buddies void reqBuddyBlock(CNSocket* sock, CNPacketData* data); + void reqPlayerBlock(CNSocket* sock, CNPacketData* data); void reqBuddyDelete(CNSocket* sock, CNPacketData* data); // Buddy warping diff --git a/src/Database.cpp b/src/Database.cpp index 38d395f..e1ff867 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -161,11 +161,17 @@ void Database::createTables() { CREATE TABLE IF NOT EXISTS "Buddyships" ( "PlayerAId" INTEGER NOT NULL, "PlayerBId" INTEGER NOT NULL, - "Status" INTEGER NOT NULL, FOREIGN KEY("PlayerAId") REFERENCES "Players"("PlayerID") ON DELETE CASCADE, FOREIGN KEY("PlayerBId") REFERENCES "Players"("PlayerID") ON DELETE CASCADE ); + CREATE TABLE IF NOT EXISTS "Blocks" ( + "PlayerId" INTEGER NOT NULL, + "BlockedPlayerId" INTEGER NOT NULL, + FOREIGN KEY("PlayerId") REFERENCES "Players"("PlayerID") ON DELETE CASCADE, + FOREIGN KEY("BlockedPlayerId") REFERENCES "Players"("PlayerID") ON DELETE CASCADE + ); + CREATE TABLE IF NOT EXISTS "EmailData" ( "PlayerId" INTEGER NOT NULL, "MsgIndex" INTEGER NOT NULL, @@ -970,6 +976,23 @@ void Database::getPlayer(Player* plr, int id) { int PlayerBId = sqlite3_column_int(stmt, 1); plr->buddyIDs[i] = id == PlayerAId ? PlayerBId : PlayerAId; + plr->isBuddyBlocked[i] = false; + i++; + } + + // get blocked players + sql = R"( + SELECT "BlockedPlayerId" FROM "Blocks" + WHERE "PlayerId" = ?; + )"; + + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_int(stmt, 1, id); + + // i remains from adding buddies! + while (sqlite3_step(stmt) == SQLITE_ROW && i < 50) { + plr->buddyIDs[i] = sqlite3_column_int(stmt, 0); + plr->isBuddyBlocked[i] = true; i++; } @@ -1268,6 +1291,7 @@ void Database::removeExpiredVehicles(Player* player) { } // buddies +/// returns num of buddies + blocked players int Database::getNumBuddies(Player* player) { std::lock_guard lock(dbCrit); @@ -1281,7 +1305,15 @@ int Database::getNumBuddies(Player* player) { sqlite3_bind_int(stmt, 2, player->iID); sqlite3_step(stmt); int result = sqlite3_column_int(stmt, 0); - sqlite3_finalize(stmt); + + sql = R"( + SELECT COUNT(*) FROM "Blocks" + WHERE "PlayerId" = ?; + )"; + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_int(stmt, 1, player->iID); + sqlite3_step(stmt); + result += sqlite3_column_int(stmt, 0); // again, for peace of mind return result > 50 ? 50 : result; @@ -1292,15 +1324,13 @@ void Database::addBuddyship(int playerA, int playerB) { const char* sql = R"( INSERT INTO "Buddyships" - ("PlayerAId", "PlayerBId", "Status") - VALUES (?, ?, ?); + ("PlayerAId", "PlayerBId") + VALUES (?, ?); )"; sqlite3_stmt* stmt; sqlite3_prepare_v2(db, sql, -1, &stmt, 0); sqlite3_bind_int(stmt, 1, playerA); sqlite3_bind_int(stmt, 2, playerB); - // blocking??? - sqlite3_bind_int(stmt, 3, 0); if (sqlite3_step(stmt) != SQLITE_DONE) std::cout << "[WARN] Database: failed to add buddies" << std::endl; @@ -1321,8 +1351,40 @@ void Database::removeBuddyship(int playerA, int playerB) { sqlite3_bind_int(stmt, 3, playerB); sqlite3_bind_int(stmt, 4, playerA); + sqlite3_step(stmt); + sqlite3_finalize(stmt); +} + +// blocking +void Database::addBlock(int playerId, int blockedPlayerId) { + std::lock_guard lock(dbCrit); + + const char* sql = R"( + INSERT INTO "Blocks" + ("PlayerId", "BlockedPlayerId") + VALUES (?, ?); + )"; + sqlite3_stmt* stmt; + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_int(stmt, 1, playerId); + sqlite3_bind_int(stmt, 2, blockedPlayerId); + if (sqlite3_step(stmt) != SQLITE_DONE) - std::cout << "[WARN] Database: failed to remove buddies" << std::endl; + std::cout << "[WARN] Database: failed to block player" << std::endl; + sqlite3_finalize(stmt); +} + +void Database::removeBlock(int playerId, int blockedPlayerId) { + const char* sql = R"( + DELETE FROM "Blocks" + WHERE "PlayerId" = ? AND "BlockedPlayerId" = ?; + )"; + sqlite3_stmt* stmt; + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_int(stmt, 1, playerId); + sqlite3_bind_int(stmt, 2, blockedPlayerId); + + sqlite3_step(stmt); sqlite3_finalize(stmt); } diff --git a/src/Database.hpp b/src/Database.hpp index 0f338a8..17343d1 100644 --- a/src/Database.hpp +++ b/src/Database.hpp @@ -85,6 +85,10 @@ namespace Database { int getNumBuddies(Player* player); void addBuddyship(int playerA, int playerB); void removeBuddyship(int playerA, int playerB); + + // blocking + void addBlock(int playerId, int blockedPlayerId); + void removeBlock(int playerId, int blockedPlayerId); // email int getUnreadEmailCount(int playerID); diff --git a/src/Player.hpp b/src/Player.hpp index c895e1b..6b374d9 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -77,6 +77,7 @@ struct Player { bool buddiesSynced; int64_t buddyIDs[50]; + bool isBuddyBlocked[50]; ChunkPos chunkPos; std::set* viewableChunks;