Skip to main content

Architecture

OpenRA-RL connects three components through a gRPC bridge:

Architecture Diagram

Three-Repo Design

RepositoryLanguageRole
OpenRA-RLPythonEnvironment wrapper, gRPC client, agent examples
OpenRA (submodule)C#Modified game engine with embedded gRPC server
OpenEnvPythonFramework providing standardized Gymnasium-style APIs

Data Flow

Agent (Python)
↕ HTTP/WebSocket (OpenEnv protocol, port 8000)
Environment Wrapper (FastAPI)
↕ gRPC/Protobuf (bidirectional streaming, port 9999)
Game Engine (OpenRA + Kestrel)
↕ Native game logic
OpenRA World (C# actors, traits, orders)

gRPC Bridge

The bridge is embedded inside the OpenRA game engine using ASP.NET Core Kestrel. Key design decisions:

  • Static ActiveBridge pattern: The gRPC server starts once (in Activate()), while a static reference is updated each time the mod reloads. This avoids port conflicts from multiple server instances.
  • DropOldest channels: The game ticks at ~25 ticks/sec independently of the agent. Observation channels use a "drop oldest" policy so slow agents always receive the latest state.
  • Non-blocking ticks: The game never blocks waiting for the agent. If no action arrives, the game continues with a no-op.

Key C# Files

FilePurpose
ExternalBotBridge.csMain trait (IBot, ITick), Kestrel gRPC server
RLBridgeService.csgRPC service implementation
ObservationSerializer.csWorld/Actor/Player state → Protobuf
ActionHandler.csProtobuf commands → OpenRA Orders

Key Python Files

FilePurpose
bridge_client.pyAsync gRPC client with background observation reader
openra_environment.pyOpenEnv Environment (reset/step/state)
openra_process.pySubprocess manager for game engine
models.pyPydantic models for observations and actions

Protobuf Schema

The canonical schema lives at proto/rl_bridge.proto and defines:

  • GameObservation — Tick-level state: economy, military, units, buildings, spatial map, episode signals
  • AgentAction — List of commands to execute
  • GameState — High-level game phase query

The proto is compiled to both Python (gRPC stubs) and C# (pre-generated for Docker/CI compatibility).

Game Lifecycle

Game State Diagram

  1. Reset: Environment starts a new game map, waits for the game to initialize
  2. Planning Phase (optional): Agent studies the map and opponent before acting
  3. Game Loop: Agent receives observations, sends actions each tick
  4. Game Over: Episode ends with win/lose/draw signal