Installed plugins (calculator, clock_widget, etc.) import from
plugins.base_plugin, but we moved BasePlugin to core.base_plugin.
This shim re-exports BasePlugin so installed plugins work without
needing to know about core module structure.
FIX:
- plugins/base_plugin.py now re-exports from core.base_plugin
- Installed plugins can continue using: from plugins.base_plugin import BasePlugin
This maintains backward compatibility for all installable plugins.
NEW UI LAYOUT:
- Added tab bar at top of content area with 3 tabs:
* 🔌 Plugins - Shows plugin list from sidebar + plugin content
* 🎨 Widgets - Widget gallery to add overlay widgets
* ⚙️ Settings - All settings in one place
WIDGETS TAB FEATURES:
- Built-in widgets section with Clock and System Monitor
- Each widget has Add button to create overlay
- Plugin widgets section (placeholder for plugin-added widgets)
- Descriptions for each widget type
SETTINGS TAB FEATURES:
- Moved settings from dialog into dedicated tab
- Sub-tabs: Plugins, Plugin Store, Hotkeys, Appearance, About
- Removed Settings button from header (now in tabs)
CHANGES:
- _create_content_area() replaced with _create_content_area_with_tabs()
- Added _switch_tab() method
- Added _create_plugins_tab(), _create_widgets_tab(), _create_settings_tab()
- Added _create_widget_button() helper
- Added _add_clock_widget() and _add_system_monitor_widget()
- Removed Settings button from header bar
- Removed old _open_settings() dialog approach
The UI is now organized with clear navigation between
plugins, widgets, and settings via top tabs.
CHANGES:
1. Fixed plugin download to use raw git files instead of git clone
- Avoids Windows permission issues with .git/objects
- Downloads __init__.py and plugin.py directly
2. Added clickable dependencies button showing full dependency dialog
- Shows Core Services Required
- Shows Plugins Required
- Lists what will be auto-installed
3. Integrated Plugin Store into Settings dialog
- Added 🔌 Store tab to Settings
- Plugin Store is now built-in, not a plugin
4. Removed plugins/settings/ and plugins/plugin_store_ui/
- Settings is now built into overlay_window.py
- Users access via Settings button
5. Added _create_plugin_store_tab() method to OverlayWindow
NOTE: Pull latest EU-Utility-Plugins-Repo to get Clock Widget
The base_plugin.py was removed from plugins/ folder during cleanup
but is still needed by core/plugin_manager.py and built-in plugins.
CHANGES:
- Restored base_plugin.py from plugin repo to core/base_plugin.py
- Updated imports in core/plugin_manager.py
- Updated imports in core/plugin_manager_optimized.py
- Updated imports in plugins/settings/plugin.py
- Updated imports in plugins/plugin_store_ui/plugin.py
This fixes ModuleNotFoundError when starting EU-Utility.
All user-facing plugins have been moved to:
https://git.lemonlink.eu/impulsivefps/EU-Utility-Plugins-Repo
REMOVED FROM CORE (30+ plugins):
- analytics, auction_tracker, auto_screenshot, auto_updater
- calculator, chat_logger, codex_tracker, crafting_calc
- dashboard, discord_presence, dpp_calculator, enhancer_calc
- event_bus_example, game_reader, game_reader_test, global_tracker
- import_export, inventory_manager, log_parser_test, loot_tracker
- mining_helper, mission_tracker, nexus_search, price_alerts
- profession_scanner, session_exporter, skill_scanner
- spotify_controller, tp_runner, universal_search
ALSO REMOVED:
- plugins/base_plugin.py (was duplicate, should be in package root)
- plugins/__pycache__ (shouldn't be in git)
REMAINING IN CORE:
- plugins/__init__.py
- plugins/settings/ (essential for configuration)
- plugins/plugin_store_ui/ (essential for plugin installation)
EU-Utility is now a pure framework. Users install plugins via
Settings → Plugin Store or manually to the plugins/ folder.
This separation enables:
- Independent plugin development
- Modular installation (only what you need)
- Community contributions via plugin repo
- Cleaner core codebase focused on framework
BREAKING CHANGE: EU-Utility is now a framework-only application.
All user-facing features have been moved to separate plugin repository.
NEW FEATURES:
1. Plugin Store Core Module (core/plugin_store.py)
- PluginStoreWorker: Background operations (fetch, download, updates)
- PluginStoreUI: Grid-based plugin browser with cards
- PluginInfo dataclass for plugin metadata
- Fetches from remote git repository
2. Plugin Store UI Features:
- Grid layout with plugin cards (300x200px each)
- Search/filter by name, description, tags
- Category filter dropdown
- Visual indicators:
* 📦 Plugin icon (emoji-based)
* Version badge
* Status badges (✅ Enabled, 📦 Installed)
* Tag display
* 🔗 Dependency count with tooltip
- Install/Enable/Disable/Uninstall buttons
- Progress bar for operations
- Refresh and Check Updates buttons
3. Settings Integration:
- New 'Plugin Store' tab in Settings
- Moved plugin management to 'My Plugins' tab
- Plugin Store uses core module directly
4. Plugin Store UI Plugin (plugins/plugin_store_ui/):
- Standalone plugin for overlay integration
- Hotkey: Ctrl+Shift+P (configurable)
ARCHITECTURE CHANGES:
- EU-Utility Core: Framework only (PluginAPI, services, overlay)
- Plugin Repository: https://git.lemonlink.eu/impulsivefps/EU-Utility-Plugins-Repo
- Plugins installed via Store → user plugins/ directory
- Local plugins/ folder still supported for development
MANIFEST FORMAT:
USER WORKFLOW:
1. Open Settings → Plugin Store
2. Browse/search available plugins
3. Click Install (with dependency confirmation)
4. Restart EU-Utility
5. Enable plugin in 'My Plugins' tab
DEVELOPER WORKFLOW:
1. Develop plugin locally in plugins/
2. Test with core framework
3. Submit to plugin repository
4. Users install via Store
This enables limitless modularity - users only install
what they need, developers can publish independently.
REFACTOR: Hotkeys are no longer hardcoded in Settings UI
NEW SYSTEM:
1. Plugins advertise their hotkeys via class attributes:
Legacy (single hotkey):
hotkey = 'ctrl+shift+s'
New format (multiple hotkeys with descriptions):
hotkeys = [
{
'action': 'toggle',
'description': 'Toggle Skill Scanner',
'default': 'ctrl+shift+s',
'config_key': 'skillscanner_toggle' # optional
},
{
'action': 'quick_scan',
'description': 'Quick Scan',
'default': 'f12',
}
]
2. Settings UI dynamically discovers hotkeys:
- Scans all plugins for hotkey/hotkeys attributes
- Groups hotkeys by plugin name
- Shows description + input field + reset button
- Core system hotkeys in separate 'Core System' group
3. Visual improvements:
- Scrollable hotkey list
- Reset button (↺) for each hotkey
- Tooltips showing default value
- Plugin grouping for organization
4. Backward compatible:
- Still supports legacy 'hotkey' attribute
- Converts to new format automatically
- Existing settings preserved
BASE PLUGIN:
- Added hotkeys attribute documentation
- Added docstring with usage examples
- Shows both formats in class docstring
SETTINGS PLUGIN:
- _create_hotkeys_tab() now dynamic
- _collect_plugin_hotkeys() scans all plugins
- Groups by plugin with QGroupBox
- Reset buttons restore defaults
- ScrollArea for long lists
This allows plugins to define multiple hotkeys with
descriptions, and they'll automatically appear in
Settings without hardcoding them in the core.
NEW FEATURES:
1. Dependency Indicators:
- 🔗 (cyan) - Plugin has dependencies (hover for list)
- ⚠️ (yellow) - Plugin is required by other enabled plugins
- 🔄 (orange) - Auto-enabled due to dependency
2. Legend Bar:
Shows what each indicator means at the top of the plugins tab
3. Dependency Tooltips:
- 🔗 Shows: 'This plugin requires: X, Y, Z. These will be auto-enabled.'
- ⚠️ Shows: 'Required by enabled plugins: A, B. Disable those first.'
- 🔄 Shows: 'Auto-enabled by: PluginName'
4. Enable with Dependencies:
When enabling a plugin with unmet dependencies:
- Shows confirmation dialog listing all plugins to be enabled
- User can cancel before enabling
- Dependencies are auto-enabled on confirmation
5. Disable Protection:
When trying to disable a plugin that others depend on:
- Shows warning dialog listing dependent plugins
- Prevents accidental breaking of dependencies
- User must disable dependents first
6. Dependency Report Dialog:
- New '📋 Dependency Report' button
- Shows HTML report with:
* Summary stats (total/enabled plugins)
* Plugins with dependencies list
* Plugins required by others list
* Full dependency chains
7. Enable/Disable All with Ordering:
- Dependencies are enabled first (topological sort)
- Dependents are disabled first (reverse order)
- Prevents enable/disable failures due to ordering
8. Auto-refresh UI:
After enabling/disabling, plugin list refreshes to show:
- Updated auto-enabled status
- Updated dependency indicators
- Updated checkbox states
VISUAL IMPROVEMENTS:
- Better spacing and layout
- Color-coded indicators
- Clear visual hierarchy
- Informative tooltips throughout
This makes plugin management much more intuitive and prevents
common mistakes like accidentally breaking dependencies.
PROBLEM: UI text like 'Position Skills window Wounding' and
'Scan Current Page Serendipity' was being parsed as skills.
FIXES:
1. Enhanced is_valid_skill_text() filtering:
- Added more UI patterns: 'Position Skills', 'Scan Current Page',
'Select Area', 'Drag over', 'Navigate pages'
- Added combined patterns: 'Combat Wounding', 'Scan Serendipity',
'Position Wounding', etc.
- Added action word detection: Click, Scan, Position, Select,
Navigate, Start, Save, Clear - any line with these is UI text
- Reduced max words from 10 to 7 for skill names
2. Added validation in _parse_skills_from_text():
- After extracting skill name, validates with is_valid_skill_text()
- Logs filtered names for debugging
- Only adds to results if validation passes
USER ACTION NEEDED:
- Pull latest code: git pull origin main
- Select Area button should appear in UI
- Drag to select your Skills window area
- Scan will only read from that area
This should eliminate UI text from scan results.
NEW FEATURE - Snipping Tool Area Selection:
WORKFLOW:
1. Click 'Select Area' button in Skill Scanner
2. Screen dims with semi-transparent overlay
3. Drag to draw rectangle over your Skills window
4. Release to confirm (right-click or Escape to cancel)
5. Selected area is saved for all future scans
6. Click 'Start Smart Scan' to begin
SNIPPING WIDGET FEATURES:
- Fullscreen overlay with darkened background
- Drag to draw selection rectangle
- White border around selection
- Dimensions displayed (e.g., '800 x 600')
- Right-click to cancel
- Escape key to cancel
- Minimum 50x50 pixels required
UI UPDATES:
- Added 'Select Area' button with blue color (#4a9eff)
- Area label shows current selection: '800x600 at (100, 200)'
- All mode instructions updated to mention Select Area step
TECHNICAL:
- SnippingWidget inherits from QWidget
- Uses Qt.TranslucentBackground for transparency
- QPainter.CompositionMode_Clear for cutout effect
- Selected area stored as self.scan_area (x, y, w, h)
- SkillOCRThread accepts scan_area parameter
- Both single scan and multi-page scan use selected area
BENEFITS:
- No more window detection errors
- User has full control over scan region
- Works regardless of window title or process name
- Precise selection of Skills window area
If no area selected, falls back to full game window capture.
BUG: SkillScannerPlugin cannot be converted to PyQt6.QtCore.QObject
CAUSE: BasePlugin inherits from ABC, not QObject. Qt signals (pyqtSignal)
must be defined in a QObject subclass.
FIX:
1. Created SignalHelper(QObject) class to hold all signals:
- hotkey_triggered
- update_status_signal
- update_session_table_signal
- update_counters_signal
- enable_scan_button_signal
2. In SkillScannerPlugin.initialize():
- Create self._signals = SignalHelper()
- Connect signals from self._signals (not self)
3. In get_ui():
- Connect enable_scan_button_signal after scan_page_btn is created
4. Updated all signal emits to use self._signals.emit()
This allows the plugin to use Qt signals for thread-safe UI updates
without requiring BasePlugin to inherit from QObject (which would
break other plugins).
BUG: OCR was reading text from Discord, EU-Utility UI, and other windows.
FIX:
1. Added find_entropia_window() - Uses win32gui + psutil on Windows to find
the game window by process name 'Entropia.exe' and window title containing
'Entropia Universe'. Returns (left, top, width, height).
2. Added capture_entropia_region() - Captures only the game window region,
falls back to full screen if window not found.
3. Added is_valid_skill_text() - Filters out non-game text patterns:
- Discord, Event Bus, Game Reader, Test, Page Scanner, HOTKEY MODE
- UI elements like 'Skill Tracker', 'Calculator', 'Nexus Search'
- Debug text like '[SkillScanner]', 'Parsed:', 'Cleared'
- Process names like 'Entropia.exe', 'Client (64 bit)', 'Arkadia'
- Lines with >10 words (skills aren't that long)
4. Added recognize_image() method to OCRService for convenience.
5. Modified SkillOCRThread.run() to:
- Capture only Entropia window
- Filter text before parsing
- Use _parse_skills_filtered() which validates each line
6. Added _parse_skills_filtered() method that:
- Splits text by lines
- Only keeps lines containing a valid rank
- Validates each line with is_valid_skill_text()
- Logs filtered lines for debugging
RESULT:
- Scanner now ONLY reads from the game window
- Invalid text (Discord, UI, debug) is filtered out
- Much cleaner skill parsing results
Note: Window title varies by location (e.g., '[Arkadia]', '[Calypso]')
but process name is always 'Entropia.exe'.
BUG: QMetaObject.invokeMethod with Q_ARG doesn't work properly in PyQt6
and was causing TypeError exceptions.
FIX:
- Added proper Qt signals at class level:
* update_status_signal(str, bool, bool)
* update_session_table_signal(object)
* update_counters_signal()
* enable_scan_button_signal(bool)
- Connected all signals to slot methods in initialize()
- Replaced all invokeMethod calls with signal.emit()
- Thread callbacks now emit signals instead of calling invokeMethod
- UI updates happen in main Qt thread via signal/slot mechanism
This is the correct PyQt6 way to do cross-thread communication.
All UI updates are now thread-safe and won't cause TypeErrors.
BUG: TypeError when using F12 hotkey - invokeMethod syntax was wrong
for PyQt6.
FIX:
1. Added hotkey_triggered = pyqtSignal() at class level
2. Connected signal to _scan_page_for_multi in initialize()
3. _hotkey_scan() now just emits the signal (thread-safe)
4. Signal ensures scan runs on main Qt thread
This is the proper Qt way to handle cross-thread communication.
The hotkey callback runs in keyboard library's thread, but the
scan must run in Qt's main thread to update UI safely.
NEW FEATURE - Smart Multi-Page Scanning:
MODES:
1. 🤖 Smart Auto + Hotkey Fallback (default)
- Tries to auto-detect page changes
- Monitors page number area (1/12, 2/12, etc.)
- If detection fails, falls back to F12 hotkey
- User gets notified: 'Auto-detect unreliable. Use F12!'
2. ⌨️ Manual Hotkey Only
- User navigates pages in EU
- Presses F12 to scan each page
- Simple and 100% reliable
3. 🖱️ Manual Click Only
- Original click-based scanning
- Click button, wait for beep, next page
SMART AUTO FEATURES:
- Checks page number area every 500ms
- Detects when page number changes (1→2, 2→3, etc.)
- Automatically triggers scan on page change
- Tracks failures - after 10 failures, falls back to hotkey
- Plays beep sound on successful auto-scan
HOTKEY FEATURES:
- F12 key registered globally
- Works even when EU-Utility not focused
- Triggers scan immediately
- Can be used as primary mode or fallback
UI UPDATES:
- Mode selector dropdown
- Dynamic instructions based on mode
- Hotkey info displayed (F12 = Scan)
- Status shows when auto-detect vs hotkey is active
TECHNICAL:
- Uses keyboard library for global hotkeys
- QTimer for auto-detection polling
- Tesseract OCR for page number reading
- Graceful fallback when auto fails
This gives users the best of both worlds:
- Try auto for convenience
- Fallback to hotkey for reliability
NEW FEATURE - Multi-Page Scanner:
WORKFLOW:
1. User positions Skills window to show skills
2. User clicks 'Scan Current Page'
3. App scans, shows checkmark ✅, plays BEEP sound
4. Status shows: 'Page X scanned! Click Next Page in game →'
5. User manually clicks Next Page in EU
6. User clicks 'Scan Current Page' again
7. Repeat until all pages scanned
8. User clicks 'Save All' to store combined results
FEATURES:
- ✅ Checkmark icon and green text on successful scan
- 🔊 Beep sound (Windows MessageBeep) to notify user
- 📊 Live counters: Pages scanned, Total skills
- 🗑 Clear Session button to start over
- 💾 Save All button merges session into main data
- 📝 Session table shows all skills collected so far
UI ELEMENTS:
- Instructions panel explaining the workflow
- Status label with color-coded feedback
- Pages: X counter
- Skills: X counter
- Three buttons: Scan Page, Save All, Clear Session
- Session table showing accumulated skills
TECHNICAL:
- current_scan_session dict accumulates skills across pages
- pages_scanned counter tracks progress
- Thread-safe UI updates via QMetaObject.invokeMethod
- Windows beep via winsound module (with fallback)
This gives users full control while guiding them through
multi-page scanning without any auto-clicking!
FIXES:
1. Changed from re.search (finds first) to re.finditer (finds ALL)
- Now extracts all skills visible in the skills window
- Not just the first skill
2. Added category name cleaning
- Removes: Attributes, Combat, Design, Construction, etc.
- Prevents 'Attributes Laser Weaponry Technology' issues
- Now correctly extracts just 'Laser Weaponry Technology'
3. Normalizes whitespace after removing categories
- Joins all text into single space-separated string
- Helps with multi-line skill parsing
4. Added validation for skill name length
- Must be more than 2 characters
- Filters out false positives
ABOUT YOUR FEATURE REQUESTS:
Multi-Page Scanning:
- To scan all pages automatically would require:
1. Detect the skills window is open
2. Click the 'next page' button automatically
3. Wait for page transition
4. Repeat until last page (detect via page counter)
5. This requires UI automation (pyautogui)
6. Risk: Could interfere with gameplay
Progress Bar Detection:
- The green bars represent % progress to next level
- To measure them would require:
1. Image processing (OpenCV) to detect bar length
2. Comparing green pixels to total bar width
3. Converting to percentage
4. This is complex and computationally expensive
5. Alternative: Track skill gains via chat.log instead
RECOMMENDATION:
For tracking skill progress precisely, the best approach is:
1. Use chat.log parsing (already implemented)
2. It catches every skill gain with exact values
3. No OCR needed - 100% accurate
4. Works in background automatically
FIXES:
1. Added 'Arch Master' to the list of multi-word ranks
- Multi-word ranks are now matched first to prevent partial matches
- Changed rank matching order: ['Arch Master', 'Grand Master'] + single ranks
- This fixes 'Laser Weaponry Technology Arch' being parsed incorrectly
- Now correctly parses as: 'Laser Weaponry Technology', 'Arch Master', 8805
2. Added 'Reset Data' button to Skill Scanner plugin
- Red button next to 'Scan Skills Window'
- Shows confirmation dialog before clearing
- Clears: skills_data, skill_gains, and the UI tables
- Also clears the data file (skill_tracker.json)
3. Clean skill names by removing 'Skill' prefix
- OCR sometimes reads 'Skill Laser Weaponry Technology'
- Now strips 'Skill' or 'SKILL' prefix from skill names
4. Updated both Skill Scanner and Game Reader Test plugins
- Both now use the same improved parsing logic
- Both handle multi-word ranks correctly
The _parse_skills_from_text method uses re (regex) but it was only
imported inside a nested function, not at module level.
Added 'import re' at the top of the file.
The Spotify 'Now Playing' overlay widget was appearing even when
the Spotify Controller plugin was not enabled.
CHANGES:
- Set 'spotify' overlay widget to enabled: False in default settings
- Removed Spotify from dashboard default widgets
- Both settings.py and settings_secure.py updated
The widget can still be manually enabled by users who want it:
1. Edit config/settings.json
2. Set overlay_widgets.spotify.enabled to true
3. Or use the overlay widget controls
This fixes the issue where the Spotify widget appeared even when
the plugin wasn't enabled.
NEW FEATURES:
1. Skills Parser Tab:
- Dedicated tab for parsing EU Skills window
- Captures screen and extracts skills automatically
- Shows results in a 3-column table (Skill Name, Rank, Points)
- Displays raw OCR text for debugging
- Shows count of parsed skills
2. Improved Skills Parsing:
- Better pattern matching for skill names with spaces
- Recognizes all EU skill ranks
- Filters out headers and category names
- Validates points are reasonable numbers
3. UI Improvements:
- Clear instructions on how to use
- Visual feedback during capture
- Color-coded status (cyan = working, red = error)
- Table auto-sizes columns
USAGE:
1. Open EU Skills window
2. Go to Game Reader Test → Skills Parser tab
3. Click 'Capture Skills Window'
4. View parsed skills in the table
This makes it much easier to test skill scanning and verify
that the OCR is parsing correctly!
The previous parser was too simple and couldn't handle the merged text
from OCR on the skills window.
IMPROVEMENTS:
1. Clean up common headers and category names from OCR text
2. Better regex pattern that handles merged text
3. Alternative parser as fallback for heavily merged text
4. Debug logging to show parsed skills
5. Validation to filter out bad matches
PARSING LOGIC:
- Finds pattern: SkillName Rank Points
- Handles multi-word skill names (e.g., 'Combat Reflexes')
- Recognizes all EU skill ranks (Newbie through Awesome)
- Validates points are reasonable numbers
This should correctly parse skills like:
Aim Amazing 5524
Combat Reflexes Incredible 5991
Handgun Grand Master 8621
The string contained C:\Program Files\Tesseract-OCR which Python
interpreted as escape sequences (\P is invalid).
Fixed by escaping backslashes: C:\Program Files\Tesseract-OCR
The _check_backends method had leftover code from an old version
mixed with the new implementation, causing:
unexpected indent (plugin.py, line 953)
Removed the duplicate/old code block.
Plugins can now declare dependencies on other plugins.
NEW FEATURES:
- dependencies['plugins'] = ['plugin_id1', 'plugin_id2']
- Separates pip packages (auto-installed) from plugin dependencies (user enabled)
- Settings dialog shows which plugins need to be enabled first
- PluginDependencyCheck tracks installed/enabled status
EXAMPLE:
dependencies = {
'pip': ['requests'],
'plugins': ['plugins.dashboard.plugin.DashboardPlugin']
}
NEW FEATURES:
1. Plugin Dependency Declaration (BasePlugin):
- Added 'dependencies' class attribute
- Format: {'pip': ['package1', 'package2'], 'optional': {...}}
- Plugins can declare required pip packages
2. Plugin Dependency Manager (core/plugin_dependency_manager.py):
- Checks if declared dependencies are installed
- Installs missing packages via pip
- Tracks installation status
- Shows progress dialog during installation
3. Settings Dialog Integration:
- When enabling a plugin with dependencies, shows dialog
- Lists missing dependencies
- Asks user if they want to install
- Shows progress bar during installation
- Handles installation failures gracefully
4. Example: Game Reader Test plugin:
- Declares dependencies: pillow, numpy
- Optional: easyocr, pytesseract, paddleocr
- When enabled, prompts to install if missing
WORKFLOW:
1. User enables a plugin in Settings → Plugins
2. System checks if plugin has dependencies
3. If dependencies missing, shows dialog
4. User clicks Yes to install
5. Progress dialog shows installation progress
6. Plugin loads after dependencies installed
This eliminates manual pip install steps for plugins!
BUG FIXES:
1. HTTPClient '_generate_cache_key' AttributeError:
- The method definition was missing, only had docstring and body
- Added proper method signature: def _generate_cache_key(self, url, params)
2. Dashboard 'bg_dark' KeyError:
- EU_COLORS doesn't have 'bg_dark'
- Changed to 'bg_secondary' which is the correct color
3. Log Parser 'maximum recursion depth exceeded':
- read_log() was calling itself instead of parent method
- Changed to super().read_log() to call BasePlugin's method
These fixes resolve:
- Universal Search not working
- API errors
- Dashboard customize dialog crash
- Log Parser infinite recursion
Added to README.md:
- New 'OCR Requirements (Optional)' section after Installation
- Instructions for installing EasyOCR (recommended), Tesseract, or PaddleOCR
- Note that Game Reader works without OCR, just shows 'not available'
Improved Game Reader Test plugin:
- Better error message when Tesseract binary is not installed
- Provides download link and installation steps in error message
- Updated Calibration tab to check if Tesseract binary is available
- Shows recommendation to use EasyOCR in backend status
This helps users understand why they get 'tesseract is not installed'
errors and how to fix them.
Added new 'File Test' tab that allows testing OCR on saved screenshot files.
This is useful when:
- The game is not currently running
- You want to test OCR on a specific saved screenshot
- You want to compare OCR results on the same image
Features:
- Browse button to select image files (PNG, JPG, BMP, TIFF)
- Backend selection (Auto/EasyOCR/Tesseract)
- Displays filename and processing stats
- Shows which backend was used and processing time
The original 'Quick Test' still captures the current screen.
The new 'File Test' lets you test on saved images.
The plugin was using wrong field names for EventBus events:
SkillGainEvent:
- Fixed: points → gain_amount
- Fixed: new_value → skill_value
LootEvent:
- Fixed: Now uses items list instead of direct item_name/quantity/value
- Updated to handle the dict structure in items list
DamageEvent:
- Fixed: amount → damage_amount
- Fixed: Now uses is_outgoing instead of is_critical for direction
- Added target_name and attacker_name fields
GlobalEvent:
- Fixed: player → player_name
- Fixed: item → item_name
- Added achievement_type field
All simulate buttons should now work correctly.
CHANGES:
1. Settings plugin is no longer categorized as 'Core' plugin
- The settings menu is built into the overlay window
- Having both was redundant
- Settings plugin still exists but won't be auto-enabled
2. Removed hardcoded SpotifyWidget from core/dashboard.py
- Spotify widget was baked into core instead of being a proper plugin
- Should be in plugins/spotify_controller/ instead
- Commented out the widget addition for now
This addresses the user's feedback that:
- Settings plugin is redundant with the settings menu
- Spotify widget shouldn't be in core
BUG 1: Sidebar buttons clicked wrong plugin
- Lambda captured idx by reference, always using last value
- Fixed by using functools.partial to capture by value
BUG 2: Dashboard plugin KeyError 'border_subtle'
- Changed to 'border_default' which exists in EU_COLORS
The sidebar should now correctly switch to the clicked plugin.
BUG: TypeError: missing 1 required positional argument: 'checked'
The lambda functions were expecting a 'checked' argument that wasn't
being passed by the signals:
- QShortcut.activated doesn't pass any arguments
- SidebarButton.clicked doesn't pass any arguments
Fix: Removed 'checked' parameter from both lambda functions.
BUG: 'bg_panel' KeyError in Dashboard plugin.
The EU_COLORS dictionary doesn't have 'bg_panel'. Changed to use
'bg_secondary' which is the correct background color for panels.
BUG: KeyError: 'border_color' when opening Settings dialog.
The color dictionary uses 'border_default' not 'border_color'.
Fixed all 5 occurrences in the file.
BUG: KeyError: 'accent_primary' when opening Settings dialog.
The color dictionary uses 'accent_orange' not 'accent_primary'.
Fixed all 10 occurrences in the file.
NEW TESTING PLUGINS:
1. Log Parser Test Plugin (plugins/log_parser_test/)
- Real-time event monitoring with counters
- Visual event history table (last 100 events)
- Raw log line viewer
- Simulated event buttons for testing:
* Skill Gain
* Loot
* Damage
- Event type filtering and statistics
- Color-coded event types
- Auto-scroll and refresh
2. Game Reader Test Plugin (plugins/game_reader_test/)
- Quick OCR test with progress bar
- Region-specific OCR testing with presets:
* Chat Window
* Skills Window
* Inventory
* Mission Tracker
- OCR backend selection (Auto/EasyOCR/Tesseract/PaddleOCR)
- Processing time tracking
- Test history with results
- Save/copy OCR results
- Calibration tools:
* Display DPI detection
* Backend status checker
* OCR tips and best practices
FEATURES FOR BOTH:
- Modern EU-styled UI
- Tabbed interface
- Error handling and logging
- Background processing (no UI freeze)
- Real-time updates
These plugins serve as both testing tools and demonstrations
of the Log Reader and OCR core services capabilities.
BUG: name 'QCheckBox' is not defined errors in plugins settings tab.
Root cause: QCheckBox was imported inside _open_settings() method but
_create_plugins_settings_tab() also uses it. The local import didn't
propagate to the helper method.
FIX:
- Added QCheckBox to top-level PyQt6 imports
- Added QTabWidget to top-level imports (also used)
- Removed redundant local imports from _open_settings()
All settings UI components now available globally in the module.
BUG: AttributeError when accessing plugin_class.name in settings tab.
The error occurred when iterating over discovered plugins and trying
to access .name, .version, or .description attributes. While all
plugins should have these attributes, there might be edge cases
where the plugin_class is not properly formed.
FIX:
- Added getattr() with defaults for safe attribute access
- Added try-except around each plugin row creation
- Added error logging for debugging
- Gracefully skip broken plugin entries instead of crashing
Changes:
- _create_plugins_settings_tab() now uses getattr() for all
plugin attributes with sensible defaults
- Each plugin row is wrapped in try-except for isolation
- Errors are logged but don't crash the settings UI
BUG: AttributeError: 'ScreenshotService' object has no attribute '_platform'
Root cause: In __init__, _get_default_save_path() was called BEFORE
_platform was initialized. The method tried to access self._platform
to determine the save path.
FIX: Moved platform detection BEFORE save path initialization in:
- core/screenshot.py
- core/screenshot_secure.py
- core/screenshot_vulnerable.py
Order changed from:
1. self._save_path = self._get_default_save_path() # FAILS - needs _platform
2. self._platform = platform.system().lower()
To:
1. self._platform = platform.system().lower()
2. self._save_path = self._get_default_save_path() # WORKS - _platform exists
This is a common Python initialization order bug where methods called
in __init__ reference attributes that haven't been set yet.
The package 'PyQt6-Qt6-SVG' does not exist on PyPI.
PyQt6 6.4.0+ includes SVG support by default via QtSvg module.
Users were getting:
ERROR: No matching distribution found for PyQt6-Qt6-SVG
Fix: Removed the invalid package line.
SVG support will work with base PyQt6 installation.
BUGS FIXED:
1. Missing dependencies in requirements.txt:
- Added pytesseract>=0.3.10 (OCR service needs it)
- Added psutil>=5.9.0 (Analytics plugin needs it)
- Added pywin32>=306 for Windows (window/screenshot needs it)
2. Type mismatch in plugin_api.py:
- get_eu_window() documented as returning Dict[str, Any]
- But actually returned WindowInfo dataclass
- Fixed: Now converts WindowInfo to dict before returning
This should resolve most import and type errors users were seeing.