fishyboteso/fishy/engine/fullautofisher/engine.py

330 lines
9.7 KiB
Python
Raw Normal View History

import math
import os
import tempfile
import uuid
from zipfile import ZipFile
import cv2
2020-06-01 12:58:18 +00:00
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
2020-10-15 02:23:15 +00:00
from fishy.engine.common.IEngine import IEngine
from pynput import keyboard, mouse
from fishy.helper import hotkey, helper
2020-10-17 19:06:07 +00:00
from fishy.helper.config import config
from fishy.helper.downloader import download_file_from_google_drive
from fishy.helper.hotkey import Key
2020-06-25 13:40:05 +00:00
mse = mouse.Controller()
kb = keyboard.Controller()
offset = 0
2020-06-25 13:40:05 +00:00
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"))
2020-06-25 13:40:05 +00:00
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:
2020-06-25 13:40:05 +00:00
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
2020-06-01 12:58:18 +00:00
class FullAuto(IEngine):
rotate_by = 30
2020-10-17 19:06:07 +00:00
def __init__(self, gui_ref):
super().__init__(gui_ref)
self.factors = config.get("full_auto_factors", None)
2020-10-15 02:23:15 +00:00
self._tesseract_dir = None
self._target = None
self.crop = config.get("full_auto_crop")
if self.factors is None:
2020-06-25 13:40:05 +00:00
logging.warning("Please callibrate first")
2020-10-15 02:23:15 +00:00
self._hole_found_flag = False
self._curr_rotate_y = 0
2020-10-17 22:35:20 +00:00
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
2020-06-01 12:58:18 +00:00
def run(self):
logging.info("Loading please wait...")
self.gui.bot_started(True)
2020-10-17 22:35:20 +00:00
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()
2020-10-17 22:35:20 +00:00
while self.start and WindowClient.running():
self.window.show(self.show, func=image_pre_process)
if not self.show:
time.sleep(0.1)
2020-06-01 12:58:18 +00:00
self.gui.bot_started(False)
2020-10-17 22:35:20 +00:00
self.controls.unassign_keys()
self.window.show(False)
logging.info("Quit")
self.window.destory()
self.fisher.toggle_start()
def get_coods(self):
2020-10-15 02:23:15 +00:00
return get_values_from_image(self.window.processed_image(func=image_pre_process), self._tesseract_dir)
2020-06-25 13:40:05 +00:00
def move_to(self, target):
if target is None:
logging.error("set target first")
return
if self.factors is None:
2020-06-25 13:40:05 +00:00
logging.error("you need to callibrate first")
return
current = self.get_coods()
print(f"Moving from {(current[0], current[1])} to {target}")
2020-06-25 13:40:05 +00:00
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()
2020-06-25 13:40:05 +00:00
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}")
2020-06-25 13:40:05 +00:00
angle_diff = target_angle - from_angle
2020-06-25 13:40:05 +00:00
if abs(angle_diff) > 180:
angle_diff = (360 - abs(angle_diff)) * sign(angle_diff) * -1
2020-06-25 13:40:05 +00:00
rotate_times = int(angle_diff / self.factors[1]) * -1
2020-06-25 13:40:05 +00:00
print(f"rotate_times: {rotate_times}")
2020-06-25 13:40:05 +00:00
for _ in range(abs(rotate_times)):
mse.move(sign(rotate_times) * FullAuto.rotate_by * -1, 0)
2020-06-25 13:40:05 +00:00
time.sleep(0.05)
2020-10-15 02:23:15 +00:00
def look_for_hole(self):
self._hole_found_flag = False
if FishingMode.CurrentMode == fishing_mode.State.LOOK:
return True
2020-10-15 02:23:15 +00:00
def found_hole(e):
if e == fishing_mode.State.LOOK:
2020-10-15 02:23:15 +00:00
self._hole_found_flag = True
fishing_mode.subscribers.append(found_hole)
2020-10-15 02:23:15 +00:00
t = 0
while not self._hole_found_flag and t <= self.factors[2] / 3:
2020-10-15 02:23:15 +00:00
mse.move(0, FullAuto.rotate_by)
time.sleep(0.05)
t += 0.05
while not self._hole_found_flag and t > 0:
2020-10-15 02:23:15 +00:00
mse.move(0, -FullAuto.rotate_by)
time.sleep(0.05)
t -= 0.05
self._curr_rotate_y = t
fishing_mode.subscribers.remove(found_hole)
2020-10-15 02:23:15 +00:00
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
2020-10-17 22:35:20 +00:00
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():
2020-10-17 22:35:20 +00:00
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
})
]
2020-10-17 22:35:20 +00:00
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)
2020-10-17 22:35:20 +00:00
def unassign_keys(self):
keys = []
for c in self.controls:
for k in c[1].keys():
2020-10-17 22:35:20 +00:00
if k not in keys:
hotkey.free_key(k)
if __name__ == '__main__':
logging.getLogger("").setLevel(logging.DEBUG)
2020-10-17 22:35:20 +00:00
hotkey.initalize()
# noinspection PyTypeChecker
2020-10-17 19:06:07 +00:00
bot = FullAuto(None)
bot.toggle_start()