diff --git a/Makefile b/Makefile index 58a3b8b..a08d557 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ SRC=\ src/CNStructs.cpp\ src/Defines.cpp\ src/main.cpp\ + src/MissionManager.cpp\ src/NanoManager.cpp\ src/ItemManager.cpp\ src/NPCManager.cpp\ @@ -43,6 +44,7 @@ HDR=\ src/Defines.hpp\ src/contrib/INIReader.hpp\ src/contrib/JSON.hpp\ + src/MissionManager.hpp\ src/NanoManager.hpp\ src/ItemManager.hpp\ src/NPCManager.hpp\ diff --git a/README.md b/README.md index b897783..e93b288 100644 --- a/README.md +++ b/README.md @@ -100,3 +100,13 @@ To make your landwalking experience more pleasant, you can make use of a few adm * A `/jump` of about 50 will send you soaring * [This map](res/dong_number_map.png) (credit to Danny O) is useful for `/warp` coordinates. * `/goto` is useful for more precise teleportation (ie. for getting into Infected Zones, etc.). + +### Item commands +* /itemN [type] [itemId] [amount] + (Refer to the [item list](https://docs.google.com/spreadsheets/d/1mpoJ9iTHl_xLI4wQ_9UvIDYNcsDYscdkyaGizs43TCg/)) + +### Nano commands +* /nano [id] (1-36) +* /nano_equip [id] (1-36) [slot] (0-2) +* /nano_unequip [slot] (0-2) +* /nano_active [slot] (0-2) diff --git a/src/MissionManager.cpp b/src/MissionManager.cpp new file mode 100644 index 0000000..bbd747b --- /dev/null +++ b/src/MissionManager.cpp @@ -0,0 +1,55 @@ +#include "CNShardServer.hpp" +#include "CNStructs.hpp" +#include "MissionManager.hpp" +#include "PlayerManager.hpp" + +void MissionManager::init() { + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_START, acceptMission); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_END, completeMission); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID, setMission); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_STOP, quitMission); +} + +void MissionManager::acceptMission(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_START)) + return; // malformed packet + + sP_CL2FE_REQ_PC_TASK_START* missionData = (sP_CL2FE_REQ_PC_TASK_START*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_TASK_START_SUCC, response); + + response.iTaskNum = missionData->iTaskNum; + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_START_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_START_SUCC)); +} + +void MissionManager::completeMission(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_END)) + return; // malformed packet + + sP_CL2FE_REQ_PC_TASK_END* missionData = (sP_CL2FE_REQ_PC_TASK_END*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response); + + response.iTaskNum = missionData->iTaskNum; + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC)); +} + +void MissionManager::setMission(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID)) + return; // malformed packet + + sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID* missionData = (sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, response); + + response.iCurrentMissionID = missionData->iCurrentMissionID; + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, sizeof(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID)); +} + +void MissionManager::quitMission(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_STOP)) + return; // malformed packet + + sP_CL2FE_REQ_PC_TASK_STOP* missionData = (sP_CL2FE_REQ_PC_TASK_STOP*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_TASK_STOP_SUCC, response); + + response.iTaskNum = missionData->iTaskNum; + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_STOP_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_STOP_SUCC)); +} \ No newline at end of file diff --git a/src/MissionManager.hpp b/src/MissionManager.hpp new file mode 100644 index 0000000..d799869 --- /dev/null +++ b/src/MissionManager.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "CNShardServer.hpp" + +namespace MissionManager { + void init(); + + void acceptMission(CNSocket* sock, CNPacketData* data); + void completeMission(CNSocket* sock, CNPacketData* data); + void setMission(CNSocket* sock, CNPacketData* data); + void quitMission(CNSocket* sock, CNPacketData* data); +} \ No newline at end of file diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 27c6ad9..a36bdee 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -75,7 +75,7 @@ void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) { return; // malformed packet sP_CL2FE_REQ_NANO_ACTIVE* pkt = (sP_CL2FE_REQ_NANO_ACTIVE*)data->buf; - PlayerView plr = PlayerManager::players[sock]; + Player plr = PlayerManager::getPlayer(sock); // Send to client INITSTRUCT(sP_FE2CL_REP_NANO_ACTIVE_SUCC, resp); @@ -85,28 +85,28 @@ void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) { if (pkt->iNanoSlotNum > 2) return; - int nanoId = plr.plr.equippedNanos[pkt->iNanoSlotNum]; + int nanoId = plr.equippedNanos[pkt->iNanoSlotNum]; if (nanoId > 36) return; // sanity check - sNano nano = plr.plr.Nanos[nanoId]; + sNano nano = plr.Nanos[nanoId]; // Send to other players INITSTRUCT(sP_FE2CL_NANO_ACTIVE, pkt1); - pkt1.iPC_ID = plr.plr.iID; + pkt1.iPC_ID = plr.iID; pkt1.Nano = nano; - for (CNSocket *s : PlayerManager::players[sock].viewable) + for (CNSocket* s : PlayerManager::players[sock].viewable) s->sendPacket((void*)&pkt1, P_FE2CL_NANO_ACTIVE, sizeof(sP_FE2CL_NANO_ACTIVE)); // update player - plr.plr.nano = nanoId; - PlayerManager::updatePlayer(sock, plr.plr); + plr.activeNano = nanoId; + PlayerManager::updatePlayer(sock, plr); DEBUGLOG( - std::cout << U16toU8(plr.plr.PCStyle.szFirstName) << U16toU8(plr.plr.PCStyle.szLastName) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl; + std::cout << U16toU8(plr.PCStyle.szFirstName) << U16toU8(plr.PCStyle.szLastName) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl; ) } @@ -115,7 +115,7 @@ void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { return; // malformed packet sP_CL2FE_REQ_NANO_SKILL_USE* skill = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf; - PlayerView plr = PlayerManager::players[sock]; + Player plr = PlayerManager::getPlayer(sock); // Send to client INITSTRUCT(sP_FE2CL_NANO_SKILL_USE_SUCC, resp); @@ -124,14 +124,10 @@ void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { resp.iArg3 = skill->iArg3; resp.iBulletID = skill->iBulletID; resp.iTargetCnt = skill->iTargetCnt; - resp.iPC_ID = plr.plr.iID; + resp.iPC_ID = plr.iID; resp.iNanoStamina = 150; // Hardcoded for now sock->sendPacket((void*)&resp, P_FE2CL_NANO_SKILL_USE_SUCC, sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC)); - - DEBUGLOG( - std::cout << U16toU8(plr.plr.PCStyle.szFirstName) << U16toU8(plr.plr.PCStyle.szLastName) << " requested to summon nano skill " << std::endl; - ) } void NanoManager::nanoSkillSetHandler(CNSocket* sock, CNPacketData* data) { @@ -179,21 +175,23 @@ void NanoManager::setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId) sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_TUNE_SUCC, sizeof(sP_FE2CL_REP_NANO_TUNE_SUCC)); + // Update the player + PlayerManager::updatePlayer(sock, plr); + DEBUGLOG( std::cout << U16toU8(plr.PCStyle.szFirstName) << U16toU8(plr.PCStyle.szLastName) << " set skill id " << skillId << " for nano: " << nanoId << std::endl; ) - // Update the player - PlayerManager::updatePlayer(sock, plr); } void NanoManager::resetNanoSkill(CNSocket* sock, int16_t nanoId) { if (nanoId > 36) return; - + Player plr = PlayerManager::getPlayer(sock); sNano nano = plr.Nanos[nanoId]; + // 0 is reset nano.iSkillID = 0; plr.Nanos[nanoId] = nano; diff --git a/src/Player.hpp b/src/Player.hpp index c80af83..ef6d5d5 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -17,9 +17,10 @@ struct Player { int slot; // player slot, not nano slot sPCStyle PCStyle; sPCStyle2 PCStyle2; - sNano Nanos[37]; + sNano Nanos[37]; // acquired nanos int equippedNanos[3]; - int nano; // active nano (index into Nanos) + int activeNano; // active nano (index into Nanos) + int8_t iPCState; int x, y, z, angle; sItemBase Equip[AEQUIP_COUNT]; diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 16b097f..196fed3 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -27,7 +27,12 @@ void PlayerManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GOTO, PlayerManager::gotoPlayer); REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SET_VALUE, PlayerManager::setSpecialPlayer); REGISTER_SHARD_PACKET(P_CL2FE_REP_LIVE_CHECK, PlayerManager::heartbeatPlayer); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_REGEN, PlayerManager::revivePlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EXIT, PlayerManager::exitGame); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH, PlayerManager::setSpecialSwitchPlayer); + + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_ON, PlayerManager::enterPlayerVehicle); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_OFF, PlayerManager::exitPlayerVehicle); } void PlayerManager::addPlayer(CNSocket* key, Player plr) { @@ -60,10 +65,6 @@ void PlayerManager::removePlayer(CNSocket* key) { std::cout << players.size() << " players" << std::endl; } -Player PlayerManager::getPlayer(CNSocket* key) { - return players[key].plr; -} - void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) { players[sock].plr.x = X; players[sock].plr.y = Y; @@ -125,7 +126,8 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) { newPlayer.PCAppearanceData.iZ = plr.z; newPlayer.PCAppearanceData.iAngle = plr.angle; newPlayer.PCAppearanceData.PCStyle = plr.PCStyle; - newPlayer.PCAppearanceData.Nano = plr.Nanos[plr.nano]; + newPlayer.PCAppearanceData.Nano = plr.Nanos[plr.activeNano]; + newPlayer.PCAppearanceData.iPCState = plr.iPCState; memcpy(newPlayer.PCAppearanceData.ItemEquip, plr.Equip, sizeof(sItemBase) * AEQUIP_COUNT); otherSock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW)); @@ -138,7 +140,8 @@ void PlayerManager::updatePlayerPosition(CNSocket* sock, int X, int Y, int Z) { newPlayer.PCAppearanceData.iZ = otherPlr.z; newPlayer.PCAppearanceData.iAngle = otherPlr.angle; newPlayer.PCAppearanceData.PCStyle = otherPlr.PCStyle; - newPlayer.PCAppearanceData.Nano = otherPlr.Nanos[otherPlr.nano]; + newPlayer.PCAppearanceData.Nano = otherPlr.Nanos[otherPlr.activeNano]; + newPlayer.PCAppearanceData.iPCState = otherPlr.iPCState; memcpy(newPlayer.PCAppearanceData.ItemEquip, otherPlr.Equip, sizeof(sItemBase) * AEQUIP_COUNT); sock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW)); @@ -184,7 +187,7 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { std::cout << "\tPC_UID: " << plr.PCStyle.iPC_UID << std::endl; ) - response.iID = rand(); + response.iID = rand(); response.uiSvrTime = getTime(); response.PCLoadData2CL.iUserLevel = 1; response.PCLoadData2CL.iHP = 3625; //TODO: Check player levelupdata and get this right @@ -203,7 +206,7 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) { for (int i = 0; i < AEQUIP_COUNT; i++) response.PCLoadData2CL.aEquip[i] = plr.Equip[i]; - for (int i = 0; i < AINVEN_COUNT; i++) + for (int i = 0; i < AINVEN_COUNT; i++) response.PCLoadData2CL.aInven[i] = plr.Inven[i]; // don't ask.. @@ -251,7 +254,7 @@ void PlayerManager::loadPlayer(CNSocket* sock, CNPacketData* data) { std::cout << "\tPC_ID: " << complete->iPC_ID << std::endl; ) - response.iPC_ID = complete->iPC_ID; + response.iPC_ID = complete->iPC_ID; sock->sendPacket((void*)&response, P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC, sizeof(sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC)); } @@ -518,7 +521,7 @@ void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) { std::cout << "\tZ: " << gotoData->iToZ << std::endl; ) - response.iX = gotoData->iToX; + response.iX = gotoData->iToX; response.iY = gotoData->iToY; response.iZ = gotoData->iToZ; @@ -539,7 +542,7 @@ void PlayerManager::setSpecialPlayer(CNSocket* sock, CNPacketData* data) { std::cout << "\tSetValue: " << setData->iSetValue << std::endl; ) - response.iPC_ID = setData->iPC_ID; + response.iPC_ID = setData->iPC_ID; response.iSetValue = setData->iSetValue; response.iSetValueType = setData->iSetValueType; @@ -553,7 +556,7 @@ void PlayerManager::heartbeatPlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::exitGame(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_EXIT)) return; - + sP_CL2FE_REQ_PC_EXIT* exitData = (sP_CL2FE_REQ_PC_EXIT*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_EXIT_SUCC, response); @@ -563,9 +566,81 @@ void PlayerManager::exitGame(CNSocket* sock, CNPacketData* data) { sock->sendPacket((void*)&response, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC)); } +void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_REGEN)) + return; + + Player plr = PlayerManager::getPlayer(sock); + + // players respawn at same spot they died at for now... + sP_CL2FE_REQ_PC_REGEN* reviveData = (sP_CL2FE_REQ_PC_REGEN*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_REGEN_SUCC, response); + response.bMoveLocation = reviveData->eIL; + response.PCRegenData.iMapNum = reviveData->iIndex; + response.PCRegenData.iHP = 1000 * plr.level; + response.PCRegenData.iX = plr.x; + response.PCRegenData.iY = plr.y; + response.PCRegenData.iZ = plr.z; + + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_REGEN_SUCC, sizeof(sP_FE2CL_REP_PC_REGEN_SUCC)); +} + +void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) { + sP_CL2FE_REQ_PC_VEHICLE_ON* vehicleData = (sP_CL2FE_REQ_PC_VEHICLE_ON*)data->buf; + INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_SUCC, response); + PlayerView plrv = PlayerManager::players[sock]; + + //send to other players + INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, pkt); + pkt.EquipSlotItem.iType = 1; + pkt.iEquipSlotNum = 8; + for (CNSocket* otherSock : plrv.viewable) { + otherSock->sendPacket((void*)&pkt, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE)); + } + + plrv.plr.iPCState = 8; + updatePlayer(sock, plrv.plr); + + sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC)); +} + +void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) { + sP_CL2FE_REQ_PC_VEHICLE_OFF* vehicleData = (sP_CL2FE_REQ_PC_VEHICLE_OFF*)data->buf; + INITSTRUCT(sP_FE2CL_PC_VEHICLE_OFF_SUCC, response); + PlayerView plrv = PlayerManager::players[sock]; + + //send to other players + INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, pkt); + pkt.EquipSlotItem.iType = 1; + pkt.iEquipSlotNum = 8; + for (CNSocket* otherSock : plrv.viewable) { + otherSock->sendPacket((void*)&pkt, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE)); + } + + plrv.plr.iPCState = 0; + updatePlayer(sock, plrv.plr); + + sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_OFF_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_OFF_SUCC)); +} + +void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) { + sP_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH* specialData = (sP_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, response); + + response.iPC_ID = specialData->iPC_ID; + response.iReqSpecialStateFlag = specialData->iSpecialStateFlag; + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC)); +} + +#pragma region Helper methods +Player PlayerManager::getPlayer(CNSocket* key) { + return players[key].plr; +} + void PlayerManager::updatePlayer(CNSocket* key, Player plr) { PlayerView plrv = players[key]; plrv.plr = plr; players[key] = plrv; } +#pragma endregion \ No newline at end of file diff --git a/src/PlayerManager.hpp b/src/PlayerManager.hpp index ae8fcdb..5a90ed8 100644 --- a/src/PlayerManager.hpp +++ b/src/PlayerManager.hpp @@ -41,5 +41,11 @@ namespace PlayerManager { void gotoPlayer(CNSocket* sock, CNPacketData* data); void setSpecialPlayer(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 enterPlayerVehicle(CNSocket* sock, CNPacketData* data); + void exitPlayerVehicle(CNSocket* sock, CNPacketData* data); } diff --git a/src/main.cpp b/src/main.cpp index e598470..929fd7c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include "PlayerManager.hpp" #include "ChatManager.hpp" #include "ItemManager.hpp" +#include "MissionManager.hpp" #include "NanoManager.hpp" #include "NPCManager.hpp" @@ -11,7 +12,7 @@ #if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS) #include "mingw/mingw.thread.h" #else - #include +#include #endif #include @@ -22,9 +23,9 @@ void startShard(CNShardServer* server) { int main() { #ifdef _WIN32 WSADATA wsaData; - if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) { - std::cerr << "OpenFusion: WSAStartup failed" << std::endl; - exit(EXIT_FAILURE); + if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { + std::cerr << "OpenFusion: WSAStartup failed" << std::endl; + exit(EXIT_FAILURE); } #endif settings::init(); @@ -33,6 +34,7 @@ int main() { PlayerManager::init(); ChatManager::init(); ItemManager::init(); + MissionManager::init(); NanoManager::init(); NPCManager::init(); @@ -41,12 +43,12 @@ int main() { CNShardServer shardServer(settings::SHARDPORT); std::thread shardThread(startShard, (CNShardServer*)&shardServer); - + loginServer.start(); shardServer.kill(); shardThread.join(); - + #ifdef _WIN32 WSACleanup(); #endif