mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-21 12:12:48 +00:00
refactor: chat packets as structs
Every packet of the chat service is now an LUBitStream struct in dNet/ChatPackets.h (docs/PacketArchitecture.md, PR 13), and nothing in the chat server or the chat side of the world server reads or writes a packet by hand any more. - World <-> chat: LoginSessionNotify, UnexpectedDisconnect, GMLevelUpdate, GMMute, Announcement (GM announce), CreateTeam, TeamUpdate (TEAM_GET_STATUS to worlds), AchievementNotify, ShowAllRequest, FindPlayerRequest. - Client -> world -> chat (friends, ignore list, teams, general and private chat): GetFriendsList, AddFriendRequest, AddFriendResponse, RemoveFriend, GetIgnoreList, AddIgnore, RemoveIgnore, GeneralChatMessage, PrivateChatMessage, TeamInvite, TeamInviteResponse, TeamLeave, TeamKick, TeamSetLeader, TeamSetLoot, TeamGetStatus. The 77 bytes the handlers skipped are named fields now (the sender block the client fills in); the 4 unused bytes after the player ID are kept as `unknown`. - What the client receives. Chat service (ChatPackets::Client): GeneralChatMessage (replaces SendChatMessage; SendSystemMessage stays as a helper built on it), PrivateChatMessage. Client service (ClientPackets, as structs go in the file of the ServiceType in their header): SendCannedText (replaces SendMessageFail), GetFriendsListResponse, AddFriendRequest, AddFriendResponse, RemoveFriendResponse, UpdateFriendNotify, WhoResponse, ShowAllResponse, Get/Add/RemoveIgnoreResponse, TeamInvite, TeamInviteInitialResponse, and the team game messages chat writes (TeamInviteConfirm, TeamGetStatusResponse, TeamSetLeader, TeamAddPlayer, TeamRemovePlayer, TeamSetOffWorldFlag) as TeamGameMsg structs, since chat doesn't link dGame's NetGameMsg. - WORLD_ROUTE_PACKET is ChatPackets::WorldRoutePacket (its own file, dNet/WorldRoutePacket.h, since it carries packets of other services): the target and the inner packet. ChatPacketHandler::SendRouted replaces the per-function route headers and SendRoutedMsg. Dispatch: dNet/PacketDispatcher.h is a dispatch map from packet ID to (struct, handler function); packets that fail to Deserialize are logged and dropped. The chat server's switch and the world's HandlePacketChat switch are now maps. The handlers take the structs; their logic is unchanged. World code sends to chat with ChatServerLink::Send (dGame) instead of writing to Game::chatServer by hand. eChatChannel, eChatMessageResponseCode and eAddIgnoreResponse moved to dCommon/dEnums so the structs can use them. Verified: tests/dGameTests/dNetTests/Legacy/ChatPacketsLegacy.h is a verbatim copy of the old senders and readers; ChatPacketsTests (25 tests) sends a grid of inputs through both and requires identical bits, bytes and destination, checks the old readers read what the structs write, round trips every struct, checks truncated packets are refused, and has hand written golden packets for general chat, canned text, GM mute and a routed team game message. Breaking one field width (UpdateFriendNotify) and the TeamAddPlayer zone flag made the tests fail. No wire bytes changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
#include "dCommonVars.h"
|
||||
#include "ChatServerLink.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "Entity.h"
|
||||
#include "EconomyLedger.h"
|
||||
#include "CDClientManager.h"
|
||||
@@ -945,12 +947,10 @@ void Entity::SetGMLevel(eGameMasterLevel value) {
|
||||
|
||||
// Update the chat server of our GM Level
|
||||
{
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::GMLEVEL_UPDATE);
|
||||
bitStream.Write(m_ObjectID);
|
||||
bitStream.Write(m_GMLevel);
|
||||
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
ChatPackets::GMLevelUpdate update;
|
||||
update.playerID = m_ObjectID;
|
||||
update.gmLevel = m_GMLevel;
|
||||
ChatServerLink::Send(update);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "User.h"
|
||||
#include "ChatServerLink.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "Database.h"
|
||||
#include "Character.h"
|
||||
#include "dServer.h"
|
||||
@@ -108,11 +110,10 @@ bool User::GetIsMuted() {
|
||||
m_MuteExpire = expire;
|
||||
|
||||
if (Game::chatServer && m_LoggedInCharID != 0) {
|
||||
RakNet::BitStream bitStream;
|
||||
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::GM_MUTE);
|
||||
bitStream.Write(m_LoggedInCharID);
|
||||
bitStream.Write(m_MuteExpire);
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
ChatPackets::GMMute mute;
|
||||
mute.playerID = m_LoggedInCharID;
|
||||
mute.expire = m_MuteExpire;
|
||||
ChatServerLink::Send(mute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "UserManager.h"
|
||||
#include "ChatServerLink.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "DashboardNotify.h"
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
@@ -441,10 +443,9 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, const WorldPacke
|
||||
Database::Get()->DeleteCharacter(objectID);
|
||||
DashboardNotify::Changed("characters", objectID);
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::UNEXPECTED_DISCONNECT);
|
||||
bitStream.Write(objectID);
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
ChatPackets::UnexpectedDisconnect notify;
|
||||
notify.playerID = objectID;
|
||||
ChatServerLink::Send(notify);
|
||||
|
||||
ClientPackets::DeleteCharacterResponse response;
|
||||
response.success = true;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "ActivityComponent.h"
|
||||
#include "ChatServerLink.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "GameMessages.h"
|
||||
#include "CDClientManager.h"
|
||||
#include "MissionComponent.h"
|
||||
@@ -441,19 +443,16 @@ void ActivityInstance::StartZone() {
|
||||
|
||||
// only make a team if we have more than one participant
|
||||
if (participants.size() > 1) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::CREATE_TEAM);
|
||||
|
||||
bitStream.Write(leader->GetObjectID());
|
||||
bitStream.Write(m_Participants.size());
|
||||
ChatPackets::CreateTeam createTeam;
|
||||
createTeam.leaderID = leader->GetObjectID();
|
||||
|
||||
for (const auto& participant : m_Participants) {
|
||||
bitStream.Write(participant);
|
||||
createTeam.members.push_back(participant);
|
||||
}
|
||||
|
||||
bitStream.Write(zoneId);
|
||||
createTeam.zoneID = zoneId;
|
||||
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
ChatServerLink::Send(createTeam);
|
||||
}
|
||||
|
||||
const auto cloneId = GeneralUtils::GenerateRandomNumber<uint32_t>(1, UINT32_MAX);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "Mission.h"
|
||||
#include "ChatServerLink.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
@@ -364,11 +365,8 @@ void Mission::Complete(const bool yieldRewards) {
|
||||
notify.earningPlayerID = entity->GetObjectID();
|
||||
notify.earnerName.string = character ? GeneralUtils::ASCIIToUTF16(character->GetName()) : u"";
|
||||
|
||||
// Manual write since it's sent to chat server and not a game client
|
||||
RakNet::BitStream bitstream;
|
||||
notify.WriteHeader(bitstream);
|
||||
notify.Serialize(bitstream);
|
||||
Game::chatServer->Send(&bitstream, HIGH_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
// Sent to the chat server, not a game client
|
||||
ChatServerLink::Send(notify, HIGH_PRIORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +214,14 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent, Up
|
||||
bool isOk = Game::chatFilter->IsSentenceOkay(valueStr.data(), eGameMasterLevel::CIVILIAN).empty();
|
||||
// In case a word is removed from the whitelist after it was approved
|
||||
const auto modelName = "%[Objects_" + std::to_string(entity.GetLOT()) + "_name]";
|
||||
if (isOk) ChatPackets::SendChatMessage(UNASSIGNED_SYSTEM_ADDRESS, 12, modelName, entity.GetObjectID(), false, GeneralUtils::ASCIIToUTF16(valueStr));
|
||||
if (isOk) {
|
||||
ChatPackets::Client::GeneralChatMessage chatMessage;
|
||||
chatMessage.chatChannel = 12;
|
||||
chatMessage.senderName = LUWString(modelName);
|
||||
chatMessage.senderID = entity.GetObjectID();
|
||||
chatMessage.message = GeneralUtils::ASCIIToUTF16(valueStr);
|
||||
chatMessage.Broadcast();
|
||||
}
|
||||
PropertyManagementComponent::Instance()->OnChatMessageReceived(valueStr.data());
|
||||
} else if (nextActionType == Actions::PRIVATE_MESSAGE) {
|
||||
PropertyManagementComponent::Instance()->OnChatMessageReceived(valueStr.data());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp"
|
||||
"ChatServerLink.cpp"
|
||||
"CheatDetection.cpp"
|
||||
"DashboardActions.cpp"
|
||||
"EconomyLedger.cpp"
|
||||
|
||||
13
dGame/dUtilities/ChatServerLink.cpp
Normal file
13
dGame/dUtilities/ChatServerLink.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "ChatServerLink.h"
|
||||
|
||||
#include "BitStream.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "Game.h"
|
||||
#include "RakPeerInterface.h"
|
||||
|
||||
void ChatServerLink::Send(const LUBitStream& msg, const PacketPriority priority, const PacketReliability reliability) {
|
||||
if (!Game::chatServer) return;
|
||||
RakNet::BitStream bitStream;
|
||||
msg.WritePacket(bitStream);
|
||||
Game::chatServer->Send(&bitStream, priority, reliability, 0, Game::chatSysAddr, false);
|
||||
}
|
||||
14
dGame/dUtilities/ChatServerLink.h
Normal file
14
dGame/dUtilities/ChatServerLink.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef CHATSERVERLINK_H
|
||||
#define CHATSERVERLINK_H
|
||||
|
||||
#include "PacketPriority.h"
|
||||
|
||||
struct LUBitStream;
|
||||
|
||||
// A world's connection to the chat server
|
||||
namespace ChatServerLink {
|
||||
// World -> chat: sends msg (a ChatPackets struct) over the world's chat connection
|
||||
void Send(const LUBitStream& msg, PacketPriority priority = SYSTEM_PRIORITY, PacketReliability reliability = RELIABLE);
|
||||
}
|
||||
|
||||
#endif // CHATSERVERLINK_H
|
||||
@@ -266,7 +266,11 @@ uint32_t DashboardActions::Apply(const PlayerActionRequest& request) {
|
||||
if (request.instanceId >= 0 && request.instanceId != Game::server->GetInstanceID()) return 0;
|
||||
if (Game::config->GetValue("chat_bridge_filter") != "0" && !Game::chatFilter->IsSentenceOkay(request.text, eGameMasterLevel::CIVILIAN).empty()) return 0;
|
||||
const auto players = PlayerManager::GetAllPlayers().size();
|
||||
ChatPackets::SendChatMessage(UNASSIGNED_SYSTEM_ADDRESS, static_cast<char>(4), request.name, LWOOBJID_EMPTY, false, GeneralUtils::UTF8ToUTF16(request.text));
|
||||
ChatPackets::Client::GeneralChatMessage chatMessage;
|
||||
chatMessage.chatChannel = 4;
|
||||
chatMessage.senderName = LUWString(request.name);
|
||||
chatMessage.message = GeneralUtils::UTF8ToUTF16(request.text);
|
||||
chatMessage.Broadcast();
|
||||
return static_cast<uint32_t>(players);
|
||||
}
|
||||
case ePlayerAction::RELOAD_VANITY:
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
|
||||
#include "SlashCommandHandler.h"
|
||||
#include "ChatServerLink.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "WorldMigration.h"
|
||||
|
||||
#include <iomanip>
|
||||
@@ -339,20 +341,10 @@ void SlashCommandHandler::SendAnnouncement(const std::string& title, const std::
|
||||
GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args);
|
||||
|
||||
//Notify chat about it
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::GM_ANNOUNCE);
|
||||
|
||||
bitStream.Write<uint32_t>(title.size());
|
||||
for (auto character : title) {
|
||||
bitStream.Write<char>(character);
|
||||
}
|
||||
|
||||
bitStream.Write<uint32_t>(message.size());
|
||||
for (auto character : message) {
|
||||
bitStream.Write<char>(character);
|
||||
}
|
||||
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
ChatPackets::Announcement announcement;
|
||||
announcement.title = title;
|
||||
announcement.message = message;
|
||||
ChatServerLink::Send(announcement);
|
||||
}
|
||||
|
||||
void SlashCommandHandler::Startup() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "GMGreaterThanZeroCommands.h"
|
||||
#include "ChatServerLink.h"
|
||||
#include "DashboardNotify.h"
|
||||
#include "SlashCommandHandler.h"
|
||||
|
||||
@@ -180,13 +181,10 @@ namespace GMGreaterThanZeroCommands {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Muted: " + GeneralUtils::UTF8ToUTF16(splitArgs[0]) + u" until " + timeStr);
|
||||
|
||||
//Notify chat about it
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::GM_MUTE);
|
||||
|
||||
bitStream.Write(characterId);
|
||||
bitStream.Write(expire);
|
||||
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
ChatPackets::GMMute mute;
|
||||
mute.playerID = characterId;
|
||||
mute.expire = expire;
|
||||
ChatServerLink::Send(mute);
|
||||
} else {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /mute <username> <days (optional)> <hours (optional)>");
|
||||
}
|
||||
@@ -281,15 +279,11 @@ namespace GMGreaterThanZeroCommands {
|
||||
if (!splitArgs.empty() && !splitArgs.at(0).empty()) displayZoneData = splitArgs.at(0) == "1";
|
||||
if (splitArgs.size() > 1) displayIndividualPlayers = splitArgs.at(1) == "1";
|
||||
|
||||
ShowAllRequest request {
|
||||
.requestor = entity->GetObjectID(),
|
||||
.displayZoneData = displayZoneData,
|
||||
.displayIndividualPlayers = displayIndividualPlayers
|
||||
};
|
||||
|
||||
CBITSTREAM;
|
||||
request.Serialize(bitStream);
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
ChatPackets::ShowAllRequest request;
|
||||
request.requestor = entity->GetObjectID();
|
||||
request.displayZoneData = displayZoneData;
|
||||
request.displayIndividualPlayers = displayIndividualPlayers;
|
||||
ChatServerLink::Send(request);
|
||||
}
|
||||
|
||||
void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
@@ -298,14 +292,10 @@ namespace GMGreaterThanZeroCommands {
|
||||
return;
|
||||
}
|
||||
|
||||
FindPlayerRequest request {
|
||||
.requestor = entity->GetObjectID(),
|
||||
.playerName = LUWString(args)
|
||||
};
|
||||
|
||||
CBITSTREAM;
|
||||
request.Serialize(bitStream);
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
ChatPackets::FindPlayerRequest request;
|
||||
request.requestor = entity->GetObjectID();
|
||||
request.playerName = LUWString(args);
|
||||
ChatServerLink::Send(request);
|
||||
}
|
||||
|
||||
void Spectate(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
|
||||
Reference in New Issue
Block a user