A Python interface layer for communicating with Counter-Strike 1.6 servers.
First-time setup (downloads HLDS + AMX Mod X):
# Run in PowerShell as Administrator
.\scripts\setup_hlds_windows.ps1Start the server:
poetry run python -m scripts.start_serverThis automatically starts:
- Redis (via Docker)
- HLDS dedicated server (de_dust2, 12 players)
- File bridge (connects game to Python)
Connect your CS 1.6 client to localhost:27015
After connecting, verify the plugin is working in your CS 1.6 console (~ key):
csif_ping # Should respond with "PONG!"
csif_status # Shows plugin status
csif_start # Start exporting observations
csif_dump_once # Create single observation file
csif_stop # Stop exporting
The server is scrim-ready by default (MR15 competitive settings). Use these configs:
| Config | Purpose | Command |
|---|---|---|
scrim.cfg |
Competitive MR15 (default) | exec scrim.cfg |
pub.cfg |
Casual/pub play | exec pub.cfg |
knife.cfg |
Knife round for side pick | exec knife.cfg |
live.cfg |
Go live after knife (3 restarts) | exec live.cfg |
overtime.cfg |
MR3 $10k overtime | exec overtime.cfg |
Scrim workflow:
exec knife.cfg # Knife for sides
exec live.cfg # Go live after knife
exec overtime.cfg # If tied at 15-15
Edit config/server.yaml to customize:
- Map, max players, server name
- RCON password
- Round settings
- Session ID for Redis
Test your code without CS 1.6:
docker compose upThis runs a mock CS server at 100Hz. Great for developing your agent.
This is the interface layer - it handles communication between Python and CS 1.6 game servers:
- Observation schemas (ObsV1) - Structured game state data
- Action schemas (ActionV1) - Structured player commands
- Redis IPC client - Pub/sub communication at 100 Hz
- Geometry utilities - Coordinate transforms, visibility checks
┌─────────────────────────────────────────────────────────────┐
│ CS 1.6 DEDICATED SERVER │
│ │
│ HLDS ──▶ Metamod ──▶ AMX Mod X ──▶ cs_interface.amxx │
│ │ │
│ ┌──────────▼──────────┐ │
│ │ File IPC (JSON) │ │
│ │ cs_interface_*.json│ │
│ └──────────┬──────────┘ │
└──────────────────────────────────────────────┼──────────────┘
│
┌────────────────────▼────────────────┐
│ REDIS │
│ cs:obs:{session} → Observations │
│ cs:act:{session} ← Actions │
└────────────────────▲────────────────┘
│
┌──────────────────────────────────────────────┼──────────────┐
│ THIS REPO (Interface Layer) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Schemas │ │ CSInterface │ │ Geometry │ │
│ │ ObsV1/Action │ │ Client │ │ Utilities │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└──────────────────────────────────────────────┼──────────────┘
│
┌──────────────────────────────────────────────┼──────────────┐
│ YOUR REPO (Agent Development) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Gymnasium │ │ Training │ │ Your Agent │ │
│ │ Env │ │ Loop │ │ Policy │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘
git clone https://github.com/cainky/CounterStrikeInterface.git
cd CounterStrikeInterface
poetry installfrom src.interface import CSInterfaceClient, CSInterfaceConfig, ActionBuilder
# Connect to server
config = CSInterfaceConfig(
redis_host="localhost",
session_id="training",
)
client = CSInterfaceClient(config)
client.connect()
# Receive observations
obs = client.get_observation()
print(f"Tick: {obs.tick}")
print(f"Position: {obs.self_state.position}")
print(f"Health: {obs.self_state.health:.0%}")
# Send actions
action_builder = ActionBuilder()
action = action_builder.build(
tick=obs.tick,
forward=1.0,
yaw_delta=5.0,
fire=True,
)
next_obs = client.step(action)from src.interface import CSInterfaceConfig, MockCSInterfaceClient
config = CSInterfaceConfig(session_id="test")
client = MockCSInterfaceClient(config)
# Generates synthetic observations
obs = client.get_observation()| Component | Description |
|---|---|
self_state |
Position, velocity, health, armor, weapons, inventory |
players |
Visible/audible enemies with relative position and angle |
sounds |
Recent sound events with direction and confidence |
round_state |
Phase, time, scores, bomb status |
map_context |
Map name, distance/angle to objectives |
| Feature | Human Mode | Oracle Mode |
|---|---|---|
| Enemy positions | Only visible | All enemies |
| Enemy health | Unknown | Exact value |
| Through-wall info | None | Full |
| Component | Type | Description |
|---|---|---|
movement |
Continuous | forward/strafe [-1,1], jump, crouch, walk |
view |
Continuous | pitch/yaw deltas (degrees) |
attack |
Binary | fire, alt_fire, reload |
utility |
Discrete | use, weapon switch, buy |
config/
└── server.yaml # Server configuration (map, players, etc.)
src/
├── schemas/ # Core data schemas
├── interface/ # Redis IPC layer
└── utils/ # Geometry, visibility utilities
scripts/
├── start_server.py # One-command server launcher
├── setup_hlds_windows.ps1 # Windows HLDS installer
├── mock_server.py # Simulate CS server (100Hz)
├── file_bridge.py # Bridge AMX plugin to Redis
└── test_observability.py
server_plugin/
├── cs_interface.sma # AMX Mod X plugin source
└── README.md # Server setup docs
This interface provides the low-level communication. To train an agent:
- Create a separate repo for your agent
- Import the interface:
from cs_interface import CSInterfaceClient, ObsV1, ActionV1 - Build your Gymnasium env wrapping the client
- Define your reward function based on
ObsV1fields - Train with your preferred RL library (stable-baselines3, cleanRL, etc.)
- Docker (for quick start)
- Or: Python 3.10+, Redis, CS 1.6 dedicated server
GPL-3.0 License. See LICENSE for details.
