diff --git a/.gitignore b/.gitignore index a12509c322..70ab34b250 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,9 @@ var/ .pydevproject .settings/ +# Cloud9 Users +.c9/ + # Installer logs pip-log.txt pip-delete-this-directory.txt @@ -86,6 +89,8 @@ celerybeat-schedule # virtualenv venv/ ENV/ +local/ +share/ # Spyder project settings .spyderproject diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py index d0f034f110..1378e5bdb9 100644 --- a/pokemongo_bot/__init__.py +++ b/pokemongo_bot/__init__.py @@ -393,6 +393,35 @@ def _register_events(self): ) self.event_manager.register_event('unset_pokemon_nickname') + # Move To map pokemon + self.event_manager.register_event( + 'move_to_map_pokemon_fail', + parameters=('message',) + ) + self.event_manager.register_event( + 'move_to_map_pokemon_updated_map', + parameters=('lat', 'lon') + ) + self.event_manager.register_event( + 'move_to_map_pokemon_teleport_to', + parameters=('poke_name', 'poke_dist', 'poke_lat', 'poke_lon', + 'disappears_in') + ) + self.event_manager.register_event( + 'move_to_map_pokemon_encounter', + parameters=('poke_name', 'poke_dist', 'poke_lat', 'poke_lon', + 'disappears_in') + ) + self.event_manager.register_event( + 'move_to_map_pokemon_move_towards', + parameters=('poke_name', 'poke_dist', 'poke_lat', 'poke_lon', + 'disappears_in') + ) + self.event_manager.register_event( + 'move_to_map_pokemon_teleport_back', + parameters=('last_lat', 'last_lon') + ) + def tick(self): self.health_record.heartbeat() self.cell = self.get_meta_cell() diff --git a/pokemongo_bot/cell_workers/move_to_map_pokemon.py b/pokemongo_bot/cell_workers/move_to_map_pokemon.py index 08ff35f281..975a9b5a36 100644 --- a/pokemongo_bot/cell_workers/move_to_map_pokemon.py +++ b/pokemongo_bot/cell_workers/move_to_map_pokemon.py @@ -1,11 +1,59 @@ # -*- coding: utf-8 -*- +""" +Moves a trainer to a Pokemon. + +Events: + move_to_map_pokemon_fail + When the worker fails. + Returns: + message: Failure message. + + move_to_map_pokemon_updated_map + When worker updates the PokemonGo-Map. + Returns: + lat: Latitude + lon: Longitude + + move_to_map_pokemon_teleport_to + When trainer is teleported to a Pokemon. + Returns: + poke_name: Pokemon's name + poke_dist: Distance from the trainer + poke_lat: Latitude of the Pokemon + poke_lon: Longitude of the Pokemon + disappears_in: Number of seconds before the Pokemon disappears + + move_to_map_pokemon_encounter + When a trainer encounters a Pokemon by teleporting or walking. + Returns: + poke_name: Pokemon's name + poke_dist: Distance from the trainer + poke_lat: Latitude of the Pokemon + poke_lon: Longitude of the Pokemon + disappears_in: Number of seconds before the Pokemon disappears + + move_to_map_pokemon_move_towards + When a trainer moves toward a Pokemon. + Returns: + poke_name: Pokemon's name + poke_dist: Distance from the trainer + poke_lat: Latitude of the Pokemon + poke_lon: Longitude of the Pokemon + disappears_in: Number of seconds before the Pokemon disappears + + move_to_map_pokemon_teleport_back + When a trainer teleports back to thier previous location. + Returns: + last_lat: Trainer's last known latitude + last_lon: Trainer's last known longitude + +""" import os import time import json import base64 import requests -from pokemongo_bot import logger from pokemongo_bot.cell_workers.utils import distance, format_dist, format_time from pokemongo_bot.step_walker import StepWalker from pokemongo_bot.worker_result import WorkerResult @@ -13,7 +61,20 @@ from pokemongo_bot.cell_workers.pokemon_catch_worker import PokemonCatchWorker +# Update the map if more than N meters away from the center. (AND'd with +# UPDATE_MAP_MIN_TIME_MINUTES) +UPDATE_MAP_MIN_DISTANCE_METERS = 500 + +# Update the map if it hasn't been updated in n seconds. (AND'd with +# UPDATE_MAP_MIN_DISTANCE_METERS) +UPDATE_MAP_MIN_TIME_SEC = 120 + +# Number of seconds to sleep between teleporting to a snipped Pokemon. +SNIPE_SLEEP_SEC = 2 + + class MoveToMapPokemon(BaseTask): + """Task for moving a trainer to a Pokemon.""" SUPPORTED_TASK_API_VERSION = 1 def initialize(self): @@ -32,13 +93,15 @@ def get_pokemon_from_map(self): try: req = requests.get('{}/raw_data?gyms=false&scanned=false'.format(self.config['address'])) except requests.exceptions.ConnectionError: - logger.log('Could not reach PokemonGo-Map Server', 'red') + self._emit_failure('Could not get Pokemon data from PokemonGo-Map: ' + '{}. Is it running?'.format( + self.config['address'])) return [] try: raw_data = req.json() except ValueError: - logger.log('Map data was not valid', 'red') + self._emit_failure('Map data was not valid') return [] pokemon_list = [] @@ -48,7 +111,7 @@ def get_pokemon_from_map(self): try: pokemon['encounter_id'] = long(base64.b64decode(pokemon['encounter_id'])) except TypeError: - log.logger('base64 error: {}'.format(pokemon['encounter_id']), 'red') + self._emit_failure('base64 error: {}'.format(pokemon['encounter_id'])) continue pokemon['spawn_point_id'] = pokemon['spawnpoint_id'] pokemon['disappear_time'] = int(pokemon['disappear_time'] / 1000) @@ -100,14 +163,17 @@ def update_map_location(self): try: req = requests.get('{}/loc'.format(self.config['address'])) except requests.exceptions.ConnectionError: - logger.log('Could not reach PokemonGo-Map Server', 'red') + self._emit_failure('Could not update trainer location ' + 'PokemonGo-Map: {}. Is it running?'.format( + self.config['address'])) return try: loc_json = req.json() except ValueError: - return log.logger('Map location data was not valid', 'red') - + err = 'Map location data was not valid' + self._emit_failure(err) + return log.logger(err, 'red') dist = distance( self.bot.position[0], @@ -118,32 +184,38 @@ def update_map_location(self): # update map when 500m away from center and last update longer than 2 minutes away now = int(time.time()) - if dist > 500 and now - self.last_map_update > 2 * 60: - requests.post('{}/next_loc?lat={}&lon={}'.format(self.config['address'], self.bot.position[0], self.bot.position[1])) - logger.log('Updated PokemonGo-Map position') + if (dist > UPDATE_MAP_MIN_DISTANCE_METERS and + now - self.last_map_update > UPDATE_MAP_MIN_TIME_SEC): + requests.post( + '{}/next_loc?lat={}&lon={}'.format(self.config['address'], + self.bot.position[0], + self.bot.position[1])) + self.emit_event( + 'move_to_map_pokemon_updated_map', + formatted='Updated PokemonGo-Map to {lat}, {lon}', + data={ + 'lat': self.bot.position[0], + 'lon': self.bot.position[1] + } + ) self.last_map_update = now def snipe(self, pokemon): - last_position = self.bot.position[0:2] - + """Snipe a Pokemon by teleporting. + + Args: + pokemon: Pokemon to snipe. + """ self.bot.heartbeat() - - logger.log('Teleporting to {} ({})'.format(pokemon['name'], format_dist(pokemon['dist'], self.unit)), 'green') - self.bot.api.set_position(pokemon['latitude'], pokemon['longitude'], 0) - - logger.log('Encounter pokemon', 'green') + self._teleport_to(pokemon) catch_worker = PokemonCatchWorker(pokemon, self.bot) api_encounter_response = catch_worker.create_encounter_api_call() - - time.sleep(2) - logger.log('Teleporting back to previous location..', 'green') - self.bot.api.set_position(last_position[0], last_position[1], 0) - time.sleep(2) + time.sleep(SNIPE_SLEEP_SEC) + self._teleport_back() + time.sleep(SNIPE_SLEEP_SEC) self.bot.heartbeat() - catch_worker.work(api_encounter_response) self.add_caught(pokemon) - return WorkerResult.SUCCESS def dump_caught_pokemon(self): @@ -182,18 +254,111 @@ def work(self): if self.config['snipe']: return self.snipe(pokemon) + step_walker = self._move_to(pokemon) + if not step_walker.step(): + return WorkerResult.RUNNING + self._encountered(pokemon) + self.add_caught(pokemon) + return WorkerResult.SUCCESS + + def _emit_failure(self, msg): + """Emits failure to event log. + + Args: + msg: Message to emit + """ + self.emit_event( + 'move_to_map_pokemon_fail', + formatted='Failure! {message}', + data={'message': msg} + ) + + def _emit_log(self, msg): + """Emits log to event log. + + Args: + msg: Message to emit + """ + self.emit_event( + 'move_to_map_pokemon', + formatted='{message}', + data={'message': msg} + ) + + def _pokemon_event_data(self, pokemon): + """Generates parameters used for the Bot's event manager. + + Args: + pokemon: Pokemon object + + Returns: + Dictionary with Pokemon's info. + """ + now = int(time.time()) + return { + 'poke_name': pokemon['name'], + 'poke_dist': (format_dist(pokemon['dist'], self.unit)), + 'poke_lat': pokemon['latitude'], + 'poke_lon': pokemon['longitude'], + 'disappears_in': (format_time(pokemon['disappear_time'] - now)) + } + + def _teleport_to(self, pokemon): + """Teleports trainer to a Pokemon. + + Args: + pokemon: Pokemon to teleport to. + """ + self.emit_event( + 'move_to_map_pokemon_teleport_to', + formatted='Teleporting to {poke_name}. ({poke_dist})', + data=self._pokemon_event_data(pokemon) + ) + self.bot.api.set_position(pokemon['latitude'], pokemon['longitude'], 0) + self._encountered(pokemon) + + def _encountered(self, pokemon): + """Emit event when trainer encounters a Pokemon. + + Args: + pokemon: Pokemon encountered. + """ + self.emit_event( + 'move_to_map_pokemon_encounter', + formatted='Encountered Pokemon: {poke_name}', + data=self._pokemon_event_data(pokemon) + ) + + def _teleport_back(self): + """Teleports trainer back to their last position.""" + last_position = self.bot.position[0:2] + self.emit_event( + 'move_to_map_pokemon_teleport_back', + formatted=('Teleporting back to previous location ({last_lat}, ' + '{last_long})'), + data={'last_lat': last_position[0], 'last_lon': last_position[1]} + ) + self.bot.api.set_position(last_position[0], last_position[1], 0) + + def _move_to(self, pokemon): + """Moves trainer towards a Pokemon. + + Args: + pokemon: Pokemon to move to. + + Returns: + StepWalker + """ now = int(time.time()) - logger.log('Moving towards {}, {} left ({})'.format(pokemon['name'], format_dist(pokemon['dist'], self.unit), format_time(pokemon['disappear_time'] - now))) - step_walker = StepWalker( + self.emit_event( + 'move_to_map_pokemon_move_towards', + formatted=('Moving towards {poke_name}, {poke_dist}, left (' + '{disappears_in})'), + data=self._pokemon_event_data(pokemon) + ) + return StepWalker( self.bot, self.bot.config.walk, pokemon['latitude'], pokemon['longitude'] ) - - if not step_walker.step(): - return WorkerResult.RUNNING - - logger.log('Arrived at {}'.format(pokemon['name'])) - self.add_caught(pokemon) - return WorkerResult.SUCCESS diff --git a/pokemongo_bot/health_record/bot_event.py b/pokemongo_bot/health_record/bot_event.py index f357a4e8e7..55a726049d 100644 --- a/pokemongo_bot/health_record/bot_event.py +++ b/pokemongo_bot/health_record/bot_event.py @@ -16,7 +16,7 @@ def __init__(self, config): # UniversalAnalytics can be reviewed here: # https://github.com/analytics-pros/universal-analytics-python if self.config.health_record: - self.logger.info('Health check is enabled. For more logrmation:') + self.logger.info('Health check is enabled. For more information:') self.logger.info('https://github.com/PokemonGoF/PokemonGo-Bot/tree/dev#analytics') self.client = Client( dsn='https://8abac56480f34b998813d831de262514:196ae1d8dced41099f8253ea2c8fe8e6@app.getsentry.com/90254',