OpenFusion/src/Chat.cpp
gsemaj d32827b692
The great re-#include
Was getting frustrated by the inconsistency in our include statements,
which were causing me problems. As a result, I went through and manually
re-organized every include statement in non-core files.

I'm just gonna copy my rant from Discord:
FOR HEADER FILES (.hpp):
- everything you use IN THE HEADER must be EXPLICITLY INCLUDED with the exception of things that fall under Core.hpp
- you may NOT include ANYTHING ELSE

FOR SOURCE FILES (.cpp):
- you can #include whatever you want as long as the partner header is included first
- anything that gets included by another include is fair game
- redundant includes are ok because they'll be harmless AS LONG AS our header files stay lean.

the point of this is NOT to optimize the number of includes used all around or make things more efficient necessarily. it's to improve readability & coherence and make it easier to avoid cyclical issues
2023-10-08 16:34:18 -04:00

320 lines
12 KiB
C++

#include "Chat.hpp"
#include "servers/CNShardServer.hpp"
#include "Player.hpp"
#include "PlayerManager.hpp"
#include "CustomCommands.hpp"
#include <assert.h>
std::vector<std::string> Chat::dump;
using namespace Chat;
static void chatHandler(CNSocket* sock, CNPacketData* data) {
auto chat = (sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE*)data->buf;
Player* plr = PlayerManager::getPlayer(sock);
std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat));
if (fullChat.length() > 1 && fullChat[0] == CMD_PREFIX) { // PREFIX
CustomCommands::runCmd(fullChat, sock);
return;
}
if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__MUTE_FREECHAT)
return;
std::string logLine = "[FreeChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
std::cout << logLine << std::endl;
dump.push_back(logLine);
// send to client
INITSTRUCT(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, resp);
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
resp.iPC_ID = plr->iID;
resp.iEmoteCode = chat->iEmoteCode;
sock->sendPacket(resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC);
// send to visible players
PlayerManager::sendToViewable(sock, resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC);
}
static void menuChatHandler(CNSocket* sock, CNPacketData* data) {
auto chat = (sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE*)data->buf;
Player *plr = PlayerManager::getPlayer(sock);
std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat));
std::string logLine = "[MenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
std::cout << logLine << std::endl;
dump.push_back(logLine);
// send to client
INITSTRUCT(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, resp);
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
resp.iPC_ID = PlayerManager::getPlayer(sock)->iID;
resp.iEmoteCode = chat->iEmoteCode;
sock->sendPacket(resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC);
// send to visible players
PlayerManager::sendToViewable(sock, resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC);
}
static void emoteHandler(CNSocket* sock, CNPacketData* data) {
auto emote = (sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT*)data->buf;
Player* plr = PlayerManager::getPlayer(sock);
// send to client
INITSTRUCT(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, resp);
resp.iEmoteCode = emote->iEmoteCode;
resp.iID_From = plr->iID;
sock->sendPacket(resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT);
// send to visible players (players within render distance)
PlayerManager::sendToViewable(sock, resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT);
}
void Chat::sendServerMessage(CNSocket* sock, std::string msg) {
INITSTRUCT(sP_FE2CL_PC_MOTD_LOGIN, motd);
motd.iType = 1;
// convert string to u16 and write it to the buffer
U8toU16(msg, (char16_t*)motd.szSystemMsg, sizeof(motd.szSystemMsg));
// send the packet :)
sock->sendPacket(motd, P_FE2CL_PC_MOTD_LOGIN);
}
static void announcementHandler(CNSocket* sock, CNPacketData* data) {
Player* plr = PlayerManager::getPlayer(sock);
if (plr->accountLevel > 30)
return; // only players with account level less than 30 (GM) are allowed to use this command
auto announcement = (sP_CL2FE_GM_REQ_PC_ANNOUNCE*)data->buf;
INITSTRUCT(sP_FE2CL_GM_REP_PC_ANNOUNCE, msg);
msg.iAnnounceType = announcement->iAnnounceType;
msg.iDuringTime = announcement->iDuringTime;
memcpy(msg.szAnnounceMsg, announcement->szAnnounceMsg, sizeof(msg.szAnnounceMsg));
std::map<CNSocket*, Player*>::iterator it;
switch (announcement->iAreaType) {
case 0: // area (all players in viewable chunks)
sock->sendPacket(msg, P_FE2CL_GM_REP_PC_ANNOUNCE);
PlayerManager::sendToViewable(sock, msg, P_FE2CL_GM_REP_PC_ANNOUNCE);
break;
case 1: // shard
case 2: // world
break; // not applicable to OpenFusion
case 3: // global (all players)
for (it = PlayerManager::players.begin(); it != PlayerManager::players.end(); it++) {
CNSocket* allSock = it->first;
allSock->sendPacket(msg, P_FE2CL_GM_REP_PC_ANNOUNCE);
}
default:
break;
}
std::string logLine = "[Bcast " + std::to_string(announcement->iAreaType) + "] " + PlayerManager::getPlayerName(plr, false) + ": " + AUTOU16TOU8(msg.szAnnounceMsg);
std::cout << logLine << std::endl;
dump.push_back("**" + logLine + "**");
}
// Buddy freechatting
static void buddyChatHandler(CNSocket* sock, CNPacketData* data) {
auto pkt = (sP_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE*)data->buf;
Player* plr = PlayerManager::getPlayer(sock);
INITSTRUCT(sP_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC, resp);
CNSocket* otherSock = PlayerManager::getSockFromID(pkt->iBuddyPCUID);
if (otherSock == nullptr)
return; // buddy offline
Player *otherPlr = PlayerManager::getPlayer(otherSock);
resp.iFromPCUID = plr->PCStyle.iPC_UID;
resp.iToPCUID = pkt->iBuddyPCUID;
resp.iEmoteCode = pkt->iEmoteCode;
std::string fullChat = sanitizeText(AUTOU16TOU8(pkt->szFreeChat));
if (fullChat.length() > 1 && fullChat[0] == CMD_PREFIX) { // PREFIX
CustomCommands::runCmd(fullChat, sock);
return;
}
if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__MUTE_FREECHAT)
return;
std::string logLine = "[BuddyChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
std::cout << logLine << std::endl;
dump.push_back(logLine);
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
sock->sendPacket(resp, P_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC); // confirm send to sender
otherSock->sendPacket(resp, P_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC); // broadcast send to receiver
}
// Buddy menuchat
static void buddyMenuChatHandler(CNSocket* sock, CNPacketData* data) {
auto pkt = (sP_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE*)data->buf;
Player* plr = PlayerManager::getPlayer(sock);
INITSTRUCT(sP_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC, resp);
CNSocket* otherSock = PlayerManager::getSockFromID(pkt->iBuddyPCUID);
if (otherSock == nullptr)
return; // buddy offline
Player *otherPlr = PlayerManager::getPlayer(otherSock);
resp.iFromPCUID = plr->PCStyle.iPC_UID;
resp.iToPCUID = pkt->iBuddyPCUID;
resp.iEmoteCode = pkt->iEmoteCode;
std::string fullChat = sanitizeText(AUTOU16TOU8(pkt->szFreeChat));
std::string logLine = "[BuddyMenuChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
std::cout << logLine << std::endl;
dump.push_back(logLine);
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
sock->sendPacket(resp, P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC); // confirm send to sender
otherSock->sendPacket(resp, P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC); // broadcast send to receiver
}
static void tradeChatHandler(CNSocket* sock, CNPacketData* data) {
auto pacdat = (sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT*)data->buf;
CNSocket* otherSock; // weird flip flop because we need to know who the other player is
if (pacdat->iID_Request == pacdat->iID_From)
otherSock = PlayerManager::getSockFromID(pacdat->iID_To);
else
otherSock = PlayerManager::getSockFromID(pacdat->iID_From);
if (otherSock == nullptr)
return;
Player *otherPlr = PlayerManager::getPlayer(otherSock);
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT, resp);
Player *plr = PlayerManager::getPlayer(sock);
resp.iID_Request = pacdat->iID_Request;
resp.iID_From = pacdat->iID_From;
resp.iID_To = pacdat->iID_To;
std::string fullChat = sanitizeText(AUTOU16TOU8(pacdat->szFreeChat));
U8toU16(fullChat, resp.szFreeChat, sizeof(resp.szFreeChat));
std::string logLine = "[TradeChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
std::cout << logLine << std::endl;
dump.push_back(logLine);
resp.iEmoteCode = pacdat->iEmoteCode;
sock->sendPacket(resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT);
otherSock->sendPacket(resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT);
}
static void groupChatHandler(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE*)data->buf;
Player* plr = PlayerManager::getPlayer(sock);
std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat));
if (fullChat.length() > 1 && fullChat[0] == CMD_PREFIX) { // PREFIX
CustomCommands::runCmd(fullChat, sock);
return;
}
if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__MUTE_FREECHAT)
return;
std::string logLine = "[GroupChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
std::cout << logLine << std::endl;
dump.push_back(logLine);
// send to client
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, resp);
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
resp.iSendPCID = plr->iID;
resp.iEmoteCode = chat->iEmoteCode;
if (plr->group == nullptr)
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC));
else
Groups::sendToGroup(plr->group, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC));
}
static void groupMenuChatHandler(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE*)data->buf;
Player* plr = PlayerManager::getPlayer(sock);
std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat));
std::string logLine = "[GroupMenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
std::cout << logLine << std::endl;
dump.push_back(logLine);
// send to client
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, resp);
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
resp.iSendPCID = plr->iID;
resp.iEmoteCode = chat->iEmoteCode;
if (plr->group == nullptr)
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC));
Groups::sendToGroup(plr->group, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC));
}
// we only allow plain ascii, at least for now
std::string Chat::sanitizeText(std::string text, bool allowNewlines) {
int i;
const int BUFSIZE = 512;
char buf[BUFSIZE];
assert(text.size() < BUFSIZE);
i = 0;
for (char c : text) {
if (i >= BUFSIZE-1)
break;
if (!allowNewlines && c == '\n')
continue;
if ((c >= ' ' && c <= '~') || c == '\n')
buf[i++] = c;
}
buf[i] = 0;
return std::string(buf);
}
void Chat::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_FREECHAT_MESSAGE, chatHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT, emoteHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_MENUCHAT_MESSAGE, menuChatHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE, buddyChatHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE, buddyMenuChatHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT, tradeChatHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE, groupChatHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE, groupMenuChatHandler);
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_ANNOUNCE, announcementHandler);
}