Crate rust_sc2[][src]

Expand description



Install Rust >= 1.42.0

Warning: Compilation is broken in rustc 1.45.0 - 1.46.0, you’ll get following error:

thread 'rustc' has overflowed its stack
error: could not compile `rust-sc2`.

Add to dependencies in Cargo.toml:

rust-sc2 = "1.1.0"

Or if you want developer version directly from github:

rust-sc2 = { git = "" }

Making a bot

Making bots with rust-sc2 is pretty easy:

use rust_sc2::prelude::*;

struct MyBot;
impl Player for MyBot {
    // This settings are used to connect bot to the game.
    fn get_player_settings(&self) -> PlayerSettings {
    // This method will be called automatically each game step.
    // Main bot's logic should be here.
    // Bot's observation updates before each step.
    fn on_step(&mut self, iteration: usize) -> SC2Result<()> {
        /* Your code here */

fn main() -> SC2Result<()> {
        // Pass mutable referece to your bot here.
        &mut MyBot::default(),
        // Opponent configuration.
        Computer::new(Race::Random, Difficulty::VeryEasy, None),
        // Map name. Panics if map doesn't exists in "StarCraft II/Maps" folder.
        // Additional settings:
        // LaunchOptions {
        //     sc2_version: Option<&str>, // Default: None - Latest available patch.
        //     save_replay_as: Option<&str>, // Default: None - Doesn't save replay.
        //     realtime: bool, // Default: false
        // }

Add some cool stuff and watch how it destroys the opponent.

If you are careful guy who don’t trust random macros that can destroy your PC, see #[bot] macro documentation to understand how it’s implemented. You always can do the same thing by hands if needed.

What bot can see?

Self information


self.raceRaceThe actual race your bot plays.
self.player_idu32Bot’s in-game id (usually 1 or 2 in 1v1 matches).
self.mineralsu32Amount of minerals bot has.
self.vespeneu32Amount of gas bot has.
self.supply_armyu32Amount of supply used by army.
self.supply_workersu32Amount of supply used by workers.
self.supply_capu32The supply limit.
self.supply_usedu32Total supply used.
self.supply_leftu32Amount of free supply.
self.start_locationPoint2Bot’s starting location.
self.start_centerPoint2Bot’s resource center on start location.

Race values

self.race_values.start_townhallUnitTypeIdDefault townhall which can be built by a worker.
self.race_values.townhallsVec<UnitTypeId>All possible forms of townhall for your race.
self.race_values.gasUnitTypeIdBuilding used to extract gas from vespene geysers.
self.race_values.rich_gasUnitTypeIdBuilding used to extract gas from rich vespene geysers.
self.race_values.supplyUnitTypeIdSupply provider for your race.
self.race_values.workerUnitTypeIdWorker of your race.

Common opponent’s information

self.enemy_raceRaceRequested race of your opponent.
self.enemy_player_idu32Opponent in-game id (usually 1 or 2 in 1v1 matches).
self.opponent_idStringOpponent id on ladder, filled in --OpponentId.
self.enemy_startPoint2Opponent’s starting location.
self.enemy_start_centerPoint2Opponents’s resource center on start location.


self.ramp.myRampYour main base ramp.
self.ramp.enemyRampOpponent’s main base ramp.
self.ramp.allVec<Ramp>All the ramps around the map.



self.units.allUnitsAll the units including owned, enemies and neutral.
self.units.myPlayerUnitsYour’s only units.
self.units.enemyPlayerUnitsOpponent’s units, on current step.
self.units.cachedPlayerUnitsOpponent’s units, but also contains some hidden units from previous steps.
self.units.mineral_fieldsUnitsAll mineral fields on the map.
self.units.vespene_geysersUnitsAll vespene geysers on the map.
self.units.resourcesUnitsAll resources (both minerals and geysers) on the map.
self.units.destructablesUnitsDestructable rocks and other trash.
self.units.watchtowersUnitsWatchtowers reveal area around them if there’re any ground units near.
self.units.inhibitor_zonesUnitsInhubitor zones slow down movement speed of nearby units.

What PlayerUnits consists of?

All fields are collections of Units:

.allAll player units (includes both units and structures).
.unitsUnits only, without structures.
.structuresStructures only.
.townhallsFrom all structures only townhalls here.
.workersWorkers only (doesn’t include MULEs).
.gas_buildingsThe gas buildings on geysers used to gather gas.
.larvasMost of zerg units are morphed from it (Populated for zergs only).
.placeholdersKind of things that appear when you order worker to build something but construction didn’t started yet.

Other information

self.timef32In-game time in seconds.
self.expansionsVec<(Point2,Point2)>All expansions stored in (location, resource center) pairs.
self.vision_blockersVec<Point2>Obstacles on map which block vision of ground units, but still pathable.
self.game_infoGameInfoInformation about map: pathing grid, building placement, terrain height.
self.game_dataGameDataConstant information about abilities, unit types, upgrades, buffs and effects.
self.stateGameStateInformation about current state, updated each step.

What bot can do?

Units training

Training as much as possible marines may look like:

// Iterating bot's barracks which are completed (ready) and not already training (idle).
for barrack in {
    // Checking if we have enough resources and supply.
    if self.can_afford(UnitTypeId::Marine, true) {
        // Ordering barracks to train marine.
        barrack.train(UnitTypeId::Marine, false);
        // Subtracting resources and suply used to train.
        self.subtract_resources(UnitTypeId::Marine, true);
    // Can't afford more marines. Stopping the iterator.
    } else {

Building structures

Building up to 5 barracks might look like:

// Building near start location, but a bit closer to map center to not accidentally block mineral line.
let main_base = self.start_location.towards(self.game_info.map_center, 8.0);

// Checking if we have enough resources to afford a barrack.
if self.can_afford(UnitTypeId::Barracks, false)
    // Checking if total (current + ordered) number of barracks less than we want.
    && self.counter().all().count(UnitTypeId::Barracks) < 5
    // Finding a perfect location for a building.
    if let Some(location) = self.find_placement(
        PlacementOptions {
            // Step increased here to leave some space between barracks,
            // so units won't stuck when coming out of them.
            step: 4,
    ) {
        if let Some(builder) = self.units
            // Finding workers which are not already building.
            .my.workers.iter().filter(|w| !w.is_constructing())
            // Selecting closest to our build location.
            // Ordering scv to build barracks finally.
  , location, false);
            // Subtracting resources used to build it.
            self.subtract_resources(UnitTypeId::Barracks, false);


Building new CCs might look like:

// Checking if we have enough minerals for new expand.
if self.can_afford(UnitTypeId::CommandCenter, false)
    // Checking if we not already building new base.
    && self.counter().ordered().count(UnitTypeId::CommandCenter) == 0
    // Getting next closest expansion
    if let Some(expansion) = self.get_expansion() {
        if let Some(builder) = self.units
            // Finding workers which are not already building.
            .my.workers.iter().filter(|w| !w.is_constructing())
            // Selecting closest to our build location.
            // Ordering scv to build new base.
  , expansion.loc, false);
            // Subtracting resources used to build CC.
            self.subtract_resources(UnitTypeId::CommandCenter, false);

Units micro

Attacking when marines >= 15, defending base before:

let main_base = self.start_location.towards(self.game_info.map_center, 8.0);
let marines =;

if self.counter().count(UnitTypeId::Marine) >= 15 {
    let targets = &self.units.enemy.all;
    if targets.is_empty() {
        for m in marines {
            m.attack(Target::Pos(self.enemy_start), false);
    } else {
        for m in marines {
            m.attack(Target::Tag(targets.closest(m)?.tag()), false);
} else {
    let targets = self.units.enemy.all.closer(25.0, self.start_location);
    if targets.is_empty() {
        for m in marines {
            m.move_to(Target::Pos(self.main_base), false);
    } else {
        for m in marines {
            m.attack(Target::Tag(targets.closest(m)?.tag()), false);

Prepearing for ladder

There’re community organized ladders for bots:

  • SC2AI - Runs games on windows and latest patch of SC2.
  • AI Arena - Runs games on linux and patch 4.10.

Both use the same kind of system. In order to get your bot ready for ladder, make it parse following args:

  • --LadderServer - IP address.
  • --OpponentId - Id of the opponent on ladder.
  • --GamePort - Port.
  • --StartPort - Yet another port.
  • --RealTime - Notifies that game is running in realtime mode. (Only for human vs bot games)

If you’re too lazy to add argparser yourself, see examples folder, some examples already have fully functional parser.

Then call run_ladder_game this way:

    &mut bot,
    ladder_server, // Should be by default.
    opponent_id, // Or `None`.

The API will do the rest.

Since SC2AI and AI Arena run the games on different platforms you’ll need to provide suitable binaries for each ladder.

Because of version differences ids are conditionally compiled for windows and linux.



Data structures for executing actions and analyzing actions failure.


Contains nice wrapper around SC2 API.


Bot struct and it’s helpers.


Everything needed to easily run games in SC2.


Useful constants and static values.


Items for interacting with Debug API.


Traits for comparing distance between points and units.


Information about units, ablities, upgrades, buffs and effects provided by API stored here.


Constant information about map, populated on first step.


Information updated every step stored here.


Things you liked (hated) at school, now in SC2.


Auto generated with script from stableid.json ids of units, ablities, upgrades, buffs and effects.


Data structures, used to store map data.


Items representing various player’s data.


The most frequent used items and various traits here. Prefered usage: use rust_sc2::prelude::*;.


Data structures for storing data of ramps on the map with methods for extracting useful info from them.


SC2 Score interface.


Stuff for convenient interaction with Units.


Data structures for storing units, fast filtering and finding ones that needed.


Different utilites useful (or useless) in bot development.



Settings that must be provided by a player when joining a game.


Request to the SC2 API.



Events that happen in game. Passed to on_event.



Trait that bots must implement.

Type Definitions


Attribute Macros


#[bot] macro implements Deref<Target = Bot> and DerefMut<Target = Bot> for your struct. Implementing this traits allows you to access Bot fields and methods on your struct through self.


#[bot_new] macro adds initialization of field added by #[bot] macro.