8.3 - Optional - Using the Raw API
The python-sc2
library is an abstraction layer. It acts as a sophisticated translator, converting the complex, raw data stream from the StarCraft II engine into clean, easy-to-use Python objects like Unit
and Units
. For 99% of developers, this high-level interface is the best and most productive way to build a bot.
However, for advanced users who require absolute control or need to access data not exposed by the high-level helpers, the library provides a direct "escape hatch" to the raw API data.
Warning: This is an advanced topic. Using the raw API requires a deep understanding of the underlying game protocol and significantly increases code complexity.
The Data Flow: High-Level vs. Raw
This diagram illustrates the two paths data can take to your bot's logic.
+--------------------+
| SC2 Game Engine |
+--------------------+
|
| (Sends complex Protobuf data)
v
+--------------------+
| python-sc2 Library|
+--------------------+
|
| (Translates and simplifies)
v
.-----------------------------------------. <-- The Standard Path (Recommended)
| High-Level Helpers (self.units, etc.) | (Clean, easy-to-use Python objects)
`-----------------------------------------`
|
| (Provides a direct passthrough)
v
.-----------------------------------------. <-- The Raw Path (Advanced)
| Raw API (self.observation_raw) | (Complex, nested Protobuf objects)
`-----------------------------------------`
Why and When to Use the Raw API
Scenario | Description |
---|---|
1. Accessing Unexposed Data | The most legitimate reason. There may be rare or newly added data fields in the game's protocol that python-sc2 does not yet parse into a high-level helper. The raw API is your only way to access these. |
2. Extreme Performance Optimization | For top-tier competitive bots, the process of creating Python Unit objects on every step can introduce a tiny amount of overhead. An expert might bypass this by creating their own, more efficient data structures directly from the raw data. This is a significant undertaking. |
3. Library Debugging | If you suspect a bug in how python-sc2 is interpreting the game state, you can compare the data from the high-level helpers against the "ground truth" provided by the raw API to diagnose the issue. |
The Trade-Offs: What You Gain and What You Lose
Aspect | High-Level API (self.units ) | Raw API (self.observation_raw.raw_data.units ) |
---|---|---|
Ease of Use | Very High. Clean objects, intuitive property names. | Very Low. Deeply nested, verbose Protobuf objects. |
Readability | if marine.is_idle: | if not raw_marine.orders: |
Helper Methods | Abundant. .distance_to , .target_in_range , etc. | None. You must implement all calculations yourself. |
Performance | Excellent for almost all use cases. | Potentially faster, but only if you build a highly optimized custom data layer to replace the library's. |
Control | High. | Absolute. Direct access to every field the API provides. |
Code Example: A Raw Data Inspector
This example demonstrates how to access the raw Protobuf objects and contrasts them with their high-level equivalents. Note the verbosity and the different property names.
# raw_api_inspector.py
from sc2 import maps
from sc2.bot_ai import BotAI
from sc2.data import Difficulty, Race
from sc2.main import run_game
from sc2.player import Bot, Computer
# Import the raw protocol buffer definitions.
from s2clientprotocol import sc2api_pb2 as sc_pb
class RawAPIInspectorBot(BotAI):
"""A bot that inspects and compares raw vs. high-level API data."""
async def on_step(self, iteration: int):
# We only want to run this once to avoid spamming the console.
if iteration == 5:
marine = None
print("--- High-Level API (Recommended) ---")
# Get the first unit using the clean, high-level interface.
# Safely get the first unit, if one exists.
if self.units:
marine = self.units.first
print(f"Unit: {marine.name}")
print(f"Health: {marine.health}/{marine.health_max}")
print(f"Position: {marine.position.rounded}")
else:
print("No units found with the high-level API.")
print("\n--- Raw API (Advanced) ---")
# Get the raw observation object for the current step.
observation: sc_pb.Observation = self.observation_raw
# Access the list of raw unit Protobufs.
raw_units = observation.raw_data.units
# Find the raw unit with the same tag as our high-level marine.
# This check will only succeed if a unit was found above.
if marine:
raw_marine_proto = next((u for u in raw_units if u.tag == marine.tag), None)
if raw_marine_proto:
# Note the different property names and data types.
print(f"Unit Tag: {raw_marine_proto.tag}")
print(f"Unit Type ID: {raw_marine_proto.unit_type}")
print(f"Health: {raw_marine_proto.health}/{raw_marine_proto.health_max}")
# Position is a nested object.
print(f"Position: (x={raw_marine_proto.pos.x:.2f}, y={raw_marine_proto.pos.y:.2f})")
else:
print(f"Could not find raw unit with tag {marine.tag}")
elif raw_units:
print(f"Total raw units found: {len(raw_units)}")
else:
print("No units found with the raw API.")
if __name__ == "__main__":
run_game(
maps.get("AcropolisLE"),
[
Bot(Race.Terran, RawAPIInspectorBot()),
Computer(Race.Zerg, Difficulty.Easy)
],
realtime=True,
)
Conclusion: The raw API is a powerful tool for experts with specific, demanding requirements. For all other developers, the standard high-level interface provides the ideal balance of power, performance, and readability.