From b57a31dea6da5aeb291848fba6bc2b0dd8e23b49 Mon Sep 17 00:00:00 2001 From: Typpi <20943337+Nick2bad4u@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:00:36 -0400 Subject: [PATCH 1/5] finish python beautifying --- README.md | 56 ++++------ client_config.py | 8 +- gui.py | 274 +++++++++++++++++++++++++++++++++++++++++++++++ gui.pyw | 3 +- gui.spec | 43 ++++++++ qodana.yaml | 29 +++++ requirements.txt | 34 +++--- setup.py | 20 ++-- 8 files changed, 397 insertions(+), 70 deletions(-) create mode 100644 gui.py create mode 100644 gui.spec create mode 100644 qodana.yaml diff --git a/README.md b/README.md index 6e8a5ea..9463648 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,26 @@ -# **BHBot** +# BHBot -#### **Gold/XP farming bot for Brawlhalla** - -[![Semgrep](https://github.com/Nick2bad4u/BHBot/actions/workflows/semgrep.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/semgrep.yml) -[![Upload Python Package](https://github.com/Nick2bad4u/BHBot/actions/workflows/python-publish.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/python-publish.yml) -[![Python Package using Conda](https://github.com/Nick2bad4u/BHBot/actions/workflows/python-package-conda.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/python-package-conda.yml) -[![CodeQL](https://github.com/Nick2bad4u/BHBot/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/github-code-scanning/codeql) -[![Bandit](https://github.com/Nick2bad4u/BHBot/actions/workflows/bandit.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/bandit.yml) -[![Dependency review](https://github.com/Nick2bad4u/BHBot/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/dependency-review.yml) -[![DevSkim](https://github.com/Nick2bad4u/BHBot/actions/workflows/devskim.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/devskim.yml) -[![Greetings](https://github.com/Nick2bad4u/BHBot/actions/workflows/greetings.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/greetings.yml) -[![Mark stale issues and pull requests](https://github.com/Nick2bad4u/BHBot/actions/workflows/stale.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/stale.yml) -[![Microsoft Defender For Devops](https://github.com/Nick2bad4u/BHBot/actions/workflows/defender-for-devops.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/defender-for-devops.yml) -[![OSSAR](https://github.com/Nick2bad4u/BHBot/actions/workflows/ossar.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/ossar.yml) -[![Python application](https://github.com/Nick2bad4u/BHBot/actions/workflows/python-app.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/python-app.yml) -[![Scorecard supply-chain security](https://github.com/Nick2bad4u/BHBot/actions/workflows/scorecard.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/scorecard.yml) -[![Sobelow](https://github.com/Nick2bad4u/BHBot/actions/workflows/sobelow.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/sobelow.yml) -[![Lint Code Base](https://github.com/Nick2bad4u/BHBot/actions/workflows/super-linter.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/super-linter.yml) +[Этот файл доступен на Русском языке](README_RU.md) -- **[Latest Release](https://github.com/Nick2bad4u/BHBot/releases)** - Download Python (Source Code) or Compiled EXE version for Windows here. +Gold/XP farming bot for Brawlhalla -###### (Looking for a Mac user to compile it into a .DMG file, if you know any or would be willing to do this, let me know.) +Heavily inspired by [BrawlhallaEZ](https://github.com/jamunano/BrawlhallaEZ) -**USA** users that want to use stealth mode, please do the following: (otherwise everytime the _"earn free rewards"_ pops up it will stop the bot until cleared) +### ------------------------------------------------------------------- -- You need to go into the bot settings and unselect "mute" if you are using stealth mode in the USA. -- Manually mute the bot via Windows Volume Mixer +### BOT IS NO LONGER ACTIVELY MAINTAINED! -[Этот файл доступен на Русском языке](README_RU.md) +### ------------------------------------------------------------------- -Heavily inspired by [BrawlhallaEZ](https://github.com/jamunano/BrawlhallaEZ) +**WARNING:** Bot was initially made for personal use. It should not, but still can cause some unexpected consequences, including making purchases from mallhalla (with in-game currencies). Developer is +not responsible for any harm the program may case. Use at your own risk -- **WARNING:** Bot was initially made for personal use. It should not, but still can cause some unexpected consequences, including making purchases from mallhalla (with in-game currencies). Developer is not responsible for any harm the program may case. -- **Use at your own risk** -- ###### (It should work fine, I tested it for >2000 hours at this point along with a variety of other people) +(it should work fine tho, I tested it for >600 hours at this point) # Installation +Latest release can always be downloaded [here](https://sovamor.co/bhbot) -Latest release can always be downloaded [here](https://github.com/Nick2bad4u/BHBot/releases/) +Bot _should_ auto-update as soon as any updates are released according to selected branch in settings # Features @@ -53,17 +36,14 @@ Latest release can always be downloaded [here](https://github.com/Nick2bad4u/BHB - ~~Brews you coffee~~ (only tea supported for now) # Usage - -- Should be pretty straightforward. Just select needed settings and click "Start" :) +Should be pretty straightforward. Just select needed settings and click "Start" :) # Limitations - -- Bot requires "Collapse crossovers" to be set to Yes. -- Bot requires ingame language to be set to English. +- Bot requires "Collapse crossovers" to be set to Yes. If you think it should automatically set it to be so, please [open an issue](https://github.com/sovamorco/bhbot/issues) +- Bot requires ingame language to be set to English. If you think it should automatically set it to be so, please [open an issue](https://github.com/sovamorco/bhbot/issues) # Internal stuff +You can always check the code, but basically bot uses windows SendMessage API to send inputs directly to Brawlhalla window and pixel detection to detect states and +decide what to do at any given point -- You can always check the code, but basically the bot uses Windows SendMessage API to send inputs directly to a Brawlhalla window with pixel detection to detect states of the game and then decide what to do at any given point - depending on mode selected - -- You can use BrawlhallaBot class directly or write your own wrapper for it. -- It is completely independent and gui.py is just a PySimpleGUI graphical wrapper +You can use BrawlhallaBot class directly or write your own wrapper for it. It should be completely independent and gui.py is just a PySimpleGUI graphical wrapper diff --git a/client_config.py b/client_config.py index 83e89ad..e2183ee 100644 --- a/client_config.py +++ b/client_config.py @@ -1,7 +1,7 @@ class ClientConfig(object): - PUBLIC_KEY = "fwL+l4+Xb4lAf5zdgwEKqr+zu+cO9kZ1/6uOb3/RNoA" - APP_NAME = "BHBot" - COMPANY_NAME = "Sovamorco" + PUBLIC_KEY = 'fwL+l4+Xb4lAf5zdgwEKqr+zu+cO9kZ1/6uOb3/RNoA' + APP_NAME = 'BHBot' + COMPANY_NAME = 'Nick2bad4u' HTTP_TIMEOUT = 30 MAX_DOWNLOAD_RETRIES = 3 - UPDATE_URLS = ["https://sovamor.co/bhbot/versions"] + UPDATE_URLS = ['https://sovamor.co/bhbot/versions'] diff --git a/gui.py b/gui.py new file mode 100644 index 0000000..de7d27f --- /dev/null +++ b/gui.py @@ -0,0 +1,274 @@ +import threading +import uuid + +from bot import * + + +class Handler(logging.StreamHandler): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def emit(self, record): + colors = {logging.DEBUG: "grey10", logging.INFO: "white"} + if isinstance(record.msg, str) and record.msg in global_settings.messages: + record.msg = global_settings.messages[record.msg] + Sg.cprint(self.format(record), text_color=colors.get(record.levelno, "red")) + + +class GUI: + def __init__(self): + self.queue = queue.Queue() + self.bot_thread = None + self.downloading_new_version = False + + self.last_window_check = time() + + self.window = self.create_window() + + display_changelog() + + handler = Handler() + handler.setFormatter(MyFormatter()) + global_settings.gui_handler = handler + global_settings.set_debug_state() + logger.addHandler(handler) + + Config.load() # Display old config warning on bot launch and not on settings opened + + @staticmethod + def create_window(): + Sg.theme("DarkGrey10") + layout = [ + [Sg.Text(" ", size=(1, 1), key="title", font=(global_settings.font, 20))], + [Sg.Text(" ", size=(1, 1), key="version", font=(global_settings.font, 13))], + [ + Sg.Text( + " ", + size=(1, 1), + key="press_start", + font=(global_settings.font, 14), + metadata=0, + ) + ], + [ + Sg.Multiline( + size=(90, 10), + key="log", + disabled=True, + autoscroll=True, + write_only=True, + reroute_cprint=True, + reroute_stderr=global_settings.compiled, + font=(global_settings.font, 12), + text_color="red", + ) + ], + ] + + buttons = [ + [ + Sg.Button( + "", key="toggle", font=(global_settings.font, 12), metadata=0 + ), + Sg.Button("", key="instructions", font=(global_settings.font, 12)), + Sg.Button("", key="settings", font=(global_settings.font, 12)), + Sg.Button("", key="exit", font=(global_settings.font, 12)), + ], + [ + Sg.Button( + "", + key="delayed_stop", + font=(global_settings.font, 12), + metadata=0, + visible=False, + ), + Sg.Button("", key="take_screenshot", font=(global_settings.font, 12)), + ], + ] + if not global_settings.compiled: + buttons[0].append( + Sg.Button("", key="test", font=(global_settings.font, 12)) + ) + + layout += buttons + layout.append([Sg.Text(" ", font="Any 50")]) + + if global_settings.new_version: + global_settings.new_version.cleanup() + update_column_layout = [ + [ + Sg.Text( + " ", + size=(1, 1), + key="update_available_title", + font=(global_settings.font, 25), + ) + ], + [ + Sg.Text( + " ", + size=(1, 1), + key="update_available_version", + font=(global_settings.font, 15), + ) + ], + [ + Sg.Button( + "", + key="update_available_button", + font=(global_settings.font, 12), + ) + ], + [Sg.Text(" ", font="Any 50")], + ] + layout.append([Sg.Column(update_column_layout)]) + + window = Sg.Window( + "", layout, icon=global_settings.icon, metadata="main_window_title" + ).Finalize() + global_settings.update_window(window) + return window + + def toggle_bot(self): + if self.bot_thread and self.bot_thread.is_alive(): + logger.info("stop_bot") + self.queue.put_nowait("STOP") + else: + logger.info("start_bot") + config = Config.load() + logger.debug(global_settings) + logger.debug(config) + bot = BrawlhallaBot(config, Hotkeys.load(), self.queue) + self.bot_thread = threading.Thread(target=bot.main_loop, daemon=True) + self.bot_thread.start() + + def clear_queue(self): + while not self.queue.empty(): + try: + self.queue.get_nowait() + except queue.Empty: + continue + self.queue.task_done() + + def delayed_stop(self): + if self.bot_thread and self.bot_thread.is_alive(): + if self.window["delayed_stop"].metadata: + logger.info("cancel_stop") + self.clear_queue() + else: + logger.info("delayed_stop") + self.queue.put_nowait("DELAYED_STOP") + self.window["delayed_stop"].metadata = not self.window[ + "delayed_stop" + ].metadata + + def refresh_buttons(self): + if self.downloading_new_version: + self.window["toggle"].update(disabled=True) + self.window["delayed_stop"].update(visible=False) + self.window["instructions"].update(disabled=True) + self.window["settings"].update(disabled=True) + self.window["update_available_button"].update(disabled=True) + self.window["exit"].update(disabled=True) + elif self.bot_thread and self.bot_thread.is_alive(): + self.window["toggle"].metadata = 1 + self.window["press_start"].metadata = 1 + self.window["delayed_stop"].Update(visible=True) + self.window["instructions"].Update(disabled=True) + self.window["settings"].Update(disabled=True) + else: + self.window["toggle"].metadata = 0 + self.window["press_start"].metadata = 0 + self.window["delayed_stop"].metadata = 0 + self.window["delayed_stop"].Update(visible=False) + self.window["instructions"].Update(disabled=False) + self.window["settings"].Update(disabled=False) + self.clear_queue() + + @staticmethod + def display_instructions(): + contents = global_settings.language.LAYOUT_MAPPING.get( + "instructions_contents", + global_settings.get_language("English").LAYOUT_MAPPING.get( + "instructions_contents", "Should be stuff here" + ), + ) + Sg.popup( + *contents, + font=(global_settings.font, 13), + title=global_settings.language.LAYOUT_MAPPING.get( + "instructions_window_title", "Instructions" + ), + icon=global_settings.icon, + ) + + def configure(self): + settings = GUIConfig() + self.window.disable() + self.window.hide() + settings.start_loop() + self.window.enable() + self.window.un_hide() + + def autostart(self): + if not global_settings.autostart: + return + if self.bot_thread and self.bot_thread.is_alive(): + self.last_window_check = time() + elif time() - self.last_window_check > 300: + logger.debug("autostart_check") + bh = BrawlhallaProcess.find() + if not bh: + self.toggle_bot() + self.last_window_check = time() + + def main_loop(self): + while True: + event, values = self.window.Read(timeout=50) + if event in (Sg.WINDOW_CLOSED, "exit"): + break + elif event == "toggle": + self.toggle_bot() + elif event == "delayed_stop": + self.delayed_stop() + elif event == "instructions": + self.display_instructions() + elif event == "settings": + self.configure() + elif event == "test": + logger.info("test") + logger.debug("test") + elif event == "take_screenshot": + bh = BrawlhallaProcess.find() + if bh is None: + logger.error("bh_not_running") + else: + screenshot_name = f"screenshot-{uuid.uuid4()}.png" + screenshot_path = ( + Path(os.getenv("LOCALAPPDATA")) / "BHBot" / screenshot_name + ) + bh.make_screenshot().save(screenshot_path) + logger.info("took_screenshot", str(screenshot_path)) + + elif event == "update_available_button": + global_settings.new_version.download(background=True) + self.downloading_new_version = True + elif not self.downloading_new_version: + self.autostart() + if ( + global_settings.compiled + and global_settings.new_version + and self.downloading_new_version + and global_settings.new_version.is_downloaded() + ): + global_settings.new_version.extract_restart() + self.refresh_buttons() + global_settings.update_window(self.window) + + self.window.close() + + +if __name__ == "__main__": + Singleton() + gui = GUI() + gui.main_loop() diff --git a/gui.pyw b/gui.pyw index 1147840..b129bc3 100644 --- a/gui.pyw +++ b/gui.pyw @@ -5,7 +5,6 @@ from bot import * class Handler(logging.StreamHandler): - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -216,7 +215,7 @@ class GUI: return if self.bot_thread and self.bot_thread.is_alive(): self.last_window_check = time() - elif time() - self.last_window_check > 300: + elif time() - self.last_window_check > 120: logger.debug("autostart_check") bh = BrawlhallaProcess.find() if not bh: diff --git a/gui.spec b/gui.spec new file mode 100644 index 0000000..c9283f8 --- /dev/null +++ b/gui.spec @@ -0,0 +1,43 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['gui.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name='gui', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) +coll = COLLECT( + exe, + a.binaries, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='gui', +) diff --git a/qodana.yaml b/qodana.yaml new file mode 100644 index 0000000..76fb7ad --- /dev/null +++ b/qodana.yaml @@ -0,0 +1,29 @@ +#-------------------------------------------------------------------------------# +# Qodana analysis is configured by qodana.yaml file # +# https://www.jetbrains.com/help/qodana/qodana-yaml.html # +#-------------------------------------------------------------------------------# +version: "1.0" + +#Specify inspection profile for code analysis +profile: + name: qodana.starter + +#Enable inspections +#include: +# - name: + +#Disable inspections +#exclude: +# - name: +# paths: +# - + +#Execute shell command before Qodana execution (Applied in CI/CD pipeline) +#bootstrap: sh ./prepare-qodana.sh + +#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline) +#plugins: +# - id: #(plugin id can be found at https://plugins.jetbrains.com) + +#Specify Qodana linter for analysis (Applied in CI/CD pipeline) +linter: jetbrains/qodana-:latest diff --git a/requirements.txt b/requirements.txt index 5b2be4b..d2206ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ altgraph==0.17.4 appdirs==1.4.4 asttokens==2.4.1 attrs==23.2.0 -auto-py-to-exe==2.43.3 +auto-py-to-exe==2.42.0 backcall==0.2.0 beautifulsoup4==4.12.3 bleach==6.1.0 @@ -22,12 +22,13 @@ dsdev-utils==1.3.0 Eel==1.0.0a1 executing==2.0.1 fastjsonschema==2.19.1 -fonttools==4.51.0 +fonttools==4.50.0 future==1.0.0 gevent==24.2.1 gevent-websocket==0.10.1 greenlet==3.0.3 -idna==3.7 +idna==3.6 +ipython==8.12.3 jedi==0.19.1 Jinja2==3.1.3 jsonschema==4.21.1 @@ -37,43 +38,44 @@ jupyter_core==5.7.2 jupyterlab_pygments==0.3.0 keyboard==0.13.5 MarkupSafe==2.1.5 -matplotlib-inline==0.1.7 +matplotlib-inline==0.1.6 mistune==3.0.2 nbclient==0.10.0 -nbconvert==7.16.3 -nbformat==5.10.4 +nbconvert==7.16.2 +nbformat==5.10.3 packaging==24.0 pandocfilters==1.5.1 -parso==0.8.4 +parso==0.8.3 pbr==6.0.0 pefile==2023.2.7 pickleshare==0.7.5 -pillow==10.3.0 +pillow==10.2.0 +pip==24.0 pipreqs==0.5.0 platformdirs==4.2.0 prompt-toolkit==3.0.43 psutil==5.9.8 pure-eval==0.2.2 -pyasn1==0.6.0 -pycparser==2.22 +pyasn1==0.5.1 +pycparser==2.21 Pygments==2.17.2 pyinstaller==6.5.0 -pyinstaller-hooks-contrib==2024.4 +pyinstaller-hooks-contrib==2024.3 PyNaCl==1.5.0 pyparsing==3.1.2 pypiwin32==223 -PySimpleGUI==5.0.4 +PySimpleGUI==5.0.3 python-dateutil==2.9.0.post0 PyUpdater==4.0 pywin32==306 pywin32-ctypes==0.2.2 -pyzmq==26.0.0 -referencing==0.34.0 +pyzmq==25.1.2 +referencing==0.33.0 regex==2023.12.25 requests==2.31.0 rpds-py==0.18.0 rsa==4.9 -setuptools==69.5.1 +setuptools==69.2.0 six==1.16.0 soupsieve==2.5 stack-data==0.6.3 @@ -88,4 +90,4 @@ whichcraft==0.6.1 wrapt==1.16.0 yarg==0.1.9 zope.event==5.0 -zope.interface==6.3 +zope.interface==6.2 \ No newline at end of file diff --git a/setup.py b/setup.py index 29fd3db..96ef883 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,14 @@ from setuptools import setup setup( - name="BHBot", - version="V2.0", - packages=[""], - url="https://github.com/Nick2bad4u/BHBot", - license="Unlicense", - author="Nick", - author_email="", - description="", - long_description=open("README.md").read(), - long_description_content_type="text/markdown", + name='BHBot-master', + version='V1', + packages=[''], + url='https://github.com/Nick2bad4u/BHBot', + license='Unlicense', + author='Nick', + author_email='', + description='', + long_description=open('README.md').read(), + long_description_content_type='text/markdown' ) From ec52ce9f12df55185f16bb68ed1bdda4f6c16cb8 Mon Sep 17 00:00:00 2001 From: Typpi <20943337+Nick2bad4u@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:17:22 -0400 Subject: [PATCH 2/5] Update levels.py --- levels.py | 170 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 120 insertions(+), 50 deletions(-) diff --git a/levels.py b/levels.py index 7cf9e24..bad8412 100644 --- a/levels.py +++ b/levels.py @@ -1,45 +1,112 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from utils import * -level_bbox = 975, 143, 1060, 198 +level_bbox = (975, 143, 1060, 198) font_color = (254, 254, 254) single_digit_diff = 21 second_digit_diff = 43 -bar_bbox = 1082, 148, 1656, 149 +bar_bbox = (1082, 148, 1656, 149) bar_colors = ((158, 158, 177), (128, 128, 153), (30, 60, 126)) -rewards_bar_bbox = 786, 331, 1365, 332 +rewards_bar_bbox = (786, 331, 1365, 332) rewards_bar_colors = ((35, 120), (190, 255), (40, 165)) -locked_pixel = 1163, 875 +locked_pixel = (1163, 875) locked_color = (110, 200, 211) first_digit_dict = { - "1": ((10, 17), (15, 45), (17, 4), (20, 15), (27, 45), (29, 4), (19, 32)), - "2": ((5, 11), (6, 5), (9, 3), (30, 4), (34, 45), (36, 12)), - "3": ((3, 37), (7, 10), (8, 3), (9, 23), (33, 6), (36, 34)), - "4": ((2, 25), (2, 34), (19, 45), (30, 45), (32, 3), (37, 27)), - "5": ((4, 37), (5, 26), (7, 4), (23, 20), (34, 4), (36, 32)), - "6": ((2, 28), (3, 37), (16, 3), (25, 46), (29, 3), (37, 27)), - "7": ((4, 3), (4, 11), (5, 45), (19, 45), (36, 3), (36, 12)), - "8": ((2, 38), (5, 12), (19, 27), (20, 3), (36, 11), (37, 35)), - "9": ((10, 45), (15, 3), (15, 30), (19, 23), (22, 28), (24, 45)), - "0": ((1, 30), (9, 6), (15, 13), (23, 46), (24, 34), (37, 17)), -} - -second_digit_dict = dict( - ( - (key, tuple(((x + second_digit_diff, y) for x, y in value))) - for key, value in first_digit_dict.items() - ) -) + '1': ( + (10, 17), + (15, 45), + (17, 4), + (20, 15), + (27, 45), + (29, 4), + (19, 32), + ), + '2': ( + (5, 11), + (6, 5), + (9, 3), + (30, 4), + (34, 45), + (36, 12), + ), + '3': ( + (3, 37), + (7, 10), + (8, 3), + (9, 23), + (33, 6), + (36, 34), + ), + '4': ( + (2, 25), + (2, 34), + (19, 45), + (30, 45), + (32, 3), + (37, 27), + ), + '5': ( + (4, 37), + (5, 26), + (7, 4), + (23, 20), + (34, 4), + (36, 32), + ), + '6': ( + (2, 28), + (3, 37), + (16, 3), + (25, 46), + (29, 3), + (37, 27), + ), + '7': ( + (4, 3), + (4, 11), + (5, 45), + (19, 45), + (36, 3), + (36, 12), + ), + '8': ( + (2, 38), + (5, 12), + (19, 27), + (20, 3), + (36, 11), + (37, 35), + ), + '9': ( + (10, 45), + (15, 3), + (15, 30), + (19, 23), + (22, 28), + (24, 45), + ), + '0': ( + (1, 30), + (9, 6), + (15, 13), + (23, 46), + (24, 34), + (37, 17), + ), + } -single_digit_dict = dict( - ( - (key, tuple(((x + single_digit_diff, y) for x, y in value))) - for key, value in first_digit_dict.items() - ) -) +second_digit_dict = dict((key, tuple((x + second_digit_diff, y) for (x, + y) in value)) for (key, value) in + first_digit_dict.items()) + +single_digit_dict = dict((key, tuple((x + single_digit_diff, y) for (x, + y) in value)) for (key, value) in + first_digit_dict.items()) level_hundred_conditions = ( (0, 9), @@ -51,10 +118,11 @@ (62, 37), (84, 9), (84, 40), -) + ) -levels_xp = [ - 0, # infinite xp if lvl 0 (undefined) +levels_xp = [ # infinite xp if lvl 0 (undefined) + # infinite xp if lvl 100 (max lvl) + 0, 210, 368, 455, @@ -154,8 +222,8 @@ 24592, 24917, 25263, - float("inf"), # infinite xp if lvl 100 (max lvl) -] + float('inf'), + ] gold_levels = list(range(7, 20, 2)) + list(range(21, 101)) @@ -169,10 +237,12 @@ def get_duration_gold(duration): class LevelNotDetected(Exception): + pass class LevelDefiner: + def __init__(self, brawlhalla): self.brawlhalla = brawlhalla @@ -180,28 +250,30 @@ def _get_single_digit_level(self, image): return int(self.get_single_digit(image)) def _get_double_digit_level(self, image): - return int(self.get_first_digit(image) + self.get_second_digit(image)) + return int(self.get_first_digit(image) + + self.get_second_digit(image)) @staticmethod def _get_level_hundred(image): - if all(image.getpixel(pos) == font_color for pos in level_hundred_conditions): + if all(image.getpixel(pos) == font_color for pos in + level_hundred_conditions): return 100 raise TypeError def get_level(self): screenshot = self.brawlhalla.make_screenshot() level = screenshot.crop(level_bbox) - for f in [ - self._get_single_digit_level, - self._get_double_digit_level, - self._get_level_hundred, - ]: + for f in [self._get_single_digit_level, + self._get_double_digit_level, + self._get_level_hundred]: try: + # noinspection PyArgumentList + return f(level) except TypeError: pass - logger.error("level_error") + logger.error('level_error') raise LevelNotDetected def get_percentage(self): @@ -221,10 +293,9 @@ def get_reward_percentage(self): bar = screenshot.crop(rewards_bar_bbox) for i in range(bar.width): pixel = bar.getpixel((i, 0)) - if all( - rewards_bar_colors[i][1] > pixel[i] > rewards_bar_colors[i][0] - for i in range(len(pixel)) - ): + if all(rewards_bar_colors[i][1] > pixel[i] + > rewards_bar_colors[i][0] for i in + range(len(pixel))): count += 1 perc = count / bar.width return perc @@ -232,10 +303,8 @@ def get_reward_percentage(self): def get_xp(self, level, reward=False): if level == 100: return 0 - return int( - (self.get_reward_percentage() if reward else self.get_percentage()) - * levels_xp[level] - ) + return int(((self.get_reward_percentage() if reward else self.get_percentage())) + * levels_xp[level]) def get_unlocked(self): screenshot = self.brawlhalla.make_screenshot() @@ -244,7 +313,8 @@ def get_unlocked(self): @staticmethod def get_digit(conditions, image): for digit in conditions: - if all(image.getpixel(pos) == font_color for pos in conditions[digit]): + if all(image.getpixel(pos) == font_color for pos in + conditions[digit]): return digit def get_first_digit(self, image): From c3e064b3d50d354a0eadcdd564345e8f9653a2ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 22:12:55 +0000 Subject: [PATCH 3/5] Bump nbconvert from 7.16.2 to 7.16.3 Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 7.16.2 to 7.16.3. - [Release notes](https://github.com/jupyter/nbconvert/releases) - [Changelog](https://github.com/jupyter/nbconvert/blob/main/CHANGELOG.md) - [Commits](https://github.com/jupyter/nbconvert/compare/v7.16.2...v7.16.3) --- updated-dependencies: - dependency-name: nbconvert dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d2206ed..58b4c57 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,7 +41,7 @@ MarkupSafe==2.1.5 matplotlib-inline==0.1.6 mistune==3.0.2 nbclient==0.10.0 -nbconvert==7.16.2 +nbconvert==7.16.3 nbformat==5.10.3 packaging==24.0 pandocfilters==1.5.1 From afd75e8c16193b7390220b15e8cb435dbe427f29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 22:12:44 +0000 Subject: [PATCH 4/5] Bump fonttools from 4.50.0 to 4.51.0 Bumps [fonttools](https://github.com/fonttools/fonttools) from 4.50.0 to 4.51.0. - [Release notes](https://github.com/fonttools/fonttools/releases) - [Changelog](https://github.com/fonttools/fonttools/blob/main/NEWS.rst) - [Commits](https://github.com/fonttools/fonttools/compare/4.50.0...4.51.0) --- updated-dependencies: - dependency-name: fonttools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 58b4c57..ebc5ea6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ dsdev-utils==1.3.0 Eel==1.0.0a1 executing==2.0.1 fastjsonschema==2.19.1 -fonttools==4.50.0 +fonttools==4.51.0 future==1.0.0 gevent==24.2.1 gevent-websocket==0.10.1 From aae96a029ef785d92a75db451cea580af293ae86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:18:17 +0000 Subject: [PATCH 5/5] Bump the pip group with 2 updates Bumps the pip group with 2 updates: [idna](https://github.com/kjd/idna) and [pillow](https://github.com/python-pillow/Pillow). Updates `idna` from 3.6 to 3.7 - [Release notes](https://github.com/kjd/idna/releases) - [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst) - [Commits](https://github.com/kjd/idna/compare/v3.6...v3.7) Updates `pillow` from 10.2.0 to 10.3.0 - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/10.2.0...10.3.0) --- updated-dependencies: - dependency-name: idna dependency-type: direct:production dependency-group: pip - dependency-name: pillow dependency-type: direct:production dependency-group: pip ... Signed-off-by: dependabot[bot] --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index ebc5ea6..77bd4d1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,7 +27,7 @@ future==1.0.0 gevent==24.2.1 gevent-websocket==0.10.1 greenlet==3.0.3 -idna==3.6 +idna==3.7 ipython==8.12.3 jedi==0.19.1 Jinja2==3.1.3 @@ -49,7 +49,7 @@ parso==0.8.3 pbr==6.0.0 pefile==2023.2.7 pickleshare==0.7.5 -pillow==10.2.0 +pillow==10.3.0 pip==24.0 pipreqs==0.5.0 platformdirs==4.2.0