diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index 907a47192..c85922334 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -205,7 +205,6 @@ SET(zone_headers pathfinder_nav_mesh.h pathfinder_null.h pathfinder_waypoint.h - pathing.h perlpacket.h petitions.h pets.h diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 5ba73d068..b7ca796cc 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -63,7 +63,6 @@ #include "guild_mgr.h" #include "map.h" #include "doors.h" -#include "pathing.h" #include "qglobals.h" #include "queryserv.h" #include "quest_parser_collection.h" diff --git a/zone/client.h b/zone/client.h index 640d9dc98..336bc7725 100644 --- a/zone/client.h +++ b/zone/client.h @@ -300,8 +300,8 @@ public: void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); virtual bool Process(); + void ProcessPackets(); void LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQEmu::ItemData* item, bool buying); - void SendPacketQueue(bool Block = true); void QueuePacket(const EQApplicationPacket* app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL, eqFilterType filter=FilterNone); void FastQueuePacket(EQApplicationPacket** app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL); void ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_skill, const char* orig_message, const char* targetname=nullptr); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c45aca912..a2ca6f4b7 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4366,7 +4366,6 @@ void Client::Handle_OP_ClientTimeStamp(const EQApplicationPacket *app) void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { - Log(Logs::General, Logs::Status, "Incoming client position packet"); if (IsAIControlled()) return; @@ -4380,8 +4379,12 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) Log(Logs::General, Logs::Error, "OP size error: OP_ClientUpdate expected:%i got:%i", sizeof(PlayerPositionUpdateClient_Struct), app->size); return; } + PlayerPositionUpdateClient_Struct* ppu = (PlayerPositionUpdateClient_Struct*)app->pBuffer; + Message(0, "Client Update Position (%.2f, %.2f, %.2f, %u) (%u)", ppu->x_pos, ppu->y_pos, ppu->z_pos, ppu->heading, ppu->animation); + Message(0, "Client Update Deltas (%.2f, %.2f, %.2f, %u)", ppu->delta_x, ppu->delta_y, ppu->delta_z, ppu->delta_heading); + /* Boat handling */ if (ppu->spawn_id != GetID()) { /* If player is controlling boat */ @@ -4607,7 +4610,6 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) m_Position.x = ppu->x_pos; m_Position.y = ppu->y_pos; m_Position.z = ppu->z_pos; - Log(Logs::General, Logs::Status, "Client position updated"); /* Visual Debugging */ if (RuleB(Character, OPClientUpdateVisualDebug)) { @@ -5690,128 +5692,111 @@ 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); + + auto 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; + + auto v = pathlist.back(); + + p.x = v.pos.x; + p.y = v.pos.y; + p.z = v.pos.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).teleport) // Teleporter + { + LeadsToTeleporter = true; + break; + } + + glm::vec3 v = (*Iterator).pos; + 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); + } } void Client::Handle_OP_Fishing(const EQApplicationPacket *app) diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 672848acc..eb89bb546 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -600,9 +600,8 @@ bool Client::Process() { EQApplicationPacket *app = nullptr; if (!eqs->CheckState(CLOSING)) { - while (ret && (app = (EQApplicationPacket *)eqs->PopPacket())) { - if (app) - ret = HandlePacket(app); + while (app = eqs->PopPacket()) { + HandlePacket(app); safe_delete(app); } } diff --git a/zone/command.cpp b/zone/command.cpp index 405eb8889..ebf70d03e 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -59,7 +59,6 @@ #include "command.h" #include "guild_mgr.h" #include "map.h" -#include "pathing.h" #include "qglobals.h" #include "queryserv.h" #include "quest_parser_collection.h" @@ -6816,313 +6815,6 @@ void command_path(Client *c, const Seperator *sep) if (zone->pathing) { zone->pathing->DebugCommand(c, 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."); } void Client::Undye() { diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 3a1215748..a3a39993c 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -19,7 +19,6 @@ #include "../common/rulesys.h" #include "map.h" -#include "pathing.h" #include "zone.h" #ifdef _WINDOWS @@ -142,10 +141,10 @@ void Mob::CalculateNewFearpoint() if (!Route.empty()) { auto first = (*Route.begin()); - m_FearWalkTarget = glm::vec3(first.x, first.y, first.z); + m_FearWalkTarget = glm::vec3(first.pos.x, first.pos.y, first.pos.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); + Log(Logs::Detail, Logs::None, "Feared to node %i (%8.3f, %8.3f, %8.3f)", Node, first.pos.x, first.pos.y, first.pos.z); return; } diff --git a/zone/pathfinder_interface.h b/zone/pathfinder_interface.h index e701b7f37..fc120fb43 100644 --- a/zone/pathfinder_interface.h +++ b/zone/pathfinder_interface.h @@ -9,7 +9,22 @@ class Seperator; class IPathfinder { public: - typedef std::list IPath; + struct IPathNode + { + IPathNode(const glm::vec3 &p) { + pos = p; + teleport = false; + } + + IPathNode(bool tp) { + teleport = tp; + } + + glm::vec3 pos; + bool teleport; + }; + + typedef std::list IPath; IPathfinder() { } virtual ~IPathfinder() { } diff --git a/zone/pathfinder_waypoint.cpp b/zone/pathfinder_waypoint.cpp index c741c4547..10c8c97a8 100644 --- a/zone/pathfinder_waypoint.cpp +++ b/zone/pathfinder_waypoint.cpp @@ -3,14 +3,15 @@ #include #include #include +#include +#include +#include #include "pathfinder_waypoint.h" #include "zone.h" #include "client.h" #include "../common/eqemu_logsys.h" #include "../common/rulesys.h" -#include -#include extern Zone *zone; @@ -115,6 +116,7 @@ PathfinderWaypoint::PathfinderWaypoint(const std::string &path) if (strncmp(Magic, "EQEMUPATH", 9)) { Log(Logs::General, Logs::Error, "Bad Magic String in .path file."); + fclose(f); return; } @@ -123,62 +125,20 @@ PathfinderWaypoint::PathfinderWaypoint(const std::string &path) Log(Logs::General, Logs::Status, "Path File Header: Version %ld, PathNodes %ld", (long)Head.version, (long)Head.PathNodeCount); - if (Head.version != 2) + if (Head.version == 2) { - Log(Logs::General, Logs::Error, "Unsupported path file version."); + LoadV2(f, Head); return; } - - std::unique_ptr PathNodes(new PathNode[Head.PathNodeCount]); - - fread(PathNodes.get(), sizeof(PathNode), Head.PathNodeCount, f); - - int MaxNodeID = Head.PathNodeCount - 1; - - m_impl->PathFileValid = true; - - m_impl->Nodes.reserve(Head.PathNodeCount); - for (uint32 i = 0; i < Head.PathNodeCount; ++i) - { - auto &n = PathNodes[i]; - - Point p = Point(n.v.x, n.v.y, n.v.z); - m_impl->Tree.insert(std::make_pair(p, i)); - - boost::add_vertex(m_impl->Graph); - Node node; - node.v = n.v; - node.bestz = n.bestz; - m_impl->Nodes.push_back(node); + else if (Head.version == 3) { + LoadV3(f, Head); + return; } - - auto weightmap = boost::get(boost::edge_weight, m_impl->Graph); - for (uint32 i = 0; i < Head.PathNodeCount; ++i) { - for (uint32 j = 0; j < 50; ++j) - { - if (PathNodes[i].Neighbours[j].id > MaxNodeID) - { - Log(Logs::General, Logs::Error, "Path Node %i, Neighbour %i (%i) out of range.", i, j, PathNodes[i].Neighbours[j].id); - m_impl->PathFileValid = false; - } - - if (PathNodes[i].Neighbours[j].id > 0) { - GraphType::edge_descriptor e; - bool inserted; - boost::tie(e, inserted) = boost::add_edge(PathNodes[i].id, PathNodes[i].Neighbours[j].id, m_impl->Graph); - weightmap[e] = PathNodes[i].Neighbours[j].distance; - - Edge edge; - edge.distance = PathNodes[i].Neighbours[j].distance; - edge.door_id = PathNodes[i].Neighbours[j].DoorID; - edge.teleport = PathNodes[i].Neighbours[j].Teleport; - - m_impl->Edges[std::make_pair(PathNodes[i].id, PathNodes[i].Neighbours[j].id)] = edge; - } - } + else { + Log(Logs::General, Logs::Error, "Unsupported path file version."); + fclose(f); + return; } - - fclose(f); } } @@ -239,8 +199,7 @@ IPathfinder::IPath PathfinderWaypoint::FindRoute(const glm::vec3 &start, const g auto &edge = iter->second; if (edge.teleport) { Route.push_front(m_impl->Nodes[v].v); - glm::vec3 teleport(100000000.0f, 100000000.0f, 100000000.0f); - Route.push_front(teleport); + Route.push_front(true); } else { Route.push_front(m_impl->Nodes[v].v); @@ -295,16 +254,75 @@ void PathfinderWaypoint::DebugCommand(Client *c, const Seperator *sep) { if (c->GetTarget() != nullptr) { auto target = c->GetTarget(); - glm::vec3 start(target->GetX(), target->GetY(), target->GetZ()); - glm::vec3 end(c->GetX(), c->GetY(), c->GetZ()); + glm::vec3 end(target->GetX(), target->GetY(), target->GetZ()); + glm::vec3 start(c->GetX(), c->GetY(), c->GetZ()); - ShowPath(start, end); + ShowPath(c, start, end); } return; } } +void PathfinderWaypoint::LoadV2(FILE *f, const PathFileHeader &header) +{ + std::unique_ptr PathNodes(new PathNode[header.PathNodeCount]); + + fread(PathNodes.get(), sizeof(PathNode), header.PathNodeCount, f); + + int MaxNodeID = header.PathNodeCount - 1; + + m_impl->PathFileValid = true; + + m_impl->Nodes.reserve(header.PathNodeCount); + for (uint32 i = 0; i < header.PathNodeCount; ++i) + { + auto &n = PathNodes[i]; + + Point p = Point(n.v.x, n.v.y, n.v.z); + m_impl->Tree.insert(std::make_pair(p, i)); + + boost::add_vertex(m_impl->Graph); + Node node; + node.v = n.v; + node.bestz = n.bestz; + m_impl->Nodes.push_back(node); + } + + auto weightmap = boost::get(boost::edge_weight, m_impl->Graph); + for (uint32 i = 0; i < header.PathNodeCount; ++i) { + for (uint32 j = 0; j < 50; ++j) + { + if (PathNodes[i].Neighbours[j].id > MaxNodeID) + { + Log(Logs::General, Logs::Error, "Path Node %i, Neighbour %i (%i) out of range.", i, j, PathNodes[i].Neighbours[j].id); + m_impl->PathFileValid = false; + } + + if (PathNodes[i].Neighbours[j].id > 0) { + GraphType::edge_descriptor e; + bool inserted; + boost::tie(e, inserted) = boost::add_edge(PathNodes[i].id, PathNodes[i].Neighbours[j].id, m_impl->Graph); + weightmap[e] = PathNodes[i].Neighbours[j].distance; + + Edge edge; + edge.distance = PathNodes[i].Neighbours[j].distance; + edge.door_id = PathNodes[i].Neighbours[j].DoorID; + edge.teleport = PathNodes[i].Neighbours[j].Teleport; + + m_impl->Edges[std::make_pair(PathNodes[i].id, PathNodes[i].Neighbours[j].id)] = edge; + } + } + } + + fclose(f); +} + +void PathfinderWaypoint::LoadV3(FILE *f, const PathFileHeader &header) +{ + fclose(f); +} + void PathfinderWaypoint::ShowNodes() { for (size_t i = 0; i < m_impl->Nodes.size(); ++i) @@ -348,46 +366,22 @@ void PathfinderWaypoint::ShowNodes() } } -void PathfinderWaypoint::ShowPath(const glm::vec3 &start, const glm::vec3 &end) +void PathfinderWaypoint::ShowPath(Client *c, const glm::vec3 &start, const glm::vec3 &end) { auto path = FindRoute(start, end); + std::vector points; + FindPerson_Point p; for (auto &node : path) { - auto npc_type = new NPCType; - memset(npc_type, 0, sizeof(NPCType)); - - sprintf(npc_type->name, "Path"); - npc_type->cur_hp = 4000000; - npc_type->max_hp = 4000000; - npc_type->race = 2254; - npc_type->gender = 2; - npc_type->class_ = 9; - npc_type->deity = 1; - npc_type->level = 75; - npc_type->npc_id = 0; - npc_type->loottable_id = 0; - npc_type->texture = 1; - npc_type->light = 0; - npc_type->runspeed = 0; - npc_type->d_melee_texture1 = 1; - npc_type->d_melee_texture2 = 1; - npc_type->merchanttype = 1; - npc_type->bodytype = 1; - - npc_type->STR = 150; - npc_type->STA = 150; - npc_type->DEX = 150; - npc_type->AGI = 150; - npc_type->INT = 150; - npc_type->WIS = 150; - npc_type->CHA = 150; - - npc_type->findable = 1; - auto position = glm::vec4(node.x, node.y, node.z, 0.0f); - auto npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - - entity_list.AddNPC(npc, true, true); + if (!node.teleport) { + p.x = node.pos.x; + p.y = node.pos.y; + p.z = node.pos.z; + + points.push_back(p); + } } + + c->SendPathPacket(points); } diff --git a/zone/pathfinder_waypoint.h b/zone/pathfinder_waypoint.h index 493531802..5d10ea25a 100644 --- a/zone/pathfinder_waypoint.h +++ b/zone/pathfinder_waypoint.h @@ -1,7 +1,8 @@ #pragma once #include "pathfinder_interface.h" -#include + +struct PathFileHeader; class PathfinderWaypoint : public IPathfinder { @@ -14,8 +15,10 @@ public: virtual void DebugCommand(Client *c, const Seperator *sep); private: + void LoadV2(FILE *f, const PathFileHeader &header); + void LoadV3(FILE *f, const PathFileHeader &header); void ShowNodes(); - void ShowPath(const glm::vec3 &start, const glm::vec3 &end); + void ShowPath(Client *c, const glm::vec3 &start, const glm::vec3 &end); struct Implementation; std::unique_ptr m_impl; diff --git a/zone/pathing.cpp b/zone/pathing.cpp index 7bbc3c727..3be00c473 100644 --- a/zone/pathing.cpp +++ b/zone/pathing.cpp @@ -1,647 +1,10 @@ #include "../common/global_define.h" #include "client.h" -#include "doors.h" -#include "pathing.h" -#include "water_map.h" #include "zone.h" -#include -#include -#include -#include -#include - -#ifdef _WINDOWS -#define snprintf _snprintf -#endif - -//#define PATHDEBUG - extern Zone *zone; -float VectorDistance(glm::vec3 a, glm::vec3 b) -{ - float xdist = a.x - b.x; - float ydist = a.y - b.y; - float zdist = a.z - b.z; - return sqrtf(xdist * xdist + ydist * ydist + zdist * zdist); -} - -float VectorDistanceNoRoot(glm::vec3 a, glm::vec3 b) -{ - float xdist = a.x - b.x; - float ydist = a.y - b.y; - float zdist = a.z - b.z; - return xdist * xdist + ydist * ydist + zdist * zdist; - -} - -PathManager* PathManager::LoadPathFile(const char* ZoneName) -{ - - FILE *PathFile = nullptr; - - char LowerCaseZoneName[64]; - - char ZonePathFileName[256]; - - PathManager* Ret = nullptr; - - strn0cpy(LowerCaseZoneName, ZoneName, 64); - - strlwr(LowerCaseZoneName); - - snprintf(ZonePathFileName, 250, "%s%s.path", Config->MapDir.c_str(), LowerCaseZoneName); - - if((PathFile = fopen(ZonePathFileName, "rb"))) - { - Ret = new PathManager(); - - if(Ret->loadPaths(PathFile)) - { - Log(Logs::General, Logs::Status, "Path File %s loaded.", ZonePathFileName); - - } - else - { - Log(Logs::General, Logs::Error, "Path File %s failed to load.", ZonePathFileName); - safe_delete(Ret); - } - fclose(PathFile); - } - else - { - Log(Logs::General, Logs::Error, "Path File %s not found.", ZonePathFileName); - } - - return Ret; -} - -PathManager::PathManager() -{ - PathNodes = nullptr; - ClosedListFlag = nullptr; - Head.PathNodeCount = 0; - Head.version = 2; - QuickConnectTarget = -1; -} - -PathManager::~PathManager() -{ - safe_delete_array(PathNodes); - safe_delete_array(ClosedListFlag); -} - -bool PathManager::loadPaths(FILE *PathFile) -{ - - char Magic[10]; - - fread(&Magic, 9, 1, PathFile); - - if(strncmp(Magic, "EQEMUPATH", 9)) - { - Log(Logs::General, Logs::Error, "Bad Magic String in .path file."); - return false; - } - - fread(&Head, sizeof(Head), 1, PathFile); - - Log(Logs::General, Logs::Status, "Path File Header: Version %ld, PathNodes %ld", - (long)Head.version, (long)Head.PathNodeCount); - - if(Head.version != 2) - { - Log(Logs::General, Logs::Error, "Unsupported path file version."); - return false; - } - - PathNodes = new PathNode[Head.PathNodeCount]; - - fread(PathNodes, sizeof(PathNode), Head.PathNodeCount, PathFile); - - ClosedListFlag = new int[Head.PathNodeCount]; - -#ifdef PATHDEBUG - PrintPathing(); -#endif - - int MaxNodeID = Head.PathNodeCount - 1; - - bool PathFileValid = true; - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - for(uint32 j = 0; j < PATHNODENEIGHBOURS; ++j) - { - if(PathNodes[i].Neighbours[j].id > MaxNodeID) - { - Log(Logs::General, Logs::Error, "Path Node %i, Neighbour %i (%i) out of range.", i, j, PathNodes[i].Neighbours[j].id); - - PathFileValid = false; - } - } - } - - if(!PathFileValid) - { - safe_delete_array(PathNodes); - } - - return PathFileValid; -} - -void PathManager::PrintPathing() -{ - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - printf("PathNode: %2d id %2d. (%8.3f, %8.3f, %8.3f), BestZ: %8.3f\n", - i, PathNodes[i].id, PathNodes[i].v.x, PathNodes[i].v.y, PathNodes[i].v.z, PathNodes[i].bestz); - - - if(PathNodes[i].Neighbours[0].id == -1) - { - printf(" NO NEIGHBOURS.\n"); - continue; - } - - for(int j=0; j= 0) - printf(" ***** via door %i *****", PathNodes[i].Neighbours[j].DoorID); - - printf("\n"); - } - } -} - -glm::vec3 PathManager::GetPathNodeCoordinates(int NodeNumber, bool BestZ) -{ - glm::vec3 Result; - - if(NodeNumber < Head.PathNodeCount) - { - Result = PathNodes[NodeNumber].v; - - if(!BestZ) - return Result; - - Result.z = PathNodes[NodeNumber].bestz; - } - - return Result; - -} - -std::deque PathManager::FindRoute(int startID, int endID) -{ - Log(Logs::Detail, Logs::None, "FindRoute from node %i to %i", startID, endID); - - memset(ClosedListFlag, 0, sizeof(int) * Head.PathNodeCount); - - std::deque OpenList, ClosedList; - - std::dequeRoute; - - AStarNode AStarEntry, CurrentNode; - - AStarEntry.PathNodeID = startID; - AStarEntry.Parent = -1; - AStarEntry.HCost = 0; - AStarEntry.GCost = 0; - AStarEntry.Teleport = false; - - OpenList.push_back(AStarEntry); - - while(!OpenList.empty()) - { - // The OpenList is maintained in sorted order, lowest to highest cost. - - CurrentNode = (*OpenList.begin()); - - ClosedList.push_back(CurrentNode); - - ClosedListFlag[CurrentNode.PathNodeID] = true; - - OpenList.pop_front(); - - for(int i = 0; i < PATHNODENEIGHBOURS; ++i) - { - if(PathNodes[CurrentNode.PathNodeID].Neighbours[i].id == -1) - break; - - if(PathNodes[CurrentNode.PathNodeID].Neighbours[i].id == CurrentNode.Parent) - continue; - - if(PathNodes[CurrentNode.PathNodeID].Neighbours[i].id == endID) - { - Route.push_back(CurrentNode.PathNodeID); - - Route.push_back(endID); - - std::deque::iterator RouteIterator; - - while(CurrentNode.PathNodeID != startID) - { - for(RouteIterator = ClosedList.begin(); RouteIterator != ClosedList.end(); ++RouteIterator) - { - if((*RouteIterator).PathNodeID == CurrentNode.Parent) - { - if(CurrentNode.Teleport) - Route.insert(Route.begin(), -1); - - CurrentNode = (*RouteIterator); - - Route.insert(Route.begin(), CurrentNode.PathNodeID); - - break; - } - } - } - - return Route; - } - if(ClosedListFlag[PathNodes[CurrentNode.PathNodeID].Neighbours[i].id]) - continue; - - AStarEntry.PathNodeID = PathNodes[CurrentNode.PathNodeID].Neighbours[i].id; - - AStarEntry.Parent = CurrentNode.PathNodeID; - - AStarEntry.Teleport = PathNodes[CurrentNode.PathNodeID].Neighbours[i].Teleport; - - // HCost is the estimated cost to get from this node to the end. - AStarEntry.HCost = VectorDistance(PathNodes[PathNodes[CurrentNode.PathNodeID].Neighbours[i].id].v, - PathNodes[endID].v); - - AStarEntry.GCost = CurrentNode.GCost + PathNodes[CurrentNode.PathNodeID].Neighbours[i].distance; - - float FCost = AStarEntry.HCost + AStarEntry.GCost; -#ifdef PATHDEBUG - printf("Node: %i, Open Neighbour %i has HCost %8.3f, GCost %8.3f (Total Cost: %8.3f)\n", - CurrentNode.PathNodeID, - PathNodes[CurrentNode.PathNodeID].Neighbours[i].id, - AStarEntry.HCost, - AStarEntry.GCost, - AStarEntry.HCost + AStarEntry.GCost); -#endif - - bool AlreadyInOpenList = false; - - std::deque::iterator OpenListIterator, InsertionPoint = OpenList.end(); - - for(OpenListIterator = OpenList.begin(); OpenListIterator != OpenList.end(); ++OpenListIterator) - { - if((*OpenListIterator).PathNodeID == PathNodes[CurrentNode.PathNodeID].Neighbours[i].id) - { - AlreadyInOpenList = true; - - float GCostToNode = CurrentNode.GCost + PathNodes[CurrentNode.PathNodeID].Neighbours[i].distance; - - if(GCostToNode < (*OpenListIterator).GCost) - { - (*OpenListIterator).Parent = CurrentNode.PathNodeID; - - (*OpenListIterator).GCost = GCostToNode; - - (*OpenListIterator).Teleport = PathNodes[CurrentNode.PathNodeID].Neighbours[i].Teleport; - } - break; - } - else if((InsertionPoint == OpenList.end()) && (((*OpenListIterator).HCost + (*OpenListIterator).GCost) > FCost)) - { - InsertionPoint = OpenListIterator; - } - } - if(!AlreadyInOpenList) - OpenList.insert(InsertionPoint, AStarEntry); - } - - } - Log(Logs::Detail, Logs::None, "Unable to find a route."); - return Route; - -} - -bool CheckLOSBetweenPoints(glm::vec3 start, glm::vec3 end) { - - glm::vec3 hit; - - if((zone->zonemap) && (zone->zonemap->LineIntersectsZone(start, end, 1, &hit))) - return false; - - return true; -} - -auto path_compare = [](const PathNodeSortStruct& a, const PathNodeSortStruct& b) -{ - return a.Distance < b.Distance; -}; - -std::deque PathManager::FindRoute(glm::vec3 Start, glm::vec3 End) -{ - Log(Logs::Detail, Logs::None, "FindRoute(%8.3f, %8.3f, %8.3f, %8.3f, %8.3f, %8.3f)", Start.x, Start.y, Start.z, End.x, End.y, End.z); - - std::deque noderoute; - - float CandidateNodeRangeXY = RuleR(Pathing, CandidateNodeRangeXY); - - float CandidateNodeRangeZ = RuleR(Pathing, CandidateNodeRangeZ); - - // Find the nearest PathNode the Start has LOS to. - // - // - int ClosestPathNodeToStart = -1; - - std::deque SortedByDistance; - - PathNodeSortStruct TempNode; - - for(uint32 i = 0 ; i < Head.PathNodeCount; ++i) - { - if ((std::abs(Start.x - PathNodes[i].v.x) <= CandidateNodeRangeXY) && - (std::abs(Start.y - PathNodes[i].v.y) <= CandidateNodeRangeXY) && - (std::abs(Start.z - PathNodes[i].v.z) <= CandidateNodeRangeZ)) { - TempNode.id = i; - TempNode.Distance = VectorDistanceNoRoot(Start, PathNodes[i].v); - SortedByDistance.push_back(TempNode); - - } - } - - std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); - - for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) - { - Log(Logs::Detail, Logs::None, "Checking Reachability of Node %i from Start Position.", PathNodes[(*Iterator).id].id); - - if(!zone->zonemap->LineIntersectsZone(Start, PathNodes[(*Iterator).id].v, 1.0f, nullptr)) - { - ClosestPathNodeToStart = (*Iterator).id; - break; - } - } - - if(ClosestPathNodeToStart <0 ) { - Log(Logs::Detail, Logs::None, "No LOS to any starting Path Node within range."); - return noderoute; - } - - Log(Logs::Detail, Logs::None, "Closest Path Node To Start: %2d", ClosestPathNodeToStart); - - // Find the nearest PathNode the end point has LOS to - - int ClosestPathNodeToEnd = -1; - - SortedByDistance.clear(); - - for(uint32 i = 0 ; i < Head.PathNodeCount; ++i) - { - if ((std::abs(End.x - PathNodes[i].v.x) <= CandidateNodeRangeXY) && - (std::abs(End.y - PathNodes[i].v.y) <= CandidateNodeRangeXY) && - (std::abs(End.z - PathNodes[i].v.z) <= CandidateNodeRangeZ)) { - TempNode.id = i; - TempNode.Distance = VectorDistanceNoRoot(End, PathNodes[i].v); - SortedByDistance.push_back(TempNode); - } - } - - std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); - - for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) - { - Log(Logs::Detail, Logs::None, "Checking Reachability of Node %i from End Position.", PathNodes[(*Iterator).id].id); - Log(Logs::Detail, Logs::None, " (%8.3f, %8.3f, %8.3f) to (%8.3f, %8.3f, %8.3f)", - End.x, End.y, End.z, - PathNodes[(*Iterator).id].v.x, PathNodes[(*Iterator).id].v.y, PathNodes[(*Iterator).id].v.z); - - if(!zone->zonemap->LineIntersectsZone(End, PathNodes[(*Iterator).id].v, 1.0f, nullptr)) - { - ClosestPathNodeToEnd = (*Iterator).id; - break; - } - } - - if(ClosestPathNodeToEnd < 0) { - Log(Logs::Detail, Logs::None, "No LOS to any end Path Node within range."); - return noderoute; - } - - Log(Logs::Detail, Logs::None, "Closest Path Node To End: %2d", ClosestPathNodeToEnd); - - if(ClosestPathNodeToStart == ClosestPathNodeToEnd) - { - noderoute.push_back(ClosestPathNodeToStart); - return noderoute; - } - noderoute = FindRoute(ClosestPathNodeToStart, ClosestPathNodeToEnd); - - int NodesToAttemptToCull = RuleI(Pathing, CullNodesFromStart); - - if(NodesToAttemptToCull > 0) - { - int CulledNodes = 0; - - std::deque::iterator First, Second; - - while((noderoute.size() >= 2) && (CulledNodes < NodesToAttemptToCull)) - { - First = noderoute.begin(); - - Second = First; - - ++Second; - - if((*Second) < 0) - break; - - if(!zone->zonemap->LineIntersectsZone(Start, PathNodes[(*Second)].v, 1.0f, nullptr) - && NoHazards(Start, PathNodes[(*Second)].v)) - { - noderoute.erase(First); - - ++CulledNodes; - } - else - break; - } - } - - NodesToAttemptToCull = RuleI(Pathing, CullNodesFromEnd); - - if(NodesToAttemptToCull > 0) - { - int CulledNodes = 0; - - std::deque::iterator First, Second; - - while((noderoute.size() >= 2) && (CulledNodes < NodesToAttemptToCull)) - { - First = noderoute.end(); - - --First; - - Second = First; - - --Second; - - if((*Second) < 0) - break; - - if(!zone->zonemap->LineIntersectsZone(End, PathNodes[(*Second)].v, 1.0f, nullptr) - && NoHazards(End, PathNodes[(*Second)].v)) - { - noderoute.erase(First); - - ++CulledNodes; - } - else - break; - } - } - - return noderoute; -} - -const char* DigitToWord(int i) -{ - switch(i) { - case 0: - return "zero"; - case 1: - return "one"; - case 2: - return "two"; - case 3: - return "three"; - case 4: - return "four"; - case 5: - return "five"; - case 6: - return "six"; - case 7: - return "seven"; - case 8: - return "eight"; - case 9: - return "nine"; - } - return ""; -} - -void PathManager::SpawnPathNodes() -{ - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - auto npc_type = new NPCType; - memset(npc_type, 0, sizeof(NPCType)); - - auto c = PathNodes[i].id / 1000u; - sprintf(npc_type->name, "Node%u", c); - npc_type->cur_hp = 4000000; - npc_type->max_hp = 4000000; - npc_type->race = 2254; - npc_type->gender = 2; - npc_type->class_ = 9; - npc_type->deity= 1; - npc_type->level = 75; - npc_type->npc_id = 0; - npc_type->loottable_id = 0; - npc_type->texture = 1; - npc_type->light = 0; - npc_type->runspeed = 0; - npc_type->d_melee_texture1 = 1; - npc_type->d_melee_texture2 = 1; - npc_type->merchanttype = 1; - npc_type->bodytype = 1; - - npc_type->STR = 150; - npc_type->STA = 150; - npc_type->DEX = 150; - npc_type->AGI = 150; - npc_type->INT = 150; - npc_type->WIS = 150; - npc_type->CHA = 150; - - npc_type->findable = 1; - auto position = glm::vec4(PathNodes[i].v.x, PathNodes[i].v.y, PathNodes[i].v.z, 0.0f); - auto npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - - entity_list.AddNPC(npc, true, true); - } -} - -void PathManager::MeshTest() -{ - // This will test connectivity between all path nodes - - int TotalTests = 0; - int NoConnections = 0; - - printf("Beginning Pathmanager connectivity tests.\n"); fflush(stdout); - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - for(uint32 j = 0; j < Head.PathNodeCount; ++j) - { - if(j == i) - continue; - - std::deque Route = FindRoute(PathNodes[i].id, PathNodes[j].id); - - if(Route.empty()) - { - ++NoConnections; - printf("FindRoute(%i, %i) **** NO ROUTE FOUND ****\n", PathNodes[i].id, PathNodes[j].id); - } - ++TotalTests; - } - } - printf("Executed %i route searches.\n", TotalTests); - printf("Failed to find %i routes.\n", NoConnections); - fflush(stdout); -} - -void PathManager::SimpleMeshTest() -{ - // This will test connectivity between the first path node and all other nodes - - int TotalTests = 0; - int NoConnections = 0; - - printf("Beginning Pathmanager connectivity tests.\n"); - fflush(stdout); - - for(uint32 j = 1; j < Head.PathNodeCount; ++j) - { - std::deque Route = FindRoute(PathNodes[0].id, PathNodes[j].id); - - if(Route.empty()) - { - ++NoConnections; - printf("FindRoute(%i, %i) **** NO ROUTE FOUND ****\n", PathNodes[0].id, PathNodes[j].id); - } - ++TotalTests; - } - printf("Executed %i route searches.\n", TotalTests); - printf("Failed to find %i routes.\n", NoConnections); - fflush(stdout); -} - glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChanged, bool &NodeReached) { glm::vec3 To(ToX, ToY, ToZ); @@ -650,7 +13,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa } glm::vec3 From(GetX(), GetY(), GetZ()); - + if (DistanceSquared(To, From) < 1.0f) { WaypointChanged = false; NodeReached = true; @@ -663,7 +26,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa PathingDestination = To; WaypointChanged = true; NodeReached = false; - return *Route.begin(); + return (*Route.begin()).pos; } else { if (PathRecalcTimer->Check()) { @@ -674,290 +37,80 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa PathingDestination = To; WaypointChanged = true; NodeReached = false; - return *Route.begin(); + return (*Route.begin()).pos; } } - bool AtNextNode = DistanceSquared(From, *Route.begin()) < 4.0f; + bool AtNextNode = DistanceSquared(From, (*Route.begin()).pos) < 4.0f; if (AtNextNode) { WaypointChanged = false; NodeReached = true; - + Route.pop_front(); - + if (Route.empty()) { Route = zone->pathing->FindRoute(From, To); PathingDestination = To; WaypointChanged = true; - return *Route.begin(); + return (*Route.begin()).pos; } else { auto node = *Route.begin(); - if (node.x == 1000000.0f && node.y == 1000000.0f && node.z == 1000000.0f) { + if (node.teleport) { //If is identity node then is teleport node. Route.pop_front(); - + if (Route.empty()) { return To; } - + auto nextNode = *Route.begin(); - - Teleport(nextNode); - + + Teleport(nextNode.pos); + Route.pop_front(); - + if (Route.empty()) { return To; } - - return *Route.begin(); + + return (*Route.begin()).pos; } - - return node; + + return node.pos; } } else { WaypointChanged = false; NodeReached = false; - return *Route.begin(); + return (*Route.begin()).pos; } } } -int PathManager::FindNearestPathNode(glm::vec3 Position) -{ - - // Find the nearest PathNode we have LOS to. - // - // - - float CandidateNodeRangeXY = RuleR(Pathing, CandidateNodeRangeXY); - - float CandidateNodeRangeZ = RuleR(Pathing, CandidateNodeRangeZ); - - int ClosestPathNodeToStart = -1; - - std::deque SortedByDistance; - - PathNodeSortStruct TempNode; - - for(uint32 i = 0 ; i < Head.PathNodeCount; ++i) - { - if ((std::abs(Position.x - PathNodes[i].v.x) <= CandidateNodeRangeXY) && - (std::abs(Position.y - PathNodes[i].v.y) <= CandidateNodeRangeXY) && - (std::abs(Position.z - PathNodes[i].v.z) <= CandidateNodeRangeZ)) { - TempNode.id = i; - TempNode.Distance = VectorDistanceNoRoot(Position, PathNodes[i].v); - SortedByDistance.push_back(TempNode); - - } - } - - std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); - - for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) - { - Log(Logs::Detail, Logs::None, "Checking Reachability of Node %i from Start Position.", PathNodes[(*Iterator).id].id); - - if(!zone->zonemap->LineIntersectsZone(Position, PathNodes[(*Iterator).id].v, 1.0f, nullptr)) - { - ClosestPathNodeToStart = (*Iterator).id; - break; - } - } - - if(ClosestPathNodeToStart <0 ) { - Log(Logs::Detail, Logs::None, "No LOS to any starting Path Node within range."); - return -1; - } - return ClosestPathNodeToStart; -} - -bool PathManager::NoHazards(glm::vec3 From, glm::vec3 To) -{ - // Test the Z coordinate at the mid point. - // - glm::vec3 MidPoint((From.x + To.x) / 2, (From.y + To.y) / 2, From.z); - - float NewZ = zone->zonemap->FindBestZ(MidPoint, nullptr); - - if (std::abs(NewZ - From.z) > RuleR(Pathing, ZDiffThresholdNew)) { - Log(Logs::Detail, Logs::None, " HAZARD DETECTED moving from %8.3f, %8.3f, %8.3f to %8.3f, %8.3f, %8.3f. Z Change is %8.3f", - From.x, From.y, From.z, MidPoint.x, MidPoint.y, MidPoint.z, NewZ - From.z); - - return false; - } - else - { - Log(Logs::Detail, Logs::None, "No HAZARD DETECTED moving from %8.3f, %8.3f, %8.3f to %8.3f, %8.3f, %8.3f. Z Change is %8.3f", - From.x, From.y, From.z, MidPoint.x, MidPoint.y, MidPoint.z, NewZ - From.z); - } - - return true; -} - -bool PathManager::NoHazardsAccurate(glm::vec3 From, glm::vec3 To) -{ - float stepx, stepy, stepz, curx, cury, curz; - glm::vec3 cur = From; - float last_z = From.z; - float step_size = 1.0; - - curx = From.x; - cury = From.y; - curz = From.z; - - do - { - stepx = (float)To.x - curx; - stepy = (float)To.y - cury; - stepz = (float)To.z - curz; - float factor = sqrt(stepx*stepx + stepy*stepy + stepz*stepz); - stepx = (stepx / factor)*step_size; - stepy = (stepy / factor)*step_size; - stepz = (stepz / factor)*step_size; - - glm::vec3 TestPoint(curx, cury, curz); - float NewZ = zone->zonemap->FindBestZ(TestPoint, nullptr); - if (std::abs(NewZ - last_z) > 5.0f) { - Log(Logs::Detail, Logs::None, " HAZARD DETECTED moving from %8.3f, %8.3f, %8.3f to %8.3f, %8.3f, %8.3f. Best Z %8.3f, Z Change is %8.3f", - From.x, From.y, From.z, TestPoint.x, TestPoint.y, TestPoint.z, NewZ, NewZ - From.z); - return false; - } - last_z = NewZ; - - if (zone->watermap) - { - auto from = glm::vec3(From.x, From.y, From.z); - auto to = glm::vec3(To.x, To.y, To.z); - if (zone->watermap->InLiquid(from) || zone->watermap->InLiquid(to)) - { - break; - } - auto testPointNewZ = glm::vec3(TestPoint.x, TestPoint.y, NewZ); - if (zone->watermap->InLiquid(testPointNewZ)) - { - glm::vec3 TestPointWater(TestPoint.x, TestPoint.y, NewZ - 0.5f); - glm::vec3 TestPointWaterDest = TestPointWater; - glm::vec3 hit; - TestPointWaterDest.z -= 500; - float best_z2 = -999990; - if (zone->zonemap->LineIntersectsZone(TestPointWater, TestPointWaterDest, 1.0f, &hit)) - { - best_z2 = hit.z; - } - if (best_z2 == -999990) - { - Log(Logs::Detail, Logs::None, " HAZARD DETECTED, really deep water/lava!"); - return false; - } - else - { - if (std::abs(NewZ - best_z2) > RuleR(Pathing, ZDiffThresholdNew)) { - Log(Logs::Detail, Logs::None, - " HAZARD DETECTED, water is fairly deep at %8.3f units deep", - std::abs(NewZ - best_z2)); - return false; - } - else - { - Log(Logs::Detail, Logs::None, - " HAZARD NOT DETECTED, water is shallow at %8.3f units deep", - std::abs(NewZ - best_z2)); - } - } - } - else - { - Log(Logs::Detail, Logs::None, "Hazard point not in water or lava!"); - } - } - else - { - Log(Logs::Detail, Logs::None, "No water map loaded for hazards!"); - } - - curx += stepx; - cury += stepy; - curz += stepz; - - cur.x = curx; - cur.y = cury; - cur.z = curz; - - if (std::abs(curx - To.x) < step_size) - cur.x = To.x; - if (std::abs(cury - To.y) < step_size) - cur.y = To.y; - if (std::abs(curz - To.z) < step_size) - cur.z = To.z; - - } while (cur.x != To.x || cur.y != To.y || cur.z != To.z); - return true; -} - -void Mob::PrintRoute() -{ - - //printf("Route is : "); - // - //for(auto Iterator = Route.begin(); Iterator !=Route.end(); ++Iterator) - //{ - // printf("%i, ", (*Iterator)); - //} - // - //printf("\n"); - -} - -void PathManager::OpenDoors(int Node1, int Node2, Mob *ForWho) -{ - if(!ForWho || (Node1 >= Head.PathNodeCount) || (Node2 >= Head.PathNodeCount) || (Node1 < 0) || (Node2 < 0)) - return; - - for(int i = 0; i < PATHNODENEIGHBOURS; ++i) - { - if(PathNodes[Node1].Neighbours[i].id == -1) - return; - - if(PathNodes[Node1].Neighbours[i].id != Node2) - continue; - - if(PathNodes[Node1].Neighbours[i].DoorID >= 0) - { - Doors *d = entity_list.FindDoor(PathNodes[Node1].Neighbours[i].DoorID); - - if(d && !d->IsDoorOpen() ) - { - Log(Logs::Detail, Logs::None, "Opening door %i for %s", PathNodes[Node1].Neighbours[i].DoorID, ForWho->GetName()); - - d->ForceOpen(ForWho); - } - return; - } - } -} - -//this assumes that the first point in the list is the player's -//current position, I dont know how well it works if its not. void Client::SendPathPacket(std::vector &points) { - if(points.size() < 2) { + if (points.size() < 2) { //empty length packet == not found. EQApplicationPacket outapp(OP_FindPersonReply, 0); QueuePacket(&outapp); return; } - int len = sizeof(FindPersonResult_Struct) + (points.size()+1) * sizeof(FindPerson_Point); + if (points.size() > 36) { + EQApplicationPacket outapp(OP_FindPersonReply, 0); + QueuePacket(&outapp); + return; + } + + int len = sizeof(FindPersonResult_Struct) + (points.size() + 1) * sizeof(FindPerson_Point); auto outapp = new EQApplicationPacket(OP_FindPersonReply, len); - FindPersonResult_Struct* fpr=(FindPersonResult_Struct*)outapp->pBuffer; + FindPersonResult_Struct* fpr = (FindPersonResult_Struct*)outapp->pBuffer; std::vector::iterator cur, end; cur = points.begin(); end = points.end(); unsigned int r; - for(r = 0; cur != end; ++cur, r++) { + for (r = 0; cur != end; ++cur, r++) { fpr->path[r] = *cur; } @@ -967,959 +120,4 @@ void Client::SendPathPacket(std::vector &points) { fpr->dest = *cur; FastQueuePacket(&outapp); - - -} - -PathNode* PathManager::FindPathNodeByCoordinates(float x, float y, float z) -{ - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - if((PathNodes[i].v.x == x) && (PathNodes[i].v.y == y) && (PathNodes[i].v.z == z)) - return &PathNodes[i]; - - return nullptr; -} - -int PathManager::GetRandomPathNode() -{ - return zone->random.Int(0, Head.PathNodeCount - 1); - -} - -void PathManager::ShowPathNodeNeighbours(Client *c) -{ - if(!c || !c->GetTarget()) - return; - - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - - if(!Node) - { - c->Message(0, "Unable to find path node."); - return; - } - c->Message(0, "Path node %4i", Node->id); - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - char Name[64]; - - if(PathNodes[i].id < 10) - sprintf(Name, "%s000", DigitToWord(PathNodes[i].id)); - else if(PathNodes[i].id < 100) - sprintf(Name, "%s_%s000", DigitToWord(PathNodes[i].id / 10), DigitToWord(PathNodes[i].id % 10)); - else - sprintf(Name, "%s_%s_%s000", DigitToWord(PathNodes[i].id/100), DigitToWord((PathNodes[i].id % 100)/10), - DigitToWord(((PathNodes[i].id % 100) %10))); - - Mob *m = entity_list.GetMob(Name); - - if(m) - m->SendIllusionPacket(151); - } - - std::stringstream Neighbours; - - for(int i = 0; i < PATHNODENEIGHBOURS; ++i) - { - if(Node->Neighbours[i].id == -1) - break; - Neighbours << Node->Neighbours[i].id << ", "; - - char Name[64]; - - if(Node->Neighbours[i].id < 10) - sprintf(Name, "%s000", DigitToWord(Node->Neighbours[i].id)); - else if(Node->Neighbours[i].id < 100) - sprintf(Name, "%s_%s000", DigitToWord(Node->Neighbours[i].id / 10), DigitToWord(Node->Neighbours[i].id % 10)); - else - sprintf(Name, "%s_%s_%s000", DigitToWord(Node->Neighbours[i].id/100), DigitToWord((Node->Neighbours[i].id % 100)/10), - DigitToWord(((Node->Neighbours[i].id % 100) %10))); - - Mob *m = entity_list.GetMob(Name); - - if(m) - m->SendIllusionPacket(46); - } - c->Message(0, "Neighbours: %s", Neighbours.str().c_str()); -} - -void PathManager::NodeInfo(Client *c) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - c->Message(0, "Pathing node: %i at (%.2f, %.2f, %.2f) with bestz %.2f", - Node->id, Node->v.x, Node->v.y, Node->v.z, Node->bestz); - - bool neighbour = false; - for(int x = 0; x < 50; ++x) - { - if(Node->Neighbours[x].id != -1) - { - if(!neighbour) - { - c->Message(0, "Neighbours found:"); - neighbour = true; - } - c->Message(0, "id: %i, distance: %.2f, door id: %i, is teleport: %i", - Node->Neighbours[x].id, Node->Neighbours[x].distance, - Node->Neighbours[x].DoorID, Node->Neighbours[x].Teleport); - } - } - - if(!neighbour) - { - c->Message(0, "No neighbours found!"); - } - return; -} - -void PathManager::DumpPath(std::string filename) -{ - std::ofstream o_file; - - std::string file_to_write = StringFormat("%s%s", Config->MapDir.c_str(), filename.c_str()); - - o_file.open(file_to_write.c_str(), std::ios_base::binary | std::ios_base::trunc | std::ios_base::out); - o_file.write("EQEMUPATH", 9); - o_file.write((const char*)&Head, sizeof(Head)); - o_file.write((const char*)PathNodes, (sizeof(PathNode)*Head.PathNodeCount)); - o_file.close(); -} - -int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 requested_id) -{ - int32 new_id = -1; - if(requested_id != 0) - { - new_id = requested_id; - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - if(PathNodes[i].id == requested_id) - { - new_id = -1; - break; - } - } - } - - if(new_id == -1) - { - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - if(PathNodes[i].id - new_id > 1) { - new_id = PathNodes[i].id - 1; - break; - } - - if(PathNodes[i].id > new_id) - new_id = PathNodes[i].id; - } - new_id++; - } - - PathNode new_node; - new_node.v.x = x; - new_node.v.y = y; - new_node.v.z = z; - new_node.bestz = best_z; - new_node.id = (uint16)new_id; - for(int x = 0; x < PATHNODENEIGHBOURS; ++x) - { - new_node.Neighbours[x].id = -1; - new_node.Neighbours[x].distance = 0.0; - new_node.Neighbours[x].DoorID = -1; - new_node.Neighbours[x].Teleport = 0; - } - - Head.PathNodeCount++; - if(Head.PathNodeCount > 1) - { - auto t_PathNodes = new PathNode[Head.PathNodeCount]; - for(uint32 x = 0; x < (Head.PathNodeCount - 1); ++x) - { - t_PathNodes[x].v.x = PathNodes[x].v.x; - t_PathNodes[x].v.y = PathNodes[x].v.y; - t_PathNodes[x].v.z = PathNodes[x].v.z; - t_PathNodes[x].bestz = PathNodes[x].bestz; - t_PathNodes[x].id = PathNodes[x].id; - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - t_PathNodes[x].Neighbours[n].distance = PathNodes[x].Neighbours[n].distance; - t_PathNodes[x].Neighbours[n].DoorID = PathNodes[x].Neighbours[n].DoorID; - t_PathNodes[x].Neighbours[n].id = PathNodes[x].Neighbours[n].id; - t_PathNodes[x].Neighbours[n].Teleport = PathNodes[x].Neighbours[n].Teleport; - } - - } - - int32 index = (Head.PathNodeCount - 1); - t_PathNodes[index].v.x = new_node.v.x; - t_PathNodes[index].v.y = new_node.v.y; - t_PathNodes[index].v.z = new_node.v.z; - t_PathNodes[index].bestz = new_node.bestz; - t_PathNodes[index].id = new_node.id; - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - t_PathNodes[index].Neighbours[n].distance = new_node.Neighbours[n].distance; - t_PathNodes[index].Neighbours[n].DoorID = new_node.Neighbours[n].DoorID; - t_PathNodes[index].Neighbours[n].id = new_node.Neighbours[n].id; - t_PathNodes[index].Neighbours[n].Teleport = new_node.Neighbours[n].Teleport; - } - - delete[] PathNodes; - PathNodes = t_PathNodes; - - auto npc_type = new NPCType; - memset(npc_type, 0, sizeof(NPCType)); - if(new_id < 10) - sprintf(npc_type->name, "%s", DigitToWord(new_id)); - else if(new_id < 100) - sprintf(npc_type->name, "%s_%s", DigitToWord(new_id/10), DigitToWord(new_id % 10)); - else - sprintf(npc_type->name, "%s_%s_%s", DigitToWord(new_id/100), DigitToWord((new_id % 100)/10), - DigitToWord(((new_id % 100) %10))); - - sprintf(npc_type->lastname, "%i", new_id); - npc_type->cur_hp = 4000000; - npc_type->max_hp = 4000000; - npc_type->race = 151; - npc_type->gender = 2; - npc_type->class_ = 9; - npc_type->deity= 1; - npc_type->level = 75; - npc_type->npc_id = 0; - npc_type->loottable_id = 0; - npc_type->texture = 1; - npc_type->light = 0; - npc_type->runspeed = 0; - npc_type->d_melee_texture1 = 1; - npc_type->d_melee_texture2 = 1; - npc_type->merchanttype = 1; - npc_type->bodytype = 1; - npc_type->STR = 150; - npc_type->STA = 150; - npc_type->DEX = 150; - npc_type->AGI = 150; - npc_type->INT = 150; - npc_type->WIS = 150; - npc_type->CHA = 150; - npc_type->findable = 1; - - auto position = glm::vec4(new_node.v.x, new_node.v.y, new_node.v.z, 0.0f); - auto npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - entity_list.AddNPC(npc, true, true); - - safe_delete_array(ClosedListFlag); - ClosedListFlag = new int[Head.PathNodeCount]; - return new_id; - } - else - { - PathNodes = new PathNode[Head.PathNodeCount]; - PathNodes[0].v.x = new_node.v.x; - PathNodes[0].v.y = new_node.v.y; - PathNodes[0].v.z = new_node.v.z; - PathNodes[0].bestz = new_node.bestz; - PathNodes[0].id = new_node.id; - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - PathNodes[0].Neighbours[n].distance = new_node.Neighbours[n].distance; - PathNodes[0].Neighbours[n].DoorID = new_node.Neighbours[n].DoorID; - PathNodes[0].Neighbours[n].id = new_node.Neighbours[n].id; - PathNodes[0].Neighbours[n].Teleport = new_node.Neighbours[n].Teleport; - } - - auto npc_type = new NPCType; - memset(npc_type, 0, sizeof(NPCType)); - if(new_id < 10) - sprintf(npc_type->name, "%s", DigitToWord(new_id)); - else if(new_id < 100) - sprintf(npc_type->name, "%s_%s", DigitToWord(new_id/10), DigitToWord(new_id % 10)); - else - sprintf(npc_type->name, "%s_%s_%s", DigitToWord(new_id/100), DigitToWord((new_id % 100)/10), - DigitToWord(((new_id % 100) %10))); - - sprintf(npc_type->lastname, "%i", new_id); - npc_type->cur_hp = 4000000; - npc_type->max_hp = 4000000; - npc_type->race = 151; - npc_type->gender = 2; - npc_type->class_ = 9; - npc_type->deity= 1; - npc_type->level = 75; - npc_type->npc_id = 0; - npc_type->loottable_id = 0; - npc_type->texture = 1; - npc_type->light = 0; - npc_type->runspeed = 0; - npc_type->d_melee_texture1 = 1; - npc_type->d_melee_texture2 = 1; - npc_type->merchanttype = 1; - npc_type->bodytype = 1; - npc_type->STR = 150; - npc_type->STA = 150; - npc_type->DEX = 150; - npc_type->AGI = 150; - npc_type->INT = 150; - npc_type->WIS = 150; - npc_type->CHA = 150; - npc_type->findable = 1; - - auto position = glm::vec4(new_node.v.x, new_node.v.y, new_node.v.z, 0.0f); - auto npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - entity_list.AddNPC(npc, true, true); - - ClosedListFlag = new int[Head.PathNodeCount]; - - return new_id; - } -} - -bool PathManager::DeleteNode(Client *c) -{ - if(!c) - { - return false; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return false; - } - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return false; - } - - return DeleteNode(Node->id); -} - -bool PathManager::DeleteNode(int32 id) -{ - //if the current list is > 1 in size create a new list of size current size - 1 - //transfer all but the current node to this new list and delete our current list - //set this new list to be our current list - //else if the size is 1 just delete our current list and set it to zero. - //go through and delete all ref in neighbors... - - if(Head.PathNodeCount > 1) - { - auto t_PathNodes = new PathNode[Head.PathNodeCount - 1]; - uint32 index = 0; - for(uint32 x = 0; x < Head.PathNodeCount; x++) - { - if(PathNodes[x].id != id) - { - t_PathNodes[index].id = PathNodes[x].id; - t_PathNodes[index].v.x = PathNodes[x].v.x; - t_PathNodes[index].v.y = PathNodes[x].v.y; - t_PathNodes[index].v.z = PathNodes[x].v.z; - t_PathNodes[index].bestz = PathNodes[x].bestz; - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - t_PathNodes[index].Neighbours[n].distance = PathNodes[x].Neighbours[n].distance; - t_PathNodes[index].Neighbours[n].DoorID = PathNodes[x].Neighbours[n].DoorID; - t_PathNodes[index].Neighbours[n].id = PathNodes[x].Neighbours[n].id; - t_PathNodes[index].Neighbours[n].Teleport = PathNodes[x].Neighbours[n].Teleport; - } - index++; - } - } - Head.PathNodeCount--; - delete[] PathNodes; - PathNodes = t_PathNodes; - - for(uint32 y = 0; y < Head.PathNodeCount; ++y) - { - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - if(PathNodes[y].Neighbours[n].id == id) - { - PathNodes[y].Neighbours[n].Teleport = 0; - PathNodes[y].Neighbours[n].DoorID = -1; - PathNodes[y].Neighbours[n].distance = 0.0; - PathNodes[y].Neighbours[n].id = -1; - } - } - } - safe_delete_array(ClosedListFlag); - ClosedListFlag = new int[Head.PathNodeCount]; - } - else - { - delete[] PathNodes; - PathNodes = nullptr; - } - return true; -} - -void PathManager::ConnectNodeToNode(Client *c, int32 Node2, int32 teleport, int32 doorid) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - c->Message(0, "Connecting %i to %i", Node->id, Node2); - - if(doorid == 0) - ConnectNodeToNode(Node->id, Node2, teleport); - else - ConnectNodeToNode(Node->id, Node2, teleport, doorid); -} - -void PathManager::ConnectNodeToNode(int32 Node1, int32 Node2, int32 teleport, int32 doorid) -{ - PathNode *a = nullptr; - PathNode *b = nullptr; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - if(PathNodes[x].id == Node1) - { - a = &PathNodes[x]; - if(b) - break; - } - else if(PathNodes[x].id == Node2) - { - b = &PathNodes[x]; - if(a) - break; - } - } - - if(a == nullptr || b == nullptr) - return; - - bool connect_a_to_b = true; - if(NodesConnected(a, b)) - connect_a_to_b = false; - - bool connect_b_to_a = true; - if(NodesConnected(b, a)) - connect_b_to_a = false; - - - if(connect_a_to_b) - { - for(int a_i = 0; a_i < PATHNODENEIGHBOURS; ++a_i) - { - if(a->Neighbours[a_i].id == -1) - { - a->Neighbours[a_i].id = b->id; - a->Neighbours[a_i].DoorID = doorid; - a->Neighbours[a_i].Teleport = teleport; - a->Neighbours[a_i].distance = VectorDistance(a->v, b->v); - break; - } - } - } - - if(connect_b_to_a) - { - for(int b_i = 0; b_i < PATHNODENEIGHBOURS; ++b_i) - { - if(b->Neighbours[b_i].id == -1) - { - b->Neighbours[b_i].id = a->id; - b->Neighbours[b_i].DoorID = doorid; - b->Neighbours[b_i].Teleport = teleport; - b->Neighbours[b_i].distance = VectorDistance(a->v, b->v); - break; - } - } - } -} - -void PathManager::ConnectNode(Client *c, int32 Node2, int32 teleport, int32 doorid) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - c->Message(0, "Connecting %i to %i", Node->id, Node2); - - if(doorid == 0) - ConnectNode(Node->id, Node2, teleport); - else - ConnectNode(Node->id, Node2, teleport, doorid); -} - -void PathManager::ConnectNode(int32 Node1, int32 Node2, int32 teleport, int32 doorid) -{ - PathNode *a = nullptr; - PathNode *b = nullptr; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - if(PathNodes[x].id == Node1) - { - a = &PathNodes[x]; - if(b) - break; - } - else if(PathNodes[x].id == Node2) - { - b = &PathNodes[x]; - if(a) - break; - } - } - - if(a == nullptr || b == nullptr) - return; - - bool connect_a_to_b = true; - if(NodesConnected(a, b)) - connect_a_to_b = false; - - if(connect_a_to_b) - { - for(int a_i = 0; a_i < PATHNODENEIGHBOURS; ++a_i) - { - if(a->Neighbours[a_i].id == -1) - { - a->Neighbours[a_i].id = b->id; - a->Neighbours[a_i].DoorID = doorid; - a->Neighbours[a_i].Teleport = teleport; - a->Neighbours[a_i].distance = VectorDistance(a->v, b->v); - break; - } - } - } -} - -void PathManager::DisconnectNodeToNode(Client *c, int32 Node2) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - DisconnectNodeToNode(Node->id, Node2); -} - -void PathManager::DisconnectNodeToNode(int32 Node1, int32 Node2) -{ - PathNode *a = nullptr; - PathNode *b = nullptr; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - if(PathNodes[x].id == Node1) - { - a = &PathNodes[x]; - if(b) - break; - } - else if(PathNodes[x].id == Node2) - { - b = &PathNodes[x]; - if(a) - break; - } - } - - if(a == nullptr || b == nullptr) - return; - - bool disconnect_a_from_b = false; - if(NodesConnected(a, b)) - disconnect_a_from_b = true; - - bool disconnect_b_from_a = false; - if(NodesConnected(b, a)) - disconnect_b_from_a = true; - - if(disconnect_a_from_b) - { - for(int a_i = 0; a_i < PATHNODENEIGHBOURS; ++a_i) - { - if(a->Neighbours[a_i].id == b->id) - { - a->Neighbours[a_i].distance = 0.0; - a->Neighbours[a_i].DoorID = -1; - a->Neighbours[a_i].id = -1; - a->Neighbours[a_i].Teleport = 0; - break; - } - } - } - - if(disconnect_b_from_a) - { - for(int b_i = 0; b_i < PATHNODENEIGHBOURS; ++b_i) - { - if(b->Neighbours[b_i].id == a->id) - { - b->Neighbours[b_i].distance = 0.0; - b->Neighbours[b_i].DoorID = -1; - b->Neighbours[b_i].id = -1; - b->Neighbours[b_i].Teleport = 0; - break; - } - } - } -} - -void PathManager::MoveNode(Client *c) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - Node->v.x = c->GetX(); - Node->v.y = c->GetY(); - Node->v.z = c->GetZ(); - - if(zone->zonemap) - { - glm::vec3 loc(c->GetX(), c->GetY(), c->GetZ()); - Node->bestz = zone->zonemap->FindBestZ(loc, nullptr); - } - else - { - Node->bestz = Node->v.z; - } -} - -void PathManager::DisconnectAll(Client *c) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - for(int x = 0; x < PATHNODENEIGHBOURS; ++x) - { - Node->Neighbours[x].distance = 0; - Node->Neighbours[x].Teleport = 0; - Node->Neighbours[x].DoorID = -1; - Node->Neighbours[x].id = -1; - } - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - if(PathNodes[i].id == Node->id) - continue; - - for(int ix = 0; ix < PATHNODENEIGHBOURS; ++ix) - { - if(PathNodes[i].Neighbours[ix].id == Node->id) - { - PathNodes[i].Neighbours[ix].distance = 0; - PathNodes[i].Neighbours[ix].Teleport = 0; - PathNodes[i].Neighbours[ix].id = -1; - PathNodes[i].Neighbours[ix].DoorID = -1; - } - } - } -} - -//checks if anything in a points to b -bool PathManager::NodesConnected(PathNode *a, PathNode *b) -{ - if(!a) - return false; - - if(!b) - return false; - - for(int x = 0; x < PATHNODENEIGHBOURS; ++x) - { - if(a->Neighbours[x].id == b->id) - return true; - } - return false; -} - -bool PathManager::CheckLosFN(glm::vec3 a, glm::vec3 b) -{ - if(zone->zonemap) - { - glm::vec3 hit; - - glm::vec3 myloc; - glm::vec3 oloc; - - myloc.x = a.x; - myloc.y = a.y; - myloc.z = a.z; - - oloc.x = b.x; - oloc.y = b.y; - oloc.z = b.z; - - - if(zone->zonemap->LineIntersectsZone(myloc, oloc, 1.0f, nullptr)) - { - return false; - } - } - return true; -} - -void PathManager::ProcessNodesAndSave(std::string filename) -{ - if(zone->zonemap) - { - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - for(int in = 0; in < PATHNODENEIGHBOURS; ++in) - { - PathNodes[i].Neighbours[in].distance = 0.0; - PathNodes[i].Neighbours[in].DoorID = -1; - PathNodes[i].Neighbours[in].id = -1; - PathNodes[i].Neighbours[in].Teleport = 0; - } - } - - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - for(uint32 y = 0; y < Head.PathNodeCount; ++y) - { - if(y == x) //can't connect to ourselves. - continue; - - if(!NodesConnected(&PathNodes[x], &PathNodes[y])) - { - if(VectorDistance(PathNodes[x].v, PathNodes[y].v) <= 200) - { - if(CheckLosFN(PathNodes[x].v, PathNodes[y].v)) - { - if(NoHazardsAccurate(PathNodes[x].v, PathNodes[y].v)) - { - ConnectNodeToNode(PathNodes[x].id, PathNodes[y].id, 0, 0); - } - } - } - } - } - } - } - DumpPath(filename); -} - -void PathManager::ResortConnections() -{ - NeighbourNode Neigh[PATHNODENEIGHBOURS]; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - int index = 0; - for(int y = 0; y < PATHNODENEIGHBOURS; ++y) - { - Neigh[y].distance = 0; - Neigh[y].DoorID = -1; - Neigh[y].id = -1; - Neigh[y].Teleport = 0; - } - - for(int z = 0; z < PATHNODENEIGHBOURS; ++z) - { - if(PathNodes[x].Neighbours[z].id != -1) - { - Neigh[index].id = PathNodes[x].Neighbours[z].id; - Neigh[index].distance = PathNodes[x].Neighbours[z].distance; - Neigh[index].DoorID = PathNodes[x].Neighbours[z].DoorID; - Neigh[index].Teleport = PathNodes[x].Neighbours[z].Teleport; - index++; - } - } - - for(int i = 0; i < PATHNODENEIGHBOURS; ++i) - { - PathNodes[x].Neighbours[i].distance = 0; - PathNodes[x].Neighbours[i].DoorID = -1; - PathNodes[x].Neighbours[i].id = -1; - PathNodes[x].Neighbours[i].Teleport = 0; - } - - for(int z = 0; z < PATHNODENEIGHBOURS; ++z) - { - PathNodes[x].Neighbours[z].distance = Neigh[z].distance; - PathNodes[x].Neighbours[z].DoorID = Neigh[z].DoorID; - PathNodes[x].Neighbours[z].id = Neigh[z].id; - PathNodes[x].Neighbours[z].Teleport = Neigh[z].Teleport; - } - } -} - -void PathManager::QuickConnect(Client *c, bool set) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - if(set) - { - c->Message(0, "Setting %i to the quick connect target", Node->id); - QuickConnectTarget = Node->id; - } - else - { - if(QuickConnectTarget >= 0) - { - ConnectNodeToNode(QuickConnectTarget, Node->id); - } - } -} - -struct InternalPathSort -{ - int16 old_id; - int16 new_id; -}; - -void PathManager::SortNodes() -{ - std::vector sorted_vals; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - InternalPathSort tmp; - tmp.old_id = PathNodes[x].id; - sorted_vals.push_back(tmp); - } - - auto t_PathNodes = new PathNode[Head.PathNodeCount]; - memcpy(t_PathNodes, PathNodes, sizeof(PathNode)*Head.PathNodeCount); - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - for(size_t j = 0; j < sorted_vals.size(); ++j) - { - if(sorted_vals[j].old_id == PathNodes[i].id) - { - if(i != PathNodes[i].id) - { - printf("Assigning new id of index %i differs from old id %i\n", i, PathNodes[i].id); - } - sorted_vals[j].new_id = i; - } - } - t_PathNodes[i].id = i; - } - - for(uint32 y = 0; y < Head.PathNodeCount; ++y) - { - for(int z = 0; z < PATHNODENEIGHBOURS; ++z) - { - if(PathNodes[y].Neighbours[z].id != -1) - { - int new_val = -1; - for(size_t c = 0; c < sorted_vals.size(); ++c) - { - if(PathNodes[y].Neighbours[z].id == sorted_vals[c].old_id) - { - new_val = sorted_vals[c].new_id; - break; - } - } - if(new_val != -1) - { - if(t_PathNodes[y].Neighbours[z].id != new_val) - { - printf("changing neighbor value to %i from %i\n", new_val, t_PathNodes[y].Neighbours[z].id); - } - t_PathNodes[y].Neighbours[z].id = new_val; - } - } - } - } - safe_delete_array(PathNodes); - PathNodes = t_PathNodes; -} - +} \ No newline at end of file diff --git a/zone/pathing.h b/zone/pathing.h deleted file mode 100644 index 9921a2ed3..000000000 --- a/zone/pathing.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef PATHING_H -#define PATHING_H - -#include "map.h" -#include "zone_config.h" -#include - -extern const ZoneConfig *Config; - -class Client; -class Mob; - -#define PATHNODENEIGHBOURS 50 - -#pragma pack(1) - -struct AStarNode -{ - int PathNodeID; - int Parent; - float HCost; - float GCost; - bool Teleport; -}; - -struct NeighbourNode { - int16 id; - float distance; - uint8 Teleport; - int16 DoorID; -}; - -struct PathNode { - uint16 id; - glm::vec3 v; - float bestz; - NeighbourNode Neighbours[PATHNODENEIGHBOURS]; -}; - -struct PathFileHeader { - uint32 version; - uint32 PathNodeCount; -}; - -#pragma pack() - -struct PathNodeSortStruct -{ - int id; - float Distance; -}; - -enum LOSType{ UnknownLOS, HaveLOS, NoLOS }; - -class PathManager { - -public: - PathManager(); - ~PathManager(); - - - 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); - - void PrintPathing(); - bool CheckLosFN(glm::vec3 a, glm::vec3 b); - bool NoHazards(glm::vec3 From, glm::vec3 To); - bool NoHazardsAccurate(glm::vec3 From, glm::vec3 To); - void OpenDoors(int Node1, int Node2, Mob* ForWho); - - 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); - bool DeleteNode(int32 id); //returns true on success, false on failure, tries to delete a node from this map - void ConnectNodeToNode(Client *c, int32 Node2, int32 teleport = 0, int32 doorid = -1); //connects a node both ways - void ConnectNodeToNode(int32 Node1, int32 Node2, int32 teleport = 0, int32 doorid = -1); - void ConnectNode(Client *c, int32 Node2, int32 teleport = 0, int32 doorid = -1); //connects a node one way - void ConnectNode(int32 Node1, int32 Node2, int32 teleport = 0, int32 doorid = -1); - void DisconnectNodeToNode(Client *c, int32 Node2); - void DisconnectNodeToNode(int32 Node1, int32 Node2); - void MoveNode(Client *c); - void DisconnectAll(Client *c); - bool NodesConnected(PathNode *a, PathNode *b); - void DumpPath(std::string filename); - void ProcessNodesAndSave(std::string filename); - void ResortConnections(); - void QuickConnect(Client *c, bool set = false); - void SortNodes(); - - 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; - - int *ClosedListFlag; -}; - - -#endif -