gui interface re created for multi threading

This commit is contained in:
DESKTOP-JVKHS7I\Adam 2020-04-17 18:15:22 +05:30
parent ba20738cbf
commit 49fa3c6294
6 changed files with 198 additions and 168 deletions

View File

@ -13,14 +13,10 @@ Options:
--borderless Use if the game is in fullscreen or borderless window
"""
import time
import cv2
from docopt import docopt
from pynput.keyboard import Listener
from fishy.systems import *
import logging
"""
Start reading from `init.py`
@ -59,10 +55,7 @@ def on_release(key):
elif c[0] == Control.Keywords.SwitchMode:
Control.nextState()
Log.ctrl()
elif c[0] == Control.Keywords.ClearPrintOnce:
Log.clearPrintIds()
logging.info(Control.getControlHelp())
def hsv2rgb(img):
@ -81,15 +74,13 @@ def startFishing():
if use_net:
net.initialize(G.arguments["--ip"])
sleepFor = 1
# initializes fishing modes and their callbacks
FishingMode("hook", 0, HookEvent())
FishingMode("stick", 1, StickEvent())
FishingMode("look", 2, LookEvent())
FishingMode("idle", 3, IdleEvent(use_net))
Log.ctrl()
logging.info(Control.getControlHelp())
fishPixWindow = Window(color=cv2.COLOR_RGB2HSV)
@ -98,11 +89,9 @@ def startFishing():
with Listener(on_release=on_release):
while not G.stop:
# record the time to calculate time taken to execute one loop
current_time = time.time()
# Services to be ran in the start of the main loop
Window.Loop()
Log.Loop()
# get the PixelLoc and find the color values, to give it to `FishingMode.Loop`
fishPixWindow.crop = PixelLoc.val
@ -112,20 +101,11 @@ def startFishing():
# if debug is on, show the color on the PixelLoc in a window and print the hue values of it
if G.debug:
fishPixWindow.show("pixloc", resize=200, func=hsv2rgb)
Log.ou(str(FishingMode.CurrentMode.label) + ":" + str(fishPixWindow.getCapture()[0][0]))
logging.debug(str(FishingMode.CurrentMode.label) + ":" + str(fishPixWindow.getCapture()[0][0]))
# Services to be ran in the end of the main loop
Log.LoopEnd()
Window.LoopEnd()
# calculate the time it took to execute one loop of code, if it is more than the expected time warn user
frameTime = time.time() - current_time
if frameTime < sleepFor:
time.sleep(sleepFor - frameTime)
else:
Log.po(231, "Program taking more time than expected, this might slow your computer try increasing "
"\"--check-frequency\".")
def main():
G.arguments = docopt(__doc__)

View File

@ -2,7 +2,6 @@ from fishy.systems.controls import Control
from fishy.systems.fishing_event import HookEvent, StickEvent, LookEvent, IdleEvent
from fishy.systems.fishing_mode import FishingMode
from fishy.systems.globals import G
from fishy.systems.log import Log
from fishy.systems.pixel_loc import PixelLoc
import fishy.systems.fishy_network as net
from fishy.systems.window import Window

View File

@ -0,0 +1 @@
{"dark_mode": true}

23
fishy/systems/config.py Normal file
View File

@ -0,0 +1,23 @@
import json
import os
filename = "config.json"
class Config:
def __init__(self):
self.config_dict = json.loads(open(filename).read()) if os.path.exists(filename) else dict()
def get(self, key, default=None):
if key in self.config_dict:
return self.config_dict[key]
return default
def set(self, key, value):
self.config_dict[key] = value
self.save_config()
def save_config(self):
with open(filename, 'w') as f:
f.write(json.dumps(self.config_dict))

View File

@ -1,97 +1,187 @@
import time
from enum import Enum
from tkinter import *
from tkinter.ttk import *
from ttkthemes import ThemedTk
from waiting import wait
import threading
dark_mode = False
from fishy.systems.config import Config
def toggle_theme():
global dark_mode
dark_mode = not dark_mode
apply_theme(dark_mode)
root.destroy()
class Callback(Enum):
START = 0,
SHORTCUT = 1,
CHECK_PIXELVAL = 2,
LOG_DUMP = 3
def apply_theme(dark):
root["theme"] = "equilux" if dark else "breeze"
console["background"] = "#707070" if dark else "#ffffff"
console["fg"] = "#ffffff" if dark else "#000000"
class GUICallback:
def __init__(self, start_callback=None,
shortcut_callback=None,
check_pixelval_callback=None,
log_dump_callback=None
):
self.start_callback = start_callback
self.shortcut_callback = shortcut_callback
self.check_pixelval_callback = check_pixelval_callback
self.log_dump_callback = log_dump_callback
def start():
writeToLog(console, "yo")
def call(self, callback_enum, args=None):
to_call = None
if callback_enum == Callback.START:
to_call = self.start_callback
elif callback_enum == Callback.SHORTCUT:
to_call = self.shortcut_callback
elif callback_enum == Callback.CHECK_PIXELVAL:
to_call = self.check_pixelval_callback
elif callback_enum == Callback.LOG_DUMP:
to_call = self.log_dump_callback
if to_call is None:
return
threading.Thread(target=to_call, args=(*args,)).start()
def writeToLog(log, msg):
numlines = log.index('end - 1 line').split('.')[0]
log['state'] = 'normal'
if int(numlines) >= 50: # delete old lines
log.delete(1.0, 2.0)
if log.index('end-1c') != '1.0': # new line for each log
log.insert('end', '\n')
log.insert('end', msg)
log.see("end") # scroll to bottom
log['state'] = 'disabled'
class GUI:
def __init__(self, gui_callback=None,
config: Config = None):
self.callbacks = GUICallback() if gui_callback is None else gui_callback
self.config = config
self.start_restart = False
self.destroyed = True
self.root = None
self._log_strings = []
self.console = None
def create(self):
self.root = ThemedTk(theme="equilux", background=True)
self.root.title("Fiishybot for Elder Scrolls Online")
self.root.geometry('650x550')
# region menu
menubar = Menu(self.root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Create Shortcut", command=lambda: self.callbacks.call(Callback.SHORTCUT))
filemenu.add_command(label="{} Dark Mode".format("Disable" if self.config.get("dark_mode", True) else "Enable"),
command=self._toggle_mode)
menubar.add_cascade(label="File", menu=filemenu)
debug_menu = Menu(menubar, tearoff=0)
debug_menu.add_command(label="Check PixelVal",
command=lambda: self.callbacks.call(Callback.CHECK_PIXELVAL))
debug_menu.add_command(label="Log Dump")
menubar.add_cascade(label="Debug", menu=debug_menu, command=lambda: self.callbacks.call(Callback.LOG_DUMP))
self.root.config(menu=menubar)
# endregion
# region console
self.console = Text(self.root, state='disabled', wrap='none', background="#707070", fg="#ffffff")
self.console.pack(fill=BOTH, expand=True, pady=(15, 15), padx=(5, 5))
self.console.mark_set("sentinel", INSERT)
self.console.config(state=DISABLED)
controls_frame = Frame(self.root)
# endregion
# region controls
left_frame = Frame(controls_frame)
Label(left_frame, text="IP").grid(row=0, column=0)
ip = Entry(left_frame)
ip.grid(row=0, column=1)
Label(left_frame, text="Fullscreen: ").grid(row=1, column=0, pady=(5, 5))
borderless = Checkbutton(left_frame)
borderless.grid(row=1, column=1)
left_frame.grid(row=0, column=0)
right_frame = Frame(controls_frame)
Label(right_frame, text="Action Key:").grid(row=0, column=0)
action_key_entry = Entry(right_frame)
action_key_entry.grid(row=0, column=1)
action_key_entry.insert(0, "e")
Label(right_frame, text="Press start").grid(row=1, columnspan=2, pady=(5, 5))
right_frame.grid(row=0, column=1, padx=(50, 0))
controls_frame.pack()
Button(self.root, text="START", width=25,
command=lambda: self.callbacks.call(Callback.START,
(ip.get(), action_key_entry.get(), borderless.instate(['selected'])))
).pack(pady=(15, 15))
# endregion
self._apply_theme(self.config.get("dark_mode", True))
self.root.update()
self.root.minsize(self.root.winfo_width(), self.root.winfo_height())
self.root.protocol("WM_DELETE_WINDOW", self._set_destroyed)
self.destroyed = False
while True:
self.root.update()
self._update_console()
if self.start_restart:
self.root.destroy()
self.root.quit()
self.start_restart = False
self.create()
if self.destroyed:
break
time.sleep(0.01)
def _apply_theme(self, dark):
self.root["theme"] = "equilux" if dark else "breeze"
self.console["background"] = "#707070" if dark else "#ffffff"
self.console["fg"] = "#ffffff" if dark else "#000000"
def start(self):
threading.Thread(target=self.create, args=()).start()
def _toggle_mode(self):
self.config.set("dark_mode", not self.config.get("dark_mode", True))
self.start_restart = True
def _set_destroyed(self):
self.destroyed = True
def writeToLog(self, msg):
self._log_strings.append(msg)
def _update_console(self):
while len(self._log_strings) > 0:
msg = self._log_strings.pop(0)
numlines = self.console.index('end - 1 line').split('.')[0]
self.console['state'] = 'normal'
if int(numlines) >= 50: # delete old lines
self.console.delete(1.0, 2.0)
if self.console.index('end-1c') != '1.0': # new line for each log
self.console.insert('end', '\n')
self.console.insert('end', msg)
self.console.see("end") # scroll to bottom
self.console['state'] = 'disabled'
while True:
root = ThemedTk(theme="equilux", background=True)
root.title("Fiishybot for Elder Scrolls Online")
root.geometry('650x550')
def start(ip, actionkey, fullscreen):
print(f"{ip}, {actionkey}, {fullscreen}")
# region menu
menubar = Menu(root)
def main():
config = Config()
gui = GUI(config=config, gui_callback=GUICallback(start_callback=start))
gui.start()
wait(lambda: not gui.destroyed)
while not gui.destroyed:
gui.writeToLog("yo")
time.sleep(1)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Create Shortcut", command=start)
filemenu.add_command(label="Disable Dark Mode", command=toggle_theme)
menubar.add_cascade(label="File", menu=filemenu)
debug_menu = Menu(menubar, tearoff=0)
debug_menu.add_command(label="Check PixelVal", command=start)
debug_menu.add_command(label="Log Dump", command=start)
menubar.add_cascade(label="Debug", menu=debug_menu)
root.config(menu=menubar)
# endregion
# region console
console = Text(root, state='disabled', wrap='none', background="#707070", fg="#ffffff")
console.pack(fill=BOTH, expand=True, pady=(15, 15), padx=(5, 5))
console.mark_set("sentinel", INSERT)
console.config(state=DISABLED)
controls_frame = Frame(root)
# endregion
# region controls
left_frame = Frame(controls_frame)
Label(left_frame, text="IP").grid(row=0, column=0)
ip = Entry(left_frame)
ip.grid(row=0, column=1)
Label(left_frame, text="Fullscreen: ").grid(row=1, column=0, pady=(5, 5))
borderless = Checkbutton(left_frame)
borderless.grid(row=1, column=1)
left_frame.grid(row=0, column=0)
right_frame = Frame(controls_frame)
Label(right_frame, text="Action Key:").grid(row=0, column=0)
action_key_entry = Entry(right_frame)
action_key_entry.grid(row=0, column=1)
action_key_entry.insert(0, "e")
Label(right_frame, text="Press start").grid(row=1, columnspan=2, pady=(5, 5))
right_frame.grid(row=0, column=1, padx=(50, 0))
controls_frame.pack()
Button(root, text="START", width=25, command=start).pack(pady=(15, 15))
# endregion
apply_theme(dark_mode)
root.update()
root.minsize(root.winfo_width(), root.winfo_height())
root.mainloop()
if __name__ == '__main__':
main()

View File

@ -1,63 +0,0 @@
from fishy.systems.controls import Control
class Log:
"""
Simple logging script
"""
ouUsed = False
prevOuUsed = False
printIds = []
@staticmethod
def Loop():
"""
Method to be called in the start of the main loop
"""
Log.ouUsed = False
@staticmethod
def LoopEnd():
"""
method to be called in the end of the main loop
"""
if Log.prevOuUsed and not Log.ouUsed:
Log.ctrl()
Log.prevOuUsed = Log.ouUsed
@staticmethod
def ctrl():
"""
Logs the control manual for the current control state
"""
print(Control.getControlHelp())
@staticmethod
def ou(s):
"""
Logging output which is supposed to dumps a lot of data,
so that after it ends, controls help is printed again
:param s: string to log
"""
Log.ouUsed = True
print(s)
@staticmethod
def po(i, s):
"""
print once
logs the string passed only once event if it is called multiple times
:param i: unique integer
:param s: string to log
"""
if i not in Log.printIds:
print(s)
Log.printIds.append(i)
@staticmethod
def clearPrintIds():
"""
clears print id for print once, so that it is printed again
"""
Log.printIds = []