868 lines
21 KiB
Markdown
868 lines
21 KiB
Markdown
# EU-Utility API Cookbook
|
|
|
|
> Code recipes and examples for common tasks
|
|
>
|
|
> **Version:** 2.1.0
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Plugin Basics](#plugin-basics)
|
|
2. [Working with Events](#working-with-events)
|
|
3. [Screen Capture & OCR](#screen-capture--ocr)
|
|
4. [Nexus API Recipes](#nexus-api-recipes)
|
|
5. [Data Persistence](#data-persistence)
|
|
6. [Background Tasks](#background-tasks)
|
|
7. [UI Components](#ui-components)
|
|
8. [Advanced Patterns](#advanced-patterns)
|
|
|
|
---
|
|
|
|
## Plugin Basics
|
|
|
|
### Minimal Plugin Template
|
|
|
|
```python
|
|
"""
|
|
Minimal working plugin template.
|
|
Copy this to get started quickly.
|
|
"""
|
|
|
|
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel
|
|
from plugins.base_plugin import BasePlugin
|
|
|
|
|
|
class MyPlugin(BasePlugin):
|
|
"""Description of what your plugin does."""
|
|
|
|
# Required metadata
|
|
name = "My Plugin"
|
|
version = "1.0.0"
|
|
author = "Your Name"
|
|
description = "What my plugin does"
|
|
|
|
# Optional
|
|
hotkey = "ctrl+shift+x" # Global hotkey
|
|
icon = "target" # Icon name
|
|
|
|
def initialize(self):
|
|
"""Called when plugin is loaded."""
|
|
self.data = self.load_data("my_key", default_value={})
|
|
self.log_info(f"{self.name} initialized")
|
|
|
|
def get_ui(self):
|
|
"""Return the plugin's UI widget."""
|
|
widget = QWidget()
|
|
layout = QVBoxLayout(widget)
|
|
|
|
label = QLabel(f"Hello from {self.name}!")
|
|
layout.addWidget(label)
|
|
|
|
return widget
|
|
|
|
def on_hotkey(self):
|
|
"""Called when hotkey is pressed."""
|
|
self.notify_info("Hotkey", f"{self.name} hotkey pressed!")
|
|
|
|
def shutdown(self):
|
|
"""Called when app closes."""
|
|
self.save_data("my_key", self.data)
|
|
self.log_info(f"{self.name} shutdown")
|
|
```
|
|
|
|
### Plugin with Settings
|
|
|
|
```python
|
|
"""
|
|
Plugin with persistent settings.
|
|
"""
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout,
|
|
QLabel, QLineEdit, QPushButton, QCheckBox
|
|
)
|
|
from plugins.base_plugin import BasePlugin
|
|
|
|
|
|
class ConfigurablePlugin(BasePlugin):
|
|
"""Plugin with user-configurable settings."""
|
|
|
|
name = "Configurable Plugin"
|
|
version = "1.0.0"
|
|
author = "Your Name"
|
|
description = "Plugin with settings example"
|
|
|
|
def initialize(self):
|
|
"""Load settings with defaults."""
|
|
self.settings = self.load_data("settings", {
|
|
"username": "",
|
|
"enabled": True,
|
|
"threshold": 100
|
|
})
|
|
|
|
def get_ui(self):
|
|
"""Create settings UI."""
|
|
widget = QWidget()
|
|
layout = QVBoxLayout(widget)
|
|
|
|
# Username setting
|
|
user_layout = QHBoxLayout()
|
|
user_layout.addWidget(QLabel("Username:"))
|
|
self.user_input = QLineEdit(self.settings["username"])
|
|
self.user_input.textChanged.connect(self._on_user_changed)
|
|
user_layout.addWidget(self.user_input)
|
|
layout.addLayout(user_layout)
|
|
|
|
# Enabled setting
|
|
self.enabled_checkbox = QCheckBox("Enable feature")
|
|
self.enabled_checkbox.setChecked(self.settings["enabled"])
|
|
self.enabled_checkbox.toggled.connect(self._on_enabled_changed)
|
|
layout.addWidget(self.enabled_checkbox)
|
|
|
|
# Threshold setting
|
|
threshold_layout = QHBoxLayout()
|
|
threshold_layout.addWidget(QLabel("Threshold:"))
|
|
self.threshold_input = QLineEdit(str(self.settings["threshold"]))
|
|
self.threshold_input.textChanged.connect(self._on_threshold_changed)
|
|
threshold_layout.addWidget(self.threshold_input)
|
|
layout.addLayout(threshold_layout)
|
|
|
|
# Save button
|
|
save_btn = QPushButton("Save Settings")
|
|
save_btn.clicked.connect(self._save_settings)
|
|
layout.addWidget(save_btn)
|
|
|
|
layout.addStretch()
|
|
return widget
|
|
|
|
def _on_user_changed(self, text):
|
|
self.settings["username"] = text
|
|
|
|
def _on_enabled_changed(self, checked):
|
|
self.settings["enabled"] = checked
|
|
|
|
def _on_threshold_changed(self, text):
|
|
try:
|
|
self.settings["threshold"] = int(text)
|
|
except ValueError:
|
|
pass
|
|
|
|
def _save_settings(self):
|
|
self.save_data("settings", self.settings)
|
|
self.notify_success("Settings Saved", "Your settings have been saved.")
|
|
|
|
def shutdown(self):
|
|
self.save_data("settings", self.settings)
|
|
```
|
|
|
|
---
|
|
|
|
## Working with Events
|
|
|
|
### Subscribe to Loot Events
|
|
|
|
```python
|
|
def initialize(self):
|
|
"""Subscribe to loot events."""
|
|
from core.event_bus import LootEvent
|
|
|
|
self.loot_subscription = self.subscribe_typed(
|
|
LootEvent,
|
|
self.on_loot_received,
|
|
replay_last=10 # Get last 10 events immediately
|
|
)
|
|
|
|
def on_loot_received(self, event):
|
|
"""Handle loot event."""
|
|
print(f"Received loot from {event.mob_name}")
|
|
print(f"Items: {event.items}")
|
|
print(f"Total TT: {event.total_tt_value}")
|
|
|
|
# Update UI
|
|
self.total_loot += event.total_tt_value
|
|
self.update_display()
|
|
|
|
def shutdown(self):
|
|
"""Unsubscribe on shutdown."""
|
|
self.unsubscribe_typed(self.loot_subscription)
|
|
```
|
|
|
|
### Subscribe to Skill Gains
|
|
|
|
```python
|
|
def initialize(self):
|
|
"""Subscribe to skill gain events."""
|
|
from core.event_bus import SkillGainEvent
|
|
|
|
# Subscribe to specific skills
|
|
self.subscribe_typed(
|
|
SkillGainEvent,
|
|
self.on_skill_gain,
|
|
skill_names=["Rifle", "Pistol", "Melee"]
|
|
)
|
|
|
|
def on_skill_gain(self, event):
|
|
"""Handle skill gain."""
|
|
print(f"{event.skill_name} increased by {event.gain_amount}")
|
|
print(f"New value: {event.skill_value}")
|
|
```
|
|
|
|
### Subscribe to Damage Events
|
|
|
|
```python
|
|
def initialize(self):
|
|
"""Subscribe to high damage hits."""
|
|
from core.event_bus import DamageEvent
|
|
|
|
# Only events with damage > 100
|
|
self.subscribe_typed(
|
|
DamageEvent,
|
|
self.on_big_hit,
|
|
min_damage=100
|
|
)
|
|
|
|
def on_big_hit(self, event):
|
|
"""Handle big damage hit."""
|
|
print(f"Big hit! {event.damage_amount} damage")
|
|
print(f"Critical: {event.is_critical}")
|
|
print(f"Target: {event.target_name}")
|
|
```
|
|
|
|
### Publish Custom Events
|
|
|
|
```python
|
|
def track_my_event(self, data):
|
|
"""Publish a custom event."""
|
|
from core.event_bus import SystemEvent
|
|
|
|
self.publish_typed(SystemEvent(
|
|
message=f"Custom event: {data}",
|
|
severity="info"
|
|
))
|
|
```
|
|
|
|
---
|
|
|
|
## Screen Capture & OCR
|
|
|
|
### Capture Screen Region
|
|
|
|
```python
|
|
def capture_game_window(self):
|
|
"""Capture the game window area."""
|
|
# Get EU window info
|
|
window = self.get_eu_window()
|
|
if not window:
|
|
return None
|
|
|
|
# Capture specific region
|
|
screenshot = self.capture_region(
|
|
x=window['x'] + 100,
|
|
y=window['y'] + 50,
|
|
width=400,
|
|
height=300
|
|
)
|
|
|
|
return screenshot
|
|
```
|
|
|
|
### OCR Text from Screen
|
|
|
|
```python
|
|
def read_game_text(self):
|
|
"""Read text from game screen using OCR."""
|
|
# Capture and OCR
|
|
result = self.ocr_capture(region=(100, 100, 400, 300))
|
|
|
|
if result:
|
|
text = result['text']
|
|
confidence = result['confidence']
|
|
|
|
print(f"OCR Result: {text}")
|
|
print(f"Confidence: {confidence}")
|
|
|
|
return text
|
|
|
|
return None
|
|
```
|
|
|
|
### OCR with Post-Processing
|
|
|
|
```python
|
|
import re
|
|
|
|
def read_coordinates(self):
|
|
"""Read coordinates from game UI."""
|
|
result = self.ocr_capture()
|
|
|
|
if not result:
|
|
return None
|
|
|
|
text = result['text']
|
|
|
|
# Extract numbers (coordinates)
|
|
numbers = re.findall(r'\d+', text)
|
|
|
|
if len(numbers) >= 2:
|
|
return {
|
|
'x': int(numbers[0]),
|
|
'y': int(numbers[1])
|
|
}
|
|
|
|
return None
|
|
```
|
|
|
|
---
|
|
|
|
## Nexus API Recipes
|
|
|
|
### Search for Items
|
|
|
|
```python
|
|
def search_weapons(self, query):
|
|
"""Search for weapons in Nexus API."""
|
|
results = self.nexus_search(
|
|
query=query,
|
|
entity_type="weapons",
|
|
limit=20
|
|
)
|
|
|
|
for item in results:
|
|
print(f"{item['name']} ({item['type']})")
|
|
|
|
return results
|
|
```
|
|
|
|
### Get Item Details
|
|
|
|
```python
|
|
def get_weapon_stats(self, item_id):
|
|
"""Get detailed weapon information."""
|
|
details = self.nexus_get_item_details(item_id)
|
|
|
|
if details:
|
|
print(f"Name: {details['name']}")
|
|
print(f"Damage: {details.get('damage', 'N/A')}")
|
|
print(f"Range: {details.get('range', 'N/A')}m")
|
|
print(f"TT Value: {details.get('tt_value', 'N/A')} PED")
|
|
|
|
return details
|
|
```
|
|
|
|
### Get Market Data
|
|
|
|
```python
|
|
def check_market_price(self, item_id):
|
|
"""Check current market price."""
|
|
market = self.nexus_get_market_data(item_id)
|
|
|
|
if market:
|
|
markup = market.get('current_markup')
|
|
volume = market.get('volume_24h')
|
|
|
|
print(f"Current markup: {markup}%")
|
|
print(f"24h volume: {volume}")
|
|
|
|
return market
|
|
|
|
return None
|
|
```
|
|
|
|
### Batch Operations
|
|
|
|
```python
|
|
def analyze_items(self, item_ids):
|
|
"""Analyze multiple items efficiently."""
|
|
results = {}
|
|
|
|
for item_id in item_ids:
|
|
details = self.nexus_get_item_details(item_id)
|
|
market = self.nexus_get_market_data(item_id)
|
|
|
|
results[item_id] = {
|
|
'details': details,
|
|
'market': market
|
|
}
|
|
|
|
return results
|
|
```
|
|
|
|
---
|
|
|
|
## Data Persistence
|
|
|
|
### Save/Load Plugin Data
|
|
|
|
```python
|
|
def save_session(self, session_data):
|
|
"""Save hunting session data."""
|
|
self.save_data("current_session", {
|
|
'start_time': session_data['start'],
|
|
'total_loot': session_data['loot'],
|
|
'mobs_killed': session_data['kills'],
|
|
'items': session_data['items']
|
|
})
|
|
|
|
def load_session(self):
|
|
"""Load hunting session data."""
|
|
return self.load_data("current_session", {
|
|
'start_time': None,
|
|
'total_loot': 0,
|
|
'mobs_killed': 0,
|
|
'items': []
|
|
})
|
|
```
|
|
|
|
### Manage Multiple Data Keys
|
|
|
|
```python
|
|
def initialize(self):
|
|
"""Initialize with multiple data keys."""
|
|
# Settings
|
|
self.config = self.load_data("config", self.default_config())
|
|
|
|
# Statistics
|
|
self.stats = self.load_data("stats", self.default_stats())
|
|
|
|
# History
|
|
self.history = self.load_data("history", [])
|
|
|
|
def default_config(self):
|
|
return {
|
|
'enabled': True,
|
|
'volume': 1.0,
|
|
'theme': 'dark'
|
|
}
|
|
|
|
def default_stats(self):
|
|
return {
|
|
'total_sessions': 0,
|
|
'total_loot': 0,
|
|
'playtime_hours': 0
|
|
}
|
|
|
|
def shutdown(self):
|
|
"""Save all data on shutdown."""
|
|
self.save_data("config", self.config)
|
|
self.save_data("stats", self.stats)
|
|
self.save_data("history", self.history)
|
|
```
|
|
|
|
---
|
|
|
|
## Background Tasks
|
|
|
|
### Simple Background Task
|
|
|
|
```python
|
|
def start_background_work(self):
|
|
"""Run function in background."""
|
|
def heavy_computation(data):
|
|
# This runs in a background thread
|
|
result = process_large_dataset(data)
|
|
return result
|
|
|
|
task_id = self.run_in_background(
|
|
heavy_computation,
|
|
self.large_dataset,
|
|
priority='normal',
|
|
on_complete=self.on_work_done,
|
|
on_error=self.on_work_error
|
|
)
|
|
|
|
def on_work_done(self, result):
|
|
"""Called when background work completes."""
|
|
self.result_label.setText(f"Done: {result}")
|
|
|
|
def on_work_error(self, error):
|
|
"""Called on error."""
|
|
self.status_label.setText(f"Error: {error}")
|
|
```
|
|
|
|
### Periodic Background Task
|
|
|
|
```python
|
|
def initialize(self):
|
|
"""Start periodic data refresh."""
|
|
# Refresh every 30 seconds
|
|
self.schedule_task(
|
|
delay_ms=0, # Start immediately
|
|
func=self.refresh_data,
|
|
periodic=True, # Repeat
|
|
interval_ms=30000, # Every 30 seconds
|
|
on_complete=self.update_display
|
|
)
|
|
|
|
def refresh_data(self):
|
|
"""Fetch fresh data."""
|
|
# This runs periodically in background
|
|
return fetch_from_api()
|
|
```
|
|
|
|
### Cancelable Task
|
|
|
|
```python
|
|
def start_long_operation(self):
|
|
"""Start operation that can be cancelled."""
|
|
self.current_task = self.run_in_background(
|
|
self.long_running_task,
|
|
on_complete=self.on_complete
|
|
)
|
|
|
|
# Enable cancel button
|
|
self.cancel_btn.setEnabled(True)
|
|
|
|
def cancel_operation(self):
|
|
"""Cancel the running operation."""
|
|
if hasattr(self, 'current_task'):
|
|
self.cancel_task(self.current_task)
|
|
self.status_label.setText("Cancelled")
|
|
```
|
|
|
|
---
|
|
|
|
## UI Components
|
|
|
|
### Styled Card Widget
|
|
|
|
```python
|
|
from PyQt6.QtWidgets import QFrame, QVBoxLayout, QLabel
|
|
|
|
def create_card(self, title, content):
|
|
"""Create a styled card widget."""
|
|
card = QFrame()
|
|
card.setStyleSheet("""
|
|
QFrame {
|
|
background-color: #2a2a2a;
|
|
border: 1px solid #444;
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
}
|
|
""")
|
|
|
|
layout = QVBoxLayout(card)
|
|
|
|
title_label = QLabel(title)
|
|
title_label.setStyleSheet("font-weight: bold; color: #4a9eff;")
|
|
layout.addWidget(title_label)
|
|
|
|
content_label = QLabel(content)
|
|
content_label.setStyleSheet("color: rgba(255,255,255,200);")
|
|
content_label.setWordWrap(True)
|
|
layout.addWidget(content_label)
|
|
|
|
return card
|
|
```
|
|
|
|
### Progress Widget
|
|
|
|
```python
|
|
from PyQt6.QtWidgets import QProgressBar, QLabel, QVBoxLayout, QWidget
|
|
|
|
def create_progress_widget(self):
|
|
"""Create a progress display widget."""
|
|
widget = QWidget()
|
|
layout = QVBoxLayout(widget)
|
|
|
|
self.progress_label = QLabel("Ready")
|
|
layout.addWidget(self.progress_label)
|
|
|
|
self.progress_bar = QProgressBar()
|
|
self.progress_bar.setStyleSheet("""
|
|
QProgressBar {
|
|
background-color: #333;
|
|
border-radius: 4px;
|
|
height: 8px;
|
|
}
|
|
QProgressBar::chunk {
|
|
background-color: #4a9eff;
|
|
border-radius: 4px;
|
|
}
|
|
""")
|
|
layout.addWidget(self.progress_bar)
|
|
|
|
return widget
|
|
|
|
def update_progress(self, value, message):
|
|
"""Update progress display."""
|
|
self.progress_bar.setValue(value)
|
|
self.progress_label.setText(message)
|
|
```
|
|
|
|
### Data Table
|
|
|
|
```python
|
|
from PyQt6.QtWidgets import QTableWidget, QTableWidgetItem
|
|
|
|
def create_data_table(self, headers):
|
|
"""Create a data table."""
|
|
table = QTableWidget()
|
|
table.setColumnCount(len(headers))
|
|
table.setHorizontalHeaderLabels(headers)
|
|
table.horizontalHeader().setStretchLastSection(True)
|
|
table.setStyleSheet("""
|
|
QTableWidget {
|
|
background-color: #2a2a2a;
|
|
border: 1px solid #444;
|
|
}
|
|
QHeaderView::section {
|
|
background-color: #333;
|
|
color: white;
|
|
padding: 5px;
|
|
}
|
|
""")
|
|
return table
|
|
|
|
def populate_table(self, table, data):
|
|
"""Populate table with data."""
|
|
table.setRowCount(len(data))
|
|
|
|
for row, item in enumerate(data):
|
|
for col, value in enumerate(item):
|
|
table.setItem(row, col, QTableWidgetItem(str(value)))
|
|
```
|
|
|
|
---
|
|
|
|
## Advanced Patterns
|
|
|
|
### Singleton Pattern
|
|
|
|
```python
|
|
class MyService:
|
|
"""Singleton service example."""
|
|
|
|
_instance = None
|
|
|
|
def __new__(cls):
|
|
if cls._instance is None:
|
|
cls._instance = super().__new__(cls)
|
|
cls._instance._initialized = False
|
|
return cls._instance
|
|
|
|
def __init__(self):
|
|
if self._initialized:
|
|
return
|
|
self._initialized = True
|
|
# Initialize here
|
|
```
|
|
|
|
### Plugin Communication
|
|
|
|
```python
|
|
def register_api_endpoint(self):
|
|
"""Register an API for other plugins."""
|
|
from core.plugin_api import APIEndpoint, APIType
|
|
|
|
endpoint = APIEndpoint(
|
|
name="get_my_data",
|
|
api_type=APIType.CUSTOM,
|
|
description="Get data from this plugin",
|
|
handler=self.provide_data,
|
|
plugin_id=self._plugin_id,
|
|
version="1.0.0"
|
|
)
|
|
|
|
self.register_api(endpoint)
|
|
|
|
def use_other_plugin_api(self):
|
|
"""Call API from another plugin."""
|
|
result = self.call_api("other_plugin", "their_api", arg1, arg2)
|
|
return result
|
|
```
|
|
|
|
### Error Handling Pattern
|
|
|
|
```python
|
|
def safe_operation(self):
|
|
"""Operation with proper error handling."""
|
|
try:
|
|
result = self.risky_operation()
|
|
return result
|
|
except NetworkError as e:
|
|
self.log_warning(f"Network error: {e}")
|
|
self.notify_warning("Connection Issue", "Please check your internet connection.")
|
|
except ValueError as e:
|
|
self.log_error(f"Invalid value: {e}")
|
|
self.notify_error("Error", f"Invalid input: {e}")
|
|
except Exception as e:
|
|
self.log_exception(f"Unexpected error: {e}")
|
|
self.notify_error("Error", "An unexpected error occurred.")
|
|
|
|
return None
|
|
```
|
|
|
|
### Context Manager for Resources
|
|
|
|
```python
|
|
from contextlib import contextmanager
|
|
|
|
@contextmanager
|
|
def temp_file(self, suffix='.tmp'):
|
|
"""Context manager for temporary files."""
|
|
import tempfile
|
|
|
|
fd, path = tempfile.mkstemp(suffix=suffix)
|
|
try:
|
|
os.close(fd)
|
|
yield path
|
|
finally:
|
|
if os.path.exists(path):
|
|
os.remove(path)
|
|
|
|
def process_with_temp(self, data):
|
|
"""Use temporary file safely."""
|
|
with self.temp_file() as temp_path:
|
|
with open(temp_path, 'w') as f:
|
|
f.write(data)
|
|
# Process temp file
|
|
result = self.process_file(temp_path)
|
|
# File automatically cleaned up
|
|
return result
|
|
```
|
|
|
|
---
|
|
|
|
## Complete Example: Mini Plugin
|
|
|
|
```python
|
|
"""
|
|
MiniTracker - Complete plugin example
|
|
Tracks a simple counter with persistent storage.
|
|
"""
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout,
|
|
QLabel, QPushButton, QSpinBox
|
|
)
|
|
from plugins.base_plugin import BasePlugin
|
|
|
|
|
|
class MiniTrackerPlugin(BasePlugin):
|
|
"""Simple counter tracker example."""
|
|
|
|
name = "Mini Tracker"
|
|
version = "1.0.0"
|
|
author = "Example"
|
|
description = "Simple counter demonstration"
|
|
hotkey = "ctrl+shift+m"
|
|
|
|
def initialize(self):
|
|
"""Load saved state."""
|
|
self.count = self.load_data("count", 0)
|
|
self.increment = self.load_data("increment", 1)
|
|
self.log_info(f"Loaded count: {self.count}")
|
|
|
|
def get_ui(self):
|
|
"""Create UI."""
|
|
widget = QWidget()
|
|
layout = QVBoxLayout(widget)
|
|
layout.setSpacing(15)
|
|
|
|
# Counter display
|
|
self.counter_label = QLabel(str(self.count))
|
|
self.counter_label.setStyleSheet("""
|
|
font-size: 48px;
|
|
font-weight: bold;
|
|
color: #4a9eff;
|
|
""")
|
|
self.counter_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
layout.addWidget(self.counter_label)
|
|
|
|
# Controls
|
|
btn_layout = QHBoxLayout()
|
|
|
|
decrement_btn = QPushButton("-")
|
|
decrement_btn.clicked.connect(self.decrement)
|
|
btn_layout.addWidget(decrement_btn)
|
|
|
|
increment_btn = QPushButton("+")
|
|
increment_btn.clicked.connect(self.increment_count)
|
|
btn_layout.addWidget(increment_btn)
|
|
|
|
layout.addLayout(btn_layout)
|
|
|
|
# Increment setting
|
|
setting_layout = QHBoxLayout()
|
|
setting_layout.addWidget(QLabel("Increment by:"))
|
|
|
|
self.increment_spin = QSpinBox()
|
|
self.increment_spin.setRange(1, 100)
|
|
self.increment_spin.setValue(self.increment)
|
|
self.increment_spin.valueChanged.connect(self._on_increment_changed)
|
|
setting_layout.addWidget(self.increment_spin)
|
|
|
|
layout.addLayout(setting_layout)
|
|
|
|
# Reset button
|
|
reset_btn = QPushButton("Reset Counter")
|
|
reset_btn.clicked.connect(self.reset)
|
|
layout.addWidget(reset_btn)
|
|
|
|
layout.addStretch()
|
|
return widget
|
|
|
|
def increment_count(self):
|
|
"""Increment counter."""
|
|
self.count += self.increment
|
|
self._update_display()
|
|
self.save_data("count", self.count)
|
|
self.record_event("counter_incremented", {"value": self.count})
|
|
|
|
def decrement(self):
|
|
"""Decrement counter."""
|
|
self.count -= self.increment
|
|
self._update_display()
|
|
self.save_data("count", self.count)
|
|
|
|
def reset(self):
|
|
"""Reset counter."""
|
|
self.count = 0
|
|
self._update_display()
|
|
self.save_data("count", self.count)
|
|
self.notify_info("Reset", "Counter has been reset.")
|
|
|
|
def _on_increment_changed(self, value):
|
|
"""Handle increment change."""
|
|
self.increment = value
|
|
self.save_data("increment", value)
|
|
|
|
def _update_display(self):
|
|
"""Update counter display."""
|
|
self.counter_label.setText(str(self.count))
|
|
|
|
def on_hotkey(self):
|
|
"""Handle hotkey."""
|
|
self.increment_count()
|
|
self.notify_info("Mini Tracker", f"Count: {self.count}")
|
|
|
|
def shutdown(self):
|
|
"""Save on shutdown."""
|
|
self.save_data("count", self.count)
|
|
self.save_data("increment", self.increment)
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
### Common Tasks
|
|
|
|
| Task | Code |
|
|
|------|------|
|
|
| Log message | `self.log_info("message")` |
|
|
| Notify user | `self.notify_info("Title", "Message")` |
|
|
| Save data | `self.save_data("key", value)` |
|
|
| Load data | `self.load_data("key", default)` |
|
|
| Run in background | `self.run_in_background(func, on_complete=cb)` |
|
|
| Schedule task | `self.schedule_task(delay_ms, func, periodic=True)` |
|
|
| Get EU window | `self.get_eu_window()` |
|
|
| Capture screen | `self.ocr_capture(region=(x,y,w,h))` |
|
|
| Search Nexus | `self.nexus_search("query", "items")` |
|
|
| Play sound | `self.play_sound("hof")` |
|
|
|
|
---
|
|
|
|
Happy plugin development! 🚀
|