chore: remove all raw packet reading from chat packet handler (#1415)

* chore: default size to 33 on LU(W)Strings since that's the most common lenght
Was doing this on other places, but not the main one

* chore: remove all raw packet reading from chat packet handler

and general chat packet cleanup

* fix team invite/promote/kick

* Address feedback

* fix friends check

* update comments

* Address feedback
Add GM level handeling

* Address feedback
This commit is contained in:
Aaron Kimbrell 2024-01-14 01:03:01 -06:00 committed by GitHub
parent a62f6d63c6
commit 6592bbea46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 305 additions and 210 deletions

View File

@ -2,7 +2,6 @@
#include "PlayerContainer.h" #include "PlayerContainer.h"
#include "Database.h" #include "Database.h"
#include <vector> #include <vector>
#include "PacketUtils.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "Game.h" #include "Game.h"
#include "dServer.h" #include "dServer.h"
@ -18,6 +17,8 @@
#include "eChatInternalMessageType.h" #include "eChatInternalMessageType.h"
#include "eClientMessageType.h" #include "eClientMessageType.h"
#include "eGameMessageType.h" #include "eGameMessageType.h"
#include "StringifiedEnum.h"
#include "eGameMasterLevel.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:
@ -78,31 +79,27 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
void ChatPacketHandler::HandleFriendRequest(Packet* packet) { void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID requestorPlayerID; LWOOBJID requestorPlayerID;
inStream.Read(requestorPlayerID); LUWString LUplayerName;
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<char>(character));
}
char isBestFriendRequest{}; char isBestFriendRequest{};
inStream.Read(requestorPlayerID);
inStream.IgnoreBytes(4);
inStream.Read(LUplayerName);
inStream.Read(isBestFriendRequest); inStream.Read(isBestFriendRequest);
auto playerName = LUplayerName.GetAsString();
auto& requestor = Game::playerContainer.GetPlayerDataMutable(requestorPlayerID); auto& requestor = Game::playerContainer.GetPlayerDataMutable(requestorPlayerID);
if (!requestor) { if (!requestor) {
LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str()); LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
return; return;
} }
// you cannot friend yourself
if (requestor.playerName == playerName) { if (requestor.playerName == playerName) {
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN); SendFriendResponse(requestor, requestor, eAddFriendResponseType::GENERALERROR);
return; return;
}; };
@ -141,6 +138,13 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
return; 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) { if (isBestFriendRequest) {
uint8_t oldBestFriendStatus{}; uint8_t oldBestFriendStatus{};
@ -218,15 +222,19 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
void ChatPacketHandler::HandleFriendResponse(Packet* packet) { void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID;
inStream.Read(playerID);
eAddFriendResponseCode clientResponseCode = static_cast<eAddFriendResponseCode>(packet->data[0x14]); LWOOBJID playerID;
std::string friendName = PacketUtils::ReadString(0x15, packet, true); eAddFriendResponseCode clientResponseCode;
LUWString friendName;
inStream.Read(playerID);
inStream.IgnoreBytes(4);
inStream.Read(clientResponseCode);
inStream.Read(friendName);
//Now to try and find both of these: //Now to try and find both of these:
auto& requestor = Game::playerContainer.GetPlayerDataMutable(playerID); auto& requestor = Game::playerContainer.GetPlayerDataMutable(playerID);
auto& requestee = Game::playerContainer.GetPlayerDataMutable(friendName); auto& requestee = Game::playerContainer.GetPlayerDataMutable(friendName.GetAsString());
if (!requestor || !requestee) return; if (!requestor || !requestee) return;
eAddFriendResponseType serverResponseCode{}; eAddFriendResponseType serverResponseCode{};
@ -288,8 +296,11 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
LUWString LUFriendName;
inStream.Read(playerID); 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. //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: //First, we need to find their ID:
@ -335,123 +346,144 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
SendRemoveFriend(goonB, goonAName, true); SendRemoveFriend(goonB, goonAName, true);
} }
void ChatPacketHandler::HandleChatMessage(Packet* packet) { void ChatPacketHandler::HandleGMLevelUpdate(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<uint8_t>(8);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(sender.playerName));
bitStream.Write(sender.playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(otherMember.playerName));
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(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<uint8_t>(7);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(goonA.playerName));
bitStream.Write(goonA.playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(goonB.playerName));
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(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<uint8_t>(7);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(goonA.playerName));
bitStream.Write(goonA.playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(goonB.playerName));
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(3); //new whisper
bitStream.Write(LUWString(message, 512));
SystemAddress sysAddr = goonB.sysAddr;
SEND_PACKET;
}
}
void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(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<uint32_t>(0); // not used
bitStream.Write(LUWString(sender.playerName));
bitStream.Write(sender.playerID);
bitStream.Write<uint16_t>(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); const auto& player = Game::playerContainer.GetPlayerData(playerID);
@ -463,7 +495,7 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
team = Game::playerContainer.CreateTeam(playerID); team = Game::playerContainer.CreateTeam(playerID);
} }
const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer); const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer.GetAsString());
if (!other) return; if (!other) return;
@ -480,7 +512,7 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
SendTeamInvite(other, player); 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) { void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
@ -534,21 +566,25 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
void ChatPacketHandler::HandleTeamKick(Packet* packet) { void ChatPacketHandler::HandleTeamKick(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
LUWString kickedPlayer;
inStream.Read(playerID); 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; LWOOBJID kickedId = LWOOBJID_EMPTY;
if (kicked) { if (kicked) {
kickedId = kicked.playerID; kickedId = kicked.playerID;
} else { } else {
kickedId = Game::playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer)); kickedId = Game::playerContainer.GetId(kickedPlayer.string);
} }
if (kickedId == LWOOBJID_EMPTY) return; if (kickedId == LWOOBJID_EMPTY) return;
@ -564,14 +600,17 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
void ChatPacketHandler::HandleTeamPromote(Packet* packet) { void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
LUWString promotedPlayer;
inStream.Read(playerID); 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.GetAsString());
const auto& promoted = Game::playerContainer.GetPlayerData(promotedPlayer);
if (!promoted) return; if (!promoted) return;

View File

@ -7,14 +7,53 @@ struct PlayerData;
enum class eAddFriendResponseType : uint8_t; 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 { namespace ChatPacketHandler {
void HandleFriendlistRequest(Packet* packet); void HandleFriendlistRequest(Packet* packet);
void HandleFriendRequest(Packet* packet); void HandleFriendRequest(Packet* packet);
void HandleFriendResponse(Packet* packet); void HandleFriendResponse(Packet* packet);
void HandleRemoveFriend(Packet* packet); void HandleRemoveFriend(Packet* packet);
void HandleGMLevelUpdate(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 HandleTeamInvite(Packet* packet);
void HandleTeamInviteResponse(Packet* packet); void HandleTeamInviteResponse(Packet* packet);

View File

@ -20,6 +20,7 @@
#include "eChatInternalMessageType.h" #include "eChatInternalMessageType.h"
#include "eWorldMessageType.h" #include "eWorldMessageType.h"
#include "ChatIgnoreList.h" #include "ChatIgnoreList.h"
#include "StringifiedEnum.h"
#include "Game.h" #include "Game.h"
#include "Server.h" #include "Server.h"
@ -223,7 +224,8 @@ void HandlePacket(Packet* packet) {
} }
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) { if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
switch (static_cast<eChatMessageType>(packet->data[3])) { eChatMessageType chat_message_type = static_cast<eChatMessageType>(packet->data[3]);
switch (chat_message_type) {
case eChatMessageType::GET_FRIENDS_LIST: case eChatMessageType::GET_FRIENDS_LIST:
ChatPacketHandler::HandleFriendlistRequest(packet); ChatPacketHandler::HandleFriendlistRequest(packet);
break; break;
@ -293,9 +295,61 @@ void HandlePacket(Packet* packet) {
case eChatMessageType::TEAM_SET_LOOT: case eChatMessageType::TEAM_SET_LOOT:
ChatPacketHandler::HandleTeamLootOption(packet); ChatPacketHandler::HandleTeamLootOption(packet);
break; 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: default:
LOG("Unknown CHAT id: %i", int(packet->data[3])); LOG("Unknown CHAT Message id: %i", chat_message_type);
} }
} }

View File

@ -10,6 +10,7 @@
#include "Database.h" #include "Database.h"
#include "eConnectionType.h" #include "eConnectionType.h"
#include "eChatInternalMessageType.h" #include "eChatInternalMessageType.h"
#include "eGameMasterLevel.h"
#include "ChatPackets.h" #include "ChatPackets.h"
#include "dConfig.h" #include "dConfig.h"
@ -22,6 +23,10 @@ PlayerContainer::~PlayerContainer() {
m_Players.clear(); m_Players.clear();
} }
PlayerData::PlayerData() {
gmLevel == eGameMasterLevel::CIVILIAN;
}
TeamData::TeamData() { TeamData::TeamData() {
lootFlag = Game::config->GetValue("default_team_loot") == "0" ? 0 : 1; 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.zoneID);
inStream.Read(data.muteExpire); inStream.Read(data.muteExpire);
inStream.Read(data.gmLevel);
data.sysAddr = packet->systemAddress; data.sysAddr = packet->systemAddress;
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName); m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);

View File

@ -7,6 +7,8 @@
#include "dServer.h" #include "dServer.h"
#include <unordered_map> #include <unordered_map>
enum class eGameMasterLevel : uint8_t;
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 {
@ -22,6 +24,7 @@ struct IgnoreData {
}; };
struct PlayerData { struct PlayerData {
PlayerData();
operator bool() const noexcept { operator bool() const noexcept {
return playerID != LWOOBJID_EMPTY; return playerID != LWOOBJID_EMPTY;
} }
@ -42,6 +45,8 @@ struct PlayerData {
std::string playerName; std::string playerName;
std::vector<FriendData> friends; std::vector<FriendData> friends;
std::vector<IgnoreData> ignoredPlayers; std::vector<IgnoreData> ignoredPlayers;
eGameMasterLevel gmLevel;
bool isFTP = false;
}; };
struct TeamData { struct TeamData {

View File

@ -25,6 +25,7 @@
#include "eTriggerEventType.h" #include "eTriggerEventType.h"
#include "eObjectBits.h" #include "eObjectBits.h"
#include "PositionUpdate.h" #include "PositionUpdate.h"
#include "eChatMessageType.h"
//Component includes: //Component includes:
#include "Component.h" #include "Component.h"
@ -858,9 +859,20 @@ void Entity::SetGMLevel(eGameMasterLevel value) {
} }
CharacterComponent* character = GetComponent<CharacterComponent>(); CharacterComponent* character = GetComponent<CharacterComponent>();
if (character) character->SetGMLevel(value); if (!character) return;
character->SetGMLevel(value);
GameMessages::SendGMLevelBroadcast(m_ObjectID, 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) { void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType) {

View File

@ -1,64 +1,8 @@
#include "PacketUtils.h" #include "PacketUtils.h"
#include <vector>
#include <fstream> #include <fstream>
#include "Logger.h" #include "Logger.h"
#include "Game.h" #include "Game.h"
uint16_t PacketUtils::ReadU16(uint32_t startLoc, Packet* packet) {
if (startLoc + 2 > packet->length) return 0;
std::vector<unsigned char> 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<unsigned char> 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<unsigned char> 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<unsigned char> 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<uint32_t>(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 //! Saves a packet to the filesystem
void PacketUtils::SavePacket(const std::string& filename, const char* data, size_t length) { 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. //If we don't log to the console, don't save the bin files either. This takes up a lot of time.

View File

@ -8,11 +8,6 @@
enum class eConnectionType : uint16_t; enum class eConnectionType : uint16_t;
namespace PacketUtils { 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); void SavePacket(const std::string& filename, const char* data, size_t length);
}; };

View File

@ -1126,6 +1126,7 @@ void HandlePacket(Packet* packet) {
bitStream.Write(zone.GetInstanceID()); bitStream.Write(zone.GetInstanceID());
bitStream.Write(zone.GetCloneID()); bitStream.Write(zone.GetCloneID());
bitStream.Write(player->GetParentUser()->GetMuteExpire()); bitStream.Write(player->GetParentUser()->GetMuteExpire());
bitStream.Write(player->GetGMLevel());
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
} }