From f5939353b1852c367f0fdb51c191e6ff235e979f Mon Sep 17 00:00:00 2001 From: CPunch Date: Fri, 2 Oct 2020 18:50:47 -0500 Subject: [PATCH] added basic command handler --- src/ChatManager.cpp | 76 ++++++++++++++++++++++++++++++++++++++++--- src/ChatManager.hpp | 16 +++++++++ src/PlayerManager.cpp | 7 ++-- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index 3ee0a4b..2b28512 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -3,22 +3,79 @@ #include "ChatManager.hpp" #include "PlayerManager.hpp" +#include +#include + +std::map ChatManager::commands; + +std::vector parseArgs(std::string full) { + std::stringstream ss(full); + std::istream_iterator begin(ss); + std::istream_iterator end; + return std::vector(begin, end); +} + +bool runCmd(std::string full, std::vector args, CNSocket* sock) { + std::string cmd = args[0].substr(1, args[0].size() - 1); + + if (ChatManager::commands.find(cmd) != ChatManager::commands.end()) { + Player* plr = PlayerManager::getPlayer(sock); + ChatCommand command = ChatManager::commands[cmd]; + + if (plr != nullptr && plr->accountLevel <= command.requiredAccLevel) { + command.handlr(full, args, sock); + return true; + } else { + ChatManager::sendServerMessage(sock, "You don't have access to that command!"); + return false; + } + } + + ChatManager::sendServerMessage(sock, "Unknown command!"); + return false; +} + +void testCommand(std::string full, std::vector args, CNSocket* sock) { + ChatManager::sendServerMessage(sock, "Test command is working!"); +} + +void accessCommand(std::string full, std::vector args, CNSocket* sock) { + ChatManager::sendServerMessage(sock, "Your access level is " + std::to_string(PlayerManager::getPlayer(sock)->accountLevel)); +} + void ChatManager::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); + + registerCommand("test", 1, testCommand); + registerCommand("access", 100, accessCommand); + // TODO: add help command +} + +void ChatManager::registerCommand(std::string cmd, int requiredLevel, CommandHandler handlr) { + commands[cmd] = ChatCommand(requiredLevel, handlr); } void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE)) return; // malformed packet + sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE*)data->buf; - PlayerView& plr = PlayerManager::players[sock]; + Player* plr = PlayerManager::getPlayer(sock); + + std::string fullChat = U16toU8(chat->szFreeChat); + std::vector args = parseArgs(fullChat); + + if (args.size() > 0 && args[0][0] == CMD_PREFIX) { // PREFIX + runCmd(fullChat, args, sock); + return; + } // send to client INITSTRUCT(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, resp); memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat)); - resp.iPC_ID = plr.plr->iID; + resp.iPC_ID = plr->iID; resp.iEmoteCode = chat->iEmoteCode; sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC)); @@ -49,14 +106,25 @@ void ChatManager::emoteHandler(CNSocket* sock, CNPacketData* data) { // you can dance with friends!!!!!!!! sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT* emote = (sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT*)data->buf; - PlayerView& plr = PlayerManager::players[sock]; + 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.plr->iID; + resp.iID_From = plr->iID; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT)); // send to visible players (players within render distance) PlayerManager::sendToViewable(sock, (void*)&resp, P_FE2CL_REP_PC_AVATAR_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_AVATAR_EMOTES_CHAT)); } + +void ChatManager::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 (TODO: add sanity check to prevent buffer overflow) + U8toU16(msg, (char16_t*)motd.szSystemMsg); + + // send the packet :) + sock->sendPacket((void*)&motd, P_FE2CL_PC_MOTD_LOGIN, sizeof(sP_FE2CL_PC_MOTD_LOGIN)); +} diff --git a/src/ChatManager.hpp b/src/ChatManager.hpp index cfc827b..82f311a 100644 --- a/src/ChatManager.hpp +++ b/src/ChatManager.hpp @@ -2,10 +2,26 @@ #include "CNShardServer.hpp" +#define CMD_PREFIX '/' + +typedef void (*CommandHandler)(std::string fullString, std::vector args, CNSocket* sock); + +struct ChatCommand { + int requiredAccLevel; + CommandHandler handlr; + + ChatCommand(int r, CommandHandler h): requiredAccLevel(r), handlr(h) {} + ChatCommand(): ChatCommand(0, nullptr) {} +}; + namespace ChatManager { + extern std::map commands; void init(); + void registerCommand(std::string cmd, int requiredLevel, CommandHandler handlr); + void chatHandler(CNSocket* sock, CNPacketData* data); void emoteHandler(CNSocket* sock, CNPacketData* data); void menuChatHandler(CNSocket* sock, CNPacketData* data); + void sendServerMessage(CNSocket* sock, std::string msg); // uses MOTD } diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 4a12daa..5a170b9 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -5,6 +5,7 @@ #include "CNShared.hpp" #include "MissionManager.hpp" #include "ItemManager.hpp" +#include "ChatManager.hpp" #include "settings.hpp" @@ -217,7 +218,6 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { sP_CL2FE_REQ_PC_ENTER* enter = (sP_CL2FE_REQ_PC_ENTER*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_ENTER_SUCC, response); - INITSTRUCT(sP_FE2CL_PC_MOTD_LOGIN, motd); // TODO: check if serialkey exists, if it doesn't send sP_FE2CL_REP_PC_ENTER_FAIL Player plr = CNSharedData::getPlayer(enter->iEnterSerialKey); @@ -311,9 +311,6 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { plr.SerialKey = enter->iEnterSerialKey; plr.instanceID = INSTANCE_OVERWORLD; // TODO: load this from the database (as long as it's not a unique instance) - motd.iType = 1; - U8toU16(settings::MOTDSTRING, (char16_t*)motd.szSystemMsg); - sock->setEKey(CNSocketEncryption::createNewKey(response.uiSvrTime, response.iID + 1, response.PCLoadData2CL.iFusionMatter + 1)); sock->setFEKey(plr.FEKey); sock->setActiveKey(SOCKETKEY_FE); // send all packets using the FE key from now on @@ -321,7 +318,7 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { sock->sendPacket((void*)&response, P_FE2CL_REP_PC_ENTER_SUCC, sizeof(sP_FE2CL_REP_PC_ENTER_SUCC)); // transmit MOTD after entering the game, so the client hopefully changes modes on time - sock->sendPacket((void*)&motd, P_FE2CL_PC_MOTD_LOGIN, sizeof(sP_FE2CL_PC_MOTD_LOGIN)); + ChatManager::sendServerMessage(sock, settings::MOTDSTRING); addPlayer(sock, plr); //check if there is an expiring vehicle