mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-04-26 16:46:31 +00:00

Makes it easier to follow team logic when you're not bouncing between 3 classes in 3 files. Consolidates all team logic to 1 namespace in TeamContainer. No logic changes were done, only renaming and fixing errors from the moving. TeamData should be replaced with unique_ptrs at some point so the Shutdown method can be removed from TeamContainer.
670 lines
18 KiB
C++
670 lines
18 KiB
C++
#include "TeamContainer.h"
|
|
|
|
#include "ChatPackets.h"
|
|
|
|
#include "MessageType/Chat.h"
|
|
#include "MessageType/Game.h"
|
|
|
|
#include "ChatPacketHandler.h"
|
|
#include "PlayerContainer.h"
|
|
|
|
namespace {
|
|
TeamContainer::Data g_TeamContainer{};
|
|
LWOOBJID g_TeamIDCounter = 0;
|
|
}
|
|
|
|
const TeamContainer::Data& TeamContainer::GetTeamContainer() {
|
|
return g_TeamContainer;
|
|
}
|
|
|
|
std::vector<TeamData*>& TeamContainer::GetTeamsMut() {
|
|
return g_TeamContainer.mTeams;
|
|
}
|
|
|
|
const std::vector<TeamData*>& TeamContainer::GetTeams() {
|
|
return GetTeamsMut();
|
|
}
|
|
|
|
void TeamContainer::Shutdown() {
|
|
for (auto* team : g_TeamContainer.mTeams) if (team) delete team;
|
|
}
|
|
|
|
void TeamContainer::HandleTeamInvite(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
|
|
LWOOBJID playerID;
|
|
LUWString invitedPlayer;
|
|
|
|
inStream.Read(playerID);
|
|
inStream.IgnoreBytes(4);
|
|
inStream.Read(invitedPlayer);
|
|
|
|
const auto& player = Game::playerContainer.GetPlayerData(playerID);
|
|
|
|
if (!player) return;
|
|
|
|
auto* team = GetTeam(playerID);
|
|
|
|
if (team == nullptr) {
|
|
team = CreateTeam(playerID);
|
|
}
|
|
|
|
const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer.GetAsString());
|
|
|
|
if (!other) return;
|
|
|
|
if (GetTeam(other.playerID) != nullptr) {
|
|
return;
|
|
}
|
|
|
|
if (team->memberIDs.size() > 3) {
|
|
// no more teams greater than 4
|
|
|
|
LOG("Someone tried to invite a 5th player to a team");
|
|
return;
|
|
}
|
|
|
|
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 TeamContainer::HandleTeamInviteResponse(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
|
inStream.Read(playerID);
|
|
uint32_t size = 0;
|
|
inStream.Read(size);
|
|
char declined = 0;
|
|
inStream.Read(declined);
|
|
LWOOBJID leaderID = LWOOBJID_EMPTY;
|
|
inStream.Read(leaderID);
|
|
|
|
LOG("Invite reponse received: %llu -> %llu (%d)", playerID, leaderID, declined);
|
|
|
|
if (declined) {
|
|
return;
|
|
}
|
|
|
|
auto* team = GetTeam(leaderID);
|
|
|
|
if (team == nullptr) {
|
|
LOG("Failed to find team for leader (%llu)", leaderID);
|
|
|
|
team = GetTeam(playerID);
|
|
}
|
|
|
|
if (team == nullptr) {
|
|
LOG("Failed to find team for player (%llu)", playerID);
|
|
return;
|
|
}
|
|
|
|
AddMember(team, playerID);
|
|
}
|
|
|
|
void TeamContainer::HandleTeamLeave(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
|
inStream.Read(playerID);
|
|
uint32_t size = 0;
|
|
inStream.Read(size);
|
|
|
|
auto* team = GetTeam(playerID);
|
|
|
|
LOG("(%llu) leaving team", playerID);
|
|
|
|
if (team != nullptr) {
|
|
RemoveMember(team, playerID, false, false, true);
|
|
}
|
|
}
|
|
|
|
void TeamContainer::HandleTeamKick(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
|
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
|
LUWString kickedPlayer;
|
|
|
|
inStream.Read(playerID);
|
|
inStream.IgnoreBytes(4);
|
|
inStream.Read(kickedPlayer);
|
|
|
|
|
|
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.GetAsString().c_str());
|
|
|
|
const auto& kicked = Game::playerContainer.GetPlayerData(kickedPlayer.GetAsString());
|
|
|
|
LWOOBJID kickedId = LWOOBJID_EMPTY;
|
|
|
|
if (kicked) {
|
|
kickedId = kicked.playerID;
|
|
} else {
|
|
kickedId = Game::playerContainer.GetId(kickedPlayer.string);
|
|
}
|
|
|
|
if (kickedId == LWOOBJID_EMPTY) return;
|
|
|
|
auto* team = GetTeam(playerID);
|
|
|
|
if (team != nullptr) {
|
|
if (team->leaderID != playerID || team->leaderID == kickedId) return;
|
|
|
|
RemoveMember(team, kickedId, false, true, false);
|
|
}
|
|
}
|
|
|
|
void TeamContainer::HandleTeamPromote(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
|
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
|
LUWString promotedPlayer;
|
|
|
|
inStream.Read(playerID);
|
|
inStream.IgnoreBytes(4);
|
|
inStream.Read(promotedPlayer);
|
|
|
|
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.GetAsString().c_str());
|
|
|
|
const auto& promoted = Game::playerContainer.GetPlayerData(promotedPlayer.GetAsString());
|
|
|
|
if (!promoted) return;
|
|
|
|
auto* team = GetTeam(playerID);
|
|
|
|
if (team != nullptr) {
|
|
if (team->leaderID != playerID) return;
|
|
|
|
PromoteMember(team, promoted.playerID);
|
|
}
|
|
}
|
|
|
|
void TeamContainer::HandleTeamLootOption(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
|
inStream.Read(playerID);
|
|
uint32_t size = 0;
|
|
inStream.Read(size);
|
|
|
|
char option;
|
|
inStream.Read(option);
|
|
|
|
auto* team = GetTeam(playerID);
|
|
|
|
if (team != nullptr) {
|
|
if (team->leaderID != playerID) return;
|
|
|
|
team->lootFlag = option;
|
|
|
|
TeamStatusUpdate(team);
|
|
|
|
UpdateTeamsOnWorld(team, false);
|
|
}
|
|
}
|
|
|
|
void TeamContainer::HandleTeamStatusRequest(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
|
inStream.Read(playerID);
|
|
|
|
auto* team = GetTeam(playerID);
|
|
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()) {
|
|
RemoveMember(team, playerID, false, false, false, true);
|
|
|
|
return;
|
|
}
|
|
|
|
if (team->memberIDs.size() <= 1 && !team->local) {
|
|
DisbandTeam(team, LWOOBJID_EMPTY, u"");
|
|
|
|
return;
|
|
}
|
|
|
|
if (!team->local) {
|
|
SendTeamSetLeader(data, team->leaderID);
|
|
} else {
|
|
SendTeamSetLeader(data, LWOOBJID_EMPTY);
|
|
}
|
|
|
|
TeamStatusUpdate(team);
|
|
|
|
const auto leaderName = GeneralUtils::UTF8ToUTF16(data.playerName);
|
|
|
|
for (const auto memberId : team->memberIDs) {
|
|
const auto& otherMember = Game::playerContainer.GetPlayerData(memberId);
|
|
|
|
if (memberId == playerID) continue;
|
|
|
|
const auto memberName = Game::playerContainer.GetName(memberId);
|
|
|
|
if (otherMember) {
|
|
SendTeamSetOffWorldFlag(otherMember, data.playerID, data.zoneID);
|
|
}
|
|
SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember ? otherMember.zoneID : LWOZONEID(0, 0, 0));
|
|
}
|
|
|
|
UpdateTeamsOnWorld(team, false);
|
|
}
|
|
}
|
|
|
|
void TeamContainer::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
|
bitStream.Write(receiver.playerID);
|
|
|
|
//portion that will get routed:
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::TEAM_INVITE);
|
|
|
|
bitStream.Write(LUWString(sender.playerName.c_str()));
|
|
bitStream.Write(sender.playerID);
|
|
|
|
SystemAddress sysAddr = receiver.worldServerSysAddr;
|
|
SEND_PACKET;
|
|
}
|
|
|
|
void TeamContainer::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
|
bitStream.Write(receiver.playerID);
|
|
|
|
//portion that will get routed:
|
|
CMSGHEADER;
|
|
|
|
bitStream.Write(receiver.playerID);
|
|
bitStream.Write(MessageType::Game::TEAM_INVITE_CONFIRM);
|
|
|
|
bitStream.Write(bLeaderIsFreeTrial);
|
|
bitStream.Write(i64LeaderID);
|
|
bitStream.Write(i64LeaderZoneID);
|
|
bitStream.Write<uint32_t>(0); // BinaryBuffe, no clue what's in here
|
|
bitStream.Write(ucLootFlag);
|
|
bitStream.Write(ucNumOfOtherPlayers);
|
|
bitStream.Write(ucResponseCode);
|
|
bitStream.Write<uint32_t>(wsLeaderName.size());
|
|
for (const auto character : wsLeaderName) {
|
|
bitStream.Write(character);
|
|
}
|
|
|
|
SystemAddress sysAddr = receiver.worldServerSysAddr;
|
|
SEND_PACKET;
|
|
}
|
|
|
|
void TeamContainer::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
|
bitStream.Write(receiver.playerID);
|
|
|
|
//portion that will get routed:
|
|
CMSGHEADER;
|
|
|
|
bitStream.Write(receiver.playerID);
|
|
bitStream.Write(MessageType::Game::TEAM_GET_STATUS_RESPONSE);
|
|
|
|
bitStream.Write(i64LeaderID);
|
|
bitStream.Write(i64LeaderZoneID);
|
|
bitStream.Write<uint32_t>(0); // BinaryBuffe, no clue what's in here
|
|
bitStream.Write(ucLootFlag);
|
|
bitStream.Write(ucNumOfOtherPlayers);
|
|
bitStream.Write<uint32_t>(wsLeaderName.size());
|
|
for (const auto character : wsLeaderName) {
|
|
bitStream.Write(character);
|
|
}
|
|
|
|
SystemAddress sysAddr = receiver.worldServerSysAddr;
|
|
SEND_PACKET;
|
|
}
|
|
|
|
void TeamContainer::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
|
bitStream.Write(receiver.playerID);
|
|
|
|
//portion that will get routed:
|
|
CMSGHEADER;
|
|
|
|
bitStream.Write(receiver.playerID);
|
|
bitStream.Write(MessageType::Game::TEAM_SET_LEADER);
|
|
|
|
bitStream.Write(i64PlayerID);
|
|
|
|
SystemAddress sysAddr = receiver.worldServerSysAddr;
|
|
SEND_PACKET;
|
|
}
|
|
|
|
void TeamContainer::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
|
bitStream.Write(receiver.playerID);
|
|
|
|
//portion that will get routed:
|
|
CMSGHEADER;
|
|
|
|
bitStream.Write(receiver.playerID);
|
|
bitStream.Write(MessageType::Game::TEAM_ADD_PLAYER);
|
|
|
|
bitStream.Write(bIsFreeTrial);
|
|
bitStream.Write(bLocal);
|
|
bitStream.Write(bNoLootOnDeath);
|
|
bitStream.Write(i64PlayerID);
|
|
bitStream.Write<uint32_t>(wsPlayerName.size());
|
|
for (const auto character : wsPlayerName) {
|
|
bitStream.Write(character);
|
|
}
|
|
bitStream.Write1();
|
|
if (receiver.zoneID.GetCloneID() == zoneID.GetCloneID()) {
|
|
zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0);
|
|
}
|
|
bitStream.Write(zoneID);
|
|
|
|
SystemAddress sysAddr = receiver.worldServerSysAddr;
|
|
SEND_PACKET;
|
|
}
|
|
|
|
void TeamContainer::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
|
bitStream.Write(receiver.playerID);
|
|
|
|
//portion that will get routed:
|
|
CMSGHEADER;
|
|
|
|
bitStream.Write(receiver.playerID);
|
|
bitStream.Write(MessageType::Game::TEAM_REMOVE_PLAYER);
|
|
|
|
bitStream.Write(bDisband);
|
|
bitStream.Write(bIsKicked);
|
|
bitStream.Write(bIsLeaving);
|
|
bitStream.Write(bLocal);
|
|
bitStream.Write(i64LeaderID);
|
|
bitStream.Write(i64PlayerID);
|
|
bitStream.Write<uint32_t>(wsPlayerName.size());
|
|
for (const auto character : wsPlayerName) {
|
|
bitStream.Write(character);
|
|
}
|
|
|
|
SystemAddress sysAddr = receiver.worldServerSysAddr;
|
|
SEND_PACKET;
|
|
}
|
|
|
|
void TeamContainer::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
|
bitStream.Write(receiver.playerID);
|
|
|
|
//portion that will get routed:
|
|
CMSGHEADER;
|
|
|
|
bitStream.Write(receiver.playerID);
|
|
bitStream.Write(MessageType::Game::TEAM_SET_OFF_WORLD_FLAG);
|
|
|
|
bitStream.Write(i64PlayerID);
|
|
if (receiver.zoneID.GetCloneID() == zoneID.GetCloneID()) {
|
|
zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0);
|
|
}
|
|
bitStream.Write(zoneID);
|
|
|
|
SystemAddress sysAddr = receiver.worldServerSysAddr;
|
|
SEND_PACKET;
|
|
}
|
|
|
|
void TeamContainer::CreateTeamServer(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
LWOOBJID playerID;
|
|
inStream.Read(playerID);
|
|
size_t membersSize = 0;
|
|
inStream.Read(membersSize);
|
|
|
|
if (membersSize >= 4) {
|
|
LOG("Tried to create a team with more than 4 players");
|
|
return;
|
|
}
|
|
|
|
std::vector<LWOOBJID> members;
|
|
|
|
members.reserve(membersSize);
|
|
|
|
for (size_t i = 0; i < membersSize; i++) {
|
|
LWOOBJID member;
|
|
inStream.Read(member);
|
|
members.push_back(member);
|
|
}
|
|
|
|
LWOZONEID zoneId;
|
|
|
|
inStream.Read(zoneId);
|
|
|
|
auto* team = CreateLocalTeam(members);
|
|
|
|
if (team != nullptr) {
|
|
team->zoneId = zoneId;
|
|
UpdateTeamsOnWorld(team, false);
|
|
}
|
|
}
|
|
|
|
TeamData* TeamContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
|
|
if (members.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
TeamData* newTeam = nullptr;
|
|
|
|
for (const auto member : members) {
|
|
auto* team = GetTeam(member);
|
|
|
|
if (team != nullptr) {
|
|
RemoveMember(team, member, false, false, true);
|
|
}
|
|
|
|
if (newTeam == nullptr) {
|
|
newTeam = CreateTeam(member, true);
|
|
} else {
|
|
AddMember(newTeam, member);
|
|
}
|
|
}
|
|
|
|
newTeam->lootFlag = 1;
|
|
|
|
TeamStatusUpdate(newTeam);
|
|
|
|
return newTeam;
|
|
}
|
|
|
|
TeamData* TeamContainer::CreateTeam(LWOOBJID leader, bool local) {
|
|
auto* team = new TeamData();
|
|
|
|
team->teamID = ++g_TeamIDCounter;
|
|
team->leaderID = leader;
|
|
team->local = local;
|
|
|
|
GetTeamsMut().push_back(team);
|
|
|
|
AddMember(team, leader);
|
|
|
|
return team;
|
|
}
|
|
|
|
TeamData* TeamContainer::GetTeam(LWOOBJID playerID) {
|
|
for (auto* team : GetTeams()) {
|
|
if (std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID) == team->memberIDs.end()) continue;
|
|
|
|
return team;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void TeamContainer::AddMember(TeamData* team, LWOOBJID playerID) {
|
|
if (team->memberIDs.size() >= 4) {
|
|
LOG("Tried to add player to team that already had 4 players");
|
|
const auto& player = Game::playerContainer.GetPlayerData(playerID);
|
|
if (!player) return;
|
|
ChatPackets::SendSystemMessage(player.worldServerSysAddr, u"The teams is full! You have not been added to a team!");
|
|
return;
|
|
}
|
|
|
|
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
|
|
|
|
if (index != team->memberIDs.end()) return;
|
|
|
|
team->memberIDs.push_back(playerID);
|
|
|
|
const auto& leader = Game::playerContainer.GetPlayerData(team->leaderID);
|
|
const auto& member = Game::playerContainer.GetPlayerData(playerID);
|
|
|
|
if (!leader || !member) return;
|
|
|
|
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader.playerName);
|
|
const auto memberName = GeneralUtils::UTF8ToUTF16(member.playerName);
|
|
|
|
SendTeamInviteConfirm(member, false, leader.playerID, leader.zoneID, team->lootFlag, 0, 0, leaderName);
|
|
|
|
if (!team->local) {
|
|
SendTeamSetLeader(member, leader.playerID);
|
|
} else {
|
|
SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
|
}
|
|
|
|
UpdateTeamsOnWorld(team, false);
|
|
|
|
for (const auto memberId : team->memberIDs) {
|
|
const auto& otherMember = Game::playerContainer.GetPlayerData(memberId);
|
|
|
|
if (otherMember == member) continue;
|
|
|
|
const auto otherMemberName = Game::playerContainer.GetName(memberId);
|
|
|
|
SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember ? otherMember.zoneID : LWOZONEID(0, 0, 0));
|
|
|
|
if (otherMember) {
|
|
SendTeamAddPlayer(otherMember, false, team->local, false, member.playerID, memberName, member.zoneID);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TeamContainer::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;
|
|
|
|
team->memberIDs.erase(index);
|
|
|
|
const auto& member = Game::playerContainer.GetPlayerData(causingPlayerID);
|
|
|
|
const auto causingMemberName = Game::playerContainer.GetName(causingPlayerID);
|
|
|
|
if (member && !silent) {
|
|
SendTeamRemovePlayer(member, disband, kicked, leaving, team->local, LWOOBJID_EMPTY, causingPlayerID, causingMemberName);
|
|
}
|
|
|
|
if (team->memberIDs.size() <= 1) {
|
|
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 = Game::playerContainer.GetPlayerData(memberId);
|
|
|
|
if (!otherMember) continue;
|
|
|
|
SendTeamRemovePlayer(otherMember, disband, kicked, leaving, team->local, team->leaderID, causingPlayerID, causingMemberName);
|
|
}
|
|
|
|
UpdateTeamsOnWorld(team, false);
|
|
}
|
|
}
|
|
|
|
void TeamContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) {
|
|
team->leaderID = newLeader;
|
|
|
|
for (const auto memberId : team->memberIDs) {
|
|
const auto& otherMember = Game::playerContainer.GetPlayerData(memberId);
|
|
|
|
if (!otherMember) continue;
|
|
|
|
SendTeamSetLeader(otherMember, newLeader);
|
|
}
|
|
}
|
|
|
|
void TeamContainer::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 = Game::playerContainer.GetPlayerData(memberId);
|
|
|
|
if (!otherMember) continue;
|
|
|
|
SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
|
|
SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, causingPlayerID, causingPlayerName);
|
|
}
|
|
|
|
UpdateTeamsOnWorld(team, true);
|
|
|
|
GetTeamsMut().erase(index);
|
|
|
|
delete team;
|
|
}
|
|
|
|
void TeamContainer::TeamStatusUpdate(TeamData* team) {
|
|
const auto index = std::find(GetTeams().begin(), GetTeams().end(), team);
|
|
|
|
if (index == GetTeams().end()) return;
|
|
|
|
const auto& leader = Game::playerContainer.GetPlayerData(team->leaderID);
|
|
|
|
if (!leader) return;
|
|
|
|
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader.playerName);
|
|
|
|
for (const auto memberId : team->memberIDs) {
|
|
const auto& otherMember = Game::playerContainer.GetPlayerData(memberId);
|
|
|
|
if (!otherMember) continue;
|
|
|
|
if (!team->local) {
|
|
SendTeamStatus(otherMember, team->leaderID, leader.zoneID, team->lootFlag, 0, leaderName);
|
|
}
|
|
}
|
|
|
|
UpdateTeamsOnWorld(team, false);
|
|
}
|
|
|
|
void TeamContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::TEAM_GET_STATUS);
|
|
|
|
bitStream.Write(team->teamID);
|
|
bitStream.Write(deleteTeam);
|
|
|
|
if (!deleteTeam) {
|
|
bitStream.Write(team->lootFlag);
|
|
bitStream.Write<char>(team->memberIDs.size());
|
|
for (const auto memberID : team->memberIDs) {
|
|
bitStream.Write(memberID);
|
|
}
|
|
}
|
|
|
|
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
|
}
|