private void DispatchJpsDebug(SharedAiDebug.JpsRouteDebug routeDebug) { var mapManager = IoCManager.Resolve <IMapManager>(); var route = new List <Vector2>(); foreach (var tile in routeDebug.Route) { var tileGrid = mapManager.GetGrid(tile.GridIndex).GridTileToLocal(tile.GridIndices); route.Add(mapManager.GetGrid(tile.GridIndex).LocalToWorld(tileGrid).Position); } var jumpNodes = new List <Vector2>(); foreach (var tile in routeDebug.JumpNodes) { var tileGrid = mapManager.GetGrid(tile.GridIndex).GridTileToLocal(tile.GridIndices); jumpNodes.Add(mapManager.GetGrid(tile.GridIndex).LocalToWorld(tileGrid).Position); } var systemMessage = new SharedAiDebug.JpsRouteMessage( routeDebug.EntityUid, route, jumpNodes, routeDebug.TimeTaken ); EntityManager.EntityNetManager.SendSystemNetworkMessage(systemMessage); }
private void DispatchJpsDebug(SharedAiDebug.JpsRouteDebug routeDebug) { var mapManager = IoCManager.Resolve <IMapManager>(); var route = new List <Vector2>(); foreach (var tile in routeDebug.Route) { var tileGrid = mapManager.GetGrid(tile.GridIndex).GridTileToLocal(tile.GridIndices); route.Add(tileGrid.ToMapPos(EntityManager)); } var jumpNodes = new List <Vector2>(); foreach (var tile in routeDebug.JumpNodes) { var tileGrid = mapManager.GetGrid(tile.GridIndex).GridTileToLocal(tile.GridIndices); jumpNodes.Add(tileGrid.ToMapPos(EntityManager)); } var systemMessage = new SharedAiDebug.JpsRouteMessage( routeDebug.EntityUid, route, jumpNodes, routeDebug.TimeTaken ); RaiseNetworkEvent(systemMessage); }
protected override async Task <Queue <TileRef>?> Process() { // VERY similar to A*; main difference is with the neighbor tiles you look for jump nodes instead if (_startNode == null || _endNode == null) { return(null); } // If we couldn't get a nearby node that's good enough if (!PathfindingHelpers.TryEndNode(ref _endNode, _pathfindingArgs)) { return(null); } var openTiles = new PriorityQueue <ValueTuple <float, PathfindingNode> >(new PathfindingComparer()); var gScores = new Dictionary <PathfindingNode, float>(); var cameFrom = new Dictionary <PathfindingNode, PathfindingNode>(); var closedTiles = new HashSet <PathfindingNode>(); #if DEBUG var jumpNodes = new HashSet <PathfindingNode>(); #endif PathfindingNode?currentNode = null; openTiles.Add((0, _startNode)); gScores[_startNode] = 0.0f; var routeFound = false; var count = 0; while (openTiles.Count > 0) { count++; // JPS probably getting a lot fewer nodes than A* is if (count % 5 == 0 && count > 0) { await SuspendIfOutOfTime(); } (_, currentNode) = openTiles.Take(); if (currentNode.Equals(_endNode)) { routeFound = true; break; } foreach (var node in currentNode.GetNeighbors()) { var direction = PathfindingHelpers.RelativeDirection(node, currentNode); var jumpNode = GetJumpPoint(currentNode, direction, _endNode); if (jumpNode != null && !closedTiles.Contains(jumpNode)) { closedTiles.Add(jumpNode); #if DEBUG jumpNodes.Add(jumpNode); #endif // GetJumpPoint should already check if we can traverse to the node var tileCost = PathfindingHelpers.GetTileCost(_pathfindingArgs, currentNode, jumpNode); if (tileCost == null) { throw new InvalidOperationException(); } var gScore = gScores[currentNode] + tileCost.Value; if (gScores.TryGetValue(jumpNode, out var nextValue) && gScore >= nextValue) { continue; } cameFrom[jumpNode] = currentNode; gScores[jumpNode] = gScore; // pFactor is tie-breaker where the fscore is otherwise equal. // See http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#breaking-ties // There's other ways to do it but future consideration var fScore = gScores[jumpNode] + PathfindingHelpers.OctileDistance(_endNode, jumpNode) * (1.0f + 1.0f / 1000.0f); openTiles.Add((fScore, jumpNode)); } } } if (!routeFound) { return(null); } DebugTools.AssertNotNull(currentNode); var route = PathfindingHelpers.ReconstructJumpPath(cameFrom, currentNode !); if (route.Count == 1) { return(null); } #if DEBUG // Need to get data into an easier format to send to the relevant clients if (DebugRoute != null && route.Count > 0) { var debugJumpNodes = new HashSet <TileRef>(jumpNodes.Count); foreach (var node in jumpNodes) { debugJumpNodes.Add(node.TileRef); } var debugRoute = new SharedAiDebug.JpsRouteDebug( _pathfindingArgs.Uid, route, debugJumpNodes, DebugTime); DebugRoute.Invoke(debugRoute); } #endif return(route); }