Merge remote-tracking branch 'origin/master' into feature/fullauto

# Conflicts:
#	fishy/engine/fullautofisher/controls.py
#	fishy/engine/fullautofisher/engine.py
#	fishy/engine/fullautofisher/mode/calibrator.py
#	fishy/engine/fullautofisher/mode/recorder.py
#	fishy/engine/fullautofisher/player.py
#	fishy/engine/semifisher/fishing_event.py
#	fishy/gui/config_top.py
This commit is contained in:
Adam Saudagar 2021-05-12 20:44:55 +05:30
commit 8f7b6b71c4
30 changed files with 378 additions and 285 deletions

View File

@ -3,16 +3,17 @@ import logging
import os import os
import sys import sys
import traceback import traceback
import win32con import win32con
import win32gui import win32gui
import fishy import fishy
from fishy import web, helper, gui from fishy import gui, helper, web
from fishy.constants import chalutier, lam2
from fishy.engine.common.event_handler import EngineEventHandler from fishy.engine.common.event_handler import EngineEventHandler
from fishy.gui import GUI, splash, update_dialog from fishy.gui import GUI, splash, update_dialog
from fishy.helper import hotkey from fishy.helper import hotkey
from fishy.helper.config import config from fishy.helper.config import config
from fishy.constants import chalutier, lam2
def check_window_name(title): def check_window_name(title):
@ -42,8 +43,8 @@ def initialize(window_to_hide):
try: try:
if helper.upgrade_avail() and not config.get("dont_ask_update", False): if helper.upgrade_avail() and not config.get("dont_ask_update", False):
cv,hv = helper.versions() cv, hv = helper.versions()
update_now, dont_ask_update = update_dialog.start(cv,hv) update_now, dont_ask_update = update_dialog.start(cv, hv)
if dont_ask_update: if dont_ask_update:
config.set("dont_ask_update", dont_ask_update) config.set("dont_ask_update", dont_ask_update)
else: else:

View File

@ -1,5 +1,5 @@
apiversion = 2 apiversion = 2
chalutier = ("Chalutier", "https://github.com/fishyboteso/Chalutier/raw/619b4ab0b8ff91746afda855542e886d27b7a794/Chalutier_1.1.2.zip", 112) chalutier = ("Chalutier", "https://www.esoui.com/downloads/dl2934/Chalutier_1.1.4.zip", 114)
lam2 = ("LibAddonMenu-2.0", "https://www.esoui.com/downloads/dl7/LibAddonMenu-2.0r32.zip", 32) lam2 = ("LibAddonMenu-2.0", "https://www.esoui.com/downloads/dl7/LibAddonMenu-2.0r32.zip", 32)
fishyqr = ("FishyQR", "https://github.com/fishyboteso/FishyQR/files/6329586/FishyQR.zip", 100) fishyqr = ("FishyQR", "https://github.com/fishyboteso/FishyQR/files/6329586/FishyQR.zip", 100)

View File

@ -5,7 +5,7 @@ import cv2
import imutils import imutils
from fishy.engine.common import window_server from fishy.engine.common import window_server
from fishy.engine.common.window_server import WindowServer, Status from fishy.engine.common.window_server import Status, WindowServer
from fishy.helper import helper from fishy.helper import helper

View File

@ -1,16 +1,14 @@
import logging import logging
import math
from enum import Enum from enum import Enum
from threading import Thread from threading import Thread
import cv2 import cv2
import math import numpy as np
import pywintypes import pywintypes
import win32gui import win32gui
from win32api import GetSystemMetrics
import numpy as np
from PIL import ImageGrab from PIL import ImageGrab
from win32api import GetSystemMetrics
from fishy.helper.config import config from fishy.helper.config import config
@ -60,8 +58,6 @@ def loop():
temp_screen = np.array(ImageGrab.grab(bbox=bbox)) temp_screen = np.array(ImageGrab.grab(bbox=bbox))
temp_screen = cv2.cvtColor(temp_screen, cv2.COLOR_BGR2RGB)
rect = win32gui.GetWindowRect(WindowServer.hwnd) rect = win32gui.GetWindowRect(WindowServer.hwnd)
crop = ( crop = (
rect[0] + WindowServer.windowOffset, rect[1] + WindowServer.titleOffset, rect[2] - WindowServer.windowOffset, rect[0] + WindowServer.windowOffset, rect[1] + WindowServer.titleOffset, rect[2] - WindowServer.windowOffset,

View File

@ -1,29 +1,29 @@
import math import math
import logging
import math
import time
import traceback import traceback
from threading import Thread from threading import Thread
import cv2 import cv2
import logging from pynput import keyboard, mouse
import time
from fishy.constants import libgps, fishyqr, lam2 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
from fishy.engine.fullautofisher.mode.calibrator import Calibrator from fishy.engine.fullautofisher.mode.calibrator import Calibrator
from fishy.engine.fullautofisher.mode.imode import FullAutoMode from fishy.engine.fullautofisher.mode.imode import FullAutoMode
from fishy.engine.fullautofisher.mode.player import Player from fishy.engine.fullautofisher.mode.player import Player
from fishy.engine.fullautofisher.mode.recorder import Recorder 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_qr_location,
get_values_from_image)
from fishy.engine.semifisher import fishing_event, fishing_mode
from fishy.engine.semifisher.fishing_mode import FishingMode from fishy.engine.semifisher.fishing_mode import FishingMode
from fishy.helper import helper, hotkey
from fishy.engine import SemiFisherEngine
from fishy.engine.common.window import WindowClient
from fishy.engine.semifisher import fishing_mode, fishing_event
from fishy.engine.common.IEngine import IEngine
from pynput import keyboard, mouse
from fishy.helper import hotkey, helper
from fishy.helper.helper import sign, log_raise, wait_until, is_eso_active
from fishy.helper.config import config from fishy.helper.config import config
from fishy.helper.helper import log_raise, wait_until, is_eso_active
from fishy.helper.helper import sign
mse = mouse.Controller() mse = mouse.Controller()
kb = keyboard.Controller() kb = keyboard.Controller()
@ -42,7 +42,6 @@ class FullAuto(IEngine):
rotate_by = 30 rotate_by = 30
def __init__(self, gui_ref): def __init__(self, gui_ref):
from fishy.engine.fullautofisher.mode.calibrator import Calibrator
from fishy.engine.fullautofisher.test import Test from fishy.engine.fullautofisher.test import Test
super().__init__(gui_ref) super().__init__(gui_ref)

View File

@ -1,16 +1,17 @@
import math
import logging import logging
import math
import time import time
import typing
import cv2 import cv2
import numpy as np import numpy as np
import typing
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from fishy.engine.fullautofisher.engine import FullAuto from fishy.engine.fullautofisher.engine import FullAuto
from pynput import keyboard, mouse
from fishy.engine.fullautofisher.mode.imode import IMode from fishy.engine.fullautofisher.mode.imode import IMode
from pynput import keyboard, mouse
from fishy.helper.config import config from fishy.helper.config import config
mse = mouse.Controller() mse = mouse.Controller()
@ -125,4 +126,3 @@ class Calibrator(IMode):
self._rotate_calibrate() self._rotate_calibrate()
config.set("calibrate", False) config.set("calibrate", False)
logging.info("calibration done") logging.info("calibration done")

View File

@ -2,20 +2,17 @@ import logging
import os import os
import pickle import pickle
import time import time
from pprint import pprint import typing
from tkinter.filedialog import asksaveasfile from tkinter.filedialog import asksaveasfile
import typing
from fishy.helper.config import config
from playsound import playsound from playsound import playsound
from fishy import helper from fishy import helper
from fishy.helper.config import config
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from fishy.engine.fullautofisher.engine import FullAuto from fishy.engine.fullautofisher.engine import FullAuto
from fishy.engine.fullautofisher.mode.imode import IMode 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
@ -71,4 +68,3 @@ class Recorder(IMode):
config.set("full_auto_rec_file", file.name) config.set("full_auto_rec_file", file.name)
logging.info(f"saved {os.path.basename(file.name)} recording, and loaded it in player") logging.info(f"saved {os.path.basename(file.name)} recording, and loaded it in player")
file.close() file.close()

View File

@ -3,12 +3,11 @@ import os
from datetime import datetime from datetime import datetime
import cv2 import cv2
from fishy.helper.helper import get_documents
import numpy as np import numpy as np
from pyzbar.pyzbar import decode from pyzbar.pyzbar import decode
from fishy.helper.helper import get_documents
def get_qr_location(og_img): def get_qr_location(og_img):
""" """

View File

@ -1,20 +1,19 @@
import logging
import time import time
import typing import typing
from threading import Thread from threading import Thread
from typing import Callable from typing import Callable, Optional
from typing import Optional
import cv2 from playsound import playsound
import logging
from fishy.engine.semifisher.fishing_event import FishEvent
from fishy.engine.common.window import WindowClient
from fishy.engine.semifisher.fishing_mode import FishingMode
from fishy.engine.common.IEngine import IEngine from fishy.engine.common.IEngine import IEngine
from fishy.engine.semifisher import fishing_mode, fishing_event from fishy.engine.common.window import WindowClient
from fishy.engine.semifisher import fishing_event, fishing_mode
from fishy.engine.semifisher.fishing_event import FishEvent
from fishy.engine.semifisher.fishing_mode import Colors, FishingMode
from fishy.engine.semifisher.pixel_loc import PixelLoc from fishy.engine.semifisher.pixel_loc import PixelLoc
from fishy.helper import helper
from fishy.helper.luaparser import sv_color_extract
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from fishy.gui import GUI from fishy.gui import GUI
@ -31,11 +30,13 @@ class SemiFisherEngine(IEngine):
code explained in comments in detail code explained in comments in detail
""" """
fishing_event.init() fishing_event.init()
self.fishPixWindow = WindowClient(color=cv2.COLOR_RGB2HSV) self.fishPixWindow = WindowClient()
# check for game window and stuff # check for game window and stuff
self.gui.bot_started(True) self.gui.bot_started(True)
sv_color_extract(Colors)
if self.get_gui: if self.get_gui:
logging.info("Starting the bot engine, look at the fishing hole to start fishing") logging.info("Starting the bot engine, look at the fishing hole to start fishing")
Thread(target=self._wait_and_check).start() Thread(target=self._wait_and_check).start()
@ -51,6 +52,7 @@ class SemiFisherEngine(IEngine):
self.fishPixWindow.crop = PixelLoc.val self.fishPixWindow.crop = PixelLoc.val
fishing_mode.loop(capture[0][0]) fishing_mode.loop(capture[0][0])
time.sleep(0.1)
logging.info("Fishing engine stopped") logging.info("Fishing engine stopped")
self.gui.bot_started(False) self.gui.bot_started(False)
@ -60,7 +62,8 @@ class SemiFisherEngine(IEngine):
def _wait_and_check(self): def _wait_and_check(self):
time.sleep(10) time.sleep(10)
if not FishEvent.FishingStarted and self.start: if not FishEvent.FishingStarted and self.start:
logging.warning("Doesn't look like fishing has started \nCheck out #read-me-first on our discord channel to troubleshoot the issue") logging.warning("Doesn't look like fishing has started \n"
"Check out #read-me-first on our discord channel to troubleshoot the issue")
def show_pixel_vals(self): def show_pixel_vals(self):
def show(): def show():
@ -80,6 +83,9 @@ class SemiFisherEngine(IEngine):
if self.start: if self.start:
self.thread = Thread(target=self.run) self.thread = Thread(target=self.run)
self.thread.start() self.thread.start()
playsound(helper.manifest_file("beep.wav"), False)
else:
helper.playsound_multiple(helper.manifest_file("beep.wav"))
if __name__ == '__main__': if __name__ == '__main__':
@ -87,4 +93,3 @@ if __name__ == '__main__':
# noinspection PyTypeChecker # noinspection PyTypeChecker
fisher = SemiFisherEngine(None) fisher = SemiFisherEngine(None)
fisher.toggle_start() fisher.toggle_start()

View File

@ -4,21 +4,17 @@ Defines different fishing modes (states) which acts as state for state machine
also implements callbacks which is called when states are changed also implements callbacks which is called when states are changed
""" """
import logging import logging
import random
import time import time
from fishy.engine.semifisher import fishing_mode import keyboard
from playsound import playsound from playsound import playsound
from fishy import web from fishy import web
from fishy.engine.semifisher.fishing_mode import State, FishingMode from fishy.engine.semifisher import fishing_mode
from fishy.engine.semifisher.fishing_mode import FishingMode, State
from fishy.helper import helper from fishy.helper import helper
import keyboard
from win32gui import GetWindowText, GetForegroundWindow
from fishy.helper.config import config from fishy.helper.config import config
import random
from fishy.helper.helper import is_eso_active from fishy.helper.helper import is_eso_active
@ -38,11 +34,11 @@ class FishEvent:
sound = False sound = False
def _fishing_sleep(waittime, lower_limit_ms = 16, upper_limit_ms = 2500): def _fishing_sleep(waittime, lower_limit_ms=16, upper_limit_ms=2500):
reaction = 0.0 reaction = 0.0
if FishEvent.jitter and upper_limit_ms > lower_limit_ms: if FishEvent.jitter and upper_limit_ms > lower_limit_ms:
reaction = float( random.randrange(lower_limit_ms, upper_limit_ms) )/1000.0 reaction = float(random.randrange(lower_limit_ms, upper_limit_ms)) / 1000.0
max_wait_t = waittime+reaction if waittime+reaction <= 2.5 else 2.5 max_wait_t = waittime + reaction if waittime + reaction <= 2.5 else 2.5
time.sleep(max_wait_t) time.sleep(max_wait_t)
@ -57,7 +53,7 @@ def if_eso_is_focused(func):
def _sound_and_send_fishy_data(): def _sound_and_send_fishy_data():
if FishEvent.fishCaught > 0: if FishEvent.fishCaught > 0:
web.send_hole_deplete(FishEvent.fishCaught, time.time() - FishEvent.hole_start_time, FishEvent.fish_times) web.send_fish_caught(FishEvent.fishCaught, time.time() - FishEvent.hole_start_time, FishEvent.fish_times)
FishEvent.fishCaught = 0 FishEvent.fishCaught = 0
if FishEvent.sound: if FishEvent.sound:
@ -89,22 +85,25 @@ def subscribe():
def fisher_callback(event: State): def fisher_callback(event: State):
callbacks_map = { callbacks_map = {
State.IDLE: on_idle, State.IDLE: on_idle,
State.LOOKAWAY: on_lookaway, State.LOOKAWAY: on_idle,
State.LOOKING: on_looking, State.LOOKING: on_looking,
State.DEPLETED: on_depleted, State.DEPLETED: on_depleted,
State.NOBAIT: on_nobait, State.NOBAIT: lambda: on_user_interact("You need to equip bait!"),
State.FISHING: on_fishing, State.FISHING: on_fishing,
State.REELIN: on_reelin, State.REELIN: on_reelin,
State.LOOT: on_loot, State.LOOT: on_loot,
State.INVFULL: on_invfull, State.INVFULL: lambda: on_user_interact("Inventory is full!"),
State.FIGHT: on_fight, State.FIGHT: lambda: on_user_interact("Character is FIGHTING!"),
State.DEAD: on_dead State.DEAD: lambda: on_user_interact("Character died!")
} }
try: try:
callbacks_map[event]() callbacks_map[event]()
FishEvent.previousState = event FishEvent.previousState = event
except KeyError as ex: except KeyError:
pass logging.error("KeyError: State " + str(event) + " is not known.")
except TypeError:
logging.error("TypeError when reading state: " + str(event))
def on_idle(): def on_idle():
@ -118,10 +117,6 @@ def on_depleted():
_sound_and_send_fishy_data() _sound_and_send_fishy_data()
def on_lookaway():
return
@if_eso_is_focused @if_eso_is_focused
def on_looking(): def on_looking():
""" """
@ -131,11 +126,13 @@ def on_looking():
keyboard.press_and_release(FishEvent.action_key) keyboard.press_and_release(FishEvent.action_key)
def on_nobait(): def on_user_interact(msg):
msg = "No bait equipped!"
logging.info(msg) logging.info(msg)
web.send_notification(msg) web.send_notification(msg)
if FishEvent.sound:
playsound(helper.manifest_file("sound.mp3"), False)
def on_fishing(): def on_fishing():
FishEvent.stickInitTime = time.time() FishEvent.stickInitTime = time.time()
@ -169,21 +166,3 @@ def on_loot():
_fishing_sleep(0) _fishing_sleep(0)
keyboard.press_and_release(FishEvent.collect_key) keyboard.press_and_release(FishEvent.collect_key)
_fishing_sleep(0) _fishing_sleep(0)
def on_invfull():
msg = "Inventory full!"
logging.info(msg)
web.send_notification(msg)
def on_fight():
msg = "FIGHTING!"
logging.info(msg)
web.send_notification(msg)
def on_dead():
msg = "Character is dead!"
logging.info(msg)
web.send_notification(msg)

View File

@ -1,21 +1,36 @@
import time
from enum import Enum from enum import Enum
subscribers = [] subscribers = []
class State(Enum): class State(Enum):
IDLE = [ 0, 0, 255] IDLE = 0
LOOKAWAY = [150, 255, 76] LOOKAWAY = 1
LOOKING = [100, 255, 101] LOOKING = 2
DEPLETED = [ 30, 255, 76] DEPLETED = 3
NOBAIT = [ 96, 255, 255] NOBAIT = 5
FISHING = [ 18, 165, 213] FISHING = 6
REELIN = [ 60, 255, 204] REELIN = 7
LOOT = [ 0, 255, 204] LOOT = 8
INVFULL = [ 0, 255, 51] INVFULL = 9
FIGHT = [120, 255, 204] FIGHT = 14
DEAD = [ 0, 0, 51] DEAD = 15
Colors = {
State.IDLE : [255, 255, 255],
State.LOOKAWAY : [ 76, 0, 76],
State.LOOKING : [101, 69, 0],
State.DEPLETED : [ 0, 76, 76],
State.NOBAIT : [255, 204, 0],
State.FISHING : [ 75, 156, 213],
State.REELIN : [ 0, 204, 0],
State.LOOT : [ 0, 0, 204],
State.INVFULL : [ 0, 0, 51],
State.FIGHT : [204, 0, 0],
State.DEAD : [ 51, 51, 51]
}
def _notify(event): def _notify(event):
for subscriber in subscribers: for subscriber in subscribers:
@ -27,16 +42,16 @@ class FishingMode:
PrevMode = State.IDLE PrevMode = State.IDLE
def loop(hsv): def loop(rgb):
""" """
Executed in the start of the main loop in fishy.py Executed in the start of the main loop in fishy.py
Changes modes, calls mode events (callbacks) when mode is changed Changes modes, calls mode events (callbacks) when mode is changed
:param hsv: hsv read by the bot :param rgb: rgb read by the bot
""" """
FishingMode.CurrentMode = State.IDLE FishingMode.CurrentMode = State.IDLE
for s in State: for s in State:
if all(hsv == s.value): if all(rgb == Colors[s]):
FishingMode.CurrentMode = s FishingMode.CurrentMode = s
if FishingMode.CurrentMode != FishingMode.PrevMode: if FishingMode.CurrentMode != FishingMode.PrevMode:

View File

@ -1,5 +1,7 @@
import logging import logging
import os import os
import tkinter as tk
import tkinter.ttk as ttk
import typing import typing
from tkinter.filedialog import askopenfilename from tkinter.filedialog import askopenfilename
@ -8,10 +10,7 @@ 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
from fishy.helper import helper
from tkinter import *
from tkinter.ttk import *
from fishy.helper.config import config from fishy.helper.config import config
from fishy.helper.popup import PopUp from fishy.helper.popup import PopUp
@ -21,7 +20,7 @@ if typing.TYPE_CHECKING:
def start_fullfisher_config(gui: 'GUI'): def start_fullfisher_config(gui: 'GUI'):
top = PopUp(helper.empty_function, gui._root, background=gui._root["background"]) top = PopUp(helper.empty_function, gui._root, background=gui._root["background"])
controls_frame = Frame(top) controls_frame = ttk.Frame(top)
top.title("Config") top.title("Config")
def file_name(): def file_name():
@ -48,19 +47,19 @@ def start_fullfisher_config(gui: 'GUI'):
def mode_command(): def mode_command():
config.set("full_auto_mode", mode_var.get()) config.set("full_auto_mode", mode_var.get())
file_name_label = StringVar(value=file_name()) file_name_label = tk.StringVar(value=file_name())
mode_var = IntVar(value=config.get("full_auto_mode", 0)) mode_var = tk.IntVar(value=config.get("full_auto_mode", 0))
Button(controls_frame, text="Calibrate", command=start_calibrate).grid(row=0, column=0, columnspan=2, pady=(5, 5)) tk.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)) tk.Label(controls_frame, text="Mode: ").grid(row=1, column=0, pady=(5, 0))
Radiobutton(controls_frame, text="Player", variable=mode_var, value=FullAutoMode.Player.value, command=mode_command).grid(row=1, column=1, sticky="w") tk.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=mode_var, value=FullAutoMode.Recorder.value, command=mode_command).grid(row=2, column=1, sticky="w", pady=(0, 5)) tk.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)) tk.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)) tk.Label(controls_frame, textvariable=file_name_label).grid(row=4, column=0, columnspan=2, pady=(0, 5))
Label(controls_frame, text="Use semi-fisher config for rest").grid(row=5, column=0, columnspan=2, pady=(15, 5)) tk.Label(controls_frame, text="Use semi-fisher config for rest").grid(row=5, column=0, columnspan=2, pady=(15, 5))
controls_frame.pack(padx=(5, 5), pady=(5, 5)) controls_frame.pack(padx=(5, 5), pady=(5, 5))
top.start() top.start()
@ -84,46 +83,46 @@ def start_semifisher_config(gui: 'GUI'):
gui._notify.set(1) gui._notify.set(1)
def del_entry_key(event): def del_entry_key(event):
event.widget.delete(0,"end") event.widget.delete(0, "end")
event.widget.insert(0, str(event.char)) event.widget.insert(0, str(event.char))
top = PopUp(save, gui._root, background=gui._root["background"]) top = PopUp(save, gui._root, background=gui._root["background"])
controls_frame = Frame(top) controls_frame = ttk.Frame(top)
top.title("Config") top.title("Config")
Label(controls_frame, text="Notification:").grid(row=0, column=0) ttk.Label(controls_frame, text="Notification:").grid(row=0, column=0)
gui._notify = IntVar(0) gui._notify = tk.IntVar(0)
gui._notify_check = Checkbutton(controls_frame, command=toggle_sub, variable=gui._notify) gui._notify_check = ttk.Checkbutton(controls_frame, command=toggle_sub, variable=gui._notify)
gui._notify_check.grid(row=0, column=1) gui._notify_check.grid(row=0, column=1)
gui._notify_check['state'] = DISABLED gui._notify_check['state'] = tk.DISABLED
is_subbed = web.is_subbed() is_subbed = web.is_subbed()
if is_subbed[1]: if is_subbed[1]:
gui._notify_check['state'] = NORMAL gui._notify_check['state'] = tk.NORMAL
gui._notify.set(is_subbed[0]) gui._notify.set(is_subbed[0])
Label(controls_frame, text="Fullscreen: ").grid(row=1, column=0, pady=(5, 5)) ttk.Label(controls_frame, text="Fullscreen: ").grid(row=1, column=0, pady=(5, 5))
borderless = Checkbutton(controls_frame, var=BooleanVar(value=config.get("borderless"))) borderless = ttk.Checkbutton(controls_frame, var=tk.BooleanVar(value=config.get("borderless")))
borderless.grid(row=1, column=1) borderless.grid(row=1, column=1)
Label(controls_frame, text="Action Key:").grid(row=2, column=0) ttk.Label(controls_frame, text="Action Key:").grid(row=2, column=0)
action_key_entry = Entry(controls_frame, justify=CENTER) action_key_entry = ttk.Entry(controls_frame, justify=tk.CENTER)
action_key_entry.grid(row=2, column=1) action_key_entry.grid(row=2, column=1)
action_key_entry.insert(0, config.get("action_key", "e")) action_key_entry.insert(0, config.get("action_key", "e"))
action_key_entry.bind("<KeyRelease>", del_entry_key) action_key_entry.bind("<KeyRelease>", del_entry_key)
Label(controls_frame, text="Looting Key:").grid(row=4, column=0, pady=(5, 5)) ttk.Label(controls_frame, text="Looting Key:").grid(row=4, column=0, pady=(5, 5))
collect_key_entry = Entry(controls_frame, justify=CENTER) collect_key_entry = ttk.Entry(controls_frame, justify=tk.CENTER)
collect_key_entry.grid(row=4, column=1, pady=(5, 5)) collect_key_entry.grid(row=4, column=1, pady=(5, 5))
collect_key_entry.insert(0, config.get("collect_key", "r")) collect_key_entry.insert(0, config.get("collect_key", "r"))
collect_key_entry.bind("<KeyRelease>", del_entry_key) collect_key_entry.bind("<KeyRelease>", del_entry_key)
Label(controls_frame, text="Sound Notification: ").grid(row=5, column=0, pady=(5, 5)) ttk.Label(controls_frame, text="Sound Notification: ").grid(row=5, column=0, pady=(5, 5))
sound = Checkbutton(controls_frame, var=BooleanVar(value=config.get("sound_notification"))) sound = ttk.Checkbutton(controls_frame, var=tk.BooleanVar(value=config.get("sound_notification")))
sound.grid(row=5, column=1) sound.grid(row=5, column=1)
Label(controls_frame, text="Human-Like Delay: ").grid(row=6, column=0, pady=(5, 5)) ttk.Label(controls_frame, text="Human-Like Delay: ").grid(row=6, column=0, pady=(5, 5))
jitter = Checkbutton(controls_frame, var=BooleanVar(value=config.get("jitter"))) jitter = ttk.Checkbutton(controls_frame, var=tk.BooleanVar(value=config.get("jitter")))
jitter.grid(row=6, column=1) jitter.grid(row=6, column=1)
controls_frame.pack(padx=(5, 5), pady=(5, 5)) controls_frame.pack(padx=(5, 5), pady=(5, 5))

View File

@ -1,15 +1,11 @@
import time import time
from tkinter import * import tkinter as tk
from tkinter import messagebox import tkinter.ttk as ttk
from tkinter.ttk import *
import typing import typing
from fishy.helper import helper from fishy.libs.tkhtmlview import HTMLLabel
from fishy.web import web from fishy.web import web
from fishy.libs.tkhtmlview import HTMLLabel
from ..helper.config import config from ..helper.config import config
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
@ -34,14 +30,14 @@ def discord_login(gui: 'GUI'):
code = int(login_code.get()) if login_code.get().isdigit() else 0 code = int(login_code.get()) if login_code.get().isdigit() else 0
if web.login(config.get("uid"), code): if web.login(config.get("uid"), code):
gui.login.set(1) gui.login.set(1)
messagebox.showinfo("Note!", "Logged in successfuly!") tk.messagebox.showinfo("Note!", "Login successful!")
quit_top() quit_top()
else: else:
messagebox.showerror("Error", "Logged wasn't successful") tk.messagebox.showerror("Error", "Login was not successful!")
top_running = [True] top_running = [True]
top = Toplevel(background=gui._root["background"]) top = tk.Toplevel(background=gui._root["background"])
top.minsize(width=300, height=300) top.minsize(width=300, height=300)
top.title("Notification Setup") top.title("Notification Setup")
@ -58,8 +54,8 @@ def discord_login(gui: 'GUI'):
html_label.pack(pady=(20, 5)) html_label.pack(pady=(20, 5))
html_label.fit_height() html_label.fit_height()
login_code = Entry(top, justify=CENTER, font="Calibri 15") login_code = ttk.Entry(top, justify=tk.CENTER, font="Calibri 15")
login_code.pack(padx=(15, 15), expand=True, fill=BOTH) login_code.pack(padx=(15, 15), expand=True, fill=tk.BOTH)
html_label = HTMLLabel(top, html_label = HTMLLabel(top,
html=f'<div style="color: {gui._console["fg"]}; text-align: center">' html=f'<div style="color: {gui._console["fg"]}; text-align: center">'
@ -69,7 +65,7 @@ def discord_login(gui: 'GUI'):
html_label.pack(pady=(5, 5)) html_label.pack(pady=(5, 5))
html_label.fit_height() html_label.fit_height()
Button(top, text="REGISTER", command=check).pack(pady=(5, 20)) ttk.Button(top, text="REGISTER", command=check).pack(pady=(5, 20))
top.protocol("WM_DELETE_WINDOW", quit_top) top.protocol("WM_DELETE_WINDOW", quit_top)
top.grab_set() top.grab_set()

View File

@ -1,6 +1,5 @@
from tkinter import messagebox
import typing import typing
from tkinter import messagebox
from fishy.helper.config import config from fishy.helper.config import config
@ -16,7 +15,7 @@ class GUIFuncsMock:
... ...
def bot_started(self, started): def bot_started(self, started):
... ...
def quit(self): def quit(self):
... ...

View File

@ -1,20 +1,21 @@
import logging import logging
import uuid
from tkinter import OptionMenu, Button, IntVar
from typing import List, Callable, Optional, Dict, Any
import queue import queue
import threading import threading
import tkinter as tk
import uuid
from typing import Any, Callable, Dict, Optional
from fishy.web import web
from ttkthemes import ThemedTk from ttkthemes import ThemedTk
from fishy.engine.common.event_handler import EngineEventHandler, IEngineHandler from fishy.engine.common.event_handler import EngineEventHandler, IEngineHandler
from fishy.gui import config_top from fishy.gui import config_top
from fishy.gui.funcs import GUIFuncs from fishy.gui.funcs import GUIFuncs
from . import main_gui from fishy.web import web
from .log_config import GUIStreamHandler
from ..helper.config import config from ..helper.config import config
from ..helper.helper import wait_until from ..helper.helper import wait_until
from . import main_gui
from .log_config import GUIStreamHandler
class GUI: class GUI:
@ -35,8 +36,8 @@ class GUI:
self._console = None self._console = None
self._start_button = None self._start_button = None
self._notify_check = None self._notify_check = None
self._engine_select: Optional[OptionMenu] = None self._engine_select: Optional[tk.OptionMenu] = None
self._config_button: Optional[Button] = None self._config_button: Optional[tk.Button] = None
self._engine_var = None self._engine_var = None
self._thread = threading.Thread(target=self.create, args=()) self._thread = threading.Thread(target=self.create, args=())

View File

@ -1,6 +1,5 @@
from logging import StreamHandler
import typing import typing
from logging import StreamHandler
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from . import GUI from . import GUI

View File

@ -1,20 +1,19 @@
import logging import logging
import time import time
from tkinter import * import tkinter as tk
from tkinter.ttk import * import tkinter.ttk as ttk
import typing
from fishy.web import web
from ttkthemes import ThemedTk from ttkthemes import ThemedTk
from fishy import helper from fishy import helper
import typing
from fishy.helper import hotkey from fishy.helper import hotkey
from .discord_login import discord_login from fishy.web import web
from ..constants import chalutier, lam2
from ..helper.config import config from ..helper.config import config
from ..helper.hotkey import Key from ..helper.hotkey import Key
from ..constants import chalutier, lam2 from .discord_login import discord_login
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from . import GUI from . import GUI
@ -36,14 +35,14 @@ def _create(gui: 'GUI'):
gui._root.iconbitmap(helper.manifest_file('icon.ico')) gui._root.iconbitmap(helper.manifest_file('icon.ico'))
# region menu # region menu
menubar = Menu(gui._root) menubar = tk.Menu(gui._root)
filemenu = Menu(menubar, tearoff=0) filemenu = tk.Menu(menubar, tearoff=0)
login = web.is_logged_in() login = web.is_logged_in()
gui.login = IntVar() gui.login = tk.IntVar()
gui.login.set(1 if login > 0 else 0) gui.login.set(1 if login > 0 else 0)
state = DISABLED if login == -1 else ACTIVE state = tk.DISABLED if login == -1 else tk.ACTIVE
filemenu.add_checkbutton(label="Login", command=lambda: discord_login(gui), variable=gui.login, state=state) filemenu.add_checkbutton(label="Login", command=lambda: discord_login(gui), variable=gui.login, state=state)
filemenu.add_command(label="Create Shortcut", command=lambda: helper.create_shortcut(False)) filemenu.add_command(label="Create Shortcut", command=lambda: helper.create_shortcut(False))
# filemenu.add_command(label="Create Anti-Ghost Shortcut", command=lambda: helper.create_shortcut(True)) # filemenu.add_command(label="Create Anti-Ghost Shortcut", command=lambda: helper.create_shortcut(True))
@ -52,7 +51,7 @@ def _create(gui: 'GUI'):
config.set("dark_mode", not config.get("dark_mode", True)) config.set("dark_mode", not config.get("dark_mode", True))
gui._start_restart = True gui._start_restart = True
dark_mode_var = IntVar() dark_mode_var = tk.IntVar()
dark_mode_var.set(int(config.get('dark_mode', True))) dark_mode_var.set(int(config.get('dark_mode', True)))
filemenu.add_checkbutton(label="Dark Mode", command=_toggle_mode, filemenu.add_checkbutton(label="Dark Mode", command=_toggle_mode,
variable=dark_mode_var) variable=dark_mode_var)
@ -72,11 +71,11 @@ def _create(gui: 'GUI'):
filemenu.add_command(label=chaEntry, command=installer) filemenu.add_command(label=chaEntry, command=installer)
menubar.add_cascade(label="Options", menu=filemenu) menubar.add_cascade(label="Options", menu=filemenu)
debug_menu = Menu(menubar, tearoff=0) debug_menu = tk.Menu(menubar, tearoff=0)
debug_menu.add_command(label="Check PixelVal", debug_menu.add_command(label="Check PixelVal",
command=lambda: gui.engine.check_pixel_val()) command=lambda: gui.engine.check_pixel_val())
debug_var = IntVar() debug_var = tk.IntVar()
debug_var.set(int(config.get('debug', False))) debug_var.set(int(config.get('debug', False)))
def keep_console(): def keep_console():
@ -87,7 +86,7 @@ def _create(gui: 'GUI'):
debug_menu.add_command(label="Restart", command=helper.restart) debug_menu.add_command(label="Restart", command=helper.restart)
menubar.add_cascade(label="Debug", menu=debug_menu) menubar.add_cascade(label="Debug", menu=debug_menu)
help_menu = Menu(menubar, tearoff=0) help_menu = tk.Menu(menubar, tearoff=0)
help_menu.add_command(label="Need Help?", command=lambda: helper.open_web("http://discord.definex.in")) help_menu.add_command(label="Need Help?", command=lambda: helper.open_web("http://discord.definex.in"))
help_menu.add_command(label="Donate", command=lambda: helper.open_web("https://paypal.me/AdamSaudagar")) help_menu.add_command(label="Donate", command=lambda: helper.open_web("https://paypal.me/AdamSaudagar"))
menubar.add_cascade(label="Help", menu=help_menu) menubar.add_cascade(label="Help", menu=help_menu)
@ -96,29 +95,29 @@ def _create(gui: 'GUI'):
# endregion # endregion
# region console # region console
gui._console = Text(gui._root, state='disabled', wrap='none', background="#707070", fg="#ffffff") gui._console = tk.Text(gui._root, state='disabled', wrap='none', background="#707070", fg="#ffffff")
gui._console.pack(fill=BOTH, expand=True, pady=(15, 15), padx=(10, 10)) gui._console.pack(fill=tk.BOTH, expand=True, pady=(15, 15), padx=(10, 10))
gui._console.mark_set("sentinel", INSERT) gui._console.mark_set("sentinel", tk.INSERT)
gui._console.config(state=DISABLED) gui._console.config(state=tk.DISABLED)
# endregion # endregion
# region controls # region controls
start_frame = Frame(gui._root) start_frame = ttk.Frame(gui._root)
gui._engine_var = StringVar(start_frame) gui._engine_var = tk.StringVar(start_frame)
labels = list(engines.keys()) labels = list(engines.keys())
last_started = config.get("last_started", labels[0]) last_started = config.get("last_started", labels[0])
gui._engine_select = OptionMenu(start_frame, gui._engine_var, last_started, *labels) gui._engine_select = ttk.OptionMenu(start_frame, gui._engine_var, last_started, *labels)
gui._engine_select.pack(side=LEFT) gui._engine_select.pack(side=tk.LEFT)
gui._config_button = Button(start_frame, text="", width=0, command=lambda: engines[gui._engine_var.get()][0]()) gui._config_button = ttk.Button(start_frame, text="", width=0, command=lambda: engines[gui._engine_var.get()][0]())
gui._config_button.pack(side=RIGHT) gui._config_button.pack(side=tk.RIGHT)
gui._start_button = Button(start_frame, text=gui._get_start_stop_text(), width=25, gui._start_button = ttk.Button(start_frame, text=gui._get_start_stop_text(), width=25,
command=gui.funcs.start_engine) command=gui.funcs.start_engine)
gui._start_button.pack(side=RIGHT) gui._start_button.pack(side=tk.RIGHT)
start_frame.pack(padx=(10, 10), pady=(5, 15), fill=X) start_frame.pack(padx=(10, 10), pady=(5, 15), fill=tk.X)
# endregion # endregion
_apply_theme(gui) _apply_theme(gui)
@ -132,7 +131,7 @@ def _create(gui: 'GUI'):
# noinspection PyProtectedMember # noinspection PyProtectedMember
def set_destroy(): def set_destroy():
if gui._bot_running: if gui._bot_running:
if not messagebox.askyesno(title="Quit?", message="Bot engine running. Quit Anyway?"): if not tk.messagebox.askyesno(title="Quit?", message="Bot engine running. Quit Anyway?"):
return return
config.set("win_loc", gui._root.geometry()) config.set("win_loc", gui._root.geometry())

View File

@ -1,15 +1,16 @@
import time import time
import tkinter as tk
from multiprocessing import Process from multiprocessing import Process
from tkinter import *
from PIL import Image, ImageTk from PIL import Image, ImageTk
from fishy.helper.config import config
from fishy.helper import helper from fishy.helper import helper
from fishy.helper.config import config
def show(win_loc): def show(win_loc):
dim=(300,200) dim = (300, 200)
top = Tk() top = tk.Tk()
top.overrideredirect(True) top.overrideredirect(True)
top.lift() top.lift()
@ -18,17 +19,17 @@ def show(win_loc):
top.resizable(False, False) top.resizable(False, False)
top.iconbitmap(helper.manifest_file('icon.ico')) top.iconbitmap(helper.manifest_file('icon.ico'))
canvas = Canvas(top, width=dim[0], height=dim[1], bg='white') canvas = tk.Canvas(top, width=dim[0], height=dim[1], bg='white')
canvas.pack() canvas.pack()
top.image = Image.open(helper.manifest_file('fishybot_logo.png')).resize(dim) top.image = Image.open(helper.manifest_file('fishybot_logo.png')).resize(dim)
top.image = ImageTk.PhotoImage(top.image) top.image = ImageTk.PhotoImage(top.image)
canvas.create_image(0, 0, anchor=NW, image=top.image) canvas.create_image(0, 0, anchor=tk.NW, image=top.image)
# Position splash at the center of the main window # Position splash at the center of the main window
default_loc = (str(top.winfo_reqwidth())+"+"+str(top.winfo_reqheight())+"+"+"0"+"0") default_loc = (str(top.winfo_reqwidth()) + "+" + str(top.winfo_reqheight()) + "+" + "0" + "0")
loc = (win_loc or default_loc).split("+")[1:] loc = (win_loc or default_loc).split("+")[1:]
top.geometry("{}x{}+{}+{}".format(dim[0], dim[1], int(loc[0])+int(dim[0]/2), int(loc[1])+int(dim[1]/2))) top.geometry("{}x{}+{}+{}".format(dim[0], dim[1], int(loc[0]) + int(dim[0] / 2), int(loc[1]) + int(dim[1] / 2)))
top.update() top.update()
time.sleep(3) time.sleep(3)

View File

@ -1,7 +1,7 @@
import webbrowser
from tkinter import *
from tkinter.ttk import *
import re import re
import tkinter as tk
import tkinter.ttk as ttk
import webbrowser
from PIL import Image, ImageTk from PIL import Image, ImageTk
@ -25,42 +25,42 @@ def _run_terms_window():
root.destroy() root.destroy()
def disable_enable_button(): def disable_enable_button():
accept_button.config(state=NORMAL if check_value.get() else DISABLED) accept_button.config(state=tk.NORMAL if check_value.get() else tk.DISABLED)
root = Tk() root = tk.Tk()
message = f'I agree to the [Terms of Service and Privacy Policy]({web.get_terms_page()})' message = f'I agree to the [Terms of Service and Privacy Policy]({web.get_terms_page()})'
root.title("EULA") root.title("EULA")
root.resizable(False, False) root.resizable(False, False)
root.iconbitmap(helper.manifest_file('icon.ico')) root.iconbitmap(helper.manifest_file('icon.ico'))
f = Frame(root) f = ttk.Frame(root)
canvas = Canvas(f, width=300, height=200) canvas = tk.Canvas(f, width=300, height=200)
canvas.pack() canvas.pack()
root.image = Image.open(helper.manifest_file('fishybot_logo.png')).resize((300, 200)) root.image = Image.open(helper.manifest_file('fishybot_logo.png')).resize((300, 200))
root.image = ImageTk.PhotoImage(root.image) root.image = ImageTk.PhotoImage(root.image)
canvas.create_image(0, 0, anchor=NW, image=root.image) canvas.create_image(0, 0, anchor=tk.NW, image=root.image)
check_value = IntVar(0) check_value = tk.IntVar(0)
g1 = Frame(f) g1 = ttk.Frame(f)
Checkbutton(g1, command=disable_enable_button, variable=check_value).pack(side=LEFT) ttk.Checkbutton(g1, command=disable_enable_button, variable=check_value).pack(side=tk.LEFT)
text = Text(g1, width=len(hyperlinkPattern.sub(r'\g<title>', message)), text = tk.Text(g1, width=len(hyperlinkPattern.sub(r'\g<title>', message)),
height=1, borderwidth=0, highlightthickness=0) height=1, borderwidth=0, highlightthickness=0)
text["background"] = root["background"] text["background"] = root["background"]
_format_hyper_link(text, message) _format_hyper_link(text, message)
text.config(state=DISABLED) text.config(state=tk.DISABLED)
text.pack(side=LEFT) text.pack(side=tk.LEFT)
g1.pack() g1.pack()
f.pack(padx=(10, 10), pady=(20, 20)) f.pack(padx=(10, 10), pady=(20, 20))
g2 = Frame(f) g2 = ttk.Frame(f)
accept_button = Button(g2, text="Accept", accept_button = ttk.Button(g2, text="Accept",
command=accept) command=accept)
accept_button.grid(row=0, column=0) accept_button.grid(row=0, column=0)
Button(g2, text="Deny", ttk.Button(g2, text="Deny",
command=lambda: root.destroy()).grid(row=0, column=1) command=lambda: root.destroy()).grid(row=0, column=1)
g2.pack(pady=(5, 0)) g2.pack(pady=(5, 0))
disable_enable_button() disable_enable_button()

View File

@ -1,35 +1,38 @@
from multiprocessing import Process, Manager import tkinter as tk
from tkinter import * from multiprocessing import Manager, Process
import time
from fishy import helper from fishy import helper
def show(currentversion, newversion, returns): def show(currentversion, newversion, returns):
top = Tk() top = tk.Tk()
top.title("A wild fishy update appeared!") top.title("A wild fishy update appeared!")
top.iconbitmap(helper.manifest_file('icon.ico')) top.iconbitmap(helper.manifest_file('icon.ico'))
dialogLabel = Label(top, text="There is a new fishy update available ("+currentversion+"->"+newversion+"). Do you want to update now?") dialogLabel = tk.Label(top, text="There is a new fishy update available (" +
currentversion + "->" + newversion + "). Do you want to update now?")
dialogLabel.grid(row=0, columnspan=2, padx=5, pady=5) dialogLabel.grid(row=0, columnspan=2, padx=5, pady=5)
cbVar = IntVar() cbVar = tk.IntVar()
dialogCheckbutton = Checkbutton(top, text="don't ask again", variable=cbVar) dialogCheckbutton = tk.Checkbutton(top, text="don't ask again", variable=cbVar)
dialogCheckbutton.grid(row=1, columnspan=2, padx=5, pady=0) dialogCheckbutton.grid(row=1, columnspan=2, padx=5, pady=0)
top.update() top.update()
buttonWidth = int(dialogLabel.winfo_width()/2)-20 buttonWidth = int(dialogLabel.winfo_width() / 2) - 20
def _clickYes(): def _clickYes():
returns[0],returns[1]=True, False returns[0], returns[1] = True, False
top.destroy() top.destroy()
def _clickNo(): def _clickNo():
returns[0],returns[1]=False, bool(cbVar.get()) returns[0], returns[1] = False, bool(cbVar.get())
top.destroy() top.destroy()
pixelVirtual = PhotoImage(width=1, height=1) # trick to use buttonWidth as pixels, not #symbols pixelVirtual = tk.PhotoImage(width=1, height=1) # trick to use buttonWidth as pixels, not #symbols
dialogBtnNo = Button(top, text="No " + str(chr(10005)), fg='red4', command=_clickNo, image=pixelVirtual, width=buttonWidth, compound="c") dialogBtnNo = tk.Button(top, text="No " + str(chr(10005)), fg='red4', command=_clickNo, image=pixelVirtual,
width=buttonWidth, compound="c")
dialogBtnNo.grid(row=2, column=0, padx=5, pady=5) dialogBtnNo.grid(row=2, column=0, padx=5, pady=5)
dialogBtnYes = Button(top, text="Yes " + str(chr(10003)), fg='green', command=_clickYes, image=pixelVirtual, width=buttonWidth, compound="c") dialogBtnYes = tk.Button(top, text="Yes " + str(chr(10003)), fg='green', command=_clickYes, image=pixelVirtual,
width=buttonWidth, compound="c")
dialogBtnYes.grid(row=2, column=1, padx=5, pady=5) dialogBtnYes.grid(row=2, column=1, padx=5, pady=5)
dialogBtnYes.focus_set() dialogBtnYes.focus_set()

View File

@ -1,4 +1,9 @@
from .auto_update import auto_upgrade, upgrade_avail, versions from .auto_update import auto_upgrade, upgrade_avail, versions
from .config import Config from .config import Config
from .helper import open_web, initialize_uid, install_thread_excepthook, unhandled_exception_logging, manifest_file, \ from .helper import (addon_exists, create_shortcut, create_shortcut_first,
create_shortcut_first, addon_exists, get_addonversion, install_addon, remove_addon, restart, create_shortcut, not_implemented, update get_addonversion, get_savedvarsdir, initialize_uid,
install_addon, install_thread_excepthook, manifest_file,
not_implemented, open_web, playsound_multiple,
remove_addon, restart, unhandled_exception_logging,
update)
from .luaparser import sv_color_extract

View File

@ -11,9 +11,9 @@ from os import execl
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
def _hr_version(v): def _hr_version(v):
return '.'.join([str(x) for x in v]) return '.'.join([str(x) for x in v])
#return str(v[0])+"."+str(v[1])+"."+str(v[2])
def _normalize_version(v): def _normalize_version(v):
@ -75,6 +75,7 @@ def _get_current_version():
index = "https://pypi.python.org/simple" index = "https://pypi.python.org/simple"
pkg = "fishy" pkg = "fishy"
def versions(): def versions():
return _hr_version(_get_current_version()), _hr_version(_get_highest_version(index, pkg)) return _hr_version(_get_current_version()), _hr_version(_get_highest_version(index, pkg))

View File

@ -3,11 +3,10 @@ config.py
Saves configuration in file as json file Saves configuration in file as json file
""" """
import json import json
import logging
import os import os
# path to save the configuration file # path to save the configuration file
from typing import Optional from typing import Optional
from event_scheduler import EventScheduler from event_scheduler import EventScheduler

View File

@ -7,24 +7,36 @@ import threading
import time import time
import traceback import traceback
import webbrowser import webbrowser
import requests from hashlib import md5
from io import BytesIO from io import BytesIO
from threading import Thread from threading import Thread
from uuid import uuid1
from zipfile import ZipFile from zipfile import ZipFile
from uuid import uuid1 import requests
from hashlib import md5 import winshell
from playsound import playsound
from win32com.client import Dispatch from win32com.client import Dispatch
from win32comext.shell import shell, shellcon from win32comext.shell import shell, shellcon
from win32gui import GetForegroundWindow, GetWindowText from win32gui import GetForegroundWindow, GetWindowText
import fishy import fishy
import winshell
from fishy import web from fishy import web
def playsound_multiple(path, count=2):
if count < 1:
logging.debug("Please don't make me beep 0 times or less.")
return
def _ps_m():
for i in range(count - 1):
playsound(path, True)
playsound(path, False)
Thread(target=_ps_m).start()
def not_implemented(): def not_implemented():
logging.error("Not Implemented") logging.error("Not Implemented")
@ -147,6 +159,13 @@ def create_shortcut(anti_ghosting: bool):
logging.error("Couldn't create shortcut") logging.error("Couldn't create shortcut")
def get_savedvarsdir():
# noinspection PyUnresolvedReferences
from win32com.shell import shell, shellcon
documents = shell.SHGetFolderPath(0, shellcon.CSIDL_PERSONAL, None, 0)
return os.path.join(documents, "Elder Scrolls Online", "live", "SavedVariables")
def get_addondir(): def get_addondir():
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from win32com.shell import shell, shellcon from win32com.shell import shell, shellcon
@ -177,21 +196,22 @@ def install_addon(name, url, v=None):
r = requests.get(url, stream=True) r = requests.get(url, stream=True)
z = ZipFile(BytesIO(r.content)) z = ZipFile(BytesIO(r.content))
z.extractall(path=get_addondir()) z.extractall(path=get_addondir())
logging.info("Add-On "+name+" installed successfully!\nPlease make sure to enable \"Allow outdated addons\" in ESO") logging.info("Add-On " + name +
" installed successfully!\nPlease make sure to enable \"Allow outdated addons\" in ESO")
return 0 return 0
except Exception as ex: except Exception:
logging.error("Could not install Add-On "+name+", try doing it manually") logging.error("Could not install Add-On " + name + ", try doing it manually")
return 1 return 1
def remove_addon(name, url=None, v=None): def remove_addon(name, url=None, v=None):
try: try:
shutil.rmtree(os.path.join(get_addondir(), name)) shutil.rmtree(os.path.join(get_addondir(), name))
logging.info("Add-On "+name+" removed!") logging.info("Add-On " + name + " removed!")
except FileNotFoundError: except FileNotFoundError:
pass pass
except PermissionError as ex: except PermissionError:
logging.error("Fishy has no permission to remove "+name+" Add-On") logging.error("Fishy has no permission to remove " + name + " Add-On")
return 1 return 1
return 0 return 0

View File

@ -1,11 +1,8 @@
from enum import Enum from enum import Enum
from threading import Thread from threading import Thread
from typing import Dict, Callable, Optional from typing import Callable, Dict, Optional
import keyboard import keyboard
from playsound import playsound
from fishy.helper import helper
class Key(Enum): class Key(Enum):
@ -27,7 +24,6 @@ def _get_callback(k):
if not _hotkeys[k]: if not _hotkeys[k]:
return return
playsound(helper.manifest_file("beep.wav"), False)
Thread(target=_hotkeys[k]).start() Thread(target=_hotkeys[k]).start()
return callback return callback

View File

@ -1,8 +1,8 @@
import time import time
from multiprocessing import Process, Queue
from threading import Thread from threading import Thread
import mouse import mouse
from multiprocessing import Process, Queue
def event_triggered(queue, e): def event_triggered(queue, e):

81
fishy/helper/luaparser.py Normal file
View File

@ -0,0 +1,81 @@
import logging
import os
from math import floor
from .helper import get_savedvarsdir
def _sv_parser(path):
try:
with open(path, "r") as f:
lua = f.read()
"""
bring lua saved-var file into a useable format:
- one line per expression (add \n where needed)
- remove all redundant characters
- make lowercase, split into list of expressions
- remove empty expressions
EXPRESSIONS: A) List-Start "name=", B) Variable assignment "name=val", C) List End "}"
"""
subs = ((",", "\n"), ("{", "{\n"), ("}", "}\n"),
("{", ""), (",", ""), ("[", ""), ("]", ""), ('"', ""), (" ", ""))
for old, new in subs:
lua = lua.replace(old, new)
lua = lua.lower().split("\n")
lua = [expression for expression in lua if expression]
"""
the lua saved-var file is parsed to a tree of dicts
each line represents either one node in the tree or the end of a subtree
the last symbol of each line decides the type of the node (branch vertex or leaf)
"""
stack = []
root = (dict(), "root")
stack.append(root)
for line in lua:
if line == "":
break
if line[-1] == '=': # subtree start
t = dict()
tname = line.split("=")[0]
stack.append((t, tname))
elif line[-1] == '}': # subtree end
t = stack.pop()
tp = stack.pop()
tp[0][t[1]] = t[0]
stack.append(tp)
else: # new element in tree
name, val = line.split("=")
t = stack.pop()
t[0][name] = val
stack.append(t)
return root[0]
except Exception as ex:
logging.error("Error: '" + str(ex) + "' occured, while parsing ESO variables.")
return None
def sv_color_extract(Colors):
root = _sv_parser(os.path.join(get_savedvarsdir(), "Chalutier.lua"))
if root is None:
return Colors
for i in range(4):
name, root = root.popitem()
colors = []
for i in root["colors"]:
"""
ingame representation of colors range from 0 to 1 in float
these values are scaled by 255
"""
rgb = [
floor(float(root["colors"][i]["r"]) * 255),
floor(float(root["colors"][i]["g"]) * 255),
floor(float(root["colors"][i]["b"]) * 255)
]
colors.append(rgb)
for i, c in enumerate(Colors):
Colors[c] = colors[i]
return Colors

View File

@ -1,2 +1,3 @@
from .urls import get_notification_page, get_terms_page from .urls import get_notification_page, get_terms_page
from .web import register_user, send_notification, send_hole_deplete, is_subbed, unsub, get_session, sub from .web import (get_session, is_subbed, register_user, send_fish_caught,
send_notification, sub, unsub)

View File

@ -3,10 +3,11 @@ from whatsmyip.ip import get_ip
from whatsmyip.providers import GoogleDnsProvider from whatsmyip.providers import GoogleDnsProvider
from fishy import helper from fishy import helper
from ..constants import apiversion
from ..helper.config import config
from . import urls from . import urls
from .decorators import fallback, uses_session from .decorators import fallback, uses_session
from ..helper.config import config
from ..constants import apiversion
_session_id = None _session_id = None
@ -16,7 +17,7 @@ def is_logged_in():
if config.get("uid") is None: if config.get("uid") is None:
return -1 return -1
body = {"uid": config.get("uid"), "apiversion":apiversion} body = {"uid": config.get("uid"), "apiversion": apiversion}
response = requests.get(urls.discord, params=body) response = requests.get(urls.discord, params=body)
logged_in = response.json()["discord_login"] logged_in = response.json()["discord_login"]
return 1 if logged_in else 0 return 1 if logged_in else 0
@ -24,7 +25,7 @@ def is_logged_in():
@fallback(False) @fallback(False)
def login(uid, login_code): def login(uid, login_code):
body = {"uid": uid, "login_code": login_code, "apiversion":apiversion} body = {"uid": uid, "login_code": login_code, "apiversion": apiversion}
reponse = requests.post(urls.discord, json=body) reponse = requests.post(urls.discord, json=body)
result = reponse.json() result = reponse.json()
@ -36,7 +37,7 @@ def login(uid, login_code):
@fallback(False) @fallback(False)
def logout(): def logout():
body = {"uid": config.get("uid"), "apiversion":apiversion} body = {"uid": config.get("uid"), "apiversion": apiversion}
reponse = requests.delete(urls.discord, json=body) reponse = requests.delete(urls.discord, json=body)
result = reponse.json() result = reponse.json()
return result["success"] return result["success"]
@ -56,13 +57,13 @@ def send_notification(message):
if not is_subbed()[0]: if not is_subbed()[0]:
return False return False
body = {"uid": config.get("uid"), "message": message, "apiversion":apiversion} body = {"uid": config.get("uid"), "message": message, "apiversion": apiversion}
requests.post(urls.notify, json=body) requests.post(urls.notify, json=body)
@uses_session @uses_session
@fallback(None) @fallback(None)
def send_hole_deplete(fish_caught, hole_time, fish_times): def send_fish_caught(fish_caught, hole_time, fish_times):
hole_data = { hole_data = {
"fish_caught": fish_caught, "fish_caught": fish_caught,
"hole_time": hole_time, "hole_time": hole_time,
@ -70,13 +71,13 @@ def send_hole_deplete(fish_caught, hole_time, fish_times):
"session": get_session() "session": get_session()
} }
body = {"uid": config.get("uid"), "hole_data": hole_data, "apiversion":apiversion} body = {"uid": config.get("uid"), "hole_data": hole_data, "apiversion": apiversion}
requests.post(urls.hole_depleted, json=body) requests.post(urls.hole_depleted, json=body)
@fallback(False) @fallback(False)
def sub(): def sub():
body = {"uid": config.get("uid"), "apiversion":apiversion} body = {"uid": config.get("uid"), "apiversion": apiversion}
response = requests.post(urls.subscription, json=body) response = requests.post(urls.subscription, json=body)
result = response.json() result = response.json()
return result["success"] return result["success"]
@ -93,7 +94,7 @@ def is_subbed():
if config.get("uid") is None: if config.get("uid") is None:
return False, False return False, False
body = {"uid": config.get("uid"), "apiversion":apiversion} body = {"uid": config.get("uid"), "apiversion": apiversion}
response = requests.get(urls.subscription, params=body) response = requests.get(urls.subscription, params=body)
if response.status_code != 200: if response.status_code != 200:
@ -105,7 +106,7 @@ def is_subbed():
@fallback(None) @fallback(None)
def unsub(): def unsub():
body = {"uid": config.get("uid"), "apiversion":apiversion} body = {"uid": config.get("uid"), "apiversion": apiversion}
response = requests.delete(urls.subscription, json=body) response = requests.delete(urls.subscription, json=body)
result = response.json() result = response.json()
return result["success"] return result["success"]
@ -118,7 +119,7 @@ def get_session(lazy=True):
if lazy and _session_id is not None: if lazy and _session_id is not None:
return _session_id return _session_id
body = {"uid": config.get("uid"), "apiversion":apiversion} body = {"uid": config.get("uid"), "apiversion": apiversion}
response = requests.post(urls.session, params=body) response = requests.post(urls.session, params=body)
if response.status_code == 405: if response.status_code == 405:
@ -132,7 +133,7 @@ def get_session(lazy=True):
@fallback(False) @fallback(False)
def has_beta(): def has_beta():
body = {"uid": config.get("uid"), "apiversion":apiversion} body = {"uid": config.get("uid"), "apiversion": apiversion}
response = requests.get(urls.beta, params=body) response = requests.get(urls.beta, params=body)
result = response.json() result = response.json()

View File

@ -4,14 +4,16 @@ https://packaging.python.org/guides/distributing-packages-using-setuptools/
https://github.com/pypa/sampleproject https://github.com/pypa/sampleproject
""" """
# Always prefer setuptools over distutils
from setuptools import setup, find_packages
from os import path
# io.open is needed for projects that support Python 2.7 # io.open is needed for projects that support Python 2.7
# It ensures open() defaults to text mode with universal newlines, # It ensures open() defaults to text mode with universal newlines,
# and accepts an argument to specify the text encoding # and accepts an argument to specify the text encoding
# Python 3 only projects can skip this import # Python 3 only projects can skip this import
from io import open from io import open
from os import path
# Always prefer setuptools over distutils
from setuptools import find_packages, setup
from fishy import __version__ from fishy import __version__
here = path.abspath(path.dirname(__file__)) here = path.abspath(path.dirname(__file__))