mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-05 06:50:04 +00:00
[refactor] Refactor ChatManager
* Extracted all commands into CustomCommands.cpp * Moved all chat-related packet handlers into ChatManger.cpp * Cleaned up redundant includes * Unified handler naming scheme * Made all command handlers in CustomCommands.cpp static
This commit is contained in:
parent
4cd3a3dabd
commit
2d7129111a
2
Makefile
2
Makefile
@ -30,6 +30,7 @@ CSRC=\
|
|||||||
|
|
||||||
CXXSRC=\
|
CXXSRC=\
|
||||||
src/ChatManager.cpp\
|
src/ChatManager.cpp\
|
||||||
|
src/CustomCommands.cpp\
|
||||||
src/CNLoginServer.cpp\
|
src/CNLoginServer.cpp\
|
||||||
src/CNProtocol.cpp\
|
src/CNProtocol.cpp\
|
||||||
src/CNShardServer.cpp\
|
src/CNShardServer.cpp\
|
||||||
@ -65,6 +66,7 @@ CXXHDR=\
|
|||||||
vendor/INIReader.hpp\
|
vendor/INIReader.hpp\
|
||||||
vendor/JSON.hpp\
|
vendor/JSON.hpp\
|
||||||
src/ChatManager.hpp\
|
src/ChatManager.hpp\
|
||||||
|
src/CustomCommands.hpp\
|
||||||
src/CNLoginServer.hpp\
|
src/CNLoginServer.hpp\
|
||||||
src/CNProtocol.hpp\
|
src/CNProtocol.hpp\
|
||||||
src/CNShardServer.hpp\
|
src/CNShardServer.hpp\
|
||||||
|
@ -17,8 +17,6 @@ void BuddyManager::init() {
|
|||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIND_NAME_MAKE_BUDDY, reqBuddyByName);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIND_NAME_MAKE_BUDDY, reqBuddyByName);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ACCEPT_MAKE_BUDDY, reqAcceptBuddy);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ACCEPT_MAKE_BUDDY, reqAcceptBuddy);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIND_NAME_ACCEPT_BUDDY, reqFindNameBuddyAccept);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIND_NAME_ACCEPT_BUDDY, reqFindNameBuddyAccept);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE, reqBuddyFreechat);
|
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE, reqBuddyMenuchat);
|
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_GET_BUDDY_STATE, reqPktGetBuddyState);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_GET_BUDDY_STATE, reqPktGetBuddyState);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_BUDDY_BLOCK, reqBuddyBlock);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_BUDDY_BLOCK, reqBuddyBlock);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_PC_BLOCK, reqPlayerBlock);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_PC_BLOCK, reqPlayerBlock);
|
||||||
@ -294,80 +292,6 @@ void BuddyManager::reqFindNameBuddyAccept(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buddy freechatting
|
|
||||||
void BuddyManager::reqBuddyFreechat(CNSocket* sock, CNPacketData* data) {
|
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE))
|
|
||||||
return; // malformed packet
|
|
||||||
|
|
||||||
sP_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE* 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 = ChatManager::sanitizeText(U16toU8(pkt->szFreeChat));
|
|
||||||
|
|
||||||
if (fullChat.length() > 1 && fullChat[0] == CMD_PREFIX) { // PREFIX
|
|
||||||
ChatManager::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;
|
|
||||||
ChatManager::dump.push_back(logLine);
|
|
||||||
|
|
||||||
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
|
|
||||||
|
|
||||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC)); // confirm send to sender
|
|
||||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_BUDDY_FREECHAT_MESSAGE_SUCC)); // broadcast send to receiver
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buddy menuchat
|
|
||||||
void BuddyManager::reqBuddyMenuchat(CNSocket* sock, CNPacketData* data) {
|
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE))
|
|
||||||
return; // malformed packet
|
|
||||||
|
|
||||||
sP_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE* 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 = ChatManager::sanitizeText(U16toU8(pkt->szFreeChat));
|
|
||||||
std::string logLine = "[BuddyMenuChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
|
||||||
|
|
||||||
std::cout << logLine << std::endl;
|
|
||||||
ChatManager::dump.push_back(logLine);
|
|
||||||
|
|
||||||
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
|
|
||||||
|
|
||||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC)); // confirm send to sender
|
|
||||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC)); // broadcast send to receiver
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getting buddy state
|
// Getting buddy state
|
||||||
void BuddyManager::reqPktGetBuddyState(CNSocket* sock, CNPacketData* data) {
|
void BuddyManager::reqPktGetBuddyState(CNSocket* sock, CNPacketData* data) {
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
@ -22,10 +22,6 @@ namespace BuddyManager {
|
|||||||
void reqAcceptBuddy(CNSocket* sock, CNPacketData* data);
|
void reqAcceptBuddy(CNSocket* sock, CNPacketData* data);
|
||||||
void reqFindNameBuddyAccept(CNSocket* sock, CNPacketData* data);
|
void reqFindNameBuddyAccept(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
// Buddy Messaging
|
|
||||||
void reqBuddyFreechat(CNSocket* sock, CNPacketData* data);
|
|
||||||
void reqBuddyMenuchat(CNSocket* sock, CNPacketData* data);
|
|
||||||
|
|
||||||
// Getting buddy state
|
// Getting buddy state
|
||||||
void reqPktGetBuddyState(CNSocket* sock, CNPacketData* data);
|
void reqPktGetBuddyState(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
|
1143
src/ChatManager.cpp
1143
src/ChatManager.cpp
File diff suppressed because it is too large
Load Diff
@ -1,34 +1,26 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CNShardServer.hpp"
|
|
||||||
|
|
||||||
#define CMD_PREFIX '/'
|
#define CMD_PREFIX '/'
|
||||||
|
|
||||||
typedef void (*CommandHandler)(std::string fullString, std::vector<std::string>& args, CNSocket* sock);
|
#include "CNShardServer.hpp"
|
||||||
|
|
||||||
struct ChatCommand {
|
|
||||||
int requiredAccLevel;
|
|
||||||
std::string help;
|
|
||||||
CommandHandler handlr;
|
|
||||||
|
|
||||||
ChatCommand(int r, CommandHandler h): requiredAccLevel(r), handlr(h) {}
|
|
||||||
ChatCommand(int r, CommandHandler h, std::string str): requiredAccLevel(r), help(str), handlr(h) {}
|
|
||||||
ChatCommand(): ChatCommand(0, nullptr) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ChatManager {
|
namespace ChatManager {
|
||||||
extern std::map<std::string, ChatCommand> commands;
|
|
||||||
extern std::vector<std::string> dump;
|
extern std::vector<std::string> dump;
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
bool runCmd(std::string full, CNSocket* sock);
|
|
||||||
void registerCommand(std::string cmd, int requiredLevel, CommandHandler handlr, std::string help = "");
|
|
||||||
|
|
||||||
void chatHandler(CNSocket* sock, CNPacketData* data);
|
void chatHandler(CNSocket* sock, CNPacketData* data);
|
||||||
void emoteHandler(CNSocket* sock, CNPacketData* data);
|
void emoteHandler(CNSocket* sock, CNPacketData* data);
|
||||||
void menuChatHandler(CNSocket* sock, CNPacketData* data);
|
void menuChatHandler(CNSocket* sock, CNPacketData* data);
|
||||||
void sendServerMessage(CNSocket* sock, std::string msg); // uses MOTD
|
|
||||||
void announcementHandler(CNSocket* sock, CNPacketData* data);
|
void announcementHandler(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
|
void buddyChatHandler(CNSocket* sock, CNPacketData* data);
|
||||||
|
void buddyMenuChatHandler(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
|
void tradeChatHandler(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
|
void groupChatHandler(CNSocket* sock, CNPacketData* data);
|
||||||
|
void groupMenuChatHandler(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
|
void sendServerMessage(CNSocket* sock, std::string msg); // uses MOTD
|
||||||
std::string sanitizeText(std::string text, bool allowNewlines=false);
|
std::string sanitizeText(std::string text, bool allowNewlines=false);
|
||||||
}
|
}
|
||||||
|
974
src/CustomCommands.cpp
Normal file
974
src/CustomCommands.cpp
Normal file
@ -0,0 +1,974 @@
|
|||||||
|
#include "CustomCommands.hpp"
|
||||||
|
#include "ChatManager.hpp"
|
||||||
|
#include "PlayerManager.hpp"
|
||||||
|
#include "TableData.hpp"
|
||||||
|
#include "NPCManager.hpp"
|
||||||
|
#include "MobManager.hpp"
|
||||||
|
#include "ItemManager.hpp"
|
||||||
|
#include "Database.hpp"
|
||||||
|
#include "TransportManager.hpp"
|
||||||
|
#include "MissionManager.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
typedef void (*CommandHandler)(std::string fullString, std::vector<std::string>& args, CNSocket* sock);
|
||||||
|
|
||||||
|
struct ChatCommand {
|
||||||
|
int requiredAccLevel;
|
||||||
|
std::string help;
|
||||||
|
CommandHandler handlr;
|
||||||
|
|
||||||
|
ChatCommand(int r, CommandHandler h): requiredAccLevel(r), handlr(h) {}
|
||||||
|
ChatCommand(int r, CommandHandler h, std::string str): requiredAccLevel(r), help(str), handlr(h) {}
|
||||||
|
ChatCommand(): ChatCommand(0, nullptr) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::map<std::string, ChatCommand> commands;
|
||||||
|
|
||||||
|
static std::vector<std::string> parseArgs(std::string full) {
|
||||||
|
std::stringstream ss(full);
|
||||||
|
std::istream_iterator<std::string> begin(ss);
|
||||||
|
std::istream_iterator<std::string> end;
|
||||||
|
return std::vector<std::string>(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CustomCommands::runCmd(std::string full, CNSocket* sock) {
|
||||||
|
std::vector<std::string> args = parseArgs(full);
|
||||||
|
std::string cmd = args[0].substr(1, args[0].size() - 1);
|
||||||
|
|
||||||
|
// check if the command exists
|
||||||
|
if (commands.find(cmd) != commands.end()) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
ChatCommand command = commands[cmd];
|
||||||
|
|
||||||
|
// sanity check + does the player have the required account level to use the command?
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void helpCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Commands available to you:");
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
for (auto& cmd : commands) {
|
||||||
|
if (cmd.second.requiredAccLevel >= plr->accountLevel)
|
||||||
|
ChatManager::sendServerMessage(sock, "/" + cmd.first + (cmd.second.help.length() > 0 ? " - " + cmd.second.help : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void accessCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Your access level is " + std::to_string(PlayerManager::getPlayer(sock)->accountLevel));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populationCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
ChatManager::sendServerMessage(sock, std::to_string(PlayerManager::players.size()) + " players online");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void levelCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/level: no level specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
char *tmp;
|
||||||
|
int level = std::strtol(args[1].c_str(), &tmp, 10);
|
||||||
|
if (*tmp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((level < 1 || level > 36) && plr->accountLevel > 30)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(level < 1 || level > 36))
|
||||||
|
plr->level = level;
|
||||||
|
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_CHANGE_LEVEL, resp);
|
||||||
|
|
||||||
|
resp.iPC_ID = plr->iID;
|
||||||
|
resp.iPC_Level = level;
|
||||||
|
|
||||||
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_CHANGE_LEVEL, sizeof(sP_FE2CL_REP_PC_CHANGE_LEVEL));
|
||||||
|
PlayerManager::sendToViewable(sock, (void*)&resp, P_FE2CL_REP_PC_CHANGE_LEVEL, sizeof(sP_FE2CL_REP_PC_CHANGE_LEVEL));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mssCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Too few arguments");
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Usage: /mss <route> <add/remove/goto/clear/test/export> <<height>>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate route number
|
||||||
|
char* routeNumC;
|
||||||
|
int routeNum = std::strtol(args[1].c_str(), &routeNumC, 10);
|
||||||
|
if (*routeNumC) {
|
||||||
|
// not an integer
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Invalid route number '" + args[1] + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.size() < 3) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Too few arguments");
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Usage: /mss <route> <add/remove/goto/clear/test> <<height>>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the route (if it doesn't exist yet, this will also make it)
|
||||||
|
std::vector<WarpLocation>* route = &TableData::RunningSkywayRoutes[routeNum];
|
||||||
|
|
||||||
|
// mss <route> add <height>
|
||||||
|
if (args[2] == "add") {
|
||||||
|
// make sure height token exists
|
||||||
|
if (args.size() < 4) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Point height must be specified");
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Usage: /mss <route> add <height>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// validate height token
|
||||||
|
char* heightC;
|
||||||
|
int height = std::strtol(args[3].c_str(), &heightC, 10);
|
||||||
|
if (*heightC) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Invalid height " + args[3]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
route->push_back({ plr->x, plr->y, height }); // add point
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Added point (" + std::to_string(plr->x) + ", " + std::to_string(plr->y) + ", " + std::to_string(height) + ") to route " + std::to_string(routeNum));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mss <route> remove
|
||||||
|
if (args[2] == "remove") {
|
||||||
|
if (route->empty()) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Route " + std::to_string(routeNum) + " is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WarpLocation pulled = route->back();
|
||||||
|
route->pop_back(); // remove point at top of stack
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Removed point (" + std::to_string(pulled.x) + ", " + std::to_string(pulled.y) + ", " + std::to_string(pulled.z) + ") from route " + std::to_string(routeNum));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mss <route> goto
|
||||||
|
if (args[2] == "goto") {
|
||||||
|
if (route->empty()) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Route " + std::to_string(routeNum) + " is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WarpLocation pulled = route->back();
|
||||||
|
PlayerManager::sendPlayerTo(sock, pulled.x, pulled.y, pulled.z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mss <route> clear
|
||||||
|
if (args[2] == "clear") {
|
||||||
|
route->clear();
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Cleared route " + std::to_string(routeNum));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mss <route> test
|
||||||
|
if (args[2] == "test") {
|
||||||
|
if (route->empty()) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Route " + std::to_string(routeNum) + " is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WarpLocation pulled = route->front();
|
||||||
|
PlayerManager::sendPlayerTo(sock, pulled.x, pulled.y, pulled.z);
|
||||||
|
TransportManager::testMssRoute(sock, route);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for compatibility: mss <route> export
|
||||||
|
if (args[2] == "export") {
|
||||||
|
ChatManager::sendServerMessage(sock, "Wrote gruntwork to " + settings::GRUNTWORKJSON);
|
||||||
|
TableData::flush();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mss ????
|
||||||
|
ChatManager::sendServerMessage(sock, "[MSS] Unknown command '" + args[2] + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void summonWCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/summonW: no mob type specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
char *rest;
|
||||||
|
int type = std::strtol(args[1].c_str(), &rest, 10);
|
||||||
|
if (*rest) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Invalid NPC number: " + args[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int limit = NPCManager::NPCData.back()["m_iNpcNumber"];
|
||||||
|
|
||||||
|
// permission & sanity check
|
||||||
|
if (type > limit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BaseNPC *npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, true);
|
||||||
|
|
||||||
|
// update angle
|
||||||
|
npc->appearanceData.iAngle = (plr->angle + 180) % 360;
|
||||||
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, plr->instanceID, npc->appearanceData.iAngle);
|
||||||
|
|
||||||
|
// if we're in a lair, we need to spawn the NPC in both the private instance and the template
|
||||||
|
if (PLAYERID(plr->instanceID) != 0) {
|
||||||
|
npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, true, true);
|
||||||
|
|
||||||
|
npc->appearanceData.iAngle = (plr->angle + 180) % 360;
|
||||||
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, npc->instanceID, npc->appearanceData.iAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "/summonW: placed mob with type: " + std::to_string(type) +
|
||||||
|
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
|
TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc; // only record the one in the template
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unsummonWCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
BaseNPC* npc = NPCManager::getNearestNPC(plr->viewableChunks, plr->x, plr->y, plr->z);
|
||||||
|
|
||||||
|
if (npc == nullptr) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/unsummonW: No NPCs found nearby");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TableData::RunningEggs.find(npc->appearanceData.iNPC_ID) != TableData::RunningEggs.end()) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/unsummonW: removed egg with type: " + std::to_string(npc->appearanceData.iNPCType) +
|
||||||
|
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
|
TableData::RunningEggs.erase(npc->appearanceData.iNPC_ID);
|
||||||
|
NPCManager::destroyNPC(npc->appearanceData.iNPC_ID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TableData::RunningMobs.find(npc->appearanceData.iNPC_ID) == TableData::RunningMobs.end()
|
||||||
|
&& TableData::RunningGroups.find(npc->appearanceData.iNPC_ID) == TableData::RunningGroups.end()) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/unsummonW: Closest NPC is not a gruntwork mob.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MobManager::Mobs.find(npc->appearanceData.iNPC_ID) != MobManager::Mobs.end()) {
|
||||||
|
int leadId = ((Mob*)npc)->groupLeader;
|
||||||
|
if (leadId != 0) {
|
||||||
|
if (MobManager::Mobs.find(leadId) == MobManager::Mobs.end()) {
|
||||||
|
std::cout << "[WARN] unsummonW: leader not found!" << std::endl;
|
||||||
|
}
|
||||||
|
Mob* leadNpc = MobManager::Mobs[leadId];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (leadNpc->groupMember[i] == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (MobManager::Mobs.find(leadNpc->groupMember[i]) == MobManager::Mobs.end()) {
|
||||||
|
std::cout << "[WARN] unsommonW: leader can't find a group member!" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NPCManager::destroyNPC(leadNpc->groupMember[i]);
|
||||||
|
}
|
||||||
|
TableData::RunningGroups.erase(leadId);
|
||||||
|
NPCManager::destroyNPC(leadId);
|
||||||
|
ChatManager::sendServerMessage(sock, "/unsummonW: Mob group destroyed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "/unsummonW: removed mob with type: " + std::to_string(npc->appearanceData.iNPCType) +
|
||||||
|
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
|
|
||||||
|
TableData::RunningMobs.erase(npc->appearanceData.iNPC_ID);
|
||||||
|
|
||||||
|
NPCManager::destroyNPC(npc->appearanceData.iNPC_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void toggleAiCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
MobManager::simulateMobs = !MobManager::simulateMobs;
|
||||||
|
|
||||||
|
if (MobManager::simulateMobs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// return all mobs to their spawn points
|
||||||
|
for (auto& pair : MobManager::Mobs) {
|
||||||
|
pair.second->state = MobState::RETREAT;
|
||||||
|
pair.second->target = nullptr;
|
||||||
|
pair.second->nextMovement = getTime();
|
||||||
|
|
||||||
|
// mobs with static paths can chill where they are
|
||||||
|
if (pair.second->staticPath) {
|
||||||
|
pair.second->roamX = pair.second->appearanceData.iX;
|
||||||
|
pair.second->roamY = pair.second->appearanceData.iY;
|
||||||
|
pair.second->roamZ = pair.second->appearanceData.iZ;
|
||||||
|
} else {
|
||||||
|
pair.second->roamX = pair.second->spawnX;
|
||||||
|
pair.second->roamY = pair.second->spawnY;
|
||||||
|
pair.second->roamZ = pair.second->spawnZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void npcRotateCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
BaseNPC* npc = NPCManager::getNearestNPC(plr->viewableChunks, plr->x, plr->y, plr->z);
|
||||||
|
|
||||||
|
if (npc == nullptr) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[NPCR] No NPCs found nearby");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int angle = (plr->angle + 180) % 360;
|
||||||
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ, npc->instanceID, angle);
|
||||||
|
|
||||||
|
// if it's a gruntwork NPC, rotate in-place
|
||||||
|
if (TableData::RunningMobs.find(npc->appearanceData.iNPC_ID) != TableData::RunningMobs.end()) {
|
||||||
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ, npc->instanceID, angle);
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for gruntwork NPC "
|
||||||
|
+ std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
|
} else {
|
||||||
|
TableData::RunningNPCRotations[npc->appearanceData.iNPC_ID] = angle;
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC "
|
||||||
|
+ std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
// update rotation clientside
|
||||||
|
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
||||||
|
pkt.NPCAppearanceData = npc->appearanceData;
|
||||||
|
sock->sendPacket((void*)&pkt, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refreshCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
ChunkPos currentChunk = plr->chunkPos;
|
||||||
|
ChunkPos nullChunk = std::make_tuple(0, 0, 0);
|
||||||
|
ChunkManager::updatePlayerChunk(sock, currentChunk, nullChunk);
|
||||||
|
ChunkManager::updatePlayerChunk(sock, nullChunk, currentChunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instanceCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
// no additional arguments: report current instance ID
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[INST] Current instance ID: " + std::to_string(plr->instanceID));
|
||||||
|
ChatManager::sendServerMessage(sock, "[INST] (Map " + std::to_string(MAPNUM(plr->instanceID)) + ", instance " + std::to_string(PLAYERID(plr->instanceID)) + ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move player to specified instance
|
||||||
|
// validate instance ID
|
||||||
|
char* instanceS;
|
||||||
|
uint64_t instance = std::strtoll(args[1].c_str(), &instanceS, 10);
|
||||||
|
if (*instanceS) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[INST] Invalid instance ID: " + args[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.size() >= 3) {
|
||||||
|
char* playeridS;
|
||||||
|
uint64_t playerid = std::strtoll(args[2].c_str(), &playeridS, 10);
|
||||||
|
|
||||||
|
if (playerid != 0) {
|
||||||
|
instance |= playerid << 32ULL;
|
||||||
|
ChunkManager::createInstance(instance);
|
||||||
|
|
||||||
|
// a precaution
|
||||||
|
plr->recallInstance = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerManager::sendPlayerTo(sock, plr->x, plr->y, plr->z, instance);
|
||||||
|
ChatManager::sendServerMessage(sock, "[INST] Switched to instance with ID " + std::to_string(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void npcInstanceCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[NPCI] Instance ID must be specified");
|
||||||
|
ChatManager::sendServerMessage(sock, "[NPCI] Usage: /npci <instance ID>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseNPC* npc = NPCManager::getNearestNPC(plr->viewableChunks, plr->x, plr->y, plr->z);
|
||||||
|
|
||||||
|
if (npc == nullptr) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[NPCI] No NPCs found nearby");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate instance ID
|
||||||
|
char* instanceS;
|
||||||
|
int instance = std::strtol(args[1].c_str(), &instanceS, 10);
|
||||||
|
if (*instanceS) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[NPCI] Invalid instance ID: " + args[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "[NPCI] Moving NPC with ID " + std::to_string(npc->appearanceData.iNPC_ID) + " to instance " + std::to_string(instance));
|
||||||
|
TableData::RunningNPCMapNumbers[npc->appearanceData.iNPC_ID] = instance;
|
||||||
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ, instance, npc->appearanceData.iAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void minfoCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
ChatManager::sendServerMessage(sock, "[MINFO] Current mission ID: " + std::to_string(plr->CurrentMissionID));
|
||||||
|
|
||||||
|
for (int i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||||
|
if (plr->tasks[i] != 0) {
|
||||||
|
TaskData& task = *MissionManager::Tasks[plr->tasks[i]];
|
||||||
|
if ((int)(task["m_iHMissionID"]) == plr->CurrentMissionID) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[MINFO] Current task ID: " + std::to_string(plr->tasks[i]));
|
||||||
|
ChatManager::sendServerMessage(sock, "[MINFO] Current task type: " + std::to_string((int)(task["m_iHTaskType"])));
|
||||||
|
ChatManager::sendServerMessage(sock, "[MINFO] Current waypoint NPC ID: " + std::to_string((int)(task["m_iSTGrantWayPoint"])));
|
||||||
|
ChatManager::sendServerMessage(sock, "[MINFO] Current terminator NPC ID: " + std::to_string((int)(task["m_iHTerminatorNPCID"])));
|
||||||
|
|
||||||
|
if ((int)(task["m_iSTGrantTimer"]) != 0)
|
||||||
|
ChatManager::sendServerMessage(sock, "[MINFO] Current task timer: " + std::to_string((int)(task["m_iSTGrantTimer"])));
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; j++)
|
||||||
|
if ((int)(task["m_iCSUEnemyID"][j]) != 0)
|
||||||
|
ChatManager::sendServerMessage(sock, "[MINFO] Current task mob #" + std::to_string(j+1) +": " + std::to_string((int)(task["m_iCSUEnemyID"][j])));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tasksCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
for (int i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||||
|
if (plr->tasks[i] != 0) {
|
||||||
|
TaskData& task = *MissionManager::Tasks[plr->tasks[i]];
|
||||||
|
ChatManager::sendServerMessage(sock, "[TASK-" + std::to_string(i) + "] mission ID: " + std::to_string((int)(task["m_iHMissionID"])));
|
||||||
|
ChatManager::sendServerMessage(sock, "[TASK-" + std::to_string(i) + "] task ID: " + std::to_string(plr->tasks[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buffCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
if (args.size() < 3) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/buff: no skill Id and duration time specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* tmp;
|
||||||
|
int skillId = std::strtol(args[1].c_str(), &tmp, 10);
|
||||||
|
if (*tmp)
|
||||||
|
return;
|
||||||
|
int duration = std::strtol(args[2].c_str(), &tmp, 10);
|
||||||
|
if (*tmp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (NPCManager::eggBuffPlayer(sock, skillId, 0, duration)<0)
|
||||||
|
ChatManager::sendServerMessage(sock, "/buff: unknown skill Id");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eggCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/egg: no egg type specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* tmp;
|
||||||
|
int eggType = std::strtol(args[1].c_str(), &tmp, 10);
|
||||||
|
if (*tmp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (NPCManager::EggTypes.find(eggType) == NPCManager::EggTypes.end()) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/egg: Unknown egg type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(NPCManager::nextId < INT32_MAX);
|
||||||
|
int id = NPCManager::nextId++;
|
||||||
|
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
// some math to place egg nicely in front of the player
|
||||||
|
// temporarly disabled for sake of gruntwork
|
||||||
|
int addX = 0; //-500.0f * sin(plr->angle / 180.0f * M_PI);
|
||||||
|
int addY = 0; //-500.0f * cos(plr->angle / 180.0f * M_PI);
|
||||||
|
|
||||||
|
Egg* egg = new Egg(plr->x + addX, plr->y + addY, plr->z, plr->instanceID, eggType, id, false); // change last arg to true after gruntwork
|
||||||
|
NPCManager::NPCs[id] = egg;
|
||||||
|
NPCManager::Eggs[id] = egg;
|
||||||
|
NPCManager::updateNPCPosition(id, plr->x + addX, plr->y + addY, plr->z, plr->instanceID, plr->angle);
|
||||||
|
|
||||||
|
// add to template
|
||||||
|
TableData::RunningEggs[id] = egg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void notifyCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
if (plr->notify) {
|
||||||
|
plr->notify = false;
|
||||||
|
ChatManager::sendServerMessage(sock, "[ADMIN] No longer receiving join notifications");
|
||||||
|
} else {
|
||||||
|
plr->notify = true;
|
||||||
|
ChatManager::sendServerMessage(sock, "[ADMIN] Receiving join notifications");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void playersCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[ADMIN] Players on the server:");
|
||||||
|
for (auto pair : PlayerManager::players)
|
||||||
|
ChatManager::sendServerMessage(sock, PlayerManager::getPlayerName(pair.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void summonGroupCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
if (args.size() < 4) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/summonGroup(W) <leadermob> <mob> <number> [distance]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
char *rest;
|
||||||
|
|
||||||
|
bool wCommand = (args[0] == "/summonGroupW");
|
||||||
|
int type = std::strtol(args[1].c_str(), &rest, 10);
|
||||||
|
int type2 = std::strtol(args[2].c_str(), &rest, 10);
|
||||||
|
int count = std::strtol(args[3].c_str(), &rest, 10);
|
||||||
|
int distance = 150;
|
||||||
|
if (args.size() > 4)
|
||||||
|
distance = std::strtol(args[4].c_str(), &rest, 10);
|
||||||
|
|
||||||
|
if (*rest) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Invalid NPC number: " + args[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int limit = NPCManager::NPCData.back()["m_iNpcNumber"];
|
||||||
|
|
||||||
|
// permission & sanity check
|
||||||
|
if (type > limit || type2 > limit || count > 5) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Invalid parameters; double check types and count");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mob* leadNpc = nullptr;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
int team = NPCManager::NPCData[type]["m_iTeam"];
|
||||||
|
int x = plr->x;
|
||||||
|
int y = plr->y;
|
||||||
|
int z = plr->z;
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
int angle = 360.0f / (count-1) * (i-1);
|
||||||
|
if (count == 3)
|
||||||
|
angle = 90 + 60 * i;
|
||||||
|
|
||||||
|
angle += (plr->angle + 180) % 360;
|
||||||
|
|
||||||
|
x += -1.0f * sin(angle / 180.0f * M_PI) * distance;
|
||||||
|
y += -1.0f * cos(angle / 180.0f * M_PI) * distance;
|
||||||
|
z = plr->z;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseNPC *npc = NPCManager::summonNPC(x, y, z, plr->instanceID, type, wCommand);
|
||||||
|
if (team == 2 && i > 0) {
|
||||||
|
leadNpc->groupMember[i-1] = npc->appearanceData.iNPC_ID;
|
||||||
|
Mob* mob = MobManager::Mobs[npc->appearanceData.iNPC_ID];
|
||||||
|
mob->groupLeader = leadNpc->appearanceData.iNPC_ID;
|
||||||
|
mob->offsetX = x - plr->x;
|
||||||
|
mob->offsetY = y - plr->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
npc->appearanceData.iAngle = (plr->angle + 180) % 360;
|
||||||
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z, plr->instanceID, npc->appearanceData.iAngle);
|
||||||
|
|
||||||
|
// if we're in a lair, we need to spawn the NPC in both the private instance and the template
|
||||||
|
if (PLAYERID(plr->instanceID) != 0) {
|
||||||
|
npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, wCommand, true);
|
||||||
|
|
||||||
|
if (team == 2 && i > 0) {
|
||||||
|
leadNpc->groupMember[i-1] = npc->appearanceData.iNPC_ID;
|
||||||
|
Mob* mob = MobManager::Mobs[npc->appearanceData.iNPC_ID];
|
||||||
|
mob->groupLeader = leadNpc->appearanceData.iNPC_ID;
|
||||||
|
mob->offsetX = x - plr->x;
|
||||||
|
mob->offsetY = y - plr->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
npc->appearanceData.iAngle = (plr->angle + 180) % 360;
|
||||||
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z, plr->instanceID, npc->appearanceData.iAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "/summonGroup(W): placed mob with type: " + std::to_string(type) +
|
||||||
|
", id: " + std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
|
|
||||||
|
if (i == 0 && team == 2) {
|
||||||
|
type = type2;
|
||||||
|
leadNpc = MobManager::Mobs[npc->appearanceData.iNPC_ID];
|
||||||
|
leadNpc->groupLeader = leadNpc->appearanceData.iNPC_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wCommand)
|
||||||
|
return; // not writing; don't add to running mobs
|
||||||
|
|
||||||
|
if (leadNpc == nullptr) {
|
||||||
|
std::cout << "/summonGroupW: can't find group leader! Won't be saved!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableData::RunningGroups[leadNpc->appearanceData.iNPC_ID] = leadNpc; // only record the leader
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flushCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
TableData::flush();
|
||||||
|
ChatManager::sendServerMessage(sock, "Wrote gruntwork to " + settings::GRUNTWORKJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void whoisCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
BaseNPC* npc = NPCManager::getNearestNPC(plr->viewableChunks, plr->x, plr->y, plr->z);
|
||||||
|
|
||||||
|
if (npc == nullptr) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] No NPCs found nearby");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] ID: " + std::to_string(npc->appearanceData.iNPC_ID));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] Type: " + std::to_string(npc->appearanceData.iNPCType));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] HP: " + std::to_string(npc->appearanceData.iHP));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] CBF: " + std::to_string(npc->appearanceData.iConditionBitFlag));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] Class: " + std::to_string(npc->npcClass));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] X: " + std::to_string(npc->appearanceData.iX));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] Y: " + std::to_string(npc->appearanceData.iY));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] Z: " + std::to_string(npc->appearanceData.iZ));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] Angle: " + std::to_string(npc->appearanceData.iAngle));
|
||||||
|
std::string chunkPosition = std::to_string(std::get<0>(npc->chunkPos)) + ", " + std::to_string(std::get<1>(npc->chunkPos)) + ", " + std::to_string(std::get<2>(npc->chunkPos));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] Chunk: {" + chunkPosition + "}");
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] MapNum: " + std::to_string(MAPNUM(npc->instanceID)));
|
||||||
|
ChatManager::sendServerMessage(sock, "[WHOIS] Instance: " + std::to_string(PLAYERID(npc->instanceID)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lairUnlockCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
if (!ChunkManager::chunkExists(plr->chunkPos))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Chunk* chnk = ChunkManager::chunks[plr->chunkPos];
|
||||||
|
int taskID = -1;
|
||||||
|
int missionID = -1;
|
||||||
|
int found = 0;
|
||||||
|
for (int32_t id : chnk->NPCs) {
|
||||||
|
if (NPCManager::NPCs.find(id) == NPCManager::NPCs.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BaseNPC* npc = NPCManager::NPCs[id];
|
||||||
|
for (auto it = NPCManager::Warps.begin(); it != NPCManager::Warps.end(); it++) {
|
||||||
|
if ((*it).second.npcID == npc->appearanceData.iNPCType) {
|
||||||
|
taskID = (*it).second.limitTaskID;
|
||||||
|
missionID = MissionManager::Tasks[taskID]->task["m_iHMissionID"];
|
||||||
|
found++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missionID == -1 || taskID == -1) {
|
||||||
|
ChatManager::sendServerMessage(sock, "You are NOT standing near a lair portal; move around and try again!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found > 1) {
|
||||||
|
ChatManager::sendServerMessage(sock, "More than one lair found; decrease chunk size and try again!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_TASK_START_SUCC, taskResp);
|
||||||
|
MissionManager::startTask(plr, taskID);
|
||||||
|
taskResp.iTaskNum = taskID;
|
||||||
|
taskResp.iRemainTime = 0;
|
||||||
|
sock->sendPacket((void*)&taskResp, P_FE2CL_REP_PC_TASK_START_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_START_SUCC));
|
||||||
|
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, missionResp);
|
||||||
|
missionResp.iCurrentMissionID = missionID;
|
||||||
|
plr->CurrentMissionID = missionID;
|
||||||
|
sock->sendPacket((void*)&missionResp, P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, sizeof(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hideCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
if (plr->hidden) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[HIDE] You're already hidden from the map.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plr->hidden = true;
|
||||||
|
ChatManager::sendServerMessage(sock, "[HIDE] Successfully hidden from the map.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unhideCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
if (!plr->hidden) {
|
||||||
|
ChatManager::sendServerMessage(sock, "[HIDE] You're already visible from the map.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plr->hidden = false;
|
||||||
|
ChatManager::sendServerMessage(sock, "[HIDE] Successfully un-hidden from the map.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void redeemCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/redeem: No code specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert string to all lowercase
|
||||||
|
const char* codeRaw = args[1].c_str();
|
||||||
|
if (args[1].size() > 256) { // prevent overflow
|
||||||
|
ChatManager::sendServerMessage(sock, "/redeem: Code too long");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[256];
|
||||||
|
for (int i = 0; i < args[1].size(); i++)
|
||||||
|
buf[i] = std::tolower(codeRaw[i]);
|
||||||
|
std::string code(buf, args[1].size());
|
||||||
|
|
||||||
|
if (ItemManager::CodeItems.find(code) == ItemManager::CodeItems.end()) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/redeem: Unknown code");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
if (Database::isCodeRedeemed(plr->iID, code)) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/redeem: You have already redeemed this code item");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itemCount = ItemManager::CodeItems[code].size();
|
||||||
|
std::vector<int> slots;
|
||||||
|
|
||||||
|
for (int i = 0; i < itemCount; i++) {
|
||||||
|
slots.push_back(ItemManager::findFreeSlot(plr));
|
||||||
|
if (slots[i] == -1) {
|
||||||
|
ChatManager::sendServerMessage(sock, "/redeem: Not enough space in inventory");
|
||||||
|
|
||||||
|
// delete any temp items we might have set
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
plr->Inven[slots[j]] = { 0, 0, 0, 0 }; // empty
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plr->Inven[slots[i]] = { 999, 999, 999, 0 }; // temp item; overwritten later
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::recordCodeRedemption(plr->iID, code);
|
||||||
|
|
||||||
|
for (int i = 0; i < itemCount; i++) {
|
||||||
|
std::pair<int32_t, int32_t> item = ItemManager::CodeItems[code][i];
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC, resp);
|
||||||
|
|
||||||
|
resp.eIL = 1;
|
||||||
|
resp.iSlotNum = slots[i];
|
||||||
|
resp.Item.iID = item.first;
|
||||||
|
resp.Item.iType = item.second;
|
||||||
|
// I think it is safe? :eyes
|
||||||
|
resp.Item.iOpt = 1;
|
||||||
|
|
||||||
|
// save serverside
|
||||||
|
plr->Inven[resp.iSlotNum] = resp.Item;
|
||||||
|
|
||||||
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_GIVE_ITEM_SUCC, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC));
|
||||||
|
}
|
||||||
|
std::string msg = itemCount == 1 ? "You have redeemed a code item" : "You have redeemed code items";
|
||||||
|
ChatManager::sendServerMessage(sock, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unwarpableCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
plr->unwarpable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warpableCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
plr->unwarpable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registerallCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
plr->iWarpLocationFlag = UINT32_MAX;
|
||||||
|
plr->aSkywayLocationFlag[0] = UINT64_MAX;
|
||||||
|
plr->aSkywayLocationFlag[1] = UINT64_MAX;
|
||||||
|
|
||||||
|
// update the client
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, resp);
|
||||||
|
|
||||||
|
resp.iWarpLocationFlag = plr->iWarpLocationFlag;
|
||||||
|
resp.aWyvernLocationFlag[0] = plr->aSkywayLocationFlag[0];
|
||||||
|
resp.aWyvernLocationFlag[1] = plr->aSkywayLocationFlag[1];
|
||||||
|
|
||||||
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, sizeof(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unregisterallCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
plr->iWarpLocationFlag = 0;
|
||||||
|
plr->aSkywayLocationFlag[0] = 0;
|
||||||
|
plr->aSkywayLocationFlag[1] = 0;
|
||||||
|
|
||||||
|
// update the client
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, resp);
|
||||||
|
|
||||||
|
resp.iWarpLocationFlag = plr->iWarpLocationFlag;
|
||||||
|
resp.aWyvernLocationFlag[0] = plr->aSkywayLocationFlag[0];
|
||||||
|
resp.aWyvernLocationFlag[1] = plr->aSkywayLocationFlag[1];
|
||||||
|
|
||||||
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, sizeof(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void banCommand(std::string full, std::vector<std::string>& args, CNSocket *sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Usage: /ban PlayerID [reason...]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *rest;
|
||||||
|
int playerId = std::strtol(args[1].c_str(), &rest, 10);
|
||||||
|
if (*rest) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Invalid PlayerID: " + args[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string reason;
|
||||||
|
if (args.size() == 2) {
|
||||||
|
reason = "no reason given";
|
||||||
|
} else {
|
||||||
|
reason = args[2];
|
||||||
|
for (int i = 3; i < args.size(); i++)
|
||||||
|
reason += " " + args[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ban the account that player belongs to
|
||||||
|
if (!Database::banPlayer(playerId, reason)) {
|
||||||
|
// propagating a more descriptive error message from banPlayer() would be too much work
|
||||||
|
ChatManager::sendServerMessage(sock, "Failed to ban target player. Check server logs.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, "Banned target player.");
|
||||||
|
std::cout << "[INFO] " << PlayerManager::getPlayerName(plr) << " banned player " << playerId << std::endl;
|
||||||
|
|
||||||
|
// if the player is online, kick them
|
||||||
|
CNSocket *otherSock = PlayerManager::getSockFromID(playerId);
|
||||||
|
if (otherSock == nullptr) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Player wasn't online. Didn't need to kick.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player *otherPlr = PlayerManager::getPlayer(otherSock);
|
||||||
|
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_EXIT_SUCC, pkt);
|
||||||
|
|
||||||
|
pkt.iID = otherPlr->iID;
|
||||||
|
pkt.iExitCode = 3; // "a GM has terminated your connection"
|
||||||
|
|
||||||
|
// send to target player
|
||||||
|
otherSock->sendPacket((void*)&pkt, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC));
|
||||||
|
|
||||||
|
// ensure that the connection has terminated
|
||||||
|
otherSock->kill();
|
||||||
|
|
||||||
|
ChatManager::sendServerMessage(sock, PlayerManager::getPlayerName(otherPlr) + " was online. Kicked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unbanCommand(std::string full, std::vector<std::string>& args, CNSocket *sock) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Usage: /unban PlayerID");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *rest;
|
||||||
|
int playerId = std::strtol(args[1].c_str(), &rest, 10);
|
||||||
|
if (*rest) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Invalid PlayerID: " + args[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Database::unbanPlayer(playerId)) {
|
||||||
|
ChatManager::sendServerMessage(sock, "Unbanned player.");
|
||||||
|
std::cout << "[INFO] " << PlayerManager::getPlayerName(plr) << " unbanned player " << playerId << std::endl;
|
||||||
|
} else {
|
||||||
|
ChatManager::sendServerMessage(sock, "Failed to unban player. Check server logs.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registerCommand(std::string cmd, int requiredLevel, CommandHandler handlr, std::string help) {
|
||||||
|
commands[cmd] = ChatCommand(requiredLevel, handlr, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomCommands::init() {
|
||||||
|
registerCommand("help", 100, helpCommand, "list all unlocked server-side commands");
|
||||||
|
registerCommand("access", 100, accessCommand, "print your access level");
|
||||||
|
registerCommand("instance", 30, instanceCommand, "print or change your current instance");
|
||||||
|
registerCommand("mss", 30, mssCommand, "edit Monkey Skyway routes");
|
||||||
|
registerCommand("npcr", 30, npcRotateCommand, "rotate NPCs");
|
||||||
|
registerCommand("npci", 30, npcInstanceCommand, "move NPCs across instances");
|
||||||
|
registerCommand("summonW", 30, summonWCommand, "permanently summon NPCs");
|
||||||
|
registerCommand("unsummonW", 30, unsummonWCommand, "delete permanently summoned NPCs");
|
||||||
|
registerCommand("toggleai", 30, toggleAiCommand, "enable/disable mob AI");
|
||||||
|
registerCommand("flush", 30, flushCommand, "save gruntwork to file");
|
||||||
|
registerCommand("level", 50, levelCommand, "change your character's level");
|
||||||
|
registerCommand("levelx", 50, levelCommand, "change your character's level"); // for Academy
|
||||||
|
registerCommand("population", 100, populationCommand, "check how many players are online");
|
||||||
|
registerCommand("refresh", 100, refreshCommand, "teleport yourself to your current location");
|
||||||
|
registerCommand("minfo", 30, minfoCommand, "show details of the current mission and task.");
|
||||||
|
registerCommand("buff", 50, buffCommand, "give yourself a buff effect");
|
||||||
|
registerCommand("egg", 30, eggCommand, "summon a coco egg");
|
||||||
|
registerCommand("tasks", 30, tasksCommand, "list all active missions and their respective task ids.");
|
||||||
|
registerCommand("notify", 30, notifyCommand, "receive a message whenever a player joins the server");
|
||||||
|
registerCommand("players", 30, playersCommand, "print all players on the server");
|
||||||
|
registerCommand("summonGroup", 30, summonGroupCommand, "summon group NPCs");
|
||||||
|
registerCommand("summonGroupW", 30, summonGroupCommand, "permanently summon group NPCs");
|
||||||
|
registerCommand("ban", 30, banCommand, "ban the account the given PlayerID belongs to");
|
||||||
|
registerCommand("unban", 30, unbanCommand, "unban the account the given PlayerID belongs to");
|
||||||
|
registerCommand("whois", 50, whoisCommand, "describe nearest NPC");
|
||||||
|
registerCommand("lair", 50, lairUnlockCommand, "get the required mission for the nearest fusion lair");
|
||||||
|
registerCommand("hide", 100, hideCommand, "hide yourself from the global player map");
|
||||||
|
registerCommand("unhide", 100, unhideCommand, "un-hide yourself from the global player map");
|
||||||
|
registerCommand("unwarpable", 100, unwarpableCommand, "prevent buddies from warping to you");
|
||||||
|
registerCommand("warpable", 100, warpableCommand, "re-allow buddies to warp to you");
|
||||||
|
registerCommand("registerall", 50, registerallCommand, "register all SCAMPER and MSS destinations");
|
||||||
|
registerCommand("unregisterall", 50, unregisterallCommand, "clear all SCAMPER and MSS destinations");
|
||||||
|
registerCommand("redeem", 100, redeemCommand, "redeem a code item");
|
||||||
|
}
|
9
src/CustomCommands.hpp
Normal file
9
src/CustomCommands.hpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CNProtocol.hpp"
|
||||||
|
|
||||||
|
namespace CustomCommands {
|
||||||
|
void init();
|
||||||
|
|
||||||
|
bool runCmd(std::string full, CNSocket* sock);
|
||||||
|
};
|
@ -1,6 +1,5 @@
|
|||||||
#include "CNShardServer.hpp"
|
#include "CNShardServer.hpp"
|
||||||
#include "CNStructs.hpp"
|
#include "CNStructs.hpp"
|
||||||
#include "ChatManager.hpp"
|
|
||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
#include "GroupManager.hpp"
|
#include "GroupManager.hpp"
|
||||||
#include "NanoManager.hpp"
|
#include "NanoManager.hpp"
|
||||||
@ -15,8 +14,6 @@ void GroupManager::init() {
|
|||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE, refuseGroup);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE, refuseGroup);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_JOIN, joinGroup);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_JOIN, joinGroup);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_LEAVE, leaveGroup);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_LEAVE, leaveGroup);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE, chatGroup);
|
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE, menuChatGroup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) {
|
void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) {
|
||||||
@ -159,68 +156,6 @@ void GroupManager::leaveGroup(CNSocket* sock, CNPacketData* data) {
|
|||||||
groupKickPlayer(plr);
|
groupKickPlayer(plr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupManager::chatGroup(CNSocket* sock, CNPacketData* data) {
|
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE))
|
|
||||||
return; // malformed packet
|
|
||||||
|
|
||||||
sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE*)data->buf;
|
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
|
||||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
|
||||||
|
|
||||||
if (otherPlr == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string fullChat = ChatManager::sanitizeText(U16toU8(chat->szFreeChat));
|
|
||||||
|
|
||||||
if (fullChat.length() > 1 && fullChat[0] == CMD_PREFIX) { // PREFIX
|
|
||||||
ChatManager::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;
|
|
||||||
ChatManager::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;
|
|
||||||
|
|
||||||
sendToGroup(otherPlr, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GroupManager::menuChatGroup(CNSocket* sock, CNPacketData* data) {
|
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE))
|
|
||||||
return; // malformed packet
|
|
||||||
|
|
||||||
sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE*)data->buf;
|
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
|
||||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
|
||||||
|
|
||||||
if (otherPlr == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string fullChat = ChatManager::sanitizeText(U16toU8(chat->szFreeChat));
|
|
||||||
std::string logLine = "[GroupMenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
|
||||||
|
|
||||||
std::cout << logLine << std::endl;
|
|
||||||
ChatManager::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;
|
|
||||||
|
|
||||||
sendToGroup(otherPlr, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GroupManager::sendToGroup(Player* plr, void* buf, uint32_t type, size_t size) {
|
void GroupManager::sendToGroup(Player* plr, void* buf, uint32_t type, size_t size) {
|
||||||
for (int i = 0; i < plr->groupCnt; i++) {
|
for (int i = 0; i < plr->groupCnt; i++) {
|
||||||
CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[i]);
|
CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[i]);
|
||||||
|
@ -15,8 +15,6 @@ namespace GroupManager {
|
|||||||
void refuseGroup(CNSocket* sock, CNPacketData* data);
|
void refuseGroup(CNSocket* sock, CNPacketData* data);
|
||||||
void joinGroup(CNSocket* sock, CNPacketData* data);
|
void joinGroup(CNSocket* sock, CNPacketData* data);
|
||||||
void leaveGroup(CNSocket* sock, CNPacketData* data);
|
void leaveGroup(CNSocket* sock, CNPacketData* data);
|
||||||
void chatGroup(CNSocket* sock, CNPacketData* data);
|
|
||||||
void menuChatGroup(CNSocket* sock, CNPacketData* data);
|
|
||||||
void sendToGroup(Player* plr, void* buf, uint32_t type, size_t size);
|
void sendToGroup(Player* plr, void* buf, uint32_t type, size_t size);
|
||||||
void groupTickInfo(Player* plr);
|
void groupTickInfo(Player* plr);
|
||||||
void groupKickPlayer(Player* plr);
|
void groupKickPlayer(Player* plr);
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include "NanoManager.hpp"
|
#include "NanoManager.hpp"
|
||||||
#include "NPCManager.hpp"
|
#include "NPCManager.hpp"
|
||||||
#include "Player.hpp"
|
#include "Player.hpp"
|
||||||
#include "ChatManager.hpp"
|
|
||||||
|
|
||||||
#include <string.h> // for memset()
|
#include <string.h> // for memset()
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -40,7 +39,6 @@ void ItemManager::init() {
|
|||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER, tradeRegisterItem);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER, tradeRegisterItem);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER, tradeUnregisterItem);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER, tradeUnregisterItem);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CASH_REGISTER, tradeRegisterCash);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CASH_REGISTER, tradeRegisterCash);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT, tradeChat);
|
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_CHEST_OPEN, chestOpenHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_CHEST_OPEN, chestOpenHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,40 +769,6 @@ void ItemManager::tradeRegisterCash(CNSocket* sock, CNPacketData* data) {
|
|||||||
plr->isTradeConfirm = false;
|
plr->isTradeConfirm = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemManager::tradeChat(CNSocket* sock, CNPacketData* data) {
|
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT))
|
|
||||||
return; // malformed packet
|
|
||||||
sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT* 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 = ChatManager::sanitizeText(U16toU8(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;
|
|
||||||
ChatManager::dump.push_back(logLine);
|
|
||||||
|
|
||||||
resp.iEmoteCode = pacdat->iEmoteCode;
|
|
||||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT));
|
|
||||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_CHEST_OPEN))
|
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_CHEST_OPEN))
|
||||||
return; // ignore the malformed packet
|
return; // ignore the malformed packet
|
||||||
|
@ -57,7 +57,6 @@ namespace ItemManager {
|
|||||||
void tradeRegisterItem(CNSocket* sock, CNPacketData* data);
|
void tradeRegisterItem(CNSocket* sock, CNPacketData* data);
|
||||||
void tradeUnregisterItem(CNSocket* sock, CNPacketData* data);
|
void tradeUnregisterItem(CNSocket* sock, CNPacketData* data);
|
||||||
void tradeRegisterCash(CNSocket* sock, CNPacketData* data);
|
void tradeRegisterCash(CNSocket* sock, CNPacketData* data);
|
||||||
void tradeChat(CNSocket* sock, CNPacketData* data);
|
|
||||||
void chestOpenHandler(CNSocket* sock, CNPacketData* data);
|
void chestOpenHandler(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
// crate opening logic with all helper functions
|
// crate opening logic with all helper functions
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "ChunkManager.hpp"
|
#include "ChunkManager.hpp"
|
||||||
#include "NanoManager.hpp"
|
#include "NanoManager.hpp"
|
||||||
#include "TableData.hpp"
|
#include "TableData.hpp"
|
||||||
#include "ChatManager.hpp"
|
|
||||||
#include "GroupManager.hpp"
|
#include "GroupManager.hpp"
|
||||||
#include "RacingManager.hpp"
|
#include "RacingManager.hpp"
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "CNShardServer.hpp"
|
#include "CNShardServer.hpp"
|
||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
#include "ChatManager.hpp"
|
#include "ChatManager.hpp"
|
||||||
|
#include "CustomCommands.hpp"
|
||||||
#include "MobManager.hpp"
|
#include "MobManager.hpp"
|
||||||
#include "ItemManager.hpp"
|
#include "ItemManager.hpp"
|
||||||
#include "MissionManager.hpp"
|
#include "MissionManager.hpp"
|
||||||
@ -94,6 +95,7 @@ int main() {
|
|||||||
TableData::init();
|
TableData::init();
|
||||||
PlayerManager::init();
|
PlayerManager::init();
|
||||||
ChatManager::init();
|
ChatManager::init();
|
||||||
|
CustomCommands::init();
|
||||||
MobManager::init();
|
MobManager::init();
|
||||||
ItemManager::init();
|
ItemManager::init();
|
||||||
MissionManager::init();
|
MissionManager::init();
|
||||||
|
Loading…
Reference in New Issue
Block a user