├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ └── java │ └── io │ └── erosemberg │ └── pkgo │ ├── util │ ├── Reference.java │ ├── annotation │ │ └── ConfigPath.java │ ├── PokemonUtil.java │ ├── Lat2Long.java │ ├── ArrayUtil.java │ ├── Log.java │ └── Config.java │ ├── PKGoHelper.java │ ├── config │ └── HelperConfig.java │ ├── tasks │ ├── PokeStopTask.java │ ├── PokeProfileTask.java │ ├── PokeWalkBackTask.java │ ├── PokeEggHatcher.java │ ├── PokeEvolveTask.java │ ├── PokeWalkTask.java │ └── PokeFinderTask.java │ └── Helper.java ├── README.md ├── .gitignore ├── gradlew.bat └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'pkgo-helper' 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exception/pkg-helper/master/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/util/Reference.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.util; 2 | 3 | /** 4 | * @author Erik Rosemberg 5 | * @since 8/11/16 6 | */ 7 | public final class Reference { 8 | 9 | public static final String VERSION = "1.0-ALPHA"; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Aug 10 10:08:33 ART 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip 7 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/util/annotation/ConfigPath.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.util.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Erik Rosemberg 10 | * @since 8/11/16 11 | */ 12 | @Target(ElementType.TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface ConfigPath { 15 | String value(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/util/PokemonUtil.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.util; 2 | 3 | import POGOProtos.Data.PokemonDataOuterClass; 4 | import com.pokegoapi.api.map.fort.FortDetails; 5 | 6 | /** 7 | * @author Erik Rosemberg 8 | * @since 8/11/16 9 | */ 10 | public class PokemonUtil { 11 | 12 | public static int getIV(PokemonDataOuterClass.PokemonData pokemon) { 13 | return pokemon.getIndividualStamina() + pokemon.getIndividualAttack() + pokemon.getIndividualDefense(); 14 | } 15 | 16 | public static int getIVPercent(PokemonDataOuterClass.PokemonData pokemon) { 17 | int iv = getIV(pokemon); 18 | return (iv * 100) / 45; 19 | } 20 | 21 | public static String getName(FortDetails details) { 22 | return details.getName(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/PKGoHelper.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo; 2 | 3 | import io.erosemberg.pkgo.config.HelperConfig; 4 | import io.erosemberg.pkgo.util.ArrayUtil; 5 | import io.erosemberg.pkgo.util.Config; 6 | import io.erosemberg.pkgo.util.Log; 7 | 8 | /** 9 | * @author Erik Rosemberg 10 | * @since 8/10/16 11 | */ 12 | public class PKGoHelper { 13 | 14 | public static void main(String[] args) { 15 | Thread.setDefaultUncaughtExceptionHandler((t, e) -> Log.debug(t.getName() + " encountered an exception, " + e.getMessage())); 16 | boolean debug = ArrayUtil.contains(args, "-d"); 17 | Log.setShouldDebug(debug); 18 | 19 | HelperConfig config = Config.load(HelperConfig.class); 20 | Helper helper = Helper.getInstance(); 21 | helper.init(config); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/util/Lat2Long.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.util; 2 | 3 | import com.google.common.util.concurrent.AtomicDouble; 4 | 5 | /** 6 | * @author Erik Rosemberg 7 | * @since 8/10/16 8 | */ 9 | public class Lat2Long { 10 | 11 | private AtomicDouble latitude = new AtomicDouble(0.00D); 12 | private AtomicDouble longitude = new AtomicDouble(0.00D); 13 | 14 | public Lat2Long(double latitude, double longitude) { 15 | this.latitude.set(latitude); 16 | this.longitude.set(longitude); 17 | } 18 | 19 | public AtomicDouble getLatitude() { 20 | return latitude; 21 | } 22 | 23 | public AtomicDouble getLongitude() { 24 | return longitude; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return latitude.get() + ", " + longitude.get(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pkg-helper 2 | An experimental smart Pokemon Go bot. Experimental because im most likely going to break everything eventually. 3 | 4 | ### Implemented features 5 | - [x] Logging In and parsing longitude/latitude from properties 6 | - [x] Finding nearby pokemons 7 | - [x] Finding nearby pokestops 8 | - [x] Walking randomly around the map 9 | - [x] Looting nearby pokestops 10 | - [x] Catching nearby pokemons 11 | - [x] Automatically hatching eggs 12 | - [x] Automatically transferring bad pokemons with CP lower than 200 if you have more than one of the type. 13 | 14 | ### Installation instructions 15 | Just now the only way to install this is compiling it yourself, to do so clone the repo doing: 16 | ```shell 17 | git clone git@github.com:erosemberg/pkg-helper.git 18 | ``` 19 | And then run 20 | ```shell 21 | gradle clean build shadowJar & cd build/libs/ & java -jar pkgo-helper-ALPHA-1.0-all.jar -d 22 | ``` 23 | 24 | ###Acknowledgements 25 | Thanks to @jabbink for providing the magic values. 26 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/util/ArrayUtil.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.util; 2 | 3 | import POGOProtos.Inventory.Item.ItemAwardOuterClass; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Erik Rosemberg 9 | * @since 8/10/16 10 | */ 11 | public final class ArrayUtil { 12 | 13 | public static boolean contains(String[] args, String argument) { 14 | for (String a : args) { 15 | if (a.equals(argument)) { 16 | return true; 17 | } 18 | } 19 | 20 | return false; 21 | } 22 | 23 | public static String prettyPrint(List awardList) { 24 | StringBuilder builder = new StringBuilder("["); 25 | for (ItemAwardOuterClass.ItemAward award : awardList) { 26 | builder.append(award.getItemCount()).append("x ").append(award.getItemId()).append(","); 27 | } 28 | 29 | String s = builder.toString().trim(); 30 | if (s.endsWith(",")) { 31 | s = s.substring(0, s.length() - 1); 32 | } 33 | 34 | s += "]"; 35 | return s; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | *.class 4 | 5 | # Mobile Tools for Java (J2ME) 6 | .mtj.tmp/ 7 | 8 | # Package Files # 9 | *.jar 10 | *.war 11 | *.ear 12 | 13 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 14 | hs_err_pid* 15 | ### Gradle template 16 | .gradle 17 | build/ 18 | 19 | # Ignore Gradle GUI config 20 | gradle-app.setting 21 | 22 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 23 | !gradle-wrapper.jar 24 | 25 | # Cache of project 26 | .gradletasknamecache 27 | 28 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 29 | # gradle/wrapper/gradle-wrapper.properties 30 | ### JetBrains template 31 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 32 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 33 | 34 | # User-specific stuff: 35 | .idea/ 36 | *.iml 37 | 38 | # Sensitive or high-churn files: 39 | .idea/dataSources.ids 40 | .idea/dataSources.xml 41 | .idea/dataSources.local.xml 42 | .idea/sqlDataSources.xml 43 | .idea/dynamic.xml 44 | .idea/uiDesigner.xml 45 | 46 | # Gradle: 47 | .idea/gradle.xml 48 | .idea/libraries 49 | 50 | # Mongo Explorer plugin: 51 | .idea/mongoSettings.xml 52 | 53 | ## File-based project format: 54 | *.iws 55 | 56 | ## Plugin-specific files: 57 | 58 | # IntelliJ 59 | /out/ 60 | 61 | # OS X files 62 | .DS_Store -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/config/HelperConfig.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.config; 2 | 3 | import io.erosemberg.pkgo.util.Config; 4 | import io.erosemberg.pkgo.util.annotation.ConfigPath; 5 | 6 | /** 7 | * @author Erik Rosemberg 8 | * @since 8/11/16 9 | */ 10 | @SuppressWarnings("all") 11 | @ConfigPath("settings.json") 12 | public class HelperConfig extends Config { 13 | 14 | private String email = "change@me.com"; 15 | private String password = "changeme"; 16 | 17 | private double latitude = 0.0D; 18 | private double longitude = 0.0D; 19 | private double minDistanceToLootPokestop = 10.0D; 20 | 21 | private int minNearbyPokemonsForIncense = 3; 22 | private boolean useIncense = false; 23 | private boolean evolvePokemons = false; 24 | private boolean useLuckyEggForEvolution = false; 25 | private int minCPForEvolution = 400; 26 | 27 | private double walkingSpeed = 2.8; 28 | 29 | public String getEmail() { 30 | return email; 31 | } 32 | 33 | public String getPassword() { 34 | return password; 35 | } 36 | 37 | public double getLatitude() { 38 | return latitude; 39 | } 40 | 41 | public double getLongitude() { 42 | return longitude; 43 | } 44 | 45 | public double getMinDistanceToLootPokestop() { 46 | return minDistanceToLootPokestop; 47 | } 48 | 49 | public int getMinNearbyPokemonsForIncense() { 50 | return minNearbyPokemonsForIncense; 51 | } 52 | 53 | public boolean isUseIncense() { 54 | return useIncense; 55 | } 56 | 57 | public boolean isEvolvePokemons() { 58 | return evolvePokemons; 59 | } 60 | 61 | public boolean isUseLuckyEggForEvolution() { 62 | return useLuckyEggForEvolution; 63 | } 64 | 65 | public int getMinCPForEvolution() { 66 | return minCPForEvolution; 67 | } 68 | 69 | public void setLatitude(double latitude) { 70 | this.latitude = latitude; 71 | } 72 | 73 | public void setLongitude(double longitude) { 74 | this.longitude = longitude; 75 | } 76 | 77 | public double getWalkingSpeed() { 78 | return walkingSpeed; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/tasks/PokeStopTask.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.tasks; 2 | 3 | import com.google.common.cache.Cache; 4 | import com.google.common.cache.CacheBuilder; 5 | import com.pokegoapi.api.PokemonGo; 6 | import com.pokegoapi.api.map.MapObjects; 7 | import com.pokegoapi.api.map.fort.Pokestop; 8 | import io.erosemberg.pkgo.Helper; 9 | import io.erosemberg.pkgo.util.Log; 10 | 11 | import java.util.Collection; 12 | import java.util.Collections; 13 | import java.util.List; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.stream.Collectors; 16 | 17 | /** 18 | * @author Erik Rosemberg 19 | * @since 8/10/16 20 | */ 21 | public class PokeStopTask implements Runnable { 22 | 23 | private PokemonGo go; 24 | private Cache recentlyLooted = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build(); 25 | 26 | public PokeStopTask(PokemonGo go) { 27 | this.go = go; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | if (!PokeWalkTask.shouldWalk.get()) { 33 | return; 34 | } 35 | try { 36 | Log.info("Scanning for pokestops..."); 37 | MapObjects objects = go.getMap().getMapObjects(); 38 | Collection pokestops = objects.getPokestops().stream().filter(pokestop -> pokestop.getCooldownCompleteTimestampMs() < System.currentTimeMillis()).collect(Collectors.toList()); 39 | 40 | if (!pokestops.isEmpty()) { 41 | Collections.sort(pokestops.stream().collect(Collectors.toList()), (o1, o2) -> Double.compare(o1.getDistance(), o2.getDistance())); 42 | List pokestopList = pokestops.stream().collect(Collectors.toList()); 43 | Pokestop pokestop = pokestopList.remove(0); 44 | if (recentlyLooted.getIfPresent(pokestop.getId()) == null) { 45 | recentlyLooted.put(pokestop.getId(), System.currentTimeMillis()); 46 | Helper.getInstance().loot(pokestop); 47 | } 48 | } else { 49 | Log.debug("No pokestops found nearby..."); 50 | } 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/util/Log.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.util; 2 | 3 | import java.io.IOException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Arrays; 6 | import java.util.Calendar; 7 | import java.util.logging.FileHandler; 8 | import java.util.logging.Logger; 9 | import java.util.logging.SimpleFormatter; 10 | 11 | /** 12 | * @author Erik Rosemberg 13 | * @since 8/10/16 14 | */ 15 | public final class Log { 16 | 17 | private static final Logger LOGGER = Logger.getGlobal(); 18 | private static boolean shouldDebug = false; 19 | 20 | static { 21 | System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tH:%1$tM:%1$tS] [%4$s]: %5$s%n"); 22 | SimpleDateFormat format = new SimpleDateFormat("M-d_HHmmss"); 23 | try { 24 | FileHandler h = new FileHandler("pkh-session-" + format.format(Calendar.getInstance().getTime()) + ".log"); 25 | LOGGER.addHandler(h); 26 | SimpleFormatter formatter = new SimpleFormatter(); 27 | Arrays.stream(LOGGER.getHandlers()).forEach(handler -> handler.setFormatter(formatter)); 28 | } catch (IOException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | public static void setShouldDebug(boolean shouldDebug) { 34 | Log.shouldDebug = shouldDebug; 35 | } 36 | 37 | public static void info(String text) { 38 | LOGGER.info(text); 39 | } 40 | 41 | public static void debug(String text) { 42 | if (shouldDebug) { 43 | LOGGER.info("[DEBUG] " + text); 44 | } 45 | } 46 | 47 | public static void red(String text) { 48 | String output = "\u001b[0;31m" + text + "\u001b[m "; 49 | LOGGER.warning(output); 50 | } 51 | 52 | public static void green(String text) { 53 | String output = "\u001b[0;32m" + text + "\u001b[m "; 54 | LOGGER.info(output); 55 | } 56 | 57 | public static void blue(String text) { 58 | String output = "\u001b[0;36m" + text + "\u001b[m "; 59 | LOGGER.info(output); 60 | } 61 | 62 | public static void yellow(String text) { 63 | String output = "\u001b[0;33m" + text + "\u001b[m "; 64 | LOGGER.info(output); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/util/Config.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import io.erosemberg.pkgo.util.annotation.ConfigPath; 6 | 7 | import java.io.File; 8 | import java.io.FileReader; 9 | import java.io.FileWriter; 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author Erik Rosemberg 14 | * @since 8/11/16 15 | */ 16 | public class Config { 17 | private static final Gson gson = new GsonBuilder().setPrettyPrinting() 18 | .serializeNulls() 19 | .serializeSpecialFloatingPointValues() 20 | .disableHtmlEscaping() 21 | .create(); 22 | private transient File file; 23 | 24 | public static T load(Class clazz) { 25 | Config config = null; 26 | 27 | try { 28 | ConfigPath path = clazz.getAnnotation(ConfigPath.class); 29 | if (path == null) { 30 | Log.red("Invalid config file found, ConfigPath.class not found"); 31 | return null; 32 | } 33 | File file = new File(path.value()); 34 | if (!file.exists()) { 35 | config = clazz.newInstance(); 36 | config.file = file; 37 | config.save(); 38 | } else { 39 | try (FileReader fr = new FileReader(file)) { 40 | config = gson.fromJson(fr, clazz); 41 | config.file = file; 42 | } catch (IOException ignored) { 43 | } 44 | } 45 | } catch (InstantiationException | IllegalAccessException ignored) { 46 | } 47 | 48 | return config == null ? null : clazz.cast(config); 49 | } 50 | 51 | public boolean save() { 52 | try { 53 | if (this.file.getParentFile() != null) { 54 | this.file.getParentFile().mkdirs(); 55 | } 56 | 57 | if (!file.exists()) { 58 | file.createNewFile(); 59 | } 60 | 61 | try (FileWriter fw = new FileWriter(file)) { 62 | fw.write(gson.toJson(this)); 63 | } catch (IOException e) { 64 | return false; 65 | } 66 | } catch (IOException e) { 67 | return false; 68 | } 69 | 70 | return true; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/tasks/PokeProfileTask.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.tasks; 2 | 3 | import POGOProtos.Enums.PokemonIdOuterClass; 4 | import POGOProtos.Networking.Responses.ReleasePokemonResponseOuterClass; 5 | import com.google.common.collect.Maps; 6 | import com.pokegoapi.api.PokemonGo; 7 | import com.pokegoapi.api.pokemon.Pokemon; 8 | import com.pokegoapi.exceptions.LoginFailedException; 9 | import com.pokegoapi.exceptions.RemoteServerException; 10 | import io.erosemberg.pkgo.Helper; 11 | import io.erosemberg.pkgo.util.Log; 12 | import io.erosemberg.pkgo.util.PokemonUtil; 13 | 14 | import java.util.Collections; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | /** 19 | * @author Erik Rosemberg 20 | * @since 8/10/16 21 | */ 22 | public class PokeProfileTask implements Runnable { 23 | 24 | private PokemonGo go; 25 | 26 | public PokeProfileTask(PokemonGo go) { 27 | this.go = go; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | try { 33 | go.getInventories().updateInventories(true); //Force inventory update. 34 | Map countByPokemon = Maps.newHashMap(); 35 | List pokemons = go.getInventories().getPokebank().getPokemons(); 36 | Collections.sort(pokemons, (o1, o2) -> Integer.compare(o1.getCp(), o2.getCp())); 37 | 38 | for (Pokemon pokemon : pokemons) { 39 | countByPokemon.put(pokemon.getPokemonId(), countByPokemon.getOrDefault(pokemon.getPokemonId(), 0) + 1); 40 | if (countByPokemon.get(pokemon.getPokemonId()) <= 1) { 41 | continue; 42 | } 43 | if (pokemon.getCp() >= 400) { 44 | continue; 45 | } 46 | boolean should = !pokemon.isFavorite() || !pokemon.getNickname().isEmpty() || !pokemon.getDeployedFortId().isEmpty(); 47 | if (should) { 48 | countByPokemon.put(pokemon.getPokemonId(), countByPokemon.getOrDefault(pokemon.getPokemonId(), 1) - 1); 49 | ReleasePokemonResponseOuterClass.ReleasePokemonResponse.Result result = pokemon.transferPokemon(); 50 | if (result != ReleasePokemonResponseOuterClass.ReleasePokemonResponse.Result.SUCCESS) { 51 | Log.red("Failed to transfer " + pokemon.getPokemonId() + ", " + result); 52 | } else { 53 | Log.green("Transferred " + pokemon.getPokemonId() + " with " + pokemon.getCp() + "CP and " + PokemonUtil.getIV(pokemon.getProto()) + "IV"); 54 | } 55 | } 56 | } 57 | } catch (LoginFailedException | RemoteServerException e) { 58 | e.printStackTrace(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/tasks/PokeWalkBackTask.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.tasks; 2 | 3 | import com.pokegoapi.api.PokemonGo; 4 | import com.pokegoapi.google.common.geometry.S2LatLng; 5 | import io.erosemberg.pkgo.Helper; 6 | import io.erosemberg.pkgo.util.Lat2Long; 7 | import io.erosemberg.pkgo.util.Log; 8 | 9 | import java.util.concurrent.ScheduledFuture; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * @author Erik Rosemberg 14 | * @since 8/11/16 15 | */ 16 | public class PokeWalkBackTask implements Runnable { 17 | 18 | private PokemonGo go; 19 | 20 | private ScheduledFuture self; 21 | 22 | public PokeWalkBackTask(PokemonGo go) { 23 | this.go = go; 24 | } 25 | 26 | @Override 27 | public void run() { 28 | Lat2Long initial = Helper.getInstance().getStartLocation(); 29 | Log.debug("Initial latitude: " + initial.getLatitude().get() + " initial longitude: " + initial.getLongitude().get()); 30 | Log.debug("Current latitude: " + go.getLatitude() + " current longitude: " + go.getLongitude()); 31 | S2LatLng end = S2LatLng.fromDegrees(initial.getLatitude().get(), initial.getLongitude().get()); 32 | S2LatLng start = S2LatLng.fromDegrees(go.getLatitude(), go.getLongitude()); 33 | 34 | S2LatLng difference = end.sub(start); 35 | double distance = start.getEarthDistance(end); 36 | Log.debug("Distance to initial: " + distance); 37 | if (distance <= 2000) { 38 | return; 39 | } 40 | 41 | double time = distance / 4; //4 Meters every 200 milliseconds. 42 | double delta = 200D / 1000D; 43 | double thing = time / delta; 44 | final long[] steps = {Math.round(thing)}; 45 | if (steps[0] == 0) { 46 | return; 47 | } 48 | 49 | Log.green("Starting walk back task to initial location... ~" + Double.valueOf(distance).intValue() + "m away (ETA: " + Double.valueOf(time).intValue() + "s)"); 50 | 51 | self = Helper.getInstance().schedule(new Runnable() { 52 | long initialSteps = steps[0]; 53 | @Override 54 | public void run() { 55 | double lat = difference.latDegrees() / initialSteps; 56 | double longi = difference.lngDegrees() / initialSteps; 57 | 58 | double lat1 = initial.getLatitude().addAndGet(-lat); 59 | double longi1 = initial.getLongitude().addAndGet(-longi); 60 | 61 | go.setLocation(lat1, longi1, 1.0); 62 | S2LatLng current = S2LatLng.fromDegrees(go.getLatitude(), go.getLongitude()); 63 | double d = current.getEarthDistance(end); 64 | 65 | Log.debug("walkback distance = " + d); 66 | if (d <= 50) { 67 | self.cancel(true); 68 | PokeWalkTask.shouldWalk.set(true); 69 | } 70 | } 71 | }, 0L, 200L, TimeUnit.MILLISECONDS); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/tasks/PokeEggHatcher.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.tasks; 2 | 3 | import POGOProtos.Networking.Responses.UseItemEggIncubatorResponseOuterClass; 4 | import com.pokegoapi.api.PokemonGo; 5 | import com.pokegoapi.api.inventory.EggIncubator; 6 | import com.pokegoapi.api.pokemon.EggPokemon; 7 | import com.pokegoapi.api.pokemon.HatchedEgg; 8 | import com.pokegoapi.api.pokemon.Pokemon; 9 | import com.pokegoapi.exceptions.LoginFailedException; 10 | import com.pokegoapi.exceptions.RemoteServerException; 11 | import io.erosemberg.pkgo.util.Log; 12 | 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | 16 | /** 17 | * @author Erik Rosemberg 18 | * @since 8/10/16 19 | */ 20 | public class PokeEggHatcher implements Runnable { 21 | 22 | private PokemonGo go; 23 | 24 | public PokeEggHatcher(PokemonGo go) { 25 | this.go = go; 26 | } 27 | 28 | @Override 29 | public void run() { 30 | try { 31 | List eggs = go.getInventories().getHatchery().queryHatchedEggs(); 32 | if (!eggs.isEmpty()) { 33 | go.getInventories().updateInventories(true); 34 | 35 | for (HatchedEgg egg : eggs) { 36 | Pokemon pokemon = go.getInventories().getPokebank().getPokemonById(egg.getId()); 37 | if (pokemon != null) { 38 | Log.green("Hatched a " + pokemon.getPokemonId() + " for " + egg.getExperience() + "XP and " + egg.getStardust() + " stardust and " + egg.getCandy() + " candy"); 39 | } 40 | } 41 | } 42 | 43 | List incubators = go.getInventories().getIncubators().stream().filter(eggIncubator -> { 44 | try { 45 | return !eggIncubator.isInUse(); 46 | } catch (LoginFailedException | RemoteServerException e) { 47 | e.printStackTrace(); 48 | return false; 49 | } 50 | }).collect(Collectors.toList()); 51 | List eggPokemons = go.getInventories().getHatchery().getEggs().stream().filter(eggPokemon -> !eggPokemon.isIncubate()).collect(Collectors.toList()); 52 | if (!incubators.isEmpty() && !eggPokemons.isEmpty()) { 53 | EggPokemon pokemon = eggPokemons.stream().findFirst().get(); 54 | UseItemEggIncubatorResponseOuterClass.UseItemEggIncubatorResponse.Result result = pokemon.incubate(incubators.stream().findFirst().get()); 55 | if (result == UseItemEggIncubatorResponseOuterClass.UseItemEggIncubatorResponse.Result.SUCCESS) { 56 | Log.green("Placed an egg in an incubator, need to walk " + pokemon.getEggKmWalkedTarget() + "km"); 57 | } else { 58 | Log.red("Failed to place egg in incubator, " + result); 59 | } 60 | } 61 | } catch (RemoteServerException | LoginFailedException e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/tasks/PokeEvolveTask.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.tasks; 2 | 3 | import POGOProtos.Networking.Responses.EvolvePokemonResponseOuterClass; 4 | import POGOProtos.Networking.Responses.UseItemXpBoostResponseOuterClass; 5 | import com.pokegoapi.api.PokemonGo; 6 | import com.pokegoapi.api.inventory.ItemBag; 7 | import com.pokegoapi.api.map.pokemon.EvolutionResult; 8 | import com.pokegoapi.api.player.PlayerProfile; 9 | import com.pokegoapi.api.pokemon.Pokemon; 10 | import com.pokegoapi.exceptions.LoginFailedException; 11 | import com.pokegoapi.exceptions.RemoteServerException; 12 | import io.erosemberg.pkgo.Helper; 13 | import io.erosemberg.pkgo.config.HelperConfig; 14 | import io.erosemberg.pkgo.util.Log; 15 | import io.erosemberg.pkgo.util.PokemonUtil; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * @author Erik Rosemberg 21 | * @since 8/11/16 22 | */ 23 | public class PokeEvolveTask implements Runnable { 24 | 25 | private PokemonGo go; 26 | 27 | public PokeEvolveTask(PokemonGo go) { 28 | this.go = go; 29 | } 30 | 31 | @Override 32 | public void run() { 33 | HelperConfig config = Helper.getInstance().getConfig(); 34 | PlayerProfile profile = go.getPlayerProfile(); 35 | try { 36 | profile.updateProfile(); 37 | ItemBag bag = go.getInventories().getItemBag(); 38 | List pokemonList = go.getInventories().getPokebank().getPokemons(); 39 | for (Pokemon pokemon : pokemonList) { 40 | int candies = pokemon.getCandy(); 41 | int needed = pokemon.getCandiesToEvolve(); 42 | if (candies >= needed) { 43 | if (config.getMinCPForEvolution() <= pokemon.getCp()) { 44 | Log.debug("Found an evolvable pokemon " + pokemon.getPokemonId() + " with " + pokemon.getCp() + "CP and " + PokemonUtil.getIV(pokemon.getProto()) + "IV."); 45 | 46 | if (config.isUseLuckyEggForEvolution()) { 47 | UseItemXpBoostResponseOuterClass.UseItemXpBoostResponse response = bag.useLuckyEgg(); 48 | UseItemXpBoostResponseOuterClass.UseItemXpBoostResponse.Result result = response.getResult(); 49 | 50 | if (response.hasAppliedItems()) { 51 | Log.green("Using a lucky egg to evolve pokemons!"); 52 | } else { 53 | Log.debug("Failed to use lucky egg " + result); 54 | } 55 | } 56 | 57 | Log.debug("Using " + needed + " " + pokemon.getPokemonId() + " candies to evolve with " + pokemon.getCp() + "CP"); 58 | EvolutionResult result = pokemon.evolve(); 59 | if (result.isSuccessful()) { 60 | Log.green("Evolved " + pokemon.getPokemonId() + " to " + result.getEvolvedPokemon().getPokemonId() + " for " + result.getExpAwarded() + "xp and " + result.getCandyAwarded() + " candies! Evolution has " + result.getEvolvedPokemon().getCp() + "CP and " + PokemonUtil.getIV(result.getEvolvedPokemon().getProto()) + "IV"); 61 | } else { 62 | if (result.getResult() == EvolvePokemonResponseOuterClass.EvolvePokemonResponse.Result.FAILED_INSUFFICIENT_RESOURCES || result.getResult() == EvolvePokemonResponseOuterClass.EvolvePokemonResponse.Result.FAILED_POKEMON_CANNOT_EVOLVE) { 63 | return; 64 | } 65 | Log.red("Failed to evolve " + pokemon.getPokemonId() + " because " + result.getResult()); 66 | } 67 | } else { 68 | Log.debug("Not evolving " + pokemon.getPokemonId() + " because CP was lower than " + config.getMinCPForEvolution() + " (" + pokemon.getCp() + ")."); 69 | } 70 | } 71 | } 72 | 73 | } catch (RemoteServerException | LoginFailedException e) { 74 | e.printStackTrace(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/tasks/PokeWalkTask.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.tasks; 2 | 3 | import com.pokegoapi.api.PokemonGo; 4 | import com.pokegoapi.api.map.fort.Pokestop; 5 | import com.pokegoapi.exceptions.LoginFailedException; 6 | import com.pokegoapi.exceptions.RemoteServerException; 7 | import com.pokegoapi.google.common.geometry.S2LatLng; 8 | import io.erosemberg.pkgo.Helper; 9 | import io.erosemberg.pkgo.util.Lat2Long; 10 | import io.erosemberg.pkgo.util.Log; 11 | import io.erosemberg.pkgo.util.PokemonUtil; 12 | 13 | import java.util.concurrent.ScheduledFuture; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.concurrent.atomic.AtomicBoolean; 16 | 17 | /** 18 | * @author Erik Rosemberg 19 | * @since 8/10/16 20 | */ 21 | public class PokeWalkTask implements Runnable { 22 | 23 | private PokemonGo go; 24 | private Lat2Long lat2Long; 25 | public static AtomicBoolean shouldWalk = new AtomicBoolean(true); 26 | 27 | public static Pokestop target; 28 | public static ScheduledFuture self; 29 | 30 | public PokeWalkTask(PokemonGo go, Lat2Long lat2Long) { 31 | this.go = go; 32 | this.lat2Long = lat2Long; 33 | } 34 | 35 | @Override 36 | public void run() { 37 | if (!shouldWalk.get()) { 38 | return; 39 | } 40 | 41 | if (target != null) { 42 | shouldWalk.set(false); //Stop walking here. 43 | Log.debug("Target was not null..processing..."); 44 | S2LatLng end = S2LatLng.fromDegrees(target.getLatitude(), target.getLongitude()); 45 | S2LatLng start = S2LatLng.fromDegrees(lat2Long.getLatitude().get(), lat2Long.getLongitude().get()); 46 | S2LatLng difference = end.sub(start); 47 | double distance = start.getEarthDistance(end); 48 | double time = distance / Helper.getInstance().getConfig().getWalkingSpeed(); 49 | double delta = 200D / 1000D; 50 | double thing = time / delta; 51 | final long[] steps = {Math.round(thing)}; 52 | if (steps[0] == 0) { 53 | return; 54 | } 55 | try { 56 | String name = PokemonUtil.getName(target.getDetails()); 57 | Log.green("Travelling to " + name + " located ~" + Double.valueOf(distance).intValue() + "m away (ETA: " + Double.valueOf(time).intValue() + "s). Cruise speed: " + Helper.getInstance().getConfig().getWalkingSpeed()); 58 | } catch (LoginFailedException | RemoteServerException ignored) { 59 | } 60 | Log.debug("Walking to stop in " + steps[0] + " steps."); 61 | 62 | self = Helper.getInstance().schedule(new Runnable() { 63 | long initialSteps = steps[0]; 64 | @Override 65 | public void run() { 66 | double lat = difference.latDegrees() / initialSteps; 67 | double longi = difference.lngDegrees() / initialSteps; 68 | 69 | double lat1 = lat2Long.getLatitude().addAndGet(lat); 70 | double longi1 = lat2Long.getLongitude().addAndGet(longi); 71 | 72 | go.setLocation(lat1, longi1, 1.0); 73 | S2LatLng current = S2LatLng.fromDegrees(go.getLatitude(), go.getLongitude()); 74 | double d = current.getEarthDistance(end); 75 | initialSteps--; 76 | 77 | Log.debug("Running, steps = " + initialSteps + ", distance = " + d); 78 | if (d >= 2000) { 79 | Log.debug("Target was too far away, stopping..."); 80 | shouldWalk.set(true); 81 | target = null; 82 | self.cancel(true); 83 | return; 84 | } 85 | if (d <= Helper.getInstance().getConfig().getMinDistanceToLootPokestop()) { //Failsafe. 86 | initialSteps = 0; 87 | } 88 | if (initialSteps == 0) { 89 | try { 90 | Helper.getInstance().loot(target); 91 | } catch (LoginFailedException | RemoteServerException e) { 92 | e.printStackTrace(); 93 | } 94 | shouldWalk.set(true); 95 | target = null; 96 | self.cancel(true); 97 | return; 98 | } 99 | shouldWalk.set(false); 100 | } 101 | }, 0L, 200L, TimeUnit.MILLISECONDS); 102 | } 103 | 104 | //Walk randomly around the map to find pokestops. 105 | double lat = lat2Long.getLatitude().addAndGet(getRandomDirection()); 106 | double longi = lat2Long.getLongitude().addAndGet(getRandomDirection()); 107 | 108 | go.setLocation(lat, longi, 1.0); 109 | 110 | Log.debug("Walking to " + lat2Long.toString()); 111 | } 112 | 113 | private double getRandomDirection() { 114 | return Math.random() * 0.0001 - 0.00005; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/tasks/PokeFinderTask.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo.tasks; 2 | 3 | import POGOProtos.Data.PokemonDataOuterClass; 4 | import POGOProtos.Networking.Responses.CatchPokemonResponseOuterClass; 5 | import com.pokegoapi.api.PokemonGo; 6 | import com.pokegoapi.api.inventory.ItemBag; 7 | import com.pokegoapi.api.map.pokemon.CatchResult; 8 | import com.pokegoapi.api.map.pokemon.CatchablePokemon; 9 | import com.pokegoapi.api.map.pokemon.encounter.DiskEncounterResult; 10 | import com.pokegoapi.api.map.pokemon.encounter.EncounterResult; 11 | import com.pokegoapi.exceptions.LoginFailedException; 12 | import com.pokegoapi.exceptions.NoSuchItemException; 13 | import com.pokegoapi.exceptions.RemoteServerException; 14 | import io.erosemberg.pkgo.Helper; 15 | import io.erosemberg.pkgo.util.Log; 16 | import io.erosemberg.pkgo.util.PokemonUtil; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.concurrent.atomic.AtomicInteger; 22 | 23 | /** 24 | * @author Erik Rosemberg 25 | * @since 8/10/16 26 | */ 27 | public class PokeFinderTask implements Runnable { 28 | 29 | private PokemonGo go; 30 | private AtomicInteger softBanConuter = new AtomicInteger(0); 31 | private boolean shouldFind = true; 32 | 33 | public PokeFinderTask(PokemonGo go) { 34 | this.go = go; 35 | } 36 | 37 | @Override 38 | public void run() { 39 | if (!shouldFind) return; 40 | try { 41 | Log.info("Scanning for catchable pokemons..."); 42 | List catchable = go.getMap().getCatchablePokemon(); 43 | 44 | if (catchable.size() > 0) { 45 | if (catchable.size() >= Helper.getInstance().getConfig().getMinNearbyPokemonsForIncense() && Helper.getInstance().getConfig().isUseIncense()) { 46 | ItemBag bag = go.getInventories().getItemBag(); 47 | bag.useIncense(); 48 | Log.debug("Using incense"); 49 | } 50 | Log.debug("Found " + catchable.size() + " catchable pokemons."); 51 | for (CatchablePokemon max : catchable) { 52 | Log.green("Found a " + max.getPokemonId()); 53 | EncounterResult result = max.encounterPokemon(); 54 | if (result.wasSuccessful()) { 55 | PokemonDataOuterClass.PokemonData data = result.getPokemonData(); 56 | Log.blue("Encountered a " + data.getPokemonId() + " with " + data.getCp() + "CP and " + PokemonUtil.getIV(data) + "IV"); 57 | 58 | CatchResult catchResult = max.catchPokemonBestBallToUse(result, new ArrayList<>(), -1, 1); 59 | 60 | if (!catchResult.isFailed()) { 61 | softBanConuter.set(0); 62 | int xp = catchResult.getXpList().stream().mapToInt(Integer::intValue).sum(); 63 | int stardust = catchResult.getStardustList().stream().mapToInt(Integer::intValue).sum(); 64 | Log.green("Caught a " + data.getPokemonId() + " with " + data.getCp() + "CP " + (result instanceof DiskEncounterResult ? "(lured)" : "(wild)") + ", earned " + xp + "xp and " + stardust + " stardust!"); 65 | } else { 66 | if (catchResult.getStatus() == CatchPokemonResponseOuterClass.CatchPokemonResponse.CatchStatus.CATCH_FLEE) { 67 | int counter = softBanConuter.addAndGet(1); 68 | if (counter >= 10) { 69 | shouldFind = false; 70 | Log.red("Possible soft-ban met, stopping the finder task for 2 minutes..."); 71 | Helper.getInstance().scheduleLater(() -> { 72 | shouldFind = true; 73 | softBanConuter.set(0); 74 | }, 2, TimeUnit.MINUTES); 75 | } 76 | } 77 | Log.red("Failed to catch " + data.getPokemonId() + ", " + catchResult.getStatus()); 78 | } 79 | } else { 80 | Log.red("Failed to encounter " + max.getPokemonId() + ", " + result.getStatus()); 81 | } 82 | } 83 | } 84 | } catch (LoginFailedException | RemoteServerException | NoSuchItemException ignored) { 85 | if (ignored instanceof NoSuchItemException) { 86 | Log.red("You have no pokeballs left! Shuting down the finder task for 10 minutes to replentish pokeballs in pokestops."); 87 | if (!shouldFind) { 88 | return; 89 | } 90 | shouldFind = false; 91 | Helper.getInstance().scheduleLater(() -> { 92 | shouldFind = true; 93 | softBanConuter.set(0); 94 | Log.green("10 minutes have passed, we should have pokeballs now!"); 95 | }, 10, TimeUnit.MINUTES); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /src/main/java/io/erosemberg/pkgo/Helper.java: -------------------------------------------------------------------------------- 1 | package io.erosemberg.pkgo; 2 | 3 | import POGOProtos.Data.PlayerDataOuterClass; 4 | import POGOProtos.Networking.Responses.FortSearchResponseOuterClass; 5 | import com.google.gson.JsonArray; 6 | import com.google.gson.JsonElement; 7 | import com.google.gson.JsonObject; 8 | import com.google.gson.JsonParser; 9 | import com.google.gson.JsonPrimitive; 10 | import com.pokegoapi.api.PokemonGo; 11 | import com.pokegoapi.api.map.fort.Pokestop; 12 | import com.pokegoapi.api.map.fort.PokestopLootResult; 13 | import com.pokegoapi.api.player.PlayerProfile; 14 | import com.pokegoapi.auth.GoogleAutoCredentialProvider; 15 | import com.pokegoapi.exceptions.LoginFailedException; 16 | import com.pokegoapi.exceptions.RemoteServerException; 17 | import io.erosemberg.pkgo.config.HelperConfig; 18 | import io.erosemberg.pkgo.tasks.PokeEggHatcher; 19 | import io.erosemberg.pkgo.tasks.PokeEvolveTask; 20 | import io.erosemberg.pkgo.tasks.PokeFinderTask; 21 | import io.erosemberg.pkgo.tasks.PokeProfileTask; 22 | import io.erosemberg.pkgo.tasks.PokeStopTask; 23 | import io.erosemberg.pkgo.tasks.PokeWalkBackTask; 24 | import io.erosemberg.pkgo.tasks.PokeWalkTask; 25 | import io.erosemberg.pkgo.util.ArrayUtil; 26 | import io.erosemberg.pkgo.util.Lat2Long; 27 | import io.erosemberg.pkgo.util.Log; 28 | import io.erosemberg.pkgo.util.Reference; 29 | import okhttp3.Call; 30 | import okhttp3.Callback; 31 | import okhttp3.OkHttpClient; 32 | import okhttp3.Request; 33 | import okhttp3.Response; 34 | import okhttp3.ResponseBody; 35 | 36 | import java.io.IOException; 37 | import java.util.Date; 38 | import java.util.Scanner; 39 | import java.util.concurrent.Executors; 40 | import java.util.concurrent.ScheduledExecutorService; 41 | import java.util.concurrent.ScheduledFuture; 42 | import java.util.concurrent.ThreadFactory; 43 | import java.util.concurrent.TimeUnit; 44 | import java.util.concurrent.atomic.AtomicInteger; 45 | import java.util.stream.IntStream; 46 | 47 | import static io.erosemberg.pkgo.tasks.PokeWalkTask.shouldWalk; 48 | 49 | /** 50 | * @author Erik Rosemberg 51 | * @since 8/10/16 52 | */ 53 | public final class Helper { 54 | 55 | private static Helper self = new Helper(); 56 | 57 | private HelperConfig config; 58 | private final ScheduledExecutorService service; 59 | private Lat2Long location; 60 | private PokemonGo go; 61 | private String user; 62 | private Lat2Long startLocation; 63 | 64 | private Helper() { 65 | service = Executors.newScheduledThreadPool(3, new ThreadFactory() { 66 | private AtomicInteger counter = new AtomicInteger(0); 67 | @Override 68 | public Thread newThread(Runnable r) { 69 | String name = "Thread " + counter.addAndGet(1); 70 | Log.debug("Starting " + name); 71 | return new Thread(r, name); 72 | } 73 | }); 74 | } 75 | 76 | void init(HelperConfig config) { 77 | this.config = config; 78 | OkHttpClient client = new OkHttpClient(); 79 | try { 80 | Log.green("Starting PokemonGo-Helper version " + Reference.VERSION); 81 | if (config == null) { 82 | Log.red("settings.json does not exist!"); 83 | return; 84 | } 85 | user = config.getEmail(); 86 | if (user.equals("change@me.com")) { 87 | Log.green("settings.json was just generated, please edit it before running again!"); 88 | return; 89 | } 90 | String password = config.getPassword(); 91 | 92 | go = new PokemonGo(new GoogleAutoCredentialProvider(client, user, password), client); 93 | Scanner scanner = new Scanner(System.in); 94 | System.out.print("Do you wish to use last time's latitude and longitude (yes/no)? "); 95 | String input = scanner.next(); 96 | boolean use; 97 | if (input.equalsIgnoreCase("yes")) { 98 | use = true; 99 | } else if (input.equalsIgnoreCase("no")) { 100 | use = false; 101 | } else { 102 | Log.red("Failed to recognize input, defaulting to yes."); 103 | use = true; 104 | } 105 | 106 | double latitude; 107 | double longitude; 108 | if (use) { 109 | latitude = config.getLatitude(); 110 | longitude = config.getLongitude(); 111 | } else { 112 | System.out.print("Please enter the desired latitude: "); 113 | latitude = scanner.nextDouble(); 114 | System.out.print("Please enter the desired longitude: "); 115 | longitude = scanner.nextDouble(); 116 | Log.green("Read values properly, resuming launch..."); 117 | config.setLatitude(latitude); 118 | config.setLongitude(longitude); 119 | config.save(); 120 | } 121 | 122 | // if (!config.isSnipe()) { 123 | // this.location = new Lat2Long(latitude, longitude); 124 | // } else { 125 | // this.location = new Lat2Long(0.0D, 0.0D); 126 | // snipe(); 127 | // } 128 | 129 | this.location = new Lat2Long(latitude, longitude); 130 | this.startLocation = new Lat2Long(latitude, longitude); 131 | go.setLocation(location.getLatitude().get(), location.getLongitude().get(), 1); 132 | Log.green("Logged in successfully...initiating"); 133 | Log.yellow("===================================================="); 134 | Log.yellow("PokemonGo Helper version " + Reference.VERSION + " has initiated."); 135 | Log.yellow("to turn on debug, run the jar again with the -d flag"); 136 | Log.yellow("===================================================="); 137 | Log.debug("Scheduling all initial tasks..."); 138 | 139 | schedule(this::printProfileInfo, 0L, 10L, TimeUnit.MINUTES); 140 | schedule(new PokeProfileTask(go), 1L, 1L, TimeUnit.MINUTES); 141 | schedule(new PokeWalkTask(go, location), 0L, 1L, TimeUnit.SECONDS); 142 | schedule(new PokeFinderTask(go), 0L, 5L, TimeUnit.SECONDS); 143 | schedule(new PokeStopTask(go), 30L, 30L, TimeUnit.SECONDS); 144 | schedule(new PokeEggHatcher(go), 0L, 1L, TimeUnit.MINUTES); 145 | schedule(new PokeWalkBackTask(go), 0L, 5L, TimeUnit.MINUTES); 146 | //schedule(new PokeSniperTask(go), 30L, 30L, TimeUnit.SECONDS); 147 | if (config.isEvolvePokemons()) { 148 | schedule(new PokeEvolveTask(go), 0L, 5L, TimeUnit.MINUTES); 149 | } 150 | 151 | Runtime.getRuntime().addShutdownHook(new Thread() { 152 | @Override 153 | public void run() { 154 | Log.red("Stopping executors..."); 155 | service.shutdown(); 156 | Log.red("Thank you and goodbye!"); 157 | } 158 | }); 159 | } catch (LoginFailedException | RemoteServerException e) { 160 | Log.red(e.getMessage()); 161 | e.printStackTrace(); 162 | } 163 | } 164 | 165 | public ScheduledFuture schedule(Runnable runnable, long initialDelay, long period, TimeUnit unit) { 166 | Log.debug("Scheduling " + runnable.getClass().getSimpleName() + " at a " + period + " " + unit.name() + " period."); 167 | return service.scheduleAtFixedRate(runnable, initialDelay, period, unit); 168 | } 169 | 170 | public void scheduleLater(Runnable runnable, long delay, TimeUnit unit) { 171 | Log.debug("Scheduled task to run in " + delay + " " + unit); 172 | service.schedule(runnable, delay, unit); 173 | } 174 | 175 | public void loot(Pokestop closest) throws LoginFailedException, RemoteServerException { 176 | if (closest.canLoot()) { 177 | Log.debug("Pausing walking task to loot pokestop..."); 178 | shouldWalk.set(false); 179 | Log.green("Going to loot pokestop " + closest.getDetails().getName() + (closest.hasLure() ? " (currently lured)" : "")); 180 | PokestopLootResult result = closest.loot(); 181 | if (result == null) { 182 | Log.red("Pokestop had no loot result, skipping"); 183 | shouldWalk.set(true); 184 | return; 185 | } 186 | 187 | if (result.wasSuccessful()) { 188 | if (result.getExperience() == 0 && result.getItemsAwarded().isEmpty()) { 189 | Log.debug("Found a possible ban, spinning it a lot of times to evade..."); 190 | IntStream.range(0, 40).forEach(value -> { 191 | try { 192 | closest.loot(); 193 | } catch (LoginFailedException | RemoteServerException e) { 194 | e.printStackTrace(); 195 | } 196 | }); 197 | } else { 198 | Log.green("Looted pokestop for " + result.getExperience() + " exp and " + ArrayUtil.prettyPrint(result.getItemsAwarded()) + "."); 199 | } 200 | } 201 | 202 | Log.debug("Resuming walking task..."); 203 | shouldWalk.set(true); 204 | } else { 205 | if (PokeWalkTask.target == null) { 206 | PokeWalkTask.target = closest; 207 | } 208 | if (closest.loot().getResult() == FortSearchResponseOuterClass.FortSearchResponse.Result.OUT_OF_RANGE) { 209 | return; 210 | } 211 | Log.red("Failed to loot pokestop, reason was " + closest.loot().getResult()); 212 | } 213 | } 214 | 215 | public void printProfileInfo() { 216 | try { 217 | go.getPlayerProfile().updateProfile(); //Force update. 218 | PlayerProfile profile = go.getPlayerProfile(); 219 | PlayerDataOuterClass.PlayerData data = profile.getPlayerData(); 220 | Log.blue("Name: " + data.getUsername() + ", Email: " + user); 221 | Log.blue("Team: " + data.getTeam().name() + ", Creation Date: " + new Date(data.getCreationTimestampMs()).toString()); 222 | Log.blue("Level: " + profile.getStats().getLevel() + ", XP: " + profile.getStats().getExperience() + "/" + profile.getStats().getNextLevelXp()); 223 | Log.blue("PokeCoins: " + profile.getCurrency(PlayerProfile.Currency.POKECOIN) + ", Stardust: " + profile.getCurrency(PlayerProfile.Currency.STARDUST) + ", Caught Pokemons: " + profile.getStats().getPokemonsCaptured()); 224 | } catch (Exception e) { 225 | e.printStackTrace(); 226 | } 227 | } 228 | 229 | public Lat2Long getLocation() { 230 | return location; 231 | } 232 | 233 | public void snipe() { 234 | OkHttpClient client = new OkHttpClient(); 235 | Request request = new Request.Builder().url("http://pokesnipers.com/api/v1/pokemon.json").build(); 236 | 237 | Lat2Long loc = new Lat2Long(0.0D, 0.0D); 238 | client.newCall(request).enqueue(new Callback() { 239 | @Override 240 | public void onFailure(Call call, IOException e) { 241 | Log.red("Failed to snipe pokemons, " + e.getMessage()); 242 | } 243 | 244 | @Override 245 | public void onResponse(Call call, Response response) throws IOException { 246 | ResponseBody body = response.body(); 247 | JsonParser parser = new JsonParser(); 248 | JsonObject object = parser.parse(body.string()).getAsJsonObject(); 249 | JsonArray results = object.getAsJsonArray("results"); 250 | String name = "Unknown"; 251 | boolean found = false; 252 | for (JsonElement element : results) { 253 | if (element instanceof JsonObject) { 254 | JsonObject snipeable = (JsonObject) element; 255 | JsonPrimitive coordsObj = (JsonPrimitive) snipeable.get("coords"); 256 | String coords = coordsObj.getAsString(); 257 | String[] split = coords.split(","); 258 | if (split.length != 2) { 259 | continue; 260 | } 261 | double lat = Double.valueOf(split[0]); 262 | double longi = Double.valueOf(split[1]); 263 | 264 | lat += 0.003; //Add to avoid softban. 265 | longi += 0.003; 266 | 267 | loc.getLatitude().set(lat); 268 | loc.getLongitude().set(longi); 269 | JsonPrimitive n = (JsonPrimitive) snipeable.get("name"); 270 | name = n.getAsString(); 271 | found = true; 272 | break; 273 | } 274 | } 275 | if (found) { 276 | Log.green("Sniping " + name + " at " + loc.toString()); 277 | getLocation().getLongitude().set(loc.getLongitude().get()); 278 | getLocation().getLatitude().set(loc.getLatitude().get()); 279 | go.setLocation(loc.getLatitude().get(), loc.getLongitude().get(), 1.0D); 280 | 281 | if (PokeWalkTask.self != null) { 282 | Log.debug("Canceling pokestop task because we are sniping pokemons!"); 283 | PokeWalkTask.self.cancel(true); 284 | PokeWalkTask.shouldWalk.set(true); 285 | PokeWalkTask.target = null; 286 | } 287 | } else { 288 | Log.debug("Found no possible pokemons to snipe."); 289 | } 290 | 291 | response.body().close(); 292 | } 293 | }); 294 | } 295 | 296 | public HelperConfig getConfig() { 297 | return config; 298 | } 299 | 300 | public static Helper getInstance() { 301 | return self; 302 | } 303 | 304 | public Lat2Long getStartLocation() { 305 | return startLocation; 306 | } 307 | } 308 | --------------------------------------------------------------------------------