Skip to content
This repository was archived by the owner on Nov 28, 2024. It is now read-only.

Commit 1464f16

Browse files
authored
Merge branch 'main' into dependabot/pip/regex-2024.4.16
2 parents 02a135e + aae96a0 commit 1464f16

File tree

9 files changed

+511
-114
lines changed

9 files changed

+511
-114
lines changed

README.md

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,26 @@
1-
# **BHBot**
1+
# BHBot
22

3-
#### **Gold/XP farming bot for Brawlhalla**
4-
5-
[![Semgrep](https://github.com/Nick2bad4u/BHBot/actions/workflows/semgrep.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/semgrep.yml)
6-
[![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)
7-
[![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)
8-
[![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)
9-
[![Bandit](https://github.com/Nick2bad4u/BHBot/actions/workflows/bandit.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/bandit.yml)
10-
[![Dependency review](https://github.com/Nick2bad4u/BHBot/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/dependency-review.yml)
11-
[![DevSkim](https://github.com/Nick2bad4u/BHBot/actions/workflows/devskim.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/devskim.yml)
12-
[![Greetings](https://github.com/Nick2bad4u/BHBot/actions/workflows/greetings.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/greetings.yml)
13-
[![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)
14-
[![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)
15-
[![OSSAR](https://github.com/Nick2bad4u/BHBot/actions/workflows/ossar.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/ossar.yml)
16-
[![Python application](https://github.com/Nick2bad4u/BHBot/actions/workflows/python-app.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/python-app.yml)
17-
[![Scorecard supply-chain security](https://github.com/Nick2bad4u/BHBot/actions/workflows/scorecard.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/scorecard.yml)
18-
[![Sobelow](https://github.com/Nick2bad4u/BHBot/actions/workflows/sobelow.yml/badge.svg)](https://github.com/Nick2bad4u/BHBot/actions/workflows/sobelow.yml)
19-
[![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)
3+
[Этот файл доступен на Русском языке](README_RU.md)
204

21-
- **[Latest Release](https://github.com/Nick2bad4u/BHBot/releases)** - Download Python (Source Code) or Compiled EXE version for Windows here.
5+
Gold/XP farming bot for Brawlhalla
226

23-
###### (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.)
7+
Heavily inspired by [BrawlhallaEZ](https://github.com/jamunano/BrawlhallaEZ)
248

25-
**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)
9+
### -------------------------------------------------------------------
2610

27-
- You need to go into the bot settings and unselect "mute" if you are using stealth mode in the USA.
28-
- Manually mute the bot via Windows Volume Mixer
11+
### BOT IS NO LONGER ACTIVELY MAINTAINED!
2912

30-
[Этот файл доступен на Русском языке](README_RU.md)
13+
### -------------------------------------------------------------------
3114

32-
Heavily inspired by [BrawlhallaEZ](https://github.com/jamunano/BrawlhallaEZ)
15+
**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
16+
not responsible for any harm the program may case. Use at your own risk
3317

34-
- **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.
35-
- **Use at your own risk**
36-
- ###### (It should work fine, I tested it for >2000 hours at this point along with a variety of other people)
18+
(it should work fine tho, I tested it for >600 hours at this point)
3719

3820
# Installation
21+
Latest release can always be downloaded [here](https://sovamor.co/bhbot)
3922

40-
Latest release can always be downloaded [here](https://github.com/Nick2bad4u/BHBot/releases/)
23+
Bot _should_ auto-update as soon as any updates are released according to selected branch in settings
4124

4225
# Features
4326

@@ -53,17 +36,14 @@ Latest release can always be downloaded [here](https://github.com/Nick2bad4u/BHB
5336
- ~~Brews you coffee~~ (only tea supported for now)
5437

5538
# Usage
56-
57-
- Should be pretty straightforward. Just select needed settings and click "Start" :)
39+
Should be pretty straightforward. Just select needed settings and click "Start" :)
5840

5941
# Limitations
60-
61-
- Bot requires "Collapse crossovers" to be set to Yes.
62-
- Bot requires ingame language to be set to English.
42+
- 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)
43+
- 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)
6344

6445
# Internal stuff
46+
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
47+
decide what to do at any given point
6548

66-
- 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
67-
68-
- You can use BrawlhallaBot class directly or write your own wrapper for it.
69-
- It is completely independent and gui.py is just a PySimpleGUI graphical wrapper
49+
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

client_config.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class ClientConfig(object):
2-
PUBLIC_KEY = "fwL+l4+Xb4lAf5zdgwEKqr+zu+cO9kZ1/6uOb3/RNoA"
3-
APP_NAME = "BHBot"
4-
COMPANY_NAME = "Sovamorco"
2+
PUBLIC_KEY = 'fwL+l4+Xb4lAf5zdgwEKqr+zu+cO9kZ1/6uOb3/RNoA'
3+
APP_NAME = 'BHBot'
4+
COMPANY_NAME = 'Nick2bad4u'
55
HTTP_TIMEOUT = 30
66
MAX_DOWNLOAD_RETRIES = 3
7-
UPDATE_URLS = ["https://sovamor.co/bhbot/versions"]
7+
UPDATE_URLS = ['https://sovamor.co/bhbot/versions']

gui.py

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
import threading
2+
import uuid
3+
4+
from bot import *
5+
6+
7+
class Handler(logging.StreamHandler):
8+
def __init__(self, *args, **kwargs):
9+
super().__init__(*args, **kwargs)
10+
11+
def emit(self, record):
12+
colors = {logging.DEBUG: "grey10", logging.INFO: "white"}
13+
if isinstance(record.msg, str) and record.msg in global_settings.messages:
14+
record.msg = global_settings.messages[record.msg]
15+
Sg.cprint(self.format(record), text_color=colors.get(record.levelno, "red"))
16+
17+
18+
class GUI:
19+
def __init__(self):
20+
self.queue = queue.Queue()
21+
self.bot_thread = None
22+
self.downloading_new_version = False
23+
24+
self.last_window_check = time()
25+
26+
self.window = self.create_window()
27+
28+
display_changelog()
29+
30+
handler = Handler()
31+
handler.setFormatter(MyFormatter())
32+
global_settings.gui_handler = handler
33+
global_settings.set_debug_state()
34+
logger.addHandler(handler)
35+
36+
Config.load() # Display old config warning on bot launch and not on settings opened
37+
38+
@staticmethod
39+
def create_window():
40+
Sg.theme("DarkGrey10")
41+
layout = [
42+
[Sg.Text(" ", size=(1, 1), key="title", font=(global_settings.font, 20))],
43+
[Sg.Text(" ", size=(1, 1), key="version", font=(global_settings.font, 13))],
44+
[
45+
Sg.Text(
46+
" ",
47+
size=(1, 1),
48+
key="press_start",
49+
font=(global_settings.font, 14),
50+
metadata=0,
51+
)
52+
],
53+
[
54+
Sg.Multiline(
55+
size=(90, 10),
56+
key="log",
57+
disabled=True,
58+
autoscroll=True,
59+
write_only=True,
60+
reroute_cprint=True,
61+
reroute_stderr=global_settings.compiled,
62+
font=(global_settings.font, 12),
63+
text_color="red",
64+
)
65+
],
66+
]
67+
68+
buttons = [
69+
[
70+
Sg.Button(
71+
"", key="toggle", font=(global_settings.font, 12), metadata=0
72+
),
73+
Sg.Button("", key="instructions", font=(global_settings.font, 12)),
74+
Sg.Button("", key="settings", font=(global_settings.font, 12)),
75+
Sg.Button("", key="exit", font=(global_settings.font, 12)),
76+
],
77+
[
78+
Sg.Button(
79+
"",
80+
key="delayed_stop",
81+
font=(global_settings.font, 12),
82+
metadata=0,
83+
visible=False,
84+
),
85+
Sg.Button("", key="take_screenshot", font=(global_settings.font, 12)),
86+
],
87+
]
88+
if not global_settings.compiled:
89+
buttons[0].append(
90+
Sg.Button("", key="test", font=(global_settings.font, 12))
91+
)
92+
93+
layout += buttons
94+
layout.append([Sg.Text(" ", font="Any 50")])
95+
96+
if global_settings.new_version:
97+
global_settings.new_version.cleanup()
98+
update_column_layout = [
99+
[
100+
Sg.Text(
101+
" ",
102+
size=(1, 1),
103+
key="update_available_title",
104+
font=(global_settings.font, 25),
105+
)
106+
],
107+
[
108+
Sg.Text(
109+
" ",
110+
size=(1, 1),
111+
key="update_available_version",
112+
font=(global_settings.font, 15),
113+
)
114+
],
115+
[
116+
Sg.Button(
117+
"",
118+
key="update_available_button",
119+
font=(global_settings.font, 12),
120+
)
121+
],
122+
[Sg.Text(" ", font="Any 50")],
123+
]
124+
layout.append([Sg.Column(update_column_layout)])
125+
126+
window = Sg.Window(
127+
"", layout, icon=global_settings.icon, metadata="main_window_title"
128+
).Finalize()
129+
global_settings.update_window(window)
130+
return window
131+
132+
def toggle_bot(self):
133+
if self.bot_thread and self.bot_thread.is_alive():
134+
logger.info("stop_bot")
135+
self.queue.put_nowait("STOP")
136+
else:
137+
logger.info("start_bot")
138+
config = Config.load()
139+
logger.debug(global_settings)
140+
logger.debug(config)
141+
bot = BrawlhallaBot(config, Hotkeys.load(), self.queue)
142+
self.bot_thread = threading.Thread(target=bot.main_loop, daemon=True)
143+
self.bot_thread.start()
144+
145+
def clear_queue(self):
146+
while not self.queue.empty():
147+
try:
148+
self.queue.get_nowait()
149+
except queue.Empty:
150+
continue
151+
self.queue.task_done()
152+
153+
def delayed_stop(self):
154+
if self.bot_thread and self.bot_thread.is_alive():
155+
if self.window["delayed_stop"].metadata:
156+
logger.info("cancel_stop")
157+
self.clear_queue()
158+
else:
159+
logger.info("delayed_stop")
160+
self.queue.put_nowait("DELAYED_STOP")
161+
self.window["delayed_stop"].metadata = not self.window[
162+
"delayed_stop"
163+
].metadata
164+
165+
def refresh_buttons(self):
166+
if self.downloading_new_version:
167+
self.window["toggle"].update(disabled=True)
168+
self.window["delayed_stop"].update(visible=False)
169+
self.window["instructions"].update(disabled=True)
170+
self.window["settings"].update(disabled=True)
171+
self.window["update_available_button"].update(disabled=True)
172+
self.window["exit"].update(disabled=True)
173+
elif self.bot_thread and self.bot_thread.is_alive():
174+
self.window["toggle"].metadata = 1
175+
self.window["press_start"].metadata = 1
176+
self.window["delayed_stop"].Update(visible=True)
177+
self.window["instructions"].Update(disabled=True)
178+
self.window["settings"].Update(disabled=True)
179+
else:
180+
self.window["toggle"].metadata = 0
181+
self.window["press_start"].metadata = 0
182+
self.window["delayed_stop"].metadata = 0
183+
self.window["delayed_stop"].Update(visible=False)
184+
self.window["instructions"].Update(disabled=False)
185+
self.window["settings"].Update(disabled=False)
186+
self.clear_queue()
187+
188+
@staticmethod
189+
def display_instructions():
190+
contents = global_settings.language.LAYOUT_MAPPING.get(
191+
"instructions_contents",
192+
global_settings.get_language("English").LAYOUT_MAPPING.get(
193+
"instructions_contents", "Should be stuff here"
194+
),
195+
)
196+
Sg.popup(
197+
*contents,
198+
font=(global_settings.font, 13),
199+
title=global_settings.language.LAYOUT_MAPPING.get(
200+
"instructions_window_title", "Instructions"
201+
),
202+
icon=global_settings.icon,
203+
)
204+
205+
def configure(self):
206+
settings = GUIConfig()
207+
self.window.disable()
208+
self.window.hide()
209+
settings.start_loop()
210+
self.window.enable()
211+
self.window.un_hide()
212+
213+
def autostart(self):
214+
if not global_settings.autostart:
215+
return
216+
if self.bot_thread and self.bot_thread.is_alive():
217+
self.last_window_check = time()
218+
elif time() - self.last_window_check > 300:
219+
logger.debug("autostart_check")
220+
bh = BrawlhallaProcess.find()
221+
if not bh:
222+
self.toggle_bot()
223+
self.last_window_check = time()
224+
225+
def main_loop(self):
226+
while True:
227+
event, values = self.window.Read(timeout=50)
228+
if event in (Sg.WINDOW_CLOSED, "exit"):
229+
break
230+
elif event == "toggle":
231+
self.toggle_bot()
232+
elif event == "delayed_stop":
233+
self.delayed_stop()
234+
elif event == "instructions":
235+
self.display_instructions()
236+
elif event == "settings":
237+
self.configure()
238+
elif event == "test":
239+
logger.info("test")
240+
logger.debug("test")
241+
elif event == "take_screenshot":
242+
bh = BrawlhallaProcess.find()
243+
if bh is None:
244+
logger.error("bh_not_running")
245+
else:
246+
screenshot_name = f"screenshot-{uuid.uuid4()}.png"
247+
screenshot_path = (
248+
Path(os.getenv("LOCALAPPDATA")) / "BHBot" / screenshot_name
249+
)
250+
bh.make_screenshot().save(screenshot_path)
251+
logger.info("took_screenshot", str(screenshot_path))
252+
253+
elif event == "update_available_button":
254+
global_settings.new_version.download(background=True)
255+
self.downloading_new_version = True
256+
elif not self.downloading_new_version:
257+
self.autostart()
258+
if (
259+
global_settings.compiled
260+
and global_settings.new_version
261+
and self.downloading_new_version
262+
and global_settings.new_version.is_downloaded()
263+
):
264+
global_settings.new_version.extract_restart()
265+
self.refresh_buttons()
266+
global_settings.update_window(self.window)
267+
268+
self.window.close()
269+
270+
271+
if __name__ == "__main__":
272+
Singleton()
273+
gui = GUI()
274+
gui.main_loop()

gui.pyw

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ from bot import *
55

66

77
class Handler(logging.StreamHandler):
8-
98
def __init__(self, *args, **kwargs):
109
super().__init__(*args, **kwargs)
1110

@@ -216,7 +215,7 @@ class GUI:
216215
return
217216
if self.bot_thread and self.bot_thread.is_alive():
218217
self.last_window_check = time()
219-
elif time() - self.last_window_check > 300:
218+
elif time() - self.last_window_check > 120:
220219
logger.debug("autostart_check")
221220
bh = BrawlhallaProcess.find()
222221
if not bh:

0 commit comments

Comments
 (0)