Address friends list IDs and removal of friends (#628)

* Add friends list migration

* Change friends to use charID

Update friends table to use charID and not LWOOBJID variant.

* Fix remove friend

Fix remove friend and make the query more readable at a glance.

* Add and remove friends in the container

Properly add and remove friends in the player container
This commit is contained in:
David Markowitz 2022-07-10 17:59:07 -07:00 committed by GitHub
parent 325dc5a571
commit 06217ad5e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 62 deletions

View File

@ -21,10 +21,17 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
auto player = playerContainer.GetPlayerData(playerID); auto player = playerContainer.GetPlayerData(playerID);
if (!player) return; if (!player) return;
//Get our friends list from the Db: //Get our friends list from the Db. Using a derived table since the friend of a player can be in either column.
auto stmt = Database::CreatePreppedStmt("SELECT * FROM friends WHERE player_id = ? OR friend_id = ?"); auto stmt = Database::CreatePreppedStmt(
stmt->setUInt64(1, playerID); "SELECT fr.requested_player, best_friend, ci.name FROM "
stmt->setUInt64(2, playerID); "(SELECT CASE "
"WHEN player_id = ? THEN friend_id "
"WHEN friend_id = ? THEN player_id "
"END AS requested_player, best_friend FROM friends) AS fr "
"JOIN charinfo AS ci ON ci.id = fr.requested_player "
"WHERE fr.requested_player IS NOT NULL;");
stmt->setUInt(1, static_cast<uint32_t>(playerID));
stmt->setUInt(2, static_cast<uint32_t>(playerID));
std::vector<FriendData> friends; std::vector<FriendData> friends;
@ -32,27 +39,16 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
while (res->next()) { while (res->next()) {
FriendData fd; FriendData fd;
fd.isFTP = false; // not a thing in DLU fd.isFTP = false; // not a thing in DLU
fd.friendID = res->getInt64(1); fd.friendID = res->getUInt(1);
if (fd.friendID == playerID) fd.friendID = res->getUInt64(2); GeneralUtils::SetBit(fd.friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
GeneralUtils::SetBit(fd.friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
fd.isBestFriend = res->getInt(3) == 2; //0 = friends, 1 = requested, 2 = bffs fd.isBestFriend = res->getInt(2) == 2; //0 = friends, 1 = requested, 2 = bffs
fd.friendName = res->getString(3);
//We need to find their name as well:
{
auto stmt = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE id=? limit 1");
stmt->setInt(1, fd.friendID);
auto res = stmt->executeQuery();
while (res->next()) {
fd.friendName = res->getString(1);
}
delete res;
delete stmt;
}
//Now check if they're online: //Now check if they're online:
auto fr = playerContainer.GetPlayerData(fd.friendID); auto fr = playerContainer.GetPlayerData(fd.friendID);
Game::logger->Log("ChatPacketHandler", "friend is %llu\n", fd.friendID);
if (fr) { if (fr) {
fd.isOnline = true; fd.isOnline = true;
fd.zoneID = fr->zoneID; fd.zoneID = fr->zoneID;
@ -69,7 +65,9 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
} }
delete res; delete res;
res = nullptr;
delete stmt; delete stmt;
stmt = nullptr;
//Now, we need to send the friendlist to the server they came from: //Now, we need to send the friendlist to the server they came from:
CBITSTREAM; CBITSTREAM;
@ -100,8 +98,6 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
std::string playerName = PacketUtils::ReadString(0x14, packet, true); std::string playerName = PacketUtils::ReadString(0x14, packet, true);
//There's another bool here to determine if it's a best friend request, but we're not handling it right now. //There's another bool here to determine if it's a best friend request, but we're not handling it right now.
//PacketUtils::SavePacket("FriendRequest.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed());
//We need to check to see if the player is actually online or not: //We need to check to see if the player is actually online or not:
auto targetData = playerContainer.GetPlayerData(playerName); auto targetData = playerContainer.GetPlayerData(playerName);
if (targetData) { if (targetData) {
@ -118,23 +114,46 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
uint8_t responseCode = packet->data[0x14]; uint8_t responseCode = packet->data[0x14];
std::string friendName = PacketUtils::ReadString(0x15, packet, true); std::string friendName = PacketUtils::ReadString(0x15, packet, true);
Game::logger->Log("ChatPacketHandler", "Friend response code: %i\n", responseCode);
if (responseCode != 0) return; //If we're not accepting the request, end here, do not insert to friends table.
PacketUtils::SavePacket("HandleFriendResponse.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed());
//Now to try and find both of these: //Now to try and find both of these:
auto goonA = playerContainer.GetPlayerData(playerID); auto goonA = playerContainer.GetPlayerData(playerID);
auto goonB = playerContainer.GetPlayerData(friendName); auto goonB = playerContainer.GetPlayerData(friendName);
if (!goonA || !goonB) return; if (!goonA || !goonB) return;
if (responseCode != 0) return; //If we're not accepting the request, end here, do not insert to friends table.
for (auto friendData : goonA->friends) {
if (friendData.friendID == goonB->playerID) return;
}
for (auto friendData : goonB->friends) {
if (friendData.friendID == goonA->playerID) return;
}
// Add the goons to their friends list
FriendData goonAData;
goonAData.zoneID = goonA->zoneID;
goonAData.friendID = goonA->playerID;
goonAData.friendName = goonA->playerName;
goonAData.isBestFriend = false;
goonAData.isFTP = false;
goonAData.isOnline = true;
goonB->friends.push_back(goonAData);
FriendData goonBData;
goonBData.zoneID = goonB->zoneID;
goonBData.friendID = goonB->playerID;
goonBData.friendName = goonB->playerName;
goonBData.isBestFriend = false;
goonBData.isFTP = false;
goonBData.isOnline = true;
goonA->friends.push_back(goonBData);
SendFriendResponse(goonB, goonA, responseCode); SendFriendResponse(goonB, goonA, responseCode);
SendFriendResponse(goonA, goonB, responseCode); //Do we need to send it to both? I think so so both get the updated friendlist but... idk. SendFriendResponse(goonA, goonB, responseCode); //Do we need to send it to both? I think so so both get the updated friendlist but... idk.
auto stmt = Database::CreatePreppedStmt("INSERT INTO `friends`(`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?)"); auto stmt = Database::CreatePreppedStmt("INSERT IGNORE INTO `friends` (`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?)");
stmt->setUInt64(1, goonA->playerID); stmt->setUInt(1, static_cast<uint32_t>(goonA->playerID));
stmt->setUInt64(2, goonB->playerID); stmt->setUInt(2, static_cast<uint32_t>(goonB->playerID));
stmt->setInt(3, 0); stmt->setInt(3, 0);
stmt->execute(); stmt->execute();
delete stmt; delete stmt;
@ -145,50 +164,61 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID); inStream.Read(playerID);
std::string friendName = PacketUtils::ReadString(16, packet, true); std::string friendName = PacketUtils::ReadString(0x14, packet, true);
//we'll have to query the db here to find the user, since you can delete them while they're offline. //we'll have to query the db here to find the user, since you can delete them while they're offline.
//First, we need to find their ID: //First, we need to find their ID:
auto stmt = Database::CreatePreppedStmt("select id from charinfo where name=? limit 1;"); auto stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? LIMIT 1;");
stmt->setString(1, friendName.c_str()); stmt->setString(1, friendName.c_str());
LWOOBJID friendID = 0; LWOOBJID friendID = 0;
auto res = stmt->executeQuery(); auto res = stmt->executeQuery();
while (res->next()) { while (res->next()) {
friendID = res->getUInt64(1); friendID = res->getUInt(1);
} }
// Convert friendID to LWOOBJID
GeneralUtils::SetBit(friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
GeneralUtils::SetBit(friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
delete res; delete res;
res = nullptr;
delete stmt; delete stmt;
stmt = nullptr;
//Set our bits to convert to the BIG BOY objectID. auto deletestmt = Database::CreatePreppedStmt("DELETE FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;");
friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_CHARACTER); deletestmt->setUInt(1, static_cast<uint32_t>(playerID));
friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_PERSISTENT); deletestmt->setUInt(2, static_cast<uint32_t>(friendID));
deletestmt->setUInt(3, static_cast<uint32_t>(friendID));
//YEET: deletestmt->setUInt(4, static_cast<uint32_t>(playerID));
auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1");
deletestmt->setUInt64(1, playerID);
deletestmt->setUInt64(2, friendID);
deletestmt->execute(); deletestmt->execute();
delete deletestmt;
//because I'm lazy and they can be reversed: delete deletestmt;
{ deletestmt = nullptr;
auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1");
deletestmt->setUInt64(1, friendID);
deletestmt->setUInt64(2, playerID);
deletestmt->execute();
delete deletestmt;
}
//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 = playerContainer.GetPlayerData(playerID);
if (goonA) { if (goonA) {
// Remove the friend from our list of friends
for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) {
if ((*friendData).friendID == friendID) {
goonA->friends.erase(friendData);
break;
}
}
SendRemoveFriend(goonA, friendName, true); SendRemoveFriend(goonA, friendName, true);
} }
auto goonB = playerContainer.GetPlayerData(friendID); auto goonB = playerContainer.GetPlayerData(friendID);
if (!goonB) return; if (!goonB) return;
// Do it again for other person
for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) {
if ((*friendData).friendID == playerID) {
goonB->friends.erase(friendData);
break;
}
}
std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID)); std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID));
SendRemoveFriend(goonB, goonAName, true); SendRemoveFriend(goonB, goonAName, true);
} }
@ -217,8 +247,6 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s\n", senderName.c_str(), channel, message.c_str()); Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s\n", senderName.c_str(), channel, message.c_str());
//PacketUtils::SavePacket("chat.bin", reinterpret_cast<char*>(packet->data), packet->length);
if (channel != 8) return; if (channel != 8) return;
auto* team = playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
@ -454,8 +482,6 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet)
playerContainer.RemoveMember(team, kickedId, false, true, false); playerContainer.RemoveMember(team, kickedId, false, true, false);
} }
//PacketUtils::SavePacket("kick.bin", reinterpret_cast<char*>(packet->data), packet->length);
} }
void ChatPacketHandler::HandleTeamPromote(Packet* packet) void ChatPacketHandler::HandleTeamPromote(Packet* packet)
@ -481,8 +507,6 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet)
playerContainer.PromoteMember(team, promoted->playerID); playerContainer.PromoteMember(team, promoted->playerID);
} }
//PacketUtils::SavePacket("promote.bin", reinterpret_cast<char*>(packet->data), packet->length);
} }
void ChatPacketHandler::HandleTeamLootOption(Packet* packet) void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
@ -509,8 +533,6 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
playerContainer.UpdateTeamsOnWorld(team, false); playerContainer.UpdateTeamsOnWorld(team, false);
} }
//PacketUtils::SavePacket("option.bin", reinterpret_cast<char*>(packet->data), packet->length);
} }
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
@ -560,7 +582,6 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
const auto memberName = playerContainer.GetName(memberId); const auto memberName = playerContainer.GetName(memberId);
//ChatPacketHandler::SendTeamAddPlayer(otherMember, false, false, false, data->playerID, leaderName, data->zoneID);
if (otherMember != nullptr) if (otherMember != nullptr)
{ {
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID); ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);

View File

@ -0,0 +1 @@
UPDATE friends SET player_id = player_id % 0x100000000, friend_id = friend_id % 0x100000000;