diff --git a/dChatServer/ChatPacketHandler.cpp b/dChatServer/ChatPacketHandler.cpp index 4bdddd68..5e2e58d7 100644 --- a/dChatServer/ChatPacketHandler.cpp +++ b/dChatServer/ChatPacketHandler.cpp @@ -2,7 +2,6 @@ #include "PlayerContainer.h" #include "Database.h" #include -#include "PacketUtils.h" #include "BitStreamUtils.h" #include "Game.h" #include "dServer.h" @@ -18,6 +17,8 @@ #include "eChatInternalMessageType.h" #include "eClientMessageType.h" #include "eGameMessageType.h" +#include "StringifiedEnum.h" +#include "eGameMasterLevel.h" void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { //Get from the packet which player we want to do something with: @@ -78,31 +79,27 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { void ChatPacketHandler::HandleFriendRequest(Packet* packet) { CINSTREAM_SKIP_HEADER; + LWOOBJID requestorPlayerID; - inStream.Read(requestorPlayerID); - uint32_t spacing{}; - inStream.Read(spacing); - std::string playerName = ""; - uint16_t character; - bool noMoreLettersInName = false; - - for (uint32_t j = 0; j < 33; j++) { - inStream.Read(character); - if (character == '\0') noMoreLettersInName = true; - if (!noMoreLettersInName) playerName.push_back(static_cast(character)); - } - + LUWString LUplayerName; char isBestFriendRequest{}; + + inStream.Read(requestorPlayerID); + inStream.IgnoreBytes(4); + inStream.Read(LUplayerName); inStream.Read(isBestFriendRequest); + auto playerName = LUplayerName.GetAsString(); + auto& requestor = Game::playerContainer.GetPlayerDataMutable(requestorPlayerID); if (!requestor) { LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str()); return; } + // you cannot friend yourself if (requestor.playerName == playerName) { - SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN); + SendFriendResponse(requestor, requestor, eAddFriendResponseType::GENERALERROR); return; }; @@ -141,6 +138,13 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) { return; } + // Prevent GM friend spam + // If the player we are trying to be friends with is not a civilian and we are a civilian, abort the process + if (requestee.gmLevel > eGameMasterLevel::CIVILIAN && requestor.gmLevel == eGameMasterLevel::CIVILIAN ) { + SendFriendResponse(requestor, requestee, eAddFriendResponseType::MYTHRAN); + return; + } + if (isBestFriendRequest) { uint8_t oldBestFriendStatus{}; @@ -218,15 +222,19 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) { void ChatPacketHandler::HandleFriendResponse(Packet* packet) { CINSTREAM_SKIP_HEADER; - LWOOBJID playerID; - inStream.Read(playerID); - eAddFriendResponseCode clientResponseCode = static_cast(packet->data[0x14]); - std::string friendName = PacketUtils::ReadString(0x15, packet, true); + LWOOBJID playerID; + eAddFriendResponseCode clientResponseCode; + LUWString friendName; + + inStream.Read(playerID); + inStream.IgnoreBytes(4); + inStream.Read(clientResponseCode); + inStream.Read(friendName); //Now to try and find both of these: auto& requestor = Game::playerContainer.GetPlayerDataMutable(playerID); - auto& requestee = Game::playerContainer.GetPlayerDataMutable(friendName); + auto& requestee = Game::playerContainer.GetPlayerDataMutable(friendName.GetAsString()); if (!requestor || !requestee) return; eAddFriendResponseType serverResponseCode{}; @@ -288,8 +296,11 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) { void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { CINSTREAM_SKIP_HEADER; LWOOBJID playerID; + LUWString LUFriendName; inStream.Read(playerID); - std::string friendName = PacketUtils::ReadString(0x14, packet, true); + inStream.IgnoreBytes(4); + inStream.Read(LUFriendName); + auto friendName = LUFriendName.GetAsString(); //we'll have to query the db here to find the user, since you can delete them while they're offline. //First, we need to find their ID: @@ -335,123 +346,144 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { SendRemoveFriend(goonB, goonAName, true); } -void ChatPacketHandler::HandleChatMessage(Packet* packet) { - CINSTREAM_SKIP_HEADER; - LWOOBJID playerID = LWOOBJID_EMPTY; - inStream.Read(playerID); - - const auto& sender = Game::playerContainer.GetPlayerData(playerID); - - if (!sender) return; - - if (sender.GetIsMuted()) return; - - inStream.SetReadOffset(0x14 * 8); - - uint8_t channel = 0; - inStream.Read(channel); - - std::string message = PacketUtils::ReadString(0x66, packet, true, 512); - - LOG("Got a message from (%s) [%d]: %s", sender.playerName.c_str(), channel, message.c_str()); - - if (channel != 8) return; - - auto* team = Game::playerContainer.GetTeam(playerID); - - if (team == nullptr) return; - - for (const auto memberId : team->memberIDs) { - const auto& otherMember = Game::playerContainer.GetPlayerData(memberId); - - if (!otherMember) return; - - CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); - bitStream.Write(otherMember.playerID); - - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); - bitStream.Write(otherMember.playerID); - bitStream.Write(8); - bitStream.Write(69); - bitStream.Write(LUWString(sender.playerName)); - bitStream.Write(sender.playerID); - bitStream.Write(0); - bitStream.Write(0); //not mythran nametag - bitStream.Write(LUWString(otherMember.playerName)); - bitStream.Write(0); //not mythran for receiver - bitStream.Write(0); //teams? - bitStream.Write(LUWString(message, 512)); - - SystemAddress sysAddr = otherMember.sysAddr; - SEND_PACKET; - } -} - -void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { - LWOOBJID senderID = PacketUtils::ReadS64(0x08, packet); - std::string receiverName = PacketUtils::ReadString(0x66, packet, true); - std::string message = PacketUtils::ReadString(0xAA, packet, true, 512); - - //Get the bois: - const auto& goonA = Game::playerContainer.GetPlayerData(senderID); - const auto& goonB = Game::playerContainer.GetPlayerData(receiverName); - if (!goonA || !goonB) return; - - if (goonA.GetIsMuted()) return; - - //To the sender: - { - CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); - bitStream.Write(goonA.playerID); - - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); - bitStream.Write(goonA.playerID); - bitStream.Write(7); - bitStream.Write(69); - bitStream.Write(LUWString(goonA.playerName)); - bitStream.Write(goonA.playerID); - bitStream.Write(0); - bitStream.Write(0); //not mythran nametag - bitStream.Write(LUWString(goonB.playerName)); - bitStream.Write(0); //not mythran for receiver - bitStream.Write(0); //success - bitStream.Write(LUWString(message, 512)); - - SystemAddress sysAddr = goonA.sysAddr; - SEND_PACKET; - } - - //To the receiver: - { - CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); - bitStream.Write(goonB.playerID); - - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); - bitStream.Write(goonA.playerID); - bitStream.Write(7); - bitStream.Write(69); - bitStream.Write(LUWString(goonA.playerName)); - bitStream.Write(goonA.playerID); - bitStream.Write(0); - bitStream.Write(0); //not mythran nametag - bitStream.Write(LUWString(goonB.playerName)); - bitStream.Write(0); //not mythran for receiver - bitStream.Write(3); //new whisper - bitStream.Write(LUWString(message, 512)); - - SystemAddress sysAddr = goonB.sysAddr; - SEND_PACKET; - } -} - -void ChatPacketHandler::HandleTeamInvite(Packet* packet) { +void ChatPacketHandler::HandleGMLevelUpdate(Packet* packet) { CINSTREAM_SKIP_HEADER; LWOOBJID playerID; inStream.Read(playerID); - std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true); + auto& player = Game::playerContainer.GetPlayerData(playerID); + if (!player) return; + inStream.Read(player.gmLevel); +} + +// the structure the client uses to send this packet is shared in many chat messages +// that are sent to the server. Because of this, there are large gaps of unused data in chat messages +void ChatPacketHandler::HandleChatMessage(Packet* packet) { + CINSTREAM_SKIP_HEADER; + LWOOBJID playerID; + inStream.Read(playerID); + + const auto& sender = Game::playerContainer.GetPlayerData(playerID); + if (!sender || sender.GetIsMuted()) return; + + eChatChannel channel; + uint32_t size; + + inStream.IgnoreBytes(4); + inStream.Read(channel); + inStream.Read(size); + inStream.IgnoreBytes(77); + + LUWString message(size); + inStream.Read(message); + + LOG("Got a message from (%s) via [%s]: %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str()); + + switch (channel) { + case eChatChannel::TEAM: { + auto* team = Game::playerContainer.GetTeam(playerID); + if (team == nullptr) return; + + for (const auto memberId : team->memberIDs) { + const auto& otherMember = Game::playerContainer.GetPlayerData(memberId); + if (!otherMember) return; + SendPrivateChatMessage(sender, otherMember, otherMember, message, eChatChannel::TEAM, eChatMessageResponseCode::SENT); + } + break; + } + default: + LOG("Unhandled Chat channel [%s]", StringifiedEnum::ToString(channel).data()); + break; + } +} + +// the structure the client uses to send this packet is shared in many chat messages +// that are sent to the server. Because of this, there are large gaps of unused data in chat messages +void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { + CINSTREAM_SKIP_HEADER; + LWOOBJID playerID; + inStream.Read(playerID); + + const auto& sender = Game::playerContainer.GetPlayerData(playerID); + if (!sender || sender.GetIsMuted()) return; + + eChatChannel channel; + uint32_t size; + LUWString LUReceiverName; + + inStream.IgnoreBytes(4); + inStream.Read(channel); + if (channel != eChatChannel::PRIVATE_CHAT) LOG("WARNING: Received Private chat with the wrong channel!"); + + inStream.Read(size); + inStream.IgnoreBytes(77); + + inStream.Read(LUReceiverName); + auto receiverName = LUReceiverName.GetAsString(); + inStream.IgnoreBytes(2); + + LUWString message(size); + inStream.Read(message); + + LOG("Got a message from (%s) via [%s]: %s to %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str(), receiverName.c_str()); + + const auto& receiver = Game::playerContainer.GetPlayerData(receiverName); + if (!receiver) { + PlayerData otherPlayer; + otherPlayer.playerName = receiverName; + auto responseType = Database::Get()->GetCharacterInfo(receiverName) + ? eChatMessageResponseCode::NOTONLINE + : eChatMessageResponseCode::GENERALERROR; + + SendPrivateChatMessage(sender, otherPlayer, sender, message, eChatChannel::GENERAL, responseType); + return; + } + + // Check to see if they are friends + // only freinds can whispr each other + for (const auto& fr : receiver.friends) { + if (fr.friendID == sender.playerID) { + //To the sender: + SendPrivateChatMessage(sender, receiver, sender, message, eChatChannel::PRIVATE_CHAT, eChatMessageResponseCode::SENT); + //To the receiver: + SendPrivateChatMessage(sender, receiver, receiver, message, eChatChannel::PRIVATE_CHAT, eChatMessageResponseCode::RECEIVEDNEWWHISPER); + return; + } + } + SendPrivateChatMessage(sender, receiver, sender, message, eChatChannel::GENERAL, eChatMessageResponseCode::NOTFRIENDS); +} + +void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) { + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + bitStream.Write(routeTo.playerID); + + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); + bitStream.Write(sender.playerID); + bitStream.Write(channel); + bitStream.Write(0); // not used + bitStream.Write(LUWString(sender.playerName)); + bitStream.Write(sender.playerID); + bitStream.Write(0); // sourceID + bitStream.Write(sender.gmLevel); + bitStream.Write(LUWString(receiver.playerName)); + bitStream.Write(receiver.gmLevel); + bitStream.Write(responseCode); + bitStream.Write(message); + + SystemAddress sysAddr = routeTo.sysAddr; + 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); @@ -463,7 +495,7 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) { team = Game::playerContainer.CreateTeam(playerID); } - const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer); + const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer.GetAsString()); if (!other) return; @@ -480,7 +512,7 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) { SendTeamInvite(other, player); - LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.c_str()); + LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.GetAsString().c_str()); } void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) { @@ -534,21 +566,25 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) { void ChatPacketHandler::HandleTeamKick(Packet* packet) { CINSTREAM_SKIP_HEADER; + LWOOBJID playerID = LWOOBJID_EMPTY; + LUWString kickedPlayer; + inStream.Read(playerID); + inStream.IgnoreBytes(4); + inStream.Read(kickedPlayer); - std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true); - LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str()); + LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.GetAsString().c_str()); - const auto& kicked = Game::playerContainer.GetPlayerData(kickedPlayer); + const auto& kicked = Game::playerContainer.GetPlayerData(kickedPlayer.GetAsString()); LWOOBJID kickedId = LWOOBJID_EMPTY; if (kicked) { kickedId = kicked.playerID; } else { - kickedId = Game::playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer)); + kickedId = Game::playerContainer.GetId(kickedPlayer.string); } if (kickedId == LWOOBJID_EMPTY) return; @@ -564,14 +600,17 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) { void ChatPacketHandler::HandleTeamPromote(Packet* packet) { CINSTREAM_SKIP_HEADER; + LWOOBJID playerID = LWOOBJID_EMPTY; + LUWString promotedPlayer; + inStream.Read(playerID); + inStream.IgnoreBytes(4); + inStream.Read(promotedPlayer); - std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true); + LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.GetAsString().c_str()); - LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str()); - - const auto& promoted = Game::playerContainer.GetPlayerData(promotedPlayer); + const auto& promoted = Game::playerContainer.GetPlayerData(promotedPlayer.GetAsString()); if (!promoted) return; diff --git a/dChatServer/ChatPacketHandler.h b/dChatServer/ChatPacketHandler.h index 6c9c2de6..847fc899 100644 --- a/dChatServer/ChatPacketHandler.h +++ b/dChatServer/ChatPacketHandler.h @@ -7,14 +7,53 @@ struct PlayerData; enum class eAddFriendResponseType : uint8_t; +enum class eChatChannel : uint8_t { + SYSTEMNOTIFY = 0, + SYSTEMWARNING, + SYSTEMERROR, + BROADCAST, + LOCAL, + LOCALNOANIM, + EMOTE, + PRIVATE_CHAT, + TEAM, + TEAMLOCAL, + GUILD, + GUILDNOTIFY, + PROPERTY, + ADMIN, + COMBATDAMAGE, + COMBATHEALING, + COMBATLOOT, + COMBATEXP, + COMBATDEATH, + GENERAL, + TRADE, + LFG, + USER +}; + + +enum class eChatMessageResponseCode : uint8_t { + SENT = 0, + NOTONLINE, + GENERALERROR, + RECEIVEDNEWWHISPER, + NOTFRIENDS, + SENDERFREETRIAL, + RECEIVERFREETRIAL, +}; + namespace ChatPacketHandler { void HandleFriendlistRequest(Packet* packet); void HandleFriendRequest(Packet* packet); void HandleFriendResponse(Packet* packet); void HandleRemoveFriend(Packet* packet); + void HandleGMLevelUpdate(Packet* packet); void HandleChatMessage(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); diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index 8ab66d73..d04cbd01 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -20,6 +20,7 @@ #include "eChatInternalMessageType.h" #include "eWorldMessageType.h" #include "ChatIgnoreList.h" +#include "StringifiedEnum.h" #include "Game.h" #include "Server.h" @@ -223,7 +224,8 @@ void HandlePacket(Packet* packet) { } if (static_cast(packet->data[1]) == eConnectionType::CHAT) { - switch (static_cast(packet->data[3])) { + eChatMessageType chat_message_type = static_cast(packet->data[3]); + switch (chat_message_type) { case eChatMessageType::GET_FRIENDS_LIST: ChatPacketHandler::HandleFriendlistRequest(packet); break; @@ -293,9 +295,61 @@ void HandlePacket(Packet* packet) { case eChatMessageType::TEAM_SET_LOOT: ChatPacketHandler::HandleTeamLootOption(packet); break; - + case eChatMessageType::GMLEVEL_UPDATE: + ChatPacketHandler::HandleGMLevelUpdate(packet); + break; + case eChatMessageType::LOGIN_SESSION_NOTIFY: + case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE: + case eChatMessageType::WORLD_DISCONNECT_REQUEST: + case eChatMessageType::WORLD_PROXIMITY_RESPONSE: + case eChatMessageType::WORLD_PARCEL_RESPONSE: + case eChatMessageType::TEAM_MISSED_INVITE_CHECK: + case eChatMessageType::GUILD_CREATE: + case eChatMessageType::GUILD_INVITE: + case eChatMessageType::GUILD_INVITE_RESPONSE: + case eChatMessageType::GUILD_LEAVE: + case eChatMessageType::GUILD_KICK: + case eChatMessageType::GUILD_GET_STATUS: + case eChatMessageType::GUILD_GET_ALL: + case eChatMessageType::SHOW_ALL: + case eChatMessageType::BLUEPRINT_MODERATED: + case eChatMessageType::BLUEPRINT_MODEL_READY: + case eChatMessageType::PROPERTY_READY_FOR_APPROVAL: + case eChatMessageType::PROPERTY_MODERATION_CHANGED: + case eChatMessageType::PROPERTY_BUILDMODE_CHANGED: + case eChatMessageType::PROPERTY_BUILDMODE_CHANGED_REPORT: + case eChatMessageType::MAIL: + case eChatMessageType::WORLD_INSTANCE_LOCATION_REQUEST: + case eChatMessageType::REPUTATION_UPDATE: + case eChatMessageType::SEND_CANNED_TEXT: + case eChatMessageType::CHARACTER_NAME_CHANGE_REQUEST: + case eChatMessageType::CSR_REQUEST: + case eChatMessageType::CSR_REPLY: + case eChatMessageType::GM_KICK: + case eChatMessageType::GM_ANNOUNCE: + case eChatMessageType::WORLD_ROUTE_PACKET: + case eChatMessageType::GET_ZONE_POPULATIONS: + case eChatMessageType::REQUEST_MINIMUM_CHAT_MODE: + case eChatMessageType::MATCH_REQUEST: + case eChatMessageType::UGCMANIFEST_REPORT_MISSING_FILE: + case eChatMessageType::UGCMANIFEST_REPORT_DONE_FILE: + case eChatMessageType::UGCMANIFEST_REPORT_DONE_BLUEPRINT: + case eChatMessageType::UGCC_REQUEST: + case eChatMessageType::WHO: + case eChatMessageType::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE: + case eChatMessageType::ACHIEVEMENT_NOTIFY: + case eChatMessageType::GM_CLOSE_PRIVATE_CHAT_WINDOW: + case eChatMessageType::UNEXPECTED_DISCONNECT: + case eChatMessageType::PLAYER_READY: + case eChatMessageType::GET_DONATION_TOTAL: + case eChatMessageType::UPDATE_DONATION: + case eChatMessageType::PRG_CSR_COMMAND: + case eChatMessageType::HEARTBEAT_REQUEST_FROM_WORLD: + case eChatMessageType::UPDATE_FREE_TRIAL_STATUS: + LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chat_message_type).data(), chat_message_type); + break; default: - LOG("Unknown CHAT id: %i", int(packet->data[3])); + LOG("Unknown CHAT Message id: %i", chat_message_type); } } diff --git a/dChatServer/PlayerContainer.cpp b/dChatServer/PlayerContainer.cpp index 242ccad1..969f5c2e 100644 --- a/dChatServer/PlayerContainer.cpp +++ b/dChatServer/PlayerContainer.cpp @@ -10,6 +10,7 @@ #include "Database.h" #include "eConnectionType.h" #include "eChatInternalMessageType.h" +#include "eGameMasterLevel.h" #include "ChatPackets.h" #include "dConfig.h" @@ -22,6 +23,10 @@ PlayerContainer::~PlayerContainer() { m_Players.clear(); } +PlayerData::PlayerData() { + gmLevel == eGameMasterLevel::CIVILIAN; +} + TeamData::TeamData() { lootFlag = Game::config->GetValue("default_team_loot") == "0" ? 0 : 1; } @@ -47,6 +52,7 @@ void PlayerContainer::InsertPlayer(Packet* packet) { inStream.Read(data.zoneID); inStream.Read(data.muteExpire); + inStream.Read(data.gmLevel); data.sysAddr = packet->systemAddress; m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName); diff --git a/dChatServer/PlayerContainer.h b/dChatServer/PlayerContainer.h index 3cacc62d..f34b1e54 100644 --- a/dChatServer/PlayerContainer.h +++ b/dChatServer/PlayerContainer.h @@ -7,6 +7,8 @@ #include "dServer.h" #include +enum class eGameMasterLevel : uint8_t; + struct IgnoreData { IgnoreData(const std::string& name, const LWOOBJID& id) : playerName(name), playerId(id) {} inline bool operator==(const std::string& other) const noexcept { @@ -22,6 +24,7 @@ struct IgnoreData { }; struct PlayerData { + PlayerData(); operator bool() const noexcept { return playerID != LWOOBJID_EMPTY; } @@ -42,6 +45,8 @@ struct PlayerData { std::string playerName; std::vector friends; std::vector ignoredPlayers; + eGameMasterLevel gmLevel; + bool isFTP = false; }; struct TeamData { diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index cdd94671..ddfaa2fc 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -25,6 +25,7 @@ #include "eTriggerEventType.h" #include "eObjectBits.h" #include "PositionUpdate.h" +#include "eChatMessageType.h" //Component includes: #include "Component.h" @@ -858,9 +859,20 @@ void Entity::SetGMLevel(eGameMasterLevel value) { } CharacterComponent* character = GetComponent(); - if (character) character->SetGMLevel(value); + if (!character) return; + character->SetGMLevel(value); GameMessages::SendGMLevelBroadcast(m_ObjectID, value); + + // Update the chat server of our GM Level + { + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GMLEVEL_UPDATE); + bitStream.Write(m_ObjectID); + bitStream.Write(m_GMLevel); + + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } } void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType) { diff --git a/dNet/PacketUtils.cpp b/dNet/PacketUtils.cpp index 95c3b2b1..5394cff0 100644 --- a/dNet/PacketUtils.cpp +++ b/dNet/PacketUtils.cpp @@ -1,64 +1,8 @@ #include "PacketUtils.h" -#include #include #include "Logger.h" #include "Game.h" -uint16_t PacketUtils::ReadU16(uint32_t startLoc, Packet* packet) { - if (startLoc + 2 > packet->length) return 0; - - std::vector t; - for (uint32_t i = startLoc; i < startLoc + 2; i++) t.push_back(packet->data[i]); - return *(uint16_t*)t.data(); -} - -uint32_t PacketUtils::ReadU32(uint32_t startLoc, Packet* packet) { - if (startLoc + 4 > packet->length) return 0; - - std::vector t; - for (uint32_t i = startLoc; i < startLoc + 4; i++) { - t.push_back(packet->data[i]); - } - return *(uint32_t*)t.data(); -} - -uint64_t PacketUtils::ReadU64(uint32_t startLoc, Packet* packet) { - if (startLoc + 8 > packet->length) return 0; - - std::vector t; - for (uint32_t i = startLoc; i < startLoc + 8; i++) t.push_back(packet->data[i]); - return *(uint64_t*)t.data(); -} - -int64_t PacketUtils::ReadS64(uint32_t startLoc, Packet* packet) { - if (startLoc + 8 > packet->length) return 0; - - std::vector t; - for (size_t i = startLoc; i < startLoc + 8; i++) t.push_back(packet->data[i]); - return *(int64_t*)t.data(); -} - -std::string PacketUtils::ReadString(uint32_t startLoc, Packet* packet, bool wide, uint32_t maxLen) { - std::string readString = ""; - - if (wide) maxLen *= 2; - - if (packet->length > startLoc) { - uint32_t i = 0; - while (packet->data[startLoc + i] != '\0' && packet->length > static_cast(startLoc + i) && maxLen > i) { - readString.push_back(packet->data[startLoc + i]); - - if (wide) { - i += 2; // Wide-char string - } else { - i++; // Regular string - } - } - } - - return readString; -} - //! Saves a packet to the filesystem void PacketUtils::SavePacket(const std::string& filename, const char* data, size_t length) { //If we don't log to the console, don't save the bin files either. This takes up a lot of time. diff --git a/dNet/PacketUtils.h b/dNet/PacketUtils.h index f8558dfd..3cd44b5f 100644 --- a/dNet/PacketUtils.h +++ b/dNet/PacketUtils.h @@ -8,11 +8,6 @@ enum class eConnectionType : uint16_t; namespace PacketUtils { - uint16_t ReadU16(uint32_t startLoc, Packet* packet); - uint32_t ReadU32(uint32_t startLoc, Packet* packet); - uint64_t ReadU64(uint32_t startLoc, Packet* packet); - int64_t ReadS64(uint32_t startLoc, Packet* packet); - std::string ReadString(uint32_t startLoc, Packet* packet, bool wide, uint32_t maxLen = 33); void SavePacket(const std::string& filename, const char* data, size_t length); }; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 2b53190a..ccc300bc 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -1126,6 +1126,7 @@ void HandlePacket(Packet* packet) { bitStream.Write(zone.GetInstanceID()); bitStream.Write(zone.GetCloneID()); bitStream.Write(player->GetParentUser()->GetMuteExpire()); + bitStream.Write(player->GetGMLevel()); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); }