From 5beca84cdeba326b2acb73e2345ad91af9331194 Mon Sep 17 00:00:00 2001 From: brockdarnold Date: Mon, 15 Jun 2026 00:54:40 +0000 Subject: [PATCH] publish eve_rock_watcher.py --- eve_rock_watcher.py | 101 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 16 deletions(-) diff --git a/eve_rock_watcher.py b/eve_rock_watcher.py index 5332e21..51c391a 100644 --- a/eve_rock_watcher.py +++ b/eve_rock_watcher.py @@ -66,14 +66,67 @@ def parse_survey(text): return rows -def save_rock_region(cp, l, t, wd, ht): +# Selected-Item panel (no survey scanner needed): "Quantity 5,593 Units" +QTY_RE = re.compile(r"quantit\w*\s*([\d.,]{2,})\s*units?", re.I) + + +def parse_selected(text): + """The selected asteroid's remaining units from its info panel, or None.""" + m = QTY_RE.search(text.replace("\n", " ")) + if not m: + return None + digits = re.sub(r"\D", "", m.group(1)) # tolerate OCR , vs . in the number + return int(digits) if digits else None + + +def save_rock_region(cp, l, t, wd, ht, mode="survey"): if not cp.has_section("rock"): cp.add_section("rock") cp["rock"]["region"] = f"{l},{t},{wd},{ht}" + cp["rock"]["mode"] = mode # 'survey' rows or 'selected' item with open(w.CONFIG_PATH, "w") as f: cp.write(f) +def detect_selected_region(cp): + """Find the Selected Item panel by locating its 'Quantity N Units' line.""" + import mss + import pytesseract + from PIL import Image + tcmd = cp.get("ocr", "tesseract_cmd", fallback="").strip() + if tcmd: + pytesseract.pytesseract.tesseract_cmd = tcmd + try: + with mss.mss() as sct: + mon = sct.monitors[0] + raw = sct.grab(mon) + img = Image.frombytes("RGB", raw.size, raw.bgra, "raw", "BGRX") + data = pytesseract.image_to_data(img, output_type=pytesseract.Output.DICT) + except Exception as e: + print(f"[rock] detect error: {e}") + return None + lines = {} + for i in range(len(data["text"])): + if not data["text"][i].strip(): + continue + k = (data["block_num"][i], data["par_num"][i], data["line_num"][i]) + lines.setdefault(k, []).append(i) + for idxs in lines.values(): + joined = " ".join(data["text"][i] for i in idxs) + if QTY_RE.search(joined): + xs = [data["left"][i] for i in idxs] + ys = [data["top"][i] for i in idxs] + rs = [data["left"][i] + data["width"][i] for i in idxs] + bs = [data["top"][i] + data["height"][i] for i in idxs] + pad = 10 + region = [mon["left"] + min(xs) - pad, mon["top"] + min(ys) - pad, + (max(rs) - min(xs)) + 2 * pad, (max(bs) - min(ys)) + 2 * pad] + save_rock_region(cp, *region, mode="selected") + print(f"[rock] auto-detected Selected-Item quantity -> {region}") + return region + return None + + def detect_survey_region(cp): """Find the Survey Scanner Results window by locating >=2 'ore name + number' rows.""" import mss @@ -163,11 +216,28 @@ class Tracker: def get_region(cp): - region_s = cp.get("rock", "region", fallback="").strip() if cp.has_section("rock") else "" - if region_s: - return [int(x) for x in region_s.split(",")] - print("[rock] no saved region — auto-detecting the Survey Scanner Results window...") - return detect_survey_region(cp) + """Return (region, mode). mode = 'survey' (scanner rows) or 'selected' (Selected Item).""" + if cp.has_section("rock"): + rs = cp.get("rock", "region", fallback="").strip() + if rs: + return [int(x) for x in rs.split(",")], cp.get("rock", "mode", fallback="survey") + print("[rock] no saved region — looking for a Survey Scanner window, else Selected Item...") + r = detect_survey_region(cp) + if r: + return r, "survey" + r = detect_selected_region(cp) + if r: + return r, "selected" + return None, None + + +def read_rows(cp, region, mode): + import pytesseract + text = pytesseract.image_to_string(w.grab_region(region)) + if mode == "selected": + q = parse_selected(text) + return [("rock", q)] if q else [] + return parse_survey(text) def main(): @@ -191,13 +261,12 @@ def main(): tcmd = cp.get("ocr", "tesseract_cmd", fallback="").strip() if tcmd: pytesseract.pytesseract.tesseract_cmd = tcmd - region = get_region(cp) + region, mode = get_region(cp) if not region: - print("Couldn't find the survey window. Open it (with rocks scanned) and retry, " - "or run --snip.") + print("Couldn't find a Survey Scanner window or a Selected-Item 'Quantity N " + "Units'. Select a rock (or open the survey results) and retry.") return - text = pytesseract.image_to_string(w.grab_region(region)) - print("rows:", parse_survey(text)) + print(f"mode={mode} rows:", read_rows(cp, region, mode)) return import pytesseract @@ -209,22 +278,22 @@ def main(): tracker = Tracker() last_alert = {} last_status = 0.0 - region = None + region = mode = None while True: if not w.bot_mining(cp): # only during a mining session tracker.h.clear() time.sleep(15) continue if region is None: - region = get_region(cp) + region, mode = get_region(cp) if region is None: - print("[rock] survey window not visible — open it (rocks scanned). Retrying...") + print("[rock] no survey window / selected rock visible — select a rock. " + "Retrying...") time.sleep(max(poll, 15)) continue w.heartbeat(cp, "rock") try: - text = pytesseract.image_to_string(w.grab_region(region)) - rows = parse_survey(text) + rows = read_rows(cp, region, mode) if not rows: region = None # lost it; re-detect next loop time.sleep(poll)