dota2 Python Module

repository·master·Indexed 42 days ago

https://github.com/valvepython/dota2

A Python library for interacting with the Dota 2 Game Coordinator, built on top of the steam library. It provides a Dota2Client for programmatic access to game data and services, supporting Python 2.7+ and 3.4+. The module features event-driven patterns for handling responses, support for Protocol Buffer enums, and utilities for fetching player profile cards and managing GC connections.

Tokens
2.6K
Snippets
12
Records
15
Agent score
53%

What's inside dota2

  1. Overview of dota2 module

    master

    The dota2 module is a Python library designed for interacting with the Dota 2 Game Coordinator. It is built upon the steam module. If you have experience with node-dota2, the API patterns in this module will feel familiar.

    Compatibility:

    • Python 2.7+
    • Python 3.4+
  2. Work with events in Dota2Client

    master

    The Dota2Client uses an event-driven pattern similar to JavaScript's EventEmitter (powered by gevent-eventemitter). You can register callbacks, trigger them once, or block execution until an event occurs.

    Registering callbacks

    • @dota.on('event_name'): Decorator to register a persistent callback.
    • dota.on('event_name', callback): Register a persistent callback.
    • dota.once('event_name', callback): Register a callback that triggers only once.
    • dota.wait_event('event_name', timeout=...): A blocking call that waits for the event and returns its arguments. Warning: Always use the timeout parameter to prevent infinite blocking.

    Emitting events

    • dota.emit("event_name", *args): Manually trigger an event with optional arguments.
    # Registering
    @dota.on('my event')
    def do_stuff(a, b):
        print "Hey!"
    
    dota.on('my event', do_stuff)
    dota.once('my event', do_stuff)
    dota.wait_event('my event', timeout=10)
    
    # Emitting
    dota.emit("my event")
    dota.emit("my event", 1, [3,4,5])
  3. Configure console logging for debugging

    master

    To see internal debug messages (like connection attempts or emitted events), configure the standard Python logging module with the DEBUG level.

    import logging
    
    logging.basicConfig(
        format='[%(asctime)s] %(levelname)s %(name)s: %(message)s',
        level=logging.DEBUG
    )
  4. Initialize a Dota2Client with SteamClient

    master

    To interact with the Dota 2 Game Coordinator (GC), you must first initialize a SteamClient and then wrap it with a Dota2Client. The typical workflow involves listening for the logged_on event from the SteamClient to call dota.launch(), and then waiting for the ready event from the Dota2Client before performing any GC actions.

    Note that client.run_forever() is required to keep the event loop running.

    from steam.client import SteamClient
    from dota2.client import Dota2Client
    
    client = SteamClient()
    dota = Dota2Client(client)
    
    @client.on('logged_on')
    def start_dota():
        dota.launch()
    
    @dota.on('ready')
    def do_dota_stuff():
        # talk to GC
        pass
    
    client.cli_login()
    client.run_forever()
  5. Install the dota2 library

    master

    You can install the latest stable version of dota2 from PyPI using pip.

    If you want to use the current development version directly from GitHub, use the git+https URL. If you are updating an existing installation, use the --upgrade-strategy only-if-needed flag to ensure dependencies are only updated when necessary.

    # Install latest version from PYPI
    pip install dota2
    
    # Install the current dev version from github
    pip install git+https://github.com/ValvePython/dota2
    
    # If you are installing over an existing install
    pip install -U --upgrade-strategy only-if-needed git+https://github.com/ValvePython/dota2
  6. Fetch a player profile card

    master

    You can request player profile cards (containing stats like trophies, matches, or MMR) using dota.request_profile_card(account_id). There are two ways to handle the response:

    1. Using the 'profile_card' event

    This is the standard way. When the request completes, the profile_card event is emitted with the account_id and the profile_card data.

    2. Using a Job ID

    request_profile_card returns a job id. You can use dota.wait_msg(jobid, timeout=...) to block until the job completes. Note: When waiting for a job ID, the returned argument is only the protobuf message, not the (account_id, profile_card) tuple provided by the event.

    Note: Not all requests return a job ID; check the API documentation for specific method details.

    # Method 1: Event-based
    @dota.on('ready')
    def fetch_profile_card():
        dota.request_profile_card(70388657)
    
    @dota.on('profile_card')
    def print_profile_card(account_id, profile_card):
        if account_id == 70388657:
            print str(profile_card)
    
    # Method 2: Job ID-based
    @dota.on('ready')
    def fetch_profile_card_job():
        jobid = dota.request_profile_card(70388657)
        profile_card = dota.wait_msg(jobid, timeout=10)
        if profile_card:
            print str(profile_card)
  7. Use protocol buffer enums from dota2.proto_enums

    master
    The dota2.proto_enums module contains enumerations that map directly to the underlying Protocol Buffer definitions used by Valve's services. Use these when you need to match the exact integer or string values defined in the Dota 2 protobuf schemas.
  8. Establish a connection with launch()

    master

    Call launch() to start the process of connecting to the Dota 2 Game Coordinator. This method will attempt to add Dota 2 (app_id 570) to the current games being played if it isn't already.

    You can monitor the connection using the following events:

    • ready: Fired when the session is ready.
    • notready: Fired if the session is lost.
    • connection_status: Fired whenever the GCConnectionStatus changes.
    dota2_client.on('ready', lambda: print("Dota 2 GC is ready!"))
    dota2_client.launch()
  9. Send messages as jobs with send_job()

    master

    Use send_job() to send a message that expects a specific response. This method assigns a unique jobid to the message, allowing you to listen for the response on a specific event.

    Returns: A string representing the job identifier (e.g., 'job_123').

    job_event = dota2_client.send_job(SOME_EMSG_ENUM, {'field': 'value'})
    dota2_client.on(job_event, lambda msg: print(f"Received job response: {msg}"))
  10. Wait for a specific message with wait_msg()

    master

    Wait for a specific event or job response to be emitted. This is a blocking call (using gevent).

    Parameters:

    • event: The EDOTAGCMsg enum or a job ID string (e.g., 'job_1').
    • timeout: (Optional) Seconds to wait.
    • raises: (Optional) If False, returns None on timeout. If True, raises gevent.Timeout.

    Returns: The first message received for that event, or None if raises=False and a timeout occurs.

    msg = dota2_client.wait_msg('job_1', timeout=2.0, raises=False)