895 lines
18 KiB
Markdown
895 lines
18 KiB
Markdown
# EU-Utility Complete API Documentation
|
|
## Version 2.1.0
|
|
|
|
---
|
|
|
|
## 📖 Table of Contents
|
|
|
|
1. [Overview](#overview)
|
|
2. [Core APIs](#core-apis)
|
|
3. [Plugin API](#plugin-api)
|
|
4. [Widget API](#widget-api)
|
|
5. [External API](#external-api)
|
|
6. [Nexus API Integration](#nexus-api-integration)
|
|
7. [Event System](#event-system)
|
|
8. [Data Storage](#data-storage)
|
|
9. [Security](#security)
|
|
10. [Examples](#examples)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
EU-Utility provides a three-tier API architecture:
|
|
|
|
| API | Purpose | Audience |
|
|
|-----|---------|----------|
|
|
| **PluginAPI** | Access core services | Plugin developers |
|
|
| **WidgetAPI** | Create overlay widgets | Widget developers |
|
|
| **ExternalAPI** | Third-party integrations | External apps |
|
|
|
|
---
|
|
|
|
## Core APIs
|
|
|
|
### Service Locator
|
|
|
|
```python
|
|
from core.api import get_api, get_widget_api, get_external_api
|
|
|
|
# Get APIs
|
|
plugin_api = get_api()
|
|
widget_api = get_widget_api()
|
|
external_api = get_external_api()
|
|
```
|
|
|
|
### Available Services
|
|
|
|
| Service | Method | Description |
|
|
|---------|--------|-------------|
|
|
| Log Reader | `get_log_reader()` | Read game chat logs |
|
|
| Window Manager | `get_window_manager()` | Control EU window |
|
|
| OCR | `get_ocr_service()` | Text recognition |
|
|
| Screenshot | `get_screenshot_service()` | Screen capture |
|
|
| Nexus API | `get_nexus_api()` | Item database |
|
|
| HTTP Client | `get_http_client()` | Web requests |
|
|
| Audio | `get_audio_manager()` | Sound playback |
|
|
| Notifications | `get_notification_manager()` | Toast notifications |
|
|
| Clipboard | `get_clipboard_manager()` | Copy/paste |
|
|
| Event Bus | `get_event_bus()` | Pub/sub events |
|
|
| Data Store | `get_data_store()` | Key-value storage |
|
|
| Task Manager | `get_task_manager()` | Background tasks |
|
|
|
|
---
|
|
|
|
## Plugin API
|
|
|
|
### Initialization
|
|
|
|
```python
|
|
from plugins.base_plugin import BasePlugin
|
|
from core.api import get_api
|
|
|
|
class MyPlugin(BasePlugin):
|
|
def initialize(self):
|
|
"""Called when plugin loads."""
|
|
self.api = get_api()
|
|
self.log_info(f"{self.name} initialized")
|
|
```
|
|
|
|
### Log Reader
|
|
|
|
```python
|
|
# Read last N log lines
|
|
lines = api.read_log_lines(100)
|
|
|
|
# Read since timestamp
|
|
from datetime import datetime, timedelta
|
|
recent = api.read_log_since(datetime.now() - timedelta(minutes=5))
|
|
|
|
# Read filtered by pattern
|
|
loot_lines = api.read_log_filtered(pattern="Loot:.*(Uber|Jackpot)")
|
|
```
|
|
|
|
**Returns:** `List[str]` - Log lines
|
|
|
|
### Window Manager
|
|
|
|
```python
|
|
# Get EU window info
|
|
window = api.get_eu_window()
|
|
if window:
|
|
print(f"Position: ({window['x']}, {window['y']})")
|
|
print(f"Size: {window['width']}x{window['height']}")
|
|
print(f"Focused: {window['is_focused']}")
|
|
|
|
# Check if EU is focused
|
|
if api.is_eu_focused():
|
|
api.play_sound("alert.wav")
|
|
|
|
# Bring EU to front
|
|
api.bring_eu_to_front()
|
|
|
|
# Get window screenshot
|
|
screenshot = api.capture_eu_window()
|
|
```
|
|
|
|
**Window Info Schema:**
|
|
```json
|
|
{
|
|
"x": 100,
|
|
"y": 100,
|
|
"width": 1920,
|
|
"height": 1080,
|
|
"is_focused": true,
|
|
"title": "Entropia Universe"
|
|
}
|
|
```
|
|
|
|
### OCR Service
|
|
|
|
```python
|
|
# Check if OCR is available
|
|
if api.ocr_available():
|
|
# Read text from screen region
|
|
text = api.recognize_text((100, 100, 200, 50))
|
|
print(f"Found: {text}")
|
|
|
|
# Read from EU window specifically
|
|
eu_text = api.recognize_eu_region("chat")
|
|
|
|
# Read with specific engine
|
|
text = api.recognize_text(
|
|
region=(100, 100, 200, 50),
|
|
engine="easyocr" # or "tesseract", "paddleocr"
|
|
)
|
|
```
|
|
|
|
**Parameters:**
|
|
- `region`: Tuple `(x, y, width, height)`
|
|
- `engine`: Optional OCR engine name
|
|
|
|
**Returns:** `str` - Recognized text
|
|
|
|
### Screenshot
|
|
|
|
```python
|
|
# Capture full screen
|
|
img = api.capture_screen()
|
|
|
|
# Capture region
|
|
img = api.capture_screen((0, 0, 1920, 1080))
|
|
|
|
# Save to file
|
|
img = api.capture_screen(save_path="screenshot.png")
|
|
|
|
# Capture EU window
|
|
img = api.capture_eu_window()
|
|
|
|
# Check availability
|
|
if api.screenshot_available():
|
|
img = api.capture_screen()
|
|
```
|
|
|
|
**Returns:** `PIL.Image` - Screenshot image
|
|
|
|
### Nexus API (Item Database)
|
|
|
|
```python
|
|
# Search items
|
|
items = api.search_items(
|
|
query="omegaton",
|
|
entity_type="weapons", # or "items", "mobs", "all"
|
|
limit=5
|
|
)
|
|
|
|
for item in items:
|
|
print(f"{item['name']}: {item['value']} PED")
|
|
|
|
# Get item details
|
|
details = api.get_item_details(item_id=12345)
|
|
|
|
# Get market data
|
|
market = api.get_market_data(item_id=12345)
|
|
print(f"Current: {market['current_price']} PED")
|
|
print(f"Markup: {market['markup']}%")
|
|
|
|
# Get blueprint info
|
|
bp = api.get_blueprint_details(bp_id=67890)
|
|
```
|
|
|
|
**Search Response Schema:**
|
|
```json
|
|
[
|
|
{
|
|
"id": "12345",
|
|
"name": "Omegaton M83 Predator",
|
|
"type": "weapon",
|
|
"category": "Rifle",
|
|
"value": 123.45,
|
|
"markup": 125.5,
|
|
"icon_url": "https://..."
|
|
}
|
|
]
|
|
```
|
|
|
|
### HTTP Client
|
|
|
|
```python
|
|
# GET request
|
|
result = api.http_get(
|
|
url="https://api.example.com/data",
|
|
params={"key": "value"},
|
|
cache=True, # Cache response
|
|
ttl=3600 # Cache for 1 hour
|
|
)
|
|
|
|
if result['success']:
|
|
data = result['data']
|
|
print(f"Status: {result['status_code']}")
|
|
|
|
# POST request
|
|
result = api.http_post(
|
|
url="https://api.example.com/save",
|
|
data={"key": "value"},
|
|
headers={"Authorization": "Bearer token"}
|
|
)
|
|
|
|
# With retry
|
|
result = api.http_get(
|
|
url="https://api.example.com/data",
|
|
retry=3,
|
|
backoff=True
|
|
)
|
|
```
|
|
|
|
**Response Schema:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {...},
|
|
"status_code": 200,
|
|
"cached": false,
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
### Audio
|
|
|
|
```python
|
|
# Play sound file
|
|
api.play_sound(
|
|
path="assets/sounds/alert.wav",
|
|
volume=0.7 # 0.0 to 1.0
|
|
)
|
|
|
|
# Play built-in sound
|
|
api.play_sound("success")
|
|
api.play_sound("error")
|
|
api.play_sound("notification")
|
|
|
|
# Simple beep
|
|
api.beep()
|
|
|
|
# Check availability
|
|
if api.audio_available():
|
|
api.play_sound("alert.wav")
|
|
```
|
|
|
|
### Notifications
|
|
|
|
```python
|
|
# Show toast notification
|
|
api.show_notification(
|
|
title="Loot Alert",
|
|
message="Found something valuable!",
|
|
duration=3000, # milliseconds
|
|
sound=True,
|
|
icon="loot" # or path to icon
|
|
)
|
|
|
|
# Show with actions
|
|
api.show_notification(
|
|
title="Mission Complete",
|
|
message="You finished the mission!",
|
|
actions=[
|
|
{"label": "View", "callback": on_view},
|
|
{"label": "Dismiss", "callback": on_dismiss}
|
|
]
|
|
)
|
|
|
|
# Update existing notification
|
|
notification_id = api.show_notification(...)
|
|
api.update_notification(
|
|
notification_id,
|
|
message="Updated message"
|
|
)
|
|
```
|
|
|
|
### Clipboard
|
|
|
|
```python
|
|
# Copy to clipboard
|
|
api.copy_to_clipboard("TT: 100 PED")
|
|
|
|
# Copy formatted
|
|
api.copy_to_clipboard(
|
|
text="Item: Omegaton",
|
|
rich_text="<b>Item:</b> Omegaton"
|
|
)
|
|
|
|
# Paste from clipboard
|
|
text = api.paste_from_clipboard()
|
|
|
|
# Check if has content
|
|
if api.clipboard_has_content():
|
|
text = api.paste_from_clipboard()
|
|
```
|
|
|
|
### Event Bus
|
|
|
|
```python
|
|
# Subscribe to events
|
|
def on_loot(event):
|
|
print(f"Loot: {event.data}")
|
|
|
|
sub_id = api.subscribe(
|
|
event_type="loot.received",
|
|
handler=on_loot
|
|
)
|
|
|
|
# Subscribe with filter
|
|
def on_valuable_loot(event):
|
|
if event.data['value'] > 100:
|
|
print(f"Uber loot: {event.data}")
|
|
|
|
api.subscribe(
|
|
event_type="loot.received",
|
|
handler=on_valuable_loot,
|
|
filter=lambda e: e.data.get('value', 0) > 100
|
|
)
|
|
|
|
# Subscribe once
|
|
api.subscribe_once(
|
|
event_type="skill.gain",
|
|
handler=on_skill_gain
|
|
)
|
|
|
|
# Unsubscribe
|
|
api.unsubscribe(sub_id)
|
|
|
|
# Publish event
|
|
api.publish(
|
|
event_type="my_plugin.event",
|
|
data={"key": "value"}
|
|
)
|
|
|
|
# Typed events
|
|
from core.event_bus import LootEvent
|
|
|
|
def on_loot_typed(event: LootEvent):
|
|
print(f"From {event.mob_name}: {event.total_tt}")
|
|
|
|
api.subscribe_typed(LootEvent, on_loot_typed)
|
|
```
|
|
|
|
**Event Types:**
|
|
- `loot.received` - Loot event
|
|
- `skill.gain` - Skill increase
|
|
- `global.recorded` - Global/HOF
|
|
- `mission.complete` - Mission finished
|
|
- `chat.message` - Chat message
|
|
- `window.focus` - Window focus change
|
|
|
|
### Data Store
|
|
|
|
```python
|
|
# Save data
|
|
api.save_data(
|
|
key="my_plugin.settings",
|
|
data={"theme": "dark", "volume": 0.8}
|
|
)
|
|
|
|
# Load data
|
|
settings = api.load_data(
|
|
key="my_plugin.settings",
|
|
default={"theme": "light", "volume": 1.0}
|
|
)
|
|
|
|
# Delete data
|
|
api.delete_data("my_plugin.settings")
|
|
|
|
# List keys
|
|
keys = api.list_data_keys(pattern="my_plugin.*")
|
|
|
|
# Check exists
|
|
if api.has_data("my_plugin.settings"):
|
|
settings = api.load_data("my_plugin.settings")
|
|
```
|
|
|
|
### Tasks
|
|
|
|
```python
|
|
# Run async task
|
|
task_id = api.run_task(
|
|
func=fetch_market_data,
|
|
args=(item_id,),
|
|
callback=on_data_received,
|
|
error_callback=on_error
|
|
)
|
|
|
|
# Cancel task
|
|
api.cancel_task(task_id)
|
|
|
|
# Schedule task
|
|
api.schedule_task(
|
|
func=check_prices,
|
|
interval=60, # seconds
|
|
repeat=True
|
|
)
|
|
|
|
# Run in background
|
|
api.run_in_background(
|
|
func=heavy_computation,
|
|
priority="low" # "high", "normal", "low"
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Widget API
|
|
|
|
### Creating Widgets
|
|
|
|
```python
|
|
from core.api import get_widget_api
|
|
|
|
widget_api = get_widget_api()
|
|
|
|
# Create overlay widget
|
|
widget = widget_api.create_widget(
|
|
name="Loot Widget",
|
|
size=(300, 200),
|
|
position=(100, 100),
|
|
draggable=True,
|
|
resizable=True,
|
|
always_on_top=True
|
|
)
|
|
|
|
# Set content
|
|
widget.set_content(my_qwidget)
|
|
|
|
# Show/hide
|
|
widget.show()
|
|
widget.hide()
|
|
|
|
# Update position
|
|
widget.move(200, 200)
|
|
widget.resize(400, 300)
|
|
|
|
# Close
|
|
widget.close()
|
|
```
|
|
|
|
### Widget Properties
|
|
|
|
```python
|
|
# Transparency
|
|
widget.set_opacity(0.8) # 0.0 to 1.0
|
|
|
|
# Click-through
|
|
widget.set_click_through(True)
|
|
|
|
# Snap to edges
|
|
widget.set_snap_to_edges(True, margin=10)
|
|
|
|
# Auto-hide
|
|
widget.set_auto_hide(
|
|
enabled=True,
|
|
hide_delay=3000,
|
|
show_on_hover=True
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## External API
|
|
|
|
### REST Endpoints
|
|
|
|
```python
|
|
from core.api import get_external_api
|
|
|
|
api = get_external_api()
|
|
|
|
# Start HTTP server
|
|
api.start_server(port=8080)
|
|
|
|
# Register endpoint
|
|
@api.endpoint("/loot/recent", methods=["GET"])
|
|
def get_recent_loot():
|
|
return {"loot": [...]}
|
|
|
|
# With authentication
|
|
@api.endpoint("/settings", methods=["GET", "POST"], auth_required=True)
|
|
def settings():
|
|
if request.method == "POST":
|
|
api.save_settings(request.json)
|
|
return api.load_settings()
|
|
```
|
|
|
|
### WebSocket
|
|
|
|
```python
|
|
# WebSocket endpoint
|
|
@api.websocket("/events")
|
|
async def events(websocket):
|
|
async for message in websocket:
|
|
await websocket.send({"echo": message})
|
|
```
|
|
|
|
---
|
|
|
|
## Nexus API Integration
|
|
|
|
### Entity Types
|
|
|
|
```python
|
|
from core.nexus_api import EntityType
|
|
|
|
# Available types
|
|
EntityType.ITEM # Items
|
|
EntityType.WEAPON # Weapons
|
|
EntityType.ARMOR # Armor
|
|
EntityType.MOB # Creatures
|
|
EntityType.BLUEPRINT # Blueprints
|
|
EntityType.MATERIAL # Materials
|
|
EntityType.LOCATION # Locations
|
|
EntityType.TELEPORTER # Teleporters
|
|
EntityType.SKILL # Skills
|
|
```
|
|
|
|
### Search
|
|
|
|
```python
|
|
nexus = get_nexus_api()
|
|
|
|
# Basic search
|
|
results = nexus.search(
|
|
query="omegaton",
|
|
entity_type=EntityType.WEAPON,
|
|
limit=10
|
|
)
|
|
|
|
# Advanced search
|
|
results = nexus.search(
|
|
query="rifle",
|
|
entity_type=EntityType.WEAPON,
|
|
filters={
|
|
"min_damage": 50,
|
|
"max_damage": 100,
|
|
"ammo_type": "blp"
|
|
},
|
|
sort_by="markup",
|
|
sort_order="desc",
|
|
limit=20
|
|
)
|
|
```
|
|
|
|
### Item Details
|
|
|
|
```python
|
|
# Get full item info
|
|
item = nexus.get_item(item_id=12345)
|
|
|
|
# Get market data
|
|
market = nexus.get_market_history(
|
|
item_id=12345,
|
|
days=30
|
|
)
|
|
|
|
# Get price alerts
|
|
alerts = nexus.get_price_alerts(item_id=12345)
|
|
```
|
|
|
|
### Blueprints
|
|
|
|
```python
|
|
# Get blueprint details
|
|
bp = nexus.get_blueprint(bp_id=67890)
|
|
|
|
# Get required materials
|
|
materials = nexus.get_bp_materials(bp_id=67890)
|
|
|
|
# Calculate crafting cost
|
|
cost = nexus.calculate_craft_cost(
|
|
bp_id=67890,
|
|
quantity=100,
|
|
include_markup=True
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Event System
|
|
|
|
### Event Structure
|
|
|
|
```python
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
|
|
@dataclass
|
|
class Event:
|
|
type: str
|
|
data: dict
|
|
timestamp: datetime
|
|
source: str
|
|
```
|
|
|
|
### Event Types Reference
|
|
|
|
| Event Type | Data Schema | Description |
|
|
|------------|-------------|-------------|
|
|
| `loot.received` | `{items: [], mob_name: str, total_tt: float}` | Loot received |
|
|
| `skill.gain` | `{skill: str, old_value: float, new_value: float}` | Skill increase |
|
|
| `global.recorded` | `{type: str, value: float, mob: str}` | Global/HOF |
|
|
| `mission.complete` | `{mission_id: str, name: str, rewards: []}` | Mission done |
|
|
| `chat.message` | `{channel: str, sender: str, message: str}` | Chat message |
|
|
| `window.focus` | `{window: str, is_focused: bool}` | Focus change |
|
|
|
|
---
|
|
|
|
## Security
|
|
|
|
### Permission Model
|
|
|
|
```python
|
|
# Request permissions in plugin manifest
|
|
permissions = [
|
|
"log_reader:read",
|
|
"overlay:create",
|
|
"data_store:write",
|
|
"network:external",
|
|
"ocr:read",
|
|
"clipboard:read",
|
|
"clipboard:write"
|
|
]
|
|
```
|
|
|
|
### Secure Data
|
|
|
|
```python
|
|
# Encrypt sensitive data
|
|
api.save_secure_data(
|
|
key="api_keys.nexus",
|
|
data="secret_key",
|
|
password=user_password
|
|
)
|
|
|
|
# Decrypt
|
|
data = api.load_secure_data(
|
|
key="api_keys.nexus",
|
|
password=user_password
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### Complete Plugin Example
|
|
|
|
```python
|
|
"""
|
|
Loot Tracker Plugin
|
|
Tracks hunting loot with analytics.
|
|
"""
|
|
|
|
from PyQt6.QtWidgets import *
|
|
from PyQt6.QtCore import *
|
|
from plugins.base_plugin import BasePlugin
|
|
from core.api import get_api
|
|
from core.event_bus import LootEvent
|
|
|
|
class LootTrackerPlugin(BasePlugin):
|
|
name = "Loot Tracker"
|
|
version = "2.0.0"
|
|
author = "ImpulsiveFPS"
|
|
description = "Track hunting loot with ROI analysis"
|
|
hotkey = "ctrl+shift+l"
|
|
|
|
def initialize(self):
|
|
self.api = get_api()
|
|
self.total_loot = 0.0
|
|
self.session_start = QDateTime.currentDateTime()
|
|
|
|
# Subscribe to loot events
|
|
self.loot_sub = self.api.subscribe_typed(
|
|
LootEvent,
|
|
self.on_loot
|
|
)
|
|
|
|
# Load history
|
|
self.history = self.api.load_data(
|
|
"loot_tracker.history",
|
|
default=[]
|
|
)
|
|
|
|
self.log_info("Loot Tracker initialized")
|
|
|
|
def on_loot(self, event: LootEvent):
|
|
"""Handle loot event."""
|
|
self.total_loot += event.total_tt
|
|
|
|
# Add to history
|
|
self.history.append({
|
|
"timestamp": event.timestamp.isoformat(),
|
|
"mob": event.mob_name,
|
|
"tt": event.total_tt,
|
|
"items": len(event.items)
|
|
})
|
|
|
|
# Save (keep last 1000)
|
|
self.api.save_data(
|
|
"loot_tracker.history",
|
|
self.history[-1000:]
|
|
)
|
|
|
|
# Update UI
|
|
self.update_display()
|
|
|
|
# Notify on big loot
|
|
if event.total_tt > 50:
|
|
self.api.show_notification(
|
|
"Big Loot!",
|
|
f"{event.mob_name}: {event.total_tt:.2f} PED",
|
|
sound=True
|
|
)
|
|
|
|
def get_ui(self):
|
|
"""Create plugin UI."""
|
|
widget = QWidget()
|
|
layout = QVBoxLayout(widget)
|
|
|
|
# Header
|
|
header = QLabel("Session Loot Tracker")
|
|
header.setStyleSheet("font-size: 18px; font-weight: bold;")
|
|
layout.addWidget(header)
|
|
|
|
# Stats
|
|
self.total_label = QLabel(f"Total: {self.total_loot:.2f} PED")
|
|
self.total_label.setStyleSheet("font-size: 24px; color: #10b981;")
|
|
layout.addWidget(self.total_label)
|
|
|
|
# Session time
|
|
self.time_label = QLabel("Session: 00:00:00")
|
|
layout.addWidget(self.time_label)
|
|
|
|
# History list
|
|
self.history_list = QListWidget()
|
|
layout.addWidget(self.history_list)
|
|
|
|
# Buttons
|
|
btn_layout = QHBoxLayout()
|
|
|
|
export_btn = QPushButton("Export")
|
|
export_btn.clicked.connect(self.export_data)
|
|
btn_layout.addWidget(export_btn)
|
|
|
|
clear_btn = QPushButton("Clear")
|
|
clear_btn.clicked.connect(self.clear_history)
|
|
btn_layout.addWidget(clear_btn)
|
|
|
|
layout.addLayout(btn_layout)
|
|
|
|
# Start update timer
|
|
self.timer = QTimer()
|
|
self.timer.timeout.connect(self.update_time)
|
|
self.timer.start(1000)
|
|
|
|
self.update_display()
|
|
return widget
|
|
|
|
def update_display(self):
|
|
"""Update UI with current stats."""
|
|
self.total_label.setText(
|
|
f"Total: {self.total_loot:.2f} PED"
|
|
)
|
|
|
|
# Update history list
|
|
self.history_list.clear()
|
|
for entry in reversed(self.history[-50:]):
|
|
text = f"{entry['mob']}: {entry['tt']:.2f} PED"
|
|
self.history_list.addItem(text)
|
|
|
|
def update_time(self):
|
|
"""Update session timer."""
|
|
elapsed = self.session_start.secsTo(
|
|
QDateTime.currentDateTime()
|
|
)
|
|
hours = elapsed // 3600
|
|
minutes = (elapsed % 3600) // 60
|
|
seconds = elapsed % 60
|
|
self.time_label.setText(
|
|
f"Session: {hours:02d}:{minutes:02d}:{seconds:02d}"
|
|
)
|
|
|
|
def export_data(self):
|
|
"""Export loot history to CSV."""
|
|
import csv
|
|
from pathlib import Path
|
|
|
|
path = Path.home() / "loot_history.csv"
|
|
with open(path, 'w', newline='') as f:
|
|
writer = csv.DictWriter(f,
|
|
fieldnames=['timestamp', 'mob', 'tt', 'items'])
|
|
writer.writeheader()
|
|
writer.writerows(self.history)
|
|
|
|
self.api.show_notification(
|
|
"Export Complete",
|
|
f"Saved to {path}"
|
|
)
|
|
|
|
def clear_history(self):
|
|
"""Clear loot history."""
|
|
self.history = []
|
|
self.total_loot = 0.0
|
|
self.api.delete_data("loot_tracker.history")
|
|
self.update_display()
|
|
|
|
def shutdown(self):
|
|
"""Cleanup on shutdown."""
|
|
self.api.unsubscribe(self.loot_sub)
|
|
self.api.save_data(
|
|
"loot_tracker.history",
|
|
self.history[-1000:]
|
|
)
|
|
self.log_info("Loot Tracker shutdown")
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Common Errors
|
|
|
|
```python
|
|
try:
|
|
result = api.http_get("https://api.example.com")
|
|
except APIError as e:
|
|
print(f"API Error: {e.code} - {e.message}")
|
|
except RateLimitError:
|
|
print("Rate limited, retrying...")
|
|
except ServiceNotAvailableError:
|
|
print("Service not available")
|
|
```
|
|
|
|
### Error Codes
|
|
|
|
| Code | Description |
|
|
|------|-------------|
|
|
| 1001 | Service not available |
|
|
| 1002 | Rate limit exceeded |
|
|
| 1003 | Permission denied |
|
|
| 1004 | Invalid parameters |
|
|
| 1005 | Network error |
|
|
| 1006 | Timeout |
|
|
|
|
---
|
|
|
|
## Version History
|
|
|
|
| Version | Changes |
|
|
|---------|---------|
|
|
| 2.1.0 | Added WidgetAPI, improved EventBus |
|
|
| 2.0.0 | Complete API redesign |
|
|
| 1.5.0 | Added Nexus API integration |
|
|
| 1.0.0 | Initial release |
|
|
|
|
---
|
|
|
|
*Complete API Documentation - EU-Utility v2.1.0*
|
|
*Generated: 2026-02-23*
|