Skip to content

Commit

Permalink
switched back to mss, much faster performance, still debugging resolu…
Browse files Browse the repository at this point in the history
…tion change errors
  • Loading branch information
tanjeffreyz committed May 28, 2022
1 parent b3f5af3 commit d1dc0b0
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 79 deletions.
6 changes: 4 additions & 2 deletions src/modules/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
178 changes: 101 additions & 77 deletions src/modules/capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)

0 comments on commit d1dc0b0

Please sign in to comment.