649 lines
18 KiB
Markdown
649 lines
18 KiB
Markdown
# Nexus API Usage Examples for Plugin Developers
|
|
|
|
> Practical examples for using the Entropia Nexus API in plugins
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Basic Search Examples](#basic-search-examples)
|
|
2. [Entity Type-Specific Searches](#entity-type-specific-searches)
|
|
3. [Item Details & Market Data](#item-details--market-data)
|
|
4. [Complete Plugin Examples](#complete-plugin-examples)
|
|
5. [Advanced Usage Patterns](#advanced-usage-patterns)
|
|
|
|
---
|
|
|
|
## Basic Search Examples
|
|
|
|
### Simple Item Search
|
|
|
|
```python
|
|
from plugins.base_plugin import BasePlugin
|
|
|
|
class MyPlugin(BasePlugin):
|
|
def find_weapons(self):
|
|
# Search for items containing "ArMatrix"
|
|
results = self.nexus_search("ArMatrix", entity_type="items")
|
|
|
|
for item in results:
|
|
print(f"Found: {item['name']} ({item['type']})")
|
|
```
|
|
|
|
### Search with Limit
|
|
|
|
```python
|
|
def find_top_results(self, query):
|
|
# Get up to 50 results
|
|
results = self.nexus_search(
|
|
query,
|
|
entity_type="items",
|
|
limit=50
|
|
)
|
|
return results
|
|
```
|
|
|
|
---
|
|
|
|
## Entity Type-Specific Searches
|
|
|
|
### Weapons
|
|
|
|
```python
|
|
def find_laser_weapons(self):
|
|
"""Search for laser weapons."""
|
|
results = self.nexus_search("laser", entity_type="weapons")
|
|
|
|
weapons = []
|
|
for item in results:
|
|
details = self.nexus_get_item_details(item['id'])
|
|
if details:
|
|
weapons.append({
|
|
'name': details['name'],
|
|
'damage': details.get('damage', 0),
|
|
'range': details.get('range', 0),
|
|
'decay': details.get('decay', 0)
|
|
})
|
|
|
|
return weapons
|
|
```
|
|
|
|
### Mobs/Creatures
|
|
|
|
```python
|
|
def find_mobs_by_name(self, name):
|
|
"""Search for creatures."""
|
|
results = self.nexus_search(name, entity_type="mobs")
|
|
|
|
mobs = []
|
|
for mob in results:
|
|
mobs.append({
|
|
'name': mob['name'],
|
|
'id': mob['id'],
|
|
'hitpoints': mob['data'].get('hitpoints', 'Unknown'),
|
|
'threat': mob['data'].get('threat', 'Unknown')
|
|
})
|
|
|
|
return mobs
|
|
|
|
# Usage
|
|
drakabas = self.find_mobs_by_name("Drakaba")
|
|
atrox = self.find_mobs_by_name("Atrox")
|
|
```
|
|
|
|
### Blueprints
|
|
|
|
```python
|
|
def find_crafting_blueprints(self, material_name):
|
|
"""Find blueprints that use a specific material."""
|
|
results = self.nexus_search(material_name, entity_type="blueprints")
|
|
|
|
blueprints = []
|
|
for bp in results:
|
|
details = self.nexus_get_item_details(bp['id'])
|
|
if details and 'materials' in details:
|
|
blueprints.append({
|
|
'name': details['name'],
|
|
'materials': details['materials'],
|
|
'qr': details.get('qr', 1.0)
|
|
})
|
|
|
|
return blueprints
|
|
```
|
|
|
|
### Locations
|
|
|
|
```python
|
|
def find_teleporters(self, planet="Calypso"):
|
|
"""Find teleporters on a specific planet."""
|
|
results = self.nexus_search(planet, entity_type="teleporters")
|
|
|
|
teleporters = []
|
|
for tp in results:
|
|
data = tp['data']
|
|
teleporters.append({
|
|
'name': tp['name'],
|
|
'x': data.get('x'),
|
|
'y': data.get('y'),
|
|
'planet': data.get('planet', planet)
|
|
})
|
|
|
|
return teleporters
|
|
```
|
|
|
|
### Skills
|
|
|
|
```python
|
|
def find_combat_skills(self):
|
|
"""Search for combat-related skills."""
|
|
results = self.nexus_search("", entity_type="skills")
|
|
|
|
combat_skills = [
|
|
s for s in results
|
|
if 'combat' in s.get('category', '').lower()
|
|
]
|
|
|
|
return combat_skills
|
|
```
|
|
|
|
---
|
|
|
|
## Item Details & Market Data
|
|
|
|
### Get Full Item Information
|
|
|
|
```python
|
|
def analyze_item(self, item_id):
|
|
"""Get complete item analysis."""
|
|
# Get basic details
|
|
details = self.nexus_get_item_details(item_id)
|
|
if not details:
|
|
return None
|
|
|
|
# Get market data
|
|
market = self.nexus_get_market_data(item_id)
|
|
|
|
analysis = {
|
|
'name': details['name'],
|
|
'category': details.get('category', 'Unknown'),
|
|
'tt_value': details.get('tt_value', 0),
|
|
'weight': details.get('weight', 0),
|
|
'decay': details.get('decay', 0),
|
|
}
|
|
|
|
# Add weapon stats if applicable
|
|
if 'damage' in details:
|
|
analysis['weapon_stats'] = {
|
|
'damage': details['damage'],
|
|
'range': details.get('range', 0),
|
|
'accuracy': details.get('accuracy', 0),
|
|
'ammo': details.get('ammo_consumption', 0)
|
|
}
|
|
|
|
# Add market info
|
|
if market:
|
|
analysis['market'] = {
|
|
'markup': market.get('current_markup', 0),
|
|
'volume_24h': market.get('volume_24h', 0),
|
|
'buy_orders': len(market.get('buy_orders', [])),
|
|
'sell_orders': len(market.get('sell_orders', []))
|
|
}
|
|
|
|
return analysis
|
|
```
|
|
|
|
### Market Price Monitoring
|
|
|
|
```python
|
|
def check_price_drops(self, watchlist):
|
|
"""Monitor items for price drops.
|
|
|
|
Args:
|
|
watchlist: List of {'item_id': str, 'max_price': float}
|
|
"""
|
|
deals = []
|
|
|
|
for watch in watchlist:
|
|
market = self.nexus_get_market_data(watch['item_id'])
|
|
if not market:
|
|
continue
|
|
|
|
current_price = market.get('current_markup', 0)
|
|
|
|
if current_price <= watch['max_price']:
|
|
deals.append({
|
|
'item_id': watch['item_id'],
|
|
'item_name': market.get('item_name', 'Unknown'),
|
|
'current_price': current_price,
|
|
'target_price': watch['max_price'],
|
|
'savings': watch['max_price'] - current_price
|
|
})
|
|
|
|
return deals
|
|
```
|
|
|
|
### Compare Item Stats
|
|
|
|
```python
|
|
def compare_weapons(self, weapon_ids):
|
|
"""Compare multiple weapons side by side."""
|
|
weapons = []
|
|
|
|
for wid in weapon_ids:
|
|
details = self.nexus_get_item_details(wid)
|
|
if details:
|
|
dpp = self.calculate_dpp(
|
|
details.get('damage', 0),
|
|
details.get('ammo_consumption', 0),
|
|
details.get('decay', 0)
|
|
)
|
|
|
|
weapons.append({
|
|
'name': details['name'],
|
|
'damage': details.get('damage', 0),
|
|
'range': details.get('range', 0),
|
|
'decay': details.get('decay', 0),
|
|
'dpp': dpp,
|
|
'tt': details.get('tt_value', 0)
|
|
})
|
|
|
|
# Sort by DPP (damage per pec)
|
|
return sorted(weapons, key=lambda w: w['dpp'], reverse=True)
|
|
```
|
|
|
|
---
|
|
|
|
## Complete Plugin Examples
|
|
|
|
### Weapon Comparison Plugin
|
|
|
|
```python
|
|
"""
|
|
Weapon Comparison Plugin
|
|
|
|
Compares weapons by DPP (Damage Per PEC) and other stats.
|
|
"""
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout,
|
|
QPushButton, QLineEdit, QTableWidget,
|
|
QTableWidgetItem, QLabel
|
|
)
|
|
from plugins.base_plugin import BasePlugin
|
|
|
|
|
|
class WeaponComparatorPlugin(BasePlugin):
|
|
name = "Weapon Comparator"
|
|
version = "1.0.0"
|
|
author = "EU-Utility"
|
|
description = "Compare weapons by DPP and stats"
|
|
hotkey = "ctrl+shift+w"
|
|
|
|
def initialize(self):
|
|
self.weapon_ids = []
|
|
|
|
def get_ui(self):
|
|
widget = QWidget()
|
|
layout = QVBoxLayout(widget)
|
|
|
|
# Search box
|
|
search_layout = QHBoxLayout()
|
|
self.search_input = QLineEdit()
|
|
self.search_input.setPlaceholderText("Search weapons...")
|
|
search_layout.addWidget(self.search_input)
|
|
|
|
add_btn = QPushButton("Add to Compare")
|
|
add_btn.clicked.connect(self.add_weapon)
|
|
search_layout.addWidget(add_btn)
|
|
|
|
layout.addLayout(search_layout)
|
|
|
|
# Results table
|
|
self.table = QTableWidget()
|
|
self.table.setColumnCount(6)
|
|
self.table.setHorizontalHeaderLabels([
|
|
"Name", "Damage", "Range", "Decay", "DPP", "TT Value"
|
|
])
|
|
layout.addWidget(self.table)
|
|
|
|
# Compare button
|
|
compare_btn = QPushButton("Compare")
|
|
compare_btn.clicked.connect(self.do_compare)
|
|
layout.addWidget(compare_btn)
|
|
|
|
return widget
|
|
|
|
def add_weapon(self):
|
|
query = self.search_input.text()
|
|
results = self.nexus_search(query, entity_type="weapons", limit=5)
|
|
|
|
if results:
|
|
# Add first result
|
|
self.weapon_ids.append(results[0]['id'])
|
|
self.search_input.clear()
|
|
self.search_input.setPlaceholderText(
|
|
f"Added {results[0]['name']} ({len(self.weapon_ids)} total)"
|
|
)
|
|
|
|
def do_compare(self):
|
|
if len(self.weapon_ids) < 2:
|
|
return
|
|
|
|
# Fetch and compare
|
|
weapons = []
|
|
for wid in self.weapon_ids:
|
|
details = self.nexus_get_item_details(wid)
|
|
if details:
|
|
dpp = self.calculate_dpp(
|
|
details.get('damage', 0),
|
|
details.get('ammo_consumption', 0),
|
|
details.get('decay', 0)
|
|
)
|
|
weapons.append({
|
|
'name': details['name'],
|
|
'damage': details.get('damage', 0),
|
|
'range': details.get('range', 0),
|
|
'decay': details.get('decay', 0),
|
|
'dpp': dpp,
|
|
'tt': details.get('tt_value', 0)
|
|
})
|
|
|
|
# Sort by DPP
|
|
weapons.sort(key=lambda w: w['dpp'], reverse=True)
|
|
|
|
# Display
|
|
self.table.setRowCount(len(weapons))
|
|
for i, w in enumerate(weapons):
|
|
self.table.setItem(i, 0, QTableWidgetItem(w['name']))
|
|
self.table.setItem(i, 1, QTableWidgetItem(f"{w['damage']:.1f}"))
|
|
self.table.setItem(i, 2, QTableWidgetItem(f"{w['range']:.0f}m"))
|
|
self.table.setItem(i, 3, QTableWidgetItem(f"{w['decay']:.2f}"))
|
|
self.table.setItem(i, 4, QTableWidgetItem(f"{w['dpp']:.2f}"))
|
|
self.table.setItem(i, 5, QTableWidgetItem(f"{w['tt']:.2f} PED"))
|
|
```
|
|
|
|
### Mob Info Plugin
|
|
|
|
```python
|
|
"""
|
|
Mob Information Plugin
|
|
|
|
Quick lookup for creature stats and locations.
|
|
"""
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout,
|
|
QLineEdit, QPushButton, QLabel
|
|
)
|
|
from plugins.base_plugin import BasePlugin
|
|
|
|
|
|
class MobInfoPlugin(BasePlugin):
|
|
name = "Mob Info"
|
|
version = "1.0.0"
|
|
author = "EU-Utility"
|
|
description = "Quick mob stats lookup"
|
|
hotkey = "ctrl+shift+m"
|
|
|
|
def get_ui(self):
|
|
widget = QWidget()
|
|
layout = QVBoxLayout(widget)
|
|
|
|
# Search
|
|
search_layout = QHBoxLayout()
|
|
self.search_input = QLineEdit()
|
|
self.search_input.setPlaceholderText("Enter mob name...")
|
|
self.search_input.returnPressed.connect(self.search_mob)
|
|
search_layout.addWidget(self.search_input)
|
|
|
|
search_btn = QPushButton("Search")
|
|
search_btn.clicked.connect(self.search_mob)
|
|
search_layout.addWidget(search_btn)
|
|
|
|
layout.addLayout(search_layout)
|
|
|
|
# Results
|
|
self.name_label = QLabel("Name: ")
|
|
self.hp_label = QLabel("HP: ")
|
|
self.damage_label = QLabel("Damage: ")
|
|
self.threat_label = QLabel("Threat: ")
|
|
self.planet_label = QLabel("Planet: ")
|
|
|
|
layout.addWidget(self.name_label)
|
|
layout.addWidget(self.hp_label)
|
|
layout.addWidget(self.damage_label)
|
|
layout.addWidget(self.threat_label)
|
|
layout.addWidget(self.planet_label)
|
|
|
|
layout.addStretch()
|
|
return widget
|
|
|
|
def search_mob(self):
|
|
query = self.search_input.text()
|
|
if not query:
|
|
return
|
|
|
|
results = self.nexus_search(query, entity_type="mobs", limit=1)
|
|
|
|
if not results:
|
|
self.name_label.setText("Mob not found")
|
|
return
|
|
|
|
mob = results[0]
|
|
data = mob.get('data', {})
|
|
|
|
self.name_label.setText(f"Name: {mob['name']}")
|
|
self.hp_label.setText(f"HP: {data.get('hitpoints', 'Unknown')}")
|
|
self.damage_label.setText(f"Damage: {data.get('damage', 'Unknown')}")
|
|
self.threat_label.setText(f"Threat: {data.get('threat', 'Unknown')}")
|
|
self.planet_label.setText(f"Planet: {data.get('planet', 'Unknown')}")
|
|
```
|
|
|
|
### Price Checker Plugin
|
|
|
|
```python
|
|
"""
|
|
Price Checker Plugin
|
|
|
|
Quick market price lookup for items.
|
|
"""
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout,
|
|
QLineEdit, QPushButton, QLabel, QFrame
|
|
)
|
|
from PyQt6.QtCore import Qt
|
|
from plugins.base_plugin import BasePlugin
|
|
|
|
|
|
class PriceCheckerPlugin(BasePlugin):
|
|
name = "Price Checker"
|
|
version = "1.0.0"
|
|
author = "EU-Utility"
|
|
description = "Quick market price lookup"
|
|
hotkey = "ctrl+shift+p"
|
|
|
|
def get_ui(self):
|
|
widget = QWidget()
|
|
layout = QVBoxLayout(widget)
|
|
|
|
# Search
|
|
search_layout = QHBoxLayout()
|
|
self.search_input = QLineEdit()
|
|
self.search_input.setPlaceholderText("Enter item name...")
|
|
self.search_input.returnPressed.connect(self.check_price)
|
|
search_layout.addWidget(self.search_input)
|
|
|
|
check_btn = QPushButton("Check Price")
|
|
check_btn.clicked.connect(self.check_price)
|
|
search_layout.addWidget(check_btn)
|
|
|
|
layout.addLayout(search_layout)
|
|
|
|
# Results frame
|
|
self.results_frame = QFrame()
|
|
results_layout = QVBoxLayout(self.results_frame)
|
|
|
|
self.item_name = QLabel("Item: ")
|
|
self.item_name.setStyleSheet("font-size: 14px; font-weight: bold;")
|
|
results_layout.addWidget(self.item_name)
|
|
|
|
self.markup_label = QLabel("Current Markup: ")
|
|
results_layout.addWidget(self.markup_label)
|
|
|
|
self.volume_label = QLabel("24h Volume: ")
|
|
results_layout.addWidget(self.volume_label)
|
|
|
|
self.range_label = QLabel("Price Range: ")
|
|
results_layout.addWidget(self.range_label)
|
|
|
|
layout.addWidget(self.results_frame)
|
|
layout.addStretch()
|
|
|
|
return widget
|
|
|
|
def check_price(self):
|
|
query = self.search_input.text()
|
|
if not query:
|
|
return
|
|
|
|
# Search for item
|
|
results = self.nexus_search(query, entity_type="items", limit=1)
|
|
|
|
if not results:
|
|
self.item_name.setText("Item not found")
|
|
return
|
|
|
|
item = results[0]
|
|
self.item_name.setText(f"Item: {item['name']}")
|
|
|
|
# Get market data
|
|
market = self.nexus_get_market_data(item['id'])
|
|
|
|
if not market:
|
|
self.markup_label.setText("No market data available")
|
|
return
|
|
|
|
markup = market.get('current_markup', 0)
|
|
avg_7d = market.get('avg_markup_7d', 0)
|
|
volume = market.get('volume_24h', 0)
|
|
|
|
self.markup_label.setText(f"Current Markup: {markup:.1f}%")
|
|
self.volume_label.setText(f"24h Volume: {volume}")
|
|
|
|
# Calculate range from orders
|
|
buy_orders = market.get('buy_orders', [])
|
|
sell_orders = market.get('sell_orders', [])
|
|
|
|
if buy_orders and sell_orders:
|
|
highest_buy = max(o['price'] for o in buy_orders)
|
|
lowest_sell = min(o['price'] for o in sell_orders)
|
|
self.range_label.setText(
|
|
f"Price Range: {highest_buy:.2f} - {lowest_sell:.2f} PED"
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Advanced Usage Patterns
|
|
|
|
### Caching Results
|
|
|
|
```python
|
|
class CachedSearchPlugin(BasePlugin):
|
|
def initialize(self):
|
|
self._cache = {}
|
|
self._cache_ttl = 300 # 5 minutes
|
|
|
|
def cached_search(self, query, entity_type="items"):
|
|
"""Search with local caching."""
|
|
cache_key = f"{entity_type}:{query}"
|
|
now = time.time()
|
|
|
|
# Check cache
|
|
if cache_key in self._cache:
|
|
result, timestamp = self._cache[cache_key]
|
|
if now - timestamp < self._cache_ttl:
|
|
return result
|
|
|
|
# Fetch fresh
|
|
results = self.nexus_search(query, entity_type)
|
|
self._cache[cache_key] = (results, now)
|
|
|
|
return results
|
|
```
|
|
|
|
### Batch Processing
|
|
|
|
```python
|
|
def analyze_multiple_items(self, item_names):
|
|
"""Process multiple items efficiently."""
|
|
analyses = []
|
|
|
|
for name in item_names:
|
|
# Search
|
|
results = self.nexus_search(name, entity_type="items", limit=1)
|
|
if not results:
|
|
continue
|
|
|
|
# Get details
|
|
details = self.nexus_get_item_details(results[0]['id'])
|
|
if not details:
|
|
continue
|
|
|
|
# Get market
|
|
market = self.nexus_get_market_data(results[0]['id'])
|
|
|
|
analyses.append({
|
|
'search_name': name,
|
|
'found_name': details['name'],
|
|
'tt_value': details.get('tt_value', 0),
|
|
'markup': market.get('current_markup', 0) if market else 0
|
|
})
|
|
|
|
return analyses
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
```python
|
|
def safe_search(self, query, entity_type="items"):
|
|
"""Search with error handling."""
|
|
try:
|
|
if not self.nexus_is_available():
|
|
print("Nexus API not available")
|
|
return []
|
|
|
|
results = self.nexus_search(query, entity_type)
|
|
return results
|
|
|
|
except Exception as e:
|
|
print(f"Search error: {e}")
|
|
return []
|
|
|
|
def safe_get_details(self, item_id):
|
|
"""Get details with fallback."""
|
|
try:
|
|
details = self.nexus_get_item_details(item_id)
|
|
return details or {'name': 'Unknown', 'id': item_id}
|
|
except Exception as e:
|
|
print(f"Details error: {e}")
|
|
return {'name': 'Error', 'id': item_id}
|
|
```
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [NEXUS_API_REFERENCE.md](./NEXUS_API_REFERENCE.md) - Complete API documentation
|
|
- [NEXUS_LINKTREE.md](./NEXUS_LINKTREE.md) - URL and endpoint reference
|
|
- [Plugin Base Class](../plugins/base_plugin.py) - Available plugin methods
|
|
|
|
---
|
|
|
|
## Tips & Best Practices
|
|
|
|
1. **Always check for None**: `nexus_get_item_details()` and `nexus_get_market_data()` can return None
|
|
2. **Use try/except**: Wrap API calls to handle network errors gracefully
|
|
3. **Cache results**: For frequently accessed data, implement local caching
|
|
4. **Respect rate limits**: Don't make too many requests in rapid succession
|
|
5. **Check availability**: Use `nexus_is_available()` before making calls
|
|
6. **Handle both field formats**: API returns both `name` and `Name` - check both
|