diff --git a/MultiBot.py b/MultiBot.py new file mode 100644 index 0000000000..795812fc00 --- /dev/null +++ b/MultiBot.py @@ -0,0 +1,161 @@ +#encoding=utf8 +# the above tag defines encoding for this document and is for Python 2.x compatibility +import gzip +import json +import multiprocessing +import os +import platform +import re +import shutil +import sys +import threading +import time +from threading import * +import requests + +Null = "" +proxyCur = 0 +hashkeyCur = 0 +accountNum = 0 +try: + os.rmdir('configs/temp') +except: + pass +try: + os.mkdir('configs/temp') +except: + pass +AccountLock = Semaphore(value=1) +MultiBotConfig = json.loads(open('configs/MultiBotConfig.json').read()) + +def getProxy(): + try: + while True: + try: + with open('configs/' + MultiBotConfig[u'ProxyFile']) as proxyFile: + proxyAll = proxyFile.readlines() + proxyNum = sum(1 for line in open('configs/' + MultiBotConfig[u'ProxyFile'])) + global proxyCur + global proxy + proxy = proxyAll[proxyCur].replace('\n', '').replace('\r', '') + proxies = {"http": "http://" + proxy, "https": "https://" + proxy} + proxyCur += 1 + if proxyCur >= proxyNum: + proxyCur = 0 + headers = {'user-agent': 'Niantic App'} + if requests.get('https://pgorelease.nianticlabs.com/plfe/', headers=headers, proxies=proxies).status_code == 200: + headers = {'user-agent': 'pokemongo/1 CFNetwork/758.5.3 Darwin/15.6.0'} + if requests.get('https://sso.pokemon.com/', headers=headers, proxies=proxies).status_code == 200: + return proxy + else: + print ("Proxy is Banned") + else: + print ("Proxy is Banned") + + except Exception as e: + print (e) + pass + except IOError: + print 'configs/{} does not exist'.format(MultiBotConfig[u'ProxyFile']) + +try: + Accounts = [] + with open('configs/' + MultiBotConfig[u'AccountsFile']) as f: + for line in f: + line = line.replace('\n', '').replace('\r', '').replace(',', '.') + Accounts.append(line) +except IOError: + print 'configs/{} does not exist'.format(MultiBotConfig[u'AccountsFile']) + +def getHashKey(): + try: + with open('configs/' + MultiBotConfig[u'HashKeyFile']) as hashkeyFile: + hashkeyAll = hashkeyFile.readlines() + hashkeyNum = sum(1 for line in open('configs/' + MultiBotConfig[u'HashKeyFile']))-1 + global hashkeyCur + global hashkey + if hashkeyCur is hashkeyNum: + hashkeyCur = 0 + hashkeyCur += 1 + return hashkeyAll[hashkeyCur].replace('\n', '').replace('\r', '') + except IOError: + print 'configs/{} does not exist'.format(MultiBotConfig[u'HashKeyFile']) + +def AccountManager(Account=None): + AccountLock.acquire() + global Accounts + if Account is None: + AccountTemp = Accounts[0] + del Accounts[0] + AccountLock.release() + return AccountTemp + else: + Accounts.append(Account) + AccountLock.release() + +def MakeConf(CurThread, username, password): + try: + jsonData = json.loads(open('configs/' + MultiBotConfig[u'AuthJsonFile']).read()) + jsonData[u'username'] = username + jsonData[u'password'] = password + jsonData[u'hashkey'] = getHashKey() + + with open('configs/temp/auth-' + str(CurThread) + '.json', 'w') as s: + s.write(json.dumps(jsonData)) + s.close() + + jsonData = json.loads(open('configs/' + MultiBotConfig[u'ConfigJsonFile']).read()) + if MultiBotConfig[u'CompleteTutorialNickName']: + for i in range(len(jsonData[u'tasks'])): + try: + if jsonData[u'tasks'][i][u'config'][u'nickname']: + jsonData[u'tasks'][i][u'config'][u'nickname'] = username.replace('_', '') + except: + pass + try: + if jsonData[u'websocket'][u'start_embedded_server']: + jsonData[u'websocket'][u'server_url'] = MultiBotConfig[u'WebSocket'][u'IP'] + ':' + str(MultiBotConfig[u'WebSocket'][u'Port'] + CurThread) + except: + print 'error websocket' + + with open('configs/temp/config-' + str(CurThread) + '.json', 'w') as s: + s.write(json.dumps(jsonData)) + s.close() + + except IOError: + print 'config file error' + time.sleep(30) + +class ThreadClass(threading.Thread): + def run(self): + self.CurThread = int(self.getName().replace('Thread-', '')) -1 + while True: + self.Account = AccountManager() + self.username, self.password = self.Account.split(':') + print 'Thread-{0} using account {1}'.format(self.CurThread, self.username) + try: + MakeConf(self.CurThread, self.username, self.password) + if MultiBotConfig[u'UseProxy']: + self.proxy = getProxy() + if platform.system() == "Linux": + self.os.system('export HTTP_PROXY="http://' + proxy + '"; export HTTPS_PROXY="https://' + proxy + '"') + if platform.system() == "Windows": + self.os.system('') + os.system( + "python pokecli.py -af configs/temp/auth-{0}.json -cf configs/temp/config-{0}.json --walker_limit_output {1}".format( + self.CurThread, MultiBotConfig[u'walker_limit_output'])) + except Exception as e: + import traceback + print("Generic Exception: " + traceback.format_exc()) + finally: + AccountManager(self.Account) + time.sleep (60) +def start(): + for i in range(MultiBotConfig[u'Threads']): + t = ThreadClass() + time.sleep (0.1) + t.start() + time.sleep (10) + +if __name__ == "__main__": + start() diff --git a/configs/MultiBotConfig.json.example b/configs/MultiBotConfig.json.example new file mode 100644 index 0000000000..140818cc72 --- /dev/null +++ b/configs/MultiBotConfig.json.example @@ -0,0 +1,16 @@ +{ + "Threads": 2, + "HashKeyFile": "MultiBotConfigHashkey.txt", + "UseProxy": false, + "ProxyFile": "MultiBotConfigProxy.txt", + "AccountsFile": "MultiBotConfigAccounts.txt", + "AuthJsonFile": "auth.json", + "ConfigJsonFile": "config.json", + "CompleteTutorialNickName": true, + "WebSocket": { + "start_embedded_server": false, + "IP": "127.0.0.1", + "Port": 4000 + }, + "walker_limit_output": true +} diff --git a/configs/MultiBotConfigAccounts.txt.example b/configs/MultiBotConfigAccounts.txt.example new file mode 100644 index 0000000000..26fdd00ee9 --- /dev/null +++ b/configs/MultiBotConfigAccounts.txt.example @@ -0,0 +1,2 @@ +username:password +username:password diff --git a/configs/MultiBotConfigHashkey.txt.example b/configs/MultiBotConfigHashkey.txt.example new file mode 100644 index 0000000000..018e99dcf9 --- /dev/null +++ b/configs/MultiBotConfigHashkey.txt.example @@ -0,0 +1,2 @@ +1I2F1L5B3D7F3K5G3Z2N +7V5J1K2H6S1F8I4V3V5Z diff --git a/configs/MultiBotConfigProxy.txt.example b/configs/MultiBotConfigProxy.txt.example new file mode 100644 index 0000000000..5151b5fed7 --- /dev/null +++ b/configs/MultiBotConfigProxy.txt.example @@ -0,0 +1,2 @@ +127.0.0.1:1080 +127.0.0.1:1080 diff --git a/docs/manual_installation.md b/docs/manual_installation.md index 12ac65c104..c210fa1611 100644 --- a/docs/manual_installation.md +++ b/docs/manual_installation.md @@ -130,13 +130,16 @@ source bin/activate ``` cd C:\Python27\ pip install --upgrade pip -pip install --upgrade virtualenv +cd .. +cd to PokemonGo-Bot directory git clone --recursive -b dev https://github.com/PokemonGoF/PokemonGo-Bot -pip install --upgrade -r C:/Python27/PokemonGo-Bot/requirements.txt -cd C:/Python27/PokemonGo-Bot/ -virtualenv . -call C:\Python27\PokemonGo-Bot\Scripts\activate.bat -pip install --upgrade -r C:/Python27/PokemonGo-Bot/requirements.txt +pip install --upgrade -r requirements.txt +git pull +cd web +git checkout master +git pull +cd .. + ``` ##### Update @@ -144,8 +147,8 @@ pip install --upgrade -r C:/Python27/PokemonGo-Bot/requirements.txt *Run the following commands in the Command Prompt with Administrator Privileges* ``` -cd C:/Python27/PokemonGo-Bot/ +cd to PokemonGo-Bot directory git pull -pip uninstall pgoapi git submodule update --init --recursive ``` + diff --git a/pokemongo_bot/cell_workers/catch_limiter.py b/pokemongo_bot/cell_workers/catch_limiter.py index 7c192fff15..5ebf4f55e5 100644 --- a/pokemongo_bot/cell_workers/catch_limiter.py +++ b/pokemongo_bot/cell_workers/catch_limiter.py @@ -1,12 +1,15 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals from __future__ import absolute_import +from __future__ import unicode_literals +import sys from datetime import datetime, timedelta -from pokemongo_bot.base_task import BaseTask -from pokemongo_bot.worker_result import WorkerResult + from pokemongo_bot import inventory +from pokemongo_bot.base_task import BaseTask from pokemongo_bot.item_list import Item +from pokemongo_bot.worker_result import WorkerResult + class CatchLimiter(BaseTask): SUPPORTED_TASK_API_VERSION = 1 @@ -15,55 +18,152 @@ def __init__(self, bot, config): super(CatchLimiter, self).__init__(bot, config) self.bot = bot self.config = config - self.enabled = self.config.get("enabled",False) + self.enabled = self.config.get("enabled", False) self.min_balls = self.config.get("min_balls", 20) - self.resume_at_balls = self.config.get("resume_at_balls", 100) - self.duration = self.config.get("duration",15) + self.resume_at_balls = self.config.get("resume_balls", 100) + self.duration = self.config.get("duration", 15) + self.no_log_until = datetime.now() self.min_ultraball_to_keep = 0 - for subVal in self.bot.config.raw_tasks: - if "type" in subVal: - if subVal["type"] == "CatchPokemon": - self.min_ultraball_to_keep = subVal["config"]["min_ultraball_to_keep"] - - if not hasattr(self.bot, "catch_resume_at"): self.bot.catch_resume_at = None + for catch_cfg in self.bot.config.raw_tasks: + if "type" in catch_cfg: + if catch_cfg["type"] == "CatchPokemon": + self.min_ultraball_to_keep = catch_cfg["config"]["min_ultraball_to_keep"] + self.daily_catch_limit = catch_cfg["config"]["daily_catch_limit"] + self.exit_on_limit_reached = catch_cfg["config"]["exit_on_limit_reached"] + + if not hasattr(self.bot, "catch_resume_at"): + self.bot.catch_resume_at = None + if not hasattr(self.bot, "catch_limit_reached"): + self.bot.catch_limit_reached = False + if not hasattr(self.bot, "warned_about_catch_limit"): + self.bot.warned_about_catch_limit = False def work(self): if not self.enabled: return WorkerResult.SUCCESS now = datetime.now() + + # check catch limits + with self.bot.database as conn: + c = conn.cursor() + c.execute( + "SELECT DISTINCT COUNT(encounter_id) FROM catch_log WHERE dated >= datetime('now','-1 day')") + + result = c.fetchone() + + # check catch limits before catch + + if result[0] >= self.daily_catch_limit: + if hasattr( + self.bot, + "warned_about_catch_limit") and not self.bot.warned_about_catch_limit: + self.emit_event( + 'catch_limit', + formatted='WARNING! You have reached (%s / %s) your daily catch limit. Disabling catching for an hour!' % + (result[0], + self.daily_catch_limit)) + self.bot.warned_about_catch_limit = True + self.bot.catch_limit_reached = True + self.bot.catch_resume_at = now + timedelta(minutes=60) + self.bot.catch_disabled = True + if self.exit_on_limit_reached: + sys.exit(2) + + return WorkerResult.SUCCESS + + elif result[0] <= (self.daily_catch_limit - 20): + if self.bot.catch_limit_reached: + self.emit_event( + 'catch_limit_off', + formatted="Resume time hasn't passed yet, but catch limit passing ({} / {}}). Re-enabling catch tasks.".format( + result[0], + self.daily_catch_limit)) + self.bot.catch_disabled = False + self.bot.catch_limit_reached = False + self.bot.catch_resume_at = now + self.bot.warned_about_catch_limit = False + + elif self.bot.catch_resume_at is not None and self.bot.catch_limit_reached: + # Lets check if the resume time has passed and the limit is okay + if now >= self.bot.catch_resume_at and result[0] < self.daily_catch_limit: + self.emit_event( + 'catch_limit_off', + formatted="Resume time has passed and catch limit passing ({} / {}}). Re-enabling catch tasks.".format( + result[0], + self.daily_catch_limit)) + self.bot.catch_disabled = False + self.bot.catch_limit_reached = False + self.bot.catch_resume_at = now + + if self.bot.catch_limit_reached: + if self.no_log_until <= now: + self.logger.info( + "All catch tasks disabled until %s beacuse we hit the daily catch limit (%s >= %s)" % + (self.bot.catch_resume_at.strftime("%H:%M:%S"), result[0], self.daily_catch_limit)) + self.no_log_until = now + timedelta(minutes=2) + return WorkerResult.SUCCESS + + # Back to the balls balls_on_hand = self.get_pokeball_count() - self.min_ultraball_to_keep - + # If resume time has passed, resume catching tasks - if self.bot.catch_disabled and now >= self.bot.catch_resume_at: + if self.bot.catch_disabled and not self.bot.catch_limit_reached and now >= self.bot.catch_resume_at: if balls_on_hand > self.min_balls: self.emit_event( 'catch_limit_off', - formatted="Resume time has passed and balls on hand ({}) exceeds threshold {}. Re-enabling catch tasks.". - format(balls_on_hand,self.min_balls) - ) + formatted="Resume time has passed and balls on hand ({}) exceeds threshold {}. Re-enabling catch tasks.".format( + balls_on_hand, + self.min_balls)) self.bot.catch_disabled = False - # If currently not catching, but balls >= resume_at_balls - if self.bot.catch_disabled and balls_on_hand >= self.resume_at_balls: + # If balls_on_hand is more than resume_at_balls, + # resume catch tasks, if not softbanned + if ( + self.bot.softban is False and + self.bot.catch_disabled and + balls_on_hand >= self.resume_at_balls + ): self.emit_event( 'catch_limit_off', - formatted="Resume time hasn't passed yet, but balls on hand ({}) exceeds threshold {}. Re-enabling catch tasks.". - format(balls_on_hand, self.resume_at_balls) - ) + formatted="Resume time hasn't passed yet, but balls on hand ({}) exceeds threshold {}. Re-enabling catch tasks.".format( + balls_on_hand, + self.resume_at_balls)) self.bot.catch_disabled = False - # If balls_on_hand less than threshold, pause catching tasks for duration minutes + # If balls_on_hand less than threshold, + # pause catching tasks for duration minutes if not self.bot.catch_disabled and balls_on_hand <= self.min_balls: - self.bot.catch_resume_at = now + timedelta(minutes = self.duration) + self.bot.catch_resume_at = now + timedelta(minutes=self.duration) + self.no_log_until = now + timedelta(minutes=2) self.bot.catch_disabled = True self.emit_event( 'catch_limit_on', - formatted="Balls on hand ({}) has reached threshold {}. Disabling catch tasks until {} or balls on hand > threshold (whichever is later).". - format(balls_on_hand, self.min_balls, self.bot.catch_resume_at.strftime("%H:%M:%S")) - ) + formatted=( + "Balls on hand ({}) has reached threshold {}." + " Disabling catch tasks until {} or balls on hand > threshold (whichever is later).").format( + balls_on_hand, + self.min_balls, + self.bot.catch_resume_at.strftime("%H:%M:%S"))) + + if self.bot.catch_disabled and self.no_log_until <= now: + if now >= self.bot.catch_resume_at: + self.logger.info( + "All catch tasks disabled until balls on hand (%s) > threshold." % + balls_on_hand) + else: + self.logger.info( + "All catch tasks disabled until %s or balls on hand (%s) >= %s" % + (self.bot.catch_resume_at.strftime("%H:%M:%S"), + balls_on_hand, + self.resume_at_balls)) + self.no_log_until = now + timedelta(minutes=2) return WorkerResult.SUCCESS def get_pokeball_count(self): - return sum([inventory.items().get(ball.value).count for ball in [Item.ITEM_POKE_BALL, Item.ITEM_GREAT_BALL, Item.ITEM_ULTRA_BALL]]) + return sum([inventory.items().get(ball.value).count for ball in [ + Item.ITEM_POKE_BALL, + Item.ITEM_GREAT_BALL, + Item.ITEM_ULTRA_BALL] + ]) diff --git a/pokemongo_bot/cell_workers/gym_pokemon.py b/pokemongo_bot/cell_workers/gym_pokemon.py index fdd567d9f4..be9e4f4816 100644 --- a/pokemongo_bot/cell_workers/gym_pokemon.py +++ b/pokemongo_bot/cell_workers/gym_pokemon.py @@ -661,14 +661,18 @@ def get_poke_info(info, pokemon): if info not in poke_info: raise ConfigException("order by {}' isn't available".format(self.order_by)) return poke_info[info] + legendaries = ["Lugia", "Zapdos", "HoOh", "Celebi", "Articuno", "Moltres", "Mewtwo", "Mew"] # Don't place a Pokemon which is already in the gym (prevent ALL Blissey etc) possible_pokemons = [p for p in self.pokemons if not p.name in current_pokemons] # Don't put in Pokemon above 3000 cp (morale drops too fast) possible_pokemons = [p for p in possible_pokemons if p.cp < 3000 and p.name not in self.ignore_max_cp_pokemon] # Filter out "bad" Pokemon possible_pokemons = [p for p in possible_pokemons if not p.is_bad] + # Ignore legendaries for in Gyms + possible_pokemons = [p for p in possible_pokemons if not p.name in legendaries] # Filter out "never place" Pokemon possible_pokemons = [p for p in possible_pokemons if p.name not in self.never_place] + # HP Must be max possible_pokemons = [p for p in possible_pokemons if p.hp == p.hp_max] possible_pokemons = [p for p in possible_pokemons if not p.in_fort] diff --git a/pokemongo_bot/event_manager.py b/pokemongo_bot/event_manager.py index bad43c0661..52549d8c53 100644 --- a/pokemongo_bot/event_manager.py +++ b/pokemongo_bot/event_manager.py @@ -52,6 +52,13 @@ def __init__(self, event, sender=None, level='info', formatted='', data={}): self.sender = str(sender).encode('ascii', 'xmlcharrefreplace') self.level = str(level).encode('ascii', 'xmlcharrefreplace') + + #Fixing issue 6123 for gym names that are in utf format. + try: + self.formatted = str(formatted).encode('ascii', 'xmlcharrefreplace') + except UnicodeEncodeError: + self.formatted = str(unicode(formatted).encode('unicode_escape')) + self.data = str(data).encode('ascii', 'xmlcharrefreplace') self.friendly_msg = "" diff --git a/runMultiBot.sh b/runMultiBot.sh new file mode 100644 index 0000000000..2f8bc98fed --- /dev/null +++ b/runMultiBot.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +pokebotpath=$(cd "$(dirname "$0")"; pwd) +cd $pokebotpath +source bin/activate 2> /dev/null +if [[ $? -eq 1 ]]; +then + echo "Virtualenv does not exits" + echo "Run: ./setup.sh -i" + exit 1 +fi +git fetch -a +installed=(`pip list 2>/dev/null |sed -e 's/ //g' -e 's/(/:/' -e 's/)//' -e 's/[-_]//g' | awk '{print tolower($0)}'`) +required=(`cat requirements.txt | sed -e 's/.*pgoapi$/pgoapi==1.2.0/' -e 's/[-_]//g' -e 's/==\(.*\)/:\1/' | awk '{print tolower($0)}'`) +for package in ${required[@]} +do + if [[ ! (${installed[*]} =~ $package) ]]; + then + echo "Some of the required packages are not found / have different version." + echo "Run: ./setup.sh -u" + exit 1 + fi +done +if [ "1" == $(git branch -vv |grep -c "* dev") ] && [ $(git log --pretty=format:"%h" -1) != $(git log --pretty=format:"%h" -1 origin/dev) ] || + [ "1" == $(git branch -vv |grep -c "* master") ] && [ $(git log --pretty=format:"%h" -1) != $(git log --pretty=format:"%h" -1 origin/master) ] +then + read -p "Branch has an update. Run ./setup.sh -u to update? y/n + " do_setup + if [[ $do_setup = "y" || $do_setup = "Y" ]]; + then + ./setup.sh -u + fi +fi +python MultiBot.py +done +exit 0 diff --git a/windows_bat/PokemonGo-Bot-MultiBot-Start.bat b/windows_bat/PokemonGo-Bot-MultiBot-Start.bat new file mode 100644 index 0000000000..6745d81d4b --- /dev/null +++ b/windows_bat/PokemonGo-Bot-MultiBot-Start.bat @@ -0,0 +1,72 @@ +TITLE PokemonGo-Bot +CLS +@ECHO OFF + + + +:init +setlocal DisableDelayedExpansion +path c:\Program Files\Git\cmd;%PATH% +path C:\Python27;%PATH% +path C:\Python27\Scripts;%PATH% +set "batchPath=%~0" +for %%k in (%0) do set batchName=%%~nk +set "vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs" +setlocal EnableDelayedExpansion + + + +:checkPrivileges +NET FILE 1>NUL 2>NUL +if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges ) + + + +:getPrivileges +if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges) +@ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%" +@ECHO args = "ELEV " >> "%vbsGetPrivileges%" +@ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%" +@ECHO args = args ^& strArg ^& " " >> "%vbsGetPrivileges%" +@ECHO Next >> "%vbsGetPrivileges%" +@ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%" +"%SystemRoot%\System32\WScript.exe" "%vbsGetPrivileges%" %* +exit /B + + + +:gotPrivileges +setlocal & pushd . +cd /d %~dp0 +if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul & shift /1) + + + +:startBot +REM CLS +REM ECHO. +REM ECHO. +REM ECHO --------------------Initializing web server-------------------- +REM ECHO. +REM ECHO. +REM set BatchPath="%~dp0" +REM start cmd.exe /k "CD %BatchPath%&CD..&CD web&python -m SimpleHTTPServer" +REM ECHO. +REM ECHO. +CLS +ECHO --------------------Starting bot-------------------- +ECHO. +ECHO. + + + +:loop +TITLE=PokemonGo-Bot +CD %BatchPath% +CD .. +python MultiBot.py +if errorlevel 1 goto restart +if errorlevel 0 goto eof + +:eof +exit