Prerequisites:

Running the SC2Abathur project the first time will generate everything needed to get started with Abathur. You should see output similar to this;

SC2Abathur first time launch.

The project will automatically launch the included demo – but can safely be closed once it starts playing. This process will generate three files on your computer, and a log folder that by default will be populated with a new file after each run.

essence.data is a binary file containing game specific details - such as unit cost, unit health, upgrade cost etc. Blizzard tweak these things frequently, so it is best practice to regenerate this file when a new patch is released.

setup.json is a small file describing which modules your Abathur agent will be running with. The file is initialised with a small demo.

{
  "IsParallelized": false,
  "Modules": [
    "RandomDemo",
    "AutoHarvestGather",
    "AutoSupply"
  ]
}

The last file is gamesettings.json which contains everything Abathur needs to know when launching the client and setting up the first game. Edit here to change map or race. The file will by default be initialised with settings that launch Cloud Kingdom LE with a random race against a very easy random AI.

{
  "FolderPath": "C:\\Program Files (x86)\\StarCraft II",
  "ConnectionAddress": "127.0.0.1",
  "ConnectionServerPort": 8165,
  "ConnectionClientPort": 8170,
  "MultiplayerSharedPort": 8175,
  "InterfaceOptions": {
    "Raw": true,
    "Score": true,
    "FeatureLayer": null,
    "Render": null
  },
  "Fullscreen": false,
  "ClientWindowWidth": 1024,
  "ClientWindowHeight": 768,
  "GameMap": "Cloud Kingdom LE",
  "DisableFog": false,
  "Realtime": false,
  "ParticipantRace": 4,
  "Opponents": [
    {
      "Type": 2,
      "Race": 4,
      "Difficulty": 1
    }
  ]
}

Adding a New Module

Abathur agents are composed of modules. Modules must inherit from IModule or IReplaceableModule – the latter allows the module to be added and removed during a game e.g. to launch a special strategy.

This tutorial will use a simple IModule. The file can be added anywhere in the solution, but I recommend placing it in SC2Abathur.Modules. Adhering to the interface is relatively simple as they are all void methods.

using Abathur.Modules;
using System;

namespace SC2Abathur.Modules
{
  class MarineModule : IModule
  {
    void IModule.Initialize() {}
    void IModule.OnGameEnded() {}
    void IModule.OnRestart() {}
    void IModule.OnStart() => Console.WriteLine("Hello from MarineModule");
    void IModule.OnStep() {}
  }
}

These methods will be invoked by Abathur, but first we need to specify that we wish to include our MarineModule in the agent. This is done by updating the setup.json file. We choose to still include 'AutoHarvestGather' and 'AutoSupply' – they are simple helper modules that put idle workers to work and create new supply depots / pylons / overlords when the supply limit is reached.

{
  "IsParallelized": false,
  "Modules": [
    "MarineModule",
    "AutoHarvestGather",
    "AutoSupply"
  ]
}

We also need to update gamesettings.json to specify which race we want to play as. Terran (1), Zerg (2), Protoss (3) or Random (4).

{
  ... [removed for brevity] ...
  "ParticipantRace": 1,
  ... [removed for brevity] ...
}

Launching the solution again should result in something like this. Note that it launches noticeably faster as the essence file already exists.

Launching Abathur with the MarineModule

Moving a Marine!

We have confirmed that Abathur acknowledge the existence of our module, now comes the fun part. Abathur expose a number of services or managers. These are all available through dependency injection, so we can add the ones we need in the constructor of our module.

IProductionManager handles production of units and buildings.
IIntelManager handles everything related to the current game state.
ICombatManager provides shortcuts for controlling units.

On the very first frame of the game, Abathur will call the OnStart() method.
We add a request to the production manager for a single Marine here. A Marine requires the Barrack, and the Barrack requires a Supply Depot – but this is all handled for us by the production manager by default.

We then register our custom handler OnUnitCreated on UnitAddedSelf events, telling the IIntelManager to inform us whenever a new non-worker unit of ours is discovered (created).

Lastly we tell our brave new Marine to venture into battle. This is done by looking through all colonies. Abathur refer to a location fit for a base (Vespene and Minerals nearby) as a colony. Plausible starting locations for the enemies are marked with the 'IsStartingLocation' flag – which makes it easy for us to locate the enemy's base in Cloud Kingdom LE as there is only one.

using Abathur.Constants;
using Abathur.Core;
using Abathur.Model;
using Abathur.Modules;
using System.Linq;

namespace SC2Abathur.Modules {
  class MarineModule : IModule {
    private IProductionManager pm;
    private IIntelManager im;
    private ICombatManager cm;
    private IUnit raynor;
    
    public MarineModule(
      IProductionManager pm,
      IIntelManager im, 
      ICombatManager cm) {
      this.pm = pm; this.im = im; this.cm = cm;
    }

    void IModule.OnStart() { 
      pm.QueueUnit(BlizzardConstants.Unit.Marine);
      im.Handler.RegisterHandler(Case.UnitAddedSelf, OnUnitCreated);
    }

    void OnUnitCreated(IUnit unit) {
      if (raynor != null || unit.UnitType != BlizzardConstants.Unit.Marine)
        return;
      raynor = unit;
    }

    void IModule.OnStep() {
      if(raynor?.Orders.Count == 0) {
        IPosition p = im.Colonies
          .Where(c => c.IsStartingLocation)
          .FirstOrDefault();
        cm.AttackMove(raynor.Tag, p.Point);
      }
    }

    void IModule.Initialize() {}
    void IModule.OnGameEnded() {}
    void IModule.OnRestart() {}
  }
}

Note that the attack action could have been done directly in the OnUnitCreated handler, but I wanted to showcase that the IUnit class can be used as a persistent reference to a unit.

That is all the code it takes create and move our very first Marine. Granted not the best agent, but an agent none-the-less. The video below showcase the expected behaviour of this code;


Conclusion

We managed to move a Marine in StarCraft II with a fairly limited amount of code. Yay! SC2Abathur includes three primitive sample bots that can put up a fight against the built-in 'very easy' AI. I recommend drawing inspiration from there when expanding your simple agent – see Modules.Examples