Skip to main content

OSRS Bot Development SDK with game-native structure

Project description

Escape

A Python SDK for Old School RuneScape (OSRS) bot development that communicates with RuneLite via a high-performance bridge. The architecture mirrors the game's interface, making it intuitive for OSRS developers.

Requirements

  • Python 3.12+
  • Linux with inotify support (required for event system)
  • RuneLite with Escape plugin running

Features

  • Game-Native Structure: Directory layout mirrors OSRS client interface (tabs, interfaces, world)
  • Event-Driven Architecture: Zero-CPU inotify-based event system for real-time game state
  • Singleton Pattern: All modules are singletons with lazy initialization
  • Type-Safe: Full type hints with IDE autocomplete support
  • Auto-Generated Constants: ItemID, NpcID, ObjectID, InterfaceID, and more
  • 3D Projection: Convert local/world coordinates to screen coordinates

Installation

# Clone the repository
git clone https://github.com/escape/escape.git
cd escape

# Install with development dependencies
pip install -e ".[dev]"

# Install pre-commit hooks
pre-commit install

Quick Start

from escape.client import client

# Client auto-connects on import and starts event consumer
# All modules are singletons - no instantiation needed

# Access inventory
items = client.tabs.inventory.getItems()
for item in items:
    print(f"{item.name}: {item.quantity}")

# Check player state
pos = client.player.position
print(f"Player at: {pos}")

# Use bank interface
if client.interfaces.bank.isOpen():
    client.interfaces.bank.depositAll()

# Direct module access (alternative pattern)
from escape.tabs.inventory import inventory
from escape.input.mouse import mouse

inventory.clickItem(995)  # Click coins
mouse.leftClick(100, 200)

Architecture

Module Structure

escape/
├── client.py           # Main singleton - auto-connects to RuneLite bridge
├── globals.py          # Global accessors (getClient, getApi, getEventCache)
│
├── tabs/               # Side panel tabs (14 tabs)
│   ├── inventory.py    # Inventory management
│   ├── equipment.py    # Worn equipment
│   ├── skills.py       # Skill levels and XP
│   ├── prayer.py       # Prayer activation
│   ├── magic.py        # Spellbook
│   ├── combat.py       # Combat options
│   └── ...             # friends, settings, logout, etc.
│
├── interfaces/         # Overlay windows
│   ├── bank.py         # Bank interface
│   └── ...             # GE, shop, dialogue (planned)
│
├── world/              # 3D world entities
│   ├── ground_items.py # Items on the ground
│   └── projection.py   # Coordinate projection (local → screen)
│
├── input/              # OS-level input
│   ├── mouse.py        # Mouse control
│   ├── keyboard.py     # Keyboard input
│   └── runelite.py     # RuneLite window management
│
├── interactions/       # Game interactions
│   └── menu.py         # Right-click menu handling
│
├── player/             # Player state
│   └── player.py       # Position, stats, status
│
├── navigation/         # Movement systems
│   └── pathfinder.py   # Pathfinding (planned)
│
├── types/              # Type definitions
│   ├── item.py         # Item dataclass
│   ├── widget.py       # Widget mask builder
│   ├── packed_position.py  # Coordinate packing
│   └── ...
│
├── utilities/          # Helper functions
│   ├── timing.py       # sleep, waitUntil
│   └── text.py         # Text utilities
│
└── _internal/          # Internal implementation
    ├── api.py          # RuneLite bridge API
    ├── query_builder.py # Fluent query interface
    ├── cache/          # Event cache and state builder
    ├── events/         # Inotify event consumer
    └── resources/      # Varps, objects database

Singleton Pattern

All modules use the singleton pattern with __new__ + _init():

# Two equivalent access patterns:

# Via client namespace
from escape.client import client
client.tabs.inventory.getItems()

# Direct import
from escape.tabs.inventory import inventory
inventory.getItems()

Event System

The SDK uses an inotify-based event system for zero-CPU-usage when idle:

from escape.client import client

# Access cached game state (updated automatically)
tick = client.cache.tick
energy = client.cache.energy
position = client.cache.position

# Get recent events
chats = client.cache.getRecentEvents('chat_message', n=10)
stats = client.cache.getRecentEvents('stat_changed', n=5)

# Access varps/varbits
quest_points = client.cache.getVarp(101)

# Check data freshness
if client.cache.isFresh(max_age=1.0):
    print(f"Data age: {client.cache.getAge():.2f}s")

Event Channels:

Channel Type Channels Description
Ring Buffer varbit_changed, chat_message, item_container_changed, stat_changed, animation_changed Guaranteed delivery, keeps history
Latest State gametick, camera_changed, world_view_loaded, world_entity, menu_open, ground_items Current state only

Projection System

Convert local/world coordinates to screen coordinates:

from escape.world.projection import projection

# Auto-configured from events - just use it
screen_pos = projection.localToCanvasSingle(localX, localY, plane)
if screen_pos:
    screenX, screenY = screen_pos
    print(f"Screen position: ({screenX}, {screenY})")

# Batch projection
import numpy as np
xs = np.array([1000, 2000, 3000])
ys = np.array([1000, 2000, 3000])
screenX, screenY, valid = projection.localToCanvas(xs, ys, plane=0)

Query Builder

Direct RuneLite API access with fluent interface:

from escape.client import client

# Build and execute queries
q = client.query()
result = q.execute({
    "inventory": q.client.getItemContainer(93),
    "position": q.localPlayer.getWorldLocation(),
    "health": q.localPlayer.getHealthRatio()
})

Code Style

Naming Conventions

Element Convention Example
Functions/Methods camelCase getItems(), isInventoryFull()
Classes PascalCase Inventory, BankInterface
Constants UPPER_CASE MAX_INVENTORY_SIZE
Private _camelCase _internalHelper()

Dependencies

# Use dependency injection with global fallback
class Inventory:
    def __init__(self, client=None):
        self.client = client or getClient()

Development

Running Tests

pytest                           # All tests
pytest --cov=escape           # With coverage
pytest tests/test_inventory.py   # Specific file
pytest -k "test_bank"            # Pattern match

Linting and Formatting

ruff check .           # Lint
ruff check --fix .     # Auto-fix
ruff format .          # Format
python check_naming.py # Verify naming conventions

Pre-commit Hooks

pre-commit install       # Install hooks
pre-commit run --all-files  # Run manually

Generated Files

On first import, Escape downloads and generates:

~/.cache/escape/
├── generated/           # Proxy classes, constants
│   ├── constants/       # ItemID, NpcID, ObjectID, etc.
│   └── proxies/         # API proxy classes
└── data/                # Game data
    ├── api_data.json    # API metadata
    ├── varps.json       # Varp definitions
    └── objects.json     # Object database

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feat/new-feature)
  3. Follow naming conventions and code style
  4. Write tests for new functionality
  5. Commit with conventional commits (feat:, fix:, etc.)
  6. Open a Pull Request

See CONTRIBUTING.md for detailed guidelines.

License

MIT License - see LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

escape_sdk-1.0.1.tar.gz (179.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

escape_sdk-1.0.1-py3-none-any.whl (209.4 kB view details)

Uploaded Python 3

File details

Details for the file escape_sdk-1.0.1.tar.gz.

File metadata

  • Download URL: escape_sdk-1.0.1.tar.gz
  • Upload date:
  • Size: 179.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for escape_sdk-1.0.1.tar.gz
Algorithm Hash digest
SHA256 7f37ce0686a2b1e35e1f3fb3c776bff3dd372dbd3091b7ab24896f3ba8b986e7
MD5 37a390756d49866d772c97be1268c715
BLAKE2b-256 f3693f732abe247edbfc9f39109e07c2a2280bd08fbdd09831916b742c7a63d7

See more details on using hashes here.

File details

Details for the file escape_sdk-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: escape_sdk-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 209.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for escape_sdk-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bb6154e0358d9d18d61e1d69411441a2225548ef737a07711f2f82e0b8a9b334
MD5 fd4e134a7e6ca8ef9d270156acf9f454
BLAKE2b-256 4a88fd297f1ab54367f1883a802fa5e0811a858c10da56b2a0893a7f92498860

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page