connected mode select in config with the engine

- restructed player and recorder to work with new system,
- remove FullAuto.State
This commit is contained in:
Adam Saudagar 2021-05-02 21:09:59 +05:30
parent 1290c877f1
commit 3ce3c24dd1
9 changed files with 174 additions and 150 deletions

View File

@ -4,8 +4,6 @@ from pynput.keyboard import Key
from fishy.helper import hotkey from fishy.helper import hotkey
from fishy.engine.fullautofisher.engine import FullAuto, State
def get_controls(controls: 'Controls'): def get_controls(controls: 'Controls'):
controls = [ controls = [
@ -36,10 +34,6 @@ class Controls:
logging.info(help_str) logging.info(help_str)
def select_mode(self, mode): def select_mode(self, mode):
if FullAuto.state != State.NONE:
self.log_help()
return
self.current_menu = 0 self.current_menu = 0
for i, control in enumerate(self.controls): for i, control in enumerate(self.controls):
if mode == control[0]: if mode == control[0]:

View File

@ -8,6 +8,9 @@ import logging
import time import time
from fishy.constants import libgps, fishyqr, lam2 from fishy.constants import libgps, fishyqr, lam2
from fishy.engine.fullautofisher.mode.imode import FullAutoMode
from fishy.engine.fullautofisher.mode.player import Player
from fishy.engine.fullautofisher.mode.recorder import Recorder
from fishy.engine.fullautofisher.qr_detection import get_values_from_image, get_qr_location from fishy.engine.fullautofisher.qr_detection import get_values_from_image, get_qr_location
from fishy.engine.semifisher.fishing_mode import FishingMode from fishy.engine.semifisher.fishing_mode import FishingMode
@ -19,7 +22,8 @@ from fishy.engine.common.IEngine import IEngine
from pynput import keyboard, mouse from pynput import keyboard, mouse
from fishy.helper import hotkey, helper from fishy.helper import hotkey, helper
from fishy.helper.helper import sign from fishy.helper.helper import sign, log_raise
from fishy.helper.config import config
mse = mouse.Controller() mse = mouse.Controller()
kb = keyboard.Controller() kb = keyboard.Controller()
@ -34,16 +38,8 @@ def image_pre_process(img):
return img return img
class State(Enum):
NONE = 0
PLAYING = 1
RECORDING = 2
OTHER = 3
class FullAuto(IEngine): class FullAuto(IEngine):
rotate_by = 30 rotate_by = 30
state = State.NONE
def __init__(self, gui_ref): def __init__(self, gui_ref):
from fishy.engine.fullautofisher.calibrator import Calibrator from fishy.engine.fullautofisher.calibrator import Calibrator
@ -58,6 +54,8 @@ class FullAuto(IEngine):
self.test = Test(self) self.test = Test(self)
self.show_crop = False self.show_crop = False
self.mode = None
def run(self): def run(self):
addons_req = [libgps, lam2, fishyqr] addons_req = [libgps, lam2, fishyqr]
@ -65,34 +63,33 @@ class FullAuto(IEngine):
if not helper.addon_exists(*addon): if not helper.addon_exists(*addon):
helper.install_addon(*addon) helper.install_addon(*addon)
FullAuto.state = State.NONE
self.gui.bot_started(True) self.gui.bot_started(True)
self.window = WindowClient(color=cv2.COLOR_RGB2GRAY, show_name="Full auto debug") self.window = WindowClient(color=cv2.COLOR_RGB2GRAY, show_name="Full auto debug")
self.mode = Player(self) if FullAutoMode(config.get("full_auto_mode", 0)) == FullAutoMode.Player else Recorder(self)
# todo use config to run player or recorder
# noinspection PyBroadException
try: try:
if self.window.get_capture() is None:
log_raise("Game window not found")
self.window.crop = get_qr_location(self.window.get_capture()) self.window.crop = get_qr_location(self.window.get_capture())
if self.window.crop is None: if self.window.crop is None:
logging.warning("FishyQR not found") log_raise("FishyQR not found")
self.start = False
raise Exception("FishyQR not found")
if not self.calibrator.all_callibrated(): if not self.calibrator.all_callibrated():
logging.error("you need to calibrate first") log_raise("you need to calibrate first")
self.fisher.toggle_start() self.fisher.toggle_start()
fishing_event.unsubscribe() fishing_event.unsubscribe()
while self.start and WindowClient.running():
if self.show_crop: if self.show_crop:
self.window.show(self.show_crop, func=image_pre_process) self.start_show()
else:
time.sleep(0.1)
except:
traceback.print_exc()
if self.window.get_capture() is None: self.mode.run()
logging.error("Game window not found")
except Exception:
traceback.print_exc()
self.start = False
self.gui.bot_started(False) self.gui.bot_started(False)
self.window.show(False) self.window.show(False)
@ -100,6 +97,12 @@ class FullAuto(IEngine):
self.window.destory() self.window.destory()
self.fisher.toggle_start() self.fisher.toggle_start()
def start_show(self):
def func():
while self.start and WindowClient.running():
self.window.show(self.show_crop, func=image_pre_process)
Thread(target=func).start()
def get_coods(self): def get_coods(self):
img = self.window.processed_image(func=image_pre_process) img = self.window.processed_image(func=image_pre_process)
return get_values_from_image(img) return get_values_from_image(img)
@ -191,10 +194,6 @@ class FullAuto(IEngine):
self._curr_rotate_y -= 0.05 self._curr_rotate_y -= 0.05
def toggle_start(self): def toggle_start(self):
if self.start and FullAuto.state != State.NONE:
logging.info("Please turn off RECORDING/PLAYING first")
return
self.start = not self.start self.start = not self.start
if self.start: if self.start:
self.thread = Thread(target=self.run) self.thread = Thread(target=self.run)

View File

@ -0,0 +1,14 @@
from abc import ABC, abstractmethod
from enum import Enum
class FullAutoMode(Enum):
Player = 0
Recorder = 1
class IMode(ABC):
@abstractmethod
def run(self):
...

View File

@ -0,0 +1,92 @@
import logging
import pickle
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
from fishy.helper import helper
from fishy.helper.config import config
def _get_rec_file():
file = config.get("full_auto_rec_file")
if not file:
logging.error("Please select a fishy file first from config")
return None
file = open(file, 'rb')
data = pickle.load(file)
file.close()
pprint(data)
if "full_auto_path" not in data:
logging.error("invalid file")
return None
return data["full_auto_path"]
class Player(IMode):
def __init__(self, engine: 'FullAuto'):
self.recording = False
self.engine = engine
self.hole_complete_flag = False
self.start_moving_flag = False
self.i = 0
self.forward = True
self.timeline = None
def run(self):
self._init()
while self.engine.start:
self._loop()
logging.info("player stopped")
def _init(self):
self.timeline = _get_rec_file()
if not self.timeline:
log_raise("data not found, can't start")
logging.info("starting player")
def _loop(self):
action = self.timeline[self.i]
if action[0] == "move_to":
self.engine.move_to(action[1])
elif action[0] == "check_fish":
self.engine.move_to(action[1])
self.engine.rotate_to(action[1][2])
fishing_event.subscribe()
fishing_mode.subscribers.append(self._hole_complete_callback)
# 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")
self.hole_complete_flag = False
helper.wait_until(lambda: self.hole_complete_flag or not self.engine.start)
self.engine.rotate_back()
else:
logging.info("no hole found")
# continue when hole completes
fishing_event.unsubscribe()
fishing_mode.subscribers.remove(self._hole_complete_callback)
self.i += 1 if self.forward else -1
if self.i >= len(self.timeline):
self.forward = False
self.i = len(self.timeline) - 1
elif self.i < 0:
self.forward = True
self.i = 0
def _hole_complete_callback(self, e):
if e == fishing_event.State.IDLE:
self.hole_complete_flag = True

View File

@ -4,17 +4,21 @@ import time
from pprint import pprint from pprint import pprint
from tkinter.filedialog import asksaveasfile from tkinter.filedialog import asksaveasfile
from fishy.engine.fullautofisher.engine import FullAuto, State import typing
if typing.TYPE_CHECKING:
from fishy.engine.fullautofisher.engine import FullAuto
from fishy.engine.fullautofisher.mode.imode import IMode
from fishy.helper.hotkey import Key from fishy.helper.hotkey import Key
from fishy.helper.hotkey_process import HotKey from fishy.helper.hotkey_process import HotKey
class Recorder: class Recorder(IMode):
recording_fps = 1 recording_fps = 1
mark_hole_key = Key.F8 mark_hole_key = Key.F8
def __init__(self, engine: FullAuto): def __init__(self, engine: 'FullAuto'):
self.recording = False self.recording = False
self.engine = engine self.engine = engine
self.timeline = [] self.timeline = []
@ -24,23 +28,14 @@ class Recorder:
self.timeline.append(("check_fish", coods)) self.timeline.append(("check_fish", coods))
logging.info("check_fish") logging.info("check_fish")
def toggle_recording(self): def run(self):
if FullAuto.state != State.RECORDING and FullAuto.state != State.NONE:
return
self.recording = not self.recording
if self.recording:
self._start_recording()
def _start_recording(self):
FullAuto.state = State.RECORDING
logging.info("starting, press f8 to mark hole") logging.info("starting, press f8 to mark hole")
hk = HotKey() hk = HotKey()
hk.start_process(self._mark_hole) hk.start_process(self._mark_hole)
self.timeline = [] self.timeline = []
while self.recording: while self.engine.start:
start_time = time.time() start_time = time.time()
coods = None coods = None
while not coods: while not coods:
@ -68,5 +63,4 @@ class Recorder:
pprint(data) pprint(data)
pickle.dump(data, file) pickle.dump(data, file)
file.close() file.close()
FullAuto.state = State.NONE

View File

@ -1,95 +0,0 @@
import logging
import pickle
from pprint import pprint
from fishy.engine.semifisher import fishing_event, fishing_mode
from fishy.engine.fullautofisher.engine import FullAuto, State
from fishy.helper import helper
from fishy.helper.config import config
def _get_rec_file():
file = config.get("full_auto_rec_file")
if not file:
logging.error("Please select a fishy file first from config")
return None
file = open(file, 'rb')
data = pickle.load(file)
file.close()
pprint(data)
if "full_auto_path" not in data:
logging.error("invalid file")
return None
return data["full_auto_path"]
class Player:
def __init__(self, engine: 'FullAuto'):
self.recording = False
self.engine = engine
self.hole_complete_flag = False
self.start_moving_flag = False
def toggle_move(self):
if FullAuto.state != State.PLAYING and FullAuto.state != State.NONE:
return
self.start_moving_flag = not self.start_moving_flag
if self.start_moving_flag:
self._start_route()
else:
logging.info("Waiting for the last action to finish...")
def _hole_complete_callback(self, e):
if e == fishing_event.State.IDLE:
self.hole_complete_flag = True
def _start_route(self):
timeline = _get_rec_file()
if not timeline:
logging.log("data not found, can't start")
return
FullAuto.state = State.PLAYING
logging.info("starting to move")
forward = True
i = 0
while self.start_moving_flag:
action = timeline[i]
if action[0] == "move_to":
self.engine.move_to(action[1])
elif action[0] == "check_fish":
self.engine.move_to(action[1])
self.engine.rotate_to(action[1][2])
fishing_event.subscribe()
fishing_mode.subscribers.append(self._hole_complete_callback)
# scan for fish hole
logging.info("scanning")
if self.engine.look_for_hole():
logging.info("starting fishing")
self.hole_complete_flag = False
helper.wait_until(lambda: self.hole_complete_flag or not self.start_moving_flag)
self.engine.rotate_back()
else:
logging.info("no hole found")
# if found start fishing and wait for hole to complete
# contine when hole completes
fishing_event.unsubscribe()
fishing_mode.subscribers.remove(self._hole_complete_callback)
i += 1 if forward else -1
if i >= len(timeline):
forward = False
i = len(timeline) - 1
elif i < 0:
forward = True
i = 0
logging.info("stopped")
FullAuto.state = State.NONE

View File

@ -4,6 +4,7 @@ import typing
from tkinter.filedialog import askopenfilename from tkinter.filedialog import askopenfilename
from fishy.engine.common.event_handler import IEngineHandler from fishy.engine.common.event_handler import IEngineHandler
from fishy.engine.fullautofisher.mode.imode import FullAutoMode
from fishy.helper import helper from fishy.helper import helper
from fishy import web from fishy import web
@ -42,17 +43,17 @@ def start_fullfisher_config(gui: 'GUI'):
def start_calibrate(): def start_calibrate():
... ...
def select_radio(): def mode_command():
... config.set("full_auto_mode", mode_var.get())
file_name_label = StringVar(value=file_name()) file_name_label = StringVar(value=file_name())
radio_var = IntVar() mode_var = IntVar(value=config.get("full_auto_mode", 0))
Button(controls_frame, text="Recalibrate", command=start_calibrate).grid(row=0, column=0, columnspan=2, pady=(5, 5)) Button(controls_frame, text="Calibrate", command=start_calibrate).grid(row=0, column=0, columnspan=2, pady=(5, 5))
Label(controls_frame, text="Mode: ").grid(row=1, column=0, pady=(5, 0)) Label(controls_frame, text="Mode: ").grid(row=1, column=0, pady=(5, 0))
Radiobutton(controls_frame, text="Player", variable=radio_var, value=0, command=select_radio).grid(row=1, column=1, sticky="w") Radiobutton(controls_frame, text="Player", variable=mode_var, value=FullAutoMode.Player.value, command=mode_command).grid(row=1, column=1, sticky="w")
Radiobutton(controls_frame, text="Recorder", variable=radio_var, value=1, command=select_radio).grid(row=2, column=1, sticky="w", pady=(0, 5)) Radiobutton(controls_frame, text="Recorder", variable=mode_var, value=FullAutoMode.Recorder.value, command=mode_command).grid(row=2, column=1, sticky="w", pady=(0, 5))
Button(controls_frame, text="Select fishy file", command=select_file).grid(row=3, column=0, columnspan=2, pady=(5, 0)) Button(controls_frame, text="Select fishy file", command=select_file).grid(row=3, column=0, columnspan=2, pady=(5, 0))
Label(controls_frame, textvariable=file_name_label).grid(row=4, column=0, columnspan=2, pady=(0, 5)) Label(controls_frame, textvariable=file_name_label).grid(row=4, column=0, columnspan=2, pady=(0, 5))

View File

@ -1,3 +1,4 @@
import ctypes
import logging import logging
import os import os
import shutil import shutil
@ -202,8 +203,32 @@ def restart():
os.execl(sys.executable, *([sys.executable] + sys.argv)) os.execl(sys.executable, *([sys.executable] + sys.argv))
def log_raise(msg):
logging.error(msg)
raise Exception(msg)
def update(): def update():
from .config import config from .config import config
config.delete("dont_ask_update") config.delete("dont_ask_update")
restart() restart()
# noinspection PyProtectedMember,PyUnresolvedReferences
def _get_id(thread):
# returns id of the respective thread
if hasattr(thread, '_thread_id'):
return thread._thread_id
for id, thread in threading._active.items():
if thread is thread:
return id
def kill_thread(thread):
thread_id = _get_id(thread)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,
ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')