Skip to content

Automation & Session Control

These functions start, restart, resign and quit matches, load saves and replays, and choose the random map and seed of the next match. They work from the game's menus, so a module can drive the game without clicks.

They are not game commands: the command rules do not apply to them. The Dispatch* functions and RefreshRandomMapSources() are blocked with Multithreading or Tournament Mode on. Tournament Mode also blocks GetAvailableSaveFiles() and the other random-map functions on this page. A blocked call logs an error once per module load and returns false, nil or an empty table.

Engine Control

SetEngineUIVisibility() and UnloadEngine() are listed under Engine.

Session Control

Function Signature Returns Description
DispatchStartGame () boolean Starts a single-player match with the current setup.
DispatchRestartGame () boolean Restarts the current single-player match or replay with the same setup.
DispatchResignGame () boolean Resigns the current match.
DispatchQuitGame () boolean Leaves the current single-player match and returns to the menu.
DispatchLoadGame (saveGameFileName) boolean Loads a save or replay from the game's load list.
GetAvailableSaveFiles () string[] Returns the file names in the game's load list, such as "MyGame.aoe2spg" or "MyMatch.aoe2record".
GetCurrentGameOptions () GameOptions or nil Returns the setup of the next or current match, or nil when the game has none.

true means the game accepted the request. The match or menu change happens over the next frames, so check the result in a later callback.

DispatchStartGame() does different things depending on where the game is:

  • In the menu, it starts a match with the current GameOptions.
  • On the end screen of a single-player match, it leaves that match and starts a new one with the same GameOptions, map source and seed request.
  • On the end screen of a replay, it plays the replay again, like DispatchRestartGame().

It returns false while a match is running, in multiplayer, when GetCurrentGameOptions() returns nil, and while an earlier start or quit is still in progress. CONTROL logs the reason as [SESSION_START] rejected=<reason>.

The other functions return false in these cases:

Function Returns false when
DispatchRestartGame The game is multiplayer, or there is no running match, ended match or replay end screen.
DispatchResignGame No match is running, or a replay is playing.
DispatchQuitGame The game is in the menu, multiplayer or a replay, or an earlier start or quit is still in progress. Logged as [SESSION_QUIT] rejected=<reason>.
DispatchLoadGame A match is running, the game is multiplayer, or the name is not in GetAvailableSaveFiles().

DispatchLoadGame() takes a file name exactly as GetAvailableSaveFiles() returns it, not a path. A file ending in .aoe2record loads as a replay.

Working With GameOptions

GetCurrentGameOptions() returns the match setup. Change it, then call DispatchStartGame(). Check the result for nil before you use it.

GameOptions lists every method and enum, and when the setters work.

Random Map Control

These functions list the random maps the game knows, select one for the next match, and read the map and seed of the running match. Select a map and seed with the GameOptions methods SetRandomMapSource() and SetRandomMapSeed().

Function Returns Description
GetRandomMapControlCapabilities() table Returns which random-map features work on this game build.
GetRandomMapStartStatus() table Returns whether a new match can start now, and why not.
RefreshRandomMapSources() number or nil Makes the game reload its list of random maps. Returns the new catalog generation.
GetAvailableRandomMapSources() RandomMapSource[] Returns the random maps in the current list.
GetEffectiveRandomMapSeed() number or nil Returns the map seed of the running match.
GetEffectiveRandomMapSource() RandomMapSource or nil Returns the random map of the running match.

RefreshRandomMapSources() works only while no single-player match is running: in the menus or on a match's end screen. It returns nil while a match runs, while a replay is loaded, in multiplayer, while a start or quit is in progress, or when the list cannot be read. CONTROL logs the reason as [RMS_CONTROL] operation=refresh rejected=<reason>. Each refresh increases the catalog generation. SetRandomMapSource() rejects a source from an earlier generation, so call GetAvailableRandomMapSources() again after a refresh.

GetEffectiveRandomMapSeed() and GetEffectiveRandomMapSource() return nil when no match is running, including on the end screen.

Capabilities

GetRandomMapControlCapabilities() returns a table of flags. A flag is false when CONTROL could not find the game function it needs on this game build. Other CONTROL features keep working.

Field Meaning
apiVersion 1.
capabilityRevision 2.
freshStart DispatchStartGame() can start a new match from an end screen.
requestedSeed GameOptions seed methods work.
effectiveSeed GetEffectiveRandomMapSeed() works.
sourceCatalog GetAvailableRandomMapSources() works.
refresh RefreshRandomMapSources() works.
selection SetRandomMapSource() works.
effectiveSource GetEffectiveRandomMapSource() works.
sourceIdentity, authoredSourceHash Same as sourceCatalog.
explicitQuitThenStart Same as freshStart.
structuredStartStatus Always true.
directPath, inlineSource, atomicFreshStart Always false. Lua cannot load a map script from an arbitrary path or from a string.

Start Status

GetRandomMapStartStatus() returns:

Field Type Meaning
canStart boolean true when DispatchStartGame() can start a new match now.
code string "ready", or the reason a match cannot start.
optionsAvailable boolean GetCurrentGameOptions() has a setup.
sessionActive boolean A single-player match is running.
multiplayer boolean The game is in multiplayer.
replay boolean A replay is loaded.
lifecycleTransitionPending boolean A start or quit is still in progress.
cleanStartContract string Always "explicit-quit-then-start".
capabilityRevision number 2.

code is one of "ready", "fresh_start_capability_unavailable", "game_options_unavailable", "multiplayer_not_supported", "replay_not_supported", "explicit_clean_end_required" (a match is running: call DispatchQuitGame() first), "lifecycle_transition_pending", "rms_session_safety_unknown" or "rms_session_safety_changing" (the game is between states; try again later).

RandomMapSource

A RandomMapSource is one entry of the random-map list. Its properties are read-only. Each also has a Get...() method, such as source:GetDisplayName().

Property Type Meaning
DisplayName string The map's name. For a local mod file, the file name without .rms.
NativeMapId number The game's map id.
SourceKind string "game-catalog" for maps in the game's list, "local-mod" for .rms files in a local mod.
ModIdentity string or nil The local mod's folder name in lower case, for local mod maps.
ResolvedPath string or nil The full path of the .rms file, when known.
SourceIdentity string An id that stays the same for the same map across refreshes.
AuthoredSourceSha256 string or nil The SHA-256 hash of a local mod's .rms file, up to 16 MiB.
CatalogGeneration number The catalog generation this value belongs to.

Besides the game's own list, CONTROL lists every .rms file in the local mods of your game profiles: %USERPROFILE%\Games\Age of Empires 2 DE\<profile id>\mods\local\<mod name>\resources\_common\random-map-scripts\. To use a new or changed script, save it there, call RefreshRandomMapSources() and select it from the new list. CONTROL does not copy map files.

The separate RMS IDE tool (AoE2RMSIDE) talks to CONTROL through its own interface, not through these Lua functions.

Example: Configure And Start A Match

function Load()
    local options = GetCurrentGameOptions()
    if not options then
        return
    end

    options:SetPlayerCivilization(0, OptionsCivilization.KOREANS)
    DispatchStartGame()
end

function End()
    DispatchRestartGame()
end

Example: Start A Local Mod Map With A Fixed Seed

function Load()
    local options = GetCurrentGameOptions()
    if not options or not GetRandomMapControlCapabilities().selection then
        return
    end

    RefreshRandomMapSources()
    for _, source in ipairs(GetAvailableRandomMapSources()) do
        if source.SourceKind == "local-mod" and source.DisplayName == "MyMap" then
            options:SetRandomMapSource(source)
            options:SetRandomMapSeed(12345)
            DispatchStartGame()
            return
        end
    end
    Log("MyMap was not found")
end

function Init()
    local seed = GetEffectiveRandomMapSeed()
    if seed then
        Log("Map seed: " .. seed)
    end
end

Example: Load The First Replay

function string:endswith(ending)
    return ending == "" or self:sub(-#ending) == ending
end

function Load()
    for _, v in ipairs(GetAvailableSaveFiles()) do
        if v:endswith(".aoe2record") then
            Log("Loading " .. v)
            DispatchLoadGame(v)
            break
        end
    end
end

function End()
    DispatchRestartGame()
end