publish eve_rock_watcher.py

This commit is contained in:
brockdarnold 2026-06-15 00:54:40 +00:00
parent b3843f5de4
commit 5beca84cde

View file

@ -66,14 +66,67 @@ def parse_survey(text):
return rows 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"): if not cp.has_section("rock"):
cp.add_section("rock") cp.add_section("rock")
cp["rock"]["region"] = f"{l},{t},{wd},{ht}" 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: with open(w.CONFIG_PATH, "w") as f:
cp.write(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): def detect_survey_region(cp):
"""Find the Survey Scanner Results window by locating >=2 'ore name + number' rows.""" """Find the Survey Scanner Results window by locating >=2 'ore name + number' rows."""
import mss import mss
@ -163,11 +216,28 @@ class Tracker:
def get_region(cp): def get_region(cp):
region_s = cp.get("rock", "region", fallback="").strip() if cp.has_section("rock") else "" """Return (region, mode). mode = 'survey' (scanner rows) or 'selected' (Selected Item)."""
if region_s: if cp.has_section("rock"):
return [int(x) for x in region_s.split(",")] rs = cp.get("rock", "region", fallback="").strip()
print("[rock] no saved region — auto-detecting the Survey Scanner Results window...") if rs:
return detect_survey_region(cp) 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(): def main():
@ -191,13 +261,12 @@ def main():
tcmd = cp.get("ocr", "tesseract_cmd", fallback="").strip() tcmd = cp.get("ocr", "tesseract_cmd", fallback="").strip()
if tcmd: if tcmd:
pytesseract.pytesseract.tesseract_cmd = tcmd pytesseract.pytesseract.tesseract_cmd = tcmd
region = get_region(cp) region, mode = get_region(cp)
if not region: if not region:
print("Couldn't find the survey window. Open it (with rocks scanned) and retry, " print("Couldn't find a Survey Scanner window or a Selected-Item 'Quantity N "
"or run --snip.") "Units'. Select a rock (or open the survey results) and retry.")
return return
text = pytesseract.image_to_string(w.grab_region(region)) print(f"mode={mode} rows:", read_rows(cp, region, mode))
print("rows:", parse_survey(text))
return return
import pytesseract import pytesseract
@ -209,22 +278,22 @@ def main():
tracker = Tracker() tracker = Tracker()
last_alert = {} last_alert = {}
last_status = 0.0 last_status = 0.0
region = None region = mode = None
while True: while True:
if not w.bot_mining(cp): # only during a mining session if not w.bot_mining(cp): # only during a mining session
tracker.h.clear() tracker.h.clear()
time.sleep(15) time.sleep(15)
continue continue
if region is None: if region is None:
region = get_region(cp) region, mode = get_region(cp)
if region is None: 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)) time.sleep(max(poll, 15))
continue continue
w.heartbeat(cp, "rock") w.heartbeat(cp, "rock")
try: try:
text = pytesseract.image_to_string(w.grab_region(region)) rows = read_rows(cp, region, mode)
rows = parse_survey(text)
if not rows: if not rows:
region = None # lost it; re-detect next loop region = None # lost it; re-detect next loop
time.sleep(poll) time.sleep(poll)