From cc29f2179f7e66098b34ccb76e574bb45fdcbbbe Mon Sep 17 00:00:00 2001 From: Jasperrr91 Date: Mon, 1 Aug 2016 20:44:14 +0200 Subject: [PATCH 01/16] Change egg hatching text (#2258) --- pokemongo_bot/cell_workers/incubate_eggs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pokemongo_bot/cell_workers/incubate_eggs.py b/pokemongo_bot/cell_workers/incubate_eggs.py index 9ec65c41de..b8ef560bbb 100644 --- a/pokemongo_bot/cell_workers/incubate_eggs.py +++ b/pokemongo_bot/cell_workers/incubate_eggs.py @@ -31,7 +31,7 @@ def work(self): if km_left <= 0: self._hatch_eggs() else: - logger.log('[x] Next egg incubates in {:.2f} km'.format(km_left),'yellow') + logger.log('[x] Current egg hatches in {:.2f} km'.format(km_left),'yellow') IncubateEggs.last_km_walked = self.km_walked sorting = self.longer_eggs_first From da73b3dbe08959e572853fbe13ac25744732cdab Mon Sep 17 00:00:00 2001 From: MFizz Date: Mon, 1 Aug 2016 20:55:23 +0200 Subject: [PATCH 02/16] [FIX] Improper use of exception (#2246) * adapted improper exception use * beautified * fixed logic error --- pokemongo_bot/__init__.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py index 85fd114e7f..e84b5d9ff1 100644 --- a/pokemongo_bot/__init__.py +++ b/pokemongo_bot/__init__.py @@ -402,15 +402,13 @@ def current_inventory(self): items_stock = {x.value: 0 for x in list(Item)} for item in inventory_dict: - try: - # print(item['inventory_item_data']['item']) - item_id = item['inventory_item_data']['item']['item_id'] - item_count = item['inventory_item_data']['item']['count'] + item_dict = item.get('inventory_item_data', {}).get('item', {}) + item_count = item_dict.get('count') + item_id = item_dict.get('item_id') + if item_count and item_id: if item_id in items_stock: items_stock[item_id] = item_count - except Exception: - continue return items_stock def item_inventory_count(self, id): From b04c1ccf301e16022d1683309f46c7c7d9636e2d Mon Sep 17 00:00:00 2001 From: z4ppy Date: Mon, 1 Aug 2016 23:32:07 +0200 Subject: [PATCH 03/16] Add optional simple lure attraction feature (#2257) * Add lure attraction params in default config * Update CONTRIBUTORS.md * Add simple lure attraction feature (move2fort) * Update move_to_fort.py --- CONTRIBUTORS.md | 1 + configs/config.json.example | 5 +- pokemongo_bot/cell_workers/move_to_fort.py | 63 +++++++++++++++++++++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c1b4763c6e..19ad62380a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -46,4 +46,5 @@ * kbinani * MFizz * NamPNQ + * z4ppy.bbc * matheussampaio diff --git a/configs/config.json.example b/configs/config.json.example index 3ae35099ec..3442c233d9 100644 --- a/configs/config.json.example +++ b/configs/config.json.example @@ -52,7 +52,10 @@ "type": "SpinFort" }, { - "type": "MoveToFort" + "type": "MoveToFort", + "config": { + "lure_attraction": true, + "lure_max_distance": 2000 }, { "type": "FollowSpiral" diff --git a/pokemongo_bot/cell_workers/move_to_fort.py b/pokemongo_bot/cell_workers/move_to_fort.py index dcb4c8d4fd..d5797be603 100644 --- a/pokemongo_bot/cell_workers/move_to_fort.py +++ b/pokemongo_bot/cell_workers/move_to_fort.py @@ -7,12 +7,21 @@ class MoveToFort(BaseTask): + + def initialize(self): + self.lure_distance = 0 + self.lure_attraction = self.config.get("lure_attraction", True) + self.lure_max_distance = self.config.get("lure_max_distance", 2000) + def should_run(self): has_space_for_loot = self.bot.has_space_for_loot() if not has_space_for_loot: logger.log("Not moving to any forts as there aren't enough space. You might want to change your config to recycle more items if this message appears consistently.", 'yellow') return has_space_for_loot or self.bot.softban + def is_attracted(self): + return (self.lure_distance > 0) + def work(self): if not self.should_run(): return WorkerResult.SUCCESS @@ -38,7 +47,12 @@ def work(self): ) if dist > Constants.MAX_DISTANCE_FORT_IS_REACHABLE: - logger.log('Moving towards fort {}, {} left'.format(fort_name, format_dist(dist, unit))) + if self.is_attracted() > 0: + add_str = ' (attraction of lure {})'.format(format_dist(self.lure_distance, unit)) + else: + add_str = '' + + logger.log('Moving towards fort {}, {} left{}'.format(fort_name, format_dist(dist, unit), add_str)) step_walker = StepWalker( self.bot, @@ -53,16 +67,63 @@ def work(self): logger.log('Arrived at pokestop.') return WorkerResult.SUCCESS + def _get_nearest_fort_on_lure_way(self, forts): + + if not self.lure_attraction: + return None, 0 + + lures = filter(lambda x: True if x.get('lure_info', None) != None else False, forts) + + if (len(lures)): + dist_lure_me = distance(self.bot.position[0], self.bot.position[1], + lures[0]['latitude'],lures[0]['longitude']) + else: + dist_lure_me = 0 + + if dist_lure_me > 0 and dist_lure_me < self.lure_max_distance: + + self.lure_distance = dist_lure_me + + for fort in forts: + dist_lure_fort = distance( + fort['latitude'], + fort['longitude'], + lures[0]['latitude'], + lures[0]['longitude']) + dist_fort_me = distance( + fort['latitude'], + fort['longitude'], + self.bot.position[0], + self.bot.position[1]) + + if dist_lure_fort < dist_lure_me and dist_lure_me > dist_fort_me: + return fort, dist_lure_me + + if dist_fort_me > dist_lure_me: + break + + return lures[0], dist_lure_me + + else: + return None, 0 + def get_nearest_fort(self): forts = self.bot.get_forts(order_by_distance=True) # Remove stops that are still on timeout forts = filter(lambda x: x["id"] not in self.bot.fort_timeouts, forts) + next_attracted_pts, lure_distance = self._get_nearest_fort_on_lure_way(forts) + # Remove all forts which were spun in the last ticks to avoid circles if set if self.bot.config.forts_avoid_circles: forts = filter(lambda x: x["id"] not in self.bot.recent_forts, forts) + self.lure_distance = lure_distance + + if (lure_distance > 0): + return next_attracted_pts + if len(forts) > 0: return forts[0] else: From d76dc9f6d4efce05bca39fa7fc60d63ebd871b3c Mon Sep 17 00:00:00 2001 From: Kal Date: Mon, 1 Aug 2016 18:07:08 -0400 Subject: [PATCH 04/16] Dev - Fixed the loss of fort data (updated) (#2269) * Keep fort data even if the server returns no fort data. Also replaced redundant code. * Making sure we only save fort data if the server returned multiple forts. --- CONTRIBUTORS.md | 1 + pokemongo_bot/__init__.py | 31 +++++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 19ad62380a..fc3a58a44a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -48,3 +48,4 @@ * NamPNQ * z4ppy.bbc * matheussampaio + * Abraxas000 diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py index e84b5d9ff1..811fd02245 100644 --- a/pokemongo_bot/__init__.py +++ b/pokemongo_bot/__init__.py @@ -103,12 +103,21 @@ def get_meta_cell(self): wild_pokemons += cell["wild_pokemons"] if "catchable_pokemons" in cell and len(cell["catchable_pokemons"]): catchable_pokemons += cell["catchable_pokemons"] - - return { - "forts": forts, - "wild_pokemons": wild_pokemons, - "catchable_pokemons": catchable_pokemons - } + + # If there are forts present in the cells sent from the server or we don't yet have any cell data, return all data retrieved + if len(forts) > 1 or not self.cell: + return { + "forts": forts, + "wild_pokemons": wild_pokemons, + "catchable_pokemons": catchable_pokemons + } + # If there are no forts present in the data from the server, keep our existing fort data and only update the pokemon cells. + else: + return { + "forts": self.cell["forts"], + "wild_pokemons": wild_pokemons, + "catchable_pokemons": catchable_pokemons + } def update_web_location(self, cells=[], lat=None, lng=None, alt=None): # we can call the function with no arguments and still get the position @@ -121,14 +130,8 @@ def update_web_location(self, cells=[], lat=None, lng=None, alt=None): alt = 0 if cells == []: - cellid = get_cell_ids(lat, lng) - timestamp = [0, ] * len(cellid) - response_dict = self.get_map_objects(lat, lng, timestamp, cellid) - map_objects = response_dict.get( - 'responses', {} - ).get('GET_MAP_OBJECTS', {}) - status = map_objects.get('status', None) - cells = map_objects['map_cells'] + location = self.position[0:2] + cells = self.find_close_cells(*location) # insert detail info about gym to fort for cell in cells: From eee7ba49c5c4e6bb1b3efefcf9f99a7c72a48671 Mon Sep 17 00:00:00 2001 From: Benoit St-Pierre Date: Mon, 1 Aug 2016 15:17:05 -0700 Subject: [PATCH 05/16] Update web to latest master commit (#2274) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current dev commit has an issue where it doesn’t show the number of candies. --- web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web b/web index 83463c2bcd..ca7c9e134b 160000 --- a/web +++ b/web @@ -1 +1 @@ -Subproject commit 83463c2bcd5c4360adbc41c61e6572406fec54ce +Subproject commit ca7c9e134bcfd1c7047f873fa1071d026491a0c2 From e58bf3d57c1c74d7847fdfa55b08410f48917bd0 Mon Sep 17 00:00:00 2001 From: thedewil Date: Tue, 2 Aug 2016 02:35:12 +0300 Subject: [PATCH 06/16] Add missing curly bracket (#2282) Added missing curly bracket to tasks>MoveToFort>config --- configs/config.json.example | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/config.json.example b/configs/config.json.example index 3442c233d9..3468ca7a99 100644 --- a/configs/config.json.example +++ b/configs/config.json.example @@ -56,6 +56,7 @@ "config": { "lure_attraction": true, "lure_max_distance": 2000 + } }, { "type": "FollowSpiral" From a05a6db1d7fec41f58a1148e27f5487865f73695 Mon Sep 17 00:00:00 2001 From: Simba Zhang Date: Mon, 1 Aug 2016 22:11:16 -0700 Subject: [PATCH 07/16] added param in config.json.pokemon.example. --- configs/config.json.pokemon.example | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configs/config.json.pokemon.example b/configs/config.json.pokemon.example index 4d340479c5..b1e6aa939b 100644 --- a/configs/config.json.pokemon.example +++ b/configs/config.json.pokemon.example @@ -52,7 +52,11 @@ "type": "SpinFort" }, { - "type": "MoveToFort" + "type": "MoveToFort", + "config":{ + "lure_attraction": true, + "lure_max_distance": 2000 + } }, { "type": "FollowSpiral" From 50303f81a2e6a7ad1da31558ead5ef636d3aa192 Mon Sep 17 00:00:00 2001 From: Moony22 Date: Tue, 2 Aug 2016 07:50:13 +0100 Subject: [PATCH 08/16] web submodule updated to latest commit (#2289) --- web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web b/web index ca7c9e134b..6ba5609c61 160000 --- a/web +++ b/web @@ -1 +1 @@ -Subproject commit ca7c9e134bcfd1c7047f873fa1071d026491a0c2 +Subproject commit 6ba5609c6151507b5b832a74e471b6b7b1a182c9 From cd21fdd002183cd8709e506282a378606f696a40 Mon Sep 17 00:00:00 2001 From: tstumm Date: Tue, 2 Aug 2016 09:43:05 +0200 Subject: [PATCH 09/16] Modify SpiralTask to use 70m as stepsize and diameter as step_count (#2194) * Lowered the stepsize in Spiral navigator to more accurate 70m * Moved max_steps to task configuration and changed it to diameter * Added diameter to configuration example * Bugfix * Removed max_steps from cli * Added max_steps as legacy configuration * Made step size of follow_spiral more configureable * Changed default value for diameter --- configs/config.json.example | 7 +++-- pokecli.py | 12 +------- pokemongo_bot/cell_workers/follow_spiral.py | 33 +++++++++++++++------ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/configs/config.json.example b/configs/config.json.example index 3468ca7a99..5fe25d3291 100644 --- a/configs/config.json.example +++ b/configs/config.json.example @@ -59,11 +59,14 @@ } }, { - "type": "FollowSpiral" + "type": "FollowSpiral", + "config": { + "diameter": 4, + "step_size": 70 + } } ], "map_object_cache_time": 5, - "max_steps": 5, "forts": { "avoid_circles": true, "max_circle_size": 50 diff --git a/pokecli.py b/pokecli.py index d37bc16313..e0c982f5e3 100755 --- a/pokecli.py +++ b/pokecli.py @@ -225,16 +225,6 @@ def init_config(): type=str, default=None ) - add_config( - parser, - load, - short_flag="-ms", - long_flag="--max_steps", - help= - "Set the steps around your initial location(DEFAULT 5 mean 25 cells around your location)", - type=int, - default=50 - ) add_config( parser, @@ -367,7 +357,7 @@ def task_configuration_error(flag_name): """.format(flag_name)) old_flags = ['mode', 'catch_pokemon', 'spin_forts', 'forts_spin', 'hatch_eggs', 'release_pokemon', 'softban_fix', - 'longer_eggs_first', 'evolve_speed', 'use_lucky_egg', 'item_filter', 'evolve_all', 'evolve_cp_min'] + 'longer_eggs_first', 'evolve_speed', 'use_lucky_egg', 'item_filter', 'evolve_all', 'evolve_cp_min', 'max_steps'] for flag in old_flags: if flag in load: task_configuration_error(flag) diff --git a/pokemongo_bot/cell_workers/follow_spiral.py b/pokemongo_bot/cell_workers/follow_spiral.py index a77363403d..bda348490a 100644 --- a/pokemongo_bot/cell_workers/follow_spiral.py +++ b/pokemongo_bot/cell_workers/follow_spiral.py @@ -1,24 +1,30 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals + +import math + import pokemongo_bot.logger as logger from pokemongo_bot.cell_workers.utils import distance, format_dist from pokemongo_bot.step_walker import StepWalker from pokemongo_bot.cell_workers.base_task import BaseTask - class FollowSpiral(BaseTask): def initialize(self): - self.steplimit = self.bot.config.max_steps + self.steplimit = self.config.get("diameter", 4) + self.step_size = self.config.get("step_size", 70) self.origin_lat = self.bot.position[0] self.origin_lon = self.bot.position[1] + self.diameter_to_steps = (self.steplimit+1) ** 2 self.points = self._generate_spiral( - self.origin_lat, self.origin_lon, 0.0018, self.steplimit + self.origin_lat, self.origin_lon, self.step_size, self.diameter_to_steps ) + self.ptr = 0 self.direction = 1 self.cnt = 0 + @staticmethod def _generate_spiral(starting_lat, starting_lng, step_size, step_limit): """ @@ -34,18 +40,24 @@ def _generate_spiral(starting_lat, starting_lng, step_size, step_limit): coords = [{'lat': starting_lat, 'lng': starting_lng}] steps, x, y, d, m = 1, 0, 0, 1, 1 + rlat = starting_lat * math.pi + latdeg = 111132.93 - 559.82 * math.cos(2*rlat) + 1.175*math.cos(4*rlat) + lngdeg = 111412.84 * math.cos(rlat) - 93.5 * math.cos(3*rlat) + step_size_lat = step_size / latdeg + step_size_lng = step_size / lngdeg + while steps < step_limit: while 2 * x * d < m and steps < step_limit: x = x + d steps += 1 - lat = x * step_size + starting_lat - lng = y * step_size + starting_lng + lat = x * step_size_lat + starting_lat + lng = y * step_size_lng + starting_lng coords.append({'lat': lat, 'lng': lng}) while 2 * y * d < m and steps < step_limit: y = y + d steps += 1 - lat = x * step_size + starting_lat - lng = y * step_size + starting_lng + lat = x * step_size_lat + starting_lat + lng = y * step_size_lng + starting_lng coords.append({'lat': lat, 'lng': lng}) d *= -1 @@ -88,9 +100,12 @@ def work(self): point['lat'], point['lng'] ) <= 1 or (self.bot.config.walk > 0 and step_walker == None): - if self.ptr + self.direction == len(self.points) or self.ptr + self.direction == -1: + if self.ptr + self.direction >= len(self.points) or self.ptr + self.direction <= -1: self.direction *= -1 - self.ptr += self.direction + if len(self.points) != 1: + self.ptr += self.direction + else: + self.ptr = 0 self.cnt = 0 return [point['lat'], point['lng']] From 5927c3b8a900ff79ce72fb8447c6c75dbb8ea858 Mon Sep 17 00:00:00 2001 From: Simba Zhang Date: Tue, 2 Aug 2016 02:06:47 -0700 Subject: [PATCH 10/16] This is just a temp fix, The one added the configure param need make sure it's really work. --- pokemongo_bot/cell_workers/move_to_fort.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pokemongo_bot/cell_workers/move_to_fort.py b/pokemongo_bot/cell_workers/move_to_fort.py index d5797be603..2313cc504d 100644 --- a/pokemongo_bot/cell_workers/move_to_fort.py +++ b/pokemongo_bot/cell_workers/move_to_fort.py @@ -10,8 +10,8 @@ class MoveToFort(BaseTask): def initialize(self): self.lure_distance = 0 - self.lure_attraction = self.config.get("lure_attraction", True) - self.lure_max_distance = self.config.get("lure_max_distance", 2000) + self.lure_attraction = True #self.config.get("lure_attraction", True) + self.lure_max_distance = 2000 #self.config.get("lure_max_distance", 2000) def should_run(self): has_space_for_loot = self.bot.has_space_for_loot() From 550b2c3c357ce2f40aade8e63c3efda9beae6ab7 Mon Sep 17 00:00:00 2001 From: JSchwerberg Date: Tue, 2 Aug 2016 10:48:03 -0700 Subject: [PATCH 11/16] Fix instance where evolve_all is unicode - fixes #2281 (#2305) * Fix instance where evolve_all is unicode * Test for isinstance basestring rather than Unicode || str --- pokemongo_bot/cell_workers/evolve_all.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pokemongo_bot/cell_workers/evolve_all.py b/pokemongo_bot/cell_workers/evolve_all.py index 7a7a19e020..38a3a32d13 100644 --- a/pokemongo_bot/cell_workers/evolve_all.py +++ b/pokemongo_bot/cell_workers/evolve_all.py @@ -9,9 +9,10 @@ def initialize(self): self.evolve_speed = self.config.get('evolve_speed', 3.7) self.evolve_cp_min = self.config.get('evolve_cp_min', 300) self.use_lucky_egg = self.config.get('use_lucky_egg', False) + self._validate_config() def _validate_config(self): - if isinstance(self.evolve_all, str): + if isinstance(self.evolve_all, basestring): self.evolve_all = [str(pokemon_name) for pokemon_name in self.evolve_all.split(',')] def work(self): From ea42eac14786b9ccd4e03d25815332790b068762 Mon Sep 17 00:00:00 2001 From: MFizz Date: Tue, 2 Aug 2016 19:50:08 +0200 Subject: [PATCH 12/16] [Feature] added keep pokemon for batch evolution (#2255) * added keep_for_evo * accounted for non evolable pokemon * additional logging * additional logging * moved get_candies to utils * disregard 2nd stage evolution pokemon * added sample configs --- configs/config.json.cluster.example | 5 + configs/config.json.example | 5 + configs/config.json.path.example | 5 + .../cell_workers/transfer_pokemon.py | 105 ++++++++++++------ pokemongo_bot/cell_workers/utils.py | 11 ++ 5 files changed, 98 insertions(+), 33 deletions(-) diff --git a/configs/config.json.cluster.example b/configs/config.json.cluster.example index a1df5cdedc..1bd6b6242f 100644 --- a/configs/config.json.cluster.example +++ b/configs/config.json.cluster.example @@ -94,6 +94,11 @@ "// any": {"keep_best_iv": 3}, "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {}, "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3} + "// Example of keeping as many Zubat as you have candy to evolve, + "// Zubat": {"keep_for_evo": true} + "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat + as you have candy to evolve:": {}, + "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true} }, "vips" : { "Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {}, diff --git a/configs/config.json.example b/configs/config.json.example index 5fe25d3291..8020f38a0c 100644 --- a/configs/config.json.example +++ b/configs/config.json.example @@ -101,6 +101,11 @@ "// any": {"keep_best_iv": 3}, "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {}, "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3} + "// Example of keeping as many Zubat as you have candy to evolve, + "// Zubat": {"keep_for_evo": true} + "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat + as you have candy to evolve:": {}, + "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true} }, "vips" : { "Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {}, diff --git a/configs/config.json.path.example b/configs/config.json.path.example index 0857e77fc9..52f2daacc9 100644 --- a/configs/config.json.path.example +++ b/configs/config.json.path.example @@ -82,6 +82,11 @@ "any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or"}, "// Example of always catching Rattata:": {}, "// Rattata": { "always_catch" : true } + "// Example of keeping as many Zubat as you have candy to evolve, + "// Zubat": {"keep_for_evo": true} + "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat + as you have candy to evolve:": {}, + "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true} }, "release": { "any": {"release_below_cp": 0, "release_below_iv": 0, "logic": "or"}, diff --git a/pokemongo_bot/cell_workers/transfer_pokemon.py b/pokemongo_bot/cell_workers/transfer_pokemon.py index 3cf40413f5..360d2a27d9 100644 --- a/pokemongo_bot/cell_workers/transfer_pokemon.py +++ b/pokemongo_bot/cell_workers/transfer_pokemon.py @@ -3,16 +3,20 @@ from pokemongo_bot import logger from pokemongo_bot.human_behaviour import action_delay from pokemongo_bot.cell_workers.base_task import BaseTask +from pokemongo_bot.cell_workers.utils import get_candies + class TransferPokemon(BaseTask): def work(self): pokemon_groups = self._release_pokemon_get_groups() + candies = get_candies(self.bot) + evolvable = 0 for pokemon_id in pokemon_groups: group = pokemon_groups[pokemon_id] if len(group) > 0: pokemon_name = self.bot.pokemon_list[pokemon_id - 1]['Name'] - keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name) + keep_best, keep_best_cp, keep_best_iv, keep_for_evo = self._validate_keep_best_config(pokemon_name) if keep_best: best_pokemon_ids = set() @@ -33,41 +37,74 @@ def work(self): order_criteria = 'iv' # remove best pokemons from all pokemons array - all_pokemons = group - best_pokemons = [] + best_pokemon = [] for best_pokemon_id in best_pokemon_ids: - for pokemon in all_pokemons: + for pokemon in group: if best_pokemon_id == pokemon['pokemon_data']['id']: - all_pokemons.remove(pokemon) - best_pokemons.append(pokemon) - - transfer_pokemons = [pokemon for pokemon in all_pokemons - if self.should_release_pokemon(pokemon_name, - pokemon['cp'], - pokemon['iv'], - True)] + group.remove(pokemon) + best_pokemon.append(pokemon) - if transfer_pokemons: - logger.log("Keep {} best {}, based on {}".format(len(best_pokemons), + if len(best_pokemon) > 0: + logger.log("Keep {} best {}, based on {}".format(len(best_pokemon), pokemon_name, order_criteria), "green") - for best_pokemon in best_pokemons: + for best_pokemon in best_pokemon: logger.log("{} [CP {}] [Potential {}]".format(pokemon_name, best_pokemon['cp'], best_pokemon['iv']), 'green') - logger.log("Transferring {} pokemon".format(len(transfer_pokemons)), "green") + high_pokemon = [] + for pokemon in group: + if self.should_release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv']): + group.remove(pokemon) + high_pokemon.append(pokemon) + if len(high_pokemon) > 0: + logger.log("Keep {} {}, based on cp/iv criteria".format(len(high_pokemon), + pokemon_name), "green") + for high_pokemon in high_pokemon: + logger.log("{} [CP {}] [Potential {}]".format(pokemon_name, + high_pokemon['cp'], + high_pokemon['iv']), 'green') + + if keep_for_evo and len(group) > 0: + if 'Previous evolution(s)' in self.bot.pokemon_list[pokemon_id - 1]: + logger.log( + '{} has previous evolution stages. This focuses on 1st stage because they use less ' + 'candy'.format(pokemon_name), 'red') + continue + + if candies == {}: + logger.log("Api call for candies failed, try again") + return + candy = candies[pokemon_id] + if 'Next Evolution Requirements' in self.bot.pokemon_list[pokemon_id - 1]: + req_candy = self.bot.pokemon_list[pokemon_id - 1]['Next Evolution Requirements']['Amount'] + num_keep = (len(group) + candy) / (req_candy + 1) + + if len(group) > num_keep: + group.sort(key=lambda x: x['iv'], reverse=True) + evo_pokemon = group[:num_keep] + group = group[num_keep:] + else: + evo_pokemon = group + group = [] + + evolvable += len(evo_pokemon) + if len(evo_pokemon) > 0: + logger.log("Keep {} {}, for evolution - {} candies".format(len(evo_pokemon), + pokemon_name, candy), "green") + for evo_pokemon in evo_pokemon: + logger.log("{} [CP {}] [Potential {}]".format(pokemon_name, + evo_pokemon['cp'], + evo_pokemon['iv']), 'green') + + logger.log("Transferring {} {}".format(len(group), pokemon_name), "green") - for pokemon in transfer_pokemons: - self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id']) - else: - group = sorted(group, key=lambda x: x['cp'], reverse=True) - for item in group: - pokemon_cp = item['cp'] - pokemon_potential = item['iv'] + for pokemon in group: + self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id']) - if self.should_release_pokemon(pokemon_name, pokemon_cp, pokemon_potential): - self.release_pokemon(pokemon_name, item['cp'], item['iv'], item['pokemon_data']['id']) + logger.log("{} pokemon transferred total. {} evolutions ready (based on pokemons additional to the ones kept" + " with cp/iv criteria)".format(len(group), evolvable), "green") def _release_pokemon_get_groups(self): pokemon_groups = {} @@ -126,15 +163,16 @@ def get_pokemon_potential(self, pokemon_data): continue return round((total_iv / 45.0), 2) - def should_release_pokemon(self, pokemon_name, cp, iv, keep_best_mode = False): + def should_release_pokemon(self, pokemon_name, cp, iv): release_config = self._get_release_config_for(pokemon_name) - if (keep_best_mode - and not release_config.has_key('never_release') - and not release_config.has_key('always_release') - and not release_config.has_key('release_below_cp') - and not release_config.has_key('release_below_iv')): - return True + release_strings = ['never_release', 'always_release', 'release_below_cp', 'release_below_iv'] + keep_strings = ['keep_best_cp', 'keep_best_iv'] + if not any(x in release_config for x in release_strings): + if any(x in release_config for x in keep_strings): + return True + else: + return False cp_iv_logic = release_config.get('logic') if not cp_iv_logic: @@ -201,6 +239,7 @@ def _validate_keep_best_config(self, pokemon_name): keep_best_cp = release_config.get('keep_best_cp', 0) keep_best_iv = release_config.get('keep_best_iv', 0) + keep_for_evo = release_config.get('keep_for_evo', False) if keep_best_cp or keep_best_iv: keep_best = True @@ -221,4 +260,4 @@ def _validate_keep_best_config(self, pokemon_name): if keep_best_cp == 0 and keep_best_iv == 0: keep_best = False - return keep_best, keep_best_cp, keep_best_iv + return keep_best, keep_best_cp, keep_best_iv, keep_for_evo diff --git a/pokemongo_bot/cell_workers/utils.py b/pokemongo_bot/cell_workers/utils.py index 253083bc0b..931570dffe 100644 --- a/pokemongo_bot/cell_workers/utils.py +++ b/pokemongo_bot/cell_workers/utils.py @@ -234,3 +234,14 @@ def find_biggest_cluster(radius, points, order=None): return {'latitude': best_coord[0], 'longitude': best_coord[1], 'num_points': len(max_clique)} else: return None + + +def get_candies(bot): + response_dict = bot.get_inventory() + inv = response_dict.get("responses", {}).get("GET_INVENTORY", {}).get("inventory_delta").get("inventory_items") + candies = {} + for item in inv: + candy = item.get("inventory_item_data", {}).get("candy", {}) + if candy != {}: + candies[candy['family_id']] = candy['candy'] + return candies From fbda65e3f063b23b5eddee87f6b3338e66710a8b Mon Sep 17 00:00:00 2001 From: Alejandro Date: Tue, 2 Aug 2016 19:50:59 +0200 Subject: [PATCH 13/16] Supporting sending requests through an HTTP proxy (#2358) * Added proxy support Added proxy support from config.json and command line. with parameters: -prxip | --proxy_ip or proxy_ip from config.json for ipv4 format as string "aaa.bbb.ccc.ddd" -prxp| --proxy_port or proxy_por from config.json as int from 1 to 65536. * Added proxy support Added two additional parameters (proxy_ip and proxy_port) to add support for proxy. proxy_ip must be as string of ipv4 format: "aaa.bbb.ccc.ddd" , proxy_port must be a int from 1 to 65536, if proxy_ip is null or set to "" and proxy port is null or set to 0 proxy will be ignored and not used. * Moved proxy function to a method. Moved proxy function to a method. * Changed the name of method Changed from set_proxy_if_exists to setup_proxy --- configs/config.json.example | 2 ++ pokecli.py | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/configs/config.json.example b/configs/config.json.example index 8020f38a0c..64c559cb7e 100644 --- a/configs/config.json.example +++ b/configs/config.json.example @@ -4,6 +4,8 @@ "password": "YOUR_PASSWORD", "location": "SOME_LOCATION", "gmapkey": "GOOGLE_MAPS_API_KEY", + "proxy_ip": "" , + "proxy_port": 0, "tasks": [ { "type": "HandleSoftBan" diff --git a/pokecli.py b/pokecli.py index e0c982f5e3..0281d938b4 100755 --- a/pokecli.py +++ b/pokecli.py @@ -322,6 +322,26 @@ def init_config(): type=float, default=5.0 ) + add_config( + parser, + load, + short_flag="-prxip", + long_flag="--proxy_ip", + help="Proxy (https and http)", + required=required("proxy_ip"), + type=str, + default=None + ) + add_config( + parser, + load, + short_flag="-prxp", + long_flag="--proxy_port", + help="Proxy port", + required=required("proxy_port"), + type=int, + default=None + ) # Start to parse other attrs config = parser.parse_args() @@ -329,7 +349,9 @@ def init_config(): config.username = raw_input("Username: ") if not config.password and 'password' not in load: config.password = getpass("Password: ") - + + setup_proxy(config) + config.catch = load.get('catch', {}) config.release = load.get('release', {}) config.action_wait_max = load.get('action_wait_max', 4) @@ -401,6 +423,12 @@ def task_configuration_error(flag_name): fix_nested_config(config) return config +def setup_proxy(config): + if config.proxy_ip and len(config.proxy_ip)>0 and config.proxy_ip.count('.') == 3 and all(0<=int(num)<256 for num in config.proxy_ip.rstrip().split('.')): + if config.proxy_port and int(config.proxy_port )<65536 and int(config.proxy_port )>1: + os.environ['http_proxy']="http://"+config.proxy_ip+":"+str(config.proxy_port)+"/" + os.environ['https_proxy']="http://"+config.proxy_ip+":"+str(config.proxy_port)+"/" + def add_config(parser, json_config, short_flag=None, long_flag=None, **kwargs): if not long_flag: raise Exception('add_config calls requires long_flag parameter!') From d5622898c0817c7f4913e1cec6076a687e4acf16 Mon Sep 17 00:00:00 2001 From: Eli White Date: Tue, 2 Aug 2016 11:12:36 -0700 Subject: [PATCH 14/16] Revert "Dev Proxy support" (#2374) --- configs/config.json.example | 2 -- pokecli.py | 30 +----------------------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/configs/config.json.example b/configs/config.json.example index 64c559cb7e..8020f38a0c 100644 --- a/configs/config.json.example +++ b/configs/config.json.example @@ -4,8 +4,6 @@ "password": "YOUR_PASSWORD", "location": "SOME_LOCATION", "gmapkey": "GOOGLE_MAPS_API_KEY", - "proxy_ip": "" , - "proxy_port": 0, "tasks": [ { "type": "HandleSoftBan" diff --git a/pokecli.py b/pokecli.py index 0281d938b4..e0c982f5e3 100755 --- a/pokecli.py +++ b/pokecli.py @@ -322,26 +322,6 @@ def init_config(): type=float, default=5.0 ) - add_config( - parser, - load, - short_flag="-prxip", - long_flag="--proxy_ip", - help="Proxy (https and http)", - required=required("proxy_ip"), - type=str, - default=None - ) - add_config( - parser, - load, - short_flag="-prxp", - long_flag="--proxy_port", - help="Proxy port", - required=required("proxy_port"), - type=int, - default=None - ) # Start to parse other attrs config = parser.parse_args() @@ -349,9 +329,7 @@ def init_config(): config.username = raw_input("Username: ") if not config.password and 'password' not in load: config.password = getpass("Password: ") - - setup_proxy(config) - + config.catch = load.get('catch', {}) config.release = load.get('release', {}) config.action_wait_max = load.get('action_wait_max', 4) @@ -423,12 +401,6 @@ def task_configuration_error(flag_name): fix_nested_config(config) return config -def setup_proxy(config): - if config.proxy_ip and len(config.proxy_ip)>0 and config.proxy_ip.count('.') == 3 and all(0<=int(num)<256 for num in config.proxy_ip.rstrip().split('.')): - if config.proxy_port and int(config.proxy_port )<65536 and int(config.proxy_port )>1: - os.environ['http_proxy']="http://"+config.proxy_ip+":"+str(config.proxy_port)+"/" - os.environ['https_proxy']="http://"+config.proxy_ip+":"+str(config.proxy_port)+"/" - def add_config(parser, json_config, short_flag=None, long_flag=None, **kwargs): if not long_flag: raise Exception('add_config calls requires long_flag parameter!') From 9b1fdefb03d4ab0752cc2d626a4a52260ee8d4f0 Mon Sep 17 00:00:00 2001 From: Douglas Camata Date: Tue, 2 Aug 2016 20:30:33 +0200 Subject: [PATCH 15/16] Revert "[Feature] added keep pokemon for batch evolution" (#2380) --- configs/config.json.cluster.example | 5 - configs/config.json.example | 5 - configs/config.json.path.example | 5 - .../cell_workers/transfer_pokemon.py | 105 ++++++------------ pokemongo_bot/cell_workers/utils.py | 11 -- 5 files changed, 33 insertions(+), 98 deletions(-) diff --git a/configs/config.json.cluster.example b/configs/config.json.cluster.example index 1bd6b6242f..a1df5cdedc 100644 --- a/configs/config.json.cluster.example +++ b/configs/config.json.cluster.example @@ -94,11 +94,6 @@ "// any": {"keep_best_iv": 3}, "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {}, "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3} - "// Example of keeping as many Zubat as you have candy to evolve, - "// Zubat": {"keep_for_evo": true} - "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat - as you have candy to evolve:": {}, - "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true} }, "vips" : { "Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {}, diff --git a/configs/config.json.example b/configs/config.json.example index 8020f38a0c..5fe25d3291 100644 --- a/configs/config.json.example +++ b/configs/config.json.example @@ -101,11 +101,6 @@ "// any": {"keep_best_iv": 3}, "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {}, "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3} - "// Example of keeping as many Zubat as you have candy to evolve, - "// Zubat": {"keep_for_evo": true} - "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat - as you have candy to evolve:": {}, - "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true} }, "vips" : { "Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {}, diff --git a/configs/config.json.path.example b/configs/config.json.path.example index 52f2daacc9..0857e77fc9 100644 --- a/configs/config.json.path.example +++ b/configs/config.json.path.example @@ -82,11 +82,6 @@ "any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or"}, "// Example of always catching Rattata:": {}, "// Rattata": { "always_catch" : true } - "// Example of keeping as many Zubat as you have candy to evolve, - "// Zubat": {"keep_for_evo": true} - "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat - as you have candy to evolve:": {}, - "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true} }, "release": { "any": {"release_below_cp": 0, "release_below_iv": 0, "logic": "or"}, diff --git a/pokemongo_bot/cell_workers/transfer_pokemon.py b/pokemongo_bot/cell_workers/transfer_pokemon.py index 360d2a27d9..3cf40413f5 100644 --- a/pokemongo_bot/cell_workers/transfer_pokemon.py +++ b/pokemongo_bot/cell_workers/transfer_pokemon.py @@ -3,20 +3,16 @@ from pokemongo_bot import logger from pokemongo_bot.human_behaviour import action_delay from pokemongo_bot.cell_workers.base_task import BaseTask -from pokemongo_bot.cell_workers.utils import get_candies - class TransferPokemon(BaseTask): def work(self): pokemon_groups = self._release_pokemon_get_groups() - candies = get_candies(self.bot) - evolvable = 0 for pokemon_id in pokemon_groups: group = pokemon_groups[pokemon_id] if len(group) > 0: pokemon_name = self.bot.pokemon_list[pokemon_id - 1]['Name'] - keep_best, keep_best_cp, keep_best_iv, keep_for_evo = self._validate_keep_best_config(pokemon_name) + keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name) if keep_best: best_pokemon_ids = set() @@ -37,74 +33,41 @@ def work(self): order_criteria = 'iv' # remove best pokemons from all pokemons array - best_pokemon = [] + all_pokemons = group + best_pokemons = [] for best_pokemon_id in best_pokemon_ids: - for pokemon in group: + for pokemon in all_pokemons: if best_pokemon_id == pokemon['pokemon_data']['id']: - group.remove(pokemon) - best_pokemon.append(pokemon) + all_pokemons.remove(pokemon) + best_pokemons.append(pokemon) + + transfer_pokemons = [pokemon for pokemon in all_pokemons + if self.should_release_pokemon(pokemon_name, + pokemon['cp'], + pokemon['iv'], + True)] - if len(best_pokemon) > 0: - logger.log("Keep {} best {}, based on {}".format(len(best_pokemon), + if transfer_pokemons: + logger.log("Keep {} best {}, based on {}".format(len(best_pokemons), pokemon_name, order_criteria), "green") - for best_pokemon in best_pokemon: + for best_pokemon in best_pokemons: logger.log("{} [CP {}] [Potential {}]".format(pokemon_name, best_pokemon['cp'], best_pokemon['iv']), 'green') - high_pokemon = [] - for pokemon in group: - if self.should_release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv']): - group.remove(pokemon) - high_pokemon.append(pokemon) - if len(high_pokemon) > 0: - logger.log("Keep {} {}, based on cp/iv criteria".format(len(high_pokemon), - pokemon_name), "green") - for high_pokemon in high_pokemon: - logger.log("{} [CP {}] [Potential {}]".format(pokemon_name, - high_pokemon['cp'], - high_pokemon['iv']), 'green') - - if keep_for_evo and len(group) > 0: - if 'Previous evolution(s)' in self.bot.pokemon_list[pokemon_id - 1]: - logger.log( - '{} has previous evolution stages. This focuses on 1st stage because they use less ' - 'candy'.format(pokemon_name), 'red') - continue - - if candies == {}: - logger.log("Api call for candies failed, try again") - return - candy = candies[pokemon_id] - if 'Next Evolution Requirements' in self.bot.pokemon_list[pokemon_id - 1]: - req_candy = self.bot.pokemon_list[pokemon_id - 1]['Next Evolution Requirements']['Amount'] - num_keep = (len(group) + candy) / (req_candy + 1) - - if len(group) > num_keep: - group.sort(key=lambda x: x['iv'], reverse=True) - evo_pokemon = group[:num_keep] - group = group[num_keep:] - else: - evo_pokemon = group - group = [] - - evolvable += len(evo_pokemon) - if len(evo_pokemon) > 0: - logger.log("Keep {} {}, for evolution - {} candies".format(len(evo_pokemon), - pokemon_name, candy), "green") - for evo_pokemon in evo_pokemon: - logger.log("{} [CP {}] [Potential {}]".format(pokemon_name, - evo_pokemon['cp'], - evo_pokemon['iv']), 'green') - - logger.log("Transferring {} {}".format(len(group), pokemon_name), "green") + logger.log("Transferring {} pokemon".format(len(transfer_pokemons)), "green") - for pokemon in group: - self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id']) + for pokemon in transfer_pokemons: + self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id']) + else: + group = sorted(group, key=lambda x: x['cp'], reverse=True) + for item in group: + pokemon_cp = item['cp'] + pokemon_potential = item['iv'] - logger.log("{} pokemon transferred total. {} evolutions ready (based on pokemons additional to the ones kept" - " with cp/iv criteria)".format(len(group), evolvable), "green") + if self.should_release_pokemon(pokemon_name, pokemon_cp, pokemon_potential): + self.release_pokemon(pokemon_name, item['cp'], item['iv'], item['pokemon_data']['id']) def _release_pokemon_get_groups(self): pokemon_groups = {} @@ -163,16 +126,15 @@ def get_pokemon_potential(self, pokemon_data): continue return round((total_iv / 45.0), 2) - def should_release_pokemon(self, pokemon_name, cp, iv): + def should_release_pokemon(self, pokemon_name, cp, iv, keep_best_mode = False): release_config = self._get_release_config_for(pokemon_name) - release_strings = ['never_release', 'always_release', 'release_below_cp', 'release_below_iv'] - keep_strings = ['keep_best_cp', 'keep_best_iv'] - if not any(x in release_config for x in release_strings): - if any(x in release_config for x in keep_strings): - return True - else: - return False + if (keep_best_mode + and not release_config.has_key('never_release') + and not release_config.has_key('always_release') + and not release_config.has_key('release_below_cp') + and not release_config.has_key('release_below_iv')): + return True cp_iv_logic = release_config.get('logic') if not cp_iv_logic: @@ -239,7 +201,6 @@ def _validate_keep_best_config(self, pokemon_name): keep_best_cp = release_config.get('keep_best_cp', 0) keep_best_iv = release_config.get('keep_best_iv', 0) - keep_for_evo = release_config.get('keep_for_evo', False) if keep_best_cp or keep_best_iv: keep_best = True @@ -260,4 +221,4 @@ def _validate_keep_best_config(self, pokemon_name): if keep_best_cp == 0 and keep_best_iv == 0: keep_best = False - return keep_best, keep_best_cp, keep_best_iv, keep_for_evo + return keep_best, keep_best_cp, keep_best_iv diff --git a/pokemongo_bot/cell_workers/utils.py b/pokemongo_bot/cell_workers/utils.py index 931570dffe..253083bc0b 100644 --- a/pokemongo_bot/cell_workers/utils.py +++ b/pokemongo_bot/cell_workers/utils.py @@ -234,14 +234,3 @@ def find_biggest_cluster(radius, points, order=None): return {'latitude': best_coord[0], 'longitude': best_coord[1], 'num_points': len(max_clique)} else: return None - - -def get_candies(bot): - response_dict = bot.get_inventory() - inv = response_dict.get("responses", {}).get("GET_INVENTORY", {}).get("inventory_delta").get("inventory_items") - candies = {} - for item in inv: - candy = item.get("inventory_item_data", {}).get("candy", {}) - if candy != {}: - candies[candy['family_id']] = candy['candy'] - return candies From bdf2e7d9cc0b2fa5fb04bb9dc4f9f09f967cd9ea Mon Sep 17 00:00:00 2001 From: Benjamin G Date: Tue, 2 Aug 2016 21:23:42 +0200 Subject: [PATCH 16/16] Adapt code to new PGoApi Code (#2357) * wip: fixing imports and tests * tests are passing * add tests, and modify calls to api accordingly * fix login bug * fix rebase * fix import error * Handle ThrottlingException * fix relogging errors --- pokemongo_bot/__init__.py | 44 +++---- pokemongo_bot/api_wrapper.py | 108 +++++++++++------ .../cell_workers/collect_level_up_reward.py | 3 +- pokemongo_bot/cell_workers/evolve_all.py | 6 +- pokemongo_bot/cell_workers/handle_soft_ban.py | 1 - pokemongo_bot/cell_workers/incubate_eggs.py | 9 +- .../cell_workers/nickname_pokemon.py | 13 +-- .../cell_workers/pokemon_catch_worker.py | 62 ++++++---- pokemongo_bot/cell_workers/recycle_items.py | 8 +- pokemongo_bot/cell_workers/spin_fort.py | 13 ++- .../cell_workers/transfer_pokemon.py | 9 +- pokemongo_bot/cell_workers/utils.py | 6 +- pokemongo_bot/metrics.py | 7 +- requirements.txt | 2 +- tests/__init__.py | 18 +-- tests/api_wrapper_test.py | 110 +++++++++++------- 16 files changed, 242 insertions(+), 177 deletions(-) diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py index 811fd02245..4c21f87493 100644 --- a/pokemongo_bot/__init__.py +++ b/pokemongo_bot/__init__.py @@ -32,6 +32,10 @@ class PokemonGoBot(object): def position(self): return self.api._position_lat, self.api._position_lng, 0 + @position.setter + def position(self, position_tuple): + self.api._position_lat, self.api._position_lng, self.api._position_alt = position_tuple + def __init__(self, config): self.config = config self.fort_timeouts = dict() @@ -103,7 +107,7 @@ def get_meta_cell(self): wild_pokemons += cell["wild_pokemons"] if "catchable_pokemons" in cell and len(cell["catchable_pokemons"]): catchable_pokemons += cell["catchable_pokemons"] - + # If there are forts present in the cells sent from the server or we don't yet have any cell data, return all data retrieved if len(forts) > 1 or not self.cell: return { @@ -138,14 +142,13 @@ def update_web_location(self, cells=[], lat=None, lng=None, alt=None): if 'forts' in cell: for fort in cell['forts']: if fort.get('type') != 1: - self.api.get_gym_details( + response_gym_details = self.api.get_gym_details( gym_id=fort.get('id'), player_latitude=lng, player_longitude=lat, gym_latitude=fort.get('latitude'), gym_longitude=fort.get('longitude') ) - response_gym_details = self.api.call() fort['gym_details'] = response_gym_details.get( 'responses', {} ).get('GET_GYM_DETAILS', None) @@ -239,6 +242,9 @@ def check_session(self, position): if remaining_time < 60: logger.log("Session stale, re-logging in", 'yellow') + position = self.position + self.api = ApiWrapper() + self.position = position self.login() @staticmethod @@ -251,13 +257,13 @@ def is_numeric(s): def login(self): logger.log('Attempting login to Pokemon Go.', 'white') - self.api.reset_auth() lat, lng = self.position[0:2] self.api.set_position(lat, lng, 0) - while not self.api.login(self.config.auth_service, - str(self.config.username), - str(self.config.password)): + while not self.api.login( + self.config.auth_service, + str(self.config.username), + str(self.config.password)): logger.log('[X] Login Error, server busy', 'red') logger.log('[X] Waiting 10 seconds to try again', 'red') @@ -267,7 +273,7 @@ def login(self): def _setup_api(self): # instantiate pgoapi - self.api = ApiWrapper(PGoApi()) + self.api = ApiWrapper() # provide player position on the earth self._set_starting_position() @@ -286,8 +292,7 @@ def _setup_api(self): def _print_character_info(self): # get player profile call # ---------------------- - self.api.get_player() - response_dict = self.api.call() + response_dict = self.api.get_player() # print('Response dictionary: \n\r{}'.format(json.dumps(response_dict, indent=2))) currency_1 = "0" currency_2 = "0" @@ -368,15 +373,11 @@ def _print_character_info(self): logger.log('') def use_lucky_egg(self): - self.api.use_item_xp_boost(item_id=301) - inventory_req = self.api.call() - return inventory_req + return self.api.use_item_xp_boost(item_id=301) def get_inventory(self): if self.latest_inventory is None: - self.api.get_inventory() - response = self.api.call() - self.latest_inventory = response + self.latest_inventory = self.api.get_inventory() return self.latest_inventory def update_inventory(self): @@ -538,9 +539,10 @@ def heartbeat(self): self.fort_timeouts = {id: timeout for id, timeout in self.fort_timeouts.iteritems() if timeout >= time.time() * 1000} - self.api.get_player() - self.api.check_awarded_badges() - self.api.call() + request = self.api.create_request() + request.get_player() + request.check_awarded_badges() + request.call() self.update_web_location() # updates every tick def get_inventory_count(self, what): @@ -620,14 +622,12 @@ def get_map_objects(self, lat, lng, timestamp, cellid): if time.time() - self.last_time_map_object < self.config.map_object_cache_time: return self.last_map_object - self.api.get_map_objects( + self.last_map_object = self.api.get_map_objects( latitude=f2i(lat), longitude=f2i(lng), since_timestamp_ms=timestamp, cell_id=cellid ) - - self.last_map_object = self.api.call() self.last_time_map_object = time.time() return self.last_map_object diff --git a/pokemongo_bot/api_wrapper.py b/pokemongo_bot/api_wrapper.py index f861cb1636..0cb3f9c62f 100644 --- a/pokemongo_bot/api_wrapper.py +++ b/pokemongo_bot/api_wrapper.py @@ -1,40 +1,70 @@ import time -from pgoapi.exceptions import (NotLoggedInException, - ServerBusyOrOfflineException) +from pgoapi.exceptions import ServerSideRequestThrottlingException, NotLoggedInException, ServerBusyOrOfflineException, NoPlayerPositionSetException, EmptySubrequestChainException +from pgoapi.pgoapi import PGoApi, PGoApiRequest, RpcApi +from pgoapi.protos.POGOProtos.Networking.Requests_pb2 import RequestType -import logger +import pokemongo_bot.logger as logger from human_behaviour import sleep - -class ApiWrapper(object): - def __init__(self, api): - self._api = api +class ApiWrapper(PGoApi): + def __init__(self): + PGoApi.__init__(self) + self.useVanillaRequest = False + + def create_request(self): + RequestClass = ApiRequest + if self.useVanillaRequest: + RequestClass = PGoApiRequest + + return RequestClass( + self._api_endpoint, + self._auth_provider, + self._position_lat, + self._position_lng, + self._position_alt + ) + + def login(self, *args): + # login needs base class "create_request" + self.useVanillaRequest = True + try: + ret_value = PGoApi.login(self, *args) + finally: + # cleanup code + self.useVanillaRequest = False + return ret_value + + +class ApiRequest(PGoApiRequest): + def __init__(self, *args): + PGoApiRequest.__init__(self, *args) self.request_callers = [] - self.reset_auth() self.last_api_request_time = None self.requests_per_seconds = 2 - def reset_auth(self): - self._api._auth_token = None - self._api._auth_provider = None - self._api._api_endpoint = None - - # wrap api methods - def _can_call(self): - if not self._api._req_method_list or len(self._api._req_method_list) == 0: - raise RuntimeError('Trying to call the api without setting any request') - if self._api._auth_provider is None or not self._api._auth_provider.is_login(): - logger.log('Not logged in!', 'red') + def can_call(self): + if not self._req_method_list: + raise EmptySubrequestChainException() + + if (self._position_lat is None) or (self._position_lng is None) or (self._position_alt is None): + raise NoPlayerPositionSetException() + + if self._auth_provider is None or not self._auth_provider.is_login(): + self.log.info('Not logged in') raise NotLoggedInException() + return True + def _call(self): + return PGoApiRequest.call(self) + def _pop_request_callers(self): r = self.request_callers self.request_callers = [] return [i.upper() for i in r] - def _is_response_valid(self, result, request_callers): + def is_response_valid(self, result, request_callers): if not result or result is None or not isinstance(result, dict): return False @@ -54,22 +84,35 @@ def _is_response_valid(self, result, request_callers): def call(self, max_retry=5): request_callers = self._pop_request_callers() - if not self._can_call(): + if not self.can_call(): return False # currently this is never ran, exceptions are raised before request_timestamp = None - - api_req_method_list = self._api._req_method_list + api_req_method_list = self._req_method_list result = None try_cnt = 0 + throttling_retry = 0 while True: request_timestamp = self.throttle_sleep() - self._api._req_method_list = [req_method for req_method in api_req_method_list] # api internally clear this field after a call - result = self._api.call() - if not self._is_response_valid(result, request_callers): + # self._call internally clear this field, so save it + self._req_method_list = [req_method for req_method in api_req_method_list] + try: + result = self._call() + should_retry = False + except ServerSideRequestThrottlingException: + should_retry = True + + if should_retry: + throttling_retry += 1 + logger.log("Server is throttling, let's slow down a bit") + if throttling_retry >= max_retry: + raise ServerSideRequestThrottlingException('Server throttled too many times') + sleep(1) # huge sleep ? + continue # skip response checking + + if not self.is_response_valid(result, request_callers): try_cnt += 1 logger.log('Server seems to be busy or offline - try again - {}/{}'.format(try_cnt, max_retry), 'red') - if try_cnt >= max_retry: raise ServerBusyOrOfflineException() sleep(1) @@ -79,15 +122,10 @@ def call(self, max_retry=5): self.last_api_request_time = request_timestamp return result - def login(self, provider, username, password): - return self._api.login(provider, username, password) - - # fallback def __getattr__(self, func): - DEFAULT_ATTRS = ['_position_lat', '_position_lng', '_auth_provider', '_api_endpoint', 'set_position', 'get_position'] - if func not in DEFAULT_ATTRS: + if func.upper() in RequestType.keys(): self.request_callers.append(func) - return getattr(self._api, func) + return PGoApiRequest.__getattr__(self, func) def throttle_sleep(self): now_milliseconds = time.time() * 1000 @@ -95,7 +133,7 @@ def throttle_sleep(self): difference = now_milliseconds - (self.last_api_request_time if self.last_api_request_time else 0) - if (self.last_api_request_time != None and difference < required_delay_between_requests): + if self.last_api_request_time != None and difference < required_delay_between_requests: sleep_time = required_delay_between_requests - difference time.sleep(sleep_time / 1000) diff --git a/pokemongo_bot/cell_workers/collect_level_up_reward.py b/pokemongo_bot/cell_workers/collect_level_up_reward.py index 8398153386..912a97d197 100644 --- a/pokemongo_bot/cell_workers/collect_level_up_reward.py +++ b/pokemongo_bot/cell_workers/collect_level_up_reward.py @@ -25,8 +25,7 @@ def work(self): self.previous_level = self.current_level def _collect_level_reward(self): - self.bot.api.level_up_rewards(level=self.current_level) - response_dict = self.bot.api.call() + response_dict = self.bot.api.level_up_rewards(level=self.current_level) if 'status_code' in response_dict and response_dict['status_code'] == 1: data = (response_dict .get('responses', {}) diff --git a/pokemongo_bot/cell_workers/evolve_all.py b/pokemongo_bot/cell_workers/evolve_all.py index 38a3a32d13..cdc6389344 100644 --- a/pokemongo_bot/cell_workers/evolve_all.py +++ b/pokemongo_bot/cell_workers/evolve_all.py @@ -157,8 +157,7 @@ def _execute_pokemon_evolve(self, pokemon, cache): if pokemon_name in cache: return - self.bot.api.evolve_pokemon(pokemon_id=pokemon_id) - response_dict = self.bot.api.call() + response_dict = self.bot.api.evolve_pokemon(pokemon_id=pokemon_id) status = response_dict['responses']['EVOLVE_POKEMON']['result'] if status == 1: logger.log('[#] Successfully evolved {} with {} CP and {} IV!'.format( @@ -174,8 +173,7 @@ def _execute_pokemon_evolve(self, pokemon, cache): # TODO: move to utils. These methods are shared with other workers. def transfer_pokemon(self, pid): - self.bot.api.release_pokemon(pokemon_id=pid) - response_dict = self.bot.api.call() + response_dict = self.bot.api.release_pokemon(pokemon_id=pid) def count_pokemon_inventory(self): response_dict = self.bot.get_inventory() diff --git a/pokemongo_bot/cell_workers/handle_soft_ban.py b/pokemongo_bot/cell_workers/handle_soft_ban.py index d13bd63eea..04e5178b50 100644 --- a/pokemongo_bot/cell_workers/handle_soft_ban.py +++ b/pokemongo_bot/cell_workers/handle_soft_ban.py @@ -50,7 +50,6 @@ def spin_fort(self, fort): player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1]) ) - self.bot.api.call() def should_run(self): return self.bot.softban diff --git a/pokemongo_bot/cell_workers/incubate_eggs.py b/pokemongo_bot/cell_workers/incubate_eggs.py index b8ef560bbb..95d497518a 100644 --- a/pokemongo_bot/cell_workers/incubate_eggs.py +++ b/pokemongo_bot/cell_workers/incubate_eggs.py @@ -47,8 +47,10 @@ def _apply_incubators(self): continue if self.bot.config.debug: logger.log('[x] Attempting to apply incubator {} to egg {}'.format(incubator['id'], egg['id'])) - self.bot.api.use_item_egg_incubator(item_id=incubator["id"], pokemon_id=egg["id"]) - ret = self.bot.api.call() + ret = self.bot.api.use_item_egg_incubator( + item_id=incubator["id"], + pokemon_id=egg["id"] + ) if ret: code = ret.get("responses", {}).get("USE_ITEM_EGG_INCUBATOR", {}).get("result", 0) if code == 1: @@ -125,8 +127,7 @@ def _check_inventory(self, lookup_ids=[]): return matched_pokemon def _hatch_eggs(self): - self.bot.api.get_hatched_eggs() - response_dict = self.bot.api.call() + response_dict = self.bot.api.get_hatched_eggs() log_color = 'green' try: result = reduce(dict.__getitem__, ["responses", "GET_HATCHED_EGGS"], response_dict) diff --git a/pokemongo_bot/cell_workers/nickname_pokemon.py b/pokemongo_bot/cell_workers/nickname_pokemon.py index d626595d11..2c61d87a9f 100644 --- a/pokemongo_bot/cell_workers/nickname_pokemon.py +++ b/pokemongo_bot/cell_workers/nickname_pokemon.py @@ -7,7 +7,7 @@ def initialize(self): self.template = self.config.get('nickname_template','').lower().strip() if self.template == "{name}": self.template = "" - + def work(self): try: inventory = reduce(dict.__getitem__, ["responses", "GET_INVENTORY", "inventory_delta", "inventory_items"], self.bot.get_inventory()) @@ -16,8 +16,8 @@ def work(self): else: pokemon_data = self._get_inventory_pokemon(inventory) for pokemon in pokemon_data: - self._nickname_pokemon(pokemon) - + self._nickname_pokemon(pokemon) + def _get_inventory_pokemon(self,inventory_dict): pokemon_data = [] for inv_data in inventory_dict: @@ -29,7 +29,7 @@ def _get_inventory_pokemon(self,inventory_dict): if not pokemon.get('is_egg',False): pokemon_data.append(pokemon) return pokemon_data - + def _nickname_pokemon(self,pokemon): """This requies a pokemon object containing all the standard fields: id, ivs, cp, etc""" new_name = "" @@ -62,10 +62,9 @@ def _nickname_pokemon(self,pokemon): logger.log("Unable to nickname {} due to bad template ({})".format(name,bad_key),log_color) if pokemon.get('nickname', "") == new_name: return - self.bot.api.nickname_pokemon(pokemon_id=instance_id,nickname=new_name) - response = self.bot.api.call() + response = self.bot.api.nickname_pokemon(pokemon_id=instance_id,nickname=new_name) sleep(1.2) - try: + try: result = reduce(dict.__getitem__, ["responses", "NICKNAME_POKEMON"], response) except KeyError: logger.log("Attempt to nickname received bad response from server.",log_color) diff --git a/pokemongo_bot/cell_workers/pokemon_catch_worker.py b/pokemongo_bot/cell_workers/pokemon_catch_worker.py index 6e90472a0c..3bcb8a6268 100644 --- a/pokemongo_bot/cell_workers/pokemon_catch_worker.py +++ b/pokemongo_bot/cell_workers/pokemon_catch_worker.py @@ -93,8 +93,11 @@ def work(self): break # Use the berry to catch - self.api.use_item_capture(item_id = berry_id,encounter_id = encounter_id,spawn_point_id = self.spawn_point_guid) - response_dict = self.api.call() + response_dict = self.api.use_item_capture( + item_id=berry_id, + encounter_id=encounter_id, + spawn_point_id=self.spawn_point_guid + ) if response_dict and response_dict['status_code'] is 1 and 'item_capture_mult' in response_dict['responses']['USE_ITEM_CAPTURE']: for i in range(len(catch_rate)): if 'item_capture_mult' in response_dict['responses']['USE_ITEM_CAPTURE']: @@ -126,8 +129,10 @@ def work(self): success_percentage = '{0:.2f}'.format(catch_rate[pokeball-1]*100) logger.log('Catch Rate with normal Pokeball is low ({}%). Thinking to throw a {}... ({} left!)'.format(success_percentage,self.item_list[str(berry_id)],berries_count-1)) - self.api.use_item_capture(item_id = berry_id,encounter_id = encounter_id,spawn_point_id = self.spawn_point_guid) - response_dict = self.api.call() + response_dict = self.api.use_item_capture(item_id=berry_id, + encounter_id=encounter_id, + spawn_point_id=self.spawn_point_guid + ) if response_dict and response_dict['status_code'] is 1 and 'item_capture_mult' in response_dict['responses']['USE_ITEM_CAPTURE']: for i in range(len(catch_rate)): if 'item_capture_mult' in response_dict['responses']['USE_ITEM_CAPTURE']: @@ -159,8 +164,10 @@ def work(self): success_percentage = '{0:.2f}'.format(catch_rate[pokeball-1]*100) logger.log('Catch Rate with normal Pokeball is low ({}%). Thinking to throw a {}... ({} left!)'.format(success_percentage,self.item_list[str(berry_id)],berries_count-1)) - self.api.use_item_capture(item_id = berry_id,encounter_id = encounter_id,spawn_point_id = self.spawn_point_guid) - response_dict = self.api.call() + response_dict = self.api.use_item_capture(item_id=berry_id, + encounter_id=encounter_id, + spawn_point_id=self.spawn_point_guid + ) if response_dict and response_dict['status_code'] is 1 and 'item_capture_mult' in response_dict['responses']['USE_ITEM_CAPTURE']: for i in range(len(catch_rate)): if 'item_capture_mult' in response_dict['responses']['USE_ITEM_CAPTURE']: @@ -205,14 +212,15 @@ def work(self): reticle_size_parameter = normalized_reticle_size(self.config.catch_randomize_reticle_factor) spin_modifier_parameter = spin_modifier(self.config.catch_randomize_spin_factor) - self.api.catch_pokemon(encounter_id=encounter_id, - pokeball=pokeball, - normalized_reticle_size=reticle_size_parameter, - spawn_point_id=self.spawn_point_guid, - hit_pokemon=1, - spin_modifier=spin_modifier_parameter, - normalized_hit_position=1) - response_dict = self.api.call() + response_dict = self.api.catch_pokemon( + encounter_id=encounter_id, + pokeball=pokeball, + normalized_reticle_size=reticle_size_parameter, + spawn_point_id=self.spawn_point_guid, + hit_pokemon=1, + spin_modifier=spin_modifier_parameter, + normalized_hit_position=1 + ) if response_dict and \ 'responses' in response_dict and \ @@ -254,8 +262,7 @@ def work(self): if len(pokemon_to_transfer) == 0: raise RuntimeError( 'Trying to evolve 0 pokemons!') - self.api.evolve_pokemon(pokemon_id=pokemon_to_transfer[0]) - response_dict = self.api.call() + response_dict = self.api.evolve_pokemon(pokemon_id=pokemon_to_transfer[0]) status = response_dict['responses']['EVOLVE_POKEMON']['result'] if status == 1: logger.log( @@ -269,8 +276,7 @@ def work(self): def count_pokemon_inventory(self): # don't use cached bot.get_inventory() here # because we need to have actual information in capture logic - self.api.get_inventory() - response_dict = self.api.call() + response_dict = self.api.get_inventory() id_list = [] callback = lambda pokemon: id_list.append(pokemon['id']) @@ -360,22 +366,30 @@ def create_encounter_api_call(self): player_latitude = self.pokemon['latitude'] player_longitude = self.pokemon['longitude'] + request = self.api.create_request() if 'spawn_point_id' in self.pokemon: spawn_point_id = self.pokemon['spawn_point_id'] self.spawn_point_guid = spawn_point_id self.response_key = 'ENCOUNTER' self.response_status_key = 'status' - self.api.encounter(encounter_id=encounter_id, spawn_point_id=spawn_point_id, - player_latitude=player_latitude, player_longitude=player_longitude) + request.encounter( + encounter_id=encounter_id, + spawn_point_id=spawn_point_id, + player_latitude=player_latitude, + player_longitude=player_longitude + ) else: fort_id = self.pokemon['fort_id'] self.spawn_point_guid = fort_id self.response_key = 'DISK_ENCOUNTER' self.response_status_key = 'result' - self.api.disk_encounter(encounter_id=encounter_id, fort_id=fort_id, - player_latitude=player_latitude, player_longitude=player_longitude) - - return self.api.call() + request.disk_encounter( + encounter_id=encounter_id, + fort_id=fort_id, + player_latitude=player_latitude, + player_longitude=player_longitude + ) + return request.call() def check_vip_pokemon(self,pokemon, cp, iv): diff --git a/pokemongo_bot/cell_workers/recycle_items.py b/pokemongo_bot/cell_workers/recycle_items.py index 2ece62f95b..022a711f1a 100644 --- a/pokemongo_bot/cell_workers/recycle_items.py +++ b/pokemongo_bot/cell_workers/recycle_items.py @@ -44,9 +44,9 @@ def work(self): logger.log("-- Failed to discard " + item_name, 'red') def send_recycle_item_request(self, item_id, count): - self.bot.api.recycle_inventory_item(item_id=item_id, count=count) - inventory_req = self.bot.api.call() - # Example of good request response #{'responses': {'RECYCLE_INVENTORY_ITEM': {'result': 1, 'new_count': 46}}, 'status_code': 1, 'auth_ticket': {'expire_timestamp_ms': 1469306228058L, 'start': '/HycFyfrT4t2yB2Ij+yoi+on778aymMgxY6RQgvrGAfQlNzRuIjpcnDd5dAxmfoTqDQrbz1m2dGqAIhJ+eFapg==', 'end': 'f5NOZ95a843tgzprJo4W7Q=='}, 'request_id': 8145806132888207460L} - return inventory_req + return self.bot.api.recycle_inventory_item( + item_id=item_id, + count=count + ) diff --git a/pokemongo_bot/cell_workers/spin_fort.py b/pokemongo_bot/cell_workers/spin_fort.py index 6534731a86..f34fc2b8ef 100644 --- a/pokemongo_bot/cell_workers/spin_fort.py +++ b/pokemongo_bot/cell_workers/spin_fort.py @@ -33,12 +33,13 @@ def work(self): logger.log('Now at Pokestop: {0}'.format(fort_name), 'cyan') logger.log('Spinning ...', 'cyan') - self.bot.api.fort_search(fort_id=fort['id'], - fort_latitude=lat, - fort_longitude=lng, - player_latitude=f2i(self.bot.position[0]), - player_longitude=f2i(self.bot.position[1])) - response_dict = self.bot.api.call() + response_dict = self.bot.api.fort_search( + fort_id=fort['id'], + fort_latitude=lat, + fort_longitude=lng, + player_latitude=f2i(self.bot.position[0]), + player_longitude=f2i(self.bot.position[1]) + ) if 'responses' in response_dict and \ 'FORT_SEARCH' in response_dict['responses']: diff --git a/pokemongo_bot/cell_workers/transfer_pokemon.py b/pokemongo_bot/cell_workers/transfer_pokemon.py index 3cf40413f5..374ffa6a87 100644 --- a/pokemongo_bot/cell_workers/transfer_pokemon.py +++ b/pokemongo_bot/cell_workers/transfer_pokemon.py @@ -71,8 +71,10 @@ def work(self): def _release_pokemon_get_groups(self): pokemon_groups = {} - self.bot.api.get_player().get_inventory() - inventory_req = self.bot.api.call() + request = self.bot.api.create_request() + request.get_player() + request.get_inventory() + inventory_req = request.call() if inventory_req.get('responses', False) is False: return pokemon_groups @@ -182,8 +184,7 @@ def release_pokemon(self, pokemon_name, cp, iv, pokemon_id): logger.log('Exchanging {} [CP {}] [Potential {}] for candy!'.format(pokemon_name, cp, iv), 'green') - self.bot.api.release_pokemon(pokemon_id=pokemon_id) - response_dict = self.bot.api.call() + response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon_id) action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max) def _get_release_config_for(self, pokemon): diff --git a/pokemongo_bot/cell_workers/utils.py b/pokemongo_bot/cell_workers/utils.py index 253083bc0b..946c757b16 100644 --- a/pokemongo_bot/cell_workers/utils.py +++ b/pokemongo_bot/cell_workers/utils.py @@ -28,10 +28,10 @@ def fort_details(bot, fort_id, latitude, longitude): """ Lookup the fort details and cache the response for future use. """ - bot.api.fort_details(fort_id=fort_id, latitude=latitude, longitude=longitude) - + request = bot.api.create_request() + request.fort_details(fort_id=fort_id, latitude=latitude, longitude=longitude) try: - response_dict = bot.api.call() + response_dict = request.call() FORT_CACHE[fort_id] = response_dict['responses']['FORT_DETAILS'] except Exception: pass diff --git a/pokemongo_bot/metrics.py b/pokemongo_bot/metrics.py index 0ab7cb14dd..0ffeb39a6c 100644 --- a/pokemongo_bot/metrics.py +++ b/pokemongo_bot/metrics.py @@ -70,9 +70,10 @@ def released_pokemon(self, count=1): self.releases += count def capture_stats(self): - self.bot.api.get_inventory() - self.bot.api.get_player() - response_dict = self.bot.api.call() + request = self.bot.api.create_request() + request.get_inventory() + request.get_player() + response_dict = request.call() try: self.dust['latest'] = response_dict['responses']['GET_PLAYER']['player_data']['currencies'][1]['amount'] if self.dust['start'] is None: self.dust['start'] = self.dust['latest'] diff --git a/requirements.txt b/requirements.txt index e572c4e2c6..08f9407c81 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ numpy==1.11.0 networkx==1.11 --e git+https://github.com/tejado/pgoapi.git@81e786cabf027a1c8fbd1e9a07e1c11aa3d8ee8b#egg=pgoapi +-e git+https://github.com/tejado/pgoapi.git@0811db23d639039f968a82e06c7aa15a0a5016b6#egg=pgoapi geopy==1.11.0 protobuf==3.0.0b4 requests==2.10.0 diff --git a/tests/__init__.py b/tests/__init__.py index 2db23ffd9d..5318e2d482 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,21 +1,15 @@ # __init__.py from mock import MagicMock -from pgoapi import PGoApi -from pokemongo_bot.api_wrapper import ApiWrapper +from pokemongo_bot.api_wrapper import ApiWrapper, ApiRequest from pokemongo_bot import PokemonGoBot class FakeApi(ApiWrapper): - def __init__(self, return_value=None): - super(FakeApi, self).__init__(PGoApi()) - self._api.call = MagicMock(return_value=return_value) - - def _can_call(self): - return True - - def setApiReturnValue(self, value): - self._api.call.return_value = value - + def create_request(self, return_value='mock return'): + request = ApiWrapper.create_request(self) + request.can_call = MagicMock(return_value=True) + request._call = MagicMock(return_value=return_value) + return request class FakeBot(PokemonGoBot): def __init__(self): diff --git a/tests/api_wrapper_test.py b/tests/api_wrapper_test.py index 0a835e0e20..335f04cbf2 100644 --- a/tests/api_wrapper_test.py +++ b/tests/api_wrapper_test.py @@ -5,43 +5,56 @@ from tests import FakeApi from pgoapi import PGoApi -from pgoapi.exceptions import NotLoggedInException, ServerBusyOrOfflineException +from pgoapi.exceptions import NotLoggedInException, ServerBusyOrOfflineException, NoPlayerPositionSetException, EmptySubrequestChainException from pokemongo_bot.api_wrapper import ApiWrapper class TestApiWrapper(unittest.TestCase): def test_raises_not_logged_in_exception(self): - api = ApiWrapper(PGoApi()) - api.get_inventory(test='awesome') + api = ApiWrapper() + api.set_position(*(42, 42, 0)) + request = api.create_request() + request.get_inventory(test='awesome') with self.assertRaises(NotLoggedInException): - api.call() + request.call() def test_api_call_with_no_requests_set(self): - api = ApiWrapper(PGoApi()) - with self.assertRaises(RuntimeError): - api.call() + request = ApiWrapper().create_request() + with self.assertRaises(EmptySubrequestChainException): + request.call() + + def test_api_wrong_request(self): + request = ApiWrapper().create_request() + with self.assertRaises(AttributeError): + request.wrong_request() + + def test_raises_no_player_position_set_exception(self): + request = ApiWrapper().create_request() + request.get_inventory(test='awesome') + with self.assertRaises(NoPlayerPositionSetException): + request.call() @patch('pokemongo_bot.api_wrapper.sleep') def test_api_server_is_unreachable_raises_server_busy_or_offline_exception(self, sleep): sleep.return_value = True # we don't need to really sleep - api = FakeApi('Wrong Value') - api.get_inventory(test='awesome') + request = FakeApi().create_request('Wrong Value') + request.get_inventory() # we expect an exception because the "server" isn't returning a valid response with self.assertRaises(ServerBusyOrOfflineException): - api.call() + request.call() def test_mocked_call(self): - api = FakeApi(True) - api._is_response_valid = MagicMock(return_value=True) - api.get_inventory(test='awesome') - result = api.call() + request = FakeApi().create_request(True) + request.is_response_valid = MagicMock(return_value=True) + request.get_inventory(test='awesome') + result = request.call() self.assertTrue(result) def test_return_value_is_not_valid(self): - - def returnApi(ret_value): - api = FakeApi(ret_value) - api.get_inventory(test='awesome') - return api + api = FakeApi() + def returnRequest(ret_value): + request = api.create_request(ret_value) + request.get_inventory(test='awesome') + return request wrong_return_values = [ None, @@ -52,52 +65,59 @@ def returnApi(ret_value): {'responses': {'GET_INVENTORY_OR_NOT': {}}, 'status_code': 0} ] for wrong in wrong_return_values: - api = returnApi(wrong) - request_callers = api._pop_request_callers() # we can pop because we do no call + request = returnRequest(wrong) + request_callers = request._pop_request_callers() # we can pop because we do no call - is_valid = api._is_response_valid(wrong, request_callers) + is_valid = request.is_response_valid(wrong, request_callers) self.assertFalse(is_valid, 'return value {} is valid somehow ?'.format(wrong)) def test_return_value_is_valid(self): - api = FakeApi() # we set the return value below - api.get_inventory(test='awesome') + request = FakeApi().create_request() # we set the return value below + request.get_inventory(test='awesome') - request = api.request_callers[0] # only one request - self.assertEqual(request.upper(), 'GET_INVENTORY') + request_caller = request.request_callers[0] # only one request + self.assertEqual(request_caller.upper(), 'GET_INVENTORY') - good_return_value = {'responses': {request.upper(): {}}, 'status_code': 0} - api.setApiReturnValue(good_return_value) + good_return_value = {'responses': {request_caller.upper(): {}}, 'status_code': 0} + request._call.return_value = good_return_value - result = api.call() + result = request.call() self.assertEqual(result, good_return_value) - self.assertEqual(len(api.request_callers), 0, 'request_callers must be empty') + self.assertEqual(len(request.request_callers), 0, 'request_callers must be empty') def test_multiple_requests(self): - api = FakeApi() - api.get_inventory(test='awesome') - api.fort_details() + request = FakeApi().create_request() + request.get_inventory(test='awesome') + request.fort_details() good_return_value = {'responses': {'GET_INVENTORY': {}, 'FORT_DETAILS': {}}, 'status_code': 0} - api.setApiReturnValue(good_return_value) + request._call.return_value = good_return_value - result = api.call() + result = request.call() self.assertEqual(result, good_return_value) @timeout(1) def test_api_call_throttle_should_pass(self): - api = FakeApi(True) - api._is_response_valid = MagicMock(return_value=True) - api.requests_per_seconds = 5 + request = FakeApi().create_request() + request.is_response_valid = MagicMock(return_value=True) + request.requests_per_seconds = 5 - for i in range(api.requests_per_seconds): - api.call() + for i in range(request.requests_per_seconds): + request.call() @timeout(1) # expects a timeout def test_api_call_throttle_should_fail(self): - api = FakeApi(True) - api._is_response_valid = MagicMock(return_value=True) - api.requests_per_seconds = 5 + request = FakeApi().create_request() + request.is_response_valid = MagicMock(return_value=True) + request.requests_per_seconds = 5 with self.assertRaises(TimeoutError): - for i in range(api.requests_per_seconds * 2): - api.call() + for i in range(request.requests_per_seconds * 2): + request.call() + + @patch('pokemongo_bot.api_wrapper.ApiRequest.is_response_valid') + def test_api_direct_call(self, mock_method): + mock_method.return_value = True + + result = FakeApi().get_inventory() + self.assertEqual(result, 'mock return')