import math import os import tempfile import uuid from zipfile import ZipFile import cv2 import logging import time import numpy as np import pytesseract from fishy.engine.semifisher.fishing_mode import FishingMode from fishy.engine import SemiFisherEngine from fishy.engine.common.window import WindowClient from fishy.engine.semifisher import fishing_mode, fishing_event from fishy.engine.common.IEngine import IEngine from pynput import keyboard, mouse from fishy.helper import hotkey, helper from fishy.helper.config import config from fishy.helper.downloader import download_file_from_google_drive from fishy.helper.hotkey import Key mse = mouse.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): scale_percent = 200 # percent of original size width = int(img.shape[1] * scale_percent / 100) height = int(img.shape[0] * scale_percent / 100) dim = (width, height) img = cv2.resize(img, dim, interpolation=cv2.INTER_AREA) img = cv2.bitwise_not(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): rotate_by = 30 def __init__(self, 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._curr_rotate_y = 0 self.fisher = SemiFisherEngine(None) self.controls = Controls(self.get_controls()) @property def show(self): return config.get("show_window_full_auto", False) @show.setter def show(self, 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): logging.info("Loading please wait...") self.gui.bot_started(True) fishing_event.unsubscribe() self.fisher.toggle_start() self.window = WindowClient(color=cv2.COLOR_RGB2GRAY, show_name="Full auto debug") if self.crop is None: self.update_crop() self.window.crop = self.crop self._tesseract_dir = os.path.join(os.environ["APPDATA"], "Tesseract-OCR") if not is_tesseract_installed(): logging.info("tesseract not found") downlaoad_and_extract_tesseract() self.controls.change_state() while self.start and WindowClient.running(): self.window.show(self.show, func=image_pre_process) if not self.show: time.sleep(0.1) self.gui.bot_started(False) self.controls.unassign_keys() self.window.show(False) logging.info("Quit") self.window.destory() self.fisher.toggle_start() def get_coods(self): return get_values_from_image(self.window.processed_image(func=image_pre_process), self._tesseract_dir) def move_to(self, target): if target is None: logging.error("set target first") return if self.factors is None: logging.error("you need to callibrate first") return current = self.get_coods() print(f"Moving from {(current[0], current[1])} to {target}") move_vec = target[0] - current[0], target[1] - current[1] dist = math.sqrt(move_vec[0] ** 2 + move_vec[1] ** 2) print(f"distance: {dist}") if dist < 5e-05: print("distance very small skipping") return target_angle = math.degrees(math.atan2(-move_vec[1], move_vec[0])) + 90 from_angle = current[2] self.rotate_to(target_angle, from_angle) walking_time = dist / self.factors[0] print(f"walking for {walking_time}") kb.press('w') time.sleep(walking_time) kb.release('w') print("done") def rotate_to(self, target_angle, from_angle=None): if from_angle is None: _, _, from_angle = self.get_coods() if target_angle < 0: target_angle = 360 + target_angle while target_angle > 360: target_angle -= 360 print(f"Rotating from {from_angle} to {target_angle}") angle_diff = target_angle - from_angle if abs(angle_diff) > 180: angle_diff = (360 - abs(angle_diff)) * sign(angle_diff) * -1 rotate_times = int(angle_diff / self.factors[1]) * -1 print(f"rotate_times: {rotate_times}") for _ in range(abs(rotate_times)): mse.move(sign(rotate_times) * FullAuto.rotate_by * -1, 0) time.sleep(0.05) def look_for_hole(self): self._hole_found_flag = False if FishingMode.CurrentMode == fishing_mode.State.LOOK: return True def found_hole(e): if e == fishing_mode.State.LOOK: self._hole_found_flag = True fishing_mode.subscribers.append(found_hole) t = 0 while not self._hole_found_flag and t <= self.factors[2] / 3: mse.move(0, FullAuto.rotate_by) time.sleep(0.05) t += 0.05 while not self._hole_found_flag and t > 0: mse.move(0, -FullAuto.rotate_by) time.sleep(0.05) t -= 0.05 self._curr_rotate_y = t fishing_mode.subscribers.remove(found_hole) return self._hole_found_flag def rotate_back(self): while self._curr_rotate_y > 0.01: mse.move(0, -FullAuto.rotate_by) time.sleep(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__': logging.getLogger("").setLevel(logging.DEBUG) hotkey.initalize() # noinspection PyTypeChecker bot = FullAuto(None) bot.toggle_start()