From 9a7d9052ba99029418b58da71b0a49b765d4d77c Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 20 Apr 2025 22:44:16 -0700 Subject: [PATCH] Add invite initial response msg re-do team leave logic to send more accurate messages Players are still able to leave the team with the same results as before, however now the correct messages are sent to team chats (no fixes for local teams). --- dChatServer/ChatPacketHandler.cpp | 20 ++++++++-- dChatServer/ChatPacketHandler.h | 2 + dChatServer/PlayerContainer.cpp | 61 +++++++++++++++---------------- dChatServer/PlayerContainer.h | 2 +- dNet/ChatPackets.cpp | 16 ++++++++ dNet/ChatPackets.h | 10 +++++ 6 files changed, 75 insertions(+), 36 deletions(-) diff --git a/dChatServer/ChatPacketHandler.cpp b/dChatServer/ChatPacketHandler.cpp index de0b395f..3690e511 100644 --- a/dChatServer/ChatPacketHandler.cpp +++ b/dChatServer/ChatPacketHandler.cpp @@ -602,6 +602,19 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) { SendTeamInvite(other, player); LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.GetAsString().c_str()); + + bool failed = false; + for (const auto& ignore : other.ignoredPlayers) { + if (ignore.playerId == player.playerID) { + failed = true; + break; + } + } + + ChatPackets::TeamInviteInitialResponse response{}; + response.inviteFailedToSend = failed; + response.playerName = invitedPlayer.string; + ChatPackets::SendRoutedMsg(response, playerID, player.worldServerSysAddr); } void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) { @@ -615,7 +628,7 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) { LWOOBJID leaderID = LWOOBJID_EMPTY; inStream.Read(leaderID); - LOG("Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined); + LOG("Invite reponse received: %llu -> %llu (%d)", playerID, leaderID, declined); if (declined) { return; @@ -744,14 +757,15 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) { const auto& data = Game::playerContainer.GetPlayerData(playerID); if (team != nullptr && data) { + LOG_DEBUG("Player %llu is requesting team status", playerID); if (team->local && data.zoneID.GetMapID() != team->zoneId.GetMapID() && data.zoneID.GetCloneID() != team->zoneId.GetCloneID()) { - Game::playerContainer.RemoveMember(team, playerID, false, false, true, true); + Game::playerContainer.RemoveMember(team, playerID, false, false, false, true); return; } if (team->memberIDs.size() <= 1 && !team->local) { - Game::playerContainer.DisbandTeam(team); + Game::playerContainer.DisbandTeam(team, LWOOBJID_EMPTY, u""); return; } diff --git a/dChatServer/ChatPacketHandler.h b/dChatServer/ChatPacketHandler.h index 519dfeb6..ca5c3648 100644 --- a/dChatServer/ChatPacketHandler.h +++ b/dChatServer/ChatPacketHandler.h @@ -71,6 +71,8 @@ namespace ChatPacketHandler { void SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName); void SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID); void SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID); + + /* Sends a message to the provided `receiver` with information about the updated team. If `i64LeaderID` is not LWOOBJID_EMPTY, the client will update the leader to that new playerID. */ void SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName); void SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID); diff --git a/dChatServer/PlayerContainer.cpp b/dChatServer/PlayerContainer.cpp index 5392fe54..b3323f81 100644 --- a/dChatServer/PlayerContainer.cpp +++ b/dChatServer/PlayerContainer.cpp @@ -284,41 +284,39 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) { } } -void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disband, bool kicked, bool leaving, bool silent) { - const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID); +void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID causingPlayerID, bool disband, bool kicked, bool leaving, bool silent) { + LOG_DEBUG("Player %llu is leaving team %i", causingPlayerID, team->teamID); + const auto index = std::ranges::find(team->memberIDs, causingPlayerID); if (index == team->memberIDs.end()) return; - const auto& member = GetPlayerData(playerID); - - if (member && !silent) { - ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY); - } - - const auto memberName = GetName(playerID); - - for (const auto memberId : team->memberIDs) { - if (silent && memberId == playerID) { - continue; - } - - const auto& otherMember = GetPlayerData(memberId); - - if (!otherMember) continue; - - ChatPacketHandler::SendTeamRemovePlayer(otherMember, disband, kicked, leaving, false, team->leaderID, playerID, memberName); - } - team->memberIDs.erase(index); - UpdateTeamsOnWorld(team, false); + const auto& member = GetPlayerData(causingPlayerID); + + const auto causingMemberName = GetName(causingPlayerID); + + if (member && !silent) { + ChatPacketHandler::SendTeamRemovePlayer(member, disband, kicked, leaving, team->local, LWOOBJID_EMPTY, causingPlayerID, causingMemberName); + } if (team->memberIDs.size() <= 1) { - DisbandTeam(team); - } else { - if (playerID == team->leaderID) { - PromoteMember(team, team->memberIDs[0]); + DisbandTeam(team, causingPlayerID, causingMemberName); + } else /* team has enough members to be a team still */ { + team->leaderID = (causingPlayerID == team->leaderID) ? team->memberIDs[0] : team->leaderID; + for (const auto memberId : team->memberIDs) { + if (silent && memberId == causingPlayerID) { + continue; + } + + const auto& otherMember = GetPlayerData(memberId); + + if (!otherMember) continue; + + ChatPacketHandler::SendTeamRemovePlayer(otherMember, disband, kicked, leaving, team->local, team->leaderID, causingPlayerID, causingMemberName); } + + UpdateTeamsOnWorld(team, false); } } @@ -334,20 +332,19 @@ void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) { } } -void PlayerContainer::DisbandTeam(TeamData* team) { - const auto index = std::find(GetTeams().begin(), GetTeams().end(), team); +void PlayerContainer::DisbandTeam(TeamData* team, const LWOOBJID causingPlayerID, const std::u16string& causingPlayerName) { + const auto index = std::ranges::find(GetTeams(), team); if (index == GetTeams().end()) return; + LOG_DEBUG("Disbanding team %i", (*index)->teamID); for (const auto memberId : team->memberIDs) { const auto& otherMember = GetPlayerData(memberId); if (!otherMember) continue; - const auto memberName = GeneralUtils::UTF8ToUTF16(otherMember.playerName); - ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY); - ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember.playerID, memberName); + ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, causingPlayerID, causingPlayerName); } UpdateTeamsOnWorld(team, true); diff --git a/dChatServer/PlayerContainer.h b/dChatServer/PlayerContainer.h index 4e9f3933..f4cffa3d 100644 --- a/dChatServer/PlayerContainer.h +++ b/dChatServer/PlayerContainer.h @@ -91,7 +91,7 @@ public: void AddMember(TeamData* team, LWOOBJID playerID); void RemoveMember(TeamData* team, LWOOBJID playerID, bool disband, bool kicked, bool leaving, bool silent = false); void PromoteMember(TeamData* team, LWOOBJID newLeader); - void DisbandTeam(TeamData* team); + void DisbandTeam(TeamData* team, const LWOOBJID causingPlayerID, const std::u16string& causingPlayerName); void TeamStatusUpdate(TeamData* team); void UpdateTeamsOnWorld(TeamData* team, bool deleteTeam); std::u16string GetName(LWOOBJID playerID); diff --git a/dNet/ChatPackets.cpp b/dNet/ChatPackets.cpp index 19375426..d1707e8e 100644 --- a/dNet/ChatPackets.cpp +++ b/dNet/ChatPackets.cpp @@ -132,3 +132,19 @@ bool ChatPackets::AchievementNotify::Deserialize(RakNet::BitStream& bitstream) { return true; } + +void ChatPackets::TeamInviteInitialResponse::Serialize(RakNet::BitStream& bitstream) const { + bitstream.Write(inviteFailedToSend); + bitstream.Write(playerName); +} + +void ChatPackets::SendRoutedMsg(const LUBitStream& msg, const LWOOBJID targetID, const SystemAddress& sysAddr) { + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); + bitStream.Write(targetID); + + // Now write the actual packet + msg.WriteHeader(bitStream); + msg.Serialize(bitStream); + Game::server->Send(bitStream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); +} diff --git a/dNet/ChatPackets.h b/dNet/ChatPackets.h index b435ecab..a0cfbc9a 100644 --- a/dNet/ChatPackets.h +++ b/dNet/ChatPackets.h @@ -46,9 +46,19 @@ namespace ChatPackets { bool Deserialize(RakNet::BitStream& bitstream) override; }; + struct TeamInviteInitialResponse : public LUBitStream { + bool inviteFailedToSend{}; + LUWString playerName{}; + TeamInviteInitialResponse() : LUBitStream(eConnectionType::CLIENT, MessageType::Client::TEAM_INVITE_INITIAL_RESPONSE) {} + + void Serialize(RakNet::BitStream& bitstream) const override; + // No Deserialize needed on our end + }; + void SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message); void SendSystemMessage(const SystemAddress& sysAddr, const std::u16string& message, bool broadcast = false); void SendMessageFail(const SystemAddress& sysAddr); + void SendRoutedMsg(const LUBitStream& msg, const LWOOBJID targetID, const SystemAddress& sysAddr); }; #endif // CHATPACKETS_H