Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:PokemonGoF/PokemonGo-Bot into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
douglascamata committed Jul 29, 2016
2 parents aceaee9 + 6154939 commit 8874c33
Show file tree
Hide file tree
Showing 25 changed files with 535 additions and 244 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@
* surceis
* SpaceWhale
* klingan
* reddivision
12 changes: 2 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ We use [Slack](https://slack.com) as a web chat. [Click here to join the chat!](
- [x] Ignore certain pokemon filter
- [x] Adjust delay between Pokemon capture & Transfer as per configuration
- [ ] Standalone Desktop Application
- [ ] Hatch eggs
- [ ] Incubate eggs
- [x] Hatch eggs
- [x] Incubate eggs
- [ ] Use candy
- [ ] Inventory cleaner

Expand Down Expand Up @@ -56,12 +56,4 @@ To ensure that all updates are documented - [@eggins](https://github.com/eggins)
- [AHAAAAAAA](https://github.com/AHAAAAAAA/PokemonGo-Map) for parts of the s2sphere stuff


## Donation

Bitcoin Address: 1PJMCx9NNQRasQYaa4MMff9yyNFffhHgLu

<p align="center">
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WQUXDC54W6EVY"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif"></a>
</p>

[![Analytics](https://ga-beacon.appspot.com/UA-81468120-1/welcome-page-dev)](https://github.com/igrigorik/ga-beacon)
1 change: 1 addition & 0 deletions configs/config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"avoid_circles": true,
"max_circle_size": 50
},
"websocket_server": false,
"walk": 4.16,
"action_wait_min": 1,
"action_wait_max": 4,
Expand Down
50 changes: 46 additions & 4 deletions pokecli.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ def init_config():
help="Username",
default=None
)
add_config(
parser,
load,
short_flag="-ws",
long_flag="--websocket_server",
help="Start websocket server (format 'host:port')",
default=False
)
add_config(
parser,
load,
Expand Down Expand Up @@ -174,11 +182,18 @@ def init_config():
add_config(
parser,
load,
<<<<<<< HEAD
long_flag="--spin",
help="Enable Spinning Pokestops",
type=bool,
default=True,
embedded_in='forts'
=======
long_flag="--forts.spin",
help="Enable Spinning Pokestops",
type=bool,
default=True,
>>>>>>> 6154939256147a79882e616ad7b71fd83dee879e
)
add_config(
parser,
Expand Down Expand Up @@ -303,21 +318,19 @@ def init_config():
parser,
load,
short_flag="-ac",
long_flag="--avoid_circles",
long_flag="--forts.avoid_circles",
help="Avoids circles (pokestops) of the max size set in max_circle_size flag",
type=bool,
default=False,
embedded_in='forts'
)
add_config(
parser,
load,
short_flag="-mcs",
long_flag="--max_circle_size",
long_flag="--forts.max_circle_size",
help="If avoid_circles flag is set, this flag specifies the maximum size of circles (pokestops) avoided",
type=int,
default=10,
embedded_in='forts'
)

# Start to parse other attrs
Expand Down Expand Up @@ -360,25 +373,54 @@ def init_config():
config.evolve_all = [str(pokemon_name) for pokemon_name in config.evolve_all.split(',')]

fix_nested_config(config)
<<<<<<< HEAD
=======
import pdb; pdb.set_trace()
>>>>>>> 6154939256147a79882e616ad7b71fd83dee879e
return config

def add_config(parser, json_config, short_flag=None, long_flag=None, embedded_in=None, **kwargs):
if not long_flag:
raise Exception('add_config calls requires long_flag parameter!')

full_attribute_path = long_flag.split('--')[1]
attribute_name = full_attribute_path.split('.')[-1]

if '.' in full_attribute_path: # embedded config!
embedded_in = full_attribute_path.split('.')[0: -1]
for level in embedded_in:
json_config = json_config.get(level, {})

if 'default' in kwargs:
<<<<<<< HEAD
attribute_name = long_flag.split('--')[1]
if embedded_in:
json_config = json_config.get(embedded_in, None)
if not json_config:
raise Exception('Container "{}" for key "{}" didnt found!'.format(embedded_in, attribute_name))
kwargs['dest'] = "{}_{}".format(embedded_in, attribute_name)
=======
>>>>>>> 6154939256147a79882e616ad7b71fd83dee879e
kwargs['default'] = json_config.get(attribute_name, kwargs['default'])
if short_flag:
args = (short_flag, long_flag)
else:
args = (long_flag,)
parser.add_argument(*args, **kwargs)

<<<<<<< HEAD
=======

def fix_nested_config(config):
config_dict = config.__dict__

for key, value in config_dict.iteritems():
if '.' in key:
new_key = key.replace('.', '_')
config_dict[new_key] = value
del config_dict[key]

>>>>>>> 6154939256147a79882e616ad7b71fd83dee879e
def parse_unicode_str(string):
try:
return string.decode('utf8')
Expand Down
105 changes: 79 additions & 26 deletions pokemongo_bot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,32 @@
from pgoapi.utilities import f2i

import logger
from cell_workers import SpinNearestFortWorker, CatchVisiblePokemonWorker, PokemonCatchWorker, SeenFortWorker, MoveToFortWorker, PokemonTransferWorker, EvolveAllWorker, RecycleItemsWorker, IncubateEggsWorker
import cell_workers
from cell_workers.utils import distance, get_cellid, encode, i2f
from human_behaviour import sleep
from item_list import Item
from metrics import Metrics
from pokemongo_bot.event_handlers import LoggingHandler
from pokemongo_bot.event_handlers import SocketIoHandler
from pokemongo_bot.socketio_server.runner import SocketIoRunner
from spiral_navigator import SpiralNavigator
from worker_result import WorkerResult
from event_manager import EventManager
from api_wrapper import ApiWrapper


class PokemonGoBot(object):

WORKERS = [
cell_workers.IncubateEggsWorker,
cell_workers.PokemonTransferWorker,
cell_workers.EvolveAllWorker,
cell_workers.RecycleItemsWorker,
cell_workers.CatchVisiblePokemonWorker,
cell_workers.SeenFortWorker,
cell_workers.MoveToFortWorker
]

@property
def position(self):
return self.api._position_lat, self.api._position_lng, 0
Expand All @@ -38,35 +52,50 @@ def __init__(self, config):
self.metrics = Metrics(self)
self.latest_inventory = None
self.cell = None
self.recent_forts = [None] * config.max_circle_size
self.recent_forts = [None] * config.forts_max_circle_size
self.tick_count = 0

# Make our own copy of the workers for this instance
self.workers = list(self.WORKERS)

def start(self):
self._setup_logging()
self._setup_api()
self.navigator = SpiralNavigator(self)
random.seed()

def _setup_event_system(self):
handlers = [LoggingHandler()]
if self.config.websocket_server:
websocket_handler = SocketIoHandler(self.config.websocket_server)
handlers.append(websocket_handler)

self.sio_runner = SocketIoRunner(self.config.websocket_server)
self.sio_runner.start_listening_async()

self.event_manager = EventManager(*handlers)

# Registering event:
# self.event_manager.register_event("location", parameters=['lat', 'lng'])
#
# Emitting event should be enough to add logging and send websocket
# message: :
# self.event_manager.emit('location', 'level'='info', data={'lat': 1, 'lng':1}),

def tick(self):
self.cell = self.get_meta_cell()

# Check if session token has expired
self.check_session(self.position[0:2])

workers = [
IncubateEggsWorker,
PokemonTransferWorker,
EvolveAllWorker,
RecycleItemsWorker,
CatchVisiblePokemonWorker,
SpinNearestFortWorker
]

for worker in workers:
for worker in self.workers:
if worker(self).work() == WorkerResult.RUNNING:
return

self.navigator.take_step()

self.tick_count +=1

def get_meta_cell(self):
location = self.position[0:2]
cells = self.find_close_cells(*location)
Expand Down Expand Up @@ -185,14 +214,22 @@ def _setup_logging(self):
# log format
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s [%(module)10s] [%(levelname)5s] %(message)s')
format='%(asctime)s [%(name)10s] [%(levelname)5s] %(message)s')

if self.config.debug:
logging.getLogger("requests").setLevel(logging.DEBUG)
logging.getLogger("websocket").setLevel(logging.DEBUG)
logging.getLogger("socketio").setLevel(logging.DEBUG)
logging.getLogger("engineio").setLevel(logging.DEBUG)
logging.getLogger("socketIO-client").setLevel(logging.DEBUG)
logging.getLogger("pgoapi").setLevel(logging.DEBUG)
logging.getLogger("rpc_api").setLevel(logging.DEBUG)
else:
logging.getLogger("requests").setLevel(logging.ERROR)
logging.getLogger("websocket").setLevel(logging.ERROR)
logging.getLogger("socketio").setLevel(logging.ERROR)
logging.getLogger("engineio").setLevel(logging.ERROR)
logging.getLogger("socketIO-client").setLevel(logging.ERROR)
logging.getLogger("pgoapi").setLevel(logging.ERROR)
logging.getLogger("rpc_api").setLevel(logging.ERROR)

Expand Down Expand Up @@ -397,18 +434,14 @@ def _set_starting_position(self):
return

if self.config.location:
try:
location_str = self.config.location.encode('utf-8')
location = (self._get_pos_by_name(location_str.replace(" ", "")))
self.api.set_position(*location)
logger.log('')
logger.log(u'Location Found: {}'.format(self.config.location))
logger.log('GeoPosition: {}'.format(self.position))
logger.log('')
has_position = True
except Exception:
logger.log('[x] The location given in the config could not be parsed. Checking for a cached location.')
pass
location_str = self.config.location.encode('utf-8')
location = (self._get_pos_by_name(location_str.replace(" ", "")))
self.api.set_position(*location)
logger.log('')
logger.log(u'Location Found: {}'.format(self.config.location))
logger.log('GeoPosition: {}'.format(self.position))
logger.log('')
has_position = True

if self.config.location_cache:
try:
Expand Down Expand Up @@ -461,7 +494,6 @@ def heartbeat(self):
in self.fort_timeouts.iteritems()
if timeout >= time.time() * 1000}
self.api.get_player()
self.api.get_hatched_eggs()
self.api.check_awarded_badges()
self.api.call()
self.update_web_location() # updates every tick
Expand Down Expand Up @@ -532,3 +564,24 @@ def get_player_info(self):
logger.log(
'Pokemon Captured: {pokemons_captured}'.format(**playerdata) +
' | Pokestops Visited: {poke_stop_visits}'.format(**playerdata), 'cyan')

def has_space_for_loot(self):
number_of_things_gained_by_stop = 5
enough_space = self.get_inventory_count('item') < self._player['max_item_storage'] - number_of_things_gained_by_stop

return enough_space

def get_forts(self, order_by_distance=False):
forts = [fort
for fort in self.cell['forts']
if 'latitude' in fort and 'type' in fort]

if order_by_distance:
forts.sort(key=lambda x: distance(
self.position[0],
self.position[1],
x['latitude'],
x['longitude']
))

return forts
20 changes: 19 additions & 1 deletion pokemongo_bot/api_wrapper.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# api_wrapper.py

from pgoapi import PGoApi
from pgoapi.exceptions import NotLoggedInException
from pgoapi.exceptions import NotLoggedInException, ServerBusyOrOfflineException
from human_behaviour import sleep
import time
import logger

class ApiWrapper(object):
def __init__(self, api):
self._api = api
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
Expand Down Expand Up @@ -54,20 +57,26 @@ def call(self, max_retry=5):
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
result = None
try_cnt = 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):
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)
else:
break

self.last_api_request_time = request_timestamp
return result

def login(self, provider, username, password):
Expand All @@ -80,5 +89,14 @@ def __getattr__(self, func):
self.request_callers.append(func)
return getattr(self._api, func)

def throttle_sleep(self):
now_milliseconds = time.time() * 1000
required_delay_between_requests = 1000 / self.requests_per_seconds

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):
sleep_time = required_delay_between_requests - difference
time.sleep(sleep_time / 1000)

return now_milliseconds
1 change: 0 additions & 1 deletion pokemongo_bot/cell_workers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@
from evolve_all_worker import EvolveAllWorker
from catch_visible_pokemon_worker import CatchVisiblePokemonWorker
from recycle_items_worker import RecycleItemsWorker
from spin_nearest_fort_worker import SpinNearestFortWorker
from incubate_eggs_worker import IncubateEggsWorker
Loading

1 comment on commit 8874c33

@matthojo
Copy link

@matthojo matthojo commented on 8874c33 Jul 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit has several git references left in pokecli.py.

Please sign in to comment.