From d1dc0b08a5c1648c064ed0bb51b79ec9a27d0b04 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Sat, 28 May 2022 15:58:13 -0700 Subject: [PATCH] switched back to mss, much faster performance, still debugging resolution change errors --- src/modules/bot.py | 6 +- src/modules/capture.py | 178 +++++++++++++++++++++++------------------ 2 files changed, 105 insertions(+), 79 deletions(-) diff --git a/src/modules/bot.py b/src/modules/bot.py index a4b891b9..baeccde5 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -143,8 +143,10 @@ def _solve_rune(self, model): threshold=0.9) if rune_buff: rune_buff_pos = min(rune_buff, key=lambda p: p[0]) - target = tuple(round(rune_buff_pos[i] + config.capture.window[i]) - for i in range(2)) + target = ( + round(rune_buff_pos[0] + config.capture.window['left']), + round(rune_buff_pos[1] + config.capture.window['top']) + ) click(target, button='right') self.rune_active = False break diff --git a/src/modules/capture.py b/src/modules/capture.py index 21cf4016..e3ff130f 100644 --- a/src/modules/capture.py +++ b/src/modules/capture.py @@ -4,10 +4,12 @@ import cv2 import threading import ctypes +import mss +import mss.windows import numpy as np from src.common import config, utils from ctypes import wintypes -from PIL import ImageGrab +# from PIL import ImageGrab user32 = ctypes.windll.user32 user32.SetProcessDPIAware() @@ -16,7 +18,7 @@ MINIMAP_TOP_BORDER = 5 # The thickness of the other three borders of the minimap -MINIMAP_BOTTOM_BORDER = 8 +MINIMAP_BOTTOM_BORDER = 9 # Offset in pixels to adjust for windowed mode WINDOWED_OFFSET_TOP = 36 @@ -50,8 +52,14 @@ def __init__(self): self.minimap = {} self.minimap_ratio = 1 self.minimap_sample = None - self.window = (0, 0, 1366, 768) - self.scale = 1.0 + self.sct = None + # self.window = (0, 0, 1366, 768) + self.window = { + 'left': 0, + 'top': 0, + 'width': 1366, + 'height': 768 + } self.ready = False self.calibrated = False @@ -67,81 +75,97 @@ def start(self): def _main(self): """Constantly monitors the player's position and in-game events.""" - while True: - if not self.calibrated: - handle = user32.FindWindowW(None, 'MapleStory') - rect = wintypes.RECT() - user32.GetWindowRect(handle, ctypes.pointer(rect)) - rect = (rect.left, rect.top, rect.right, rect.bottom) - rect = tuple(max(0, x) for x in rect) - - # Preliminary window to template match minimap - self.scale = ctypes.windll.shcore.GetScaleFactorForDevice(0) / 100 - self.window = ( - rect[0], - rect[1], - max(rect[2], rect[0] + MMT_WIDTH), # Make room for minimap templates - max(rect[3], rect[1] + MMT_HEIGHT) - ) - - # Calibrate by finding the bottom right corner of the minimap + mss.windows.CAPTUREBLT = 0 + with mss.mss() as self.sct: + while True: + if not self.calibrated: + handle = user32.FindWindowW(None, 'MapleStory') + rect = wintypes.RECT() + user32.GetWindowRect(handle, ctypes.pointer(rect)) + rect = (rect.left, rect.top, rect.right, rect.bottom) + rect = tuple(max(0, x) for x in rect) + + # Preliminary window to template match minimap + # self.window = ( + # rect[0], + # rect[1], + # max(rect[2], rect[0] + MMT_WIDTH), # Make room for minimap templates + # max(rect[3], rect[1] + MMT_HEIGHT) + # ) + self.window['left'] = rect[0] + self.window['top'] = rect[1] + self.window['width'] = max(rect[2] - rect[0], MMT_WIDTH) + self.window['height'] = max(rect[3] - rect[1], MMT_HEIGHT) + + # Calibrate by finding the bottom right corner of the minimap + self.frame = self.screenshot() + if self.frame is None: + continue + # self.frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR) + tl, _ = utils.single_match(self.frame, MM_TL_TEMPLATE) + _, br = utils.single_match(self.frame, MM_BR_TEMPLATE) + mm_tl = ( + tl[0] + MINIMAP_BOTTOM_BORDER, + tl[1] + MINIMAP_TOP_BORDER + ) + mm_br = ( + max(mm_tl[0] + PT_WIDTH, br[0] - MINIMAP_BOTTOM_BORDER), + max(mm_tl[1] + PT_HEIGHT, br[1] - MINIMAP_BOTTOM_BORDER) + ) + + # Resize window to encompass minimap if needed + # self.window = ( + # rect[0], + # rect[1], + # max(rect[2], mm_br[0]), + # max(rect[3], mm_br[1]) + # ) + + self.minimap_ratio = (mm_br[0] - mm_tl[0]) / (mm_br[1] - mm_tl[1]) + self.minimap_sample = self.frame[mm_tl[1]:mm_br[1], mm_tl[0]:mm_br[0]] + self.calibrated = True + + # Take screenshot self.frame = self.screenshot() if self.frame is None: continue - self.frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR) - tl, _ = utils.single_match(self.frame, MM_TL_TEMPLATE) - _, br = utils.single_match(self.frame, MM_BR_TEMPLATE) - mm_tl = ( - tl[0] + MINIMAP_BOTTOM_BORDER, - tl[1] + MINIMAP_TOP_BORDER - ) - mm_br = ( - max(mm_tl[0] + PT_WIDTH, br[0] - MINIMAP_BOTTOM_BORDER), - max(mm_tl[1] + PT_HEIGHT, br[1] - MINIMAP_BOTTOM_BORDER - 1) - ) - - # Resize window to encompass minimap if needed - self.window = ( - rect[0], - rect[1], - max(rect[2], mm_br[0]), - max(rect[3], mm_br[1]) - ) - self.minimap_ratio = (mm_br[0] - mm_tl[0]) / (mm_br[1] - mm_tl[1]) - self.minimap_sample = self.frame[mm_tl[1]:mm_br[1], mm_tl[0]:mm_br[0]] - self.calibrated = True - - # Take screenshot - self.frame = self.screenshot() - if self.frame is None: - continue - self.frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR) - - # Crop the frame to only show the minimap - minimap = self.frame[mm_tl[1]:mm_br[1], mm_tl[0]:mm_br[0]] - - # Determine the player's position - player = utils.multi_match(minimap, PLAYER_TEMPLATE, threshold=0.8) - if player: - config.player_pos = utils.convert_to_relative(player[0], minimap) - - # Package display information to be polled by GUI - self.minimap = { - 'minimap': minimap, - 'rune_active': config.bot.rune_active, - 'rune_pos': config.bot.rune_pos, - 'path': config.path, - 'player_pos': config.player_pos - } - - if not self.ready: - self.ready = True - time.sleep(0.001) + # self.frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR) + + # Crop the frame to only show the minimap + minimap = self.frame[mm_tl[1]:mm_br[1], mm_tl[0]:mm_br[0]] + + # Determine the player's position + player = utils.multi_match(minimap, PLAYER_TEMPLATE, threshold=0.8) + if player: + config.player_pos = utils.convert_to_relative(player[0], minimap) + + # Package display information to be polled by GUI + self.minimap = { + 'minimap': minimap, + 'rune_active': config.bot.rune_active, + 'rune_pos': config.bot.rune_pos, + 'path': config.path, + 'player_pos': config.player_pos + } + + if not self.ready: + self.ready = True + time.sleep(0.001) + + # def screenshot(self, delay=1): + # try: + # return np.array(ImageGrab.grab(self.window)) + # except OSError: + # print(f'\n[!] Error while taking screenshot, retrying in {delay} second' + # + ('s' if delay != 1 else '')) + # time.sleep(delay) def screenshot(self, delay=1): - try: - return np.array(ImageGrab.grab(self.window)) - except OSError: - print(f'\n[!] Error while taking screenshot, retrying in {delay} second' - + ('s' if delay != 1 else '')) - time.sleep(delay) + if self.sct is not None: + try: + return np.array(self.sct.grab(self.window)) + except mss.exception.ScreenShotError: + print(f'\n[!] Error while taking screenshot, retrying in {delay} second' + + ('s' if delay != 1 else '')) + print(self.window) + time.sleep(delay)