#pragma once #include #include #include #include #include template bool idDijkstra::TracePath( const nodeHolderType& nodeHolder, const nodeIndexType startNode, const nodeIndexType destNode, const djScratch_t* scratchBuff, pathType& path) { (void)nodeHolder; const int start = static_cast(startNode.Get()); const int destination = static_cast(destNode.Get()); if (lastStartNode != start) { return false; } path.num = 0; path.cost = 0x7FFFFFFF; if (destination == start) { return false; } path.path[path.num++] = nodeIndexType( static_cast(destination)); const djScratch_t* scratch = &scratchBuff[destination]; path.cost = scratch->Cost(); while (path.num < 32) { const short previous = scratch->prevIndex; if (previous < 0) { path.cost = 0x7FFFFFFF; path.num = 0; return false; } path.path[path.num++] = nodeIndexType(previous); scratch = &scratchBuff[previous]; if (previous == start) { path.Invert(); return true; } } // The recovered implementation returns the first 32 nodes when a route // exceeds the fixed route buffer, then reverses that bounded prefix. path.Invert(); return true; } template bool idDijkstra::FindShortestPaths( const nodeHolderType& nodeHolder, const nodeIndexType startNode, const nodeIndexType* destNodes, const int numDestNodes, const edgeCacheType* edges, djScratch_t* scratchBuff, const int skipFlags, const int requiredFlags) { const int nodeCount = nodeHolder.decl->nodes.num; std::memset(scratchBuff, 0xFF, sizeof(djScratch_t) * static_cast(nodeCount)); for (int listIndex = 0; listIndex < nodeHolder.pathableSubWebNodeLists.num; ++listIndex) { const auto* const pathable = nodeHolder.pathableSubWebNodeLists.list[listIndex]; for (int nodeIndex = 0; nodeIndex < pathable->num; ++nodeIndex) { const int value = static_cast(pathable->list[nodeIndex].Get()); scratchBuff[value].SetVisited(false); } } const int start = static_cast(startNode.Get()); scratchBuff[start].SetVisited(false); scratchBuff[start].SetCost(0); scratchBuff[start].prevIndex = -1; lastStartNode = -1; using heapEntry_t = std::pair; std::priority_queue, std::greater> heap; heap.push(heapEntry_t(0, start)); int destinationsFound = 0; int processedNodes = 0; while (!heap.empty() && processedNodes < nodeCount) { const int node = heap.top().second; heap.pop(); djScratch_t& nodeScratch = scratchBuff[node]; if (nodeScratch.Visited()) { continue; } for (int destinationIndex = 0; destinationIndex < numDestNodes; ++destinationIndex) { if (destNodes[destinationIndex].Get() == node) { ++destinationsFound; if (destinationsFound == numDestNodes) { lastStartNode = start; return true; } break; } } const nodeCacheType& nodeCache = nodeHolder.decl->nodeCache.list[node]; const int nodeCost = nodeScratch.Cost(); nodeScratch.SetVisited(true); if ((nodeCache.flags & skipFlags) == 0 && (nodeCache.flags & requiredFlags) == requiredFlags) { for (int localEdge = 0; localEdge < nodeCache.numEdges; ++localEdge) { const int edgeIndex = nodeHolder.decl->edgeIndexCache[ nodeCache.edgeIndexOffset + localEdge]; const edgeCacheType& edge = edges[edgeIndex]; const int destination = static_cast( edge.destNodeIndex.Get()); djScratch_t& destinationScratch = scratchBuff[destination]; if (destinationScratch.Visited()) { continue; } const float scaledCost = static_cast( nodeHolder.InternalGetEdgeCost( nodeIndexType(static_cast(node)), { static_cast(edgeIndex) })) * (static_cast(edge.weightScale) * 0.0625f); const int newCost = nodeCost + static_cast(scaledCost); if (destinationScratch.Cost() > newCost) { destinationScratch.prevIndex = static_cast(node); destinationScratch.SetCost(newCost); heap.push(heapEntry_t(newCost, destination)); } } } ++processedNodes; } lastStartNode = start; return true; }