Fixes and fail saves (#44)
* remove old discord, add offset_left, fix coordinate clamping * proper bot thread
This commit is contained in:
@@ -50,7 +50,8 @@ run_shenk=0
|
||||
--------------------------------|---------------------------------------------
|
||||
monitor | Select on which monitor D2R is running in case multiple are available
|
||||
res | Resolution settings can be any of [1920_1080, 1280_720]
|
||||
offset_top | Your D2R window should always be in the top left corner. If you are on windowed mode you might have a window bar on top. Measure the pixel height of the bar and set the offset here.
|
||||
offset_top | Your D2R windows offset from top of the screen (including the window bar). For fullscreen leave at 0.
|
||||
offset_left | Your D2R window offset from left of screen. For fullscreen leave at 0.
|
||||
min_game_length_s | Games must have at least this length, will wait in hero selection for if game is too quick (to avoid server connection issues)
|
||||
exit_key | Pressing this key (anywhere), will force botty to shut down
|
||||
resume_key | After starting the exe botty will wait for this keypress to atually start botting away
|
||||
@@ -58,7 +59,6 @@ color_checker_key | Pressing this key will start a debug mode to check if the co
|
||||
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
|
||||
send_drops_to_discord | If 1 sends your drops to the discord channel "drop-log"
|
||||
custom_discord_hook | Add your own discord hook here to get messages about drops and in case botty got stuck and can not resume
|
||||
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...
|
||||
|
||||
+1
-1
@@ -2,6 +2,7 @@
|
||||
monitor=0
|
||||
res=1920_1080
|
||||
offset_top=0
|
||||
offset_left=0
|
||||
min_game_length_s=65
|
||||
resume_key=f11
|
||||
exit_key=f12
|
||||
@@ -10,7 +11,6 @@ color_checker_key=f10
|
||||
logg_lvl=info
|
||||
randomize_runs=0
|
||||
difficulty=hell
|
||||
send_drops_to_discord=1
|
||||
custom_discord_hook=
|
||||
info_screenshots=1
|
||||
loot_screenshots=0
|
||||
|
||||
+9
-1
@@ -81,6 +81,11 @@ class Bot:
|
||||
def start(self):
|
||||
self.trigger('create_game')
|
||||
|
||||
def current_game_length(self):
|
||||
if self._timer is None:
|
||||
return 0
|
||||
return time.time() - self._timer
|
||||
|
||||
def shuffle_runs(self):
|
||||
tmp = list(self._do_runs.items())
|
||||
random.shuffle(tmp)
|
||||
@@ -97,7 +102,10 @@ class Bot:
|
||||
def _shut_down(self):
|
||||
Logger.error("Something went wrong here, bot is unsure about current location. Closing down bot.")
|
||||
if self._config.general["custom_discord_hook"] != "":
|
||||
send_discord_thread = threading.Thread(target=send_discord, args=("Botty got stuck and can not resume", self._config.general["custom_discord_hook"]))
|
||||
send_discord_thread = threading.Thread(
|
||||
target=send_discord,
|
||||
args=("Botty got stuck and can not resume", self._config.general["custom_discord_hook"])
|
||||
)
|
||||
send_discord_thread.daemon = True
|
||||
send_discord_thread.start()
|
||||
self._ui_manager.save_and_exit()
|
||||
|
||||
+2
-1
@@ -69,7 +69,8 @@ class IChar:
|
||||
keyboard.send(self._char_config["tp"])
|
||||
wait(0.05, 0.1)
|
||||
mouse.click(button="right")
|
||||
mouse.move(120, 450, randomize=150, delay_factor=[0.8, 1.4])
|
||||
# TODO: Add hardcoded coordinates to ini file
|
||||
mouse.move(int(120 * self._config.scale), int(450 * self._config.scale), randomize=150, delay_factor=[0.8, 1.4])
|
||||
wait(0.8, 1.3) # takes quite a while for tp to be visible
|
||||
roi = self._config.ui_roi["tp_search"]
|
||||
start = time.time()
|
||||
|
||||
+18
-19
@@ -37,23 +37,25 @@ class Sorceress(IChar):
|
||||
if self._char_config["cta_available"]:
|
||||
self._pre_buff_cta()
|
||||
|
||||
def _left_attack(self, cast_pos: Tuple[float, float], delay: float, spray: int = 10):
|
||||
def _left_attack(self, cast_pos_abs: Tuple[float, float], delay: float, spray: int = 10):
|
||||
keyboard.send(self._char_config["stand_still"], do_release=False)
|
||||
mouse.move(cast_pos[0], cast_pos[1])
|
||||
keyboard.send(self._skill_hotkeys["skill_left"])
|
||||
if self._skill_hotkeys["skill_left"]:
|
||||
keyboard.send(self._skill_hotkeys["skill_left"])
|
||||
for _ in range(6):
|
||||
x = cast_pos[0] + (random.random() * 2*spray - spray)
|
||||
y = cast_pos[1] + (random.random() * 2*spray - spray)
|
||||
mouse.move(x, y)
|
||||
x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
|
||||
y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
|
||||
cast_pos_monitor = self._screen.convert_abs_to_monitor((x, y))
|
||||
mouse.move(*cast_pos_monitor)
|
||||
mouse.click(button="left")
|
||||
wait(delay[0], delay[1])
|
||||
keyboard.send(self._char_config["stand_still"], do_press=False)
|
||||
|
||||
def _main_attack(self, cast_pos: Tuple[float, float], delay: float, spray: float = 10):
|
||||
def _main_attack(self, cast_pos_abs: Tuple[float, float], delay: float, spray: float = 10):
|
||||
keyboard.send(self._skill_hotkeys["skill_right"])
|
||||
x = cast_pos[0] + (random.random() * 2*spray - spray)
|
||||
y = cast_pos[1] + (random.random() * 2*spray - spray)
|
||||
mouse.move(x, y)
|
||||
x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
|
||||
y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
|
||||
cast_pos_monitor = self._screen.convert_abs_to_monitor((x, y))
|
||||
mouse.move(*cast_pos_monitor)
|
||||
mouse.click(button="right")
|
||||
wait(delay[0], delay[1])
|
||||
|
||||
@@ -65,10 +67,9 @@ class Sorceress(IChar):
|
||||
pindle_pos_abs = self._pather.find_abs_node_pos(104, self._screen.grab())
|
||||
if pindle_pos_abs is not None:
|
||||
cast_pos_abs = [pindle_pos_abs[0] * 0.9, pindle_pos_abs[1] * 0.9]
|
||||
cast_pos_monitor = self._screen.convert_abs_to_monitor(cast_pos_abs)
|
||||
for _ in range(int(self._char_config["atk_len_pindle"])):
|
||||
self._main_attack(cast_pos_monitor, delay, 15)
|
||||
self._left_attack(cast_pos_monitor, delay, 15)
|
||||
self._main_attack(cast_pos_abs, delay, 15)
|
||||
self._left_attack(cast_pos_abs, delay, 15)
|
||||
wait(0.1, 0.15)
|
||||
# Move to items
|
||||
if self._config.char["static_path_pindle"]:
|
||||
@@ -83,10 +84,9 @@ class Sorceress(IChar):
|
||||
pos_abs = self._pather.find_abs_node_pos(123, self._screen.grab())
|
||||
if pos_abs is not None:
|
||||
cast_pos_abs = [pos_abs[0] * 0.9, pos_abs[1] * 0.9]
|
||||
cast_pos_monitor = self._screen.convert_abs_to_monitor(cast_pos_abs)
|
||||
for _ in range(int(self._char_config["atk_len_eldritch"])):
|
||||
self._main_attack(cast_pos_monitor, delay, 90)
|
||||
self._left_attack(cast_pos_monitor, delay, 90)
|
||||
self._main_attack(cast_pos_abs, delay, 90)
|
||||
self._left_attack(cast_pos_abs, delay, 90)
|
||||
wait(0.2, 0.3)
|
||||
# Move to items
|
||||
if self._config.char["static_path_eldritch"]:
|
||||
@@ -100,10 +100,9 @@ class Sorceress(IChar):
|
||||
delay = [0.2, 0.3]
|
||||
pos_abs = self._pather.find_abs_node_pos(149, self._screen.grab())
|
||||
cast_pos_abs = [pos_abs[0] * 0.9, pos_abs[1] * 0.9]
|
||||
cast_pos_monitor = self._screen.convert_abs_to_monitor(cast_pos_abs)
|
||||
for _ in range(int(self._char_config["atk_len_shenk"])):
|
||||
self._main_attack(cast_pos_monitor, delay, 90)
|
||||
self._left_attack(cast_pos_monitor, delay, 90)
|
||||
self._main_attack(cast_pos_abs, delay, 90)
|
||||
self._left_attack(cast_pos_abs, delay, 90)
|
||||
wait(0.2, 0.3)
|
||||
# Move to items
|
||||
self._pather.traverse_nodes(Location.SHENK_SAVE_DIST, Location.SHENK_END, self, time_out=2.0, force_tp=True)
|
||||
|
||||
+1
-1
@@ -28,6 +28,7 @@ class Config:
|
||||
"monitor": int(self._select_val("general", "monitor")),
|
||||
"res": self._select_val("general", "res"),
|
||||
"offset_top": int(self._select_val("general", "offset_top")),
|
||||
"offset_left": int(self._select_val("general", "offset_left")),
|
||||
"min_game_length_s": float(self._select_val("general", "min_game_length_s")),
|
||||
"exit_key": self._select_val("general", "exit_key"),
|
||||
"resume_key": self._select_val("general", "resume_key"),
|
||||
@@ -36,7 +37,6 @@ 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"),
|
||||
"send_drops_to_discord": bool(int(self._select_val("general", "send_drops_to_discord"))),
|
||||
"custom_discord_hook": self._select_val("general", "custom_discord_hook"),
|
||||
"info_screenshots": bool(int(self._select_val("general", "info_screenshots"))),
|
||||
"loot_screenshots": bool(int(self._select_val("general", "loot_screenshots"))),
|
||||
|
||||
@@ -3,7 +3,7 @@ from ui_manager import UiManager
|
||||
import cv2
|
||||
import time
|
||||
import keyboard
|
||||
from utils.misc import kill_thread, cut_roi, color_filter
|
||||
from utils.misc import kill_thread, cut_roi, color_filter, wait
|
||||
from logger import Logger
|
||||
from screen import Screen
|
||||
import numpy as np
|
||||
@@ -78,15 +78,16 @@ class HealthManager:
|
||||
return merc_health_percentage
|
||||
|
||||
def _do_chicken(self, img, run_thread):
|
||||
kill_thread(run_thread)
|
||||
if self._config.general["info_screenshots"]:
|
||||
cv2.imwrite("./info_screenshots/info_debug_chicken_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img)
|
||||
# clean up key presses that might be pressed in the run_thread
|
||||
keyboard.release(self._config.char["stand_still"])
|
||||
wait(0.02, 0.05)
|
||||
keyboard.release(self._config.char["show_items"])
|
||||
time.sleep(0.01)
|
||||
self._ui_manager.save_and_exit(does_chicken=True)
|
||||
self._did_chicken = True
|
||||
kill_thread(run_thread)
|
||||
self._do_monitor = False
|
||||
|
||||
def start_monitor(self, run_thread: Thread):
|
||||
|
||||
+4
-5
@@ -71,12 +71,11 @@ class PickIt:
|
||||
else:
|
||||
# send log to discord
|
||||
if found_items and self._config.items[closest_item.name] == 2 and closest_item.name not in picked_up_items:
|
||||
if self._config.general["send_drops_to_discord"]:
|
||||
send_discord_thread = threading.Thread(target=send_discord, args=(f"Botty just found: {closest_item.name}",))
|
||||
send_discord_thread.daemon = True
|
||||
send_discord_thread.start()
|
||||
if self._config.general["custom_discord_hook"] != "":
|
||||
send_discord_thread = threading.Thread(target=send_discord, args=(f"Botty just found: {closest_item.name}", self._config.general["custom_discord_hook"]))
|
||||
send_discord_thread = threading.Thread(
|
||||
target=send_discord,
|
||||
args=(f"Botty just found: {closest_item.name}", self._config.general["custom_discord_hook"])
|
||||
)
|
||||
send_discord_thread.daemon = True
|
||||
send_discord_thread.start()
|
||||
picked_up_items.append(closest_item.name)
|
||||
|
||||
+5
-4
@@ -12,9 +12,8 @@ import time
|
||||
import logging
|
||||
|
||||
|
||||
def start_bot():
|
||||
def start_bot(bot):
|
||||
try:
|
||||
bot = Bot()
|
||||
bot.start()
|
||||
except KeyboardInterrupt:
|
||||
Logger.info('Exit (ctrl+c)') or exit()
|
||||
@@ -45,8 +44,9 @@ if __name__ == "__main__":
|
||||
|
||||
while 1:
|
||||
if keyboard.is_pressed(config.general['resume_key']):
|
||||
start_bot()
|
||||
break
|
||||
bot = Bot()
|
||||
bot_thread = threading.Thread(target=start_bot, args=(bot,))
|
||||
bot_thread.start()
|
||||
if keyboard.is_pressed(config.general['auto_settings_key']):
|
||||
adjust_settings()
|
||||
elif keyboard.is_pressed(config.general['color_checker_key']):
|
||||
@@ -54,5 +54,6 @@ if __name__ == "__main__":
|
||||
break
|
||||
time.sleep(0.02)
|
||||
|
||||
bot_thread.join()
|
||||
print("Press Enter to exit ...")
|
||||
input()
|
||||
|
||||
+3
-2
@@ -24,10 +24,11 @@ class Screen:
|
||||
self._monitor_roi = self._sct.monitors[monitor_idx]
|
||||
# For windowed screens it is expected to always have them at the top left edge and adjust offset_top then
|
||||
self._monitor_roi["top"] += config.general["offset_top"]
|
||||
self._monitor_roi["left"] += config.general["offset_left"]
|
||||
self._monitor_roi["width"] = config.ui_pos["screen_width"]
|
||||
self._monitor_roi["height"] = config.ui_pos["screen_height"]
|
||||
self._monitor_x_range = (self._monitor_roi["left"] + 2, self._monitor_roi["left"] + self._monitor_roi["width"] - 2)
|
||||
self._monitor_y_range = (self._monitor_roi["top"] + 2, self._monitor_roi["top"] + self._monitor_roi["height"] - 2)
|
||||
self._monitor_x_range = (self._monitor_roi["left"] + 10, self._monitor_roi["left"] + self._monitor_roi["width"] - 10)
|
||||
self._monitor_y_range = (self._monitor_roi["top"] + 10, self._monitor_roi["top"] + self._monitor_roi["height"] - 10)
|
||||
|
||||
def convert_monitor_to_screen(self, screen_coord: Tuple[float, float]) -> Tuple[float, float]:
|
||||
return (screen_coord[0] - self._monitor_roi["left"], screen_coord[1] - self._monitor_roi["top"])
|
||||
|
||||
+7
-6
@@ -10,7 +10,7 @@ import itertools
|
||||
import os
|
||||
import numpy as np
|
||||
from logger import Logger
|
||||
from utils.misc import wait, cut_roi, color_filter, send_discord
|
||||
from utils.misc import wait, cut_roi, color_filter
|
||||
from config import Config
|
||||
|
||||
class UiManager():
|
||||
@@ -135,13 +135,14 @@ class UiManager():
|
||||
wait(0.1)
|
||||
exit_btn_pos = (self._config.ui_pos["save_and_exit_x"], self._config.ui_pos["save_and_exit_y"])
|
||||
x_m, y_m = self._screen.convert_screen_to_monitor(exit_btn_pos)
|
||||
away_x_m, away_y_m = self._screen.convert_screen_to_monitor((200, 450))
|
||||
# TODO: Add hardcoded coordinates to ini file
|
||||
away_x_m, away_y_m = self._screen.convert_screen_to_monitor((int(170 * self._config.scale), int(400 * self._config.scale)))
|
||||
templates = ["SAVE_AND_EXIT_NO_HIGHLIGHT","SAVE_AND_EXIT_HIGHLIGHT"]
|
||||
while self._template_finder.search_and_wait(templates, roi=self._config.ui_roi["save_and_exit"], time_out=1.5, take_ss=False)[0]:
|
||||
delay = [0.9, 1.1]
|
||||
if does_chicken:
|
||||
delay = [0.3, 0.4]
|
||||
mouse.move(x_m, y_m, randomize=[60, 10], delay_factor=delay)
|
||||
mouse.move(x_m, y_m, randomize=[38, 7], delay_factor=delay)
|
||||
wait(0.03, 0.06)
|
||||
mouse.click(button="left")
|
||||
if does_chicken:
|
||||
@@ -149,7 +150,7 @@ class UiManager():
|
||||
wait(0.05, 0.08)
|
||||
mouse.click(button="left")
|
||||
wait(0.1, 0.2)
|
||||
mouse.move(away_x_m, away_y_m, randomize=100, delay_factor=[0.6, 0.9])
|
||||
mouse.move(away_x_m, away_y_m, randomize=60, delay_factor=[0.6, 0.9])
|
||||
wait(0.1, 0.5)
|
||||
return True
|
||||
return False
|
||||
@@ -177,7 +178,7 @@ class UiManager():
|
||||
Logger.debug(f"Found Play Btn ({mode_info}) -> clicking it")
|
||||
if mode_info == "online":
|
||||
Logger.warning("You are creating a game in online mode!")
|
||||
mouse.move(x, y, randomize=[50, 15], delay_factor=[1.0, 1.8])
|
||||
mouse.move(x, y, randomize=[50, 9], delay_factor=[1.0, 1.8])
|
||||
wait(0.1, 0.15)
|
||||
mouse.click(button="left")
|
||||
break
|
||||
@@ -200,7 +201,7 @@ class UiManager():
|
||||
|
||||
x, y = self._screen.convert_screen_to_monitor((self._config.ui_pos[f"{difficulty}_x"], self._config.ui_pos[f"{difficulty}_y"]))
|
||||
Logger.debug(f"Found {difficulty} Btn -> clicking it")
|
||||
mouse.move(x, y, randomize=[50, 15], delay_factor=[1.0, 1.8])
|
||||
mouse.move(x, y, randomize=[50, 9], delay_factor=[1.0, 1.8])
|
||||
wait(0.15, 0.2)
|
||||
mouse.click(button="left")
|
||||
break
|
||||
|
||||
+3
-3
@@ -9,9 +9,9 @@ import subprocess
|
||||
from version import __version__
|
||||
|
||||
|
||||
def send_discord(msg, url:str = None):
|
||||
if url is None:
|
||||
url = "https://discord.com/api/webhooks/908071105372250213/puaS6gIYqYxTE-TBLAIs6_Qb6ZUwuygSeQfTQkpuXrSag5DPeV2gk0SctOjPy5qMHGeh"
|
||||
def send_discord(msg, url: str):
|
||||
if not url:
|
||||
return
|
||||
data = {"content": f"{msg} (v{__version__})"}
|
||||
requests.post(url, json=data)
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = '0.2.2'
|
||||
__version__ = '0.2.2-dev'
|
||||
|
||||
Reference in New Issue
Block a user