Update borealis_overlay.py
This commit is contained in:
parent
794376ca76
commit
57e0c8de00
@ -16,10 +16,10 @@ from rich.console import Console
|
|||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
from rich.progress import Progress, BarColumn, TextColumn
|
from rich.progress import Progress, BarColumn, TextColumn
|
||||||
|
|
||||||
# ---------------- [ Global Config ] ----------------
|
# ---- [ Global Config ] ----
|
||||||
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
|
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
|
||||||
|
|
||||||
OCR_ENGINE = "Tesseract" # Hard-coded since we removed EasyOCR
|
OCR_ENGINE = "Tesseract"
|
||||||
POLLING_RATE_MS = 1000
|
POLLING_RATE_MS = 1000
|
||||||
MAX_DATA_POINTS = 7
|
MAX_DATA_POINTS = 7
|
||||||
|
|
||||||
@ -60,9 +60,7 @@ def format_experience_value(value):
|
|||||||
|
|
||||||
def format_duration(seconds):
|
def format_duration(seconds):
|
||||||
"""
|
"""
|
||||||
Convert total seconds into hours / min / sec:
|
Convert total seconds into hours/min/seconds (e.g. "Xh Ym Zs" or "Xm Ys").
|
||||||
- If hours > 0 => "Xh Ym Zs"
|
|
||||||
- Otherwise => "Xm Ys"
|
|
||||||
"""
|
"""
|
||||||
seconds = int(seconds)
|
seconds = int(seconds)
|
||||||
hours = seconds // 3600
|
hours = seconds // 3600
|
||||||
@ -133,13 +131,13 @@ class OverlayCanvas(QWidget):
|
|||||||
|
|
||||||
if event.button() == Qt.LeftButton:
|
if event.button() == Qt.LeftButton:
|
||||||
for region in reversed(self.regions):
|
for region in reversed(self.regions):
|
||||||
# Check handles
|
# Check each handle
|
||||||
for i, handle in enumerate(region.resize_handles()):
|
for i, handle in enumerate(region.resize_handles()):
|
||||||
if handle.contains(event.pos()):
|
if handle.contains(event.pos()):
|
||||||
self.selected_region = region
|
self.selected_region = region
|
||||||
self.selected_handle = i
|
self.selected_handle = i
|
||||||
return
|
return
|
||||||
# Check label or rect
|
# Check label or main rect
|
||||||
if region.label_rect().contains(event.pos()):
|
if region.label_rect().contains(event.pos()):
|
||||||
self.selected_region = region
|
self.selected_region = region
|
||||||
self.selected_handle = None
|
self.selected_handle = None
|
||||||
@ -156,7 +154,7 @@ class OverlayCanvas(QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if self.selected_handle is None:
|
if self.selected_handle is None:
|
||||||
# Drag rectangle
|
# Drag entire rectangle
|
||||||
self.selected_region.x = event.x() - self.drag_offset.x()
|
self.selected_region.x = event.x() - self.drag_offset.x()
|
||||||
self.selected_region.y = event.y() - self.drag_offset.y()
|
self.selected_region.y = event.y() - self.drag_offset.y()
|
||||||
else:
|
else:
|
||||||
@ -191,33 +189,29 @@ class OverlayCanvas(QWidget):
|
|||||||
self.selected_handle = None
|
self.selected_handle = None
|
||||||
|
|
||||||
class BorealisOverlay(QWidget):
|
class BorealisOverlay(QWidget):
|
||||||
"""
|
|
||||||
Project Borealis with Tesseract + Rich table + Rich progress bar,
|
|
||||||
properly displayed with "with Progress(...) as progress".
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
# Fullscreen overlay
|
|
||||||
screen_geometry = QApplication.primaryScreen().geometry()
|
screen_geometry = QApplication.primaryScreen().geometry()
|
||||||
self.setGeometry(screen_geometry)
|
self.setGeometry(screen_geometry)
|
||||||
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
||||||
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
||||||
|
|
||||||
self.regions = [
|
self.regions = [ Region(250, 50, label="Experience") ]
|
||||||
Region(250, 50, label="Experience"),
|
|
||||||
]
|
|
||||||
self.canvas = OverlayCanvas(self.regions, self)
|
self.canvas = OverlayCanvas(self.regions, self)
|
||||||
self.canvas.setGeometry(self.rect())
|
self.canvas.setGeometry(self.rect())
|
||||||
|
|
||||||
# Tesseract
|
# Tesseract only
|
||||||
self.engine = pytesseract
|
self.engine = pytesseract
|
||||||
|
|
||||||
self.points = []
|
self.points = []
|
||||||
|
|
||||||
self.timer = QTimer(self)
|
self.timer = QTimer(self)
|
||||||
self.timer.timeout.connect(self.collect_ocr_data)
|
self.timer.timeout.connect(self.collect_ocr_data)
|
||||||
self.timer.start(POLLING_RATE_MS)
|
self.timer.start(POLLING_RATE_MS)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# OCR & Data
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
def collect_ocr_data(self):
|
def collect_ocr_data(self):
|
||||||
if not self.engine:
|
if not self.engine:
|
||||||
return
|
return
|
||||||
@ -227,9 +221,9 @@ class BorealisOverlay(QWidget):
|
|||||||
screenshot = ImageGrab.grab(
|
screenshot = ImageGrab.grab(
|
||||||
bbox=(region.x, region.y, region.x + region.w, region.y + region.h)
|
bbox=(region.x, region.y, region.x + region.w, region.y + region.h)
|
||||||
)
|
)
|
||||||
processed_image = self.preprocess_image(screenshot)
|
processed = self.preprocess_image(screenshot)
|
||||||
|
|
||||||
text = pytesseract.image_to_string(processed_image, config='--psm 6 --oem 1')
|
text = pytesseract.image_to_string(processed, config='--psm 6 --oem 1')
|
||||||
region.data = text.strip()
|
region.data = text.strip()
|
||||||
|
|
||||||
if region.label.lower() == "experience":
|
if region.label.lower() == "experience":
|
||||||
@ -255,16 +249,20 @@ class BorealisOverlay(QWidget):
|
|||||||
now = time.time()
|
now = time.time()
|
||||||
if self.points:
|
if self.points:
|
||||||
_, last_v = self.points[-1]
|
_, last_v = self.points[-1]
|
||||||
|
# skip duplicates
|
||||||
if abs(new_val - last_v) < 1e-6:
|
if abs(new_val - last_v) < 1e-6:
|
||||||
return
|
return
|
||||||
|
# rollover
|
||||||
if new_val < last_v:
|
if new_val < last_v:
|
||||||
self.points.clear()
|
self.points.clear()
|
||||||
self.points.append((now, new_val))
|
self.points.append((now, new_val))
|
||||||
if len(self.points) > MAX_DATA_POINTS:
|
if len(self.points) > MAX_DATA_POINTS:
|
||||||
self.points.pop(0)
|
self.points.pop(0)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Table & Calculation
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
def compute_time_to_100(self):
|
def compute_time_to_100(self):
|
||||||
"""Return integer seconds until 100% or None if not feasible."""
|
|
||||||
n = len(self.points)
|
n = len(self.points)
|
||||||
if n < 2:
|
if n < 2:
|
||||||
return None
|
return None
|
||||||
@ -292,6 +290,8 @@ class BorealisOverlay(QWidget):
|
|||||||
return int(remain / rate_per_s)
|
return int(remain / rate_per_s)
|
||||||
|
|
||||||
def display_ocr_data_in_terminal(self):
|
def display_ocr_data_in_terminal(self):
|
||||||
|
from rich.progress import Progress, BarColumn, TextColumn
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
os.system('cls' if os.name == 'nt' else 'clear')
|
os.system('cls' if os.name == 'nt' else 'clear')
|
||||||
|
|
||||||
@ -299,9 +299,9 @@ class BorealisOverlay(QWidget):
|
|||||||
console.print("[dim]Flyff Information Overlay[/dim]\n")
|
console.print("[dim]Flyff Information Overlay[/dim]\n")
|
||||||
|
|
||||||
console.print(f"[bold]OCR Engine[/bold]: {OCR_ENGINE}")
|
console.print(f"[bold]OCR Engine[/bold]: {OCR_ENGINE}")
|
||||||
console.print(f"[bold]Data Polling Rate[/bold]: {POLLING_RATE_MS / 1000}s\n")
|
console.print(f"[bold]Data Polling Rate[/bold]: {POLLING_RATE_MS/1000}s\n")
|
||||||
|
|
||||||
# Build the historical table
|
# Build table
|
||||||
table = Table(show_header=True, header_style=GREEN_HEADER_STYLE, style=None)
|
table = Table(show_header=True, header_style=GREEN_HEADER_STYLE, style=None)
|
||||||
table.add_column("Historical EXP", justify="center", style="green")
|
table.add_column("Historical EXP", justify="center", style="green")
|
||||||
table.add_column("Time Since Last Kill", justify="center", style="green")
|
table.add_column("Time Since Last Kill", justify="center", style="green")
|
||||||
@ -309,6 +309,7 @@ class BorealisOverlay(QWidget):
|
|||||||
table.add_column("Average Time Between Kills", justify="center", style="green")
|
table.add_column("Average Time Between Kills", justify="center", style="green")
|
||||||
|
|
||||||
n = len(self.points)
|
n = len(self.points)
|
||||||
|
# If we only have 1 data point => show single row
|
||||||
if n == 1:
|
if n == 1:
|
||||||
t0, v0 = self.points[0]
|
t0, v0 = self.points[0]
|
||||||
exp_str = f"[green]{format_experience_value(v0)}%[/green]"
|
exp_str = f"[green]{format_experience_value(v0)}%[/green]"
|
||||||
@ -318,30 +319,46 @@ class BorealisOverlay(QWidget):
|
|||||||
t_cur, v_cur = self.points[i]
|
t_cur, v_cur = self.points[i]
|
||||||
t_prev, v_prev = self.points[i - 1]
|
t_prev, v_prev = self.points[i - 1]
|
||||||
|
|
||||||
exp_str = f"[green]{format_experience_value(v_cur)}%[/green]"
|
# Calculate a difference
|
||||||
|
delta_v = v_cur - v_prev
|
||||||
|
delta_str = f"{delta_v:+.4f}%"
|
||||||
|
# e.g. "v_cur + (delta in dark gray)"
|
||||||
|
# "72.8260% [dim](+0.0334%) [/dim]"
|
||||||
|
exp_main = format_experience_value(v_cur)
|
||||||
|
exp_str = (
|
||||||
|
f"[green]{exp_main}%[/green] "
|
||||||
|
f"[dim]({delta_str})[/dim]"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Time since last kill
|
||||||
delta_t = t_cur - t_prev
|
delta_t = t_cur - t_prev
|
||||||
t_since_str = f"{delta_t:.1f}s"
|
t_since_str = f"{delta_t:.1f}s"
|
||||||
|
|
||||||
|
# average exp from first data point
|
||||||
diff_v = v_cur - self.points[0][1]
|
diff_v = v_cur - self.points[0][1]
|
||||||
steps = i
|
steps = i
|
||||||
avg_exp_str = f"{diff_v/steps:.4f}%"
|
avg_exp_str = f"{diff_v/steps:.4f}%"
|
||||||
|
|
||||||
|
# average time from first data point
|
||||||
total_time = t_cur - self.points[0][0]
|
total_time = t_cur - self.points[0][0]
|
||||||
avg_kill_time = total_time / steps
|
avg_kill_time = total_time / steps
|
||||||
avg_time_str = f"{avg_kill_time:.1f}s"
|
avg_time_str = f"{avg_kill_time:.1f}s"
|
||||||
|
|
||||||
table.add_row(exp_str, t_since_str, avg_exp_str, avg_time_str)
|
table.add_row(
|
||||||
|
exp_str,
|
||||||
|
t_since_str,
|
||||||
|
avg_exp_str,
|
||||||
|
avg_time_str
|
||||||
|
)
|
||||||
|
|
||||||
console.print(table)
|
console.print(table)
|
||||||
console.print()
|
console.print()
|
||||||
|
|
||||||
# Prepare the progress bar
|
# Progress bar
|
||||||
current_exp = self.points[-1][1] if self.points else 0.0
|
current_exp = self.points[-1][1] if self.points else 0.0
|
||||||
secs_left = self.compute_time_to_100()
|
secs_left = self.compute_time_to_100()
|
||||||
time_str = format_duration(secs_left) if secs_left is not None else "???"
|
time_str = format_duration(secs_left) if secs_left else "???"
|
||||||
|
|
||||||
# We'll display a single progress bar line in a context manager
|
|
||||||
# Setting transient=False ensures it remains in the console
|
|
||||||
with Progress(
|
with Progress(
|
||||||
TextColumn("[bold white]Predicted Time to Level:[/bold white] "),
|
TextColumn("[bold white]Predicted Time to Level:[/bold white] "),
|
||||||
BarColumn(bar_width=30),
|
BarColumn(bar_width=30),
|
||||||
@ -351,16 +368,14 @@ class BorealisOverlay(QWidget):
|
|||||||
transient=False,
|
transient=False,
|
||||||
) as progress:
|
) as progress:
|
||||||
task_id = progress.add_task("", total=100, completed=current_exp)
|
task_id = progress.add_task("", total=100, completed=current_exp)
|
||||||
# Force a manual refresh so the bar appears immediately
|
|
||||||
progress.refresh()
|
progress.refresh()
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
window = BorealisOverlay()
|
window = BorealisOverlay()
|
||||||
window.setWindowTitle("Project Borealis Overlay (Fixed Progress Bar)")
|
window.setWindowTitle("Project Borealis Overlay (Delta in Historical EXP)")
|
||||||
window.show()
|
window.show()
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user