This commit is contained in:
Aaron Kimbre 2025-01-31 00:30:05 -06:00
parent aedc8a09fe
commit 6978b56016
6 changed files with 127 additions and 102 deletions

View File

@ -20,7 +20,7 @@
#include "eGameMasterLevel.h"
#include "ChatPackets.h"
#include "json.hpp"
#include "Web.h"
#include "ChatWeb.h"
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Get from the packet which player we want to do something with:
@ -428,50 +428,41 @@ void ChatPacketHandler::HandleShowAll(Packet* packet) {
// 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);
LOG("Got a message from player %llu", playerID);
ChatMessage data;
LWOOBJID sender;
inStream.Read(sender);
LOG("Got a message from player %llu", sender);
const auto& sender = Game::playerContainer.GetPlayerData(playerID);
if (!sender || sender.GetIsMuted()) return;
data.sender = Game::playerContainer.GetPlayerData(sender);
if (!data.sender || data.sender.GetIsMuted()) return;
eChatChannel channel;
uint32_t size;
inStream.IgnoreBytes(4);
inStream.Read(channel);
inStream.Read(data.channel);
inStream.Read(size);
inStream.IgnoreBytes(77);
LOG("message size: %u", size);
LUWString message(size);
inStream.Read(message);
data.message = LUWString(size);
inStream.Read(data.message);
LOG("Got message %s from (%s) via [%s]: %s", message.GetAsString().c_str(), sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str());
LOG("Got message from (%s) via [%s]: %s", data.sender.playerName.c_str(), StringifiedEnum::ToString(data.channel).data(), data.message.GetAsString().c_str());
// build chat json data
nlohmann::json data;
data["playerName"] = sender.playerName;
data["message"] = message.GetAsString();
auto& zoneID = data["zone_id"];
zoneID["map_id"] = sender.zoneID.GetMapID();
zoneID["instance_id"] = sender.zoneID.GetInstanceID();
zoneID["clone_id"] = sender.zoneID.GetCloneID();
switch (channel) {
case eChatChannel::LOCAL: {
Game::web.SendWSMessage("chat_local", data);
break;
}
case eChatChannel::TEAM: {
auto* team = Game::playerContainer.GetTeam(playerID);
auto* team = Game::playerContainer.GetTeam(data.sender.playerID);
if (team == nullptr) return;
data.teamID = team->teamID;
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);
data["teamID"] = team->teamID;
Game::web.SendWSMessage("chat_team", data);
SendPrivateChatMessage(data.sender, otherMember, otherMember, data.message, eChatChannel::TEAM, eChatMessageResponseCode::SENT);
}
break;
}
@ -479,70 +470,68 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
LOG("Unhandled Chat channel [%s]", StringifiedEnum::ToString(channel).data());
break;
}
ChatWeb::SendWSChatMessage(data);
}
// 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) {
ChatMessage data;
data.channel = eChatChannel::GENERAL;
CINSTREAM_SKIP_HEADER;
LWOOBJID playerID;
inStream.Read(playerID);
const auto& sender = Game::playerContainer.GetPlayerData(playerID);
if (!sender || sender.GetIsMuted()) return;
data.sender = Game::playerContainer.GetPlayerData(playerID);
if (!data.sender || data.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(data.channel);
if (data.channel != eChatChannel::PRIVATE_CHAT) LOG("WARNING: Received Private chat with the wrong channel!");
inStream.Read(size);
inStream.IgnoreBytes(77);
LUWString LUReceiverName;
inStream.Read(LUReceiverName);
auto receiverName = LUReceiverName.GetAsString();
inStream.IgnoreBytes(2);
LUWString message(size);
inStream.Read(message);
data.message = LUWString(size);
inStream.Read(data.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());
LOG("Got a message from (%s) via [%s]: %s to %s", data.sender.playerName.c_str(), StringifiedEnum::ToString(data.channel).data(), data.message.GetAsString().c_str(), receiverName.c_str());
const auto& receiver = Game::playerContainer.GetPlayerData(receiverName);
if (!receiver) {
data.receiver = Game::playerContainer.GetPlayerData(receiverName);
if (!data.receiver) {
PlayerData otherPlayer;
otherPlayer.playerName = receiverName;
auto responseType = Database::Get()->GetCharacterInfo(receiverName)
? eChatMessageResponseCode::NOTONLINE
: eChatMessageResponseCode::GENERALERROR;
SendPrivateChatMessage(sender, otherPlayer, sender, message, eChatChannel::GENERAL, responseType);
SendPrivateChatMessage(data.sender, otherPlayer, data.sender, data.message, data.channel, 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) {
nlohmann::json data;
data["sender"] = sender.playerName;
data["receiver"] = receiverName;
data["message"] = message.GetAsString();
data["zone_id"]["map_id"] = sender.zoneID.GetMapID();
data["zone_id"]["instance_id"] = sender.zoneID.GetInstanceID();
data["zone_id"]["clone_id"] = sender.zoneID.GetCloneID();
Game::web.SendWSMessage("chat_private", data);
for (const auto& fr : data.receiver.friends) {
if (fr.friendID == data.sender.playerID) {
data.channel = eChatChannel::PRIVATE_CHAT;
// To the sender:
SendPrivateChatMessage(sender, receiver, sender, message, eChatChannel::PRIVATE_CHAT, eChatMessageResponseCode::SENT);
SendPrivateChatMessage(data.sender, data.receiver, data.sender, data.message, data.channel, eChatMessageResponseCode::SENT);
// To the receiver:
SendPrivateChatMessage(sender, receiver, receiver, message, eChatChannel::PRIVATE_CHAT, eChatMessageResponseCode::RECEIVEDNEWWHISPER);
SendPrivateChatMessage(data.sender, data.receiver, data.receiver, data.message, data.channel, eChatMessageResponseCode::RECEIVEDNEWWHISPER);
// To the WebSocket
ChatWeb::SendWSChatMessage(data);
return;
}
}
SendPrivateChatMessage(sender, receiver, sender, message, eChatChannel::GENERAL, eChatMessageResponseCode::NOTFRIENDS);
SendPrivateChatMessage(data.sender, data.receiver, data.sender, data.message, data.channel, eChatMessageResponseCode::NOTFRIENDS);
}
void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) {

View File

@ -44,6 +44,14 @@ enum class eChatMessageResponseCode : uint8_t {
RECEIVERFREETRIAL,
};
struct ChatMessage {
LUWString message;
PlayerData sender;
PlayerData receiver;
eChatChannel channel;
LWOOBJID teamID;
};
namespace ChatPacketHandler {
void HandleFriendlistRequest(Packet* packet);
void HandleFriendRequest(Packet* packet);

View File

@ -56,7 +56,6 @@ void HandleHTTPAnnounceRequest(HTTPReply& reply, std::string body) {
}
}
void HandleWSChat(mg_connection* connection, json data) {
auto check = JSONUtils::CheckRequiredData(data, { "user", "message" });
if (!check.empty()) {
@ -65,11 +64,13 @@ void HandleWSChat(mg_connection* connection, json data) {
const auto user = data["user"].get<std::string>();
const auto message = data["message"].get<std::string>();
LOG_DEBUG("EXTERNAL Chat message from %s: %s", user.c_str(), message.c_str());
// TODO: use chat filter and respond if the message isn't allowed
// TODO: Send chat message to corret world server to broadcast to players
}
}
void ChatWeb::RegisterRoutes() {
namespace ChatWeb {
void RegisterRoutes() {
// REST API v1 routes
std::string v1_route = "/api/v1/";
Game::web.RegisterHTTPRoute({
@ -100,6 +101,43 @@ void ChatWeb::RegisterRoutes() {
Game::web.RegisterWSSubscription("chat_local");
Game::web.RegisterWSSubscription("chat_team");
Game::web.RegisterWSSubscription("chat_private");
Game::web.RegisterWSSubscription("chat");
Game::web.RegisterWSSubscription("player");
Game::web.RegisterWSSubscription("team");
}
void SendWSPlayerUpdate(const PlayerData& player, eActivityType activityType) {
json data;
data["player_data"] = player;
data["update_type"] = magic_enum::enum_name(activityType);
Game::web.SendWSMessage("player_update", data);
}
void SendWSChatMessage(const ChatMessage& chatMessage) {
json data;
data["message"] = chatMessage.message.GetAsString();
data["sender"] = chatMessage.sender;
data["channel"] = magic_enum::enum_name(chatMessage.channel);
std::string event = "chat"; // generic catch all
switch (chatMessage.channel) {
case eChatChannel::LOCAL:
event = "chat_local";
break;
case eChatChannel::TEAM:
event = "chat_team";
data["teamID"] = chatMessage.teamID;
break;
case eChatChannel::PRIVATE_CHAT:
data["receiver"] = chatMessage.receiver;
event = "chat_private";
break;
default:
LOG_DEBUG("Unhandled Chat channel [%s] in websocket send", StringifiedEnum::ToString(chatMessage.channel).data());
break;
}
Game::web.SendWSMessage(event, data);
}
}

View File

@ -5,9 +5,14 @@
#include <functional>
#include "Web.h"
#include "PlayerContainer.h"
#include "IActivityLog.h"
#include "ChatPacketHandler.h"
namespace ChatWeb {
void RegisterRoutes();
void SendWSPlayerUpdate(const PlayerData& player, eActivityType activityType);
void SendWSChatMessage(const ChatMessage& chatMessage);
};

View File

@ -12,8 +12,7 @@
#include "ChatPackets.h"
#include "dConfig.h"
#include "MessageType/Chat.h"
#include "json.hpp"
#include "Web.h"
#include "ChatWeb.h"
void PlayerContainer::Initialize() {
m_MaxNumberOfBestFriends =
@ -60,18 +59,8 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
m_PlayerCount++;
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
// Send to connected websockets
nlohmann::json wsdata;
wsdata["action"] = "character_update";
wsdata["type"] = "add";
wsdata["playerName"] = data.playerName;
wsdata["playerID"] = data.playerID;
auto& zoneID = wsdata["zone_id"];
zoneID["map_id"] = data.zoneID.GetMapID();
zoneID["instance_id"] = data.zoneID.GetInstanceID();
zoneID["clone_id"] = data.zoneID.GetCloneID();
Game::web.SendWSMessage("player", wsdata);
Database::Get()->UpdateActivityLog(data.playerID, eActivityType::PlayerLoggedIn, data.zoneID.GetMapID());
ChatWeb::SendWSPlayerUpdate(data, isLogin ? eActivityType::PlayerLoggedIn : eActivityType::PlayerChangedZone);
Database::Get()->UpdateActivityLog(data.playerID, isLogin ? eActivityType::PlayerLoggedIn : eActivityType::PlayerChangedZone, data.zoneID.GetMapID());
m_PlayersToRemove.erase(playerId);
}
@ -125,12 +114,7 @@ void PlayerContainer::RemovePlayer(const LWOOBJID playerID) {
}
}
nlohmann::json wsdata;
wsdata["action"] = "character_update";
wsdata["type"] = "remove";
wsdata["playerName"] = player.playerName;
wsdata["playerID"] = player.playerID;
Game::web.SendWSMessage("player", wsdata);
ChatWeb::SendWSPlayerUpdate(player, eActivityType::PlayerLoggedOut);
m_PlayerCount--;
LOG("Removed user: %llu", playerID);

View File

@ -8,6 +8,7 @@
enum class eActivityType : uint32_t {
PlayerLoggedIn,
PlayerLoggedOut,
PlayerChangedZone,
};
class IActivityLog {