Merge pull request #97 from fishyboteso/improvement/fishyqr-integration

This commit is contained in:
Adam Saudagar 2021-11-21 16:33:14 +05:30 committed by GitHub
commit bde31fce85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 127 additions and 143 deletions

View File

@ -1,2 +1,4 @@
from fishy import constants
from fishy.__main__ import main
__version__ = "0.5.2"
__version__ = constants.version

View File

@ -9,13 +9,14 @@ import win32gui
import fishy
from fishy import gui, helper, web
from fishy.constants import chalutier, lam2
from fishy.constants import chalutier, lam2, fishyqr, libgps
from fishy.engine.common.event_handler import EngineEventHandler
from fishy.gui import GUI, splash, update_dialog
from fishy.helper import hotkey
from fishy.helper.active_poll import active
from fishy.helper.config import config
from fishy.helper.hotkey.hotkey_process import hotkey
from fishy.helper.migration import Migration
def check_window_name(title):
@ -28,6 +29,8 @@ def check_window_name(title):
# noinspection PyBroadException
def initialize(window_to_hide):
Migration.migrate()
helper.create_shortcut_first()
helper.initialize_uid()
@ -62,10 +65,7 @@ def initialize(window_to_hide):
helper.install_thread_excepthook()
sys.excepthook = helper.unhandled_exception_logging
if not config.get("addoninstalled", 0) or helper.get_addonversion(chalutier[0]) < chalutier[2]:
helper.install_addon(*chalutier)
helper.install_addon(*lam2)
config.set("addoninstalled", helper.get_addonversion(chalutier[0]))
helper.install_required_addons()
def main():

View File

@ -1,6 +1,11 @@
apiversion = 2
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)
fishyqr = ("FishyQR", "https://github.com/fishyboteso/FishyQR/files/6329586/FishyQR.zip", 100)
# removed since 0.5.3
chalutier = ("Chalutier", "https://www.esoui.com/downloads/dl2934/Chalutier_1.1.4.zip", 114)
# addons used
lam2 = ("LibAddonMenu-2.0", "https://www.esoui.com/downloads/dl7/LibAddonMenu-2.0r32.zip", 32)
fishyqr = ("FishyQR", "https://github.com/fishyboteso/FishyQR/files/7575974/FishyQR.zip", 101)
libgps = ("LibGPS", "https://cdn.esoui.com/downloads/file601/LibGPS_3_0_3.zip", 30)
version = "0.5.3"

View File

@ -9,6 +9,15 @@ from pyzbar.pyzbar import decode, ZBarSymbol
from fishy.helper.helper import get_documents
def image_pre_process(img):
scale_percent = 100 # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
img = cv2.resize(img, dim, interpolation=cv2.INTER_AREA)
return img
def get_qr_location(og_img):
"""
code from https://stackoverflow.com/a/45770227/4512396
@ -41,7 +50,7 @@ def get_values_from_image(img):
try:
for qr in decode(img, symbols=[ZBarSymbol.QRCODE]):
vals = qr.data.decode('utf-8').split(",")
return float(vals[0]), float(vals[1]), float(vals[2])
return tuple(float(v) for v in vals)
logging.error("FishyQR not found")
return None

View File

@ -1,5 +1,6 @@
import logging
import math
import traceback
from enum import Enum
from threading import Thread
@ -75,10 +76,15 @@ def loop_end():
cv2.waitKey(25)
# noinspection PyBroadException
def run():
# todo use config
while WindowServer.status == Status.RUNNING:
loop()
try:
loop()
except Exception:
traceback.print_exc()
WindowServer.status = Status.CRASHED
loop_end()

View File

@ -1,4 +1,3 @@
import math
import logging
import math
import time
@ -16,8 +15,8 @@ from fishy.engine.fullautofisher.mode.calibrator import Calibrator
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_qr_location,
get_values_from_image)
from fishy.engine.common.qr_detection import (get_qr_location,
get_values_from_image, image_pre_process)
from fishy.engine.semifisher import fishing_event, fishing_mode
from fishy.engine.semifisher.fishing_mode import FishingMode
from fishy.helper import helper, hotkey
@ -29,15 +28,6 @@ mse = mouse.Controller()
kb = keyboard.Controller()
def image_pre_process(img):
scale_percent = 100 # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
img = cv2.resize(img, dim, interpolation=cv2.INTER_AREA)
return img
class FullAuto(IEngine):
rotate_by = 30
@ -56,12 +46,6 @@ class FullAuto(IEngine):
self.mode = None
def run(self):
addons_req = [libgps, lam2, fishyqr]
for addon in addons_req:
if not helper.addon_exists(*addon):
helper.install_addon(*addon)
self.gui.bot_started(True)
self.window = WindowClient(color=cv2.COLOR_RGB2GRAY, show_name="Full auto debug")

View File

@ -4,14 +4,16 @@ import typing
from threading import Thread
from typing import Callable, Optional
import cv2
from fishy.helper.helper import log_raise
from playsound import playsound
from fishy.engine.common.IEngine import IEngine
from fishy.engine.common.qr_detection import get_qr_location, get_values_from_image, image_pre_process
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.helper import helper
from fishy.helper.luaparser import sv_color_extract
@ -22,7 +24,7 @@ if typing.TYPE_CHECKING:
class SemiFisherEngine(IEngine):
def __init__(self, gui_ref: Optional['Callable[[], GUI]']):
super().__init__(gui_ref)
self.fishPixWindow = None
self.window = None
def run(self):
"""
@ -30,34 +32,43 @@ class SemiFisherEngine(IEngine):
code explained in comments in detail
"""
fishing_event.init()
self.fishPixWindow = WindowClient()
self.window = WindowClient(color=cv2.COLOR_RGB2GRAY, show_name="semifisher debug")
# check for game window and stuff
self.gui.bot_started(True)
sv_color_extract(Colors)
if self.get_gui:
logging.info("Starting the bot engine, look at the fishing hole to start fishing")
Thread(target=self._wait_and_check).start()
while self.start and WindowClient.running():
capture = self.fishPixWindow.get_capture()
self.window.crop = get_qr_location(self.window.get_capture())
if self.window.crop is None:
log_raise("FishyQR not found")
while self.start and WindowClient.running():
capture = self.window.processed_image(func=image_pre_process)
# if window server crashed
if capture is None:
# if window server crashed
self.gui.bot_started(False)
self.toggle_start()
continue
self.fishPixWindow.crop = PixelLoc.val
fishing_mode.loop(capture[0][0])
# crop qr and get the values from it
values = get_values_from_image(capture)
if values is None:
self.gui.bot_started(False)
self.toggle_start()
continue
fishing_mode.loop(values[3])
time.sleep(0.1)
self.window.show(False)
logging.info("Fishing engine stopped")
self.gui.bot_started(False)
fishing_event.unsubscribe()
self.fishPixWindow.destory()
self.window.destory()
def _wait_and_check(self):
time.sleep(10)
@ -71,7 +82,7 @@ class SemiFisherEngine(IEngine):
t = 0
while t < 10.0:
t += freq
logging.debug(str(FishingMode.CurrentMode) + ":" + str(self.fishPixWindow.get_capture()[0][0]))
logging.debug(str(FishingMode.CurrentMode) + ":" + str(self.window.get_capture()[0][0]))
time.sleep(freq)
logging.debug("Will display pixel values for 10 seconds")

View File

@ -107,7 +107,10 @@ def fisher_callback(event: State):
def on_idle():
if FishEvent.previousState in (State.FISHING, State.REELIN):
if FishEvent.previousState == State.REELIN:
logging.info("HOLE DEPLETED")
_sound_and_send_fishy_data()
elif FishEvent.previousState == State.FISHING:
logging.info("FISHING INTERRUPTED")
_sound_and_send_fishy_data()

View File

@ -17,21 +17,6 @@ class State(Enum):
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):
for subscriber in subscribers:
subscriber(event)
@ -42,17 +27,12 @@ class FishingMode:
PrevMode = State.IDLE
def loop(rgb):
def loop(state_num: int):
"""
Executed in the start of the main loop in fishy.py
Changes modes, calls mode events (callbacks) when mode is changed
:param rgb: rgb read by the bot
"""
FishingMode.CurrentMode = State.IDLE
for s in State:
if all(rgb == Colors[s]):
FishingMode.CurrentMode = s
FishingMode.CurrentMode = State(state_num)
if FishingMode.CurrentMode != FishingMode.PrevMode:
_notify(FishingMode.CurrentMode)

View File

@ -1,66 +0,0 @@
import cv2
def get_keypoint_from_image(img):
"""
convert image int hsv
creates a mask for brown color
uses blob detection to find a blob in the mask
filter the blobs to find the correct one
:param img: rgb image
:return: location of the pixel which is used to detect different fishing states
"""
# Setup SimpleBlobDetector parameters.
hsv_img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
lower = (99, 254, 100)
upper = (100, 255, 101)
mask = cv2.inRange(hsv_img, lower, upper)
# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()
# Change thresholds
params.minThreshold = 10
params.maxThreshold = 255
params.filterByColor = True
params.blobColor = 255
params.filterByCircularity = False
params.filterByConvexity = False
params.filterByInertia = False
params.filterByArea = True
params.minArea = 10.0
detector = cv2.SimpleBlobDetector_create(params)
# Detect blobs.
key_points = detector.detect(mask)
if len(key_points) <= 0:
return None
return int(key_points[0].pt[0]), int(key_points[0].pt[1])
class PixelLoc:
"""
finds the pixel loc and store it
"""
val = None
@staticmethod
def config():
"""
Uses the game window to get an image of the game screen
then uses `GetKeypointFromImage()` to find the Chalutier pixel location
:return: false if pixel loc not found
"""
PixelLoc.val = (0, 0, 1, 1)
return True

View File

@ -9,7 +9,7 @@ from ttkthemes import ThemedTk
from fishy import helper
from fishy.web import web
from ..constants import chalutier, lam2
from ..constants import chalutier, lam2, fishyqr
from ..helper.config import config
from .discord_login import discord_login
from ..helper.hotkey.hotkey_process import hotkey
@ -59,15 +59,13 @@ def _create(gui: 'GUI'):
filemenu.add_command(label="Update", command=helper.update)
def installer():
if filemenu.entrycget(4, 'label') == "Remove Chalutier":
if helper.remove_addon(chalutier[0]) == 0:
filemenu.entryconfigure(4, label="Install Chalutier")
if filemenu.entrycget(4, 'label') == "Remove FishyQR":
if helper.remove_addon(fishyqr[0]) == 0:
filemenu.entryconfigure(4, label="Install FishyQR")
else:
r = helper.install_addon(*chalutier)
r += helper.install_addon(*lam2)
if r == 0:
filemenu.entryconfigure(4, label="Remove Chalutier")
chaEntry = "Remove Chalutier" if helper.addon_exists(chalutier[0]) else "Install Chalutier"
helper.install_required_addons(True)
filemenu.entryconfigure(4, label="Remove FishyQR")
chaEntry = "Remove FishyQR" if helper.addon_exists(fishyqr[0]) else "Install FishyQR"
filemenu.add_command(label=chaEntry, command=installer)
menubar.add_cascade(label="Options", menu=filemenu)

View File

@ -5,5 +5,5 @@ from .helper import (addon_exists, create_shortcut, create_shortcut_first,
install_addon, install_thread_excepthook, manifest_file,
not_implemented, open_web, playsound_multiple,
remove_addon, restart, unhandled_exception_logging,
update)
update, install_required_addons)
from .luaparser import sv_color_extract

View File

@ -22,6 +22,8 @@ from win32gui import GetForegroundWindow, GetWindowText
import fishy
from fishy import web
from fishy.constants import libgps, lam2, fishyqr
from fishy.helper.config import config
def playsound_multiple(path, count=2):
@ -190,17 +192,34 @@ def get_addonversion(name, url=None, v=None):
return 0
def install_required_addons(force=False):
addons_req = [libgps, lam2, fishyqr]
addon_version = config.get("addon_version", {})
installed = False
for addon in addons_req:
if force or (addon_exists(*addon) and
(addon[0] not in addon_version or (
addon[0] in addon_version and addon_version[addon[0]] < addon[2]))):
remove_addon(*addon)
install_addon(*addon)
addon_version[addon[0]] = addon[2]
installed = True
config.set("addon_version", addon_version)
if installed:
logging.info("Please make sure to enable \"Allow outdated addons\" in ESO")
# noinspection PyBroadException
def install_addon(name, url, v=None):
try:
r = requests.get(url, stream=True)
z = ZipFile(BytesIO(r.content))
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!")
return 0
except Exception:
logging.error("Could not install Add-On " + name + ", try doing it manually")
traceback.print_exc()
return 1

33
fishy/helper/migration.py Normal file
View File

@ -0,0 +1,33 @@
import logging
from fishy.helper.auto_update import _normalize_version
from fishy.constants import chalutier, version
from fishy.helper import helper
from .config import config
class Migration:
@staticmethod
def up_to_0_5_3():
helper.remove_addon(*chalutier)
config.delete("addoninstalled")
@staticmethod
def migrate():
prev_version = _normalize_version(config.get("prev_version", "0.0.0"))
current_version = _normalize_version(version)
if current_version > prev_version:
for v, f in migration_code:
if prev_version < _normalize_version(v) <= current_version:
logging.info(f"running migration for {v}")
f()
config.set("prev_version", version)
migration_code = [
# version, upgrade_code
("0.5.3", Migration.up_to_0_5_3)
]