EU-Utility/plugins/log_parser_test/plugin.py

367 lines
13 KiB
Python

"""
EU-Utility - Log Parser Test Plugin
Debug and test tool for the Log Reader core service.
Monitors log parsing in real-time with detailed output.
"""
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QTextEdit,
QLabel, QPushButton, QComboBox, QCheckBox,
QSpinBox, QGroupBox, QSplitter, QFrame,
QTableWidget, QTableWidgetItem, QHeaderView
)
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtGui import QColor, QFont
from plugins.base_plugin import BasePlugin
from core.event_bus import SkillGainEvent, LootEvent, DamageEvent, GlobalEvent
class LogParserTestPlugin(BasePlugin):
"""Test and debug tool for log parsing functionality."""
name = "Log Parser Test"
version = "1.0.0"
author = "EU-Utility"
description = "Debug tool for testing log parsing and event detection"
def __init__(self, overlay_window, config):
super().__init__(overlay_window, config)
self.event_counts = {
'skill_gain': 0,
'loot': 0,
'global': 0,
'damage': 0,
'damage_taken': 0,
'heal': 0,
'mission_complete': 0,
'tier_increase': 0,
'enhancer_break': 0,
'unknown': 0
}
self.recent_events = []
self.max_events = 100
self.auto_scroll = True
def initialize(self):
"""Initialize plugin and subscribe to events."""
# Subscribe to all event types for testing
self.subscribe_typed(SkillGainEvent, self._on_skill_gain)
self.subscribe_typed(LootEvent, self._on_loot)
self.subscribe_typed(DamageEvent, self._on_damage)
self.subscribe_typed(GlobalEvent, self._on_global)
# Also subscribe to raw log events via API
api = self._get_api()
if api:
api.subscribe('log_event', self._on_raw_log_event)
self.log_info("Log Parser Test initialized - monitoring events...")
def _get_api(self):
"""Get PluginAPI instance."""
try:
from core.plugin_api import get_api
return get_api()
except:
return None
def _on_skill_gain(self, event: SkillGainEvent):
"""Handle skill gain events."""
self.event_counts['skill_gain'] += 1
self._add_event("Skill Gain", f"{event.skill_name}: +{event.points} pts", "#4ecdc4")
def _on_loot(self, event: LootEvent):
"""Handle loot events."""
self.event_counts['loot'] += 1
value_str = f" ({event.value:.2f} PED)" if event.value else ""
self._add_event("Loot", f"{event.item_name} x{event.quantity}{value_str}", "#ff8c42")
def _on_damage(self, event: DamageEvent):
"""Handle damage events."""
if event.is_critical:
self.event_counts['damage'] += 1
self._add_event("Damage", f"{event.amount} damage ({event.damage_type})", "#ff6b6b")
else:
self.event_counts['damage_taken'] += 1
self._add_event("Damage Taken", f"{event.amount} damage", "#ff4757")
def _on_global(self, event: GlobalEvent):
"""Handle global events."""
self.event_counts['global'] += 1
self._add_event("Global", f"{event.player} found {event.item} worth {event.value} PED!", "#ffd93d")
def _on_raw_log_event(self, event_data):
"""Handle raw log events."""
event_type = event_data.get('event_type', 'unknown')
self.event_counts[event_type] = self.event_counts.get(event_type, 0) + 1
def _add_event(self, event_type: str, details: str, color: str):
"""Add event to recent events list."""
from datetime import datetime
timestamp = datetime.now().strftime("%H:%M:%S")
self.recent_events.insert(0, {
'time': timestamp,
'type': event_type,
'details': details,
'color': color
})
# Trim to max
if len(self.recent_events) > self.max_events:
self.recent_events = self.recent_events[:self.max_events]
# Update UI if available
if hasattr(self, 'events_table'):
self._update_events_table()
def get_ui(self):
"""Create plugin UI."""
widget = QWidget()
layout = QVBoxLayout(widget)
layout.setSpacing(12)
# Header
header = QLabel("📊 Log Parser Test & Debug Tool")
header.setStyleSheet("font-size: 16px; font-weight: bold; color: #ff8c42;")
layout.addWidget(header)
# Status bar
status_frame = QFrame()
status_frame.setStyleSheet("background-color: #1a1f2e; border-radius: 6px; padding: 8px;")
status_layout = QHBoxLayout(status_frame)
self.status_label = QLabel("Status: Monitoring...")
self.status_label.setStyleSheet("color: #4ecdc4;")
status_layout.addWidget(self.status_label)
status_layout.addStretch()
self.log_path_label = QLabel()
self._update_log_path()
self.log_path_label.setStyleSheet("color: #666;")
status_layout.addWidget(self.log_path_label)
layout.addWidget(status_frame)
# Event counters
counters_group = QGroupBox("Event Counters")
counters_layout = QHBoxLayout(counters_group)
self.counter_labels = {}
for event_type, color in [
('skill_gain', '#4ecdc4'),
('loot', '#ff8c42'),
('global', '#ffd93d'),
('damage', '#ff6b6b'),
('damage_taken', '#ff4757')
]:
frame = QFrame()
frame.setStyleSheet(f"background-color: #1a1f2e; border-left: 3px solid {color}; padding: 8px;")
frame_layout = QVBoxLayout(frame)
name_label = QLabel(event_type.replace('_', ' ').title())
name_label.setStyleSheet("color: #888; font-size: 10px;")
frame_layout.addWidget(name_label)
count_label = QLabel("0")
count_label.setStyleSheet(f"color: {color}; font-size: 20px; font-weight: bold;")
frame_layout.addWidget(count_label)
self.counter_labels[event_type] = count_label
counters_layout.addWidget(frame)
layout.addWidget(counters_group)
# Recent events table
events_group = QGroupBox("Recent Events (last 100)")
events_layout = QVBoxLayout(events_group)
self.events_table = QTableWidget()
self.events_table.setColumnCount(3)
self.events_table.setHorizontalHeaderLabels(["Time", "Type", "Details"])
self.events_table.horizontalHeader().setStretchLastSection(True)
self.events_table.setStyleSheet("""
QTableWidget {
background-color: #141f23;
border: 1px solid #333;
}
QTableWidget::item {
padding: 6px;
}
""")
events_layout.addWidget(self.events_table)
# Auto-scroll checkbox
self.auto_scroll_cb = QCheckBox("Auto-scroll to new events")
self.auto_scroll_cb.setChecked(True)
events_layout.addWidget(self.auto_scroll_cb)
layout.addWidget(events_group, 1) # Stretch factor 1
# Test controls
controls_group = QGroupBox("Test Controls")
controls_layout = QHBoxLayout(controls_group)
# Simulate event buttons
btn_layout = QHBoxLayout()
test_skill_btn = QPushButton("Test: Skill Gain")
test_skill_btn.clicked.connect(self._simulate_skill_gain)
btn_layout.addWidget(test_skill_btn)
test_loot_btn = QPushButton("Test: Loot")
test_loot_btn.clicked.connect(self._simulate_loot)
btn_layout.addWidget(test_loot_btn)
test_damage_btn = QPushButton("Test: Damage")
test_damage_btn.clicked.connect(self._simulate_damage)
btn_layout.addWidget(test_damage_btn)
clear_btn = QPushButton("Clear Events")
clear_btn.clicked.connect(self._clear_events)
btn_layout.addWidget(clear_btn)
controls_layout.addLayout(btn_layout)
controls_layout.addStretch()
layout.addWidget(controls_group)
# Raw log view
raw_group = QGroupBox("Raw Log Lines (last 50)")
raw_layout = QVBoxLayout(raw_group)
self.raw_log_text = QTextEdit()
self.raw_log_text.setReadOnly(True)
self.raw_log_text.setStyleSheet("""
QTextEdit {
background-color: #0d1117;
color: #c9d1d9;
font-family: Consolas, monospace;
font-size: 11px;
}
""")
raw_layout.addWidget(self.raw_log_text)
layout.addWidget(raw_group)
# Start update timer
self.update_timer = QTimer()
self.update_timer.timeout.connect(self._update_counters)
self.update_timer.start(1000) # Update every second
# Subscribe to raw log lines
self.read_log(lines=50) # Pre-fill with recent log
return widget
def _update_log_path(self):
"""Update log path display."""
try:
from core.log_reader import LogReader
reader = LogReader()
if reader.log_path:
self.log_path_label.setText(f"Log: {reader.log_path}")
else:
self.log_path_label.setText("Log: Not found")
except Exception as e:
self.log_path_label.setText(f"Log: Error - {e}")
def _update_counters(self):
"""Update counter displays."""
for event_type, label in self.counter_labels.items():
count = self.event_counts.get(event_type, 0)
label.setText(str(count))
def _update_events_table(self):
"""Update events table with recent events."""
self.events_table.setRowCount(len(self.recent_events))
for i, event in enumerate(self.recent_events):
# Time
time_item = QTableWidgetItem(event['time'])
time_item.setForeground(QColor("#888"))
self.events_table.setItem(i, 0, time_item)
# Type
type_item = QTableWidgetItem(event['type'])
type_item.setForeground(QColor(event['color']))
type_item.setFont(QFont("Segoe UI", weight=QFont.Weight.Bold))
self.events_table.setItem(i, 1, type_item)
# Details
details_item = QTableWidgetItem(event['details'])
details_item.setForeground(QColor("#c9d1d9"))
self.events_table.setItem(i, 2, details_item)
# Auto-scroll
if self.auto_scroll_cb.isChecked() and self.recent_events:
self.events_table.scrollToTop()
def _simulate_skill_gain(self):
"""Simulate a skill gain event for testing."""
from datetime import datetime
event = SkillGainEvent(
timestamp=datetime.now(),
skill_name="Rifle",
points=0.1234,
new_value=1234.56
)
self._on_skill_gain(event)
self.log_info("Simulated skill gain event")
def _simulate_loot(self):
"""Simulate a loot event for testing."""
from datetime import datetime
event = LootEvent(
timestamp=datetime.now(),
item_name="Shrapnel",
quantity=100,
value=1.0,
mob_name="Atrox"
)
self._on_loot(event)
self.log_info("Simulated loot event")
def _simulate_damage(self):
"""Simulate a damage event for testing."""
from datetime import datetime
event = DamageEvent(
timestamp=datetime.now(),
amount=45,
damage_type="Impact",
is_critical=True
)
self._on_damage(event)
self.log_info("Simulated damage event")
def _clear_events(self):
"""Clear all events."""
self.recent_events.clear()
for key in self.event_counts:
self.event_counts[key] = 0
self._update_events_table()
self._update_counters()
self.log_info("Cleared all events")
def read_log(self, lines=50):
"""Read recent log lines."""
try:
log_lines = self.read_log(lines=lines)
if log_lines:
self.raw_log_text.setPlainText('\n'.join(log_lines))
except Exception as e:
self.raw_log_text.setPlainText(f"Error reading log: {e}")
def on_show(self):
"""Called when plugin is shown."""
self._update_events_table()
self._update_counters()
def shutdown(self):
"""Clean up."""
if hasattr(self, 'update_timer'):
self.update_timer.stop()
super().shutdown()