# How the Unciv AutoPlay System Automates Gameplay: A Technical Deep Dive

> Explore the Unciv AutoPlay system's technical details. Learn how it automates unit movements, city management, and turn transitions using the AutoPlay class for seamless gameplay.

- Repository: [Yair Morgenstern/Unciv](https://github.com/yairm210/Unciv)
- Tags: deep-dive
- Published: 2026-06-18

---

**The Unciv AutoPlay system automates gameplay by executing unit movements, city management, and turn transitions on background threads through the `AutoPlay` class, which coordinates with `WorldScreen` to run multi-turn sequences or single-use automation actions without player input.**

The AutoPlay system in Unciv—an open-source Civilization V clone—allows players to delegate repetitive turn-based decisions to AI algorithms. Built around the `AutoPlay` class located in [`core/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.kt), this system manages automation state, turn counters, and thread safety while integrating tightly with the UI layer. Understanding how the AutoPlay system automates Unciv gameplay reveals a carefully designed architecture that balances background processing with game state integrity.

## Core Architecture of the AutoPlay System

The AutoPlay implementation separates concerns across three architectural layers: the core automation controller, the UI integration point, and the thread management system.

### The AutoPlay Class and Settings

The `AutoPlay` class serves as the central coordination hub, instantiated with `GameSettings.GameSettingsAutoPlay` configuration. It maintains the `turnsToAutoPlay` counter to track remaining automated turns and references `autoPlayMaxTurns` and `autoPlayUntilEnd` flags to determine stopping conditions.

### WorldScreen Integration

`WorldScreen` owns the primary `AutoPlay` instance and monitors automation status through `autoPlay.isAutoPlaying()` checks during UI update cycles. When victory or defeat conditions trigger, the screen invokes `autoPlay.stopAutoPlay()` to immediately halt further automation and return control to the player.

### User Interface Components

The **AutoPlayStatusButton** in [`core/src/com/unciv/ui/screens/worldscreen/status/AutoPlayStatusButton.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/screens/worldscreen/status/AutoPlayStatusButton.kt) provides the primary interaction surface. A right-click or the `KeyboardBinding.AutoPlay` shortcut triggers `startMultiturnAutoPlay()` directly, while left-clicking opens the **AutoPlayMenu** for specific single-use actions. Configuration options for maximum turns and automation modes reside in `AutomationTab` within the Options screen.

## How AutoPlay Automates Gameplay Execution

The system differentiates between continuous multi-turn automation and discrete single-use actions, each following distinct execution paths.

### Starting Multi-Turn Automation

When initiated via `startMultiturnAutoPlay()`, the system initializes `Timers.singleton` for performance tracking and sets `turnsToAutoPlay` to the configured `autoPlayMaxTurns` value. This mode continues decrementing the counter each turn until reaching zero or until the `autoPlayUntilEnd` flag triggers completion at game end.

```kotlin
fun startMultiturnAutoPlay() {
    Timers.singleton.startTiming()
    autoPlayTurnInProgress = false
    turnsToAutoPlay = autoPlaySettings.autoPlayMaxTurns
}

```

### Executing Single-Use Automation Jobs

Specific actions like "Military Once" or "Civilian Once" utilize `runAutoPlayJobInNewThread()`, which accepts a lambda containing the automation logic. The method signature ensures proper thread isolation:

```kotlin
fun runAutoPlayJobInNewThread(
    jobName: String,
    worldScreen: WorldScreen,
    setPlayerTurnAfterEnd: Boolean = true,
    job: () -> Unit
) {
    if (autoPlayTurnInProgress) throw IllegalStateException("AutoPlay already in progress")
    autoPlayTurnInProgress = true
    worldScreen.isPlayersTurn = false
    autoPlayJob = Concurrency.runOnNonDaemonThreadPool(jobName) {
        job()
        autoPlayTurnInProgress = false
        if (setPlayerTurnAfterEnd) worldScreen.isPlayersTurn = true
    }
}

```

### The Automation Logic Pipeline

Different automation modes trigger distinct AI behaviors implemented in [`AutoPlayMenu.kt`](https://github.com/yairm210/Unciv/blob/main/AutoPlayMenu.kt):

- **Military Once**: Filters military units using `isMilitary()`, sorts them by `NextTurnAutomation.getUnitPriority()`, and invokes `UnitAutomation.automateUnitMoves()` for each unit. It also calls `UnitAutomation.tryBombardEnemy()` for cities.
- **Civilian Once**: Similar logic but filters for civilian units only, automating workers and settlers.
- **Economy Once**: Executes `NextTurnAutomation.automateCities()` to handle production queues, tile assignments, and city growth.
- **End-Turn**: Runs the complete AI turn via `TurnManager.automateTurn()` followed by `worldScreen.nextTurn()` to advance the game state.

### Turn Counting and Stopping Conditions

After each automated turn completes, `endTurnMultiturnAutoPlay()` manages the countdown:

```kotlin
fun endTurnMultiturnAutoPlay() {
    if (!autoPlaySettings.autoPlayUntilEnd && turnsToAutoPlay > 0)
        turnsToAutoPlay--
}

```

The UI checks `isAutoPlaying()` each frame, ensuring immediate cessation when turns exhaust or when `WorldScreen` detects victory/defeat conditions.

## Thread Safety and State Management

The AutoPlay system prevents race conditions through the `autoPlayTurnInProgress` boolean flag. Before spawning background threads, `runAutoPlayJobInNewThread()` validates this flag is false, throwing `IllegalStateException` if a job is already active. The system disables player input via `worldScreen.isPlayersTurn = false` during execution and restores control only after the lambda completes successfully and `setPlayerTurnAfterEnd` evaluates to true.

## Practical Code Examples

### Initiating Multi-Turn AutoPlay Programmatically

```kotlin
val worldScreen = UncivGame.Current.worldScreen
worldScreen.autoPlay.startMultiturnAutoPlay()

```

### Implementing Custom Military Automation

```kotlin
val worldScreen = UncivGame.Current.worldScreen
val autoPlay = worldScreen.autoPlay

val militaryJob = {
    val civ = worldScreen.viewingCiv
    val isAtWar = civ.isAtWar()
    
    val units = civ.units.getCivUnits()
        .filter { it.isMilitary() }
        .sortedBy { unit -> 
            NextTurnAutomation.getUnitPriority(unit, isAtWar) 
        }
    
    for (unit in units) {
        UnitAutomation.automateUnitMoves(unit)
    }
    for (city in civ.cities) {
        UnitAutomation.tryBombardEnemy(city)
    }
    
    worldScreen.shouldUpdate = true
}

autoPlay.runAutoPlayJobInNewThread(
    "AutoPlayMilitary", 
    worldScreen, 
    true, 
    militaryJob
)

```

### Integrating Keyboard Shortcuts

The `AutoPlayStatusButton` binds shortcuts using:

```kotlin
val directAutoPlay = {
    if (!worldScreen.gameInfo.gameParameters.isOnlineMultiplayer &&
        worldScreen.viewingCiv == worldScreen.gameInfo.currentPlayerCiv) {
        worldScreen.autoPlay.startMultiturnAutoPlay()
        nextTurnButton.update()
    }
}

keyShortcuts.add(KeyboardBinding.AutoPlay, action = directAutoPlay)
onRightClick(action = directAutoPlay)

```

## Summary

- The `AutoPlay` class in [`core/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.kt) centralizes automation logic, turn counters, and thread management.
- **Multi-turn automation** executes via `startMultiturnAutoPlay()`, while **single-use actions** run through `runAutoPlayJobInNewThread()` with specific lambdas.
- Background execution uses `Concurrency.runOnNonDaemonThreadPool` with `autoPlayTurnInProgress` locking to prevent concurrent automation jobs.
- Automation delegates to `UnitAutomation` and `NextTurnAutomation` for military movements, civilian actions, and economic management.
- UI components in [`AutoPlayStatusButton.kt`](https://github.com/yairm210/Unciv/blob/main/AutoPlayStatusButton.kt) and [`AutoPlayMenu.kt`](https://github.com/yairm210/Unciv/blob/main/AutoPlayMenu.kt) provide interaction points, while [`AutomationTab.kt`](https://github.com/yairm210/Unciv/blob/main/AutomationTab.kt) exposes configuration options.

## Frequently Asked Questions

### What is the difference between multi-turn and single-use AutoPlay in Unciv?

Multi-turn AutoPlay runs continuously for a specified number of turns or until game end, managed by the `turnsToAutoPlay` counter in the `AutoPlay` class. Single-use AutoPlay executes specific actions—such as moving only military units or managing cities once—then immediately returns control to the player through the `AutoPlayMenu` options.

### How does the Unciv AutoPlay system prevent game state corruption?

The system uses the `autoPlayTurnInProgress` atomic flag to block concurrent automation jobs. Before executing any background task, `runAutoPlayJobInNewThread()` verifies no job is active, disables player input via `isPlayersTurn = false`, and only restores control after the lambda completes successfully, ensuring the game state remains consistent during automation.

### Can AutoPlay be used in Unciv multiplayer games?

No. The `AutoPlayStatusButton` explicitly checks `!worldScreen.gameInfo.gameParameters.isOnlineMultiplayer` before starting automation. This restriction prevents AutoPlay activation in multiplayer sessions to maintain fairness and synchronization between human players.

### Which source files should developers modify to extend AutoPlay functionality?

Extend automation logic in [`core/src/com/unciv/ui/screens/worldscreen/status/AutoPlayMenu.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/screens/worldscreen/status/AutoPlayMenu.kt) for new action types like automated exploration or diplomacy. Modify [`core/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.kt) for core state management changes. Update [`core/src/com/unciv/ui/popups/options/AutomationTab.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/popups/options/AutomationTab.kt) to expose new settings in the Options screen, and adjust [`WorldScreen.kt`](https://github.com/yairm210/Unciv/blob/main/WorldScreen.kt) for integration with the main game loop.