import threading import time import base64 from flask import Flask, jsonify, Response from PyQt5.QtCore import QMutex # Global datastore for character metrics data_store = { "hp_current": 0, "hp_total": 0, "mp_current": 0, "mp_total": 0, "fp_current": 0, "fp_total": 0, "exp": 0.0 } # Mutex for thread safety 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__) @app.route('/data') def data_api(): """ Returns the current character metrics as JSON. """ return jsonify(get_data()) @app.route('/exp') def exp_api(): """ Returns the EXP data. """ return jsonify({"exp": get_data()["exp"]}) @app.route('/hp') def hp_api(): """ Returns the HP data. """ return jsonify({ "hp_current": get_data()["hp_current"], "hp_total": get_data()["hp_total"] }) @app.route('/mp') def mp_api(): """ Returns the MP data. """ return jsonify({ "mp_current": get_data()["mp_current"], "mp_total": get_data()["mp_total"] }) @app.route('/fp') def fp_api(): """ Returns the FP data. """ return jsonify({ "fp_current": get_data()["fp_current"], "fp_total": get_data()["fp_total"] }) @app.route('/flyff/status') 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 = """ Borealis - Live Status """ return html @app.route('/flyff/status_rawdata') 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. """ def run(): app.run(host="0.0.0.0", port=5000) # Allows external connections t = threading.Thread(target=run, daemon=True) t.start() def get_data(): """ Return a copy of the global data_store. """ data_mutex.lock() data_copy = data_store.copy() data_mutex.unlock() return data_copy def set_data(key, value): """ Set a single metric in the global data_store. """ data_mutex.lock() data_store[key] = value data_mutex.unlock() def set_data_bulk(metrics_dict): """ Update multiple metrics in the global data_store at once. """ 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()