How the Unciv AutoPlay System Automates Gameplay: A Technical Deep Dive
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, 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 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.
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:
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:
- Military Once: Filters military units using
isMilitary(), sorts them byNextTurnAutomation.getUnitPriority(), and invokesUnitAutomation.automateUnitMoves()for each unit. It also callsUnitAutomation.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 byworldScreen.nextTurn()to advance the game state.
Turn Counting and Stopping Conditions
After each automated turn completes, endTurnMultiturnAutoPlay() manages the countdown:
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
val worldScreen = UncivGame.Current.worldScreen
worldScreen.autoPlay.startMultiturnAutoPlay()
Implementing Custom Military Automation
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:
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
AutoPlayclass incore/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.ktcentralizes automation logic, turn counters, and thread management. - Multi-turn automation executes via
startMultiturnAutoPlay(), while single-use actions run throughrunAutoPlayJobInNewThread()with specific lambdas. - Background execution uses
Concurrency.runOnNonDaemonThreadPoolwithautoPlayTurnInProgresslocking to prevent concurrent automation jobs. - Automation delegates to
UnitAutomationandNextTurnAutomationfor military movements, civilian actions, and economic management. - UI components in
AutoPlayStatusButton.ktandAutoPlayMenu.ktprovide interaction points, whileAutomationTab.ktexposes 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 for new action types like automated exploration or diplomacy. Modify 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 to expose new settings in the Options screen, and adjust WorldScreen.kt for integration with the main game loop.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →