From a5c40b66f5050ab51f198161ca63618615ef6108 Mon Sep 17 00:00:00 2001 From: Gent Date: Wed, 16 Sep 2020 22:27:21 -0400 Subject: [PATCH] Add basic Monkey Skyway functionality --- src/TableData.cpp | 22 +++++++++ src/TransportManager.cpp | 98 ++++++++++++++++++++++++++++++++++++---- src/TransportManager.hpp | 11 +++++ src/settings.cpp | 2 + src/settings.hpp | 1 + tdata | 2 +- 6 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/TableData.cpp b/src/TableData.cpp index d018692..6c9f34c 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -42,6 +42,28 @@ void TableData::init() { std::cerr << "[WARN] Malformed NPCs.json file! Reason:" << err.what() << std::endl; } + // load paths + try { + std::ifstream inFile(settings::PATHJSON); + nlohmann::json pathData; + + // read file into json + inFile >> pathData; + + nlohmann::json pathDataSkyway = pathData["skyway"]; + for (nlohmann::json::iterator skywayPath = pathDataSkyway.begin(); skywayPath != pathDataSkyway.end(); skywayPath++) { + std::vector points; + nlohmann::json pathPoints = skywayPath.value()["points"]; + for (nlohmann::json::iterator point = pathPoints.begin(); point != pathPoints.end(); point++) + points.push_back({point.value()["iX"], point.value()["iY"], point.value()["iZ"] }); + TransportManager::SkywayPaths[skywayPath.value()["iRouteID"]] = points; + } + + std::cout << "[INFO] Loaded " << TransportManager::SkywayPaths.size() << " skyway paths" << std::endl; + } + catch (const std::exception& err) { + std::cerr << "[WARN] Malformed paths.json file! Reason:" << err.what() << std::endl; + } // load everything else from xdttable std::cout << "[INFO] Parsing xdt.json..." << std::endl; std::ifstream infile(settings::XDTJSON); diff --git a/src/TransportManager.cpp b/src/TransportManager.cpp index 07a16f4..77efe46 100644 --- a/src/TransportManager.cpp +++ b/src/TransportManager.cpp @@ -3,11 +3,16 @@ #include "PlayerManager.hpp" #include "TransportManager.hpp" +#include std::map TransportManager::Routes; std::map TransportManager::Locations; +std::map> TransportManager::SkywayPaths; +std::unordered_map> TransportManager::SkywayQueue; void TransportManager::init() { + REGISTER_SHARD_TIMER(tickSkywaySystem, 1000); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION, transportWarpHandler); } @@ -34,7 +39,7 @@ void TransportManager::transportRegisterLocationHandler(CNSocket* sock, CNPacket } // update registration bitfield using bit shifting + bitwise or - plr->iWarpLocationFlag |= (1UL << (transport->iLocationID - 1)); + plr->iWarpLocationFlag |= plr->IsGM ? INT32_MAX : (1UL << (transport->iLocationID - 1)); } else if (transport->eTT == 2) { // Monkey Skyway System if (transport->iLocationID < 1 || transport->iLocationID > 127) { // sanity check std::cout << "[WARN] Skyway location ID " << transport->iLocationID << " is out of bounds" << std::endl; @@ -52,7 +57,13 @@ void TransportManager::transportRegisterLocationHandler(CNSocket* sock, CNPacket * assuming the two bitfields are just stuck together to make a longer one... do a similar operation, but on the respective integer * this approach seems to work with initial testing, but we have yet to see a monkey ID greater than 63. */ - plr->aSkywayLocationFlag[transport->iLocationID > 63 ? 1 : 0] |= (1ULL << (transport->iLocationID > 63 ? transport->iLocationID - 65 : transport->iLocationID - 1)); + if (plr->IsGM) { + plr->aSkywayLocationFlag[0] = INT64_MAX; + plr->aSkywayLocationFlag[1] = INT64_MAX; + } + else { + plr->aSkywayLocationFlag[transport->iLocationID > 63 ? 1 : 0] |= (1ULL << (transport->iLocationID > 63 ? transport->iLocationID - 65 : transport->iLocationID - 1)); + } } else { std::cout << "[WARN] Unknown mode of transport; eTT = " << transport->eTT << std::endl; INITSTRUCT(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_FAIL, failResp); @@ -92,8 +103,7 @@ void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data) * iSlotNum -- inventory slot number */ - if (Routes.find(req->iTransporationID) == Routes.end() || Locations.find(Routes[req->iTransporationID].end) == Locations.end() - || Routes[req->iTransporationID].cost > plr->money) { // sanity check + if (Routes.find(req->iTransporationID) == Routes.end() || Routes[req->iTransporationID].cost > plr->money) { // sanity check INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_FAIL, failResp); failResp.iErrorCode = 0; // TODO: error code @@ -104,19 +114,30 @@ void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data) } TransportRoute route = Routes[req->iTransporationID]; - plr->money -= route.cost; - TransportLocation target = Locations[route.end]; + TransportLocation target; + PlayerView& plrv = PlayerManager::players[sock]; + std::vector* points = nullptr; switch (route.type) { case 1: // S.C.A.M.P.E.R. + target = Locations[route.end]; plr->x = target.x; plr->y = target.y; plr->z = target.z; + /* + * Not strictly necessary since there isn't a valid SCAMPER that puts you in the + * same map tile you were already in, but we might as well force an NPC reload. + */ + plrv.viewable.clear(); + plrv.viewableNPCs.clear(); break; case 2: // Monkey Skyway - // TODO: implement + if (SkywayPaths.find(route.mssRouteNum) != SkywayPaths.end()) // sanity check + points = &SkywayPaths[route.mssRouteNum]; + else + std::cout << "[WARN] MSS route " << route.mssRouteNum << " not pathed" << std::endl; break; default: std::cout << "[WARN] Unknown tranportation type " << route.type << std::endl; @@ -124,13 +145,13 @@ void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data) } INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC, resp); - // response parameters resp.eTT = route.type; resp.iCandy = plr->money; resp.iX = plr->x; resp.iY = plr->y; resp.iZ = plr->z; + sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC)); /* * Not strictly necessary since there isn't a valid SCAMPER that puts you in the @@ -141,6 +162,65 @@ void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data) PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock); plrv.currentChunks.clear(); plrv.chunkPos = std::make_pair(0, 0); + if (points == nullptr) // no skyway path set + return; - sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC)); + // Interpolate + std::queue queue; + WarpLocation last = { plr->x, plr->y, plr->z }; // start pos + for (std::vector::iterator point = points->begin(); point != points->end(); point++) { + // avoiding pow here + int distanceBetween = sqrt((last.x - point->x) * (last.x - point->x) + (last.y - point->y) * (last.y - point->y) + (last.z - point->z) * (last.z - point->z)); + int lerps = distanceBetween / (int)LERP_GAP; // integer division to ensure a whole number + for (int i = 0; i < lerps; i++) { + WarpLocation lerp; + float frac = 1.0f / (lerps + 1); + lerp.x = (last.x * (1.0f - frac)) + (point->x * frac); + lerp.y = (last.y * (1.0f - frac)) + (point->y * frac); + lerp.z = (last.z * (1.0f - frac)) + (point->z * frac); + queue.push(lerp); // add lerp'd point to the queue + } + queue.push(*point); + last = { point->x, point->y, point->z }; // update start pos + } + SkywayQueue[sock] = queue; +} + +void TransportManager::tickSkywaySystem(CNServer* serv, time_t currTime) { + + std::cout << SkywayQueue.size(); + // using an unordered list so we can remove finished players in one iteration + std::unordered_map>::iterator it = SkywayQueue.begin(); + while (it != SkywayQueue.end()) { + + std::queue* queue = &it->second; + Player* plr = PlayerManager::getPlayer(it->first); + if (plr == nullptr) { + // sanity check + it = SkywayQueue.erase(it); // remove player from tracking map + update iterator + } + else if (queue->empty()) { + // send dismount packet + INITSTRUCT(sP_FE2CL_REP_PC_RIDING_SUCC, rideSucc); + rideSucc.iPC_ID = plr == nullptr ? 0 : plr->iID; + rideSucc.eRT = 0; + it->first->sendPacket((void*)&rideSucc, P_FE2CL_REP_PC_RIDING_SUCC, sizeof(sP_FE2CL_REP_PC_RIDING_SUCC)); + // TODO: send packet to nearby players? + it = SkywayQueue.erase(it); // remove player from tracking map + update iterator + } + else { + WarpLocation point = queue->front(); // get point + queue->pop(); // remove point from front of queue + + INITSTRUCT(sP_FE2CL_PC_BROOMSTICK_MOVE, bmstk); + bmstk.iPC_ID = plr == nullptr ? 0 : plr->iID; + bmstk.iToX = point.x; + bmstk.iToY = point.y; + bmstk.iToZ = point.z; + it->first->sendPacket((void*)&bmstk, P_FE2CL_PC_BROOMSTICK_MOVE, sizeof(sP_FE2CL_PC_BROOMSTICK_MOVE)); + // TODO: send packet to nearby players? + + it++; // go to next entry in map + } + } } diff --git a/src/TransportManager.hpp b/src/TransportManager.hpp index 7ad34b0..aad44e7 100644 --- a/src/TransportManager.hpp +++ b/src/TransportManager.hpp @@ -1,6 +1,13 @@ #pragma once #include "CNShardServer.hpp" +#include "NPCManager.hpp" + +#include + +#define LERP_GAP 5000 + +struct WarpLocation; struct TransportRoute { int type, start, end, cost, mssSpeed, mssRouteNum; @@ -13,9 +20,13 @@ struct TransportLocation { namespace TransportManager { extern std::map Routes; extern std::map Locations; + extern std::map> SkywayPaths; + extern std::unordered_map> SkywayQueue; void init(); void transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data); void transportWarpHandler(CNSocket* sock, CNPacketData* data); + + void tickSkywaySystem(CNServer* serv, time_t currTime); } diff --git a/src/settings.cpp b/src/settings.cpp index e7a83ce..2219643 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -23,6 +23,7 @@ int settings::SPAWN_ANGLE = 130; std::string settings::NPCJSON = "tdata/NPCs.json"; std::string settings::XDTJSON = "tdata/xdt.json"; std::string settings::MOBJSON = "tdata/mobs.json"; +std::string settings::PATHJSON = "tdata/paths.json"; std::string settings::MOTDSTRING = "Welcome to OpenFusion!"; bool settings::GM = true; @@ -54,6 +55,7 @@ void settings::init() { NPCJSON = reader.Get("shard", "npcdata", NPCJSON); XDTJSON = reader.Get("shard", "xdtdata", XDTJSON); MOBJSON = reader.Get("shard", "mobdata", MOBJSON); + PATHJSON = reader.Get("shard", "pathdata", PATHJSON); MOTDSTRING = reader.Get("shard", "motd", MOTDSTRING); GM = reader.GetBoolean("shard", "gm", GM); } diff --git a/src/settings.hpp b/src/settings.hpp index 6700ab6..bba3288 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -18,6 +18,7 @@ namespace settings { extern std::string NPCJSON; extern std::string XDTJSON; extern std::string MOBJSON; + extern std::string PATHJSON; extern bool GM; void init(); diff --git a/tdata b/tdata index 19d9902..f9c5f6a 160000 --- a/tdata +++ b/tdata @@ -1 +1 @@ -Subproject commit 19d9902331c94174785323d39daccc2cd23c5872 +Subproject commit f9c5f6a245c36add9fd8663badeca96e19a5d7ed