diff --git a/README.md b/README.md index 0158406..7249ddf 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ run_shenk=0 | logger_lvl | Can be any of [info, debug] and determines how much output you see on the command line | | randomize_runs | If 0, the order will always be pindle -> eldritch/shenk. If 1 the order will be random | | difficulty | Set to `normal` `nightmare` or `hell` for game difficulty | -| custom_discord_hook | Add your own discord hook here to get messages about drops and in case botty got stuck and can not resume | +| custom_message_hook | Add your own message hook here to get messages about drops and in case botty got stuck and can not resume, discord webhook is default | | discord_status_count | Number of games between discord status messges being sent. Leave empty for no status reports. | info_screenshots | If 1, the bot takes a screenshot with timestamp on every stuck / chicken / timeout / inventory full event. This is 1 by Default, so remember to clean up the folder every once in a while | | loot_screenshots | If 1, the bot takes a screenshot with timestamp everytime he presses show_items button and saves it to loot_screenshots folder. Remember to clear them once in a while... | diff --git a/config/params.ini b/config/params.ini index d2e8721..4ae56f9 100644 --- a/config/params.ini +++ b/config/params.ini @@ -11,7 +11,7 @@ graphic_debugger_key=f10 logg_lvl=debug randomize_runs=0 difficulty=hell -custom_discord_hook= +custom_message_hook= discord_status_count=20 info_screenshots=1 loot_screenshots=0 @@ -82,3 +82,6 @@ redemption= [advanced_options] ;===== don't touch unless you know what you're doing ===== pathing_delay_factor=5 +message_headers= +message_body_template={{"content": "{msg}"}} +message_highlight=1 diff --git a/src/config.py b/src/config.py index 2d05e22..bb74a53 100644 --- a/src/config.py +++ b/src/config.py @@ -44,7 +44,7 @@ class Config: "logg_lvl": self._select_val("general", "logg_lvl"), "randomize_runs": bool(int(self._select_val("general", "randomize_runs"))), "difficulty": self._select_val("general", "difficulty"), - "custom_discord_hook": self._select_val("general", "custom_discord_hook"), + "custom_message_hook": self._select_val("general", "custom_message_hook"), "discord_status_count": False if not self._select_val("general", "discord_status_count") else int(self._select_val("general", "discord_status_count")), "info_screenshots": bool(int(self._select_val("general", "info_screenshots"))), "loot_screenshots": bool(int(self._select_val("general", "loot_screenshots"))), @@ -109,6 +109,9 @@ class Config: self.advanced_options = { "pathing_delay_factor": min(max(int(self._select_val("advanced_options", "pathing_delay_factor")), 1), 10), + "message_headers": self._select_val("advanced_options", "message_headers"), + "message_body_template": self._select_val("advanced_options", "message_body_template"), + "message_highlight": bool(int(self._select_val("advanced_options", "message_highlight"))), } self.items = {} diff --git a/src/game_stats.py b/src/game_stats.py index 90a6317..5f7a64d 100644 --- a/src/game_stats.py +++ b/src/game_stats.py @@ -2,13 +2,17 @@ from logger import Logger import time import threading from config import Config -from utils.misc import send_discord, hms +from messenger import Messenger +from utils.misc import hms import inspect +from version import __version__ + class GameStats: def __init__(self): self._config = Config() + self._messenger = Messenger() self._picked_up_items = [] self._start_time = time.time() self._timer = None @@ -20,38 +24,37 @@ class GameStats: self._runs_failed = 0 self._failed_game_time = 0 - def _send_discord_thread(self, msg: str, color_it: bool = False): - if self._config.general["custom_discord_hook"]: - msg = f"{self._config.general['name']}: {msg}" - send_discord_thread = threading.Thread( - target=send_discord, - args=(msg, self._config.general["custom_discord_hook"], color_it) + def _send_message_thread(self, msg: str): + if self._config.general["custom_message_hook"]: + send_message_thread = threading.Thread( + target=self._messenger.send, + kwargs={"msg": msg} ) - send_discord_thread.daemon = True - send_discord_thread.start() + send_message_thread.daemon = True + send_message_thread.start() - def log_item_pickup(self, item_name: str, send_discord: bool, area: str = None): + def log_item_pickup(self, item_name: str, send_message: bool, area: str = None): self._picked_up_items.append(item_name) - if send_discord: - msg = f"Found {item_name}" + if send_message: + msg = f"{self._config.general['name']}: Found {item_name}" if area is not None: msg += f" at {area}" - self._send_discord_thread(msg, True) + self._send_message_thread(msg) def log_death(self): self._death_counter += 1 - self._send_discord_thread(f"You have died") + self._send_message_thread(f"{self._config.general['name']}: You have died") def log_chicken(self): self._chicken_counter += 1 - self._send_discord_thread(f"You have chickened") + self._send_message_thread(f"{self._config.general['name']}: You have chickened") def log_start_game(self): if self._game_counter > 0: self._save_stats_to_file() if self._config.general["discord_status_count"] and self._game_counter % self._config.general["discord_status_count"] == 0: - # every 20th game send a discord update about current status - self._send_discord_status_update() + # every 20th game send a message update about current status + self._send_status_update() self._game_counter += 1 self._timer = time.time() Logger.info(f"Starting game #{self._game_counter}") @@ -108,9 +111,9 @@ class GameStats: ''') return msg - def _send_discord_status_update(self): - msg = f"Status Report\n{self._create_msg()}\nVersion:" - self._send_discord_thread(msg) + def _send_status_update(self): + msg = f"{self._config.general['name']}: Status Report\\n{self._create_msg()}\\nVersion: {__version__}" + self._send_message_thread(msg) def _save_stats_to_file(self): msg = self._create_msg() diff --git a/src/main.py b/src/main.py index f419421..434ae20 100644 --- a/src/main.py +++ b/src/main.py @@ -7,10 +7,11 @@ import logging import cv2 import traceback +from messenger import Messenger from version import __version__ from utils.graphic_debugger import run_graphic_debugger from utils.auto_settings import adjust_settings -from utils.misc import kill_thread, send_discord +from utils.misc import kill_thread from config import Config from screen import Screen @@ -42,6 +43,7 @@ def run_bot( do_restart = False keyboard.add_hotkey(config.general["exit_key"], lambda: Logger.info(f'Force Exit') or os._exit(1)) keyboard.add_hotkey(config.general['resume_key'], lambda: bot.toggle_pause()) + messenger = Messenger() while 1: health_manager.update_location(bot.get_curr_location()) max_game_length_reached = game_stats.get_current_game_length() > config.general["max_game_length_s"] @@ -72,8 +74,8 @@ def run_bot( if config.general["info_screenshots"]: cv2.imwrite("./info_screenshots/info_could_not_recover_" + time.strftime("%Y%m%d_%H%M%S") + ".png", bot._screen.grab()) Logger.error(f"{config.general['name']} could not recover from a max game length violation. Shutting down everything.") - if config.general["custom_discord_hook"]: - send_discord(f"{config.general['name']} got stuck and can not resume", config.general["custom_discord_hook"]) + if config.general["custom_message_hook"]: + messenger.send(msg=f"{config.general['name']}: got stuck and can not resume") os._exit(1) def main(): diff --git a/src/messenger.py b/src/messenger.py new file mode 100644 index 0000000..9bbe52c --- /dev/null +++ b/src/messenger.py @@ -0,0 +1,44 @@ +from config import Config +import json +import requests + + +class Messenger: + def __init__(self): + self._config = Config() + + def send(self, msg): + if self._config.advanced_options['message_highlight']: + if " magic_" in msg: + msg = f"```ini\\n[ {msg} \\n```" + elif " set_" in msg: + msg = f"```diff\\n+ {msg} \\n```" + elif " rune_" in msg: + msg = f"```css\\n[ {msg} ]\\n```" + elif " uniq_" in msg or "rare" in msg: + # TODO: It is more gold than yellow, find a better yellow highlight + msg = f"```fix\\n- {msg} \\n```" + elif " eth_" in msg: + msg = f"```python\\n# {msg} \\n```" + else: + msg = f"```\\n{msg} \\n```" + + self._send(msg=msg) + + def _send(self, msg): + url = self._config.general['custom_message_hook'] + if not url: + return + + headers = {} + if self._config.advanced_options['message_headers']: + headers = json.loads(self._config.advanced_options['message_headers']) + + data = json.loads(self._config.advanced_options['message_body_template'].format(msg=msg), strict=False) + + requests.post(url, headers=headers, json=data) + + +if __name__ == "__main__": + messenger = Messenger() + messenger.send(msg=f" uniq_test") diff --git a/src/shop/anya.py b/src/shop/anya.py index f867ffc..09400e8 100644 --- a/src/shop/anya.py +++ b/src/shop/anya.py @@ -12,9 +12,11 @@ from logger import Logger from npc_manager import NpcManager, Npc from template_finder import TemplateFinder from utils.custom_mouse import mouse -from utils.misc import wait, load_template, send_discord +from utils.misc import wait, load_template import cv2 +from messenger import Messenger + def exit(run_obj): run_time = str(datetime.timedelta(seconds=round(time.time() - run_obj.start_time))) @@ -64,10 +66,11 @@ class AnyaShopper: self.trap_claw_min_score = self._config.shop["trap_min_score"] self.look_for_melee_claws = self._config.shop["shop_melee_claws"] self.melee_claw_min_score = self._config.shop["melee_min_score"] - - + + self._screen = Screen(config.general["monitor"]) self._template_finder = TemplateFinder(self._screen, ["assets\\templates", "assets\\npc", "assets\\shop"]) + self._messenger = Messenger() self._npc_manager = NpcManager( screen=self._screen, template_finder=self._template_finder ) @@ -126,7 +129,7 @@ class AnyaShopper: ) if gg_gloves.valid: mouse.click(button="right") - send_discord(f"Bought awesome IAS/+3 gloves!", self._config.general["custom_discord_hook"]) + self._messenger.send(msg=f"{self._config.general['name']}: Bought awesome IAS/+3 gloves!") Logger.info("IAS/+3 gloves bought!") self.gloves_bought += 1 time.sleep(1) @@ -143,7 +146,7 @@ class AnyaShopper: ) if g_gloves.valid: mouse.click(button="right") - send_discord(f"Bought some decent IAS/+2 gloves", self._config.general["custom_discord_hook"]) + self._messenger.send(msg=f"{self._config.general['name']}: Bought some decent IAS/+2 gloves") Logger.info("IAS/+2 gloves bought!") self.gloves_bought += 1 time.sleep(1) @@ -204,7 +207,7 @@ class AnyaShopper: if trap_score > self.trap_claw_min_score and self.look_for_trap_claws is True: # pick it up mouse.click(button="right") - send_discord(f"Bought some terrific trap Claws (score: {trap_score})", self._config.general["custom_discord_hook"]) + self._messenger.send(msg=f"{self._config.general['name']}: Bought some terrific trap Claws (score: {trap_score})") Logger.info(f"Trap Claws (score: {trap_score}) bought!") self.claws_bought += 1 time.sleep(1) @@ -212,7 +215,7 @@ class AnyaShopper: if melee_score > self.melee_claw_min_score and self.look_for_melee_claws is True: # pick it up mouse.click(button="right") - send_discord(f"Bought some mad melee Claws (score: {melee_score})", self._config.general["custom_discord_hook"]) + self._messenger.send(msg=f"{self._config.general['name']}: Bought some mad melee Claws (score: {melee_score})") Logger.info(f"Melee Claws (score: {melee_score}) bought!") self.claws_bought += 1 time.sleep(1) diff --git a/src/ui/ui_manager.py b/src/ui/ui_manager.py index 271fa81..3be2a4e 100644 --- a/src/ui/ui_manager.py +++ b/src/ui/ui_manager.py @@ -7,7 +7,7 @@ import os import numpy as np from utils.custom_mouse import mouse -from utils.misc import wait, cut_roi, color_filter, send_discord +from utils.misc import wait, cut_roi, color_filter from logger import Logger from config import Config @@ -15,6 +15,8 @@ from screen import Screen from item import ItemFinder from template_finder import TemplateFinder +from messenger import Messenger + class UiManager(): """Everything that is clicking on some static 2D UI or is checking anything in regard to it should be placed here.""" @@ -22,6 +24,7 @@ class UiManager(): def __init__(self, screen: Screen, template_finder: TemplateFinder): self._config = Config() self._template_finder = template_finder + self._messenger = Messenger() self._screen = screen self._curr_stash = {"items": 0, "gold": 0} #0: personal, 1: shared1, 2: shared2, 3: shared3 @@ -325,8 +328,8 @@ class UiManager(): if inventory_full_gold.valid: msg = "All stash tabs and character are full of gold, turn of gold pickup" Logger.info(msg) - if self._config.general["custom_discord_hook"]: - send_discord(f"{self._config.general['name']}: {msg}", self._config.general["custom_discord_hook"]) + if self._config.general["custom_message_hook"]: + self._messenger.send(msg=f"{self._config.general['name']}: {msg}") self._config.items["misc_gold"] = 0 item_finder.update_items_to_pick(self._config) else: @@ -392,8 +395,8 @@ class UiManager(): self._curr_stash["items"] += 1 if self._curr_stash["items"] > 3: Logger.error("All stash is full, quitting") - if self._config.general["custom_discord_hook"]: - send_discord(f"{self._config.general['name']} all stash is full, quitting", self._config.general["custom_discord_hook"]) + if self._config.general["custom_message_hook"]: + self._messenger.send(msg=f"{self._config.general['name']}: all stash is full, quitting") os._exit(1) else: # move to next stash diff --git a/src/utils/misc.py b/src/utils/misc.py index 66b3153..fdf659a 100644 --- a/src/utils/misc.py +++ b/src/utils/misc.py @@ -5,31 +5,9 @@ import numpy as np from logger import Logger import cv2 from typing import List, Tuple -import requests import os -from version import __version__ -def send_discord(msg, url: str, color_it: bool = False): - if not url: - return - msg = f"{msg} (v{__version__})" - if color_it: - if " magic_" in msg: - msg = f"```ini\n[ {msg} \n```" - elif " set_" in msg: - msg = f"```diff\n+ {msg} \n```" - elif " rune_" in msg: - msg = f"```css\n[ {msg} ]\n```" - elif " uniq_" in msg or "rare" in msg: - # TODO: It is more gold than yellow, find a better yellow highlight - msg = f"```fix\n- {msg} \n```" - elif " eth_" in msg: - msg = f"```python\n# {msg} \n```" - else: - msg = f"```\n {msg} \n```" - requests.post(url, json={"content": msg}) - def wait(min_seconds, max_seconds = None): if max_seconds is None: max_seconds = min_seconds