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