Merge pull request #125 from fishyboteso/improvement/resilient-qr

This commit is contained in:
Adam Saudagar 2022-06-30 22:28:42 +05:30 committed by GitHub
commit dfc3c14c2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 46 deletions

View File

@ -3,11 +3,38 @@ import re
import cv2 import cv2
import numpy as np import numpy as np
from fishy.engine.common.window import WindowClient
detector = cv2.QRCodeDetector() detector = cv2.QRCodeDetector()
def image_pre_process(img): # noinspection PyBroadException
def get_values(window: WindowClient):
values = None
for _ in range(5):
img = window.processed_image(func=_image_pre_process)
if img is None:
logging.debug("Couldn't capture window.")
continue
if not window.crop:
window.crop = _get_qr_location(img)
if not window.crop:
logging.debug("FishyQR not found.")
continue
img = window.processed_image(func=_image_pre_process)
values = _get_values_from_image(img)
if not values:
window.crop = None
logging.debug("Values not able to read.")
continue
break
return values
def _image_pre_process(img):
scale_percent = 100 # percent of original size scale_percent = 100 # percent of original size
width = int(img.shape[1] * scale_percent / 100) width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100) height = int(img.shape[0] * scale_percent / 100)
@ -16,7 +43,7 @@ def image_pre_process(img):
return img return img
def get_qr_location(image): def _get_qr_location(image):
""" """
code from https://stackoverflow.com/a/45770227/4512396 code from https://stackoverflow.com/a/45770227/4512396
""" """
@ -29,16 +56,15 @@ def get_qr_location(image):
return [int(x) for x in [p[0][0], p[0][1], p[1][0], p[2][1]]] return [int(x) for x in [p[0][0], p[0][1], p[1][0], p[2][1]]]
# noinspection PyBroadException def _get_values_from_image(img):
def get_values_from_image(img):
h, w = img.shape h, w = img.shape
points = np.array([[(0, 0), (w, 0), (w, h), (0, h)]]) points = np.array([[(0, 0), (w, 0), (w, h), (0, h)]])
code = detector.decode(img, points)[0] code = detector.decode(img, points)[0]
return parse_qr_code(code) return _parse_qr_code(code)
# this needs to be updated each time qr code format is changed # this needs to be updated each time qr code format is changed
def parse_qr_code(code): def _parse_qr_code(code):
if not code: if not code:
return None return None
match = re.match(r'^(-?\d+\.\d+),(-?\d+\.\d+),(-?\d+),(\d+)$', code) match = re.match(r'^(-?\d+\.\d+),(-?\d+\.\d+),(-?\d+),(\d+)$', code)

View File

@ -3,6 +3,7 @@ import math
import time import time
from threading import Thread from threading import Thread
from fishy.engine.common import qr_detection
from pynput import keyboard, mouse from pynput import keyboard, mouse
from fishy.engine import SemiFisherEngine from fishy.engine import SemiFisherEngine
@ -12,8 +13,6 @@ from fishy.engine.fullautofisher.mode.calibrator import Calibrator
from fishy.engine.fullautofisher.mode.imode import FullAutoMode from fishy.engine.fullautofisher.mode.imode import FullAutoMode
from fishy.engine.fullautofisher.mode.player import Player from fishy.engine.fullautofisher.mode.player import Player
from fishy.engine.fullautofisher.mode.recorder import Recorder from fishy.engine.fullautofisher.mode.recorder import Recorder
from fishy.engine.common.qr_detection import (get_qr_location,
get_values_from_image, image_pre_process)
from fishy.engine.semifisher import fishing_mode from fishy.engine.semifisher import fishing_mode
from fishy.engine.semifisher.fishing_mode import FishingMode from fishy.engine.semifisher.fishing_mode import FishingMode
from fishy.helper.config import config from fishy.helper.config import config
@ -60,7 +59,13 @@ class FullAuto(IEngine):
logging.info("starting in 2 secs...") logging.info("starting in 2 secs...")
time.sleep(2) time.sleep(2)
if not self._pre_run_checks(): if not (type(self.mode) is Calibrator) and not self.calibrator.all_calibrated():
logging.error("you need to calibrate first")
return
if not qr_detection.get_values(self.window):
logging.error("FishyQR not found, if its not hidden, try to drag it around, "
"or increase/decrease its size and try again\nStopping engine...")
return return
if config.get("tabout_stop", 1): if config.get("tabout_stop", 1):
@ -73,26 +78,10 @@ class FullAuto(IEngine):
logging.error("exception occurred while running full auto mode") logging.error("exception occurred while running full auto mode")
print_exc() print_exc()
def _pre_run_checks(self):
if self.window.get_capture() is None:
logging.error("Game window not found")
return False
self.window.crop = get_qr_location(self.window.get_capture())
if self.window.crop is None:
logging.error("FishyQR not found, try to drag it around and try again")
return False
if not (type(self.mode) is Calibrator) and not self.calibrator.all_calibrated():
logging.error("you need to calibrate first")
return False
return True
def start_show(self): def start_show(self):
def func(): def func():
while self.start and WindowClient.running(): while self.start and WindowClient.running():
self.window.show(self.show_crop, func=image_pre_process) self.window.show(self.show_crop)
Thread(target=func).start() Thread(target=func).start()
def stop_on_inactive(self): def stop_on_inactive(self):
@ -111,8 +100,7 @@ class FullAuto(IEngine):
todo find a better way of handling None: switch from start bool to state which knows todo find a better way of handling None: switch from start bool to state which knows
todo its waiting for qr which doesn't block the engine when commanded to close todo its waiting for qr which doesn't block the engine when commanded to close
""" """
img = self.window.processed_image(func=image_pre_process) values = qr_detection.get_values(self.window)
values = get_values_from_image(img)
return values[:3] if values else None return values[:3] if values else None
def move_to(self, target) -> bool: def move_to(self, target) -> bool:

View File

@ -4,10 +4,11 @@ import typing
from threading import Thread from threading import Thread
from typing import Callable, Optional from typing import Callable, Optional
from fishy.engine.common import qr_detection
from fishy.engine.semifisher.fishing_mode import FishingMode from fishy.engine.semifisher.fishing_mode import FishingMode
from fishy.engine.common.IEngine import IEngine from fishy.engine.common.IEngine import IEngine
from fishy.engine.common.qr_detection import get_qr_location, get_values_from_image, image_pre_process
from fishy.engine.common.window import WindowClient from fishy.engine.common.window import WindowClient
from fishy.engine.semifisher import fishing_event, fishing_mode from fishy.engine.semifisher import fishing_event, fishing_mode
from fishy.engine.semifisher.fishing_event import FishEvent from fishy.engine.semifisher.fishing_event import FishEvent
@ -35,15 +36,6 @@ class SemiFisherEngine(IEngine):
Thread(target=self._wait_and_check).start() Thread(target=self._wait_and_check).start()
time.sleep(0.2) time.sleep(0.2)
capture = self.window.get_capture()
if capture is None:
logging.error("couldn't get game capture")
return
self.window.crop = get_qr_location(capture)
if not self.window.crop:
logging.error("FishyQR not found, try to drag it around and try again")
return
fishing_event.init() fishing_event.init()
# noinspection PyBroadException # noinspection PyBroadException
@ -59,15 +51,9 @@ class SemiFisherEngine(IEngine):
def _engine_loop(self): def _engine_loop(self):
skip_count = 0 skip_count = 0
while self.state == 1 and WindowClient.running(): while self.state == 1 and WindowClient.running():
capture = self.window.processed_image(func=image_pre_process)
# if window server crashed
if capture is None:
logging.error("Couldn't capture window stopping engine")
return
# crop qr and get the values from it # crop qr and get the values from it
self.values = get_values_from_image(capture) self.values = qr_detection.get_values(self.window)
# if fishyqr fails to get read multiple times, stop the bot # if fishyqr fails to get read multiple times, stop the bot
if not self.values: if not self.values:
if skip_count >= 5: if skip_count >= 5: