Added Custom Pathing via GPX files

Spegeli [2016-07-24 17:47:21]
Added Custom Pathing via GPX files

Thx @ https://github.com/NecronomiconCoding/NecroBot/pull/376
Filename
PokemonGo.RocketAPI.Console/App.config
PokemonGo.RocketAPI.Console/Settings.cs
PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
PokemonGo.RocketAPI.Console/UserSettings.settings
PokemonGo.RocketAPI.Logic/Logic.cs
PokemonGo.RocketAPI.Logic/Navigation.cs
PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj
PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs
PokemonGo.RocketAPI/ISettings.cs
PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj
PokemonGo.RocketAPI/Properties/AssemblyInfo.cs
diff --git a/PokemonGo.RocketAPI.Console/App.config b/PokemonGo.RocketAPI.Console/App.config
index 7b4eede..4f58a92 100644
--- a/PokemonGo.RocketAPI.Console/App.config
+++ b/PokemonGo.RocketAPI.Console/App.config
@@ -59,11 +59,17 @@
         <value>password</value>
       </setting>
       <setting name="PrioritizeIVOverCP" serializeAs="String">
-        <value>False</value>
+        <value>True</value>
       </setting>
       <setting name="MaxTravelDistanceInMeters" serializeAs="String">
         <value>1000</value>
       </setting>
+      <setting name="UseGPXPathing" serializeAs="String">
+        <value>False</value>
+      </setting>
+      <setting name="GPXFile" serializeAs="String">
+        <value>GPXFile.GPX</value>
+      </setting>
     </PokemonGo.RocketAPI.Console.UserSettings>
   </userSettings>
 </configuration>
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Console/Settings.cs b/PokemonGo.RocketAPI.Console/Settings.cs
index 2b823eb..16711c0 100644
--- a/PokemonGo.RocketAPI.Console/Settings.cs
+++ b/PokemonGo.RocketAPI.Console/Settings.cs
@@ -32,6 +32,9 @@ namespace PokemonGo.RocketAPI.Console
         public bool PrioritizeIVOverCP => UserSettings.Default.PrioritizeIVOverCP;
         public int MaxTravelDistanceInMeters => UserSettings.Default.MaxTravelDistanceInMeters;

+        public bool UseGPXPathing => UserSettings.Default.UseGPXPathing;
+        public string GPXFile => UserSettings.Default.GPXFile;
+
         private ICollection<PokemonId> _pokemonsToEvolve;
         private ICollection<PokemonId> _pokemonsNotToTransfer;
         private ICollection<PokemonId> _pokemonsNotToCatch;
diff --git a/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs b/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
index 9b0046f..1c5a32e 100644
--- a/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
+++ b/PokemonGo.RocketAPI.Console/UserSettings.Designer.cs
@@ -181,7 +181,7 @@ namespace PokemonGo.RocketAPI.Console {

         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("False")]
+        [global::System.Configuration.DefaultSettingValueAttribute("True")]
         public bool PrioritizeIVOverCP {
             get {
                 return ((bool)(this["PrioritizeIVOverCP"]));
@@ -202,5 +202,29 @@ namespace PokemonGo.RocketAPI.Console {
                 this["MaxTravelDistanceInMeters"] = value;
             }
         }
+
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("False")]
+        public bool UseGPXPathing {
+            get {
+                return ((bool)(this["UseGPXPathing"]));
+            }
+            set {
+                this["UseGPXPathing"] = value;
+            }
+        }
+
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("GPXFile.GPX")]
+        public string GPXFile {
+            get {
+                return ((string)(this["GPXFile"]));
+            }
+            set {
+                this["GPXFile"] = value;
+            }
+        }
     }
 }
diff --git a/PokemonGo.RocketAPI.Console/UserSettings.settings b/PokemonGo.RocketAPI.Console/UserSettings.settings
index 7c7f600..5c0b59b 100644
--- a/PokemonGo.RocketAPI.Console/UserSettings.settings
+++ b/PokemonGo.RocketAPI.Console/UserSettings.settings
@@ -42,10 +42,16 @@
       <Value Profile="(Default)">password</Value>
     </Setting>
     <Setting Name="PrioritizeIVOverCP" Type="System.Boolean" Scope="User">
-      <Value Profile="(Default)">False</Value>
+      <Value Profile="(Default)">True</Value>
     </Setting>
     <Setting Name="MaxTravelDistanceInMeters" Type="System.Int32" Scope="User">
       <Value Profile="(Default)">1000</Value>
     </Setting>
+    <Setting Name="UseGPXPathing" Type="System.Boolean" Scope="User">
+      <Value Profile="(Default)">False</Value>
+    </Setting>
+    <Setting Name="GPXFile" Type="System.String" Scope="User">
+      <Value Profile="(Default)">GPXFile.GPX</Value>
+    </Setting>
   </Settings>
 </SettingsFile>
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Logic/Logic.cs b/PokemonGo.RocketAPI.Logic/Logic.cs
index 79580a2..baf544c 100644
--- a/PokemonGo.RocketAPI.Logic/Logic.cs
+++ b/PokemonGo.RocketAPI.Logic/Logic.cs
@@ -129,7 +129,7 @@ namespace PokemonGo.RocketAPI.Logic
                 if (_clientSettings.TransferDuplicatePokemon) await TransferDuplicatePokemon();
                 await PokemonToCSV();
                 await RecycleItems();
-                await ExecuteFarmingPokestopsAndPokemons();
+                await ExecuteFarmingPokestopsAndPokemons(_clientSettings.UseGPXPathing);

                 /*
             * Example calls below
@@ -145,6 +145,100 @@ namespace PokemonGo.RocketAPI.Logic
             }
         }

+        private async Task ExecuteFarmingPokestopsAndPokemons(bool path = false)
+        {
+            if (!path)
+                await ExecuteFarmingPokestopsAndPokemons();
+            else
+            {
+                //bool onTrack = true;
+                List<GPXReader.trk> Tracks = GetGPXTracks(_clientSettings.GPXFile);
+                int curTrkPt = 0;
+                int maxTrkPt = 0;
+                int curTrk = 0;
+                int maxTrk = Tracks.Count - 1;
+                int curTrkSeg = 0;
+                int maxTrkSeg = 0;
+                while (curTrk <= maxTrk)
+                {
+                    var Track = Tracks.ElementAt(curTrk);
+                    var trackSegments = Track.Segments;
+                    maxTrkSeg = trackSegments.Count - 1;
+                    while (curTrkSeg <= maxTrkSeg)
+                    {
+                        List<GPXReader.trkpt> TrackPoints = Track.Segments.ElementAt(0).TrackPoints;
+                        maxTrkPt = TrackPoints.Count - 1;
+                        var mapObjects = await _client.GetMapObjects();
+                        while (curTrkPt <= maxTrkPt)
+                        {
+                            GPXReader.trkpt nextPoint = TrackPoints.ElementAt(curTrkPt);
+                            if (LocationUtils.CalculateDistanceInMeters(_client.CurrentLat, _client.CurrentLng, Convert.ToDouble(nextPoint.Lat), Convert.ToDouble(nextPoint.Lon)) > 5000)
+                            {
+                                Logger.Write($"Your desired destination of {nextPoint.Lat}, {nextPoint.Lon} is too far from your current position of {_client.CurrentLat}, {_client.CurrentLng}", LogLevel.Error);
+                                break;
+                            }
+
+                            Logger.Write($"Your desired destination is {nextPoint.Lat}, your location is {nextPoint.Lon} {_client.CurrentLat}, {_client.CurrentLng}", LogLevel.Warning);
+
+                            // Wasn't sure how to make this pretty. Edit as needed.
+                            var pokeStops =
+                                mapObjects.MapCells.SelectMany(i => i.Forts)
+                                    .Where(
+                                        i =>
+                                            i.Type == FortType.Checkpoint &&
+                                            i.CooldownCompleteTimestampMs < DateTime.UtcNow.ToUnixTime() &&
+                                            ( // Make sure PokeStop is within 40 meters, otherwise we cannot hit them.
+                                            LocationUtils.CalculateDistanceInMeters(
+                                                _client.CurrentLat, _client.CurrentLng,
+                                                    i.Latitude, i.Longitude) < 40)
+                                            );
+
+                            var pokestopList = pokeStops.ToList();
+
+                            while (pokestopList.Any())
+                            {
+                                pokestopList = pokestopList.OrderBy(i => LocationUtils.CalculateDistanceInMeters(_client.CurrentLat, _client.CurrentLng, i.Latitude, i.Longitude)).ToList();
+                                var pokeStop = pokestopList[0];
+                                pokestopList.RemoveAt(0);
+
+                                var fortInfo = await _client.GetFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);
+
+                                var fortSearch = await _client.SearchFort(pokeStop.Id, pokeStop.Latitude, pokeStop.Longitude);
+                                if (fortSearch.ExperienceAwarded > 0)
+                                {
+                                    _stats.AddExperience(fortSearch.ExperienceAwarded);
+                                    _stats.UpdateConsoleTitle(_inventory);
+                                    //todo: fix egg crash
+                                    Logger.Write($"XP: {fortSearch.ExperienceAwarded}, Gems: {fortSearch.GemsAwarded}, Items: {StringUtils.GetSummedFriendlyNameOfItemAwardList(fortSearch.ItemsAwarded)}", LogLevel.Pokestop);
+                                }
+
+                                await Task.Delay(1000);
+                                await RecycleItems();
+                                if (_clientSettings.TransferDuplicatePokemon) await TransferDuplicatePokemon();
+
+
+                            }
+
+                            var update = await _navigation.HumanPathWalking(TrackPoints.ElementAt(curTrkPt), _clientSettings.WalkingSpeedInKilometerPerHour, ExecuteCatchAllNearbyPokemons);
+
+                            if (curTrkPt >= maxTrkPt)
+                                curTrkPt = 0;
+                            else
+                                curTrkPt++;
+
+                        }//end trkpts
+                        if (curTrkSeg >= maxTrkSeg)
+                            curTrkSeg = 0;
+                        else
+                            curTrkSeg++;
+                    }//end trksegs
+                    if (curTrk >= maxTrkSeg)
+                        curTrk = 0;
+                    else
+                        curTrk++;
+                }//end tracks
+            }
+        }
         private async Task ExecuteFarmingPokestopsAndPokemons()
         {
             var distanceFromStart = LocationUtils.CalculateDistanceInMeters(
@@ -514,7 +608,36 @@ namespace PokemonGo.RocketAPI.Logic
             }
         }

+        private async Task LoadAndDisplayGPXFile()
+        {
+            string xmlString = File.ReadAllText(_clientSettings.GPXFile);
+            GPXReader Readgpx = new GPXReader(xmlString);
+            foreach (GPXReader.trk trk in Readgpx.Tracks)
+            {
+                foreach (GPXReader.trkseg trkseg in trk.Segments)
+                {
+                    foreach (GPXReader.trkpt trpkt in trkseg.TrackPoints)
+                    {
+                        Console.WriteLine(trpkt.ToString());
+                    }
+                }
+            }
+            await Task.Delay(0);
+        }

+        private GPXReader.trk GetGPXTrack(string gpxFile)
+        {
+            string xmlString = File.ReadAllText(_clientSettings.GPXFile);
+            GPXReader Readgpx = new GPXReader(xmlString);
+            return Readgpx.Tracks.ElementAt(0);
+        }
+
+        private List<GPXReader.trk> GetGPXTracks(string gpxFile)
+        {
+            string xmlString = File.ReadAllText(_clientSettings.GPXFile);
+            GPXReader Readgpx = new GPXReader(xmlString);
+            return Readgpx.Tracks;
+        }

     }
 }
\ No newline at end of file
diff --git a/PokemonGo.RocketAPI.Logic/Navigation.cs b/PokemonGo.RocketAPI.Logic/Navigation.cs
index 96e8a5d..1486473 100644
--- a/PokemonGo.RocketAPI.Logic/Navigation.cs
+++ b/PokemonGo.RocketAPI.Logic/Navigation.cs
@@ -76,6 +76,64 @@ namespace PokemonGo.RocketAPI.Logic
             return result;
         }

+        public async Task<PlayerUpdateResponse> HumanPathWalking(GPXReader.trkpt trk, double walkingSpeedInKilometersPerHour, Func<Task> functionExecutedWhileWalking)
+        {
+            //PlayerUpdateResponse result = null;
+
+            var targetLocation = new GeoCoordinate(Convert.ToDouble(trk.Lat), Convert.ToDouble(trk.Lon));
+
+            var speedInMetersPerSecond = walkingSpeedInKilometersPerHour / 3.6;
+
+            var sourceLocation = new GeoCoordinate(_client.CurrentLat, _client.CurrentLng);
+            var distanceToTarget = LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation);
+            // Logger.Write($"Distance to target location: {distanceToTarget:0.##} meters. Will take {distanceToTarget/speedInMetersPerSecond:0.##} seconds!", LogLevel.Info);
+
+            var nextWaypointBearing = LocationUtils.DegreeBearing(sourceLocation, targetLocation);
+            var nextWaypointDistance = speedInMetersPerSecond;
+            var waypoint = LocationUtils.CreateWaypoint(sourceLocation, nextWaypointDistance, nextWaypointBearing, Convert.ToDouble(trk.Ele));
+
+            //Initial walking
+
+            var requestSendDateTime = DateTime.Now;
+            var result =
+                await
+                    _client.UpdatePlayerLocation(waypoint.Latitude, waypoint.Longitude, waypoint.Altitude);
+
+            do
+            {
+                var millisecondsUntilGetUpdatePlayerLocationResponse =
+                    (DateTime.Now - requestSendDateTime).TotalMilliseconds;
+
+                sourceLocation = new GeoCoordinate(_client.CurrentLat, _client.CurrentLng);
+                var currentDistanceToTarget = LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation);
+
+                //if (currentDistanceToTarget < 40)
+                //{
+                //    if (speedInMetersPerSecond > SpeedDownTo)
+                //    {
+                //        //Logger.Write("We are within 40 meters of the target. Speeding down to 10 km/h to not pass the target.", LogLevel.Info);
+                //        speedInMetersPerSecond = SpeedDownTo;
+                //    }
+                //}
+
+                nextWaypointDistance = Math.Min(currentDistanceToTarget,
+                    millisecondsUntilGetUpdatePlayerLocationResponse / 1000 * speedInMetersPerSecond);
+                nextWaypointBearing = LocationUtils.DegreeBearing(sourceLocation, targetLocation);
+                waypoint = LocationUtils.CreateWaypoint(sourceLocation, nextWaypointDistance, nextWaypointBearing);
+
+                requestSendDateTime = DateTime.Now;
+                result =
+                    await
+                        _client.UpdatePlayerLocation(waypoint.Latitude, waypoint.Longitude,
+                            waypoint.Altitude);
+                if (functionExecutedWhileWalking != null)
+                    await functionExecutedWhileWalking();// look for pokemon
+                await Task.Delay(Math.Min((int)(distanceToTarget / speedInMetersPerSecond * 1000), 3000));
+            } while (LocationUtils.CalculateDistanceInMeters(sourceLocation, targetLocation) >= 30);
+
+            return result;
+        }
+
         public static FortData[] pathByNearestNeighbour(FortData[] pokeStops)
         {
             for (var i = 1; i < pokeStops.Length - 1; i++)
diff --git a/PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj b/PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj
index bb4377b..5c6e5a4 100644
--- a/PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj
+++ b/PokemonGo.RocketAPI.Logic/PokemonGo.RocketAPI.Logic.csproj
@@ -55,6 +55,7 @@
     <Compile Include="Logic.cs" />
     <Compile Include="Navigation.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utils\GPXReader.cs" />
     <Compile Include="Utils\LocationUtils.cs" />
     <Compile Include="Utils\Statistics.cs" />
     <Compile Include="Utils\StringUtils.cs" />
diff --git a/PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs b/PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs
index 2a44693..e250a36 100644
--- a/PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs
+++ b/PokemonGo.RocketAPI.Logic/Utils/LocationUtils.cs
@@ -50,6 +50,33 @@ namespace PokemonGo.RocketAPI.Logic.Utils
             return new GeoCoordinate(ToDegrees(targetLatitudeRadians), ToDegrees(targetLongitudeRadians));
         }

+        public static GeoCoordinate CreateWaypoint(GeoCoordinate sourceLocation, double distanceInMeters, double bearingDegrees, double altitude)
+        //from http://stackoverflow.com/a/17545955
+        {
+            var distanceKm = distanceInMeters / 1000.0;
+            var distanceRadians = distanceKm / 6371; //6371 = Earth's radius in km
+
+            var bearingRadians = ToRad(bearingDegrees);
+            var sourceLatitudeRadians = ToRad(sourceLocation.Latitude);
+            var sourceLongitudeRadians = ToRad(sourceLocation.Longitude);
+
+            var targetLatitudeRadians = Math.Asin(Math.Sin(sourceLatitudeRadians) * Math.Cos(distanceRadians)
+                                                  +
+                                                  Math.Cos(sourceLatitudeRadians) * Math.Sin(distanceRadians) *
+                                                  Math.Cos(bearingRadians));
+
+            var targetLongitudeRadians = sourceLongitudeRadians + Math.Atan2(Math.Sin(bearingRadians)
+                                                                             * Math.Sin(distanceRadians) *
+                                                                             Math.Cos(sourceLatitudeRadians),
+                Math.Cos(distanceRadians)
+                - Math.Sin(sourceLatitudeRadians) * Math.Sin(targetLatitudeRadians));
+
+            // adjust toLonRadians to be in the range -180 to +180...
+            targetLongitudeRadians = (targetLongitudeRadians + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
+
+            return new GeoCoordinate(ToDegrees(targetLatitudeRadians), ToDegrees(targetLongitudeRadians), altitude);
+        }
+
         public static double DegreeBearing(GeoCoordinate sourceLocation, GeoCoordinate targetLocation)
         // from http://stackoverflow.com/questions/2042599/direction-between-2-latitude-longitude-points-in-c-sharp
         {
diff --git a/PokemonGo.RocketAPI/ISettings.cs b/PokemonGo.RocketAPI/ISettings.cs
index 043ee76..c935e24 100644
--- a/PokemonGo.RocketAPI/ISettings.cs
+++ b/PokemonGo.RocketAPI/ISettings.cs
@@ -27,6 +27,9 @@ namespace PokemonGo.RocketAPI
         bool PrioritizeIVOverCP { get; }
         int MaxTravelDistanceInMeters { get; }

+        bool UseGPXPathing { get; }
+        string GPXFile { get; }
+
         ICollection<KeyValuePair<ItemId, int>> ItemRecycleFilter { get; }

         ICollection<PokemonId> PokemonsToEvolve { get; }
diff --git a/PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj b/PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj
index a758415..61ddc2d 100644
--- a/PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj
+++ b/PokemonGo.RocketAPI/PokemonGo.RocketAPI.csproj
@@ -17,7 +17,7 @@
     <UpdateAssemblyInfoVersion>False</UpdateAssemblyInfoVersion>
     <AssemblyVersionSettings>YearStamp.MonthStamp.DayStamp.Increment</AssemblyVersionSettings>
     <PrimaryVersionType>AssemblyVersionAttribute</PrimaryVersionType>
-    <AssemblyVersion>2016.7.24.283</AssemblyVersion>
+    <AssemblyVersion>2016.7.24.286</AssemblyVersion>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
diff --git a/PokemonGo.RocketAPI/Properties/AssemblyInfo.cs b/PokemonGo.RocketAPI/Properties/AssemblyInfo.cs
index 68d9d4d..951128e 100644
--- a/PokemonGo.RocketAPI/Properties/AssemblyInfo.cs
+++ b/PokemonGo.RocketAPI/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2016.7.24.283")]
+[assembly: AssemblyVersion("2016.7.24.286")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
You may download the files in Public Git.