public override async Task <PlayerUpdateResponse> Walk(GeoCoordinate targetLocation, Func <Task <bool> > functionExecutedWhileWalking, ISession session, CancellationToken cancellationToken, double walkSpeed = 0.0) { GetGoogleInstance(session); _minStepLengthInMeters = session.LogicSettings.DefaultStepLength; var currentLocation = new GeoCoordinate(_client.CurrentLatitude, _client.CurrentLongitude, _client.CurrentAltitude); var googleResult = _googleDirectionsService.GetDirections(currentLocation, new List <GeoCoordinate>(), targetLocation); if (googleResult.Directions.status.Equals("OVER_QUERY_LIMIT")) { return(await RedirectToNextFallbackStrategy(session.LogicSettings, targetLocation, functionExecutedWhileWalking, session, cancellationToken)); } var googleWalk = GoogleWalk.Get(googleResult); session.EventDispatcher.Send(new FortTargetEvent { Name = FortInfo.Name, Distance = googleResult.GetDistance(), Route = "GoogleWalk" }); List <GeoCoordinate> points = googleWalk.Waypoints; return(await DoWalk(points, session, functionExecutedWhileWalking, currentLocation, targetLocation, cancellationToken)); }
public async Task <GoogleWalk> GetDirections(GeoCoordinate origin, List <GeoCoordinate> waypoints, GeoCoordinate destino) { GoogleResult googleResult = null; try { if (_cache) { var item = OldResults .FirstOrDefault(pesquisa => IsSameAdress(origin, waypoints, destino, pesquisa)); if (item != null) { item.FromCache = true; googleResult = item; } } if (googleResult == null) { var url = GetUrl(origin, waypoints, destino); using (var client = new HttpClient()) { client.BaseAddress = new Uri("https://maps.googleapis.com/maps/api/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage responseMessage = await client.GetAsync(url).ConfigureAwait(false); var resposta = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); var google = JsonConvert.DeserializeObject <DirectionsResponse>(resposta); if (google.status.Equals("OVER_QUERY_LIMIT")) { // If we get an error, don't cache empty GoogleResult. Just return null. return(null); } var resultadoPesquisa = new GoogleResult { Directions = google, RequestDate = DateTime.Now, Origin = origin, Waypoints = waypoints, Destiny = destino, FromCache = false, }; if (_cache) { SaveResult(resultadoPesquisa); } googleResult = resultadoPesquisa; } } if (googleResult != null) { return(GoogleWalk.Get(googleResult)); } } catch (ActiveSwitchByRuleException ex) { throw ex; } catch (Exception) { } return(null); }
public async Task <PlayerUpdateResponse> Walk(GeoCoordinate targetLocation, Func <Task <bool> > functionExecutedWhileWalking, ISession session, CancellationToken cancellationToken) { GetGoogleInstance(session); _minStepLengthInMeters = session.LogicSettings.DefaultStepLength; var currentLocation = new GeoCoordinate(_client.CurrentLatitude, _client.CurrentLongitude, _client.CurrentAltitude); var googleResult = _googleDirectionsService.GetDirections(currentLocation, new List <GeoCoordinate>(), targetLocation); if (googleResult.Directions.status.Equals("OVER_QUERY_LIMIT")) { return(await RedirectToHumanStrategy(targetLocation, functionExecutedWhileWalking, session, cancellationToken)); } var googleWalk = GoogleWalk.Get(googleResult); PlayerUpdateResponse result = null; var points = googleWalk.Waypoints; //filter google defined waypoints and remove those that are too near to the previous ones var waypointsDists = new Dictionary <Tuple <GeoCoordinate, GeoCoordinate>, double>(); var minWaypointsDistance = RandomizeStepLength(_minStepLengthInMeters); Logger.Write($"Generating waypoints, will remove those with distance form previous less than: {minWaypointsDistance.ToString("0.000")}", LogLevel.Debug, force: true); for (var i = 0; i < points.Count; i++) { if (i > 0) { var dist = LocationUtils.CalculateDistanceInMeters(points[i - 1], points[i]); waypointsDists[new Tuple <GeoCoordinate, GeoCoordinate>(points[i - 1], points[i])] = dist; Logger.Write($"WP{i-1}-{i}: {{{points[i-1].Latitude},{points[i-1].Longitude}}} -{{{points[i].Latitude},{points[i].Longitude}}}, dist: {dist.ToString("0.000")}", LogLevel.Debug, force: true); } } var tooNearPoints = waypointsDists.Where(kvp => kvp.Value < minWaypointsDistance).Select(kvp => kvp.Key.Item1).ToList(); foreach (var tooNearPoint in tooNearPoints) { points.Remove(tooNearPoint); } if (points.Any()) //check if first waypoint is the current location (this is what google returns), in such case remove it! { var firstStep = points.First(); if (firstStep == currentLocation) { points.Remove(points.First()); } } var stringifiedPath = string.Join(",\n", points.Select(point => $"{{lat: {point.Latitude}, lng: {point.Longitude}}}")); session.EventDispatcher.Send(new PathEvent { IsCalculated = true, StringifiedPath = stringifiedPath }); var walkedPointsList = new List <GeoCoordinate>(); foreach (var nextStep in points) { Logger.Write($"Leading to a next google waypoint: {{lat: {nextStep.Latitude}, lng: {nextStep.Longitude}}}", LogLevel.Debug, force: true); currentLocation = new GeoCoordinate(_client.CurrentLatitude, _client.CurrentLongitude); if (_currentWalkingSpeed <= 0) { _currentWalkingSpeed = session.LogicSettings.WalkingSpeedInKilometerPerHour; } if (session.LogicSettings.UseWalkingSpeedVariant) { _currentWalkingSpeed = session.Navigation.VariantRandom(session, _currentWalkingSpeed); } var speedInMetersPerSecond = _currentWalkingSpeed / 3.6; var nextStepBearing = LocationUtils.DegreeBearing(currentLocation, nextStep); //particular steps are limited by minimal length, first step is calculated from the original speed per second (distance in 1s) var nextStepDistance = Math.Max(RandomizeStepLength(_minStepLengthInMeters), speedInMetersPerSecond); Logger.Write($"Distance to walk in the next position update: {nextStepDistance.ToString("0.00")}m bearing: {nextStepBearing.ToString("0.00")}", LogLevel.Debug, force: true); var waypoint = LocationUtils.CreateWaypoint(currentLocation, nextStepDistance, nextStepBearing); walkedPointsList.Add(waypoint); var previousLocation = currentLocation; //store the current location for comparison and correction purposes var requestSendDateTime = DateTime.Now; result = await _client.Player.UpdatePlayerLocation(waypoint.Latitude, waypoint.Longitude, waypoint.Altitude); var realDistanceToTarget = LocationUtils.CalculateDistanceInMeters(currentLocation, targetLocation); Logger.Write($"Real remaining distance to target: {realDistanceToTarget.ToString("0.00")}m", LogLevel.Debug, force: true); if (realDistanceToTarget < 10) { break; } do { cancellationToken.ThrowIfCancellationRequested(); var msToPositionChange = (DateTime.Now - requestSendDateTime).TotalMilliseconds; currentLocation = new GeoCoordinate(_client.CurrentLatitude, _client.CurrentLongitude); var currentDistanceToWaypoint = LocationUtils.CalculateDistanceInMeters(currentLocation, nextStep); realDistanceToTarget = LocationUtils.CalculateDistanceInMeters(currentLocation, targetLocation); Logger.Write($"Actual position: {{lat: {currentLocation.Latitude}, lng: {currentLocation.Longitude}}}, reached in {msToPositionChange.ToString("0.00")}ms, distance from the next waypoint: {currentDistanceToWaypoint.ToString("0.000")}m, distance from the target: {realDistanceToTarget.ToString("0.000")}m", LogLevel.Debug, force: true); var realSpeedinMperS = nextStepDistance / (msToPositionChange / 1000); var realDistanceWalked = LocationUtils.CalculateDistanceInMeters(previousLocation, currentLocation); //if the real calculated speed is lower than the one expected, we will raise the speed for the following step double speedRaise = 0; if (realSpeedinMperS < speedInMetersPerSecond) { speedRaise = speedInMetersPerSecond - realSpeedinMperS; } double distanceRaise = 0; if (realDistanceWalked < nextStepDistance) { distanceRaise = nextStepDistance - realDistanceWalked; } Logger.Write($"Actual/Expected speed: {realSpeedinMperS.ToString("0.00")}/{speedInMetersPerSecond.ToString("0.00")}m/s, actual/expected distance: {realDistanceWalked.ToString("0.00")}/{nextStepDistance.ToString("0.00")}m, next speed and dist raise by {speedRaise.ToString("0.00")}m/s and {distanceRaise.ToString("0.00")}m", LogLevel.Debug, force: true); var realDistanceToTargetSpeedDown = LocationUtils.CalculateDistanceInMeters(currentLocation, targetLocation); if (realDistanceToTargetSpeedDown < 40) { if (speedInMetersPerSecond > SpeedDownTo) { speedInMetersPerSecond = SpeedDownTo; } } if (session.LogicSettings.UseWalkingSpeedVariant) { _currentWalkingSpeed = session.Navigation.VariantRandom(session, _currentWalkingSpeed); speedInMetersPerSecond = _currentWalkingSpeed / 3.6; } speedInMetersPerSecond += speedRaise; nextStepBearing = LocationUtils.DegreeBearing(currentLocation, nextStep); //setting next step distance is limited by the target and the next waypoint distance (we don't want to miss them) //also the minimal step length is used as we don't want to spend minutes jumping by cm lengths nextStepDistance = Math.Min(Math.Min(realDistanceToTarget, currentDistanceToWaypoint), //also add the distance raise (bot overhead corrections) to the normal step length Math.Max(RandomizeStepLength(_minStepLengthInMeters) + distanceRaise, (msToPositionChange / 1000) * speedInMetersPerSecond) + distanceRaise); // After a correct waypoint, get a random imprecise point in 5 meters around player - more realistic //var impreciseLocation = GenerateUnaccurateGeocoordinate(waypoint, nextWaypointBearing); Logger.Write($"Distance to walk in the next position update: {nextStepDistance.ToString("0.00")}, bearing: {nextStepBearing.ToString("0.00")}, speed: {speedInMetersPerSecond.ToString("0.00")}", LogLevel.Debug, force: true); waypoint = LocationUtils.CreateWaypoint(currentLocation, nextStepDistance, nextStepBearing); walkedPointsList.Add(waypoint); previousLocation = currentLocation; //store the current location for comparison and correction purposes requestSendDateTime = DateTime.Now; result = await _client.Player.UpdatePlayerLocation(waypoint.Latitude, waypoint.Longitude, waypoint.Altitude); UpdatePositionEvent?.Invoke(waypoint.Latitude, waypoint.Longitude); if (functionExecutedWhileWalking != null) { await functionExecutedWhileWalking(); // look for pokemon } } while (LocationUtils.CalculateDistanceInMeters(currentLocation, nextStep) >= 2); UpdatePositionEvent?.Invoke(nextStep.Latitude, nextStep.Longitude); } stringifiedPath = string.Join(",\n", walkedPointsList.Select(point => $"{{lat: {point.Latitude}, lng: {point.Longitude}}}")); session.EventDispatcher.Send(new PathEvent { IsCalculated = false, StringifiedPath = stringifiedPath }); return(result); }
public async Task <PlayerUpdateResponse> Walk(GeoCoordinate targetLocation, Func <Task <bool> > functionExecutedWhileWalking, ISession session, CancellationToken cancellationToken) { GetGoogleInstance(session); var sourceLocation = new GeoCoordinate(_client.CurrentLatitude, _client.CurrentLongitude, _client.CurrentAltitude); var googleResult = _googleDirectionsService.GetDirections(sourceLocation, new List <GeoCoordinate>(), targetLocation); if (googleResult.Directions.status.Equals("OVER_QUERY_LIMIT")) { return(await RedirectToHumanStrategy(targetLocation, functionExecutedWhileWalking, session, cancellationToken)); } session.EventDispatcher.Send(new NewPathToDestinyEvent { GoogleData = googleResult }); var googleWalk = GoogleWalk.Get(googleResult); PlayerUpdateResponse result = null; List <GeoCoordinate> points = googleWalk.Waypoints; foreach (var nextStep in points) { var speedInMetersPerSecond = session.LogicSettings.UseWalkingSpeedVariant ? MajorWalkingSpeedVariant(session) : session.LogicSettings.WalkingSpeedInKilometerPerHour / 3.6; sourceLocation = new GeoCoordinate(_client.CurrentLatitude, _client.CurrentLongitude); var nextWaypointBearing = LocationUtils.DegreeBearing(sourceLocation, nextStep); var nextWaypointDistance = speedInMetersPerSecond; var waypoint = LocationUtils.CreateWaypoint(sourceLocation, nextWaypointDistance, nextWaypointBearing); var requestSendDateTime = DateTime.Now; result = await _client.Player.UpdatePlayerLocation(waypoint.Latitude, waypoint.Longitude, waypoint.Altitude); UpdatePositionEvent?.Invoke(waypoint.Latitude, waypoint.Longitude); var realDistanceToTarget = LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation); if (realDistanceToTarget < 10) { break; } do { cancellationToken.ThrowIfCancellationRequested(); var millisecondsUntilGetUpdatePlayerLocationResponse = (DateTime.Now - requestSendDateTime).TotalMilliseconds; sourceLocation = new GeoCoordinate(_client.CurrentLatitude, _client.CurrentLongitude); var currentDistanceToTarget = LocationUtils.CalculateDistanceInMeters(sourceLocation, nextStep); var realDistanceToTargetSpeedDown = LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation); if (realDistanceToTargetSpeedDown < 40) { if (speedInMetersPerSecond > SpeedDownTo) { speedInMetersPerSecond = SpeedDownTo; } } if (session.LogicSettings.UseWalkingSpeedVariant) { speedInMetersPerSecond = MinorWalkingSpeedVariant(session); } nextWaypointDistance = Math.Min(currentDistanceToTarget, millisecondsUntilGetUpdatePlayerLocationResponse / 1000 * speedInMetersPerSecond); nextWaypointBearing = LocationUtils.DegreeBearing(sourceLocation, nextStep); waypoint = LocationUtils.CreateWaypoint(sourceLocation, nextWaypointDistance, nextWaypointBearing); requestSendDateTime = DateTime.Now; result = await _client.Player.UpdatePlayerLocation(waypoint.Latitude, waypoint.Longitude, waypoint.Altitude); UpdatePositionEvent?.Invoke(waypoint.Latitude, waypoint.Longitude); if (functionExecutedWhileWalking != null) { await functionExecutedWhileWalking(); // look for pokemon } } while (LocationUtils.CalculateDistanceInMeters(sourceLocation, nextStep) >= 2); UpdatePositionEvent?.Invoke(nextStep.Latitude, nextStep.Longitude); } return(result); }