From 5f1063acb9440d80078e253557b96aa769377635 Mon Sep 17 00:00:00 2001 From: KimLS Date: Tue, 18 Jul 2017 00:01:59 -0700 Subject: [PATCH] Add pathfinding interfaces, still heavily wip --- zone/CMakeLists.txt | 3 + zone/bot.cpp | 28 +- zone/client_packet.cpp | 244 +++++++------- zone/command.cpp | 612 +++++++++++++++++----------------- zone/entity.cpp | 20 -- zone/entity.h | 1 - zone/fearpath.cpp | 25 +- zone/lua_mob.cpp | 13 - zone/lua_mob.h | 2 - zone/merc.cpp | 16 +- zone/mob.cpp | 12 - zone/mob.h | 15 +- zone/mob_ai.cpp | 38 +-- zone/pathfinder_interface.cpp | 7 + zone/pathfinder_interface.h | 18 + zone/pathfinder_nav_mesh.h | 3 + zone/pathfinder_null.cpp | 15 + zone/pathfinder_null.h | 13 + zone/pathfinder_waypoint.h | 13 + zone/pathing.cpp | 495 ++++----------------------- zone/pathing.h | 27 +- zone/perl_mob.cpp | 38 --- zone/questmgr.cpp | 133 ++++---- zone/waypoints.cpp | 85 +---- zone/zone.cpp | 6 +- zone/zone.h | 4 +- 26 files changed, 705 insertions(+), 1181 deletions(-) create mode 100644 zone/pathfinder_interface.cpp create mode 100644 zone/pathfinder_null.cpp create mode 100644 zone/pathfinder_null.h diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index 5eb161cf5..907a47192 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -84,7 +84,9 @@ SET(zone_sources npc_ai.cpp object.cpp oriented_bounding_box.cpp + pathfinder_interface.cpp pathfinder_nav_mesh.cpp + pathfinder_null.cpp pathfinder_waypoint.cpp pathing.cpp perl_client.cpp @@ -201,6 +203,7 @@ SET(zone_headers oriented_bounding_box.h pathfinder_interface.h pathfinder_nav_mesh.h + pathfinder_null.h pathfinder_waypoint.h pathing.h perlpacket.h diff --git a/zone/bot.cpp b/zone/bot.cpp index f5a9285a3..834aa7bd6 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2165,7 +2165,7 @@ void Bot::AI_Process() { } else if(!IsRooted()) { if(GetTarget() && GetTarget()->GetHateTop() && GetTarget()->GetHateTop() != this) { Log(Logs::Detail, Logs::AI, "Returning to location prior to being summoned."); - CalculateNewPosition2(m_PreSummonLocation.x, m_PreSummonLocation.y, m_PreSummonLocation.z, GetBotRunspeed()); + CalculateNewPosition(m_PreSummonLocation.x, m_PreSummonLocation.y, m_PreSummonLocation.z, GetBotRunspeed()); SetHeading(CalculateHeadingToTarget(m_PreSummonLocation.x, m_PreSummonLocation.y)); return; } @@ -2256,12 +2256,12 @@ void Bot::AI_Process() { if (WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetBotRunspeed()); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetBotRunspeed()); } else { Mob* follow = entity_list.GetMob(GetFollowID()); if (follow) - CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), GetBotRunspeed()); + CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), GetBotRunspeed()); } return; @@ -2352,7 +2352,7 @@ void Bot::AI_Process() { float newZ = 0; FaceTarget(GetTarget()); if (PlotPositionAroundTarget(this, newX, newY, newZ)) { - CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed()); + CalculateNewPosition(newX, newY, newZ, GetBotRunspeed()); return; } } @@ -2364,7 +2364,7 @@ void Bot::AI_Process() { float newY = 0; float newZ = 0; if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ)) { - CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed()); + CalculateNewPosition(newX, newY, newZ, GetBotRunspeed()); return; } } @@ -2375,7 +2375,7 @@ void Bot::AI_Process() { float newY = 0; float newZ = 0; if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) { - CalculateNewPosition2(newX, newY, newZ, GetBotRunspeed()); + CalculateNewPosition(newX, newY, newZ, GetBotRunspeed()); return; } } @@ -2500,7 +2500,7 @@ void Bot::AI_Process() { if (AI_movement_timer->Check()) { if(!IsRooted()) { Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); - CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetBotRunspeed()); + CalculateNewPosition(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetBotRunspeed()); return; } @@ -2560,10 +2560,10 @@ void Bot::AI_Process() { if (WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed); } else { - CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed); + CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), speed); } if (rest_timer.Enabled()) @@ -2643,14 +2643,14 @@ void Bot::PetAIProcess() { if(botPet->GetClass() == ROGUE && !petHasAggro && !botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) { // Move the rogue to behind the mob if(botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ)) { - botPet->CalculateNewPosition2(newX, newY, newZ, botPet->GetRunspeed()); + botPet->CalculateNewPosition(newX, newY, newZ, botPet->GetRunspeed()); return; } } else if(GetTarget() == botPet->GetTarget() && !petHasAggro && !botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) { // If the bot owner and the bot are fighting the same mob, then move the pet to the rear arc of the mob if(botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ)) { - botPet->CalculateNewPosition2(newX, newY, newZ, botPet->GetRunspeed()); + botPet->CalculateNewPosition(newX, newY, newZ, botPet->GetRunspeed()); return; } } @@ -2665,7 +2665,7 @@ void Bot::PetAIProcess() { moveBehindMob = true; if(botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ, moveBehindMob)) { - botPet->CalculateNewPosition2(newX, newY, newZ, botPet->GetRunspeed()); + botPet->CalculateNewPosition(newX, newY, newZ, botPet->GetRunspeed()); return; } } @@ -2748,7 +2748,7 @@ void Bot::PetAIProcess() { botPet->SetRunAnimSpeed(0); if(!botPet->IsRooted()) { Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", botPet->GetTarget()->GetCleanName()); - botPet->CalculateNewPosition2(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetOwner()->GetRunspeed()); + botPet->CalculateNewPosition(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetOwner()->GetRunspeed()); return; } else { botPet->SetHeading(botPet->GetTarget()->GetHeading()); @@ -2776,7 +2776,7 @@ void Bot::PetAIProcess() { float dist = DistanceSquared(botPet->GetPosition(), botPet->GetTarget()->GetPosition()); botPet->SetRunAnimSpeed(0); if(dist > 184) { - botPet->CalculateNewPosition2(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetTarget()->GetRunspeed()); + botPet->CalculateNewPosition(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetTarget()->GetRunspeed()); return; } else { botPet->SetHeading(botPet->GetTarget()->GetHeading()); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index e8ae68e69..dbf09faa3 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -5688,128 +5688,128 @@ void Client::Handle_OP_FeignDeath(const EQApplicationPacket *app) void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app) { - if (app->size != sizeof(FindPersonRequest_Struct)) - printf("Error in FindPersonRequest_Struct. Expected size of: %zu, but got: %i\n", sizeof(FindPersonRequest_Struct), app->size); - else { - FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer; - - std::vector points; - Mob* target = entity_list.GetMob(t->npc_id); - - if (target == nullptr) { - //empty length packet == not found. - EQApplicationPacket outapp(OP_FindPersonReply, 0); - QueuePacket(&outapp); - return; - } - - if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader || - target->CastToClient()->Buyer)) { - Message(15, "Moving you to Trader %s", target->GetName()); - MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f); - } - - if (!RuleB(Pathing, Find) || !zone->pathing) - { - //fill in the path array... - // - points.resize(2); - points[0].x = GetX(); - points[0].y = GetY(); - points[0].z = GetZ(); - points[1].x = target->GetX(); - points[1].y = target->GetY(); - points[1].z = target->GetZ(); - } - else - { - glm::vec3 Start(GetX(), GetY(), GetZ() + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION); - glm::vec3 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION); - - if (!zone->zonemap->LineIntersectsZone(Start, End, 1.0f, nullptr) && zone->pathing->NoHazards(Start, End)) - { - points.resize(2); - points[0].x = Start.x; - points[0].y = Start.y; - points[0].z = Start.z; - - points[1].x = End.x; - points[1].y = End.y; - points[1].z = End.z; - - } - else - { - std::deque pathlist = zone->pathing->FindRoute(Start, End); - - if (pathlist.empty()) - { - EQApplicationPacket outapp(OP_FindPersonReply, 0); - QueuePacket(&outapp); - return; - } - - //the client seems to have issues with packets larger than this - if (pathlist.size() > 36) - { - EQApplicationPacket outapp(OP_FindPersonReply, 0); - QueuePacket(&outapp); - return; - } - - // Live appears to send the points in this order: - // Final destination. - // Current Position. - // rest of the points. - FindPerson_Point p; - - int PointNumber = 0; - - bool LeadsToTeleporter = false; - - glm::vec3 v = zone->pathing->GetPathNodeCoordinates(pathlist.back()); - - p.x = v.x; - p.y = v.y; - p.z = v.z; - points.push_back(p); - - p.x = GetX(); - p.y = GetY(); - p.z = GetZ(); - points.push_back(p); - - for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator) - { - if ((*Iterator) == -1) // Teleporter - { - LeadsToTeleporter = true; - break; - } - - glm::vec3 v = zone->pathing->GetPathNodeCoordinates((*Iterator), false); - p.x = v.x; - p.y = v.y; - p.z = v.z; - points.push_back(p); - ++PointNumber; - } - - if (!LeadsToTeleporter) - { - p.x = target->GetX(); - p.y = target->GetY(); - p.z = target->GetZ(); - - points.push_back(p); - } - - } - } - - SendPathPacket(points); - } - return; + //if (app->size != sizeof(FindPersonRequest_Struct)) + // printf("Error in FindPersonRequest_Struct. Expected size of: %zu, but got: %i\n", sizeof(FindPersonRequest_Struct), app->size); + //else { + // FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer; + // + // std::vector points; + // Mob* target = entity_list.GetMob(t->npc_id); + // + // if (target == nullptr) { + // //empty length packet == not found. + // EQApplicationPacket outapp(OP_FindPersonReply, 0); + // QueuePacket(&outapp); + // return; + // } + // + // if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader || + // target->CastToClient()->Buyer)) { + // Message(15, "Moving you to Trader %s", target->GetName()); + // MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f); + // } + // + // if (!RuleB(Pathing, Find) || !zone->pathing) + // { + // //fill in the path array... + // // + // points.resize(2); + // points[0].x = GetX(); + // points[0].y = GetY(); + // points[0].z = GetZ(); + // points[1].x = target->GetX(); + // points[1].y = target->GetY(); + // points[1].z = target->GetZ(); + // } + // else + // { + // glm::vec3 Start(GetX(), GetY(), GetZ() + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION); + // glm::vec3 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION); + // + // if (!zone->zonemap->LineIntersectsZone(Start, End, 1.0f, nullptr) && zone->pathing->NoHazards(Start, End)) + // { + // points.resize(2); + // points[0].x = Start.x; + // points[0].y = Start.y; + // points[0].z = Start.z; + // + // points[1].x = End.x; + // points[1].y = End.y; + // points[1].z = End.z; + // + // } + // else + // { + // std::deque pathlist = zone->pathing->FindRoute(Start, End); + // + // if (pathlist.empty()) + // { + // EQApplicationPacket outapp(OP_FindPersonReply, 0); + // QueuePacket(&outapp); + // return; + // } + // + // //the client seems to have issues with packets larger than this + // if (pathlist.size() > 36) + // { + // EQApplicationPacket outapp(OP_FindPersonReply, 0); + // QueuePacket(&outapp); + // return; + // } + // + // // Live appears to send the points in this order: + // // Final destination. + // // Current Position. + // // rest of the points. + // FindPerson_Point p; + // + // int PointNumber = 0; + // + // bool LeadsToTeleporter = false; + // + // glm::vec3 v = zone->pathing->GetPathNodeCoordinates(pathlist.back()); + // + // p.x = v.x; + // p.y = v.y; + // p.z = v.z; + // points.push_back(p); + // + // p.x = GetX(); + // p.y = GetY(); + // p.z = GetZ(); + // points.push_back(p); + // + // for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator) + // { + // if ((*Iterator) == -1) // Teleporter + // { + // LeadsToTeleporter = true; + // break; + // } + // + // glm::vec3 v = zone->pathing->GetPathNodeCoordinates((*Iterator), false); + // p.x = v.x; + // p.y = v.y; + // p.z = v.z; + // points.push_back(p); + // ++PointNumber; + // } + // + // if (!LeadsToTeleporter) + // { + // p.x = target->GetX(); + // p.y = target->GetY(); + // p.z = target->GetZ(); + // + // points.push_back(p); + // } + // + // } + // } + // + // SendPathPacket(points); + //} + //return; } void Client::Handle_OP_Fishing(const EQApplicationPacket *app) diff --git a/zone/command.cpp b/zone/command.cpp index 9463e2484..c11500ffc 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -6813,312 +6813,312 @@ void command_qglobal(Client *c, const Seperator *sep) { void command_path(Client *c, const Seperator *sep) { - if(sep->arg[1][0] == '\0' || !strcasecmp(sep->arg[1], "help")) - { - c->Message(0, "Syntax: #path shownodes: Spawns a npc to represent every npc node."); - c->Message(0, "#path info node_id: Gives information about node info (requires shownode target)."); - c->Message(0, "#path dump file_name: Dumps the current zone->pathing to a file of your naming."); - c->Message(0, "#path add [requested_id]: Adds a node at your current location will try to take the requested id if possible."); - c->Message(0, "#path connect connect_to_id [is_teleport] [door_id]: Connects the currently targeted node to connect_to_id's node and connects that node back (requires shownode target)."); - c->Message(0, "#path sconnect connect_to_id [is_teleport] [door_id]: Connects the currently targeted node to connect_to_id's node (requires shownode target)."); - c->Message(0, "#path qconnect [set]: short cut connect, connects the targeted node to the node you set with #path qconnect set (requires shownode target)."); - c->Message(0, "#path disconnect [all]/disconnect_from_id: Disconnects the currently targeted node to disconnect from disconnect from id's node (requires shownode target), if passed all as the second argument it will disconnect this node from every other node."); - c->Message(0, "#path move: Moves your targeted node to your current position"); - c->Message(0, "#path process file_name: processes the map file and tries to automatically generate a rudimentary path setup and then dumps the current zone->pathing to a file of your naming."); - c->Message(0, "#path resort [nodes]: resorts the connections/nodes after you've manually altered them so they'll work."); - return; - } - if(!strcasecmp(sep->arg[1], "shownodes")) - { - if(zone->pathing) - zone->pathing->SpawnPathNodes(); - - return; - } - - if(!strcasecmp(sep->arg[1], "info")) - { - if(zone->pathing) - { - zone->pathing->NodeInfo(c); - } - return; - } - - if(!strcasecmp(sep->arg[1], "dump")) - { - if(zone->pathing) - { - if(sep->arg[2][0] == '\0') - return; - - zone->pathing->DumpPath(sep->arg[2]); - } - return; - } - - if(!strcasecmp(sep->arg[1], "add")) - { - if(zone->pathing) - { - float px = c->GetX(); - float py = c->GetY(); - float pz = c->GetZ(); - float best_z; - - if(zone->zonemap) - { - glm::vec3 loc(px, py, pz); - best_z = zone->zonemap->FindBestZ(loc, nullptr); - } - else - { - best_z = pz; - } - int32 res = zone->pathing->AddNode(px, py, pz, best_z, atoi(sep->arg[2])); - if(res >= 0) - { - c->Message(0, "Added Path Node: %i", res); - } - else - { - c->Message(0, "Failed to add Path Node"); - } - } - else - { - zone->pathing = new PathManager(); - float px = c->GetX(); - float py = c->GetY(); - float pz = c->GetZ(); - float best_z; - - if(zone->zonemap) - { - glm::vec3 loc(px, py, pz); - best_z = zone->zonemap->FindBestZ(loc, nullptr); - } - else - { - best_z = pz; - } - int32 res = zone->pathing->AddNode(px, py, pz, best_z, atoi(sep->arg[2])); - if(res >= 0) - { - c->Message(0, "Added Path Node: %i", res); - } - else - { - c->Message(0, "Failed to add Path Node"); - } - } - return; - } - - if(!strcasecmp(sep->arg[1], "remove")) - { - if(zone->pathing) - { - if(zone->pathing->DeleteNode(c)) - { - c->Message(0, "Removed Node."); - } - else - { - c->Message(0, "Unable to Remove Node."); - } - } - return; - } - - if(!strcasecmp(sep->arg[1], "connect")) - { - if(zone->pathing) - { - zone->pathing->ConnectNodeToNode(c, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); - } - return; - } - - if(!strcasecmp(sep->arg[1], "sconnect")) - { - if(zone->pathing) - { - zone->pathing->ConnectNode(c, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); - } - return; - } - - if(!strcasecmp(sep->arg[1], "qconnect")) - { - if(zone->pathing) - { - if(!strcasecmp(sep->arg[2], "set")) - { - zone->pathing->QuickConnect(c, true); - } - else - { - zone->pathing->QuickConnect(c, false); - } - } - return; - } - - if(!strcasecmp(sep->arg[1], "disconnect")) - { - if(zone->pathing) - { - if(!strcasecmp(sep->arg[2], "all")) - { - zone->pathing->DisconnectAll(c); - } - else - { - zone->pathing->DisconnectNodeToNode(c, atoi(sep->arg[2])); - } - } - return; - } - - - if(!strcasecmp(sep->arg[1], "move")) - { - if(zone->pathing) - { - zone->pathing->MoveNode(c); - } - return; - } - - if(!strcasecmp(sep->arg[1], "process")) - { - if(zone->pathing) - { - if(sep->arg[2][0] == '\0') - return; - - zone->pathing->ProcessNodesAndSave(sep->arg[2]); - c->Message(0, "Path processed..."); - } - return; - } - - if(!strcasecmp(sep->arg[1], "resort")) - { - if(zone->pathing) - { - if(!strcasecmp(sep->arg[2], "nodes")) - { - zone->pathing->SortNodes(); - c->Message(0, "Nodes resorted..."); - } - else - { - zone->pathing->ResortConnections(); - c->Message(0, "Connections resorted..."); - } - } - return; - } - - if(!strcasecmp(sep->arg[1], "hazard")) - { - if(zone->pathing) - { - if(c && c->GetTarget()) - { - if (zone->pathing->NoHazardsAccurate(glm::vec3(c->GetX(), c->GetY(), c->GetZ()), - glm::vec3(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()))) - { - c->Message(0, "No hazards."); - } - else - { - c->Message(0, "Hazard Detected..."); - } - } - } - return; - } - - if(!strcasecmp(sep->arg[1], "print")) - { - if(zone->pathing) - { - zone->pathing->PrintPathing(); - } - return; - } - - if(!strcasecmp(sep->arg[1], "showneighbours") || !strcasecmp(sep->arg[1], "showneighbors")) - { - if(!c->GetTarget()) - { - c->Message(0, "First #path shownodes to spawn the pathnodes, and then target one of them."); - return; - } - if(zone->pathing) - { - zone->pathing->ShowPathNodeNeighbours(c); - return; - } - } - if(!strcasecmp(sep->arg[1], "meshtest")) - { - if(zone->pathing) - { - if(!strcasecmp(sep->arg[2], "simple")) - { - c->Message(0, "You may go linkdead. Results will be in the log file."); - zone->pathing->SimpleMeshTest(); - return; - } - else - { - c->Message(0, "You may go linkdead. Results will be in the log file."); - zone->pathing->MeshTest(); - return; - } - } - } - - if(!strcasecmp(sep->arg[1], "allspawns")) - { - if(zone->pathing) - { - c->Message(0, "You may go linkdead. Results will be in the log file."); - entity_list.FindPathsToAllNPCs(); - return; - } - } - - if(!strcasecmp(sep->arg[1], "nearest")) - { - if(!c->GetTarget() || !c->GetTarget()->IsMob()) - { - c->Message(0, "You must target something."); - return; - } - - if(zone->pathing) - { - Mob *m = c->GetTarget(); - - glm::vec3 Position(m->GetX(), m->GetY(), m->GetZ()); - - int Node = zone->pathing->FindNearestPathNode(Position); - - if(Node == -1) - c->Message(0, "Unable to locate a path node within range."); - else - c->Message(0, "Nearest path node is %i", Node); - - return; - } - } - - c->Message(0, "Unknown path command."); + //if(sep->arg[1][0] == '\0' || !strcasecmp(sep->arg[1], "help")) + //{ + // c->Message(0, "Syntax: #path shownodes: Spawns a npc to represent every npc node."); + // c->Message(0, "#path info node_id: Gives information about node info (requires shownode target)."); + // c->Message(0, "#path dump file_name: Dumps the current zone->pathing to a file of your naming."); + // c->Message(0, "#path add [requested_id]: Adds a node at your current location will try to take the requested id if possible."); + // c->Message(0, "#path connect connect_to_id [is_teleport] [door_id]: Connects the currently targeted node to connect_to_id's node and connects that node back (requires shownode target)."); + // c->Message(0, "#path sconnect connect_to_id [is_teleport] [door_id]: Connects the currently targeted node to connect_to_id's node (requires shownode target)."); + // c->Message(0, "#path qconnect [set]: short cut connect, connects the targeted node to the node you set with #path qconnect set (requires shownode target)."); + // c->Message(0, "#path disconnect [all]/disconnect_from_id: Disconnects the currently targeted node to disconnect from disconnect from id's node (requires shownode target), if passed all as the second argument it will disconnect this node from every other node."); + // c->Message(0, "#path move: Moves your targeted node to your current position"); + // c->Message(0, "#path process file_name: processes the map file and tries to automatically generate a rudimentary path setup and then dumps the current zone->pathing to a file of your naming."); + // c->Message(0, "#path resort [nodes]: resorts the connections/nodes after you've manually altered them so they'll work."); + // return; + //} + //if(!strcasecmp(sep->arg[1], "shownodes")) + //{ + // if(zone->pathing) + // zone->pathing->SpawnPathNodes(); + // + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "info")) + //{ + // if(zone->pathing) + // { + // zone->pathing->NodeInfo(c); + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "dump")) + //{ + // if(zone->pathing) + // { + // if(sep->arg[2][0] == '\0') + // return; + // + // zone->pathing->DumpPath(sep->arg[2]); + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "add")) + //{ + // if(zone->pathing) + // { + // float px = c->GetX(); + // float py = c->GetY(); + // float pz = c->GetZ(); + // float best_z; + // + // if(zone->zonemap) + // { + // glm::vec3 loc(px, py, pz); + // best_z = zone->zonemap->FindBestZ(loc, nullptr); + // } + // else + // { + // best_z = pz; + // } + // int32 res = zone->pathing->AddNode(px, py, pz, best_z, atoi(sep->arg[2])); + // if(res >= 0) + // { + // c->Message(0, "Added Path Node: %i", res); + // } + // else + // { + // c->Message(0, "Failed to add Path Node"); + // } + // } + // else + // { + // zone->pathing = new PathManager(); + // float px = c->GetX(); + // float py = c->GetY(); + // float pz = c->GetZ(); + // float best_z; + // + // if(zone->zonemap) + // { + // glm::vec3 loc(px, py, pz); + // best_z = zone->zonemap->FindBestZ(loc, nullptr); + // } + // else + // { + // best_z = pz; + // } + // int32 res = zone->pathing->AddNode(px, py, pz, best_z, atoi(sep->arg[2])); + // if(res >= 0) + // { + // c->Message(0, "Added Path Node: %i", res); + // } + // else + // { + // c->Message(0, "Failed to add Path Node"); + // } + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "remove")) + //{ + // if(zone->pathing) + // { + // if(zone->pathing->DeleteNode(c)) + // { + // c->Message(0, "Removed Node."); + // } + // else + // { + // c->Message(0, "Unable to Remove Node."); + // } + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "connect")) + //{ + // if(zone->pathing) + // { + // zone->pathing->ConnectNodeToNode(c, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "sconnect")) + //{ + // if(zone->pathing) + // { + // zone->pathing->ConnectNode(c, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "qconnect")) + //{ + // if(zone->pathing) + // { + // if(!strcasecmp(sep->arg[2], "set")) + // { + // zone->pathing->QuickConnect(c, true); + // } + // else + // { + // zone->pathing->QuickConnect(c, false); + // } + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "disconnect")) + //{ + // if(zone->pathing) + // { + // if(!strcasecmp(sep->arg[2], "all")) + // { + // zone->pathing->DisconnectAll(c); + // } + // else + // { + // zone->pathing->DisconnectNodeToNode(c, atoi(sep->arg[2])); + // } + // } + // return; + //} + // + // + //if(!strcasecmp(sep->arg[1], "move")) + //{ + // if(zone->pathing) + // { + // zone->pathing->MoveNode(c); + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "process")) + //{ + // if(zone->pathing) + // { + // if(sep->arg[2][0] == '\0') + // return; + // + // zone->pathing->ProcessNodesAndSave(sep->arg[2]); + // c->Message(0, "Path processed..."); + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "resort")) + //{ + // if(zone->pathing) + // { + // if(!strcasecmp(sep->arg[2], "nodes")) + // { + // zone->pathing->SortNodes(); + // c->Message(0, "Nodes resorted..."); + // } + // else + // { + // zone->pathing->ResortConnections(); + // c->Message(0, "Connections resorted..."); + // } + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "hazard")) + //{ + // if(zone->pathing) + // { + // if(c && c->GetTarget()) + // { + // if (zone->pathing->NoHazardsAccurate(glm::vec3(c->GetX(), c->GetY(), c->GetZ()), + // glm::vec3(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()))) + // { + // c->Message(0, "No hazards."); + // } + // else + // { + // c->Message(0, "Hazard Detected..."); + // } + // } + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "print")) + //{ + // if(zone->pathing) + // { + // zone->pathing->PrintPathing(); + // } + // return; + //} + // + //if(!strcasecmp(sep->arg[1], "showneighbours") || !strcasecmp(sep->arg[1], "showneighbors")) + //{ + // if(!c->GetTarget()) + // { + // c->Message(0, "First #path shownodes to spawn the pathnodes, and then target one of them."); + // return; + // } + // if(zone->pathing) + // { + // zone->pathing->ShowPathNodeNeighbours(c); + // return; + // } + //} + //if(!strcasecmp(sep->arg[1], "meshtest")) + //{ + // if(zone->pathing) + // { + // if(!strcasecmp(sep->arg[2], "simple")) + // { + // c->Message(0, "You may go linkdead. Results will be in the log file."); + // zone->pathing->SimpleMeshTest(); + // return; + // } + // else + // { + // c->Message(0, "You may go linkdead. Results will be in the log file."); + // zone->pathing->MeshTest(); + // return; + // } + // } + //} + // + //if(!strcasecmp(sep->arg[1], "allspawns")) + //{ + // if(zone->pathing) + // { + // c->Message(0, "You may go linkdead. Results will be in the log file."); + // entity_list.FindPathsToAllNPCs(); + // return; + // } + //} + // + //if(!strcasecmp(sep->arg[1], "nearest")) + //{ + // if(!c->GetTarget() || !c->GetTarget()->IsMob()) + // { + // c->Message(0, "You must target something."); + // return; + // } + // + // if(zone->pathing) + // { + // Mob *m = c->GetTarget(); + // + // glm::vec3 Position(m->GetX(), m->GetY(), m->GetZ()); + // + // int Node = zone->pathing->FindNearestPathNode(Position); + // + // if(Node == -1) + // c->Message(0, "Unable to locate a path node within range."); + // else + // c->Message(0, "Nearest path node is %i", Node); + // + // return; + // } + //} + // + //c->Message(0, "Unknown path command."); } void Client::Undye() { diff --git a/zone/entity.cpp b/zone/entity.cpp index 52eb41165..d5c558a7b 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2822,26 +2822,6 @@ void EntityList::ListPlayerCorpses(Client *client) client->Message(0, "%d player corpses listed.", x); } -void EntityList::FindPathsToAllNPCs() -{ - if (!zone->pathing) - return; - - auto it = npc_list.begin(); - while (it != npc_list.end()) { - glm::vec3 Node0 = zone->pathing->GetPathNodeCoordinates(0, false); - glm::vec3 Dest(it->second->GetX(), it->second->GetY(), it->second->GetZ()); - std::deque Route = zone->pathing->FindRoute(Node0, Dest); - if (Route.empty()) - printf("Unable to find a route to %s\n", it->second->GetName()); - else - printf("Found a route to %s\n", it->second->GetName()); - ++it; - } - - fflush(stdout); -} - // returns the number of corpses deleted. A negative number indicates an error code. int32 EntityList::DeleteNPCCorpses() { diff --git a/zone/entity.h b/zone/entity.h index 036e0c419..33434ed04 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -383,7 +383,6 @@ public: void ListNPCs(Client* client, const char* arg1 = 0, const char* arg2 = 0, uint8 searchtype = 0); void ListNPCCorpses(Client* client); void ListPlayerCorpses(Client* client); - void FindPathsToAllNPCs(); int32 DeleteNPCCorpses(); int32 DeletePlayerCorpses(); void CorpseFix(Client* c); diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index ea5bb16d9..3a1215748 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -130,23 +130,25 @@ void Mob::CalculateNewFearpoint() { if(RuleB(Pathing, Fear) && zone->pathing) { - int Node = zone->pathing->GetRandomPathNode(); + auto Node = zone->pathing->GetRandomLocation(); + if (Node.x != 0.0f || Node.y != 0.0f || Node.z != 0.0f) { - glm::vec3 Loc = zone->pathing->GetPathNodeCoordinates(Node); + ++Node.z; - ++Loc.z; + glm::vec3 CurrentPosition(GetX(), GetY(), GetZ()); - glm::vec3 CurrentPosition(GetX(), GetY(), GetZ()); + auto Route = zone->pathing->FindRoute(CurrentPosition, Node); - std::deque Route = zone->pathing->FindRoute(CurrentPosition, Loc); + if (!Route.empty()) + { + auto first = (*Route.begin()); + m_FearWalkTarget = glm::vec3(first.x, first.y, first.z); + currently_fleeing = true; - if(!Route.empty()) - { - m_FearWalkTarget = glm::vec3(Loc.x, Loc.y, Loc.z); - currently_fleeing = true; + Log(Logs::Detail, Logs::None, "Feared to node %i (%8.3f, %8.3f, %8.3f)", Node, first.x, first.y, first.z); + return; + } - Log(Logs::Detail, Logs::None, "Feared to node %i (%8.3f, %8.3f, %8.3f)", Node, Loc.x, Loc.y, Loc.z); - return; } Log(Logs::Detail, Logs::None, "No path found to selected node. Falling through to old fear point selection."); @@ -171,6 +173,7 @@ void Mob::CalculateNewFearpoint() break; } } + if (currently_fleeing) m_FearWalkTarget = glm::vec3(ranx, rany, ranz); else //Break fear diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 18651edea..308b915d4 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -1125,17 +1125,6 @@ bool Lua_Mob::CalculateNewPosition(double x, double y, double z, double speed, b check_z); } -bool Lua_Mob::CalculateNewPosition2(double x, double y, double z, double speed) { - Lua_Safe_Call_Bool(); - return self->CalculateNewPosition2(static_cast(x), static_cast(y), static_cast(z), static_cast(speed)); -} - -bool Lua_Mob::CalculateNewPosition2(double x, double y, double z, double speed, bool check_z) { - Lua_Safe_Call_Bool(); - return self->CalculateNewPosition2(static_cast(x), static_cast(y), static_cast(z), static_cast(speed), - check_z); -} - float Lua_Mob::CalculateDistance(double x, double y, double z) { Lua_Safe_Call_Real(); return self->CalculateDistance(static_cast(x), static_cast(y), static_cast(z)); @@ -2287,8 +2276,6 @@ luabind::scope lua_register_mob() { .def("CalculateHeadingToTarget", (double(Lua_Mob::*)(double,double))&Lua_Mob::CalculateHeadingToTarget) .def("CalculateNewPosition", (bool(Lua_Mob::*)(double,double,double,double))&Lua_Mob::CalculateNewPosition) .def("CalculateNewPosition", (bool(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::CalculateNewPosition) - .def("CalculateNewPosition2", (bool(Lua_Mob::*)(double,double,double,double))&Lua_Mob::CalculateNewPosition2) - .def("CalculateNewPosition2", (bool(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::CalculateNewPosition2) .def("CalculateDistance", (float(Lua_Mob::*)(double,double,double))&Lua_Mob::CalculateDistance) .def("SendTo", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::SendTo) .def("SendToFixZ", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::SendToFixZ) diff --git a/zone/lua_mob.h b/zone/lua_mob.h index c54deb6bc..936703f8c 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -240,8 +240,6 @@ public: double CalculateHeadingToTarget(double in_x, double in_y); bool CalculateNewPosition(double x, double y, double z, double speed); bool CalculateNewPosition(double x, double y, double z, double speed, bool check_z); - bool CalculateNewPosition2(double x, double y, double z, double speed); - bool CalculateNewPosition2(double x, double y, double z, double speed, bool check_z); float CalculateDistance(double x, double y, double z); void SendTo(double x, double y, double z); void SendToFixZ(double x, double y, double z); diff --git a/zone/merc.cpp b/zone/merc.cpp index 80565c6b4..f6a13ba6e 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1487,12 +1487,12 @@ void Merc::AI_Process() { if (WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed()); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetRunspeed()); } else { Mob* follow = entity_list.GetMob(GetFollowID()); if (follow) - CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), GetRunspeed()); + CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), GetRunspeed()); } return; @@ -1559,7 +1559,7 @@ void Merc::AI_Process() { float newZ = 0; FaceTarget(GetTarget()); if (PlotPositionAroundTarget(this, newX, newY, newZ)) { - CalculateNewPosition2(newX, newY, newZ, GetRunspeed()); + CalculateNewPosition(newX, newY, newZ, GetRunspeed()); return; } } @@ -1571,7 +1571,7 @@ void Merc::AI_Process() { float newY = 0; float newZ = 0; if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ)) { - CalculateNewPosition2(newX, newY, newZ, GetRunspeed()); + CalculateNewPosition(newX, newY, newZ, GetRunspeed()); return; } } @@ -1582,7 +1582,7 @@ void Merc::AI_Process() { float newY = 0; float newZ = 0; if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) { - CalculateNewPosition2(newX, newY, newZ, GetRunspeed()); + CalculateNewPosition(newX, newY, newZ, GetRunspeed()); return; } } @@ -1709,7 +1709,7 @@ void Merc::AI_Process() { { if(!IsRooted()) { Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); - CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed()); + CalculateNewPosition(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed()); return; } @@ -1781,10 +1781,10 @@ void Merc::AI_Process() { if (WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed); } else { - CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed); + CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), speed); } if (rest_timer.Enabled()) diff --git a/zone/mob.cpp b/zone/mob.cpp index 33863081a..2d4b10da7 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -430,15 +430,7 @@ Mob::Mob(const char* in_name, m_TargetRing = glm::vec3(); flymode = FlyMode3; - // Pathing - PathingLOSState = UnknownLOS; - PathingLoopCount = 0; - PathingLastNodeVisited = -1; - PathingLOSCheckTimer = new Timer(RuleI(Pathing, LOSCheckFrequency)); - PathingRouteUpdateTimerShort = new Timer(RuleI(Pathing, RouteUpdateFrequencyShort)); - PathingRouteUpdateTimerLong = new Timer(RuleI(Pathing, RouteUpdateFrequencyLong)); DistractedFromGrid = false; - PathingTraversedNodes = 0; hate_list.SetHateOwner(this); m_AllowBeneficial = false; @@ -485,9 +477,6 @@ Mob::~Mob() entity_list.DestroyTempPets(this); } entity_list.UnMarkNPC(GetID()); - safe_delete(PathingLOSCheckTimer); - safe_delete(PathingRouteUpdateTimerShort); - safe_delete(PathingRouteUpdateTimerLong); UninitializeBuffSlots(); #ifdef BOTS @@ -1642,7 +1631,6 @@ void Mob::ShowBuffList(Client* client) { } void Mob::GMMove(float x, float y, float z, float heading, bool SendUpdate) { - Route.clear(); if(IsNPC()) { diff --git a/zone/mob.h b/zone/mob.h index 8286bf647..e5ae2a479 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -21,7 +21,7 @@ #include "common.h" #include "entity.h" #include "hate_list.h" -#include "pathing.h" +#include "pathfinder_interface.h" #include "position.h" #include "aa_ability.h" #include "aa.h" @@ -908,8 +908,7 @@ public: inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);} float CalculateHeadingToTarget(float in_x, float in_y); - bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = false, bool calcheading = true); - virtual bool CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true); + virtual bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true); float CalculateDistance(float x, float y, float z); float GetGroundZ(float new_x, float new_y, float z_offset=0.0); void SendTo(float new_x, float new_y, float new_z); @@ -1410,16 +1409,8 @@ protected: // Pathing // glm::vec3 PathingDestination; - glm::vec3 PathingLastPosition; - int PathingLoopCount; - int PathingLastNodeVisited; - std::deque Route; - LOSType PathingLOSState; - Timer *PathingLOSCheckTimer; - Timer *PathingRouteUpdateTimerShort; - Timer *PathingRouteUpdateTimerLong; + IPathfinder::IPath Route; bool DistractedFromGrid; - int PathingTraversedNodes; uint32 pDontHealMeBefore; uint32 pDontBuffMeBefore; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index e1e4682b0..6a54edf37 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -563,10 +563,6 @@ void Client::AI_Stop() { // only call this on a zone shutdown event void Mob::AI_ShutDown() { - safe_delete(PathingLOSCheckTimer); - safe_delete(PathingRouteUpdateTimerShort); - safe_delete(PathingRouteUpdateTimerLong); - attack_timer.Disable(); attack_dw_timer.Disable(); ranged_timer.Disable(); @@ -770,7 +766,7 @@ void Client::AI_Process() CalculateNewFearpoint(); } if(!RuleB(Pathing, Fear) || !zone->pathing) - CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, speed, true); + CalculateNewPosition(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, speed, true); else { bool WaypointChanged, NodeReached; @@ -781,7 +777,7 @@ void Client::AI_Process() if(WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, speed); } } return; @@ -853,7 +849,7 @@ void Client::AI_Process() newspeed *= 2; SetCurrentSpeed(newspeed); if(!RuleB(Pathing, Aggro) || !zone->pathing) - CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), newspeed); + CalculateNewPosition(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), newspeed); else { bool WaypointChanged, NodeReached; @@ -863,7 +859,7 @@ void Client::AI_Process() if(WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, newspeed); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, newspeed); } } } @@ -912,7 +908,7 @@ void Client::AI_Process() nspeed *= 2; SetCurrentSpeed(nspeed); - CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), nspeed); + CalculateNewPosition(owner->GetX(), owner->GetY(), owner->GetZ(), nspeed); } } else @@ -969,7 +965,7 @@ void Mob::AI_Process() { } if(!RuleB(Pathing, Fear) || !zone->pathing) { - CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true); + CalculateNewPosition(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true); } else { @@ -981,7 +977,7 @@ void Mob::AI_Process() { if(WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetFearSpeed()); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetFearSpeed()); } } return; @@ -1300,7 +1296,7 @@ void Mob::AI_Process() { if (!IsRooted()) { Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName()); if (!RuleB(Pathing, Aggro) || !zone->pathing) - CalculateNewPosition2(target->GetX(), target->GetY(), target->GetZ(), GetRunspeed()); + CalculateNewPosition(target->GetX(), target->GetY(), target->GetZ(), GetRunspeed()); else { bool WaypointChanged, NodeReached; @@ -1311,7 +1307,7 @@ void Mob::AI_Process() { if (WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed()); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, GetRunspeed()); } } @@ -1395,7 +1391,7 @@ void Mob::AI_Process() { if (dist >= 5625) speed = GetRunspeed(); - CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed); + CalculateNewPosition(owner->GetX(), owner->GetY(), owner->GetZ(), speed); } else { @@ -1454,7 +1450,7 @@ void Mob::AI_Process() { int speed = GetWalkspeed(); if (dist2 >= followdist + 150) speed = GetRunspeed(); - CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed); + CalculateNewPosition(follow->GetX(), follow->GetY(), follow->GetZ(), speed); } else { @@ -1536,7 +1532,7 @@ void NPC::AI_DoMovement() { Log(Logs::Detail, Logs::AI, "Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)", roambox_distance, roambox_min_x, roambox_max_x, roambox_min_y, roambox_max_y, roambox_movingto_x, roambox_movingto_y); - if (!CalculateNewPosition2(roambox_movingto_x, roambox_movingto_y, GetZ(), walksp, true)) + if (!CalculateNewPosition(roambox_movingto_x, roambox_movingto_y, GetZ(), walksp, true)) { roambox_movingto_x = roambox_max_x + 1; // force update pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); @@ -1593,7 +1589,7 @@ void NPC::AI_DoMovement() { if (doMove) { // not at waypoint yet or at 0 pause WP, so keep moving if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0)) - CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true); + CalculateNewPosition(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true); else { bool WaypointChanged; @@ -1605,13 +1601,13 @@ void NPC::AI_DoMovement() { if(NodeReached) entity_list.OpenDoorsNear(CastToNPC()); - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, walksp, true); + CalculateNewPosition(Goal.x, Goal.y, Goal.z, walksp, true); } } } } // endif (gridno > 0) -// handle new quest grid command processing + // handle new quest grid command processing else if (gridno < 0) { // this mob is under quest control if (movetimercompleted==true) @@ -1630,7 +1626,7 @@ void NPC::AI_DoMovement() { { bool CP2Moved; if(!RuleB(Pathing, Guard) || !zone->pathing) - CP2Moved = CalculateNewPosition2(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp); + CP2Moved = CalculateNewPosition(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp); else { if(!((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && (m_Position.z == m_GuardPoint.z))) @@ -1643,7 +1639,7 @@ void NPC::AI_DoMovement() { if(NodeReached) entity_list.OpenDoorsNear(CastToNPC()); - CP2Moved = CalculateNewPosition2(Goal.x, Goal.y, Goal.z, walksp); + CP2Moved = CalculateNewPosition(Goal.x, Goal.y, Goal.z, walksp); } else CP2Moved = false; diff --git a/zone/pathfinder_interface.cpp b/zone/pathfinder_interface.cpp new file mode 100644 index 000000000..f3110808e --- /dev/null +++ b/zone/pathfinder_interface.cpp @@ -0,0 +1,7 @@ +#include "pathfinder_null.h" +#include "pathfinder_nav_mesh.h" +#include "pathfinder_waypoint.h" + +IPathfinder *IPathfinder::Load(const std::string &zone) { + return new PathfinderNull(); +} \ No newline at end of file diff --git a/zone/pathfinder_interface.h b/zone/pathfinder_interface.h index e69de29bb..ea4aa6642 100644 --- a/zone/pathfinder_interface.h +++ b/zone/pathfinder_interface.h @@ -0,0 +1,18 @@ +#pragma once + +#include "map.h" +#include + +class IPathfinder +{ +public: + typedef std::list IPath; + + IPathfinder() { } + virtual ~IPathfinder() { } + + virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end) = 0; + virtual glm::vec3 GetRandomLocation() = 0; + + static IPathfinder *Load(const std::string &zone); +}; diff --git a/zone/pathfinder_nav_mesh.h b/zone/pathfinder_nav_mesh.h index e69de29bb..bdb83a41e 100644 --- a/zone/pathfinder_nav_mesh.h +++ b/zone/pathfinder_nav_mesh.h @@ -0,0 +1,3 @@ +#pragma once + +#include "pathfinder_interface.h" \ No newline at end of file diff --git a/zone/pathfinder_null.cpp b/zone/pathfinder_null.cpp new file mode 100644 index 000000000..98a9ce5d7 --- /dev/null +++ b/zone/pathfinder_null.cpp @@ -0,0 +1,15 @@ +#include "pathfinder_null.h" +#pragma once + +IPathfinder::IPath PathfinderNull::FindRoute(const glm::vec3 &start, const glm::vec3 &end) +{ + IPath ret; + ret.push_back(start); + ret.push_back(end); + return ret; +} + +glm::vec3 PathfinderNull::GetRandomLocation() +{ + return glm::vec3(); +} diff --git a/zone/pathfinder_null.h b/zone/pathfinder_null.h new file mode 100644 index 000000000..6d2674230 --- /dev/null +++ b/zone/pathfinder_null.h @@ -0,0 +1,13 @@ +#pragma once + +#include "pathfinder_interface.h" + +class PathfinderNull : public IPathfinder +{ +public: + PathfinderNull() { } + virtual ~PathfinderNull() { } + + virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end); + virtual glm::vec3 GetRandomLocation(); +}; \ No newline at end of file diff --git a/zone/pathfinder_waypoint.h b/zone/pathfinder_waypoint.h index e69de29bb..5c51ac915 100644 --- a/zone/pathfinder_waypoint.h +++ b/zone/pathfinder_waypoint.h @@ -0,0 +1,13 @@ +#pragma once + +#include "pathfinder_interface.h" + +class PathfinderWaypoint : public IPathfinder +{ +public: + PathfinderWaypoint() { } + virtual ~PathfinderWaypoint() { } + + virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end); + virtual glm::vec3 GetRandomLocation(); +}; \ No newline at end of file diff --git a/zone/pathing.cpp b/zone/pathing.cpp index 48b945905..599e8af6b 100644 --- a/zone/pathing.cpp +++ b/zone/pathing.cpp @@ -467,7 +467,7 @@ std::deque PathManager::FindRoute(glm::vec3 Start, glm::vec3 End) break; if(!zone->zonemap->LineIntersectsZone(Start, PathNodes[(*Second)].v, 1.0f, nullptr) - && zone->pathing->NoHazards(Start, PathNodes[(*Second)].v)) + && NoHazards(Start, PathNodes[(*Second)].v)) { noderoute.erase(First); @@ -500,7 +500,7 @@ std::deque PathManager::FindRoute(glm::vec3 Start, glm::vec3 End) break; if(!zone->zonemap->LineIntersectsZone(End, PathNodes[(*Second)].v, 1.0f, nullptr) - && zone->pathing->NoHazards(End, PathNodes[(*Second)].v)) + && NoHazards(End, PathNodes[(*Second)].v)) { noderoute.erase(First); @@ -644,439 +644,62 @@ void PathManager::SimpleMeshTest() glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChanged, bool &NodeReached) { - WaypointChanged = false; - - NodeReached = false; - - glm::vec3 NodeLoc; + glm::vec3 To(ToX, ToY, ToZ); + if (Speed <= 0) { + return To; + } glm::vec3 From(GetX(), GetY(), GetZ()); - - glm::vec3 HeadPosition(From.x, From.y, From.z + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION); - - glm::vec3 To(ToX, ToY, ToZ); - - bool SameDestination = (To == PathingDestination); - - if (Speed <= 0) // our speed is 0, we cant move so lets return the dest - return To; // this will also avoid the teleports cleanly - - int NextNode; - - if(To == From) + + if (DistanceSquared(To, From) < 1.0f) { + WaypointChanged = false; + NodeReached = true; + Route.clear(); return To; + } - Log(Logs::Detail, Logs::None, "UpdatePath. From(%8.3f, %8.3f, %8.3f) To(%8.3f, %8.3f, %8.3f)", From.x, From.y, From.z, To.x, To.y, To.z); - - if(From == PathingLastPosition) - { - ++PathingLoopCount; - - if((PathingLoopCount > 5) && !IsRooted()) - { - Log(Logs::Detail, Logs::None, "appears to be stuck. Teleporting them to next position.", GetName()); - - if(Route.empty()) - { - Teleport(To); - - WaypointChanged = true; - - PathingLoopCount = 0; - - return To; - } - NodeLoc = zone->pathing->GetPathNodeCoordinates(Route.front()); - - Route.pop_front(); - - ++PathingTraversedNodes; - - Teleport(NodeLoc); - + if (Route.empty()) { + Route = zone->pathing->FindRoute(From, To); + PathingDestination = To; + WaypointChanged = true; + NodeReached = false; + return *Route.begin(); + } + else { + bool SameDestination = DistanceSquared(To, PathingDestination) < 1.0f; + if (!SameDestination) { + //We had a route but our target position moved too much + Route = zone->pathing->FindRoute(From, To); + PathingDestination = To; WaypointChanged = true; - - PathingLoopCount = 0; - - return NodeLoc; + NodeReached = false; + return *Route.begin(); } - } - else - { - PathingLoopCount = 0; - - PathingLastPosition = From; - } - - if(!Route.empty()) - { - - // If we are already pathing, and the destination is the same as before ... - if(SameDestination) - { - Log(Logs::Detail, Logs::None, " Still pathing to the same destination."); - - // Get the coordinates of the first path node we are going to. - NextNode = Route.front(); - - NodeLoc = zone->pathing->GetPathNodeCoordinates(NextNode); - - // May need to refine this as rounding errors may mean we never have equality - // We have reached the path node. - if(NodeLoc == From) - { - Log(Logs::Detail, Logs::None, " Arrived at node %i", NextNode); - + else { + bool AtNextNode = DistanceSquared(From, *Route.begin()) < 1.0f; + if (AtNextNode) { + WaypointChanged = false; NodeReached = true; - PathingLastNodeVisited = Route.front(); - // We only check for LOS again after traversing more than 1 node, otherwise we can get into - // a loop where we have a hazard and so run to a path node far enough away from the hazard, and - // then run right back towards the same hazard again. - // - // An exception is when we are about to head for the last node. We always check LOS then. This - // is because we are seeking a path to the node nearest to our target. This node may be behind the - // target, and we may run past the target if we don't check LOS at this point. - int RouteSize = Route.size(); - - Log(Logs::Detail, Logs::None, "Route size is %i", RouteSize); - - if((RouteSize == 2) - || ((PathingTraversedNodes >= RuleI(Pathing, MinNodesTraversedForLOSCheck)) - && (RouteSize <= RuleI(Pathing, MinNodesLeftForLOSCheck)) - && PathingLOSCheckTimer->Check())) - { - Log(Logs::Detail, Logs::None, " Checking distance to target."); - float Distance = VectorDistanceNoRoot(From, To); - - Log(Logs::Detail, Logs::None, " Distance between From and To (NoRoot) is %8.3f", Distance); - - if ((Distance <= RuleR(Pathing, MinDistanceForLOSCheckShort)) && - (std::abs(From.z - To.z) <= RuleR(Pathing, ZDiffThresholdNew))) { - if(!zone->zonemap->LineIntersectsZone(HeadPosition, To, 1.0f, nullptr)) - PathingLOSState = HaveLOS; - else - PathingLOSState = NoLOS; - Log(Logs::Detail, Logs::None, "NoLOS"); - - if((PathingLOSState == HaveLOS) && zone->pathing->NoHazards(From, To)) - { - Log(Logs::Detail, Logs::None, " No hazards. Running directly to target."); - Route.clear(); - - return To; - } - else - { - Log(Logs::Detail, Logs::None, " Continuing on node path."); - } - } - else - PathingLOSState = UnknownLOS; - } - // We are on the same route, no LOS (or not checking this time, so pop off the node we just reached - // Route.pop_front(); - ++PathingTraversedNodes; - - WaypointChanged = true; - - // If there are more nodes on the route, return the coords of the next node - if(!Route.empty()) - { - NextNode = Route.front(); - - if(NextNode == -1) - { - // -1 indicates a teleport to the next node - Route.pop_front(); - - if(Route.empty()) - { - Log(Logs::Detail, Logs::None, "Missing node after teleport."); - return To; - } - - NextNode = Route.front(); - - NodeLoc = zone->pathing->GetPathNodeCoordinates(NextNode); - - Teleport(NodeLoc); - - Log(Logs::Detail, Logs::None, " TELEPORTED to %8.3f, %8.3f, %8.3f\n", NodeLoc.x, NodeLoc.y, NodeLoc.z); - - Route.pop_front(); - - if(Route.empty()) - return To; - - NextNode = Route.front(); - } - zone->pathing->OpenDoors(PathingLastNodeVisited, NextNode, this); - - Log(Logs::Detail, Logs::None, " Now moving to node %i", NextNode); - - return zone->pathing->GetPathNodeCoordinates(NextNode); - } - else - { - // we have run all the nodes, all that is left is the direct path from the last node - // to the destination - Log(Logs::Detail, Logs::None, " Reached end of node path, running direct to target."); - - return To; - } - } - // At this point, we are still on the previous path, but not reached a node yet. - // The route shouldn't be empty, but check anyway. - // - int RouteSize = Route.size(); - - if((PathingTraversedNodes >= RuleI(Pathing, MinNodesTraversedForLOSCheck)) - && (RouteSize <= RuleI(Pathing, MinNodesLeftForLOSCheck)) - && PathingLOSCheckTimer->Check()) - { - Log(Logs::Detail, Logs::None, " Checking distance to target."); - - float Distance = VectorDistanceNoRoot(From, To); - - Log(Logs::Detail, Logs::None, " Distance between From and To (NoRoot) is %8.3f", Distance); - - if ((Distance <= RuleR(Pathing, MinDistanceForLOSCheckShort)) && - (std::abs(From.z - To.z) <= RuleR(Pathing, ZDiffThresholdNew))) { - if(!zone->zonemap->LineIntersectsZone(HeadPosition, To, 1.0f, nullptr)) - PathingLOSState = HaveLOS; - else - PathingLOSState = NoLOS; - Log(Logs::Detail, Logs::None, "NoLOS"); - - if((PathingLOSState == HaveLOS) && zone->pathing->NoHazards(From, To)) - { - Log(Logs::Detail, Logs::None, " No hazards. Running directly to target."); - Route.clear(); - - return To; - } - else - { - Log(Logs::Detail, Logs::None, " Continuing on node path."); - } - } - else - PathingLOSState = UnknownLOS; - } - return NodeLoc; - } - else - { - // We get here if we were already pathing, but our destination has now changed. - // - Log(Logs::Detail, Logs::None, " Target has changed position."); - // Update our record of where we are going to. - PathingDestination = To; - // Check if we now have LOS etc to the new destination. - if(PathingLOSCheckTimer->Check()) - { - float Distance = VectorDistanceNoRoot(From, To); - - if ((Distance <= RuleR(Pathing, MinDistanceForLOSCheckShort)) && - (std::abs(From.z - To.z) <= RuleR(Pathing, ZDiffThresholdNew))) { - Log(Logs::Detail, Logs::None, " Checking for short LOS at distance %8.3f.", Distance); - if(!zone->zonemap->LineIntersectsZone(HeadPosition, To, 1.0f, nullptr)) - PathingLOSState = HaveLOS; - else - PathingLOSState = NoLOS; - - Log(Logs::Detail, Logs::None, "NoLOS"); - - if((PathingLOSState == HaveLOS) && zone->pathing->NoHazards(From, To)) - { - Log(Logs::Detail, Logs::None, " No hazards. Running directly to target."); - Route.clear(); - return To; - } - else - { - Log(Logs::Detail, Logs::None, " Continuing on node path."); - } - } - } - - // If the player is moving, we don't want to recalculate our route too frequently. - // - if(static_cast(Route.size()) <= RuleI(Pathing, RouteUpdateFrequencyNodeCount)) - { - if(!PathingRouteUpdateTimerShort->Check()) - { - Log(Logs::Detail, Logs::None, "Short route update timer not yet expired."); - return zone->pathing->GetPathNodeCoordinates(Route.front()); - } - Log(Logs::Detail, Logs::None, "Short route update timer expired."); - } - else - { - if(!PathingRouteUpdateTimerLong->Check()) - { - Log(Logs::Detail, Logs::None, "Long route update timer not yet expired."); - return zone->pathing->GetPathNodeCoordinates(Route.front()); - } - Log(Logs::Detail, Logs::None, "Long route update timer expired."); - } - - // We are already pathing, destination changed, no LOS. Find the nearest node to our destination. - int DestinationPathNode= zone->pathing->FindNearestPathNode(To); - - // Destination unreachable via pathing, return direct route. - if(DestinationPathNode == -1) - { - Log(Logs::Detail, Logs::None, " Unable to find path node for new destination. Running straight to target."); - Route.clear(); - return To; - } - // If the nearest path node to our new destination is the same as for the previous - // one, we will carry on on our path. - if(DestinationPathNode == Route.back()) - { - Log(Logs::Detail, Logs::None, " Same destination Node (%i). Continue with current path.", DestinationPathNode); - - NodeLoc = zone->pathing->GetPathNodeCoordinates(Route.front()); - - // May need to refine this as rounding errors may mean we never have equality - // Check if we have reached a path node. - if(NodeLoc == From) - { - Log(Logs::Detail, Logs::None, " Arrived at node %i, moving to next one.\n", Route.front()); - - NodeReached = true; - - PathingLastNodeVisited = Route.front(); - - Route.pop_front(); - - ++PathingTraversedNodes; - + if (Route.empty()) { + Route = zone->pathing->FindRoute(From, To); + PathingDestination = To; WaypointChanged = true; - - if(!Route.empty()) - { - NextNode = Route.front(); - - if(NextNode == -1) - { - // -1 indicates a teleport to the next node - Route.pop_front(); - - if(Route.empty()) - { - Log(Logs::Detail, Logs::None, "Missing node after teleport."); - return To; - } - - NextNode = Route.front(); - - NodeLoc = zone->pathing->GetPathNodeCoordinates(NextNode); - - Teleport(NodeLoc); - - Log(Logs::Detail, Logs::None, " TELEPORTED to %8.3f, %8.3f, %8.3f\n", NodeLoc.x, NodeLoc.y, NodeLoc.z); - - Route.pop_front(); - - if(Route.empty()) - return To; - - NextNode = Route.front(); - } - // Return the coords of our next path node on the route. - Log(Logs::Detail, Logs::None, " Now moving to node %i", NextNode); - - zone->pathing->OpenDoors(PathingLastNodeVisited, NextNode, this); - - return zone->pathing->GetPathNodeCoordinates(NextNode); - } - else - { - Log(Logs::Detail, Logs::None, " Reached end of path grid. Running direct to target."); - return To; - } + return *Route.begin(); + } + else { + return *Route.begin(); } - return NodeLoc; } - else - { - Log(Logs::Detail, Logs::None, " Target moved. End node is different. Clearing route."); - - Route.clear(); - // We will now fall through to get a new route. + else { + WaypointChanged = false; + NodeReached = false; + return *Route.begin(); } - - } - - - } - Log(Logs::Detail, Logs::None, " Our route list is empty."); - - if((SameDestination) && !PathingLOSCheckTimer->Check()) - { - Log(Logs::Detail, Logs::None, " Destination same as before, LOS check timer not reached. Returning To."); - return To; - } - - PathingLOSState = UnknownLOS; - - PathingDestination = To; - - WaypointChanged = true; - - float Distance = VectorDistanceNoRoot(From, To); - - if ((Distance <= RuleR(Pathing, MinDistanceForLOSCheckLong)) && - (std::abs(From.z - To.z) <= RuleR(Pathing, ZDiffThresholdNew))) { - Log(Logs::Detail, Logs::None, " Checking for long LOS at distance %8.3f.", Distance); - - if(!zone->zonemap->LineIntersectsZone(HeadPosition, To, 1.0f, nullptr)) - PathingLOSState = HaveLOS; - else - PathingLOSState = NoLOS; - - Log(Logs::Detail, Logs::None, "NoLOS"); - - if((PathingLOSState == HaveLOS) && zone->pathing->NoHazards(From, To)) - { - Log(Logs::Detail, Logs::None, "Target is reachable. Running directly there."); - return To; } } - Log(Logs::Detail, Logs::None, " Calculating new route to target."); - - Route = zone->pathing->FindRoute(From, To); - - PathingTraversedNodes = 0; - - if(Route.empty()) - { - Log(Logs::Detail, Logs::None, " No route available, running direct."); - - return To; - } - - if(SameDestination && (Route.front() == PathingLastNodeVisited)) - { - Log(Logs::Detail, Logs::None, " Probable loop detected. Same destination and Route.front() == PathingLastNodeVisited."); - - Route.clear(); - - return To; - } - NodeLoc = zone->pathing->GetPathNodeCoordinates(Route.front()); - - Log(Logs::Detail, Logs::None, " New route determined, heading for node %i", Route.front()); - - PathingLoopCount = 0; - - return NodeLoc; - } int PathManager::FindNearestPathNode(glm::vec3 Position) @@ -1254,14 +877,14 @@ bool PathManager::NoHazardsAccurate(glm::vec3 From, glm::vec3 To) void Mob::PrintRoute() { - printf("Route is : "); - - for(auto Iterator = Route.begin(); Iterator !=Route.end(); ++Iterator) - { - printf("%i, ", (*Iterator)); - } - - printf("\n"); + //printf("Route is : "); + // + //for(auto Iterator = Route.begin(); Iterator !=Route.end(); ++Iterator) + //{ + // printf("%i, ", (*Iterator)); + //} + // + //printf("\n"); } @@ -1346,7 +969,7 @@ void PathManager::ShowPathNodeNeighbours(Client *c) return; - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { @@ -1412,7 +1035,7 @@ void PathManager::NodeInfo(Client *c) return; } - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { return; @@ -1661,7 +1284,7 @@ bool PathManager::DeleteNode(Client *c) return false; } - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { return false; @@ -1742,7 +1365,7 @@ void PathManager::ConnectNodeToNode(Client *c, int32 Node2, int32 teleport, int3 return; } - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { return; @@ -1832,7 +1455,7 @@ void PathManager::ConnectNode(Client *c, int32 Node2, int32 teleport, int32 door return; } - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { return; @@ -1902,7 +1525,7 @@ void PathManager::DisconnectNodeToNode(Client *c, int32 Node2) return; } - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { return; @@ -1986,7 +1609,7 @@ void PathManager::MoveNode(Client *c) return; } - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { return; @@ -2020,7 +1643,7 @@ void PathManager::DisconnectAll(Client *c) return; } - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { return; @@ -2193,7 +1816,7 @@ void PathManager::QuickConnect(Client *c, bool set) return; } - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); + PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); if(!Node) { return; diff --git a/zone/pathing.h b/zone/pathing.h index d65ebfdcf..9921a2ed3 100644 --- a/zone/pathing.h +++ b/zone/pathing.h @@ -59,26 +59,18 @@ public: ~PathManager(); - static PathManager *LoadPathFile(const char *ZoneName); - bool loadPaths(FILE *fp); - void PrintPathing(); + static PathManager *LoadPathFile(const char *ZoneName); std::deque FindRoute(glm::vec3 Start, glm::vec3 End); +private: + bool loadPaths(FILE *fp); std::deque FindRoute(int startID, int endID); - glm::vec3 GetPathNodeCoordinates(int NodeNumber, bool BestZ = true); + void PrintPathing(); bool CheckLosFN(glm::vec3 a, glm::vec3 b); - void SpawnPathNodes(); - void MeshTest(); - void SimpleMeshTest(); - int FindNearestPathNode(glm::vec3 Position); bool NoHazards(glm::vec3 From, glm::vec3 To); bool NoHazardsAccurate(glm::vec3 From, glm::vec3 To); void OpenDoors(int Node1, int Node2, Mob* ForWho); - PathNode* FindPathNodeByCoordinates(float x, float y, float z); - void ShowPathNodeNeighbours(Client *c); - int GetRandomPathNode(); - void NodeInfo(Client *c); int32 AddNode(float x, float y, float z, float best_z, int32 requested_id = 0); //return -1 on failure, else returns the id of this node bool DeleteNode(Client *c); @@ -98,7 +90,16 @@ public: void QuickConnect(Client *c, bool set = false); void SortNodes(); -private: + glm::vec3 GetPathNodeCoordinates(int NodeNumber, bool BestZ = true); + void SpawnPathNodes(); + void MeshTest(); + void SimpleMeshTest(); + int FindNearestPathNode(glm::vec3 Position); + + PathNode* FindPathNodeByCoordinates(float x, float y, float z); + void ShowPathNodeNeighbours(Client *c); + int GetRandomPathNode(); + PathFileHeader Head; PathNode *PathNodes; int QuickConnectTarget; diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index f95deb3de..e27a2f241 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -5886,43 +5886,6 @@ XS(XS_Mob_CalculateNewPosition) XSRETURN(1); } -XS(XS_Mob_CalculateNewPosition2); /* prototype to pass -Wmissing-prototypes */ -XS(XS_Mob_CalculateNewPosition2) -{ - dXSARGS; - if (items < 5 || items > 6) - Perl_croak(aTHX_ "Usage: Mob::CalculateNewPosition2(THIS, x, y, z, speed, checkZ= false)"); - { - Mob * THIS; - bool RETVAL; - float x = (float)SvNV(ST(1)); - float y = (float)SvNV(ST(2)); - float z = (float)SvNV(ST(3)); - float speed = (float)SvNV(ST(4)); - bool checkZ; - - if (sv_derived_from(ST(0), "Mob")) { - IV tmp = SvIV((SV*)SvRV(ST(0))); - THIS = INT2PTR(Mob *,tmp); - } - else - Perl_croak(aTHX_ "THIS is not of type Mob"); - if(THIS == nullptr) - Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - - if (items < 6) - checkZ = false; - else { - checkZ = (bool)SvTRUE(ST(5)); - } - - RETVAL = THIS->CalculateNewPosition2(x, y, z, speed, checkZ); - ST(0) = boolSV(RETVAL); - sv_2mortal(ST(0)); - } - XSRETURN(1); -} - XS(XS_Mob_CalculateDistance); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_CalculateDistance) { @@ -9262,7 +9225,6 @@ XS(boot_Mob) newXSproto(strcpy(buf, "CheckAggro"), XS_Mob_CheckAggro, file, "$$"); newXSproto(strcpy(buf, "CalculateHeadingToTarget"), XS_Mob_CalculateHeadingToTarget, file, "$$$"); newXSproto(strcpy(buf, "CalculateNewPosition"), XS_Mob_CalculateNewPosition, file, "$$$$$;$"); - newXSproto(strcpy(buf, "CalculateNewPosition2"), XS_Mob_CalculateNewPosition2, file, "$$$$$;$"); newXSproto(strcpy(buf, "CalculateDistance"), XS_Mob_CalculateDistance, file, "$$$$"); newXSproto(strcpy(buf, "SendTo"), XS_Mob_SendTo, file, "$$$$"); newXSproto(strcpy(buf, "SendToFixZ"), XS_Mob_SendToFixZ, file, "$$$$"); diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index c77e96979..b06f39ca5 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -673,76 +673,79 @@ void QuestManager::repopzone() { } void QuestManager::ConnectNodeToNode(int node1, int node2, int teleport, int doorid) { - if (!node1 || !node2) - { - Log(Logs::General, Logs::Quests, "QuestManager::ConnectNodeToNode called without node1 or node2. Probably syntax error in quest file."); - } - else - { - if (!teleport) - { - teleport = 0; - } - else if (teleport == 1 || teleport == -1) - { - teleport = -1; - } - - if (!doorid) - { - doorid = 0; - } - - if (!zone->pathing) - { - // if no pathing bits available, make them available. - zone->pathing = new PathManager(); - } - - if (zone->pathing) - { - zone->pathing->ConnectNodeToNode(node1, node2, teleport, doorid); - Log(Logs::Moderate, Logs::Quests, "QuestManager::ConnectNodeToNode connecting node %i to node %i.", node1, node2); - } - } + //PATHING TODO + //if (!node1 || !node2) + //{ + // Log(Logs::General, Logs::Quests, "QuestManager::ConnectNodeToNode called without node1 or node2. Probably syntax error in quest file."); + //} + //else + //{ + // if (!teleport) + // { + // teleport = 0; + // } + // else if (teleport == 1 || teleport == -1) + // { + // teleport = -1; + // } + // + // if (!doorid) + // { + // doorid = 0; + // } + // + // if (!zone->pathing) + // { + // // if no pathing bits available, make them available. + // zone->pathing = new PathManager(); + // } + // + // if (zone->pathing) + // { + // zone->pathing->ConnectNodeToNode(node1, node2, teleport, doorid); + // Log(Logs::Moderate, Logs::Quests, "QuestManager::ConnectNodeToNode connecting node %i to node %i.", node1, node2); + // } + //} } void QuestManager::AddNode(float x, float y, float z, float best_z, int32 requested_id) { - if (!x || !y || !z) - { - Log(Logs::General, Logs::Quests, "QuestManager::AddNode called without x, y, z. Probably syntax error in quest file."); - } + //PATHING TODO - if (!best_z || best_z == 0) - { - if (zone->zonemap) - { - glm::vec3 loc(x, y, z); - best_z = zone->zonemap->FindBestZ(loc, nullptr); - } - else - { - best_z = z; - } - } - - if (!requested_id) - { - requested_id = 0; - } - - if (!zone->pathing) - { - // if no pathing bits available, make them available. - zone->pathing = new PathManager(); - } - - if (zone->pathing) - { - zone->pathing->AddNode(x, y, z, best_z, requested_id); - Log(Logs::Moderate, Logs::Quests, "QuestManager::AddNode adding node at (%i, %i, %i).", x, y, z); - } + //if (!x || !y || !z) + //{ + // Log(Logs::General, Logs::Quests, "QuestManager::AddNode called without x, y, z. Probably syntax error in quest file."); + //} + // + //if (!best_z || best_z == 0) + //{ + // if (zone->zonemap) + // { + // glm::vec3 loc(x, y, z); + // best_z = zone->zonemap->FindBestZ(loc, nullptr); + // } + // else + // { + // best_z = z; + // } + //} + // + //if (!requested_id) + //{ + // requested_id = 0; + //} + // + //if (!zone->pathing) + //{ + // // if no pathing bits available, make them available. + // zone->pathing = new PathManager(); + //} + // + //if (zone->pathing) + //{ + // zone->pathing->AddNode(x, y, z, best_z, requested_id); + // Log(Logs::Moderate, Logs::Quests, "QuestManager::AddNode adding node at (%i, %i, %i).", x, y, z); + //} } void QuestManager::settarget(const char *type, int target_id) { diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 15ab630ca..ad423113a 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -412,7 +412,7 @@ void NPC::SaveGuardSpot(bool iClearGuardSpot) { } void NPC::NextGuardPosition() { - if (!CalculateNewPosition2(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, GetMovespeed())) { + if (!CalculateNewPosition(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, GetMovespeed())) { SetHeading(m_GuardPoint.w); Log(Logs::Detail, Logs::AI, "Unable to move to next guard position. Probably rooted."); } @@ -625,89 +625,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo return true; } -bool Mob::CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { - return MakeNewPositionAndSendUpdate(x, y, z, speed, checkZ); -} - bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { - if (GetID() == 0) - return true; - - float nx = m_Position.x; - float ny = m_Position.y; - float nz = m_Position.z; - - // if NPC is rooted - if (speed == 0) { - SetHeading(CalculateHeadingToTarget(x, y)); - if (moved) { - SetCurrentSpeed(0); - moved = false; - } - Log(Logs::Detail, Logs::AI, "Rooted while calculating new position to (%.3f, %.3f, %.3f)", x, y, z); - return true; - } - - float old_test_vector = test_vector; - m_TargetV.x = x - nx; - m_TargetV.y = y - ny; - m_TargetV.z = z - nz; - - if (m_TargetV.x == 0 && m_TargetV.y == 0) - return false; - SetCurrentSpeed((int8)(speed)); //*NPC_RUNANIM_RATIO); - //speed *= NPC_SPEED_MULTIPLIER; - - Log(Logs::Detail, Logs::AI, "Calculating new position to (%.3f, %.3f, %.3f) vector (%.3f, %.3f, %.3f) rate %.3f RAS %d", x, y, z, m_TargetV.x, m_TargetV.y, m_TargetV.z, speed, pRunAnimSpeed); - - // -------------------------------------------------------------------------- - // 2: get unit vector - // -------------------------------------------------------------------------- - test_vector = sqrtf(x*x + y*y + z*z); - tar_vector = speed / sqrtf(m_TargetV.x*m_TargetV.x + m_TargetV.y*m_TargetV.y + m_TargetV.z*m_TargetV.z); - m_Position.w = CalculateHeadingToTarget(x, y); - - if (tar_vector >= 1.0) { - if (IsNPC()) { - entity_list.ProcessMove(CastToNPC(), x, y, z); - } - - m_Position.x = x; - m_Position.y = y; - m_Position.z = z; - Log(Logs::Detail, Logs::AI, "Close enough, jumping to waypoint"); - } - else { - float new_x = m_Position.x + m_TargetV.x*tar_vector; - float new_y = m_Position.y + m_TargetV.y*tar_vector; - float new_z = m_Position.z + m_TargetV.z*tar_vector; - if (IsNPC()) { - entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z); - } - - m_Position.x = new_x; - m_Position.y = new_y; - m_Position.z = new_z; - Log(Logs::Detail, Logs::AI, "Next position (%.3f, %.3f, %.3f)", m_Position.x, m_Position.y, m_Position.z); - } - - if (fix_z_timer.Check()) - this->FixZ(); - - //OP_MobUpdate - if ((old_test_vector != test_vector) || tar_ndx>20) { //send update - tar_ndx = 0; - this->SetMoving(true); - moved = true; - m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f); - SendPositionUpdate(); - } - tar_ndx++; - - // now get new heading - SetAppearance(eaStanding, false); // make sure they're standing - pLastChange = Timer::GetCurrentTime(); - return true; + return MakeNewPositionAndSendUpdate(x, y, z, speed, checkZ); } void NPC::AssignWaypoints(int32 grid) diff --git a/zone/zone.cpp b/zone/zone.cpp index 6a0754dea..c1ef23119 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -42,7 +42,9 @@ #include "net.h" #include "npc.h" #include "object.h" -#include "pathing.h" +#include "pathfinder_null.h" +#include "pathfinder_nav_mesh.h" +#include "pathfinder_waypoint.h" #include "petitions.h" #include "quest_parser_collection.h" #include "spawn2.h" @@ -893,7 +895,7 @@ bool Zone::Init(bool iStaticZone) { zone->zonemap = Map::LoadMapFile(zone->map_name); zone->watermap = WaterMap::LoadWaterMapfile(zone->map_name); - zone->pathing = PathManager::LoadPathFile(zone->map_name); + zone->pathing = IPathfinder::Load(zone->map_name); Log(Logs::General, Logs::Status, "Loading spawn conditions..."); if(!spawn_conditions.LoadSpawnConditions(short_name, instanceid)) { diff --git a/zone/zone.h b/zone/zone.h index a3e9f59b4..4f5e3b5cc 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -28,6 +28,7 @@ #include "spawn2.h" #include "spawngroup.h" #include "aa_ability.h" +#include "pathfinder_interface.h" struct ZonePoint { @@ -73,7 +74,6 @@ struct item_tick_struct { class Client; class Map; class Mob; -class PathManager; class WaterMap; extern EntityList entity_list; struct NPCType; @@ -211,7 +211,7 @@ public: Map* zonemap; WaterMap* watermap; - PathManager *pathing; + IPathfinder *pathing; NewZone_Struct newzone_data; SpawnConditionManager spawn_conditions;