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
Example config/server.yaml:
server:
map: de_dust2
maxplayers: 12
hostname: "CS Training Server"
rcon_password: "changeme"
redis:
host: localhost
port: 6379
session_id: training
game:
round_time: 3 # minutes
freeze_time: 3 # seconds
buy_time: 15 # seconds
bot_quota: 10 # number of botsSymptom: csif_ping in console does nothing, or says "Unknown command"
Check:
-
Verify AMX Mod X is loaded:
meta listShould show
AMX Mod Xin the list. -
Verify plugin is loaded:
amxx pluginsShould show
cs_interface.amxxwith statusrunning. -
If plugin shows
errororbad load:- Check
cstrike/addons/amxmodx/logs/for error messages - Ensure
cs_interface.amxxis incstrike/addons/amxmodx/plugins/ - Ensure it's listed in
cstrike/addons/amxmodx/configs/plugins.ini
- Check
What success looks like:
] csif_ping
[CS Interface] PONG! Plugin v3 ready.
] csif_status
[CS Interface] Status: IDLE
[CS Interface] Session epoch: 42
[CS Interface] File IPC: ENABLED
[CS Interface] Last write: 0.003s ago
Symptom: client.get_observation() hangs or returns None
Check:
-
Is Redis running?
redis-cli ping
Should return
PONG. -
Is the file bridge running?
poetry run python -m scripts.file_bridge
Should show
[Bridge] Connected to Redis, watching for snapshots... -
Is the plugin exporting?
csif_start csif_statusStatus should show
RUNNING, notIDLE. -
Check the snapshot file exists and is updating:
ls -la C:/hlds_cs16/cstrike/addons/amxmodx/configs/csif_snapshot.json
Timestamp should be updating every ~10ms.
Symptom: ConnectionRefusedError: [Errno 111] Connection refused
Fix:
# If using Docker:
docker run -d --name redis -p 6379:6379 redis:alpine
# Verify:
redis-cli ping # Should return PONGSymptom: Server runs, you connect, but no bots appear
Fix:
# In CS console:
bot_quota 10
bot_add_ct
bot_add_t
Or ensure bot_quota is set in your server.yaml.
Symptom: Plugin fails to write JSON files
Fix: Run HLDS as Administrator, or ensure the cstrike/addons/amxmodx/configs/ folder has write permissions for all users.
GPL-3.0 License. See LICENSE for details.
