Add NPC pathing queues

This commit is contained in:
Gent 2020-09-23 10:29:29 -04:00
parent 7dfc888552
commit 65bd2d120b
2 changed files with 115 additions and 6 deletions

View File

@ -9,9 +9,10 @@ std::map<int32_t, TransportRoute> TransportManager::Routes;
std::map<int32_t, TransportLocation> TransportManager::Locations; std::map<int32_t, TransportLocation> TransportManager::Locations;
std::map<int32_t, std::queue<WarpLocation>> TransportManager::SkywayPaths; std::map<int32_t, std::queue<WarpLocation>> TransportManager::SkywayPaths;
std::unordered_map<CNSocket*, std::queue<WarpLocation>> TransportManager::SkywayQueues; std::unordered_map<CNSocket*, std::queue<WarpLocation>> TransportManager::SkywayQueues;
std::unordered_map<int32_t, std::queue<WarpLocation>> TransportManager::NPCQueues;
void TransportManager::init() { 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_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION, transportWarpHandler); 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); BaseNPC* bus = new BaseNPC(220447, 162431, -3650, 1, NPC_BUS);
NPCManager::NPCs[bus->appearanceData.iNPC_ID] = bus; NPCManager::NPCs[bus->appearanceData.iNPC_ID] = bus;
ChunkManager::addNPC(bus->appearanceData.iX, bus->appearanceData.iY, bus->appearanceData.iNPC_ID); ChunkManager::addNPC(bus->appearanceData.iX, bus->appearanceData.iY, bus->appearanceData.iNPC_ID);
std::queue<WarpLocation> 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) { 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)); 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. * 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. * 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 // using an unordered map so we can remove finished players in one iteration
std::unordered_map<CNSocket*, std::queue<WarpLocation>>::iterator it = SkywayQueues.begin(); std::unordered_map<CNSocket*, std::queue<WarpLocation>>::iterator it = SkywayQueues.begin();
while (it != SkywayQueues.end()) { 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<int32_t, std::queue<WarpLocation>>::iterator it = NPCQueues.begin();
while (it != NPCQueues.end()) {
std::queue<WarpLocation>* 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<WarpLocation>* 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
}
}

View File

@ -20,11 +20,16 @@ namespace TransportManager {
extern std::map<int32_t, TransportLocation> Locations; extern std::map<int32_t, TransportLocation> Locations;
extern std::map<int32_t, std::queue<WarpLocation>> SkywayPaths; // predefined skyway paths with points extern std::map<int32_t, std::queue<WarpLocation>> SkywayPaths; // predefined skyway paths with points
extern std::unordered_map<CNSocket*, std::queue<WarpLocation>> SkywayQueues; // player sockets with queued broomstick points extern std::unordered_map<CNSocket*, std::queue<WarpLocation>> SkywayQueues; // player sockets with queued broomstick points
extern std::unordered_map<int32_t, std::queue<WarpLocation>> NPCQueues; // NPC ids with queued pathing points
void init(); void init();
void transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data); void transportRegisterLocationHandler(CNSocket*, CNPacketData*);
void transportWarpHandler(CNSocket* sock, CNPacketData* data); 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, WarpLocation, int);
} }