From f9c25875577b00e439488afec7c220ed4d18d2fb Mon Sep 17 00:00:00 2001 From: dongresource Date: Fri, 12 Mar 2021 23:18:00 +0100 Subject: [PATCH] [refactor] Extract BuiltinCommands.cpp from PlayerManager.cpp And move itemGMGiveHandler() from ItemManager. --- Makefile | 2 + src/BuiltinCommands.cpp | 356 ++++++++++++++++++++++++++++++++++++++++ src/BuiltinCommands.hpp | 9 + src/ItemManager.cpp | 41 ----- src/ItemManager.hpp | 1 - src/PlayerManager.cpp | 310 +--------------------------------- src/PlayerManager.hpp | 8 - src/main.cpp | 2 + 8 files changed, 371 insertions(+), 358 deletions(-) create mode 100644 src/BuiltinCommands.cpp create mode 100644 src/BuiltinCommands.hpp diff --git a/Makefile b/Makefile index 56ca877..a77c0cf 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ CXXSRC=\ src/ItemManager.cpp\ src/NPCManager.cpp\ src/PlayerManager.cpp\ + src/BuiltinCommands.cpp\ src/settings.cpp\ src/TransportManager.cpp\ src/TableData.cpp\ @@ -83,6 +84,7 @@ CXXHDR=\ src/NPCManager.hpp\ src/Player.hpp\ src/PlayerManager.hpp\ + src/BuiltinCommands.hpp\ src/settings.hpp\ src/TransportManager.hpp\ src/TableData.hpp\ diff --git a/src/BuiltinCommands.cpp b/src/BuiltinCommands.cpp new file mode 100644 index 0000000..aa3e380 --- /dev/null +++ b/src/BuiltinCommands.cpp @@ -0,0 +1,356 @@ +#include "BuiltinCommands.hpp" +#include "PlayerManager.hpp" +#include "ChatManager.hpp" +#include "ItemManager.hpp" +#include "MissionManager.hpp" + +// helper function, not a packet handler +void BuiltinCommands::setSpecialState(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH)) + return; // ignore the malformed packet + + sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH* setData = (sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH*)data->buf; + Player *plr = PlayerManager::getPlayer(sock); + + // HACK: work around the invisible weapon bug + if (setData->iSpecialStateFlag == CN_SPECIAL_STATE_FLAG__FULL_UI) + ItemManager::updateEquips(sock, plr); + + INITSTRUCT(sP_FE2CL_PC_SPECIAL_STATE_CHANGE, response); + + plr->iSpecialState ^= setData->iSpecialStateFlag; + + response.iPC_ID = setData->iPC_ID; + response.iReqSpecialStateFlag = setData->iSpecialStateFlag; + response.iSpecialState = plr->iSpecialState; + + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC)); + PlayerManager::sendToViewable(sock, (void*)&response, P_FE2CL_PC_SPECIAL_STATE_CHANGE, sizeof(sP_FE2CL_PC_SPECIAL_STATE_CHANGE)); +} + +static void setGMSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) { + if (PlayerManager::getPlayer(sock)->accountLevel > 30) + return; + + BuiltinCommands::setSpecialState(sock, data); +} + +static void gotoPlayer(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_GOTO)) + return; // ignore the malformed packet + + Player *plr = PlayerManager::getPlayer(sock); + if (plr->accountLevel > 50) + return; + + sP_CL2FE_REQ_PC_GOTO* gotoData = (sP_CL2FE_REQ_PC_GOTO*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_GOTO_SUCC, response); + + DEBUGLOG( + std::cout << "P_CL2FE_REQ_PC_GOTO:" << std::endl; + std::cout << "\tX: " << gotoData->iToX << std::endl; + std::cout << "\tY: " << gotoData->iToY << std::endl; + std::cout << "\tZ: " << gotoData->iToZ << std::endl; + ) + + PlayerManager::sendPlayerTo(sock, gotoData->iToX, gotoData->iToY, gotoData->iToZ, INSTANCE_OVERWORLD); +} + +static void setValuePlayer(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_SET_VALUE)) + return; // ignore the malformed packet + + Player *plr = PlayerManager::getPlayer(sock); + if (plr->accountLevel > 50) + return; + + sP_CL2FE_GM_REQ_PC_SET_VALUE* setData = (sP_CL2FE_GM_REQ_PC_SET_VALUE*)data->buf; + + INITSTRUCT(sP_FE2CL_GM_REP_PC_SET_VALUE, response); + + DEBUGLOG( + std::cout << "P_CL2FE_GM_REQ_PC_SET_VALUE:" << std::endl; + std::cout << "\tPC_ID: " << setData->iPC_ID << std::endl; + std::cout << "\tSetValueType: " << setData->iSetValueType << std::endl; + std::cout << "\tSetValue: " << setData->iSetValue << std::endl; + ) + + // Handle serverside value-changes + switch (setData->iSetValueType) { + case 1: + plr->HP = setData->iSetValue; + break; + case 2: + plr->batteryW = setData->iSetValue; + // caps + if (plr->batteryW > 9999) + plr->batteryW = 9999; + break; + case 3: + plr->batteryN = setData->iSetValue; + // caps + if (plr->batteryN > 9999) + plr->batteryN = 9999; + break; + case 4: + MissionManager::updateFusionMatter(sock, setData->iSetValue - plr->fusionmatter); + break; + case 5: + plr->money = setData->iSetValue; + break; + } + + response.iPC_ID = setData->iPC_ID; + response.iSetValue = setData->iSetValue; + response.iSetValueType = setData->iSetValueType; + + sock->sendPacket((void*)&response, P_FE2CL_GM_REP_PC_SET_VALUE, sizeof(sP_FE2CL_GM_REP_PC_SET_VALUE)); + + // if one lowers their own health to 0, make sure others can see it + if (plr->HP <= 0) { + INITSTRUCT(sP_FE2CL_PC_SUDDEN_DEAD, dead); + + dead.iPC_ID = plr->iID; + dead.iDamage = plr->HP; + dead.iHP = plr->HP = 0; + + PlayerManager::sendToViewable(sock, (void*)&dead, P_FE2CL_PC_SUDDEN_DEAD, sizeof(sP_FE2CL_PC_SUDDEN_DEAD)); + } +} + +static void setGMSpecialOnOff(CNSocket *sock, CNPacketData *data) { + if (data->size != sizeof(sP_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF)) + return; // sanity check + + Player *plr = PlayerManager::getPlayer(sock); + + // access check + if (plr->accountLevel > 30) + return; + + sP_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF *req = (sP_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF*)data->buf; + + CNSocket *otherSock = PlayerManager::getSockFromAny(req->eTargetSearchBy, req->iTargetPC_ID, req->iTargetPC_UID, + U16toU8(req->szTargetPC_FirstName), U16toU8(req->szTargetPC_LastName)); + if (otherSock == nullptr) { + ChatManager::sendServerMessage(sock, "player to teleport not found"); + return; + } + + Player *otherPlr = PlayerManager::getPlayer(otherSock); + if (req->iONOFF) + otherPlr->iSpecialState |= req->iSpecialStateFlag; + else + otherPlr->iSpecialState &= ~req->iSpecialStateFlag; + + // this is only used for muting players, so no need to update the client since that logic is server-side +} + +static void locatePlayer(CNSocket *sock, CNPacketData *data) { + if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_LOCATION)) + return; // sanity check + + Player *plr = PlayerManager::getPlayer(sock); + + // access check + if (plr->accountLevel > 30) + return; + + sP_CL2FE_GM_REQ_PC_LOCATION *req = (sP_CL2FE_GM_REQ_PC_LOCATION*)data->buf; + + CNSocket *otherSock = PlayerManager::getSockFromAny(req->eTargetSearchBy, req->iTargetPC_ID, req->iTargetPC_UID, + U16toU8(req->szTargetPC_FirstName), U16toU8(req->szTargetPC_LastName)); + if (otherSock == nullptr) { + ChatManager::sendServerMessage(sock, "player not found"); + return; + } + + INITSTRUCT(sP_FE2CL_GM_REP_PC_LOCATION, resp); + Player *otherPlr = PlayerManager::getPlayer(otherSock); + + resp.iTargetPC_UID = otherPlr->accountId; + resp.iTargetPC_ID = otherPlr->iID; + resp.iShardID = 0; // sharding is unsupported + resp.iMapType = !!PLAYERID(otherPlr->instanceID); // private instance or not + resp.iMapID = PLAYERID(otherPlr->instanceID); + resp.iMapNum = MAPNUM(otherPlr->instanceID); + resp.iX = otherPlr->x; + resp.iY = otherPlr->y; + resp.iZ = otherPlr->z; + + memcpy(resp.szTargetPC_FirstName, otherPlr->PCStyle.szFirstName, sizeof(resp.szTargetPC_FirstName)); + memcpy(resp.szTargetPC_LastName, otherPlr->PCStyle.szLastName, sizeof(resp.szTargetPC_LastName)); + + sock->sendPacket((void*)&resp, P_FE2CL_GM_REP_PC_LOCATION, sizeof(sP_FE2CL_GM_REP_PC_LOCATION)); +} + +static void kickPlayer(CNSocket *sock, CNPacketData *data) { + if (data->size != sizeof(sP_CL2FE_GM_REQ_KICK_PLAYER)) + return; // sanity check + + Player *plr = PlayerManager::getPlayer(sock); + + // access check + if (plr->accountLevel > 30) + return; + + sP_CL2FE_GM_REQ_KICK_PLAYER *req = (sP_CL2FE_GM_REQ_KICK_PLAYER*)data->buf; + + CNSocket *otherSock = PlayerManager::getSockFromAny(req->eTargetSearchBy, req->iTargetPC_ID, req->iTargetPC_UID, + U16toU8(req->szTargetPC_FirstName), U16toU8(req->szTargetPC_LastName)); + if (otherSock == nullptr) { + ChatManager::sendServerMessage(sock, "player not found"); + return; + } + + Player *otherPlr = PlayerManager::getPlayer(otherSock); + + if (plr->accountLevel > otherPlr->accountLevel) { + ChatManager::sendServerMessage(sock, "player has higher access level"); + return; + } + + INITSTRUCT(sP_FE2CL_REP_PC_EXIT_SUCC, response); + + response.iID = otherPlr->iID; + response.iExitCode = 3; // "a GM has terminated your connection" + + // send to target player + otherSock->sendPacket((void*)&response, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC)); + + // ensure that the connection has terminated + otherSock->kill(); +} + +static void warpToPlayer(CNSocket *sock, CNPacketData *data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_WARP_TO_PC)) + return; // sanity check + + Player *plr = PlayerManager::getPlayer(sock); + + // access check + if (plr->accountLevel > 30) + return; + + sP_CL2FE_REQ_PC_WARP_TO_PC *req = (sP_CL2FE_REQ_PC_WARP_TO_PC*)data->buf; + + Player *otherPlr = PlayerManager::getPlayerFromID(req->iPC_ID); + if (otherPlr == nullptr) { + ChatManager::sendServerMessage(sock, "player not found"); + return; + } + + PlayerManager::sendPlayerTo(sock, otherPlr->x, otherPlr->y, otherPlr->z, otherPlr->instanceID); +} + +// GM teleport command +static void teleportPlayer(CNSocket *sock, CNPacketData *data) { + if (data->size != sizeof(sP_CL2FE_GM_REQ_TARGET_PC_TELEPORT)) + return; // sanity check + + Player *plr = PlayerManager::getPlayer(sock); + + // access check + if (plr->accountLevel > 30) + return; + + sP_CL2FE_GM_REQ_TARGET_PC_TELEPORT *req = (sP_CL2FE_GM_REQ_TARGET_PC_TELEPORT*)data->buf; + + // player to teleport + CNSocket *targetSock = PlayerManager::getSockFromAny(req->eTargetPCSearchBy, req->iTargetPC_ID, req->iTargetPC_UID, + U16toU8(req->szTargetPC_FirstName), U16toU8(req->szTargetPC_LastName)); + if (targetSock == nullptr) { + ChatManager::sendServerMessage(sock, "player to teleport not found"); + return; + } + + CNSocket *goalSock = nullptr; + Player *goalPlr = nullptr; + Player *targetPlr = nullptr; + uint64_t instance = plr->instanceID; + const int unstickRange = 400; + + switch (req->eTeleportType) { + case eCN_GM_TeleportMapType__MyLocation: + PlayerManager::sendPlayerTo(targetSock, plr->x, plr->y, plr->z, instance); + break; + case eCN_GM_TeleportMapType__MapXYZ: + instance = req->iToMap; + // fallthrough + case eCN_GM_TeleportMapType__XYZ: + PlayerManager::sendPlayerTo(targetSock, req->iToX, req->iToY, req->iToZ, instance); + break; + case eCN_GM_TeleportMapType__SomeoneLocation: + // player to teleport to + goalSock = PlayerManager::getSockFromAny(req->eGoalPCSearchBy, req->iGoalPC_ID, req->iGoalPC_UID, + U16toU8(req->szGoalPC_FirstName), U16toU8(req->szGoalPC_LastName)); + if (goalSock == nullptr) { + ChatManager::sendServerMessage(sock, "teleportation target player not found"); + return; + } + goalPlr = PlayerManager::getPlayer(goalSock); + + PlayerManager::sendPlayerTo(targetSock, goalPlr->x, goalPlr->y, goalPlr->z, goalPlr->instanceID); + break; + case eCN_GM_TeleportMapType__Unstick: + targetPlr = PlayerManager::getPlayer(targetSock); + + PlayerManager::sendPlayerTo(targetSock, targetPlr->x - unstickRange/2 + rand() % unstickRange, + targetPlr->y - unstickRange/2 + rand() % unstickRange, targetPlr->z + 80); + break; + } +} + +static void itemGMGiveHandler(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_ITEM)) + return; // ignore the malformed packet + + sP_CL2FE_REQ_PC_GIVE_ITEM* itemreq = (sP_CL2FE_REQ_PC_GIVE_ITEM*)data->buf; + Player* plr = PlayerManager::getPlayer(sock); + + if (plr->accountLevel > 50) { + // TODO: send fail packet + return; + } + + if (itemreq->eIL == 2) { + // Quest item, not a real item, handle this later, stubbed for now + // sock->sendPacket(new CNPacketData((void*)resp, P_FE2CL_REP_PC_GIVE_ITEM_FAIL, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_FAIL), sock->getFEKey())); + } else if (itemreq->eIL == 1 && itemreq->Item.iType >= 0 && itemreq->Item.iType <= 10) { + + if (ItemManager::ItemData.find(std::pair(itemreq->Item.iID, itemreq->Item.iType)) == ItemManager::ItemData.end()) { + // invalid item + std::cout << "[WARN] Item id " << itemreq->Item.iID << " with type " << itemreq->Item.iType << " is invalid (give item)" << std::endl; + return; + } + + INITSTRUCT(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC, resp); + + resp.eIL = itemreq->eIL; + resp.iSlotNum = itemreq->iSlotNum; + if (itemreq->Item.iType == 10) { + // item is vehicle, set expiration date + // set time limit: current time + 7days + itemreq->Item.iTimeLimit = getTimestamp() + 604800; + } + resp.Item = itemreq->Item; + + plr->Inven[itemreq->iSlotNum] = itemreq->Item; + + sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_GIVE_ITEM_SUCC, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC)); + } +} + +void BuiltinCommands::init() { + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GOTO, gotoPlayer); + REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SET_VALUE, setValuePlayer); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_ITEM, itemGMGiveHandler); + + REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH, setGMSpecialSwitchPlayer); + REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF, setGMSpecialOnOff); + + REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_LOCATION, locatePlayer); + REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_KICK_PLAYER, kickPlayer); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_TO_PC, warpToPlayer); + REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_TARGET_PC_TELEPORT, teleportPlayer); +} diff --git a/src/BuiltinCommands.hpp b/src/BuiltinCommands.hpp new file mode 100644 index 0000000..558178f --- /dev/null +++ b/src/BuiltinCommands.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "CNProtocol.hpp" + +namespace BuiltinCommands { + void init(); + + void setSpecialState(CNSocket *sock, CNPacketData *data); +}; diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index 5ce35c0..516f4b7 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -25,7 +25,6 @@ std::map ItemManager::NanoCapsules; // crate id -> nano id void ItemManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler); - REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_ITEM, itemGMGiveHandler); // this one is for gumballs REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_USE, itemUseHandler); // Bank @@ -213,46 +212,6 @@ void ItemManager::itemDeleteHandler(CNSocket* sock, CNPacketData* data) { sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_ITEM_DELETE_SUCC, sizeof(sP_FE2CL_REP_PC_ITEM_DELETE_SUCC)); } -void ItemManager::itemGMGiveHandler(CNSocket* sock, CNPacketData* data) { - if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_ITEM)) - return; // ignore the malformed packet - - sP_CL2FE_REQ_PC_GIVE_ITEM* itemreq = (sP_CL2FE_REQ_PC_GIVE_ITEM*)data->buf; - Player* plr = PlayerManager::getPlayer(sock); - - if (plr->accountLevel > 50) { - // TODO: send fail packet - return; - } - - if (itemreq->eIL == 2) { - // Quest item, not a real item, handle this later, stubbed for now - // sock->sendPacket(new CNPacketData((void*)resp, P_FE2CL_REP_PC_GIVE_ITEM_FAIL, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_FAIL), sock->getFEKey())); - } else if (itemreq->eIL == 1 && itemreq->Item.iType >= 0 && itemreq->Item.iType <= 10) { - - if (ItemData.find(std::pair(itemreq->Item.iID, itemreq->Item.iType)) == ItemData.end()) { - // invalid item - std::cout << "[WARN] Item id " << itemreq->Item.iID << " with type " << itemreq->Item.iType << " is invalid (give item)" << std::endl; - return; - } - - INITSTRUCT(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC, resp); - - resp.eIL = itemreq->eIL; - resp.iSlotNum = itemreq->iSlotNum; - if (itemreq->Item.iType == 10) { - // item is vehicle, set expiration date - // set time limit: current time + 7days - itemreq->Item.iTimeLimit = getTimestamp() + 604800; - } - resp.Item = itemreq->Item; - - plr->Inven[itemreq->iSlotNum] = itemreq->Item; - - sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_GIVE_ITEM_SUCC, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC)); - } -} - void ItemManager::itemUseHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_ITEM_USE)) return; // ignore the malformed packet diff --git a/src/ItemManager.hpp b/src/ItemManager.hpp index 37da3ac..a3b517f 100644 --- a/src/ItemManager.hpp +++ b/src/ItemManager.hpp @@ -44,7 +44,6 @@ namespace ItemManager { void itemMoveHandler(CNSocket* sock, CNPacketData* data); void itemDeleteHandler(CNSocket* sock, CNPacketData* data); - void itemGMGiveHandler(CNSocket* sock, CNPacketData* data); void itemUseHandler(CNSocket* sock, CNPacketData* data); // Bank void itemBankOpenHandler(CNSocket* sock, CNPacketData* data); diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 24e26d0..8e6bb82 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -1,8 +1,6 @@ -#include "CNProtocol.hpp" #include "PlayerManager.hpp" #include "NPCManager.hpp" #include "CNShardServer.hpp" -#include "CNShared.hpp" #include "MissionManager.hpp" #include "ItemManager.hpp" #include "NanoManager.hpp" @@ -12,6 +10,7 @@ #include "BuddyManager.hpp" #include "MobManager.hpp" #include "RacingManager.hpp" +#include "BuiltinCommands.hpp" #include "settings.hpp" @@ -36,22 +35,14 @@ void PlayerManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVEPLATFORM, movePlatformPlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVETRANSPORTATION, moveSliderPlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SLOPE, moveSlopePlayer); - REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GOTO, gotoPlayer); - REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SET_VALUE, setValuePlayer); REGISTER_SHARD_PACKET(P_CL2FE_REP_LIVE_CHECK, heartbeatPlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_REGEN, revivePlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EXIT, exitGame); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH, setSpecialSwitchPlayer); - REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH, setGMSpecialSwitchPlayer); - REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF, setGMSpecialOnOff); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_ON, enterPlayerVehicle); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_OFF, exitPlayerVehicle); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_CHANGE_MENTOR, changePlayerGuide); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIRST_USE_FLAG_SET, setFirstUseFlag); - REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_LOCATION, locatePlayer); - REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_KICK_PLAYER, kickPlayer); - REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_TO_PC, warpToPlayer); - REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_TARGET_PC_TELEPORT, teleportPlayer); } void PlayerManager::addPlayer(CNSocket* key, Player plr) { @@ -670,89 +661,6 @@ void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) { sendToViewable(sock, (void*)&slopeResponse, P_FE2CL_PC_SLOPE, sizeof(sP_FE2CL_PC_SLOPE)); } -void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) { - if (data->size != sizeof(sP_CL2FE_REQ_PC_GOTO)) - return; // ignore the malformed packet - - Player *plr = getPlayer(sock); - if (plr->accountLevel > 50) - return; - - sP_CL2FE_REQ_PC_GOTO* gotoData = (sP_CL2FE_REQ_PC_GOTO*)data->buf; - INITSTRUCT(sP_FE2CL_REP_PC_GOTO_SUCC, response); - - DEBUGLOG( - std::cout << "P_CL2FE_REQ_PC_GOTO:" << std::endl; - std::cout << "\tX: " << gotoData->iToX << std::endl; - std::cout << "\tY: " << gotoData->iToY << std::endl; - std::cout << "\tZ: " << gotoData->iToZ << std::endl; - ) - - sendPlayerTo(sock, gotoData->iToX, gotoData->iToY, gotoData->iToZ, INSTANCE_OVERWORLD); -} - -void PlayerManager::setValuePlayer(CNSocket* sock, CNPacketData* data) { - if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_SET_VALUE)) - return; // ignore the malformed packet - - Player *plr = getPlayer(sock); - if (plr->accountLevel > 50) - return; - - sP_CL2FE_GM_REQ_PC_SET_VALUE* setData = (sP_CL2FE_GM_REQ_PC_SET_VALUE*)data->buf; - - INITSTRUCT(sP_FE2CL_GM_REP_PC_SET_VALUE, response); - - DEBUGLOG( - std::cout << "P_CL2FE_GM_REQ_PC_SET_VALUE:" << std::endl; - std::cout << "\tPC_ID: " << setData->iPC_ID << std::endl; - std::cout << "\tSetValueType: " << setData->iSetValueType << std::endl; - std::cout << "\tSetValue: " << setData->iSetValue << std::endl; - ) - - // Handle serverside value-changes - switch (setData->iSetValueType) { - case 1: - plr->HP = setData->iSetValue; - break; - case 2: - plr->batteryW = setData->iSetValue; - // caps - if (plr->batteryW > 9999) - plr->batteryW = 9999; - break; - case 3: - plr->batteryN = setData->iSetValue; - // caps - if (plr->batteryN > 9999) - plr->batteryN = 9999; - break; - case 4: - MissionManager::updateFusionMatter(sock, setData->iSetValue - plr->fusionmatter); - break; - case 5: - plr->money = setData->iSetValue; - break; - } - - response.iPC_ID = setData->iPC_ID; - response.iSetValue = setData->iSetValue; - response.iSetValueType = setData->iSetValueType; - - sock->sendPacket((void*)&response, P_FE2CL_GM_REP_PC_SET_VALUE, sizeof(sP_FE2CL_GM_REP_PC_SET_VALUE)); - - // if one lowers their own health to 0, make sure others can see it - if (plr->HP <= 0) { - INITSTRUCT(sP_FE2CL_PC_SUDDEN_DEAD, dead); - - dead.iPC_ID = plr->iID; - dead.iDamage = plr->HP; - dead.iHP = plr->HP = 0; - - sendToViewable(sock, (void*)&dead, P_FE2CL_PC_SUDDEN_DEAD, sizeof(sP_FE2CL_PC_SUDDEN_DEAD)); - } -} - void PlayerManager::heartbeatPlayer(CNSocket* sock, CNPacketData* data) { getPlayer(sock)->lastHeartbeat = getTime(); } @@ -912,38 +820,7 @@ void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) { } void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) { - setSpecialState(sock, data); -} - -void PlayerManager::setGMSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) { - - if (getPlayer(sock)->accountLevel > 30) - return; - - setSpecialState(sock, data); -} - -void PlayerManager::setSpecialState(CNSocket* sock, CNPacketData* data) { - if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH)) - return; // ignore the malformed packet - - sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH* setData = (sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH*)data->buf; - Player *plr = getPlayer(sock); - - // HACK: work around the invisible weapon bug - if (setData->iSpecialStateFlag == CN_SPECIAL_STATE_FLAG__FULL_UI) - ItemManager::updateEquips(sock, plr); - - INITSTRUCT(sP_FE2CL_PC_SPECIAL_STATE_CHANGE, response); - - plr->iSpecialState ^= setData->iSpecialStateFlag; - - response.iPC_ID = setData->iPC_ID; - response.iReqSpecialStateFlag = setData->iSpecialStateFlag; - response.iSpecialState = plr->iSpecialState; - - sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC)); - sendToViewable(sock, (void*)&response, P_FE2CL_PC_SPECIAL_STATE_CHANGE, sizeof(sP_FE2CL_PC_SPECIAL_STATE_CHANGE)); + BuiltinCommands::setSpecialState(sock, data); } void PlayerManager::changePlayerGuide(CNSocket *sock, CNPacketData *data) { @@ -994,189 +871,6 @@ void PlayerManager::setFirstUseFlag(CNSocket* sock, CNPacketData* data) { plr->iFirstUseFlag[1] |= (1ULL << (flag->iFlagCode - 65)); } -void PlayerManager::setGMSpecialOnOff(CNSocket *sock, CNPacketData *data) { - if (data->size != sizeof(sP_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF)) - return; // sanity check - - Player *plr = getPlayer(sock); - - // access check - if (plr->accountLevel > 30) - return; - - sP_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF *req = (sP_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF*)data->buf; - - CNSocket *otherSock = getSockFromAny(req->eTargetSearchBy, req->iTargetPC_ID, req->iTargetPC_UID, - U16toU8(req->szTargetPC_FirstName), U16toU8(req->szTargetPC_LastName)); - if (otherSock == nullptr) { - ChatManager::sendServerMessage(sock, "player to teleport not found"); - return; - } - - Player *otherPlr = getPlayer(otherSock); - if (req->iONOFF) - otherPlr->iSpecialState |= req->iSpecialStateFlag; - else - otherPlr->iSpecialState &= ~req->iSpecialStateFlag; - - // this is only used for muting players, so no need to update the client since that logic is server-side -} - -void PlayerManager::locatePlayer(CNSocket *sock, CNPacketData *data) { - if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_LOCATION)) - return; // sanity check - - Player *plr = getPlayer(sock); - - // access check - if (plr->accountLevel > 30) - return; - - sP_CL2FE_GM_REQ_PC_LOCATION *req = (sP_CL2FE_GM_REQ_PC_LOCATION*)data->buf; - - CNSocket *otherSock = getSockFromAny(req->eTargetSearchBy, req->iTargetPC_ID, req->iTargetPC_UID, - U16toU8(req->szTargetPC_FirstName), U16toU8(req->szTargetPC_LastName)); - if (otherSock == nullptr) { - ChatManager::sendServerMessage(sock, "player not found"); - return; - } - - INITSTRUCT(sP_FE2CL_GM_REP_PC_LOCATION, resp); - Player *otherPlr = getPlayer(otherSock); - - resp.iTargetPC_UID = otherPlr->accountId; - resp.iTargetPC_ID = otherPlr->iID; - resp.iShardID = 0; // sharding is unsupported - resp.iMapType = !!PLAYERID(otherPlr->instanceID); // private instance or not - resp.iMapID = PLAYERID(otherPlr->instanceID); - resp.iMapNum = MAPNUM(otherPlr->instanceID); - resp.iX = otherPlr->x; - resp.iY = otherPlr->y; - resp.iZ = otherPlr->z; - - memcpy(resp.szTargetPC_FirstName, otherPlr->PCStyle.szFirstName, sizeof(resp.szTargetPC_FirstName)); - memcpy(resp.szTargetPC_LastName, otherPlr->PCStyle.szLastName, sizeof(resp.szTargetPC_LastName)); - - sock->sendPacket((void*)&resp, P_FE2CL_GM_REP_PC_LOCATION, sizeof(sP_FE2CL_GM_REP_PC_LOCATION)); -} - -void PlayerManager::kickPlayer(CNSocket *sock, CNPacketData *data) { - if (data->size != sizeof(sP_CL2FE_GM_REQ_KICK_PLAYER)) - return; // sanity check - - Player *plr = getPlayer(sock); - - // access check - if (plr->accountLevel > 30) - return; - - sP_CL2FE_GM_REQ_KICK_PLAYER *req = (sP_CL2FE_GM_REQ_KICK_PLAYER*)data->buf; - - CNSocket *otherSock = getSockFromAny(req->eTargetSearchBy, req->iTargetPC_ID, req->iTargetPC_UID, - U16toU8(req->szTargetPC_FirstName), U16toU8(req->szTargetPC_LastName)); - if (otherSock == nullptr) { - ChatManager::sendServerMessage(sock, "player not found"); - return; - } - - Player *otherPlr = getPlayer(otherSock); - - if (plr->accountLevel > otherPlr->accountLevel) { - ChatManager::sendServerMessage(sock, "player has higher access level"); - return; - } - - INITSTRUCT(sP_FE2CL_REP_PC_EXIT_SUCC, response); - - response.iID = otherPlr->iID; - response.iExitCode = 3; // "a GM has terminated your connection" - - // send to target player - otherSock->sendPacket((void*)&response, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC)); - - // ensure that the connection has terminated - otherSock->kill(); -} - -void PlayerManager::warpToPlayer(CNSocket *sock, CNPacketData *data) { - if (data->size != sizeof(sP_CL2FE_REQ_PC_WARP_TO_PC)) - return; // sanity check - - Player *plr = getPlayer(sock); - - // access check - if (plr->accountLevel > 30) - return; - - sP_CL2FE_REQ_PC_WARP_TO_PC *req = (sP_CL2FE_REQ_PC_WARP_TO_PC*)data->buf; - - Player *otherPlr = getPlayerFromID(req->iPC_ID); - if (otherPlr == nullptr) { - ChatManager::sendServerMessage(sock, "player not found"); - return; - } - - sendPlayerTo(sock, otherPlr->x, otherPlr->y, otherPlr->z, otherPlr->instanceID); -} - -// GM teleport command -void PlayerManager::teleportPlayer(CNSocket *sock, CNPacketData *data) { - if (data->size != sizeof(sP_CL2FE_GM_REQ_TARGET_PC_TELEPORT)) - return; // sanity check - - Player *plr = getPlayer(sock); - - // access check - if (plr->accountLevel > 30) - return; - - sP_CL2FE_GM_REQ_TARGET_PC_TELEPORT *req = (sP_CL2FE_GM_REQ_TARGET_PC_TELEPORT*)data->buf; - - // player to teleport - CNSocket *targetSock = getSockFromAny(req->eTargetPCSearchBy, req->iTargetPC_ID, req->iTargetPC_UID, - U16toU8(req->szTargetPC_FirstName), U16toU8(req->szTargetPC_LastName)); - if (targetSock == nullptr) { - ChatManager::sendServerMessage(sock, "player to teleport not found"); - return; - } - - CNSocket *goalSock = nullptr; - Player *goalPlr = nullptr; - Player *targetPlr = nullptr; - uint64_t instance = plr->instanceID; - const int unstickRange = 400; - - switch (req->eTeleportType) { - case eCN_GM_TeleportMapType__MyLocation: - sendPlayerTo(targetSock, plr->x, plr->y, plr->z, instance); - break; - case eCN_GM_TeleportMapType__MapXYZ: - instance = req->iToMap; - // fallthrough - case eCN_GM_TeleportMapType__XYZ: - sendPlayerTo(targetSock, req->iToX, req->iToY, req->iToZ, instance); - break; - case eCN_GM_TeleportMapType__SomeoneLocation: - // player to teleport to - goalSock = getSockFromAny(req->eGoalPCSearchBy, req->iGoalPC_ID, req->iGoalPC_UID, - U16toU8(req->szGoalPC_FirstName), U16toU8(req->szGoalPC_LastName)); - if (goalSock == nullptr) { - ChatManager::sendServerMessage(sock, "teleportation target player not found"); - return; - } - goalPlr = getPlayer(goalSock); - - sendPlayerTo(targetSock, goalPlr->x, goalPlr->y, goalPlr->z, goalPlr->instanceID); - break; - case eCN_GM_TeleportMapType__Unstick: - targetPlr = getPlayer(targetSock); - - sendPlayerTo(targetSock, targetPlr->x - unstickRange/2 + rand() % unstickRange, - targetPlr->y - unstickRange/2 + rand() % unstickRange, targetPlr->z + 80); - break; - } -} - #pragma region Helper methods Player *PlayerManager::getPlayer(CNSocket* key) { if (players.find(key) != players.end()) diff --git a/src/PlayerManager.hpp b/src/PlayerManager.hpp index e57966f..06d7d47 100644 --- a/src/PlayerManager.hpp +++ b/src/PlayerManager.hpp @@ -37,20 +37,12 @@ namespace PlayerManager { void movePlatformPlayer(CNSocket* sock, CNPacketData* data); void moveSliderPlayer(CNSocket* sock, CNPacketData* data); void moveSlopePlayer(CNSocket* sock, CNPacketData* data); - void gotoPlayer(CNSocket* sock, CNPacketData* data); - void setValuePlayer(CNSocket* sock, CNPacketData* data); void heartbeatPlayer(CNSocket* sock, CNPacketData* data); void revivePlayer(CNSocket* sock, CNPacketData* data); void exitGame(CNSocket* sock, CNPacketData* data); void setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data); - void setGMSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data); - void setGMSpecialOnOff(CNSocket* sock, CNPacketData *data); void changePlayerGuide(CNSocket *sock, CNPacketData *data); - void locatePlayer(CNSocket *sock, CNPacketData *data); - void kickPlayer(CNSocket *sock, CNPacketData *data); - void warpToPlayer(CNSocket *sock, CNPacketData *data); - void teleportPlayer(CNSocket *sock, CNPacketData *data); void enterPlayerVehicle(CNSocket* sock, CNPacketData* data); void exitPlayerVehicle(CNSocket* sock, CNPacketData* data); diff --git a/src/main.cpp b/src/main.cpp index d0c1c77..1e2511e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include "CNLoginServer.hpp" #include "CNShardServer.hpp" #include "PlayerManager.hpp" +#include "BuiltinCommands.hpp" #include "ChatManager.hpp" #include "CustomCommands.hpp" #include "MobManager.hpp" @@ -94,6 +95,7 @@ int main() { std::cout << "[INFO] Intializing Packet Managers..." << std::endl; TableData::init(); PlayerManager::init(); + BuiltinCommands::init(); ChatManager::init(); CustomCommands::init(); MobManager::init();