publish eve_orehold_watcher.py

This commit is contained in:
brockdarnold 2026-06-15 02:56:08 +00:00
parent 6545b6ca3f
commit 3476f9a4a3

View file

@ -293,13 +293,77 @@ def parse_orehold_text(text):
return cur, cap return cur, cap
def capture_window(cls="triuiScreen"):
"""Capture the EVE client window via PrintWindow — gets EVE's pixels even when it's
behind Discord/unfocused/moved (no overlap, no screen-position dependence). Returns a
PIL Image (window-relative, e.g. 3840x2160) or None. Frees GDI handles each call."""
if os.name != "nt":
return None
import ctypes
import ctypes.wintypes as wt
from PIL import Image
u = ctypes.windll.user32
g = ctypes.windll.gdi32
try:
u.SetProcessDPIAware()
except Exception:
pass
hwnd = u.FindWindowW(cls, None)
if not hwnd:
res = []
@ctypes.WINFUNCTYPE(ctypes.c_bool, wt.HWND, wt.LPARAM)
def _cb(h, _l):
n = u.GetWindowTextLengthW(h)
if n:
b = ctypes.create_unicode_buffer(n + 1)
u.GetWindowTextW(h, b, n + 1)
if b.value.startswith("EVE -"):
res.append(h)
return True
u.EnumWindows(_cb, 0)
hwnd = res[0] if res else 0
if not hwnd:
return None
r = wt.RECT()
u.GetClientRect(hwnd, ctypes.byref(r))
w, h = r.right, r.bottom
if w <= 0 or h <= 0:
return None
hdc = u.GetDC(hwnd)
mdc = g.CreateCompatibleDC(hdc)
bmp = g.CreateCompatibleBitmap(hdc, w, h)
g.SelectObject(mdc, bmp)
u.PrintWindow(hwnd, mdc, 2) # PW_RENDERFULLCONTENT (works for DX windows)
class BMIH(ctypes.Structure):
_fields_ = [("biSize", wt.DWORD), ("biWidth", ctypes.c_long), ("biHeight", ctypes.c_long),
("biPlanes", wt.WORD), ("biBitCount", wt.WORD), ("biCompression", wt.DWORD),
("biSizeImage", wt.DWORD), ("p1", ctypes.c_long), ("p2", ctypes.c_long),
("p3", wt.DWORD), ("p4", wt.DWORD)]
bmi = BMIH()
bmi.biSize = ctypes.sizeof(BMIH); bmi.biWidth = w; bmi.biHeight = -h
bmi.biPlanes = 1; bmi.biBitCount = 32; bmi.biCompression = 0
buf = ctypes.create_string_buffer(w * h * 4)
g.GetDIBits(mdc, bmp, 0, h, buf, ctypes.byref(bmi), 0)
img = Image.frombuffer("RGB", (w, h), buf, "raw", "BGRX", 0, 1)
g.DeleteObject(bmp); g.DeleteDC(mdc); u.ReleaseDC(hwnd, hdc) # avoid GDI leak
return img
def grab_region(region): def grab_region(region):
"""Crop a WINDOW-RELATIVE region from the EVE window capture (occlusion-proof).
Falls back to absolute-screen grab if the EVE window can't be found."""
img = capture_window()
if img is not None:
l, t, ww, hh = region
return img.crop((l, t, l + ww, t + hh))
import mss import mss
from PIL import Image from PIL import Image
left, top, width, height = region left, top, width, height = region
with mss.mss() as sct: with mss.mss() as sct:
raw = sct.grab({"left": left, "top": top, "width": width, raw = sct.grab({"left": left, "top": top, "width": width, "height": height})
"height": height})
return Image.frombytes("RGB", raw.size, raw.bgra, "raw", "BGRX") return Image.frombytes("RGB", raw.size, raw.bgra, "raw", "BGRX")
@ -347,24 +411,13 @@ def _detect_readout(cp, img, mon_left=0, mon_top=0, save=True, scale=1):
def auto_region(cp): def auto_region(cp):
"""Scan the whole screen for the ore-hold readout and save its location — """Find the ore-hold 'X / Y m³' readout WITHIN the EVE window capture (clean,
replaces the manual --snip. Just have the in-game Ore Hold window open.""" occlusion-proof). Returns a WINDOW-RELATIVE region. Have the Ore Hold window open."""
import mss img = capture_window()
from PIL import Image if img is None:
try:
with mss.mss() as sct:
mon = sct.monitors[0] # full virtual desktop (all screens)
raw = sct.grab(mon)
img = Image.frombytes("RGB", raw.size, raw.bgra, "raw", "BGRX")
# crop the center band (where EVE sits) then upscale, so small m³ text is readable
W, Hh = img.size
cx0, cy0 = int(W * 0.22), 0
crop = img.crop((cx0, cy0, int(W * 0.82), int(Hh * 0.97)))
up = crop.resize((crop.width * 2, crop.height * 2))
except Exception as e:
print(f"[ocr] auto-detect error: {e}")
return None return None
return _detect_readout(cp, up, mon["left"] + cx0, mon["top"] + cy0, scale=2) up = img.resize((img.width * 2, img.height * 2)) # upscale so small m³ text reads
return _detect_readout(cp, up, 0, 0, scale=2) # window-relative (origin 0,0)
def run_ocr(cp): def run_ocr(cp):