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_server
This 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 10ドルk 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 up
This 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 bots
Symptom: 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 PONG
Symptom: 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.