diff --git a/.gitignore b/.gitignore
index a4d6d9c..f417792 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-.vs/
\ No newline at end of file
+.vs/
+Borealis-Workflow-Automation-Tool/
\ No newline at end of file
diff --git a/Data/Modules/data_collector.py b/Data/Modules/data_collector.py
index 99eb4f0..50ef5fd 100644
--- a/Data/Modules/data_collector.py
+++ b/Data/Modules/data_collector.py
@@ -35,7 +35,6 @@ regions = {}
app_instance = None
-
def _ensure_qapplication():
"""
Ensures that QApplication is initialized before creating widgets.
@@ -45,6 +44,15 @@ def _ensure_qapplication():
if app_instance is None:
app_instance = QApplication(sys.argv) # Start in main thread
+def capture_region_as_image(region_id):
+ collector_mutex.lock()
+ if region_id not in regions:
+ collector_mutex.unlock()
+ return None
+ x, y, w, h = regions[region_id]['bbox'][:]
+ collector_mutex.unlock()
+ screenshot = ImageGrab.grab(bbox=(x, y, x + w, y + h))
+ return screenshot
def create_ocr_region(region_id, x=250, y=50, w=DEFAULT_WIDTH, h=DEFAULT_HEIGHT, color=(255, 255, 0), thickness=2):
"""
diff --git a/Data/Modules/data_manager.py b/Data/Modules/data_manager.py
index b07b4a5..53732db 100644
--- a/Data/Modules/data_manager.py
+++ b/Data/Modules/data_manager.py
@@ -1,7 +1,7 @@
-# Modules/data_manager.py
import threading
import time
-from flask import Flask, jsonify
+import base64
+from flask import Flask, jsonify, Response
from PyQt5.QtCore import QMutex
# Global datastore for character metrics
@@ -21,6 +21,9 @@ data_mutex = QMutex()
# Flag to ensure only one character status collector node exists
character_status_collector_exists = False
+# A place to store the screenshot in base64
+status_screenshot_base64 = ""
+
# Flask Application
app = Flask(__name__)
@@ -68,6 +71,47 @@ def fp_api():
"fp_total": get_data()["fp_total"]
})
+@app.route('/status_screenshot')
+def status_screenshot():
+ """
+ Returns an HTML page that displays the stored screenshot and
+ automatically refreshes it every second without requiring a manual page reload.
+ """
+ html = """
+
+
+ Live Flyff Character Status
+
+
+
+
+
+
+ """
+ return html
+
+@app.route('/status_screenshot_data')
+def status_screenshot_data():
+ """
+ Serves the raw PNG bytes (decoded from base64) used by
in /status_screenshot.
+ """
+ data_mutex.lock()
+ encoded = status_screenshot_base64
+ data_mutex.unlock()
+
+ if not encoded:
+ # No image captured yet, return HTTP 204 "No Content"
+ return "", 204
+
+ raw_img = base64.b64decode(encoded)
+ return Response(raw_img, mimetype='image/png')
+
def start_api_server():
"""
Starts the Flask API server in a separate daemon thread.
@@ -101,3 +145,12 @@ def set_data_bulk(metrics_dict):
data_mutex.lock()
data_store.update(metrics_dict)
data_mutex.unlock()
+
+def set_status_screenshot(encoded_str):
+ """
+ Called by the OCR node to store the base64-encoded screenshot data.
+ """
+ global status_screenshot_base64
+ data_mutex.lock()
+ status_screenshot_base64 = encoded_str
+ data_mutex.unlock()
diff --git a/Data/Nodes/Flyff/flyff_character_status_node.py b/Data/Nodes/Flyff/flyff_character_status_node.py
index 184f9dc..fc331d6 100644
--- a/Data/Nodes/Flyff/flyff_character_status_node.py
+++ b/Data/Nodes/Flyff/flyff_character_status_node.py
@@ -3,12 +3,19 @@
Flyff Character Status Node:
- Creates an OCR region in data_collector.
- Periodically grabs raw text from that region and updates status.
+- ALSO: Captures a screenshot from the same region, converts to base64,
+ and updates data_manager so the Flask server can serve it.
"""
import re
+import base64
+from io import BytesIO
+
from OdenGraphQt import BaseNode
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtCore import QTimer # Corrected import
+
+# Import the existing modules
from Modules import data_manager, data_collector
class FlyffCharacterStatusNode(BaseNode):
@@ -29,7 +36,10 @@ class FlyffCharacterStatusNode(BaseNode):
self.add_text_input("exp", "EXP", text="EXP: 0%")
self.region_id = "character_status"
- data_collector.create_ocr_region(self.region_id, x=250, y=50, w=180, h=130, color=(255, 255, 0), thickness=2)
+ data_collector.create_ocr_region(
+ self.region_id, x=250, y=50, w=180, h=130,
+ color=(255, 255, 0), thickness=2
+ )
data_collector.start_collector()
self.set_name("Flyff - Character Status")
@@ -80,14 +90,14 @@ class FlyffCharacterStatusNode(BaseNode):
def process_input(self):
"""
- Called periodically to update character status from OCR.
+ Called periodically to update character status from OCR,
+ and also capture the screenshot to display via Flask.
"""
+ # 1) Update the text-based status (same as before).
raw_text = data_collector.get_raw_text(self.region_id)
-# print("Raw OCR Text:", raw_text) # Debugging OCR text reading
-
hp_c, hp_t, mp_c, mp_t, fp_c, fp_t, exp_v = self.parse_character_stats(raw_text)
- # Update the data manager with the parsed values
+ # Update data_manager with the parsed values
data_manager.set_data_bulk({
"hp_current": hp_c,
"hp_total": hp_t,
@@ -103,3 +113,12 @@ class FlyffCharacterStatusNode(BaseNode):
self.set_property("mp", f"MP: {mp_c}/{mp_t}")
self.set_property("fp", f"FP: {fp_c}/{fp_t}")
self.set_property("exp", f"EXP: {exp_v}%")
+
+ # 2) Capture the screenshot used by OCR and store as base64
+ screenshot_img = data_collector.capture_region_as_image(self.region_id)
+ if screenshot_img:
+ # Convert PIL image to base64
+ buf = BytesIO()
+ screenshot_img.save(buf, format='PNG')
+ image_b64 = base64.b64encode(buf.getvalue()).decode('utf-8')
+ data_manager.set_status_screenshot(image_b64)