Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/com/pokegoapi/api/gym/Gym.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import java.util.ArrayList;
import java.util.List;

public class Gym implements MapPoint{
public class Gym implements MapPoint {
private FortData proto;
private GetGymDetailsResponse details;
private PokemonGo api;
Expand Down
41 changes: 33 additions & 8 deletions src/main/java/com/pokegoapi/api/map/Map.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import POGOProtos.Map.Fort.FortDataOuterClass.FortData;
import POGOProtos.Map.Fort.FortTypeOuterClass.FortType;
import POGOProtos.Map.MapCellOuterClass.MapCell;
import POGOProtos.Map.Pokemon.MapPokemonOuterClass;
import POGOProtos.Map.Pokemon.MapPokemonOuterClass.MapPokemon;
import POGOProtos.Map.Pokemon.NearbyPokemonOuterClass;
import POGOProtos.Map.Pokemon.WildPokemonOuterClass;
Expand All @@ -38,11 +39,13 @@
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.annimon.stream.function.Function;
import com.annimon.stream.function.Predicate;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.pokegoapi.api.PokemonGo;
import com.pokegoapi.api.gym.Gym;
import com.pokegoapi.api.map.fort.FortDetails;
import com.pokegoapi.api.map.fort.Pokestop;
import com.pokegoapi.api.map.pokemon.CatchablePokemon;
import com.pokegoapi.api.map.pokemon.NearbyPokemon;
import com.pokegoapi.exceptions.LoginFailedException;
Expand All @@ -52,7 +55,6 @@
import com.pokegoapi.google.common.geometry.S2LatLng;
import com.pokegoapi.main.AsyncServerRequest;
import com.pokegoapi.main.ServerRequest;
import com.pokegoapi.util.DummyFuture;
import com.pokegoapi.util.FutureWrapper;
import com.pokegoapi.util.MapUtil;
import com.pokegoapi.util.PokemonFuture;
Expand All @@ -69,6 +71,7 @@ public class Map {
private static int RESEND_REQUEST = 5000;
private final PokemonGo api;
private MapObjects cachedMapObjects;
private List<CatchablePokemon> cachedCatchable;
private long lastMapUpdate;

/**
Expand All @@ -91,6 +94,11 @@ public Map(PokemonGo api) throws LoginFailedException, RemoteServerException {
* @return a List of CatchablePokemon at your current location
*/
public PokemonFuture<List<CatchablePokemon>> getCatchablePokemonAsync() {

if (useCache() && cachedCatchable != null) {
return FutureWrapper.just(cachedCatchable);
}

List<Long> cellIds = getDefaultCells();
return new FutureWrapper<MapObjects, List<CatchablePokemon>>(getMapObjectsAsync(cellIds)) {
@Override
Expand All @@ -103,13 +111,22 @@ protected List<CatchablePokemon> handle(MapObjects mapObjects) throws RemoteServ
for (WildPokemonOuterClass.WildPokemon wildPokemon : mapObjects.getWildPokemons()) {
catchablePokemons.add(new CatchablePokemon(api, wildPokemon));
}
// TODO: Check if this code is correct; merged because this contains many other fixes
/*for (Pokestop pokestop : objects.getPokestops()) {
if (pokestop.inRange() && pokestop.hasLurePokemon()) {

/*
TODO: i have more success checking if encounterId > 0
i don't want to use the hasLure because it do a request every call
*/
for (Pokestop pokestop : mapObjects.getPokestops()) {
if (pokestop.inRange()
&& pokestop.getFortData().hasLureInfo()
&& pokestop.getFortData().getLureInfo().getEncounterId() > 0) {
//if (pokestop.inRange() && pokestop.hasLurePokemon()) {
catchablePokemons.add(new CatchablePokemon(api, pokestop.getFortData()));
}
}*/
return new ArrayList<>(catchablePokemons);
}

cachedCatchable = new ArrayList<>(catchablePokemons);
return cachedCatchable;
}
};
}
Expand Down Expand Up @@ -310,8 +327,8 @@ public PokemonFuture<MapObjects> getMapObjectsAsync(int width) {
*/
public PokemonFuture<MapObjects> getMapObjectsAsync(List<Long> cellIds) {

if ((api.currentTimeMillis() - lastMapUpdate) < RESEND_REQUEST) {
return new DummyFuture<MapObjects>(cachedMapObjects);
if (useCache()) {
return FutureWrapper.just(cachedMapObjects);
}

lastMapUpdate = api.currentTimeMillis();
Expand Down Expand Up @@ -649,6 +666,14 @@ public CatchPokemonResponse catchPokemon(
return response;
}

/**
* Wether or not to get a fresh copy or use cache;
*
* @return true if enough time has elapsed since the last request, false otherwise
*/
private boolean useCache() {
return (api.currentTimeMillis() - lastMapUpdate) < RESEND_REQUEST;
}

private List<Long> getDefaultCells() {
return getCellIds(api.getLatitude(), api.getLongitude(), CELL_WIDTH);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/pokegoapi/api/map/Point.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import lombok.Getter;
import lombok.Setter;

public class Point implements MapPoint{
public class Point implements MapPoint {
@Getter
@Setter
private double longitude;
Expand Down
110 changes: 93 additions & 17 deletions src/main/java/com/pokegoapi/api/map/pokemon/CatchablePokemon.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,31 @@

package com.pokegoapi.api.map.pokemon;

import POGOProtos.Enums.PokemonIdOuterClass;

import POGOProtos.Enums.PokemonIdOuterClass.PokemonId;
import POGOProtos.Inventory.Item.ItemIdOuterClass.ItemId;
import POGOProtos.Map.Fort.FortDataOuterClass.FortData;
import POGOProtos.Map.Pokemon.MapPokemonOuterClass.MapPokemon;
import POGOProtos.Map.Pokemon.WildPokemonOuterClass.WildPokemon;
import POGOProtos.Networking.Requests.Messages.CatchPokemonMessageOuterClass.CatchPokemonMessage;
import POGOProtos.Networking.Requests.Messages.EncounterMessageOuterClass;
import POGOProtos.Networking.Requests.Messages.DiskEncounterMessageOuterClass;
import POGOProtos.Networking.Requests.Messages.DiskEncounterMessageOuterClass.DiskEncounterMessage;
import POGOProtos.Networking.Requests.Messages.EncounterMessageOuterClass.EncounterMessage;
import POGOProtos.Networking.Requests.Messages.UseItemCaptureMessageOuterClass.UseItemCaptureMessage;
import POGOProtos.Networking.Requests.RequestTypeOuterClass;
import POGOProtos.Networking.Requests.RequestTypeOuterClass.RequestType;
import POGOProtos.Networking.Responses.CatchPokemonResponseOuterClass.CatchPokemonResponse;
import POGOProtos.Networking.Responses.CatchPokemonResponseOuterClass.CatchPokemonResponse.CatchStatus;
import POGOProtos.Networking.Responses.EncounterResponseOuterClass;
import POGOProtos.Networking.Responses.DiskEncounterResponseOuterClass.DiskEncounterResponse;
import POGOProtos.Networking.Responses.EncounterResponseOuterClass.EncounterResponse;
import POGOProtos.Networking.Responses.UseItemCaptureResponseOuterClass.UseItemCaptureResponse;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.pokegoapi.api.PokemonGo;
import com.pokegoapi.api.inventory.ItemBag;
import com.pokegoapi.api.inventory.Pokeball;
import com.pokegoapi.api.map.pokemon.encounter.DiskEncounterResult;
import com.pokegoapi.api.map.pokemon.encounter.EncounterResult;
import com.pokegoapi.api.map.pokemon.encounter.NormalEncounterResult;
import com.pokegoapi.exceptions.LoginFailedException;
import com.pokegoapi.exceptions.NoSuchItemException;
import com.pokegoapi.exceptions.RemoteServerException;
Expand All @@ -48,11 +54,19 @@

import java.util.concurrent.Future;


/**
* The type Catchable pokemon.
*/
@ToString
public class CatchablePokemon implements MapPoint{
public class CatchablePokemon implements MapPoint {

private enum EncounterKind {
NORMAL,
DISK;
}


private static final String TAG = CatchablePokemon.class.getSimpleName();
private final PokemonGo api;

Expand All @@ -61,16 +75,19 @@ public class CatchablePokemon implements MapPoint{
@Getter
private final long encounterId;
@Getter
private final PokemonIdOuterClass.PokemonId pokemonId;
private final PokemonId pokemonId;
@Getter
private final long expirationTimestampMs;
@Getter
private final double latitude;
@Getter
private final double longitude;
private final EncounterKind encounterKind;

private Boolean encountered = null;



/**
* Instantiates a new Catchable pokemon.
*
Expand All @@ -79,7 +96,7 @@ public class CatchablePokemon implements MapPoint{
*/
public CatchablePokemon(PokemonGo api, MapPokemon proto) {
this.api = api;

this.encounterKind = EncounterKind.NORMAL;
this.spawnPointId = proto.getSpawnPointId();
this.encounterId = proto.getEncounterId();
this.pokemonId = proto.getPokemonId();
Expand All @@ -96,6 +113,7 @@ public CatchablePokemon(PokemonGo api, MapPokemon proto) {
*/
public CatchablePokemon(PokemonGo api, WildPokemon proto) {
this.api = api;
this.encounterKind = EncounterKind.NORMAL;
this.spawnPointId = proto.getSpawnPointId();
this.encounterId = proto.getEncounterId();
this.pokemonId = proto.getPokemonData().getPokemonId();
Expand All @@ -116,13 +134,24 @@ public CatchablePokemon(PokemonGo api, FortData proto) {
}
this.api = api;
// TODO: does this work?
this.spawnPointId = null;
// seems that spawnPoint it's fortId in catchAPI so it should be safe to just set it in that way
this.spawnPointId = proto.getLureInfo().getFortId();
this.encounterId = proto.getLureInfo().getEncounterId();
this.pokemonId = proto.getLureInfo().getActivePokemonId();
this.expirationTimestampMs = proto.getLureInfo()
.getLureExpiresTimestampMs();
this.latitude = proto.getLatitude();
this.longitude = proto.getLongitude();
this.encounterKind = EncounterKind.DISK;
}

/**
* Encounter pokemon
*
* @return the encounter result
*/
public EncounterResult encounterPokemon() throws LoginFailedException, RemoteServerException {
return encounterPokemonAsync().toBlocking();
}

/**
Expand All @@ -131,26 +160,41 @@ public CatchablePokemon(PokemonGo api, FortData proto) {
* @return the encounter result
*/
public PokemonFuture<EncounterResult> encounterPokemonAsync() {
EncounterMessageOuterClass.EncounterMessage reqMsg = EncounterMessageOuterClass.EncounterMessage
if (encounterKind == EncounterKind.NORMAL) {
return encounterNormalPokemonAsync();
} else if (encounterKind == EncounterKind.DISK) {
return encounterDiskPokemonAsync();
}

throw new IllegalStateException("Catchable pokemon missing encounter type");
}

/**
* Encounter pokemon encounter result.
*
* @return the encounter result
*/
public PokemonFuture<EncounterResult> encounterNormalPokemonAsync() {
EncounterMessage reqMsg = EncounterMessage
.newBuilder().setEncounterId(getEncounterId())
.setPlayerLatitude(api.getLatitude())
.setPlayerLongitude(api.getLongitude())
.setSpawnPointId(getSpawnPointId()).build();
AsyncServerRequest serverRequest = new AsyncServerRequest(
RequestTypeOuterClass.RequestType.ENCOUNTER, reqMsg);
RequestType.ENCOUNTER, reqMsg);
return new FutureWrapper<ByteString, EncounterResult>(api.getRequestHandler()
.sendAsyncServerRequests(serverRequest)) {
@Override
protected EncounterResult handle(ByteString result) throws RemoteServerException {
EncounterResponseOuterClass.EncounterResponse response;
EncounterResponse response;
try {
response = EncounterResponseOuterClass.EncounterResponse
response = EncounterResponse
.parseFrom(result);
} catch (InvalidProtocolBufferException e) {
throw new RemoteServerException(e);
}
encountered = response.getStatus() == EncounterResponse.Status.ENCOUNTER_SUCCESS;
return new EncounterResult(response);
return new NormalEncounterResult(response);
}
};
}
Expand All @@ -162,11 +206,42 @@ protected EncounterResult handle(ByteString result) throws RemoteServerException
* @throws LoginFailedException the login failed exception
* @throws RemoteServerException the remote server exception
*/
public EncounterResult encounterPokemon() throws LoginFailedException,
public EncounterResult encounterNormalPokemon() throws LoginFailedException,
RemoteServerException {
return encounterPokemonAsync().toBlocking();
return encounterNormalPokemonAsync().toBlocking();
}



/**
* Encounter pokemon
*
* @return the encounter result
*/
public PokemonFuture<EncounterResult> encounterDiskPokemonAsync() {
DiskEncounterMessage reqMsg = DiskEncounterMessage
.newBuilder().setEncounterId(getEncounterId())
.setPlayerLatitude(api.getLatitude())
.setPlayerLongitude(api.getLongitude())
.setFortId(getSpawnPointId()).build();
AsyncServerRequest serverRequest = new AsyncServerRequest(RequestType.DISK_ENCOUNTER, reqMsg);
return new FutureWrapper<ByteString, EncounterResult>(api.getRequestHandler()
.sendAsyncServerRequests(serverRequest)) {
@Override
protected EncounterResult handle(ByteString result) throws RemoteServerException {
DiskEncounterResponse response;
try {
response = DiskEncounterResponse.parseFrom(result);
} catch (InvalidProtocolBufferException e) {
throw new RemoteServerException(e);
}
encountered = response.getResult() == DiskEncounterResponse.Result.SUCCESS;
return new DiskEncounterResult(response);
}
};
}


/**
* Tries to catch a pokemon (will attempt to use a pokeball, if you have
* none will use greatball etc) and uwill use a single razz berry if available.
Expand Down Expand Up @@ -389,11 +464,12 @@ public PokemonFuture<CatchResult> catchPokemonAsync(double normalizedHitPosition
.setSpinModifier(spinModifier)
.setPokeball(type.getBallType()).build();
AsyncServerRequest serverRequest = new AsyncServerRequest(
RequestTypeOuterClass.RequestType.CATCH_POKEMON, reqMsg);
RequestType.CATCH_POKEMON, reqMsg);
return new FutureWrapper<ByteString, CatchResult>(api.getRequestHandler()
.sendAsyncServerRequests(serverRequest)) {
@Override
protected CatchResult handle(ByteString result) throws RemoteServerException, LoginFailedException {
System.out.println("ASYNC CATCH CALL");
CatchPokemonResponse response;

try {
Expand Down Expand Up @@ -439,7 +515,7 @@ public PokemonFuture<CatchItemResult> useItemAsync(ItemId item) {
.build();

AsyncServerRequest serverRequest = new AsyncServerRequest(
RequestTypeOuterClass.RequestType.USE_ITEM_CAPTURE, reqMsg);
RequestType.USE_ITEM_CAPTURE, reqMsg);
return new FutureWrapper<ByteString, CatchItemResult>(api.getRequestHandler()
.sendAsyncServerRequests(serverRequest)) {
@Override
Expand Down
Loading