ai fix and full-auto test setup:

gui
- enable "Debug > Keep Console" to unhide full auto
- Removed Log Dump from Debug menu

semi-auto
- starting ai fix, sometime bot doesnt start
- minimize bug fix, when minimized gui goes out of sync
- keyboard button to pause play, now bot can be paused and played using f9
- now shows running as admin message
- better error message, now tells to check #read-me-first instead

full-auto
- add tesseract binary in directory
- install addon for full auto
This commit is contained in:
DESKTOP-JVKHS7I\Adam 2020-06-25 06:52:39 +05:30
parent 648f3a8a32
commit 1ae645294d
16 changed files with 121 additions and 57 deletions

View File

@ -3,6 +3,7 @@ include README.md
include requirements.txt
include fishy/icon.ico
include fishy/ProvisionsChalutier.zip
include fishy/FooAddon.zip
include fishy/fishybot_logo.png
recursive-include tests *

BIN
fishy/FooAddon.zip Normal file

Binary file not shown.

View File

@ -1,2 +1,2 @@
from fishy.__main__ import main
__version__ = "0.3.5"
__version__ = "0.3.6"

View File

@ -11,7 +11,6 @@ from fishy import web, helper, gui
from fishy.engine.event_handler import EngineEventHandler
from fishy.gui import GUI
from fishy.helper import Config
from fishy.engine import SemiFisherEngine
# noinspection PyBroadException
@ -42,7 +41,10 @@ def initialize(c: Config, window_to_hide):
helper.install_thread_excepthook()
sys.excepthook = helper.unhandled_exception_logging
helper.check_addon()
helper.check_addon("ProvisionsChalutier")
if c.get("debug", False):
helper.check_addon("FooAddon")
def main():

View File

View File

@ -46,15 +46,16 @@ def image_pre_process(img):
return img
def get_values_from_image(img):
# noinspection PyBroadException
def get_values_from_image(img, tesseract_dir):
try:
pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files (x86)/Tesseract-OCR/tesseract.exe'
tessdata_dir_config = '--tessdata-dir "C:/Program Files (x86)/Tesseract-OCR/" -c tessedit_char_whitelist=0123456789.'
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)
vals = text.split(":")
return float(vals[0]), float(vals[1]), float(vals[2])
except:
except Exception:
logging.error("Couldn't read coods")
return None
@ -63,6 +64,7 @@ class FullAuto(IEngine):
def __init__(self, config, gui_ref):
super().__init__(config, gui_ref)
self.factors = None
self.tesseract_dir = None
def run(self):
@ -70,25 +72,35 @@ class FullAuto(IEngine):
Window.init(False)
except pywintypes.error:
logging.info("Game window not found")
self.start = False
self.toggle_start()
return
self.window = Window(color=cv2.COLOR_RGB2GRAY)
self.window.crop = get_crop_coods(self.window)
self.tesseract_dir = self.config.get("tesseract_dir", None)
time.sleep(2)
if self.tesseract_dir is None:
logging.warning("Can't start without Tesseract Directory")
self.gui.bot_started(False)
self.toggle_start()
return
if self.get_gui is not None:
self.gui.bot_started(True)
while self.start:
Window.loop()
self.window.show("test", func=image_pre_process)
Window.loop_end()
logging.info("Controlls:\nUP: Callibrate\nLEFT: Pring Coordinates\nDOWN: Quit")
with keyboard.Listener(
on_press=self.on_press,
):
while self.start:
Window.loop()
self.window.show("test", func=image_pre_process)
Window.loop_end()
self.gui.bot_started(False)
def get_coods(self):
return get_values_from_image(self.window.processed_image(func=image_pre_process))
return get_values_from_image(self.window.processed_image(func=image_pre_process), self.tesseract_dir)
def callibrate(self):
logging.debug("Callibrating...")
@ -130,7 +142,9 @@ class FullAuto(IEngine):
def on_press(self, key):
if key == Key.down:
bot.start = False
quit()
self.toggle_start()
if self.get_gui is not None:
quit()
elif key == Key.left:
logging.info(self.get_coods())
elif key == Key.up:
@ -139,6 +153,7 @@ class FullAuto(IEngine):
if __name__ == '__main__':
logging.getLogger("").setLevel(logging.DEBUG)
# noinspection PyTypeChecker
bot = FullAuto(None, None)
bot.toggle_start()
with keyboard.Listener(

View File

@ -19,16 +19,10 @@ if typing.TYPE_CHECKING:
from fishy.gui import GUI
def _wait_and_check(gui):
time.sleep(10)
if not fishing_event._FishingStarted:
gui.show_error("Doesn't look like fishing has started\n\n"
"Check out #faqs on our discord channel to troubleshoot the issue")
class SemiFisherEngine(IEngine):
def __init__(self, config, gui_ref: 'Callable[[], GUI]'):
super().__init__(config, gui_ref)
self.fishPixWindow = None
def run(self):
"""
@ -59,10 +53,15 @@ class SemiFisherEngine(IEngine):
# check for game window and stuff
self.gui.bot_started(True)
logging.info("Starting the bot engine, look at the fishing hole to start fishing")
Thread(target=_wait_and_check, args=(self.gui,)).start()
Thread(target=self._wait_and_check).start()
while self.start:
# Services to be ran in the start of the main loop
Window.loop()
success = Window.loop()
if not success:
self.gui.bot_started(False)
self.toggle_start()
continue
# get the PixelLoc and find the color values, to give it to `FishingMode.Loop`
self.fishPixWindow.crop = PixelLoc.val
@ -73,6 +72,12 @@ class SemiFisherEngine(IEngine):
logging.info("Fishing engine stopped")
self.gui.bot_started(False)
def _wait_and_check(self):
time.sleep(10)
if not fishing_event._FishingStarted and self.start:
self.gui.show_error("Doesn't look like fishing has started\n\n"
"Check out #read-me-first on our discord channel to troubleshoot the issue")
def show_pixel_vals(self):
def show():
freq = 0.5

View File

@ -10,10 +10,7 @@ class FishingMode:
Modes list of states
"""
HValues = [60, 18, 100]
Threshold = 1
CurrentCount = 0
PrevLabel = -1
CurrentMode = None
PrevMode = None
@ -52,22 +49,17 @@ class FishingMode:
:param hue_values: hue_values read by the bot
"""
if FishingMode.PrevMode is None:
FishingMode.PrevMode = FishingMode.get_by_label(3)
current_label = 3
for i, val in enumerate(FishingMode.HValues):
if hue_values == val:
current_label = i
# check if it passes threshold, if so change labelNum
if FishingMode.PrevLabel == current_label:
FishingMode.CurrentCount += 1
else:
FishingMode.CurrentCount = 0
FishingMode.PrevLabel = current_label
FishingMode.CurrentMode = FishingMode.get_by_label(current_label)
if FishingMode.CurrentCount >= FishingMode.Threshold:
FishingMode.CurrentMode = FishingMode.get_by_label(current_label)
if FishingMode.CurrentMode != FishingMode.PrevMode and FishingMode.PrevMode is not None:
if FishingMode.CurrentMode != FishingMode.PrevMode:
if FishingMode.PrevMode.event is not None:
FishingMode.PrevMode.event.on_exit_callback(FishingMode.CurrentMode)

View File

@ -67,7 +67,9 @@ class Window:
if Window.Screen.size == 0:
logging.info("Don't minimize or drag game window outside the screen")
quit(1)
return False
return True
@staticmethod
def loop_end():
@ -111,6 +113,7 @@ class Window:
def show(self, name, resize=None, func=None, ready_img=None):
"""
Displays the processed image for debugging purposes
:param ready_img: send ready image, just show the `ready_img` directly
:param name: unique name for the image, used to create a new window
:param resize: scale the image to make small images more visible
:param func: function to process the image

View File

@ -12,6 +12,24 @@ if typing.TYPE_CHECKING:
from fishy.gui import GUI
def start_fullfisher_config(gui: 'GUI'):
def save():
gui._config.set("tesseract_dir", tesseract_entry.get(), False)
gui._config.save_config()
top = PopUp(save, gui._root, background=gui._root["background"])
controls_frame = Frame(top)
top.title("Config")
Label(controls_frame, text="Tesseract Directory:").grid(row=0, column=0)
tesseract_entry = Entry(controls_frame, justify=CENTER)
tesseract_entry.insert(0, gui._config.get("tesseract_dir", ""))
tesseract_entry.grid(row=0, column=1)
controls_frame.pack(padx=(5, 5), pady=(5, 5))
top.start()
def start_semifisher_config(gui: 'GUI'):
def save():
gui._config.set("action_key", action_key_entry.get(), False)
@ -45,4 +63,3 @@ def start_semifisher_config(gui: 'GUI'):
controls_frame.pack(padx=(5, 5), pady=(5, 5))
top.start()

View File

@ -1,9 +1,13 @@
from tkinter import messagebox, NORMAL
from tkinter import messagebox
import typing
if typing.TYPE_CHECKING:
from fishy.gui import GUI
# noinspection PyProtectedMember
class GUIFuncs:
def __init__(self, gui):
def __init__(self, gui: 'GUI'):
self.gui = gui
def show_error(self, error):
@ -12,6 +16,12 @@ class GUIFuncs:
def bot_started(self, started):
def func():
self.gui._bot_running = started
self.gui._start_button["text"] = "STOP" if self.gui._bot_running else "START"
self.gui._start_button["text"] = self.gui._get_start_stop_text()
self.gui.call_in_thread(func)
def quit(self):
def func():
self.gui._root.destroy()
self.gui.call_in_thread(func)

View File

@ -2,9 +2,10 @@ import logging
from typing import List, Callable
import threading
from ttkthemes import ThemedTk
from fishy.engine.event_handler import EngineEventHandler
from fishy.gui.funcs import GUIFuncs
from fishy.engine import SemiFisherEngine
from . import main_gui
from .log_config import GUIStreamHandler
from fishy.helper import Config
@ -26,7 +27,7 @@ class GUI:
self._bot_running = False
# UI items
self._root = None
self._root: ThemedTk = None
self._console = None
self._start_button = None
self._notify = None
@ -57,3 +58,6 @@ class GUI:
def call_in_thread(self, func: Callable):
self._function_queue.append(func)
def _get_start_stop_text(self):
return "STOP (F9)" if self._bot_running else "START (F9)"

View File

@ -2,9 +2,12 @@ import logging
import time
from tkinter import *
from tkinter.ttk import *
from pynput import keyboard
from pynput.keyboard import Key
from ttkthemes import ThemedTk
from fishy import helper, web
from fishy import helper
from fishy.gui import config_top
import typing
@ -25,10 +28,11 @@ def _apply_theme(gui: 'GUI'):
def _create(gui: 'GUI'):
engines = {
"Semi Fisher": [lambda: config_top.start_semifisher_config(gui), gui.engine.toggle_semifisher],
"Full-Auto Fisher": [not_implemented, gui.engine.toggle_fullfisher],
# "Lock Picker": [not_implemented, not_implemented]
}
if gui._config.get('debug', False):
engines["Full-Auto Fisher"] = [lambda: config_top.start_fullfisher_config(gui), gui.engine.toggle_fullfisher]
def start_engine(label):
gui._config.set("last_started", label)
engines[label][1]()
@ -67,7 +71,6 @@ def _create(gui: 'GUI'):
logging.debug("Restart to update the changes")
debug_menu.add_checkbutton(label="Keep Console", command=keep_console, variable=debug_var)
debug_menu.add_command(label="Log Dump", command=not_implemented)
debug_menu.add_command(label="Restart", command=helper.restart)
menubar.add_cascade(label="Debug", menu=debug_menu)
@ -99,7 +102,7 @@ def _create(gui: 'GUI'):
config_button = Button(start_frame, text="", width=0, command=lambda: engines[engine_var.get()][0]())
config_button.pack(side=RIGHT)
gui._start_button = Button(start_frame, text="STOP" if gui._bot_running else "START", width=25,
gui._start_button = Button(start_frame, text=gui._get_start_stop_text(), width=25,
command=lambda: start_engine(engine_var.get()))
gui._start_button.pack(side=RIGHT)
@ -110,6 +113,15 @@ def _create(gui: 'GUI'):
gui._root.update()
gui._root.minsize(gui._root.winfo_width() + 10, gui._root.winfo_height() + 10)
def keyboard_listener(key):
if key == Key.f9:
gui.call_in_thread(lambda: start_engine(engine_var.get()))
kb_listener = keyboard.Listener(
on_press=keyboard_listener,
)
kb_listener.start()
def set_destroy():
gui._destroyed = True
@ -128,3 +140,5 @@ def _create(gui: 'GUI'):
gui.engine.quit()
break
time.sleep(0.01)
kb_listener.stop()

View File

@ -118,19 +118,18 @@ def create_shortcut():
# noinspection PyBroadException
def check_addon():
def check_addon(name):
"""
Extracts the addon from zip and installs it into the AddOn folder of eso
"""
try:
user = os.path.expanduser("~")
addon_dir = os.path.join(user, "Documents", "Elder Scrolls Online", "live", "Addons")
if not os.path.exists(os.path.join(addon_dir, 'ProvisionsChalutier')):
logging.info("Addon not found, installing it...")
with ZipFile(manifest_file("ProvisionsChalutier.zip"), 'r') as z:
if not os.path.exists(os.path.join(addon_dir, name)):
logging.info(f"{name} Addon not found, installing it...")
with ZipFile(manifest_file(f"{name}.zip"), 'r') as z:
z.extractall(path=addon_dir)
logging.info("Please make sure you enable \"Allow outdated addons\" in-game\n"
"Also, make sure the addon is visible clearly on top left corner of the game window")
logging.info("Please make sure you enable \"Allow outdated addons\" in-game")
except Exception:
logging.error("couldn't install addon, try doing it manually")

View File

@ -9,7 +9,7 @@ def center(win):
height = win.winfo_height()
offset_x = win.master.winfo_x() + win.master.winfo_width() // 2 - (width // 2)
offset_y = win.master.winfo_y()+ win.master.winfo_height() // 2 - (height // 2)
offset_y = win.master.winfo_y() + win.master.winfo_height() // 2 - (height // 2)
win.geometry('{}x{}+{}+{}'.format(width, height, offset_x, offset_y))
@ -18,7 +18,7 @@ class PopUp(Toplevel):
def __init__(self, quit_callback, *args, **kwargs):
super().__init__(*args, **kwargs)
self.running = True
self.quit_callback = quit_callback
self.quit_callback = quit_callback
def quit_top(self):
self.quit_callback()

View File

@ -10,3 +10,5 @@ pyautogui
requests
beautifulsoup4
whatsmyip
pynput
pytesseract