From 65bd2d120bf15a236f11e806f132943c16f4e8e9 Mon Sep 17 00:00:00 2001 From: Gent Date: Wed, 23 Sep 2020 10:29:29 -0400 Subject: [PATCH] Add NPC pathing queues --- src/TransportManager.cpp | 110 +++++++++++++++++++++++++++++++++++++-- src/TransportManager.hpp | 11 ++-- 2 files changed, 115 insertions(+), 6 deletions(-) diff --git a/src/TransportManager.cpp b/src/TransportManager.cpp index 031231e..59fa11d 100644 --- a/src/TransportManager.cpp +++ b/src/TransportManager.cpp @@ -9,9 +9,10 @@ std::map TransportManager::Routes; std::map TransportManager::Locations; std::map> TransportManager::SkywayPaths; std::unordered_map> TransportManager::SkywayQueues; +std::unordered_map> TransportManager::NPCQueues; void TransportManager::init() { - REGISTER_SHARD_TIMER(tickSkywaySystem, 1000); + REGISTER_SHARD_TIMER(tickTransportationSystem, 1000); REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION, transportWarpHandler); @@ -19,6 +20,13 @@ void TransportManager::init() { BaseNPC* bus = new BaseNPC(220447, 162431, -3650, 1, NPC_BUS); NPCManager::NPCs[bus->appearanceData.iNPC_ID] = bus; ChunkManager::addNPC(bus->appearanceData.iX, bus->appearanceData.iY, bus->appearanceData.iNPC_ID); + std::queue busPoints; + WarpLocation start = { bus->appearanceData.iX, bus->appearanceData.iY, -3650 }; + WarpLocation end = { 220441, 188102, -3653 }; + busPoints.push(start); + TransportManager::lerp(&busPoints, start, end, 1000); + busPoints.push(end); + NPCQueues[bus->appearanceData.iNPC_ID] = busPoints; } void TransportManager::transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data) { @@ -178,13 +186,17 @@ void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data) sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC)); } +void TransportManager::tickTransportationSystem(CNServer* serv, time_t currTime) { + stepNPCPathing(); + stepSkywaySystem(); +} + /* * Go through every socket that has broomstick points queued up, and advance to the next point. * If the player has disconnected or finished the route, clean up and remove them from the queue. */ -void TransportManager::tickSkywaySystem(CNServer* serv, time_t currTime) { +void TransportManager::stepSkywaySystem() { - //std::cout << SkywayQueue.size(); // using an unordered map so we can remove finished players in one iteration std::unordered_map>::iterator it = SkywayQueues.begin(); while (it != SkywayQueues.end()) { @@ -232,3 +244,95 @@ void TransportManager::tickSkywaySystem(CNServer* serv, time_t currTime) { } } } + +void TransportManager::stepNPCPathing() { + + // all NPC pathing queues + std::unordered_map>::iterator it = NPCQueues.begin(); + while (it != NPCQueues.end()) { + + std::queue* queue = &it->second; + + BaseNPC* npc = nullptr; + if (NPCManager::NPCs.find(it->first) != NPCManager::NPCs.end()) + npc = NPCManager::NPCs[it->first]; + + if (npc == nullptr) { + // pluck out dead path + update iterator + it = NPCQueues.erase(it); + continue; + } + + WarpLocation point = queue->front(); // get point + queue->pop(); // remove point from front of queue + + // calculate displacement + int dXY = hypot(point.x - npc->appearanceData.iX, point.y - npc->appearanceData.iY); // XY plane distance + int distanceBetween = hypot(dXY, point.z - npc->appearanceData.iZ); // total distance + + // update NPC location to update viewables + npc->appearanceData.iX = point.x; + npc->appearanceData.iY = point.y; + npc->appearanceData.iZ = point.z; + + auto chunk = ChunkManager::grabChunk(npc->appearanceData.iX, npc->appearanceData.iY); + auto chunks = ChunkManager::grabChunks(chunk); + + switch (npc->npcClass) { + case NPC_BUS: + INITSTRUCT(sP_FE2CL_TRANSPORTATION_MOVE, busMove); + busMove.eTT = 3; + busMove.iT_ID = npc->appearanceData.iNPC_ID; + busMove.iMoveStyle = 0; // ??? + busMove.iToX = point.x; + busMove.iToY = point.y; + busMove.iToZ = point.z; + busMove.iSpeed = distanceBetween; // set to distance to match how monkeys work + + // send packet to players in view + for (Chunk* chunk : chunks) { + for (CNSocket* s : chunk->players) { + s->sendPacket(&busMove, P_FE2CL_TRANSPORTATION_MOVE, sizeof(sP_FE2CL_TRANSPORTATION_MOVE)); + } + } + break; + default: + INITSTRUCT(sP_FE2CL_NPC_MOVE, move); + move.iNPC_ID = npc->appearanceData.iNPC_ID; + move.iMoveStyle = 0; // ??? + move.iToX = point.x; + move.iToY = point.y; + move.iToZ = point.z; + move.iSpeed = 600; // TODO: figure out a way to make this variable + + // send packet to players in view + for (Chunk* chunk : chunks) { + for (CNSocket* s : chunk->players) { + s->sendPacket(&move, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE)); + } + } + break; + } + + queue->push(point); // move processed point to the back to maintain cycle + it++; // go to next entry in map + } +} + +/* + * Linearly interpolate between two points and insert the results into a queue. + */ +static void TransportManager::lerp(std::queue* queue, WarpLocation start, WarpLocation end, int gapSize) { + int dXY = hypot(end.x - start.x, end.y - start.y); // XY plane distance + int distanceBetween = hypot(dXY, end.z - start.z); // total distance + int lerps = distanceBetween / gapSize; // integer division to ensure a whole number of in-between points + for (int i = 0; i < lerps; i++) { + WarpLocation lerp; + // lerp math + float frac = (i + 1) * 1.0f / (lerps + 1); + lerp.x = (start.x * (1.0f - frac)) + (end.x * frac); + lerp.y = (start.y * (1.0f - frac)) + (end.y * frac); + lerp.z = (start.z * (1.0f - frac)) + (end.z * frac); + queue->push(lerp); // add lerp'd point + } +} diff --git a/src/TransportManager.hpp b/src/TransportManager.hpp index 0f0f67d..9c42b02 100644 --- a/src/TransportManager.hpp +++ b/src/TransportManager.hpp @@ -20,11 +20,16 @@ namespace TransportManager { extern std::map Locations; extern std::map> SkywayPaths; // predefined skyway paths with points extern std::unordered_map> SkywayQueues; // player sockets with queued broomstick points + extern std::unordered_map> NPCQueues; // NPC ids with queued pathing points void init(); - void transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data); - void transportWarpHandler(CNSocket* sock, CNPacketData* data); + void transportRegisterLocationHandler(CNSocket*, CNPacketData*); + void transportWarpHandler(CNSocket*, CNPacketData*); - void tickSkywaySystem(CNServer* serv, time_t currTime); + void tickTransportationSystem(CNServer*, time_t); + void stepNPCPathing(); + void stepSkywaySystem(); + + static void lerp(std::queue*, WarpLocation, WarpLocation, int); }