/// <summary> /// Processes the result. /// </summary> /// <param name="result">The result.</param> /// <param name="steerer">The steerer.</param> /// <returns> /// <c>true</c> if the result was handled by this processor, otherwise <c>false</c> /// </returns> public override bool HandleResult(PathResult result, SteerForPathComponent steerer) { switch (result.status) { case PathingStatus.DestinationBlocked: { var request = result.originalRequest; //Try to find an unobstructed cell as close to the original destination as possible var toGrid = GridManager.instance.GetGrid(request.to); if (toGrid == null) { return false; } var newDestination = toGrid.GetNearestWalkableCell( request.to, this.transform.position, false, this.maxCellDistanceForNewDestination, request.requesterProperties); if (newDestination != null) { request.to = newDestination.position; steerer.RequestPath(request); return true; } break; } } return false; }
/// <summary> /// Processes the result. /// </summary> /// <param name="result">The result.</param> /// <param name="steerer">The steerer.</param> /// <returns> /// <c>true</c> if the result was handled by this processor, otherwise <c>false</c> /// </returns> public override bool HandleResult(PathResult result, SteerForPathComponent steerer) { switch (result.status) { case PathingStatus.NoRouteExists: { var request = result.originalRequest; if (_retries < this.maxRetries) { _retries++; request.type = RequestType.Normal; //Having this as a separate call apparently avoids allocation of anonymous method, which otherwise happens even if the status is not the one triggering this action. IssueRequest(request, steerer); return true; } break; } } _retries = 0; return false; }
public IEnumerator ProcessRequestCoroutineInternal(IPathRequest request) { //Granted this could be done smarter, but since this is not an expected scenario, we just use exception handling to handle it. ValidateRequest(request); _currentResult = new PathResult(PathingStatus.Complete, null, 0, request); var status = PathingStatus.Complete; //Iterate over the waypoints of the request, including the end point _segmentRequest.Start(request); do { status = StartPathSegment(); if (status != PathingStatus.Running) { break; } while (status == PathingStatus.Running) { status = ProcessNext(); yield return(null); } if (!CompletePathSegment(status)) { break; } }while (_segmentRequest.MoveNext()); if (status != PathingStatus.Complete) { if (_segments.count > 0) { _currentResult.RegisterPartialResult(status, _segmentRequest.GetPendingWaypoints()); } else { _currentResult.status = status; } } //Splice the path segments and complete the request _currentResult.path = Path.FromSegments(_segments); request.Complete(_currentResult); _segments.Clear(); _segmentRequest.Clear(); _currentResult = null; }
private void FailRequest(IPathRequest request, Exception e) { _segments.Clear(); _segmentRequest.Clear(); _currentResult = null; var result = new PathResult(PathingStatus.Failed, null, 0, request) { errorInfo = string.Concat(e.Message, Environment.NewLine, e.StackTrace) }; request.Complete(result); }
/// <summary> /// Processes the result. /// </summary> /// <param name="result">The result.</param> /// <param name="steerer">The steerer.</param> /// <returns> /// <c>true</c> if the result was handled by this processor, otherwise <c>false</c> /// </returns> public abstract bool HandleResult(PathResult result, SteerForPathComponent steerer);
public void Complete(PathResult result) { throw new InvalidOperationException(); }
/// <summary> /// Completes this request /// </summary> /// <param name="result">The result.</param> void IPathRequest.Complete(PathResult result) { this.requester.ConsumePathResult(result); }
public IEnumerator ProcessRequestCoroutineInternal(IPathRequest request) { //Granted this could be done smarter, but since this is not an expected scenario, we just use exception handling to handle it. ValidateRequest(request); _currentResult = new PathResult(PathingStatus.Complete, null, 0, request); var status = PathingStatus.Complete; //Iterate over the waypoints of the request, including the end point _segmentRequest.Start(request); do { status = StartPathSegment(); if (status != PathingStatus.Running) { break; } while (status == PathingStatus.Running) { status = ProcessNext(); yield return null; } if (!CompletePathSegment(status)) { break; } } while (_segmentRequest.MoveNext()); if (status != PathingStatus.Complete) { if (_segments.count > 0) { _currentResult.RegisterPartialResult(status, _segmentRequest.GetPendingWaypoints()); } else { _currentResult.status = status; } } //Splice the path segments and complete the request _currentResult.path = Path.FromSegments(_segments); request.Complete(_currentResult); _segments.Clear(); _segmentRequest.Clear(); _currentResult = null; }
private void FailRequest(IPathRequest request, Exception e) { _segments.Clear(); _segmentRequest.Clear(); _currentResult = null; var result = new PathResult(PathingStatus.Failed, null, 0, request) { errorInfo = string.Concat(e.Message, Environment.NewLine, e.StackTrace) }; request.Complete(result); }
//Note this may be called from another thread if the PathService is running asynchronously void INeedPath.ConsumePathResult(PathResult result) { lock (_syncLock) { //If we have stooped or get back the result of a request other than the one we currently expect, just toss it as it will be outdated. if (_stopped || result.originalRequest != _pendingPathRequest) { return; } _pendingResult = result; _pendingPathRequest = null; } }
void INeedPath.ConsumePathResult(PathResult result) { LoadBalancer.marshaller.ExecuteOnMainThread(() => _callback(result)); }
/// <summary> /// The path request callback method. /// </summary> /// <param name="result">The path result.</param> /// <param name="unit">This unit's UnitFacade.</param> /// <param name="unitPos">This unit's position.</param> /// <param name="destination">The destination.</param> /// <param name="grid">The grid.</param> private void PathRequestCallback(PathResult result, IUnitFacade unit, Vector3 unitPos, Vector3 destination, IGrid grid) { // if the normal path request fails... Action<PathResult> callback = (secondResult) => { if (secondResult.status == PathingStatus.Complete) { // add the unit's current position to the path var path = result.path; path.Push(unit); FollowPath(path, unit); return; } // if the second path request fails, there is nothing to do _stopped = true; }; // try to request a path from the nearest (from) walkable cell Cell fromCell = grid.GetNearestWalkableCell(unitPos, unitPos, true, 1, unit); if (fromCell != null) { QueuePathRequest(fromCell.position, destination, unit, callback); return; } // if that fails, search through all 8 neighbour cells and attempt to request a path from the nearest isWalkable neighbour int neighboursCount = _neighbours.count; for (int i = 0; i < neighboursCount; i++) { var neighbourCell = _neighbours[i]; if (neighbourCell.isWalkable(unit.attributes)) { QueuePathRequest(neighbourCell.position, destination, unit, callback); return; } } }
private bool ProcessAndValidateResult(PathResult result, bool isWaypoint) { _wayPoints.frozen = false; for (int i = 0; i < _resultProcessors.Length; i++) { if (_resultProcessors[i].HandleResult(result, this)) { return (result.status == PathingStatus.Complete); } } var status = result.status; bool isPartial = (status == PathingStatus.CompletePartial); if (isPartial) { status = result.innerResult.status; } switch (status) { case PathingStatus.Complete: { /* All is good, no more to do */ _arrivalEvent = UnitNavigationEventMessage.Event.DestinationReached; return true; } case PathingStatus.NoRouteExists: case PathingStatus.EndOutsideGrid: { _arrivalEvent = UnitNavigationEventMessage.Event.StoppedNoRouteExists; break; } case PathingStatus.StartOutsideGrid: { _arrivalEvent = UnitNavigationEventMessage.Event.StoppedUnitOutsideGrid; break; } case PathingStatus.DestinationBlocked: { _arrivalEvent = UnitNavigationEventMessage.Event.StoppedDestinationBlocked; break; } case PathingStatus.Decayed: { //We cannot reissue the request here, since we may be on a different thread, but then again why would we issue the request again if it had a decay threshold its no longer valid. _arrivalEvent = UnitNavigationEventMessage.Event.StoppedRequestDecayed; break; } case PathingStatus.Failed: { StopInternal(); Debug.LogError("Path request failed: " + result.errorInfo); break; } } _wayPoints.frozen = true; if (isPartial) { return true; } if (!isWaypoint) { //If we are not already moving stop and announce here StopAndAnnounceArrival(); } return false; }
private bool ProcessAndValidateResult(PathResult result) { UnitNavigationEventMessage.Event msgEvent = UnitNavigationEventMessage.Event.None; switch (result.status) { case PathingStatus.Complete: { /* All is good, no more to do */ return true; } case PathingStatus.NoRouteExists: case PathingStatus.EndOutsideGrid: { msgEvent = UnitNavigationEventMessage.Event.StoppedNoRouteExists; break; } case PathingStatus.StartOutsideGrid: { msgEvent = UnitNavigationEventMessage.Event.StoppedUnitOutsideGrid; break; } case PathingStatus.DestinationBlocked: { msgEvent = UnitNavigationEventMessage.Event.StoppedDestinationBlocked; break; } case PathingStatus.Decayed: { //We cannot reissue the request here, since we may be on a different thread, but then again why would we issue the request again if it had a decay threshold its no longer valid. msgEvent = UnitNavigationEventMessage.Event.StoppedRequestDecayed; break; } case PathingStatus.Failed: { Debug.LogError("Path request failed: " + result.errorInfo); break; } } var destination = result.originalRequest.to; var pendingWaypoints = _wayPoints.count > 0 ? _wayPoints.ToArray() : Consts.EmptyVectorArray; Stop(); if (msgEvent != UnitNavigationEventMessage.Event.None) { AnnounceEvent(msgEvent, destination, pendingWaypoints); } return false; }
private void CompleteRequest(PathingStatus status) { PathResult result; if (_currentRequest.type == RequestType.IntelOnly) { result = new PathResult(status, null, _goal.g, _currentRequest); } else if (status == PathingStatus.Complete) { Path path; var maxPathLength = Mathf.CeilToInt(_goal.g / (_goal.parent.cellSize * _costProvider.baseMoveCost)); //Fix the actual destination so it does not overlap obstructions FixupGoal(_currentRequest); if (_currentRequest.pathFinderOptions.usePathSmoothing) { path = _smoother.Smooth(_goal, maxPathLength, _currentRequest, _cellCostStrategy); } else { path = new Path(maxPathLength); //Push the actual end position as the goal path.Push(new Position(_currentRequest.to)); IPathNode current = _goal.predecessor; while (current != null) { path.Push(current); current = current.predecessor; } //Instead of testing for it in the while loop, just pop off the start node and replace it with the actual start position if (path.count > 1) { path.Pop(); } path.Push(new Position(_currentRequest.from)); } result = new PathResult(status, path, _goal.g, _currentRequest); } else { result = new PathResult(status, null, 0, _currentRequest); } _currentRequest.Complete(result); _currentRequest = null; }
private void ConsumePath() { PathResult result = _pendingResult; _pendingResult = null; var req = result.originalRequest as InternalPathRequest; //Consume way points if appropriate. This must be done prior to the processing of the result, since if the request was a way point request, the first item in line is the one the result concerns. if (req.pathType == InternalPathRequest.Type.Waypoint) { AnnounceEvent(UnitNavigationEventMessage.Event.WaypointReached, _wayPoints.Dequeue(), null); } //Process the result if (!ProcessAndValidateResult(result)) { return; } _currentPath = result.path; // If we have a formation we want to recalculate positions // We turn the model unit to face the new path direction so the formation can be sorted right away. if (_currentFormation != null) { _modelUnit.transform.LookAt(_currentPath[1].position); SetFormation(_currentFormation); } SetVectorFieldPath(); }
void INeedPath.ConsumePathResult(PathResult result) { // Execute on the main thread to avoid multi-threading issues or the need for using a lock or Monitor NavLoadBalancer.marshaller.ExecuteOnMainThread(() => { // If we have stopped or get back the result of a request other than the one we currently expect, just toss it as it will be outdated. if (result.originalRequest != _pendingPathRequest) { return; } _pendingResult = result; _pendingPathRequest = null; }); }
private bool ConsumeResult() { //Since result processing may actually repath and consequently a new result may arrive we need to operate on locals and null the pending result PathResult result; lock (_syncLock) { result = _pendingResult; _pendingResult = null; } var req = result.originalRequest as InternalPathRequest; //Consume way points if appropriate. This must be done prior to the processing of the result, since if the request was a way point request, the first item in line is the one the result concerns. if (req.pathType == InternalPathRequest.Type.Waypoint) { _wayPoints.Dequeue(); } else if (req.pathType == InternalPathRequest.Type.PathboundWaypoint) { _pathboundWayPoints.Dequeue(); } //Reset current destination and path no matter what _previousDestination = _transform.position; _currentDestination = null; _currentPath = null; //Process the result if (!ProcessAndValidateResult(result)) { return false; } //Consume the result _onFinalApproach = false; _currentPath = result.path; _currentGrid = req.fromGrid; _remainingSquaredDistance = _currentPath.CalculateSquaredLength(); _endOfResolvedPath = _currentPath.Last().position; _endOfPath = _endOfResolvedPath; //Update pending way points UpdatePathboundWaypoints(result.pendingWaypoints); //Pop the first node as our next destination. _unit.hasArrivedAtDestination = false; _currentDestination = _currentPath.Pop(); return true; }
void INeedPath.ConsumePathResult(PathResult result) { LoadBalancer.marshaller.ExecuteOnMainThread(() => _callback(result)); }
private bool ProcessAndValidateResult(PathResult result) { for (int i = 0; i < _resultProcessors.Length; i++) { if (_resultProcessors[i].HandleResult(result, this)) { return (result.status == PathingStatus.Complete); } } UnitNavigationEventMessage.Event msgEvent = UnitNavigationEventMessage.Event.None; switch (result.status) { case PathingStatus.Complete: { /* All is good, no more to do */ return true; } case PathingStatus.NoRouteExists: { msgEvent = UnitNavigationEventMessage.Event.StoppedNoRouteExists; break; } case PathingStatus.DestinationBlocked: { msgEvent = UnitNavigationEventMessage.Event.StoppedDestinationBlocked; break; } case PathingStatus.Decayed: { //We cannot reissue the request here, since we may be on a different thread, but then again why would we issue the request again if it had a decay threshold its no longer valid. msgEvent = UnitNavigationEventMessage.Event.StoppedRequestDecayed; break; } case PathingStatus.StartOutsideGrid: case PathingStatus.EndOutsideGrid: case PathingStatus.Failed: { //The first two are handled before going to the pather, by the DirectPather, and since it would be a bug if either happen and not something a handler should care for //we do not send a message Debug.LogError("Unexpected status returned from pather: " + result.status.ToString()); break; } } var destination = result.originalRequest.to; var pendingWaypoints = _wayPoints.ToArray(); StopInternal(); if (msgEvent != UnitNavigationEventMessage.Event.None) { AnnounceEvent(msgEvent, destination, pendingWaypoints); } return false; }
/// <summary> /// Completes this request /// </summary> /// <param name="result">The result.</param> void IPathRequest.Complete(PathResult result) { this.requester.ConsumePathResult(result); }
public void Complete(PathResult result) { throw new InvalidOperationException(); }
private void ConsumeResult() { //Since result processing may actually repath and consequently a new result may arrive we need to operate on locals and null the pending result PathResult result; lock (_syncLock) { result = _pendingResult; _pendingResult = null; } var req = result.originalRequest as InternalPathRequest; //Consume way points if appropriate. This must be done prior to the processing of the result, since if the request was a way point request, the first item in line is the one the result concerns. bool isWaypoint = req.pathType == InternalPathRequest.Type.Waypoint; if (!isWaypoint) { //Since a waypoint request does not account for the entire path, we do not set the request time _lastPathRequestTime = req.timeStamp; } //Process the result if (ProcessAndValidateResult(result, isWaypoint)) { //Consume the result SetPath(result.path, isWaypoint); } }
//INeedPath public virtual void ConsumePathResult(PathResult result) { Debug.LogWarning("Received path " + result); //throw new NotImplementedException(); }
private void StopInternal() { lock (_syncLock) { _stopped = true; _wayPoints.Clear(); _currentPath = null; _pendingPathRequest = null; _currentDestination = null; _pendingResult = null; _manualReplan = null; } }
private void ConsumeResult() { //Consume way points if appropriate. This must be done prior to the processing of the result, since if the request was a way point request, the first item in line is the one the result concerns. if (_pendingResult.originalRequest.type == RequestType.Waypoint) { _wayPoints.Dequeue(); } else if (_pendingResult.originalRequest.type == RequestType.PathboundWaypoint) { _pathboundWayPoints.Dequeue(); } //Reset current destination no matter what _currentDestination = null; //Since result processing may actually repath and consequently a new result may arrive we need to operate on locals and null the pending result var result = _pendingResult; _pendingResult = null; //Process the result if (!ProcessAndValidateResult(result)) { return; } //Consume the result _currentPath = result.path; _currentGrid = result.originalRequest.fromGrid; _endOfResolvedPath = _currentPath.Last().position; _endOfPath = _endOfResolvedPath; //Update pending way points UpdatePathboundWaypoints(result.pendingWaypoints); //The first point on the path is always the origin of the request, so we want to skip that. _currentPath.Pop(); }