diff --git a/configs/config.json.map.example b/configs/config.json.map.example index 5cd42485e3..dad7221fa6 100644 --- a/configs/config.json.map.example +++ b/configs/config.json.map.example @@ -148,6 +148,7 @@ "update_map": true, "mode": "priority", "map_path": "raw_data", + "walker": "StepWalker", "catch": { "==========Legendaries==========": 0, "Aerodactyl": 1000, diff --git a/pokemongo_bot/cell_workers/follow_cluster.py b/pokemongo_bot/cell_workers/follow_cluster.py index 1e227c0343..d080667784 100644 --- a/pokemongo_bot/cell_workers/follow_cluster.py +++ b/pokemongo_bot/cell_workers/follow_cluster.py @@ -1,4 +1,4 @@ -from pokemongo_bot.step_walker import StepWalker +from pokemongo_bot.walkers.step_walker import StepWalker from pokemongo_bot.cell_workers.utils import distance from pokemongo_bot.cell_workers.utils import find_biggest_cluster from pokemongo_bot.base_task import BaseTask diff --git a/pokemongo_bot/cell_workers/follow_path.py b/pokemongo_bot/cell_workers/follow_path.py index 4f98cb93fd..0d3fe30b7b 100644 --- a/pokemongo_bot/cell_workers/follow_path.py +++ b/pokemongo_bot/cell_workers/follow_path.py @@ -6,7 +6,7 @@ from pokemongo_bot.base_task import BaseTask from pokemongo_bot.cell_workers.utils import distance, i2f, format_dist from pokemongo_bot.human_behaviour import sleep -from pokemongo_bot.step_walker import StepWalker +from pokemongo_bot.walkers.step_walker import StepWalker from pgoapi.utilities import f2i diff --git a/pokemongo_bot/cell_workers/follow_spiral.py b/pokemongo_bot/cell_workers/follow_spiral.py index f956f352eb..8c9ef87a93 100644 --- a/pokemongo_bot/cell_workers/follow_spiral.py +++ b/pokemongo_bot/cell_workers/follow_spiral.py @@ -4,7 +4,7 @@ import math from pokemongo_bot.cell_workers.utils import distance, format_dist -from pokemongo_bot.step_walker import StepWalker +from pokemongo_bot.walkers.step_walker import StepWalker from pokemongo_bot.base_task import BaseTask class FollowSpiral(BaseTask): diff --git a/pokemongo_bot/cell_workers/move_to_fort.py b/pokemongo_bot/cell_workers/move_to_fort.py index bf6e90e9ce..f1f2589145 100644 --- a/pokemongo_bot/cell_workers/move_to_fort.py +++ b/pokemongo_bot/cell_workers/move_to_fort.py @@ -3,7 +3,7 @@ from pokemongo_bot import inventory from pokemongo_bot.constants import Constants -from pokemongo_bot.step_walker import StepWalker +from pokemongo_bot.walkers.step_walker import StepWalker from pokemongo_bot.worker_result import WorkerResult from pokemongo_bot.base_task import BaseTask from utils import distance, format_dist, fort_details diff --git a/pokemongo_bot/cell_workers/move_to_map_pokemon.py b/pokemongo_bot/cell_workers/move_to_map_pokemon.py index 8c275a2528..3de6d987bb 100644 --- a/pokemongo_bot/cell_workers/move_to_map_pokemon.py +++ b/pokemongo_bot/cell_workers/move_to_map_pokemon.py @@ -58,7 +58,7 @@ from pokemongo_bot import inventory from pokemongo_bot.base_dir import _base_dir from pokemongo_bot.cell_workers.utils import distance, format_dist, format_time -from pokemongo_bot.step_walker import StepWalker +from pokemongo_bot.walkers.walker_factory import walker_factory from pokemongo_bot.worker_result import WorkerResult from pokemongo_bot.base_task import BaseTask from pokemongo_bot.cell_workers.pokemon_catch_worker import PokemonCatchWorker @@ -90,10 +90,10 @@ def initialize(self): self.caught = [] self.min_ball = self.config.get('min_ball', 1) self.map_path = self.config.get('map_path', 'raw_data') + self.walker = self.config.get('walker', 'StepWalker') self.snipe_high_prio_only = self.config.get('snipe_high_prio_only', False) self.snipe_high_prio_threshold = self.config.get('snipe_high_prio_threshold', 400) - data_file = os.path.join(_base_dir, 'map-caught-{}.json'.format(self.bot.config.username)) if os.path.isfile(data_file): self.caught = json.load( @@ -365,7 +365,7 @@ def _move_to(self, pokemon): pokemon: Pokemon to move to. Returns: - StepWalker + Walker """ now = int(time.time()) self.emit_event( @@ -374,8 +374,9 @@ def _move_to(self, pokemon): '{disappears_in})'), data=self._pokemon_event_data(pokemon) ) - return StepWalker( + return walker_factory(self.walker, self.bot, pokemon['latitude'], - pokemon['longitude'] + pokemon['longitude'], + **{'parent': MoveToMapPokemon} ) diff --git a/tests/step_walker_test.py b/pokemongo_bot/test/step_walker_test.py similarity index 93% rename from tests/step_walker_test.py rename to pokemongo_bot/test/step_walker_test.py index 578a9ec8b0..b0eac07273 100644 --- a/tests/step_walker_test.py +++ b/pokemongo_bot/test/step_walker_test.py @@ -1,15 +1,15 @@ import unittest from mock import MagicMock, patch -from pokemongo_bot.step_walker import StepWalker +from pokemongo_bot.walkers.step_walker import StepWalker from pokemongo_bot.cell_workers.utils import float_equal NORMALIZED_LAT_LNG_DISTANCE_STEP = 6.3593e-6 class TestStepWalker(unittest.TestCase): def setUp(self): - self.patcherSleep = patch('pokemongo_bot.step_walker.sleep') - self.patcherRandomLat = patch('pokemongo_bot.step_walker.random_lat_long_delta', return_value=0) + self.patcherSleep = patch('pokemongo_bot.walkers.step_walker.sleep') + self.patcherRandomLat = patch('pokemongo_bot.walkers.step_walker.random_lat_long_delta', return_value=0) self.patcherSleep.start() self.patcherRandomLat.start() diff --git a/pokemongo_bot/walkers/__init__.py b/pokemongo_bot/walkers/__init__.py index c7021b6d56..e69de29bb2 100644 --- a/pokemongo_bot/walkers/__init__.py +++ b/pokemongo_bot/walkers/__init__.py @@ -1,2 +0,0 @@ -from polyline_generator import Polyline -from polyline_walker import PolylineWalker diff --git a/pokemongo_bot/walkers/polyline_generator.py b/pokemongo_bot/walkers/polyline_generator.py index ee225cb9e8..28dac8c6ac 100644 --- a/pokemongo_bot/walkers/polyline_generator.py +++ b/pokemongo_bot/walkers/polyline_generator.py @@ -6,9 +6,48 @@ import polyline import requests +class PolylineObjectHandler: + ''' + Does this need to be a class? + More like a namespace... + ''' + _cache = {} + _kill_these = set() -class Polyline(object): + @staticmethod + def cached_polyline(bot, origin, destination, speed, parent_cls): + ''' + Google API has limits, so we can't generate new Polyline at every tick... + ''' + for key in list(PolylineObjectHandler._kill_these): + PolylineObjectHandler._cache.pop(key) + PolylineObjectHandler._kill_these.remove(key) + + key = parent_cls + if key not in PolylineObjectHandler._cache: + polyline = Polyline(origin, destination, speed) + polyline.key = key + polyline.destination = destination + + PolylineObjectHandler._cache[key] = polyline + elif key in PolylineObjectHandler._cache and PolylineObjectHandler._cache[key].destination != destination: + # The case bot changes mind to catch Mew instead of following Doduo... + # Merge with upper code? Without comment, it would be quite puzzling... + polyline = Polyline(origin, destination, speed) + polyline.key = key + polyline.destination = destination + + PolylineObjectHandler._cache[key] = polyline + else: + polyline = PolylineObjectHandler._cache[key] + return polyline + @staticmethod + def delete_cache(polyline): + PolylineObjectHandler._cache.pop(polyline.key) + + +class Polyline(object): def __init__(self, origin, destination, speed): self.DISTANCE_API_URL='https://maps.googleapis.com/maps/api/directions/json?mode=walking' self.origin = origin @@ -18,12 +57,16 @@ def __init__(self, origin, destination, speed): '{},{}'.format(*self.destination)) self.request_responce = requests.get(self.URL).json() try: + # Polyline walker starts teleporting after reaching api query limit. + # throw error here atm, catch it at factory and return StepWalker + # TODO Check what is happening... self.polyline_points = [x['polyline']['points'] for x in - self.request_responce['routes'][0]['legs'][0]['steps']] + self.request_responce['routes'][0]['legs'][0]['steps']] except IndexError: self.polyline_points = self.request_responce['routes'] - self.speed = float(speed) + raise # catch at factory atm... self.points = [self.origin] + self.get_points(self.polyline_points) + [self.destination] + self.speed = float(speed) self.lat, self.long = self.points[0][0], self.points[0][1] self.polyline = self.combine_polylines(self.points) self._timestamp = time.time() diff --git a/pokemongo_bot/walkers/polyline_walker.py b/pokemongo_bot/walkers/polyline_walker.py index 687371e866..0b66efee0b 100644 --- a/pokemongo_bot/walkers/polyline_walker.py +++ b/pokemongo_bot/walkers/polyline_walker.py @@ -1,31 +1,40 @@ # -*- coding: utf-8 -*- from pokemongo_bot.human_behaviour import sleep -from pokemongo_bot.step_walker import StepWalker -from polyline_generator import Polyline - +from pokemongo_bot.walkers.step_walker import StepWalker +from polyline_generator import PolylineObjectHandler +from pokemongo_bot.cell_workers.utils import distance +from pokemongo_bot.constants import Constants class PolylineWalker(StepWalker): + ''' + Heavy multi-botting can cause issue, since the directions API has limits. + ''' - def __init__(self, bot, speed, dest_lat, dest_lng): + def __init__(self, bot, speed, dest_lat, dest_lng, parent): super(PolylineWalker, self).__init__(bot, speed, dest_lat, dest_lng) - self.polyline_walker = Polyline((self.api._position_lat, self.api._position_lng), - (self.destLat, self.destLng), self.speed) - self.bot.event_manager.emit( - 'polyline_request', - sender=self, - level='info', - formatted="{url}", - data={'url': self.polyline_walker.URL} + self.polyline_walker = PolylineObjectHandler.cached_polyline(bot, (self.api._position_lat, self.api._position_lng), + (self.destLat, self.destLng), self.speed, parent) + self.dist = distance( + self.bot.position[0], + self.bot.position[1], + dest_lat, + dest_lng ) def step(self): cLat, cLng = self.api._position_lat, self.api._position_lng - while (cLat, cLng) != self.polyline_walker.get_pos()[0]: - self.polyline_walker.unpause() - sleep(1) - self.polyline_walker.pause() - cLat, cLng = self.polyline_walker.get_pos()[0] - self.api.set_position(round(cLat, 5), round(cLng, 5), 0) - self.bot.heartbeat() - return True + + if self.dist < 10: # 10m, add config? set it at constants? + PolylineObjectHandler.delete_cache(self.polyline_walker) + return True + + self.polyline_walker.unpause() + sleep(1) + self.polyline_walker.pause() + cLat, cLng = self.polyline_walker.get_pos()[0] + _, _, alt = self.api.get_position() + self.api.set_position(cLat, cLng, alt) + self.bot.heartbeat() + return False + diff --git a/pokemongo_bot/step_walker.py b/pokemongo_bot/walkers/step_walker.py similarity index 95% rename from pokemongo_bot/step_walker.py rename to pokemongo_bot/walkers/step_walker.py index f765e3c636..1946351b8a 100644 --- a/pokemongo_bot/step_walker.py +++ b/pokemongo_bot/walkers/step_walker.py @@ -1,8 +1,8 @@ from math import sqrt from random import random -from cell_workers.utils import distance -from human_behaviour import random_lat_long_delta, sleep +from pokemongo_bot.cell_workers.utils import distance +from pokemongo_bot.human_behaviour import random_lat_long_delta, sleep class StepWalker(object): diff --git a/pokemongo_bot/walkers/walker_factory.py b/pokemongo_bot/walkers/walker_factory.py new file mode 100644 index 0000000000..2252ac1ef0 --- /dev/null +++ b/pokemongo_bot/walkers/walker_factory.py @@ -0,0 +1,15 @@ +from pokemongo_bot.walkers.polyline_walker import PolylineWalker +from pokemongo_bot.walkers.step_walker import StepWalker + +def walker_factory(name, bot, speed, dest_lat, dest_lng, *args, **kwargs): + ''' + Charlie and the Walker Factory + ''' + if 'StepWalker' == name: + ret = StepWalker(bot, speed, dest_lat, dest_lng) + elif 'PolylineWalker' == name: + try: + ret = PolylineWalker(bot, speed, dest_lat, dest_lng, *args, **kwargs) + except: + ret = StepWalker(bot, speed, dest_lat, dest_lng) + return ret