fullauto reworked with the new parent class

- removed double beep on turnoff
- removed show crop feature in fullauto
- semi fisher is started only when needed, and turned off when the job is done by mode, instead of full auto engine
- use the last coord from recording isntead of getting a new one when using editor in recorder mode, to avoid recording failure when saving the recording
This commit is contained in:
Adam Saudagar 2022-02-01 16:57:14 +05:30
parent a5236e9b30
commit 245493fbc4
5 changed files with 88 additions and 76 deletions

View File

@ -29,15 +29,18 @@ class IEngine:
return self.get_gui().funcs
@property
def start(self):
return self.state == 1
def toggle_start(self):
if self.state == 1:
self.turn_off()
elif self.state == 0:
if self.state == 0:
self.turn_on()
else:
self.turn_on()
def turn_on(self):
self.state = 1
playsound(helper.manifest_file("beep.wav"), False)
self.thread = Thread(target=self._crash_safe)
self.thread.start()
@ -46,8 +49,12 @@ class IEngine:
this method only signals the thread to close using start flag,
its the responsibility of the thread to shut turn itself off
"""
self.state = 2
helper.playsound_multiple(helper.manifest_file("beep.wav"))
if self.state == 1:
logging.info("turning off...")
self.state = 2
else:
logging.error("engine already signaled to turn off")
# todo: implement force turn off on repeated calls
# noinspection PyBroadException
def _crash_safe(self):

View File

@ -7,7 +7,6 @@ from threading import Thread
import cv2
from pynput import keyboard, mouse
from fishy.constants import fishyqr, lam2, libgps
from fishy.engine import SemiFisherEngine
from fishy.engine.common.IEngine import IEngine
from fishy.engine.common.window import WindowClient
@ -19,10 +18,9 @@ from fishy.engine.common.qr_detection import (get_qr_location,
get_values_from_image, image_pre_process)
from fishy.engine.semifisher import fishing_event, fishing_mode
from fishy.engine.semifisher.fishing_mode import FishingMode
from fishy.helper import helper, hotkey
from fishy.helper import hotkey
from fishy.helper.config import config
from fishy.helper.helper import log_raise, wait_until, is_eso_active
from fishy.helper.helper import sign
from fishy.helper.helper import wait_until, is_eso_active, sign
mse = mouse.Controller()
kb = keyboard.Controller()
@ -45,7 +43,6 @@ class FullAuto(IEngine):
self.mode = None
def run(self):
self.gui.bot_started(True)
self.window = WindowClient(color=cv2.COLOR_RGB2GRAY, show_name="Full auto debug")
self.mode = None
@ -55,7 +52,11 @@ class FullAuto(IEngine):
self.mode = Player(self)
elif FullAutoMode(config.get("full_auto_mode", 0)) == FullAutoMode.Recorder:
self.mode = Recorder(self)
else:
logging.error("not a valid mode selected")
return
# block thread until game window becomes active
if not is_eso_active():
logging.info("Waiting for eso window to be active...")
wait_until(lambda: is_eso_active() or not self.start)
@ -63,37 +64,34 @@ class FullAuto(IEngine):
logging.info("starting in 2 secs...")
time.sleep(2)
if not self._pre_run_checks():
return
if config.get("tabout_stop", 1):
self.stop_on_inactive()
# noinspection PyBroadException
try:
if self.window.get_capture() is None:
log_raise("Game window not found")
self.window.crop = get_qr_location(self.window.get_capture())
if self.window.crop is None:
log_raise("FishyQR not found, try to drag it around and try again")
if not (type(self.mode) is Calibrator) and not self.calibrator.all_calibrated():
log_raise("you need to calibrate first")
self.fisher.toggle_start()
fishing_event.unsubscribe()
if self.show_crop:
self.start_show()
if config.get("tabout_stop", 1):
self.stop_on_inactive()
self.mode.run()
except Exception:
logging.error("exception occurred while running full auto mode")
traceback.print_exc()
self.start = False
self.gui.bot_started(False)
self.window.show(False)
logging.info("Quitting")
self.window.destory()
self.fisher.toggle_start()
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 func():
@ -103,8 +101,10 @@ class FullAuto(IEngine):
def stop_on_inactive(self):
def func():
wait_until(lambda: not is_eso_active())
self.start = False
logging.info("stop on inactive started")
wait_until(lambda: not is_eso_active() or self.start != 1)
self.turn_off()
logging.info("stop on inactive stopped")
Thread(target=func).start()
def get_coords(self):
@ -143,6 +143,7 @@ class FullAuto(IEngine):
time.sleep(walking_time)
kb.release('w')
print("done")
# todo: maybe check if it reached the destination before returning true?
return True
def rotate_to(self, target_angle, from_angle=None) -> bool:
@ -177,6 +178,7 @@ class FullAuto(IEngine):
valid_states = [fishing_mode.State.LOOKING, fishing_mode.State.FISHING]
_hole_found_flag = FishingMode.CurrentMode in valid_states
# if vertical movement is disabled
if not config.get("look_for_hole", 1):
return _hole_found_flag

View File

@ -75,25 +75,25 @@ class Calibrator(IMode):
def _walk_calibrate(self):
walking_time = 3
coods = self.engine.get_coords()
if coods is None:
coords = self.engine.get_coords()
if coords is None:
return
x1, y1, rot1 = coods
x1, y1, rot1 = coords
kb.press('w')
time.sleep(walking_time)
kb.release('w')
time.sleep(0.5)
coods = self.engine.get_coords()
if coods is None:
coords = self.engine.get_coords()
if coords is None:
return
x2, y2, rot2 = coods
x2, y2, rot2 = coords
move_factor = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) / walking_time
_update_factor("move_factor", move_factor)
logging.info("walk calibrate done")
logging.info(f"walk calibrate done, move_factor: {move_factor}")
def _rotate_calibrate(self):
from fishy.engine.fullautofisher.engine import FullAuto
@ -119,7 +119,7 @@ class Calibrator(IMode):
rot_factor = (rot3 - rot2) / rotate_times
_update_factor("rot_factor", rot_factor)
logging.info("rotate calibrate done")
logging.info(f"rotate calibrate done, rot_factor: {rot_factor}")
def run(self):
self._walk_calibrate()

View File

@ -2,14 +2,11 @@ import logging
import math
import pickle
import time
from pprint import pprint
import typing
from threading import Thread
from fishy.engine.fullautofisher.mode.imode import IMode
from fishy.engine.semifisher import fishing_event, fishing_mode
from fishy.helper.helper import log_raise, wait_until, kill_thread
if typing.TYPE_CHECKING:
from fishy.engine.fullautofisher.engine import FullAuto
@ -56,23 +53,28 @@ class Player(IMode):
self.timeline = None
def run(self):
self._init()
if not self._init():
return
while self.engine.start:
self._loop()
time.sleep(0.1)
logging.info("player stopped")
def _init(self):
def _init(self) -> bool:
self.timeline = get_rec_file()
if not self.timeline:
log_raise("data not found, can't start")
logging.info("starting player")
logging.error("data not found, can't start")
return False
coords = self.engine.get_coords()
if not coords:
log_raise("QR not found")
logging.error("QR not found")
return False
self.i = find_nearest(self.timeline, coords)[0]
logging.info("starting player")
def _loop(self):
action = self.timeline[self.i]
@ -87,21 +89,22 @@ class Player(IMode):
if not self.engine.rotate_to(action[1][2]):
return
fishing_mode.subscribers.append(self._hole_complete_callback)
fishing_event.subscribe()
self.engine.fisher.turn_on()
# scan for fish hole
logging.info("scanning")
# if found start fishing and wait for hole to complete
if self.engine.look_for_hole():
logging.info("starting fishing")
fishing_mode.subscribers.append(self._hole_complete_callback)
self.hole_complete_flag = False
helper.wait_until(lambda: self.hole_complete_flag or not self.engine.start)
fishing_mode.subscribers.remove(self._hole_complete_callback)
self.engine.rotate_back()
else:
logging.info("no hole found")
# continue when hole completes
fishing_mode.subscribers.remove(self._hole_complete_callback)
fishing_event.unsubscribe()
self.engine.fisher.turn_off()
self.next()

View File

@ -9,20 +9,18 @@ import typing
from tkinter.filedialog import asksaveasfile
from fishy.engine.fullautofisher.mode import player
from fishy.helper import helper
from fishy.helper.helper import empty_function, log_raise
from fishy.helper.helper import empty_function
from fishy.helper.hotkey.process import Key
from fishy.helper.popup import PopUp
from playsound import playsound
from fishy.helper.config import config
if typing.TYPE_CHECKING:
from fishy.engine.fullautofisher.engine import FullAuto
from fishy.engine.fullautofisher.mode.imode import IMode
from fishy.helper.hotkey.hotkey_process import HotKey, hotkey
from fishy.helper.hotkey.hotkey_process import hotkey
class Recorder(IMode):
@ -49,48 +47,50 @@ class Recorder(IMode):
old_timeline = player.get_rec_file()
if not old_timeline:
log_raise("Edit mode selected, but no fishy file selected")
logging.error("Edit mode selected, but no fishy file selected")
return
coords = self.engine.get_coords()
if not coords:
log_raise("QR not found")
logging.error("QR not found")
return
start_from = player.find_nearest(old_timeline, coords)
if not self.engine.move_to(start_from[2]):
log_raise("QR not found")
logging.error("QR not found")
return
logging.info("starting, press LMB to mark hole")
hotkey.hook(Key.LMB, self._mark_hole)
self.timeline = []
last_coord = None
while self.engine.start:
start_time = time.time()
coods = self.engine.get_coords()
if not coods:
coords = self.engine.get_coords()
if not coords:
logging.warning("missed a frame, as qr not be read properly...")
time.sleep(0.1)
continue
self.timeline.append(("move_to", (coods[0], coods[1])))
self.timeline.append(("move_to", (coords[0], coords[1])))
# maintaining constant frequency for recording
time_took = time.time() - start_time
if time_took <= Recorder.recording_fps:
time.sleep(Recorder.recording_fps - time_took)
else:
logging.warning("Took too much time to record")
last_coord = coords
hotkey.free(Key.LMB)
if config.get("edit_recorder_mode"):
logging.info("moving to nearest coord in recording")
# todo allow the user the chance to wait for qr
coords = self.engine.get_coords()
if not coords:
log_raise("QR not found")
end = player.find_nearest(old_timeline, coords)
end = player.find_nearest(old_timeline, last_coord)
self.engine.move_to(end[2])
# recording stitching
part1 = old_timeline[:start_from[0]]
part2 = old_timeline[end[0]:]
self.timeline = part1 + self.timeline + part2