def __init__(self, args, dev_id, origin, last_known_state, communicator: AbstractCommunicator, mapping_manager: MappingManager, area_id: int, routemanager_name: str, db_wrapper: DbWrapper, pogo_window_manager: PogoWindows, walker=None, event=None): AbstractWorker.__init__(self, origin=origin, communicator=communicator) self._mapping_manager: MappingManager = mapping_manager self._routemanager_name: str = routemanager_name self._area_id = area_id self._dev_id: int = dev_id self._event = event self._origin: str = origin self._applicationArgs = args self._last_known_state = last_known_state self._work_mutex = Lock() self.loop = None self.loop_started = Event() self.loop_tid = None self._async_io_looper_thread = None self._location_count = 0 self._init: bool = self._mapping_manager.routemanager_get_init( self._routemanager_name) self._walker = walker self._lastScreenshotTaken = 0 self._stop_worker_event = Event() self._db_wrapper = db_wrapper self._resocalc = Resocalculator self._screen_x = 0 self._screen_y = 0 self._geofix_sleeptime = 0 self._pogoWindowManager = pogo_window_manager self._waittime_without_delays = 0 self._transporttype = 0 self._not_injected_count: int = 0 self._same_screen_count: int = 0 self._last_screen_type: ScreenType = ScreenType.UNDEFINED self._loginerrorcounter: int = 0 self._mode = self._mapping_manager.routemanager_get_mode( self._routemanager_name) self._levelmode = self._mapping_manager.routemanager_get_level( self._routemanager_name) self._geofencehelper = self._mapping_manager.routemanager_get_geofence_helper( self._routemanager_name) self.current_location = Location(0.0, 0.0) self.last_location = self.get_devicesettings_value( "last_location", None) if self.last_location is None: self.last_location = Location(0.0, 0.0) if self.get_devicesettings_value('last_mode', None) is not None and \ self.get_devicesettings_value('last_mode') in ("raids_mitm", "mon_mitm", "iv_mitm"): # Reset last_location - no useless waiting delays (otherwise stop mode) self.last_location = Location(0.0, 0.0) self.set_devicesettings_value( "last_mode", self._mapping_manager.routemanager_get_mode( self._routemanager_name)) self.workerstart = None self._WordToScreenMatching = WordToScreenMatching( self._communicator, self._pogoWindowManager, self._origin, self._resocalc, mapping_manager, self._applicationArgs)
class WorkerBase(AbstractWorker): def __init__(self, args, dev_id, origin, last_known_state, communicator: AbstractCommunicator, mapping_manager: MappingManager, area_id: int, routemanager_name: str, db_wrapper: DbWrapper, pogo_window_manager: PogoWindows, walker=None, event=None): AbstractWorker.__init__(self, origin=origin, communicator=communicator) self._mapping_manager: MappingManager = mapping_manager self._routemanager_name: str = routemanager_name self._area_id = area_id self._dev_id: int = dev_id self._event = event self._origin: str = origin self._applicationArgs = args self._last_known_state = last_known_state self._work_mutex = Lock() self.loop = None self.loop_started = Event() self.loop_tid = None self._async_io_looper_thread = None self._location_count = 0 self._init: bool = self._mapping_manager.routemanager_get_init( self._routemanager_name) self._walker = walker self._lastScreenshotTaken = 0 self._stop_worker_event = Event() self._db_wrapper = db_wrapper self._resocalc = Resocalculator self._screen_x = 0 self._screen_y = 0 self._geofix_sleeptime = 0 self._pogoWindowManager = pogo_window_manager self._waittime_without_delays = 0 self._transporttype = 0 self._not_injected_count: int = 0 self._same_screen_count: int = 0 self._last_screen_type: ScreenType = ScreenType.UNDEFINED self._loginerrorcounter: int = 0 self._mode = self._mapping_manager.routemanager_get_mode( self._routemanager_name) self._levelmode = self._mapping_manager.routemanager_get_level( self._routemanager_name) self._geofencehelper = self._mapping_manager.routemanager_get_geofence_helper( self._routemanager_name) self.current_location = Location(0.0, 0.0) self.last_location = self.get_devicesettings_value( "last_location", None) if self.last_location is None: self.last_location = Location(0.0, 0.0) if self.get_devicesettings_value('last_mode', None) is not None and \ self.get_devicesettings_value('last_mode') in ("raids_mitm", "mon_mitm", "iv_mitm"): # Reset last_location - no useless waiting delays (otherwise stop mode) self.last_location = Location(0.0, 0.0) self.set_devicesettings_value( "last_mode", self._mapping_manager.routemanager_get_mode( self._routemanager_name)) self.workerstart = None self._WordToScreenMatching = WordToScreenMatching( self._communicator, self._pogoWindowManager, self._origin, self._resocalc, mapping_manager, self._applicationArgs) def set_devicesettings_value(self, key: str, value): self._mapping_manager.set_devicesetting_value_of( self._origin, key, value) def get_devicesettings_value(self, key: str, default_value: object = None): self.logger.debug("Fetching devicemappings") try: devicemappings: Optional[ dict] = self._mapping_manager.get_devicemappings_of( self._origin) except (EOFError, FileNotFoundError) as e: self.logger.warning( "Failed fetching devicemappings in with description: {}. Stopping worker", e) self._stop_worker_event.set() return None if devicemappings is None: return default_value return devicemappings.get("settings", {}).get(key, default_value) def get_screenshot_path(self, fileaddon: bool = False) -> str: screenshot_ending: str = ".jpg" addon: str = "" if self.get_devicesettings_value("screenshot_type", "jpeg") == "png": screenshot_ending = ".png" if fileaddon: addon: str = "_" + str(time.time()) screenshot_filename = "screenshot_{}{}{}".format( str(self._origin), str(addon), screenshot_ending) if fileaddon: self.logger.info("Creating debugscreen: {}", screenshot_filename) return os.path.join(self._applicationArgs.temp_path, screenshot_filename) def check_max_walkers_reached(self): walkermax = self._walker.get('walkermax', False) if walkermax is False or (type(walkermax) is str and len(walkermax) == 0): return True reg_workers = self._mapping_manager.routemanager_get_registered_workers( self._routemanager_name) if len(reg_workers) > int(walkermax): return False return True @abstractmethod def _pre_work_loop(self): """ Work to be done before the main while true work-loop Start off asyncio loops etc in here :return: """ pass @abstractmethod def _health_check(self): """ Health check before a location is grabbed. Internally, a self._start_pogo call is already executed since that usually includes a topmost check :return: """ pass @abstractmethod def _pre_location_update(self): """ Override to run stuff like update injections settings in MITM worker Runs before walk/teleport to the location previously grabbed :return: """ pass @abstractmethod def _move_to_location(self): """ Location has previously been grabbed, the overriden function will be called. You may teleport or walk by your choosing Any post walk/teleport delays/sleeps have to be run in the derived, override method :return: """ pass @abstractmethod def _post_move_location_routine(self, timestamp): """ Routine called after having moved to a new location. MITM worker e.g. has to wait_for_data :param timestamp: :return: """ @abstractmethod def _cleanup(self): """ Cleanup any threads you started in derived classes etc self.stop_worker() and self.loop.stop() will be called afterwards :return: """ @abstractmethod def _worker_specific_setup_start(self): """ Routine preparing the state to scan. E.g. starting specific apps or clearing certain files Returns: """ @abstractmethod def _worker_specific_setup_stop(self): """ Routine destructing the state to scan. E.g. stopping specific apps or clearing certain files Returns: """ def _start_asyncio_loop(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.loop_tid = current_thread() self.loop.call_soon(self.loop_started.set) self.loop.run_forever() def _add_task_to_loop(self, coro): create_task = functools.partial(self.loop.create_task, coro) if current_thread() == self.loop_tid: # We can call directly if we're not going between threads. return create_task() else: # We're in a non-event loop thread so we use a Future # to get the task from the event loop thread once # it's ready. return self.loop.call_soon_threadsafe(create_task) def start_worker(self): t_main_work = Thread(name=self._origin, target=self._main_work_thread) t_main_work.daemon = True t_main_work.start() # do some other stuff in the main process while not self._stop_worker_event.isSet(): time.sleep(1) while t_main_work.is_alive(): time.sleep(1) t_main_work.join() self.logger.info("Worker stopped gracefully") return self._last_known_state def stop_worker(self): if self._stop_worker_event.set(): self.logger.info('Worker already stopped - waiting for it') else: self._stop_worker_event.set() self.logger.warning("Worker stop called") def _internal_pre_work(self): current_thread().name = self._origin start_position = self.get_devicesettings_value("startcoords_of_walker", None) calc_type = self._mapping_manager.routemanager_get_calc_type( self._routemanager_name) if start_position and (self._levelmode and calc_type == "routefree"): startcoords = self.get_devicesettings_value("startcoords_of_walker").replace(' ', '') \ .replace('_', '').split(',') if not self._geofencehelper.is_coord_inside_include_geofence( Location(float(startcoords[0]), float(startcoords[1]))): self.logger.warning( "Startcoords not in geofence - setting middle of fence as starting position" ) lat, lng = self._geofencehelper.get_middle_from_fence() start_position = str(lat) + "," + str(lng) if start_position is None and \ (self._levelmode and calc_type == "routefree"): self.logger.warning( "Starting level mode without worker start position") # setting coords lat, lng = self._geofencehelper.get_middle_from_fence() start_position = str(lat) + "," + str(lng) if start_position is not None: startcoords = start_position.replace(' ', '').replace('_', '').split(',') if not self._geofencehelper.is_coord_inside_include_geofence( Location(float(startcoords[0]), float(startcoords[1]))): self.logger.warning( "Startcoords not in geofence - setting middle of fence as startposition" ) lat, lng = self._geofencehelper.get_middle_from_fence() start_position = str(lat) + "," + str(lng) startcoords = start_position.replace(' ', '').replace('_', '').split(',') self.logger.info('Setting startcoords or walker lat {} / lng {}', startcoords[0], startcoords[1]) self._communicator.set_location( Location(startcoords[0], startcoords[1]), 0) self._mapping_manager.set_worker_startposition( routemanager_name=self._routemanager_name, worker_name=self._origin, lat=float(startcoords[0]), lon=float(startcoords[1])) with self._work_mutex: try: self._turn_screen_on_and_start_pogo() self._get_screen_size() # register worker in routemanager self.logger.info( "Try to register in Routemanager {}", self._mapping_manager.routemanager_get_name( self._routemanager_name)) self._mapping_manager.register_worker_to_routemanager( self._routemanager_name, self._origin) except WebsocketWorkerRemovedException: self.logger.error("Timeout during init of worker") # no cleanup required here? TODO: signal websocket server somehow self._stop_worker_event.set() return self._async_io_looper_thread = Thread(name=self._origin, target=self._start_asyncio_loop) self._async_io_looper_thread.daemon = True self._async_io_looper_thread.start() self.loop_started.wait() self._pre_work_loop() def _internal_health_check(self): # check if pogo is topmost and start if necessary self.logger.debug4( "_internal_health_check: Calling _start_pogo routine to check if pogo is topmost" ) pogo_started = False with self._work_mutex: self.logger.debug2("_internal_health_check: worker lock acquired") self.logger.debug4("Checking if we need to restart pogo") # Restart pogo every now and then... restart_pogo_setting = self.get_devicesettings_value( "restart_pogo", 0) if restart_pogo_setting > 0: if self._location_count > restart_pogo_setting: self.logger.info("scanned {} locations, restarting game", restart_pogo_setting) pogo_started = self._restart_pogo() self._location_count = 0 else: pogo_started = self._start_pogo() else: pogo_started = self._start_pogo() self.logger.debug4("_internal_health_check: worker lock released") return pogo_started def _internal_cleanup(self): # set the event just to make sure - in case of exceptions for example self._stop_worker_event.set() try: self._mapping_manager.unregister_worker_from_routemanager( self._routemanager_name, self._origin) except ConnectionResetError as e: self.logger.warning( "Failed unregistering from routemanager, routemanager may have stopped running already." "Exception: {}", e) self.logger.info("Internal cleanup of started") self._cleanup() self.logger.info("Internal cleanup signaling end to websocketserver") if self._async_io_looper_thread is not None: self.logger.info("Stopping worker's asyncio loop") self.loop.call_soon_threadsafe(self.loop.stop) self._async_io_looper_thread.join() self._communicator.cleanup() self.logger.info("Internal cleanup of finished") def _main_work_thread(self): # TODO: signal websocketserver the removal try: self._internal_pre_work() except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException, WebsocketWorkerConnectionClosedException): self.logger.error( "Failed initializing worker, connection terminated exceptionally" ) self._internal_cleanup() return if not self.check_max_walkers_reached(): self.logger.warning( 'Max. Walkers in Area {} - closing connections', self._mapping_manager.routemanager_get_name( self._routemanager_name)) self.set_devicesettings_value('finished', True) self._internal_cleanup() return while not self._stop_worker_event.isSet(): try: # TODO: consider getting results of health checks and aborting the entire worker? walkercheck = self.check_walker() if not walkercheck: self.set_devicesettings_value('finished', True) break except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException, WebsocketWorkerConnectionClosedException): self.logger.warning("Worker killed by walker settings") break try: # TODO: consider getting results of health checks and aborting the entire worker? self._internal_health_check() self._health_check() except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException, WebsocketWorkerConnectionClosedException): self.logger.error( "Websocket connection to lost while running healthchecks, connection terminated " "exceptionally") break try: settings = self._internal_grab_next_location() if settings is None: continue except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException, WebsocketWorkerConnectionClosedException): self.logger.warning( "Worker of does not support mode that's to be run, connection terminated " "exceptionally") break try: self.logger.debug('Checking if new location is valid') valid = self._check_location_is_valid() if not valid: break except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException, WebsocketWorkerConnectionClosedException): self.logger.warning("Worker received non valid coords!") break try: self._pre_location_update() except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException, WebsocketWorkerConnectionClosedException): self.logger.warning( "Worker of stopping because of stop signal in pre_location_update, connection " "terminated exceptionally") break try: self.logger.debug2( 'LastLat: {}, LastLng: {}, CurLat: {}, CurLng: {}', self.get_devicesettings_value("last_location", Location(0, 0)).lat, self.get_devicesettings_value("last_location", Location(0, 0)).lng, self.current_location.lat, self.current_location.lng) time_snapshot, process_location = self._move_to_location() except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException, WebsocketWorkerConnectionClosedException): self.logger.warning( "Worker failed moving to new location, stopping worker, connection terminated " "exceptionally") break if process_location: self._add_task_to_loop(self._update_position_file()) self._location_count += 1 if self._applicationArgs.last_scanned: self.logger.debug( "Seting new 'scannedlocation' in Database") self._add_task_to_loop( self.update_scanned_location(self.current_location.lat, self.current_location.lng, time_snapshot)) try: self._post_move_location_routine(time_snapshot) except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException, WebsocketWorkerConnectionClosedException): self.logger.warning( "Worker failed running post_move_location_routine, stopping worker" ) break self.logger.info("Worker finished iteration, continuing work") self._internal_cleanup() async def _update_position_file(self): self.logger.debug2("Updating .position file") if self.current_location is not None: with open( os.path.join(self._applicationArgs.file_path, self._origin + '.position'), 'w') as outfile: outfile.write( str(self.current_location.lat) + ", " + str(self.current_location.lng)) async def update_scanned_location(self, latitude, longitude, timestamp): try: self._db_wrapper.set_scanned_location(str(latitude), str(longitude)) except Exception as e: self.logger.error("Failed updating scanned location: {}", e) return def check_walker(self): mode = self._walker['walkertype'] walkereventid = self._walker.get('eventid', None) if walkereventid is not None and walkereventid != self._event.get_current_event_id( ): self.logger.warning("A other Event has started - leaving now") return False if mode == "countdown": self.logger.info("Checking walker mode 'countdown'") countdown = self._walker['walkervalue'] if not countdown: self.logger.error( "No Value for Mode - check your settings! Killing worker") return False if self.workerstart is None: self.workerstart = math.floor(time.time()) else: if math.floor( time.time()) >= int(self.workerstart) + int(countdown): return False return True elif mode == "timer": self.logger.debug("Checking walker mode 'timer'") exittime = self._walker['walkervalue'] if not exittime or ':' not in exittime: self.logger.error( "No or wrong Value for Mode - check your settings! Killing worker" ) return False return check_walker_value_type(exittime) elif mode == "round": self.logger.debug("Checking walker mode 'round'") rounds = self._walker['walkervalue'] if len(rounds) == 0: self.logger.error( "No Value for Mode - check your settings! Killing worker") return False processed_rounds = self._mapping_manager.routemanager_get_rounds( self._routemanager_name, self._origin) if int(processed_rounds) >= int(rounds): return False return True elif mode == "period": self.logger.debug("Checking walker mode 'period'") period = self._walker['walkervalue'] if len(period) == 0: self.logger.error( "No Value for Mode - check your settings! Killing worker") return False return check_walker_value_type(period) elif mode == "coords": exittime = self._walker['walkervalue'] if len(exittime) > 0: return check_walker_value_type(exittime) return True elif mode == "idle": self.logger.debug("Checking walker mode 'idle'") if len(self._walker['walkervalue']) == 0: self.logger.error( "Wrong Value for mode - check your settings! Killing worker" ) return False sleeptime = self._walker['walkervalue'] self.logger.info('going to sleep') killpogo = False if check_walker_value_type(sleeptime): self._stop_pogo() killpogo = True while not self._stop_worker_event.isSet( ) and check_walker_value_type(sleeptime): time.sleep(1) self.logger.info('just woke up') if killpogo: self._start_pogo() return False else: self.logger.error("Unknown walker mode! Killing worker") return False def set_geofix_sleeptime(self, sleeptime: int) -> bool: self._geofix_sleeptime = sleeptime return True def _internal_grab_next_location(self): # TODO: consider adding runWarningThreadEvent.set() self._last_known_state["last_location"] = self.last_location self.logger.debug("Requesting next location from routemanager") # requesting a location is blocking (iv_mitm will wait for a prioQ item), we really need to clean # the workers up... if int(self._geofix_sleeptime) > 0: self.logger.info( 'Getting a geofix position from MADMin - sleeping for {} seconds', self._geofix_sleeptime) time.sleep(int(self._geofix_sleeptime)) self._geofix_sleeptime = 0 self._check_for_mad_job() self.current_location = self._mapping_manager.routemanager_get_next_location( self._routemanager_name, self._origin) return self._mapping_manager.routemanager_get_settings( self._routemanager_name) def _check_for_mad_job(self): if self.get_devicesettings_value("job", False): self.logger.info("Worker get a job - waiting") while self.get_devicesettings_value( "job", False) and not self._stop_worker_event.is_set(): time.sleep(10) self.logger.info("Worker processed the job and go on ") def _check_location_is_valid(self): if self.current_location is None: # there are no more coords - so worker is finished successfully self.set_devicesettings_value('finished', True) return None elif self.current_location is not None: self.logger.debug2('Coords are valid') return True def _turn_screen_on_and_start_pogo(self): if not self._communicator.is_screen_on(): self._communicator.start_app("de.grennith.rgc.remotegpscontroller") self.logger.warning("Turning screen on") self._communicator.turn_screen_on() time.sleep( self.get_devicesettings_value("post_turn_screen_on_delay", 2)) # check if pogo is running and start it if necessary self.logger.info("turnScreenOnAndStartPogo: (Re-)Starting Pogo") self._start_pogo() def _ensure_pogo_topmost(self): self.logger.info('Checking pogo screen...') while not self._stop_worker_event.is_set(): screen_type: ScreenType = self._WordToScreenMatching.detect_screentype( ) if screen_type in [ScreenType.POGO, ScreenType.QUEST]: self._last_screen_type = screen_type self._loginerrorcounter = 0 self.logger.debug2("Found pogo or questlog to be open") break if screen_type != ScreenType.ERROR and self._last_screen_type == screen_type: self._same_screen_count += 1 self.logger.warning("Found {} multiple times in a row ({})", screen_type, self._same_screen_count) if self._same_screen_count > 3: self.logger.warning("Screen is frozen!") if self._same_screen_count > 4 or not self._restart_pogo(): self.logger.error( "Restarting PoGo failed - reboot device") self._reboot() break elif self._last_screen_type != screen_type: self._same_screen_count = 0 # now handle all screens that may not have been handled by detect_screentype since that only clicks around # so any clearing data whatsoever happens here (for now) if screen_type == ScreenType.UNDEFINED: self.logger.error("Undefined screentype!") elif screen_type == ScreenType.BLACK: self.logger.info("Found Black Loading Screen - waiting ...") time.sleep(20) elif screen_type == ScreenType.CLOSE: self.logger.debug( "screendetection found pogo closed, start it...") self._start_pogo() self._loginerrorcounter += 1 elif screen_type in [ScreenType.GAMEDATA, ScreenType.CONSENT]: self.logger.warning( 'Error getting Gamedata or strange ggl message appears') self._loginerrorcounter += 1 if self._loginerrorcounter < 2: self._restart_pogo_safe() elif screen_type == ScreenType.DISABLED: # Screendetection is disabled break elif screen_type == ScreenType.UPDATE: self.logger.warning( 'Found update pogo screen - sleeping 5 minutes for another check of the screen' ) # update pogo - later with new rgc version time.sleep(300) elif screen_type in [ScreenType.ERROR, ScreenType.FAILURE]: self.logger.warning( 'Something wrong with screendetection or pogo failure screen' ) self._loginerrorcounter += 1 elif screen_type == ScreenType.NOGGL: self.logger.warning( 'Detected login select screen missing the Google' ' button - likely entered an invalid birthdate previously') self._loginerrorcounter += 1 elif screen_type == ScreenType.GPS: self.logger.error("Detected GPS error - reboot device") self._reboot() break elif screen_type == ScreenType.SN: self.logger.warning( 'Getting SN Screen - restart PoGo and later PD') self._restart_pogo_safe() break if self._loginerrorcounter > 1: self.logger.error( 'Could not login again - (clearing game data + restarting device' ) self._stop_pogo() self._communicator.clear_app_cache("com.nianticlabs.pokemongo") if self.get_devicesettings_value('clear_game_data', False): self.logger.info('Clearing game data') self._communicator.reset_app_data( "com.nianticlabs.pokemongo") self._loginerrorcounter = 0 self._reboot() break self._last_screen_type = screen_type self.logger.info('Checking pogo screen is finished') return True def _restart_pogo_safe(self): self.logger.warning( "WorkerBase::_restart_pogo_safe restarting pogo the long way") self._stop_pogo() time.sleep(1) if self._applicationArgs.enable_worker_specific_extra_start_stop_handling: self._worker_specific_setup_stop() time.sleep(1) self._communicator.magisk_off() time.sleep(1) self._communicator.magisk_on() time.sleep(1) self._communicator.start_app("com.nianticlabs.pokemongo") time.sleep(25) self._stop_pogo() time.sleep(1) if self._applicationArgs.enable_worker_specific_extra_start_stop_handling: self._worker_specific_setup_start() time.sleep(1) return self._start_pogo() def _switch_user(self): self.logger.info('Switching User - please wait ...') self._stop_pogo() time.sleep(5) self._communicator.reset_app_data("com.nianticlabs.pokemongo") self._turn_screen_on_and_start_pogo() if not self._ensure_pogo_topmost(): self.logger.error('Kill Worker...') self._stop_worker_event.set() return False self.logger.info('Switching finished ...') return True def _start_pogo(self) -> bool: """ Routine to start pogo. Return the state as a boolean do indicate a successful start :return: """ pogo_topmost = self._communicator.is_pogo_topmost() if pogo_topmost: return True if not self._communicator.is_screen_on(): self._communicator.start_app("de.grennith.rgc.remotegpscontroller") self.logger.warning("Turning screen on") self._communicator.turn_screen_on() time.sleep( self.get_devicesettings_value("post_turn_screen_on_delay", 7)) cur_time = time.time() start_result = False while not pogo_topmost: start_result = self._communicator.start_app( "com.nianticlabs.pokemongo") time.sleep(1) pogo_topmost = self._communicator.is_pogo_topmost() if start_result: self.logger.success("startPogo: Started pogo successfully...") self._last_known_state["lastPogoRestart"] = cur_time self._wait_pogo_start_delay() return start_result def is_stopping(self) -> bool: return self._stop_worker_event.is_set() def _stop_pogo(self): attempts = 0 stop_result = self._communicator.stop_app("com.nianticlabs.pokemongo") pogo_topmost = self._communicator.is_pogo_topmost() while pogo_topmost: attempts += 1 if attempts > 10: return False stop_result = self._communicator.stop_app( "com.nianticlabs.pokemongo") time.sleep(1) pogo_topmost = self._communicator.is_pogo_topmost() return stop_result def _reboot(self, mitm_mapper: Optional[MitmMapper] = None): try: start_result = self._communicator.reboot() except WebsocketWorkerRemovedException: self.logger.error( "Could not reboot due to client already disconnected") start_result = False time.sleep(5) if mitm_mapper is not None: mitm_mapper.collect_location_stats( self._origin, self.current_location, 1, time.time(), 3, 0, self._mapping_manager.routemanager_get_mode( self._routemanager_name), 99) self._db_wrapper.save_last_reboot(self._dev_id) self._reboot_count = 0 self._restart_count = 0 self.stop_worker() return start_result def _restart_pogo(self, clear_cache=True, mitm_mapper: Optional[MitmMapper] = None): successful_stop = self._stop_pogo() self._db_wrapper.save_last_restart(self._dev_id) self._restart_count = 0 self.logger.debug("restartPogo: stop game resulted in {}", str(successful_stop)) if successful_stop: if clear_cache: self._communicator.clear_app_cache("com.nianticlabs.pokemongo") time.sleep(1) if mitm_mapper is not None: mitm_mapper.collect_location_stats( self._origin, self.current_location, 1, time.time(), 4, 0, self._mapping_manager.routemanager_get_mode( self._routemanager_name), 99) return self._start_pogo() else: return False def _get_trash_positions(self, full_screen=False): self.logger.debug2("_get_trash_positions: Get_trash_position.") if not self._take_screenshot( delay_before=self.get_devicesettings_value( "post_screenshot_delay", 1)): self.logger.debug( "_get_trash_positions: Failed getting screenshot") return None if os.path.isdir(self.get_screenshot_path()): self.logger.error( "_get_trash_positions: screenshot.png is not a file/corrupted") return None self.logger.debug2("_get_trash_positions: checking screen") trashes = self._pogoWindowManager.get_trash_click_positions( self._origin, self.get_screenshot_path(), full_screen=full_screen) return trashes def _take_screenshot(self, delay_after=0.0, delay_before=0.0, errorscreen: bool = False): self.logger.debug2("Taking screenshot...") time.sleep(delay_before) time_since_last_screenshot = time.time() - self._lastScreenshotTaken self.logger.debug4("Last screenshot taken: {}", str(self._lastScreenshotTaken)) # TODO: area settings for jpg/png and quality? screenshot_type: ScreenshotType = ScreenshotType.JPEG if self.get_devicesettings_value("screenshot_type", "jpeg") == "png": screenshot_type = ScreenshotType.PNG screenshot_quality: int = self.get_devicesettings_value( "screenshot_quality", 80) take_screenshot = self._communicator.get_screenshot( self.get_screenshot_path(fileaddon=errorscreen), screenshot_quality, screenshot_type) if self._lastScreenshotTaken and time_since_last_screenshot < 0.5: self.logger.error( "screenshot taken recently, returning immediately") return True elif not take_screenshot: self.logger.error("Failed retrieving screenshot") return False else: self.logger.debug("Success retrieving screenshot") self._lastScreenshotTaken = time.time() time.sleep(delay_after) return True def _check_pogo_main_screen(self, max_attempts, again=False): self.logger.debug( "_check_pogo_main_screen: Trying to get to the Mainscreen with {} max attempts...", max_attempts) pogo_topmost = self._communicator.is_pogo_topmost() if not pogo_topmost: return False if not self._take_screenshot( delay_before=self.get_devicesettings_value( "post_screenshot_delay", 1)): if again: self.logger.error( "_check_pogo_main_screen: failed getting a screenshot again" ) return False attempts = 0 screenshot_path = self.get_screenshot_path() if os.path.isdir(screenshot_path): self.logger.error( "_check_pogo_main_screen: screenshot.png/.jpg is not a file/corrupted" ) return False self.logger.debug("_check_pogo_main_screen: checking mainscreen") while not self._pogoWindowManager.check_pogo_mainscreen( screenshot_path, self._origin): self.logger.warning( "_check_pogo_main_screen: not on Mainscreen...") if attempts == max_attempts: # could not reach raidtab in given max_attempts self.logger.error( "_check_pogo_main_screen: Could not get to Mainscreen within {} attempts", max_attempts) return False found = self._pogoWindowManager.check_close_except_nearby_button( self.get_screenshot_path(), self._origin, self._communicator, close_raid=True) if found: self.logger.debug( "_check_pogo_main_screen: Found (X) button (except nearby)" ) if not found and self._pogoWindowManager.look_for_button( self._origin, screenshot_path, 2.20, 3.01, self._communicator): self.logger.debug( "_check_pogo_main_screen: Found button (small)") found = True if not found and self._pogoWindowManager.look_for_button( self._origin, screenshot_path, 1.05, 2.20, self._communicator): self.logger.debug( "_check_pogo_main_screen: Found button (big)") time.sleep(5) found = True self.logger.debug( "_check_pogo_main_screen: Previous checks found pop ups: {}", found) self._take_screenshot(delay_before=self.get_devicesettings_value( "post_screenshot_delay", 1)) attempts += 1 self.logger.debug("_check_pogo_main_screen: done") return True def _check_pogo_button(self): self.logger.debug("checkPogoButton: Trying to find buttons") pogo_topmost = self._communicator.is_pogo_topmost() if not pogo_topmost: return False if not self._take_screenshot( delay_before=self.get_devicesettings_value( "post_screenshot_delay", 1)): self.logger.debug("checkPogoButton: Failed getting screenshot") return False if os.path.isdir(self.get_screenshot_path()): self.logger.error( "checkPogoButton: screenshot.png is not a file/corrupted") return False self.logger.debug("checkPogoButton: checking for buttons") found = self._pogoWindowManager.look_for_button( self._origin, self.get_screenshot_path(), 2.20, 3.01, self._communicator) if found: time.sleep(1) self.logger.debug("checkPogoButton: Found button (small)") if not found and self._pogoWindowManager.look_for_button( self._origin, self.get_screenshot_path(), 1.05, 2.20, self._communicator): self.logger.debug("checkPogoButton: Found button (big)") found = True self.logger.debug("checkPogoButton: done") return found def _wait_pogo_start_delay(self): delay_count: int = 0 pogo_start_delay: int = self.get_devicesettings_value( "post_pogo_start_delay", 60) self.logger.info('Waiting for pogo start: {} seconds', pogo_start_delay) while delay_count <= pogo_start_delay: if not self._mapping_manager.routemanager_present(self._routemanager_name) \ or self._stop_worker_event.is_set(): self.logger.error("Killed while waiting for pogo start") raise InternalStopWorkerException time.sleep(1) delay_count += 1 def _check_pogo_close(self, takescreen=True): self.logger.debug("checkPogoClose: Trying to find closeX") pogo_topmost = self._communicator.is_pogo_topmost() if not pogo_topmost: return False if takescreen: if not self._take_screenshot( delay_before=self.get_devicesettings_value( "post_screenshot_delay", 1)): self.logger.debug("checkPogoClose: Could not get screenshot") return False if os.path.isdir(self.get_screenshot_path()): self.logger.error( "checkPogoClose: screenshot.png is not a file/corrupted") return False self.logger.debug("checkPogoClose: checking for CloseX") found = self._pogoWindowManager.check_close_except_nearby_button( self.get_screenshot_path(), self._origin, self._communicator) if found: time.sleep(1) self.logger.debug( "checkPogoClose: Found (X) button (except nearby)") self.logger.debug("checkPogoClose: done") return True self.logger.debug("checkPogoClose: done") return False def _get_screen_size(self): if self._stop_worker_event.is_set(): raise WebsocketWorkerRemovedException screen = self._communicator.get_screensize() if screen is None: raise WebsocketWorkerRemovedException screen = screen.strip().split(' ') self._screen_x = screen[0] self._screen_y = screen[1] x_offset = self.get_devicesettings_value("screenshot_x_offset", 0) y_offset = self.get_devicesettings_value("screenshot_y_offset", 0) self.logger.debug( 'Get Screensize: X: {}, Y: {}, X-Offset: {}, Y-Offset: {}', self._screen_x, self._screen_y, x_offset, y_offset) self._resocalc.get_x_y_ratio(self, self._screen_x, self._screen_y, x_offset, y_offset)