mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-04-26 16:46:31 +00:00
chore: move team logic to separate container
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.
This commit is contained in:
parent
9a7d9052ba
commit
5b5a3add2a
@ -1,9 +1,10 @@
|
|||||||
set(DCHATSERVER_SOURCES
|
set(DCHATSERVER_SOURCES
|
||||||
"ChatIgnoreList.cpp"
|
"ChatIgnoreList.cpp"
|
||||||
"ChatPacketHandler.cpp"
|
"ChatPacketHandler.cpp"
|
||||||
"PlayerContainer.cpp"
|
|
||||||
"ChatWebAPI.cpp"
|
"ChatWebAPI.cpp"
|
||||||
"JSONUtils.cpp"
|
"JSONUtils.cpp"
|
||||||
|
"PlayerContainer.cpp"
|
||||||
|
"TeamContainer.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(ChatServer "ChatServer.cpp")
|
add_executable(ChatServer "ChatServer.cpp")
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "StringifiedEnum.h"
|
#include "StringifiedEnum.h"
|
||||||
#include "eGameMasterLevel.h"
|
#include "eGameMasterLevel.h"
|
||||||
#include "ChatPackets.h"
|
#include "ChatPackets.h"
|
||||||
|
#include "TeamContainer.h"
|
||||||
|
|
||||||
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||||
//Get from the packet which player we want to do something with:
|
//Get from the packet which player we want to do something with:
|
||||||
@ -447,7 +448,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
|||||||
|
|
||||||
switch (channel) {
|
switch (channel) {
|
||||||
case eChatChannel::TEAM: {
|
case eChatChannel::TEAM: {
|
||||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
auto* team = TeamContainer::GetTeam(playerID);
|
||||||
if (team == nullptr) return;
|
if (team == nullptr) return;
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs) {
|
for (const auto memberId : team->memberIDs) {
|
||||||
@ -563,400 +564,6 @@ void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const P
|
|||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ChatPacketHandler::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 = Game::playerContainer.GetTeam(playerID);
|
|
||||||
|
|
||||||
if (team == nullptr) {
|
|
||||||
team = Game::playerContainer.CreateTeam(playerID);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer.GetAsString());
|
|
||||||
|
|
||||||
if (!other) return;
|
|
||||||
|
|
||||||
if (Game::playerContainer.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 ChatPacketHandler::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 = Game::playerContainer.GetTeam(leaderID);
|
|
||||||
|
|
||||||
if (team == nullptr) {
|
|
||||||
LOG("Failed to find team for leader (%llu)", leaderID);
|
|
||||||
|
|
||||||
team = Game::playerContainer.GetTeam(playerID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (team == nullptr) {
|
|
||||||
LOG("Failed to find team for player (%llu)", playerID);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::playerContainer.AddMember(team, playerID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
|
|
||||||
CINSTREAM_SKIP_HEADER;
|
|
||||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
|
||||||
inStream.Read(playerID);
|
|
||||||
uint32_t size = 0;
|
|
||||||
inStream.Read(size);
|
|
||||||
|
|
||||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
|
||||||
|
|
||||||
LOG("(%llu) leaving team", playerID);
|
|
||||||
|
|
||||||
if (team != nullptr) {
|
|
||||||
Game::playerContainer.RemoveMember(team, playerID, false, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatPacketHandler::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 = Game::playerContainer.GetTeam(playerID);
|
|
||||||
|
|
||||||
if (team != nullptr) {
|
|
||||||
if (team->leaderID != playerID || team->leaderID == kickedId) return;
|
|
||||||
|
|
||||||
Game::playerContainer.RemoveMember(team, kickedId, false, true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatPacketHandler::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 = Game::playerContainer.GetTeam(playerID);
|
|
||||||
|
|
||||||
if (team != nullptr) {
|
|
||||||
if (team->leaderID != playerID) return;
|
|
||||||
|
|
||||||
Game::playerContainer.PromoteMember(team, promoted.playerID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatPacketHandler::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 = Game::playerContainer.GetTeam(playerID);
|
|
||||||
|
|
||||||
if (team != nullptr) {
|
|
||||||
if (team->leaderID != playerID) return;
|
|
||||||
|
|
||||||
team->lootFlag = option;
|
|
||||||
|
|
||||||
Game::playerContainer.TeamStatusUpdate(team);
|
|
||||||
|
|
||||||
Game::playerContainer.UpdateTeamsOnWorld(team, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
|
||||||
CINSTREAM_SKIP_HEADER;
|
|
||||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
|
||||||
inStream.Read(playerID);
|
|
||||||
|
|
||||||
auto* team = Game::playerContainer.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()) {
|
|
||||||
Game::playerContainer.RemoveMember(team, playerID, false, false, false, true);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (team->memberIDs.size() <= 1 && !team->local) {
|
|
||||||
Game::playerContainer.DisbandTeam(team, LWOOBJID_EMPTY, u"");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!team->local) {
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(data, team->leaderID);
|
|
||||||
} else {
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::playerContainer.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) {
|
|
||||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data.playerID, data.zoneID);
|
|
||||||
}
|
|
||||||
ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember ? otherMember.zoneID : LWOZONEID(0, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::playerContainer.UpdateTeamsOnWorld(team, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatPacketHandler::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 ChatPacketHandler::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 ChatPacketHandler::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 ChatPacketHandler::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 ChatPacketHandler::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 ChatPacketHandler::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 ChatPacketHandler::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 ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const PlayerData& playerData, uint8_t notifyType, uint8_t isBestFriend) {
|
void ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const PlayerData& playerData, uint8_t notifyType, uint8_t isBestFriend) {
|
||||||
/*chat notification is displayed if log in / out and friend is updated in friends list
|
/*chat notification is displayed if log in / out and friend is updated in friends list
|
||||||
[u8] - update type
|
[u8] - update type
|
||||||
|
@ -35,13 +35,13 @@ enum class eChatChannel : uint8_t {
|
|||||||
|
|
||||||
|
|
||||||
enum class eChatMessageResponseCode : uint8_t {
|
enum class eChatMessageResponseCode : uint8_t {
|
||||||
SENT = 0,
|
SENT = 0,
|
||||||
NOTONLINE,
|
NOTONLINE,
|
||||||
GENERALERROR,
|
GENERALERROR,
|
||||||
RECEIVEDNEWWHISPER,
|
RECEIVEDNEWWHISPER,
|
||||||
NOTFRIENDS,
|
NOTFRIENDS,
|
||||||
SENDERFREETRIAL,
|
SENDERFREETRIAL,
|
||||||
RECEIVERFREETRIAL,
|
RECEIVERFREETRIAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace ChatPacketHandler {
|
namespace ChatPacketHandler {
|
||||||
@ -52,33 +52,14 @@ namespace ChatPacketHandler {
|
|||||||
void HandleGMLevelUpdate(Packet* packet);
|
void HandleGMLevelUpdate(Packet* packet);
|
||||||
void HandleWho(Packet* packet);
|
void HandleWho(Packet* packet);
|
||||||
void HandleShowAll(Packet* packet);
|
void HandleShowAll(Packet* packet);
|
||||||
|
|
||||||
void HandleChatMessage(Packet* packet);
|
void HandleChatMessage(Packet* packet);
|
||||||
void HandlePrivateChatMessage(Packet* packet);
|
void HandlePrivateChatMessage(Packet* packet);
|
||||||
void SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode);
|
|
||||||
|
|
||||||
void HandleTeamInvite(Packet* packet);
|
|
||||||
void HandleTeamInviteResponse(Packet* packet);
|
|
||||||
void HandleTeamLeave(Packet* packet);
|
|
||||||
void HandleTeamKick(Packet* packet);
|
|
||||||
void HandleTeamPromote(Packet* packet);
|
|
||||||
void HandleTeamLootOption(Packet* packet);
|
|
||||||
void HandleTeamStatusRequest(Packet* packet);
|
|
||||||
void OnAchievementNotify(RakNet::BitStream& bitstream, const SystemAddress& sysAddr);
|
void OnAchievementNotify(RakNet::BitStream& bitstream, const SystemAddress& sysAddr);
|
||||||
|
|
||||||
void SendTeamInvite(const PlayerData& receiver, const PlayerData& sender);
|
|
||||||
void SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName);
|
|
||||||
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);
|
|
||||||
|
|
||||||
//FriendData is the player we're SENDING this stuff to. Player is the friend that changed state.
|
//FriendData is the player we're SENDING this stuff to. Player is the friend that changed state.
|
||||||
void SendFriendUpdate(const PlayerData& friendData, const PlayerData& playerData, uint8_t notifyType, uint8_t isBestFriend);
|
void SendFriendUpdate(const PlayerData& friendData, const PlayerData& playerData, uint8_t notifyType, uint8_t isBestFriend);
|
||||||
|
void SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode);
|
||||||
void SendFriendRequest(const PlayerData& receiver, const PlayerData& sender);
|
void SendFriendRequest(const PlayerData& receiver, const PlayerData& sender);
|
||||||
void SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
|
void SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
|
||||||
void SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful);
|
void SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "MessageType/World.h"
|
#include "MessageType/World.h"
|
||||||
#include "ChatIgnoreList.h"
|
#include "ChatIgnoreList.h"
|
||||||
#include "StringifiedEnum.h"
|
#include "StringifiedEnum.h"
|
||||||
|
#include "TeamContainer.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Server.h"
|
#include "Server.h"
|
||||||
@ -95,7 +96,7 @@ int main(int argc, char** argv) {
|
|||||||
// seyup the chat api web server
|
// seyup the chat api web server
|
||||||
bool web_server_enabled = Game::config->GetValue("web_server_enabled") == "1";
|
bool web_server_enabled = Game::config->GetValue("web_server_enabled") == "1";
|
||||||
ChatWebAPI chatwebapi;
|
ChatWebAPI chatwebapi;
|
||||||
if (web_server_enabled && !chatwebapi.Startup()){
|
if (web_server_enabled && !chatwebapi.Startup()) {
|
||||||
// if we want the web api and it fails to start, exit
|
// if we want the web api and it fails to start, exit
|
||||||
LOG("Failed to start web server, shutting down.");
|
LOG("Failed to start web server, shutting down.");
|
||||||
Database::Destroy("ChatServer");
|
Database::Destroy("ChatServer");
|
||||||
@ -197,6 +198,7 @@ int main(int argc, char** argv) {
|
|||||||
std::this_thread::sleep_until(t);
|
std::this_thread::sleep_until(t);
|
||||||
}
|
}
|
||||||
Game::playerContainer.Shutdown();
|
Game::playerContainer.Shutdown();
|
||||||
|
TeamContainer::Shutdown();
|
||||||
//Delete our objects here:
|
//Delete our objects here:
|
||||||
Database::Destroy("ChatServer");
|
Database::Destroy("ChatServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
@ -234,7 +236,7 @@ void HandlePacket(Packet* packet) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::CREATE_TEAM:
|
case MessageType::Chat::CREATE_TEAM:
|
||||||
Game::playerContainer.CreateTeamServer(packet);
|
TeamContainer::CreateTeamServer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::GET_FRIENDS_LIST:
|
case MessageType::Chat::GET_FRIENDS_LIST:
|
||||||
@ -254,7 +256,7 @@ void HandlePacket(Packet* packet) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::TEAM_GET_STATUS:
|
case MessageType::Chat::TEAM_GET_STATUS:
|
||||||
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
TeamContainer::HandleTeamStatusRequest(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::ADD_FRIEND_REQUEST:
|
case MessageType::Chat::ADD_FRIEND_REQUEST:
|
||||||
@ -284,27 +286,27 @@ void HandlePacket(Packet* packet) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::TEAM_INVITE:
|
case MessageType::Chat::TEAM_INVITE:
|
||||||
ChatPacketHandler::HandleTeamInvite(packet);
|
TeamContainer::HandleTeamInvite(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::TEAM_INVITE_RESPONSE:
|
case MessageType::Chat::TEAM_INVITE_RESPONSE:
|
||||||
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
TeamContainer::HandleTeamInviteResponse(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::TEAM_LEAVE:
|
case MessageType::Chat::TEAM_LEAVE:
|
||||||
ChatPacketHandler::HandleTeamLeave(packet);
|
TeamContainer::HandleTeamLeave(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::TEAM_SET_LEADER:
|
case MessageType::Chat::TEAM_SET_LEADER:
|
||||||
ChatPacketHandler::HandleTeamPromote(packet);
|
TeamContainer::HandleTeamPromote(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::TEAM_KICK:
|
case MessageType::Chat::TEAM_KICK:
|
||||||
ChatPacketHandler::HandleTeamKick(packet);
|
TeamContainer::HandleTeamKick(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageType::Chat::TEAM_SET_LOOT:
|
case MessageType::Chat::TEAM_SET_LOOT:
|
||||||
ChatPacketHandler::HandleTeamLootOption(packet);
|
TeamContainer::HandleTeamLootOption(packet);
|
||||||
break;
|
break;
|
||||||
case MessageType::Chat::GMLEVEL_UPDATE:
|
case MessageType::Chat::GMLEVEL_UPDATE:
|
||||||
ChatPacketHandler::HandleGMLevelUpdate(packet);
|
ChatPacketHandler::HandleGMLevelUpdate(packet);
|
||||||
|
@ -28,7 +28,7 @@ typedef struct mg_http_message mg_http_message;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char* json_content_type = "Content-Type: application/json\r\n";
|
const char* json_content_type = "Content-Type: application/json\r\n";
|
||||||
std::map<std::pair<eHTTPMethod, std::string>, WebAPIHTTPRoute> Routes {};
|
std::map<std::pair<eHTTPMethod, std::string>, WebAPIHTTPRoute> Routes{};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValidateAuthentication(const mg_http_message* http_msg) {
|
bool ValidateAuthentication(const mg_http_message* http_msg) {
|
||||||
@ -54,7 +54,7 @@ void HandlePlayersRequest(HTTPReply& reply, std::string body) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandleTeamsRequest(HTTPReply& reply, std::string body) {
|
void HandleTeamsRequest(HTTPReply& reply, std::string body) {
|
||||||
const json data = Game::playerContainer.GetTeamContainer();
|
const json data = TeamContainer::GetTeamContainer();
|
||||||
reply.status = data.empty() ? eHTTPStatusCode::NO_CONTENT : eHTTPStatusCode::OK;
|
reply.status = data.empty() ? eHTTPStatusCode::NO_CONTENT : eHTTPStatusCode::OK;
|
||||||
reply.message = data.empty() ? "{\"error\":\"No Teams Online\"}" : data.dump();
|
reply.message = data.empty() ? "{\"error\":\"No Teams Online\"}" : data.dump();
|
||||||
}
|
}
|
||||||
@ -87,12 +87,12 @@ void HandleInvalidRoute(HTTPReply& reply) {
|
|||||||
|
|
||||||
void HandleHTTPMessage(mg_connection* connection, const mg_http_message* http_msg) {
|
void HandleHTTPMessage(mg_connection* connection, const mg_http_message* http_msg) {
|
||||||
HTTPReply reply;
|
HTTPReply reply;
|
||||||
|
|
||||||
if (!http_msg) {
|
if (!http_msg) {
|
||||||
reply.status = eHTTPStatusCode::BAD_REQUEST;
|
reply.status = eHTTPStatusCode::BAD_REQUEST;
|
||||||
reply.message = "{\"error\":\"Invalid Request\"}";
|
reply.message = "{\"error\":\"Invalid Request\"}";
|
||||||
} else if (ValidateAuthentication(http_msg)) {
|
} else if (ValidateAuthentication(http_msg)) {
|
||||||
|
|
||||||
// convert method from cstring to std string
|
// convert method from cstring to std string
|
||||||
std::string method_string(http_msg->method.buf, http_msg->method.len);
|
std::string method_string(http_msg->method.buf, http_msg->method.len);
|
||||||
// get mehtod from mg to enum
|
// get mehtod from mg to enum
|
||||||
@ -105,8 +105,8 @@ void HandleHTTPMessage(mg_connection* connection, const mg_http_message* http_ms
|
|||||||
// convert body from cstring to std string
|
// convert body from cstring to std string
|
||||||
std::string body(http_msg->body.buf, http_msg->body.len);
|
std::string body(http_msg->body.buf, http_msg->body.len);
|
||||||
|
|
||||||
|
|
||||||
const auto routeItr = Routes.find({method, uri});
|
const auto routeItr = Routes.find({ method, uri });
|
||||||
|
|
||||||
if (routeItr != Routes.end()) {
|
if (routeItr != Routes.end()) {
|
||||||
const auto& [_, route] = *routeItr;
|
const auto& [_, route] = *routeItr;
|
||||||
@ -122,11 +122,11 @@ void HandleHTTPMessage(mg_connection* connection, const mg_http_message* http_ms
|
|||||||
|
|
||||||
void HandleRequests(mg_connection* connection, int request, void* request_data) {
|
void HandleRequests(mg_connection* connection, int request, void* request_data) {
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case MG_EV_HTTP_MSG:
|
case MG_EV_HTTP_MSG:
|
||||||
HandleHTTPMessage(connection, static_cast<mg_http_message*>(request_data));
|
HandleHTTPMessage(connection, static_cast<mg_http_message*>(request_data));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,19 +172,19 @@ bool ChatWebAPI::Startup() {
|
|||||||
.path = v1_route + "players",
|
.path = v1_route + "players",
|
||||||
.method = eHTTPMethod::GET,
|
.method = eHTTPMethod::GET,
|
||||||
.handle = HandlePlayersRequest
|
.handle = HandlePlayersRequest
|
||||||
});
|
});
|
||||||
|
|
||||||
RegisterHTTPRoutes({
|
RegisterHTTPRoutes({
|
||||||
.path = v1_route + "teams",
|
.path = v1_route + "teams",
|
||||||
.method = eHTTPMethod::GET,
|
.method = eHTTPMethod::GET,
|
||||||
.handle = HandleTeamsRequest
|
.handle = HandleTeamsRequest
|
||||||
});
|
});
|
||||||
|
|
||||||
RegisterHTTPRoutes({
|
RegisterHTTPRoutes({
|
||||||
.path = v1_route + "announce",
|
.path = v1_route + "announce",
|
||||||
.method = eHTTPMethod::POST,
|
.method = eHTTPMethod::POST,
|
||||||
.handle = HandleAnnounceRequest
|
.handle = HandleAnnounceRequest
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,19 +18,12 @@ void to_json(json& data, const PlayerData& playerData) {
|
|||||||
|
|
||||||
void to_json(json& data, const PlayerContainer& playerContainer) {
|
void to_json(json& data, const PlayerContainer& playerContainer) {
|
||||||
data = json::array();
|
data = json::array();
|
||||||
for(auto& playerData : playerContainer.GetAllPlayers()) {
|
for (auto& playerData : playerContainer.GetAllPlayers()) {
|
||||||
if (playerData.first == LWOOBJID_EMPTY) continue;
|
if (playerData.first == LWOOBJID_EMPTY) continue;
|
||||||
data.push_back(playerData.second);
|
data.push_back(playerData.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void to_json(json& data, const TeamContainer& teamContainer) {
|
|
||||||
for (auto& teamData : Game::playerContainer.GetTeams()) {
|
|
||||||
if (!teamData) continue;
|
|
||||||
data.push_back(*teamData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_json(json& data, const TeamData& teamData) {
|
void to_json(json& data, const TeamData& teamData) {
|
||||||
data["id"] = teamData.teamID;
|
data["id"] = teamData.teamID;
|
||||||
data["loot_flag"] = teamData.lootFlag;
|
data["loot_flag"] = teamData.lootFlag;
|
||||||
@ -48,6 +41,13 @@ void to_json(json& data, const TeamData& teamData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TeamContainer::to_json(json& data, const TeamContainer::Data& teamContainer) {
|
||||||
|
for (auto& teamData : TeamContainer::GetTeams()) {
|
||||||
|
if (!teamData) continue;
|
||||||
|
data.push_back(*teamData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string JSONUtils::CheckRequiredData(const json& data, const std::vector<std::string>& requiredData) {
|
std::string JSONUtils::CheckRequiredData(const json& data, const std::vector<std::string>& requiredData) {
|
||||||
json check;
|
json check;
|
||||||
check["error"] = json::array();
|
check["error"] = json::array();
|
||||||
|
@ -3,12 +3,18 @@
|
|||||||
|
|
||||||
#include "json_fwd.hpp"
|
#include "json_fwd.hpp"
|
||||||
#include "PlayerContainer.h"
|
#include "PlayerContainer.h"
|
||||||
|
#include "TeamContainer.h"
|
||||||
|
|
||||||
|
/* Remember, to_json needs to be in the same namespace as the class its located in */
|
||||||
|
|
||||||
void to_json(nlohmann::json& data, const PlayerData& playerData);
|
void to_json(nlohmann::json& data, const PlayerData& playerData);
|
||||||
void to_json(nlohmann::json& data, const PlayerContainer& playerContainer);
|
void to_json(nlohmann::json& data, const PlayerContainer& playerContainer);
|
||||||
void to_json(nlohmann::json& data, const TeamContainer& teamData);
|
|
||||||
void to_json(nlohmann::json& data, const TeamData& teamData);
|
void to_json(nlohmann::json& data, const TeamData& teamData);
|
||||||
|
|
||||||
|
namespace TeamContainer {
|
||||||
|
void to_json(nlohmann::json& data, const TeamContainer::Data& teamData);
|
||||||
|
};
|
||||||
|
|
||||||
namespace JSONUtils {
|
namespace JSONUtils {
|
||||||
// check required data for reqeust
|
// check required data for reqeust
|
||||||
std::string CheckRequiredData(const nlohmann::json& data, const std::vector<std::string>& requiredData);
|
std::string CheckRequiredData(const nlohmann::json& data, const std::vector<std::string>& requiredData);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "ChatPackets.h"
|
#include "ChatPackets.h"
|
||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
#include "MessageType/Chat.h"
|
#include "MessageType/Chat.h"
|
||||||
|
#include "TeamContainer.h"
|
||||||
|
|
||||||
void PlayerContainer::Initialize() {
|
void PlayerContainer::Initialize() {
|
||||||
m_MaxNumberOfBestFriends =
|
m_MaxNumberOfBestFriends =
|
||||||
@ -99,7 +100,7 @@ void PlayerContainer::RemovePlayer(const LWOOBJID playerID) {
|
|||||||
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0, fr.isBestFriend);
|
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0, fr.isBestFriend);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* team = GetTeam(playerID);
|
auto* team = TeamContainer::GetTeam(playerID);
|
||||||
|
|
||||||
if (team != nullptr) {
|
if (team != nullptr) {
|
||||||
const auto memberName = GeneralUtils::UTF8ToUTF16(player.playerName);
|
const auto memberName = GeneralUtils::UTF8ToUTF16(player.playerName);
|
||||||
@ -109,7 +110,7 @@ void PlayerContainer::RemovePlayer(const LWOOBJID playerID) {
|
|||||||
|
|
||||||
if (!otherMember) continue;
|
if (!otherMember) continue;
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
|
TeamContainer::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,40 +141,6 @@ void PlayerContainer::MuteUpdate(Packet* packet) {
|
|||||||
BroadcastMuteUpdate(playerID, expire);
|
BroadcastMuteUpdate(playerID, expire);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_MUTE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_MUTE);
|
||||||
@ -184,218 +151,6 @@ void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
|||||||
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TeamData* PlayerContainer::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* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) {
|
|
||||||
auto* team = new TeamData();
|
|
||||||
|
|
||||||
team->teamID = ++m_TeamIDCounter;
|
|
||||||
team->leaderID = leader;
|
|
||||||
team->local = local;
|
|
||||||
|
|
||||||
GetTeamsMut().push_back(team);
|
|
||||||
|
|
||||||
AddMember(team, leader);
|
|
||||||
|
|
||||||
return team;
|
|
||||||
}
|
|
||||||
|
|
||||||
TeamData* PlayerContainer::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 PlayerContainer::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 = 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 = GetPlayerData(team->leaderID);
|
|
||||||
const auto& member = GetPlayerData(playerID);
|
|
||||||
|
|
||||||
if (!leader || !member) return;
|
|
||||||
|
|
||||||
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader.playerName);
|
|
||||||
const auto memberName = GeneralUtils::UTF8ToUTF16(member.playerName);
|
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamInviteConfirm(member, false, leader.playerID, leader.zoneID, team->lootFlag, 0, 0, leaderName);
|
|
||||||
|
|
||||||
if (!team->local) {
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(member, leader.playerID);
|
|
||||||
} else {
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateTeamsOnWorld(team, false);
|
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs) {
|
|
||||||
const auto& otherMember = GetPlayerData(memberId);
|
|
||||||
|
|
||||||
if (otherMember == member) continue;
|
|
||||||
|
|
||||||
const auto otherMemberName = GetName(memberId);
|
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember ? otherMember.zoneID : LWOZONEID(0, 0, 0));
|
|
||||||
|
|
||||||
if (otherMember) {
|
|
||||||
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member.playerID, memberName, member.zoneID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
team->memberIDs.erase(index);
|
|
||||||
|
|
||||||
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, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) {
|
|
||||||
team->leaderID = newLeader;
|
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs) {
|
|
||||||
const auto& otherMember = GetPlayerData(memberId);
|
|
||||||
|
|
||||||
if (!otherMember) continue;
|
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(otherMember, newLeader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
|
|
||||||
ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, causingPlayerID, causingPlayerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateTeamsOnWorld(team, true);
|
|
||||||
|
|
||||||
GetTeamsMut().erase(index);
|
|
||||||
|
|
||||||
delete team;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
|
||||||
const auto index = std::find(GetTeams().begin(), GetTeams().end(), team);
|
|
||||||
|
|
||||||
if (index == GetTeams().end()) return;
|
|
||||||
|
|
||||||
const auto& leader = GetPlayerData(team->leaderID);
|
|
||||||
|
|
||||||
if (!leader) return;
|
|
||||||
|
|
||||||
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader.playerName);
|
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs) {
|
|
||||||
const auto& otherMember = GetPlayerData(memberId);
|
|
||||||
|
|
||||||
if (!otherMember) continue;
|
|
||||||
|
|
||||||
if (!team->local) {
|
|
||||||
ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader.zoneID, team->lootFlag, 0, leaderName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateTeamsOnWorld(team, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerContainer::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);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
|
std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
|
||||||
const auto iter = m_Names.find(playerID);
|
const auto iter = m_Names.find(playerID);
|
||||||
|
|
||||||
@ -444,5 +199,4 @@ void PlayerContainer::Shutdown() {
|
|||||||
Database::Get()->UpdateActivityLog(id, eActivityType::PlayerLoggedOut, playerData.zoneID.GetMapID());
|
Database::Get()->UpdateActivityLog(id, eActivityType::PlayerLoggedOut, playerData.zoneID.GetMapID());
|
||||||
m_Players.erase(m_Players.begin());
|
m_Players.erase(m_Players.begin());
|
||||||
}
|
}
|
||||||
for (auto* team : GetTeams()) if (team) delete team;
|
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,6 @@ enum class eGameMasterLevel : uint8_t;
|
|||||||
|
|
||||||
struct TeamData;
|
struct TeamData;
|
||||||
|
|
||||||
struct TeamContainer {
|
|
||||||
std::vector<TeamData*> mTeams;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IgnoreData {
|
struct IgnoreData {
|
||||||
IgnoreData(const std::string& name, const LWOOBJID& id) : playerName{ name }, playerId{ id } {}
|
IgnoreData(const std::string& name, const LWOOBJID& id) : playerName{ name }, playerId{ id } {}
|
||||||
inline bool operator==(const std::string& other) const noexcept {
|
inline bool operator==(const std::string& other) const noexcept {
|
||||||
@ -73,7 +69,6 @@ public:
|
|||||||
void ScheduleRemovePlayer(Packet* packet);
|
void ScheduleRemovePlayer(Packet* packet);
|
||||||
void RemovePlayer(const LWOOBJID playerID);
|
void RemovePlayer(const LWOOBJID playerID);
|
||||||
void MuteUpdate(Packet* packet);
|
void MuteUpdate(Packet* packet);
|
||||||
void CreateTeamServer(Packet* packet);
|
|
||||||
void BroadcastMuteUpdate(LWOOBJID player, time_t time);
|
void BroadcastMuteUpdate(LWOOBJID player, time_t time);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
@ -81,34 +76,19 @@ public:
|
|||||||
const PlayerData& GetPlayerData(const std::string& playerName);
|
const PlayerData& GetPlayerData(const std::string& playerName);
|
||||||
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
||||||
PlayerData& GetPlayerDataMutable(const std::string& playerName);
|
PlayerData& GetPlayerDataMutable(const std::string& playerName);
|
||||||
|
std::u16string GetName(LWOOBJID playerID);
|
||||||
|
LWOOBJID GetId(const std::u16string& playerName);
|
||||||
|
void Update(const float deltaTime);
|
||||||
|
|
||||||
uint32_t GetPlayerCount() { return m_PlayerCount; };
|
uint32_t GetPlayerCount() { return m_PlayerCount; };
|
||||||
uint32_t GetSimCount() { return m_SimCount; };
|
uint32_t GetSimCount() { return m_SimCount; };
|
||||||
const std::map<LWOOBJID, PlayerData>& GetAllPlayers() const { return m_Players; };
|
const std::map<LWOOBJID, PlayerData>& GetAllPlayers() const { return m_Players; };
|
||||||
|
|
||||||
TeamData* CreateLocalTeam(std::vector<LWOOBJID> members);
|
|
||||||
TeamData* CreateTeam(LWOOBJID leader, bool local = false);
|
|
||||||
TeamData* GetTeam(LWOOBJID playerID);
|
|
||||||
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, const LWOOBJID causingPlayerID, const std::u16string& causingPlayerName);
|
|
||||||
void TeamStatusUpdate(TeamData* team);
|
|
||||||
void UpdateTeamsOnWorld(TeamData* team, bool deleteTeam);
|
|
||||||
std::u16string GetName(LWOOBJID playerID);
|
|
||||||
LWOOBJID GetId(const std::u16string& playerName);
|
|
||||||
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
|
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
|
||||||
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
|
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
|
||||||
const TeamContainer& GetTeamContainer() { return m_TeamContainer; }
|
|
||||||
std::vector<TeamData*>& GetTeamsMut() { return m_TeamContainer.mTeams; };
|
|
||||||
const std::vector<TeamData*>& GetTeams() { return GetTeamsMut(); };
|
|
||||||
|
|
||||||
void Update(const float deltaTime);
|
|
||||||
bool PlayerBeingRemoved(const LWOOBJID playerID) { return m_PlayersToRemove.contains(playerID); }
|
bool PlayerBeingRemoved(const LWOOBJID playerID) { return m_PlayersToRemove.contains(playerID); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LWOOBJID m_TeamIDCounter = 0;
|
|
||||||
std::map<LWOOBJID, PlayerData> m_Players;
|
std::map<LWOOBJID, PlayerData> m_Players;
|
||||||
TeamContainer m_TeamContainer{};
|
|
||||||
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
||||||
std::map<LWOOBJID, float> m_PlayersToRemove;
|
std::map<LWOOBJID, float> m_PlayersToRemove;
|
||||||
uint32_t m_MaxNumberOfBestFriends = 5;
|
uint32_t m_MaxNumberOfBestFriends = 5;
|
||||||
|
669
dChatServer/TeamContainer.cpp
Normal file
669
dChatServer/TeamContainer.cpp
Normal file
@ -0,0 +1,669 @@
|
|||||||
|
#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);
|
||||||
|
}
|
59
dChatServer/TeamContainer.h
Normal file
59
dChatServer/TeamContainer.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Darkflame Universe
|
||||||
|
// Copyright 2025
|
||||||
|
|
||||||
|
#ifndef TEAMCONTAINER_H
|
||||||
|
#define TEAMCONTAINER_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "dCommonVars.h"
|
||||||
|
|
||||||
|
struct Packet;
|
||||||
|
struct PlayerData;
|
||||||
|
struct TeamData;
|
||||||
|
|
||||||
|
namespace TeamContainer {
|
||||||
|
struct Data {
|
||||||
|
std::vector<TeamData*> mTeams;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void HandleTeamInvite(Packet* packet);
|
||||||
|
void HandleTeamInviteResponse(Packet* packet);
|
||||||
|
void HandleTeamLeave(Packet* packet);
|
||||||
|
void HandleTeamKick(Packet* packet);
|
||||||
|
void HandleTeamPromote(Packet* packet);
|
||||||
|
void HandleTeamLootOption(Packet* packet);
|
||||||
|
void HandleTeamStatusRequest(Packet* packet);
|
||||||
|
|
||||||
|
void SendTeamInvite(const PlayerData& receiver, const PlayerData& sender);
|
||||||
|
void SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName);
|
||||||
|
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);
|
||||||
|
|
||||||
|
void CreateTeamServer(Packet* packet);
|
||||||
|
|
||||||
|
TeamData* CreateLocalTeam(std::vector<LWOOBJID> members);
|
||||||
|
TeamData* CreateTeam(LWOOBJID leader, bool local = false);
|
||||||
|
TeamData* GetTeam(LWOOBJID playerID);
|
||||||
|
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, const LWOOBJID causingPlayerID, const std::u16string& causingPlayerName);
|
||||||
|
void TeamStatusUpdate(TeamData* team);
|
||||||
|
void UpdateTeamsOnWorld(TeamData* team, bool deleteTeam);
|
||||||
|
|
||||||
|
const TeamContainer::Data& GetTeamContainer();
|
||||||
|
std::vector<TeamData*>& GetTeamsMut();
|
||||||
|
const std::vector<TeamData*>& GetTeams();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!TEAMCONTAINER_H
|
Loading…
x
Reference in New Issue
Block a user