abstracted modules of fullauto engine into different scripts

This commit is contained in:
Adam Saudagar
2020-11-07 22:10:57 +05:30
parent 721c2ae7ce
commit a51a301070
7 changed files with 259 additions and 184 deletions

View File

@ -2,6 +2,9 @@ import math
import logging import logging
import time import time
import cv2
import numpy as np
from fishy.engine.fullautofisher.engine import FullAuto from fishy.engine.fullautofisher.engine import FullAuto
from pynput import keyboard, mouse from pynput import keyboard, mouse
@ -13,30 +16,77 @@ from fishy.helper.hotkey import Key
mse = mouse.Controller() mse = mouse.Controller()
kb = keyboard.Controller() kb = keyboard.Controller()
""" offset = 0
-1 callibrating speed and rotation,
0, waiting for looking up and first f8,
1, waiting for reaching down and second f8,
2 done
"""
class Calibrate(): def get_crop_coods(window):
img = window.get_capture()
img = cv2.inRange(img, 0, 1)
cnt, h = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
"""
code from https://stackoverflow.com/a/45770227/4512396
"""
for i in range(len(cnt)):
area = cv2.contourArea(cnt[i])
if 5000 < area < 100000:
mask = np.zeros_like(img)
cv2.drawContours(mask, cnt, i, 255, -1)
x, y, w, h = cv2.boundingRect(cnt[i])
return x, y + offset, x + w, y + h - offset
def _update_factor(key, value):
full_auto_factors = config.get("full_auto_factors", {})
full_auto_factors[key] = value
config.set("full_auto_factors", full_auto_factors)
def _get_factor(key):
config.get("full_auto_factors", {}).get(key)
class Calibrate:
def __init__(self, engine: FullAuto): def __init__(self, engine: FullAuto):
self._callibrate_state = -1 self._callibrate_state = -1
self.engine = engine self.engine = engine
def f8_pressed(self): # region getters
self._callibrate_state += 1 @property
def crop(self):
return _get_factor("crop")
def callibrate(self): @property
logging.debug("Callibrating...") def move_factor(self):
_callibrate_state = -1 return _get_factor("move_factor")
@property
def rot_factor(self):
return _get_factor("rot_factor")
@property
def time_to_reach_bottom(self):
return _get_factor("time_to_reach_bottom")
# endregion
def all_callibrated(self):
return self.crop and self.move_factor and self.rot_factor
def toggle_show(self):
self.engine.show_crop = not self.engine.show_crop
def update_crop(self, enable_crop=True):
if enable_crop:
self.engine.show_crop = True
crop = get_crop_coods(self.engine.window)
self.engine.window.crop = self.engine.crop
_update_factor("crop", crop)
def walk_calibrate(self):
walking_time = 3 walking_time = 3
rotate_times = 50
# region rotate and move
coods = self.engine.get_coods() coods = self.engine.get_coods()
if coods is None: if coods is None:
return return
@ -53,6 +103,17 @@ class Calibrate():
return return
x2, y2, rot2 = coods x2, y2, rot2 = coods
move_factor = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) / walking_time
_update_factor("move_factor", move_factor)
def rotate_calibrate(self):
rotate_times = 50
coods = self.engine.get_coods()
if coods is None:
return
_, _, rot2 = coods
for _ in range(rotate_times): for _ in range(rotate_times):
mse.move(FullAuto.rotate_by, 0) mse.move(FullAuto.rotate_by, 0)
time.sleep(0.05) time.sleep(0.05)
@ -65,13 +126,17 @@ class Calibrate():
if rot3 > rot2: if rot3 > rot2:
rot3 -= 360 rot3 -= 360
move_factor = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) / walking_time
rot_factor = (rot3 - rot2) / rotate_times rot_factor = (rot3 - rot2) / rotate_times
# endregion _update_factor("rot_factor", rot_factor)
def time_to_reach_bottom_callibrate(self):
self._callibrate_state = 0
def _f8_pressed():
self._callibrate_state += 1
logging.info("Now loop up and press f8") logging.info("Now loop up and press f8")
hotkey.set_hotkey(Key.F8, _f8_pressed)
hotkey.set_hotkey(Key.F8, self.f8_pressed)
wait_until(lambda: self._callibrate_state == 1) wait_until(lambda: self._callibrate_state == 1)
@ -81,11 +146,7 @@ class Calibrate():
while self._callibrate_state == 1: while self._callibrate_state == 1:
mse.move(0, FullAuto.rotate_by) mse.move(0, FullAuto.rotate_by)
time.sleep(0.05) time.sleep(0.05)
hotkey.free_key(Key.F8)
time_to_reach_bottom = time.time() - y_cal_start_time time_to_reach_bottom = time.time() - y_cal_start_time
_update_factor("time_to_reach_bottom", time_to_reach_bottom)
self.engine.factors = move_factor, rot_factor, time_to_reach_bottom
config.set("full_auto_factors", self.engine.factors)
logging.info(self.engine.factors)
hotkey.free_key(Key.F8)

View File

@ -0,0 +1,60 @@
import logging
from fishy.helper import hotkey
from fishy.engine.fullautofisher.engine import FullAuto
from fishy.helper.config import config
from fishy.helper.hotkey import Key
def get_controls(engine: FullAuto):
from fishy.engine.fullautofisher.calibrate import Calibrate
from fishy.engine.fullautofisher.recorder import Recorder
from fishy.engine.fullautofisher.player import Player
controls = [
# ("MAIN", {
# Key.RIGHT: Player(engine).start_route,
# Key.UP: Calibrate(engine).callibrate,
# Key.LEFT: Recorder(engine).start_recording,
# Key.DOWN: change_state
# }),
# ("COODS", {
# Key.RIGHT: print_coods,
# Key.UP: engine.update_crop,
# Key.LEFT: toggle_show,
# Key.DOWN: change_state
# }),
# ("TEST1", {
# Key.RIGHT: set_target,
# Key.UP: rotate_to_90,
# Key.LEFT: move_to_target,
# Key.DOWN: change_state
# })
]
return controls
class Controls:
def __init__(self, controls, first=0):
self.current_menu = first - 1
self.controls = controls
def change_state(self):
self.current_menu += 1
if self.current_menu == len(self.controls):
self.current_menu = 0
help_str = F"CONTROLS: {self.controls[self.current_menu][0]}"
for key, func in self.controls[self.current_menu][1].items():
hotkey.set_hotkey(key, func)
help_str += f"\n{key.value}: {func.__name__}"
logging.info(help_str)
def unassign_keys(self):
keys = []
for c in self.controls:
for k in c[1].keys():
if k not in keys:
hotkey.free_key(k)

View File

@ -10,6 +10,9 @@ import time
import numpy as np import numpy as np
import pytesseract import pytesseract
from fishy.engine.fullautofisher.tesseract import is_tesseract_installed, downlaoad_and_extract_tesseract, \
get_values_from_image
from fishy.engine.semifisher.fishing_mode import FishingMode from fishy.engine.semifisher.fishing_mode import FishingMode
from fishy.engine import SemiFisherEngine from fishy.engine import SemiFisherEngine
@ -22,53 +25,11 @@ from pynput import keyboard, mouse
from fishy.helper import hotkey, helper from fishy.helper import hotkey, helper
from fishy.helper.config import config from fishy.helper.config import config
from fishy.helper.downloader import download_file_from_google_drive from fishy.helper.downloader import download_file_from_google_drive
from fishy.helper.helper import sign
from fishy.helper.hotkey import Key from fishy.helper.hotkey import Key
mse = mouse.Controller() mse = mouse.Controller()
kb = keyboard.Controller() kb = keyboard.Controller()
offset = 0
def downlaoad_and_extract_tesseract():
logging.info("Tesseract-OCR downlaoding, Please wait...")
f = tempfile.NamedTemporaryFile(delete=False)
download_file_from_google_drive("16llzcBlaCsG9fm-rY2dD4Gvopnhm3XoE", f)
f.close()
logging.info("Tesseract-OCR downloaded, now installing")
addon_dir = os.path.join(os.environ["APPDATA"], "Tesseract-OCR")
with ZipFile(f.name, 'r') as z:
z.extractall(path=addon_dir)
logging.info("Tesseract-OCR installed")
def is_tesseract_installed():
return os.path.exists(os.path.join(os.environ["APPDATA"], "Tesseract-OCR"))
def sign(x):
return -1 if x < 0 else 1
def get_crop_coods(window):
img = window.get_capture()
img = cv2.inRange(img, 0, 1)
cnt, h = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
"""
code from https://stackoverflow.com/a/45770227/4512396
"""
for i in range(len(cnt)):
area = cv2.contourArea(cnt[i])
if 5000 < area < 100000:
mask = np.zeros_like(img)
cv2.drawContours(mask, cnt, i, 255, -1)
x, y, w, h = cv2.boundingRect(cnt[i])
return x, y + offset, x + w, y + h - offset
def image_pre_process(img): def image_pre_process(img):
@ -81,55 +42,32 @@ def image_pre_process(img):
return img return img
# noinspection PyBroadException
def get_values_from_image(img, tesseract_dir):
try:
pytesseract.pytesseract.tesseract_cmd = tesseract_dir + '/tesseract.exe'
tessdata_dir_config = f'--tessdata-dir "{tesseract_dir}" -c tessedit_char_whitelist=0123456789.'
text = pytesseract.image_to_string(img, lang="eng", config=tessdata_dir_config)
text = text.replace(" ", "")
vals = text.split(":")
return float(vals[0]), float(vals[1]), float(vals[2])
except Exception:
logging.error("Couldn't read coods")
cv2.imwrite(f"fail_{str(uuid.uuid4())[:8]}", img)
return None
class FullAuto(IEngine): class FullAuto(IEngine):
rotate_by = 30 rotate_by = 30
def __init__(self, gui_ref): def __init__(self, gui_ref):
from fishy.engine.fullautofisher.controls import Controls
from fishy.engine.fullautofisher import controls
from fishy.engine.fullautofisher.calibrate import Calibrate
from fishy.engine.fullautofisher.test import Test
super().__init__(gui_ref) super().__init__(gui_ref)
self.factors = config.get("full_auto_factors", None)
self._tesseract_dir = None
self._target = None
self.crop = config.get("full_auto_crop")
if self.factors is None:
logging.warning("Please callibrate first")
self._hole_found_flag = False self._hole_found_flag = False
self._curr_rotate_y = 0 self._curr_rotate_y = 0
self.fisher = SemiFisherEngine(None) self.fisher = SemiFisherEngine(None)
self.controls = Controls(self.get_controls()) self.controls = Controls(controls.get_controls(self))
self.calibrate = Calibrate(self)
self.test = Test(self)
@property @property
def show(self): def show_crop(self):
return config.get("show_window_full_auto", False) return config.get("show_window_full_auto", False)
@show.setter @show_crop.setter
def show(self, x): def show_crop(self, x):
config.set("show_window_full_auto", x) config.set("show_window_full_auto", x)
def update_crop(self):
self.show = True
self.crop = get_crop_coods(self.window)
config.set("full_auto_crop", self.crop)
self.window.crop = self.crop
def run(self): def run(self):
logging.info("Loading please wait...") logging.info("Loading please wait...")
self.gui.bot_started(True) self.gui.bot_started(True)
@ -137,19 +75,18 @@ class FullAuto(IEngine):
self.fisher.toggle_start() self.fisher.toggle_start()
self.window = WindowClient(color=cv2.COLOR_RGB2GRAY, show_name="Full auto debug") self.window = WindowClient(color=cv2.COLOR_RGB2GRAY, show_name="Full auto debug")
if self.crop is None: if self.calibrate.crop is None:
self.update_crop() self.calibrate.update_crop(enable_crop=False)
self.window.crop = self.crop self.window.crop = self.calibrate.crop
self._tesseract_dir = os.path.join(os.environ["APPDATA"], "Tesseract-OCR")
if not is_tesseract_installed(): if not is_tesseract_installed():
logging.info("tesseract not found") logging.info("tesseract not found")
downlaoad_and_extract_tesseract() downlaoad_and_extract_tesseract()
self.controls.change_state() self.controls.change_state()
while self.start and WindowClient.running(): while self.start and WindowClient.running():
self.window.show(self.show, func=image_pre_process) self.window.show(self.show_crop, func=image_pre_process)
if not self.show: if not self.show_crop:
time.sleep(0.1) time.sleep(0.1)
self.gui.bot_started(False) self.gui.bot_started(False)
@ -160,14 +97,15 @@ class FullAuto(IEngine):
self.fisher.toggle_start() self.fisher.toggle_start()
def get_coods(self): def get_coods(self):
return get_values_from_image(self.window.processed_image(func=image_pre_process), self._tesseract_dir) img = self.window.processed_image(func=image_pre_process)
return get_values_from_image(img)
def move_to(self, target): def move_to(self, target):
if target is None: if target is None:
logging.error("set target first") logging.error("set target first")
return return
if self.factors is None: if not self.calibrate.all_callibrated():
logging.error("you need to callibrate first") logging.error("you need to callibrate first")
return return
@ -186,7 +124,7 @@ class FullAuto(IEngine):
self.rotate_to(target_angle, from_angle) self.rotate_to(target_angle, from_angle)
walking_time = dist / self.factors[0] walking_time = dist / self.calibrate.move_factor
print(f"walking for {walking_time}") print(f"walking for {walking_time}")
kb.press('w') kb.press('w')
time.sleep(walking_time) time.sleep(walking_time)
@ -208,7 +146,7 @@ class FullAuto(IEngine):
if abs(angle_diff) > 180: if abs(angle_diff) > 180:
angle_diff = (360 - abs(angle_diff)) * sign(angle_diff) * -1 angle_diff = (360 - abs(angle_diff)) * sign(angle_diff) * -1
rotate_times = int(angle_diff / self.factors[1]) * -1 rotate_times = int(angle_diff / self.calibrate.rot_factor) * -1
print(f"rotate_times: {rotate_times}") print(f"rotate_times: {rotate_times}")
@ -229,7 +167,7 @@ class FullAuto(IEngine):
fishing_mode.subscribers.append(found_hole) fishing_mode.subscribers.append(found_hole)
t = 0 t = 0
while not self._hole_found_flag and t <= self.factors[2] / 3: while not self._hole_found_flag and t <= self.calibrate.time_to_reach_bottom / 3:
mse.move(0, FullAuto.rotate_by) mse.move(0, FullAuto.rotate_by)
time.sleep(0.05) time.sleep(0.05)
t += 0.05 t += 0.05
@ -248,78 +186,6 @@ class FullAuto(IEngine):
time.sleep(0.05) time.sleep(0.05)
self._curr_rotate_y -= 0.05 self._curr_rotate_y -= 0.05
def get_controls(self):
from fishy.engine.fullautofisher.calibrate import Calibrate
from fishy.engine.fullautofisher.recorder import Recorder
from fishy.engine.fullautofisher.player import Player
def change_state():
self.controls.change_state()
def print_coods():
logging.info(self.get_coods())
def set_target():
t = self.get_coods()[:-1]
config.set("target", t)
print(f"target_coods are {t}")
def move_to_target():
self.move_to(config.get("target"))
def rotate_to_90():
self.rotate_to(90)
def toggle_show():
self.show = not self.show
controls = [
("MAIN", {
Key.RIGHT: Player(self).start_route,
Key.UP: Calibrate(self).callibrate,
Key.LEFT: Recorder(self).start_recording,
Key.DOWN: change_state
}),
("COODS", {
Key.RIGHT: print_coods,
Key.UP: self.update_crop,
Key.LEFT: toggle_show,
Key.DOWN: change_state
}),
("TEST1", {
Key.RIGHT: set_target,
Key.UP: rotate_to_90,
Key.LEFT: move_to_target,
Key.DOWN: change_state
})
]
return controls
class Controls:
def __init__(self, controls, first=0):
self.current_menu = first - 1
self.controls = controls
def change_state(self):
self.current_menu += 1
if self.current_menu == len(self.controls):
self.current_menu = 0
help_str = F"CONTROLS: {self.controls[self.current_menu][0]}"
for key, func in self.controls[self.current_menu][1].items():
hotkey.set_hotkey(key, func)
help_str += f"\n{key.value}: {func.__name__}"
logging.info(help_str)
def unassign_keys(self):
keys = []
for c in self.controls:
for k in c[1].keys():
if k not in keys:
hotkey.free_key(k)
if __name__ == '__main__': if __name__ == '__main__':
logging.getLogger("").setLevel(logging.DEBUG) logging.getLogger("").setLevel(logging.DEBUG)

View File

@ -75,6 +75,7 @@ class Player:
logging.info("starting fishing") logging.info("starting fishing")
self.hole_complete_flag = False self.hole_complete_flag = False
helper.wait_until(lambda: self.hole_complete_flag or not self.start_moving_flag) helper.wait_until(lambda: self.hole_complete_flag or not self.start_moving_flag)
self.engine.rotate_back()
else: else:
logging.info("no hole found") logging.info("no hole found")
# if found start fishing and wait for hole to complete # if found start fishing and wait for hole to complete

View File

@ -0,0 +1,48 @@
import logging
import os
import tempfile
import uuid
from zipfile import ZipFile
import cv2
import pytesseract
from fishy.helper.downloader import download_file_from_google_drive
directory = os.path.join(os.environ["APPDATA"], "Tesseract-OCR")
def downlaoad_and_extract_tesseract():
logging.info("Tesseract-OCR downlaoding, Please wait...")
f = tempfile.NamedTemporaryFile(delete=False)
download_file_from_google_drive("16llzcBlaCsG9fm-rY2dD4Gvopnhm3XoE", f)
f.close()
logging.info("Tesseract-OCR downloaded, now installing")
with ZipFile(f.name, 'r') as z:
z.extractall(path=directory)
logging.info("Tesseract-OCR installed")
def is_tesseract_installed():
return os.path.exists(os.path.join(os.environ["APPDATA"], "Tesseract-OCR"))
# noinspection PyBroadException
def get_values_from_image(img):
try:
pytesseract.pytesseract.tesseract_cmd = directory + '/tesseract.exe'
tessdata_dir_config = f'--tessdata-dir "{directory}" -c tessedit_char_whitelist=0123456789.'
text = pytesseract.image_to_string(img, lang="eng", config=tessdata_dir_config)
text = text.replace(" ", "")
vals = text.split(":")
return float(vals[0]), float(vals[1]), float(vals[2])
except Exception:
logging.error("Couldn't read coods, make sure 'crop' calibration is correct")
cv2.imwrite(f"fail_{str(uuid.uuid4())[:8]}", img)
return None

View File

@ -0,0 +1,35 @@
import logging
from fishy.engine.fullautofisher.engine import FullAuto
from fishy.helper.config import config
class Test:
def __init__(self, engine: FullAuto):
self.engine = engine
self.target = None
def print_coods(self):
logging.info(self.engine.get_coods())
def set_target(self):
self.target = self.engine.get_coods()
logging.info(f"target_coods are {self.target}")
def move_to_target(self):
if not self.target:
logging.info("please set a target first")
self.engine.move_to(self.target)
def rotate_to_target(self):
if not self.target:
logging.info("please set a target first")
self.engine.rotate_to(self.target[2])
def look_for_hole(self):
logging.info("looking for a hole")
if self.engine.look_for_hole():
logging.info("found a hole")
else:
logging.info("no hole found")

View File

@ -34,6 +34,10 @@ def wait_until(func):
time.sleep(0.1) time.sleep(0.1)
def sign(x):
return -1 if x < 0 else 1
def open_web(website): def open_web(website):
""" """
Opens a website on browser, Opens a website on browser,