--- title: "How to Add Custom Maps to a CS 1.6 Server" excerpt: "Add custom maps to a CS 1.6 server the right way: where the .bsp and its assets go, the mapcycle, fast download so players actually get the files, and the missing-resource crashes." category: "installation" tags: "maps, custom-content" image: "" read_time: "8 min read" ---
Adding a map is not just dropping a .bsp in a folder. A map references textures, models, sounds and sprites that must all be present on the server, and — for a public server — must be downloadable by every client that joins. Get the file placement right and the crashes disappear; get fast download right and players stop timing out on the loading screen. This guide covers both.
A single custom map is typically several files across several directories inside cstrike/:
maps/de_mymap.bsp <-- the level itself maps/de_mymap.txt <-- optional MOTD/overview text maps/de_mymap.res <-- optional resource list (used by fast download) overviews/de_mymap.bmp <-- radar overview overviews/de_mymap.txt sound/mymap/... <-- custom sounds the map plays gfx/env/... <-- custom skybox, if any models/... sprites/... <-- any custom models/sprites
Many maps embed their textures inside the .bsp; those need nothing extra. Maps that reference external WADs need those WADs present too, or players see missing textures.
cp de_mymap.bsp /home/steam/hlds/cstrike/maps/ cp de_mymap.txt /home/steam/hlds/cstrike/maps/ cp overview.bmp /home/steam/hlds/cstrike/overviews/de_mymap.bmp
Filenames are case-sensitive on Linux. De_MyMap.bsp and a mapcycle entry of de_mymap will not match, and the server will report the map as not found.
The rotation is driven by mapcycle.txt in cstrike/:
de_dust2 de_mymap de_inferno
If you run a map-vote or nomination plugin, add the map to its map list too (commonly addons/amxmodx/configs/maps.ini). A map in mapcycle.txt but not the vote list can be rotated to but not chosen by players, and vice versa.
Without fast download, clients pull custom files over the game channel at a crawl and frequently time out. Point clients at an HTTP mirror of your cstrike/ tree:
sv_downloadurl "http://dl.example.com/cstrike" sv_allowdownload 1 sv_allowupload 1
On the web host, the directory served at that URL must mirror the layout under cstrike/ exactly — the map's .bsp at maps/de_mymap.bsp, sounds at sound/..., and so on. The client requests the same relative path it needs locally. A .res file next to the .bsp lists every asset the client should pre-download, which prevents the "connected but missing sounds" experience.
The engine's HTTP downloader also accepts bzip2-compressed copies. Ship de_mymap.bsp.bz2 alongside de_mymap.bsp on the download host and clients grab the smaller file:
bzip2 -k maps/de_mymap.bsp # keep the original, produce de_mymap.bsp.bz2
Do this for the large assets. The uncompressed file must still exist on the game server itself — the .bz2 is only for the download mirror.
Host_Error: Map change failed: 'de_mymap' not found on server — the .bsp is missing, misspelled, or wrong-case in maps/.Host_Error: PF_precache_sound_I: 'mymap/x.wav' Precache can only be done in spawn functions or failed to load — a sound/model the map calls is not on the server. Copy the map's sound/ and models/ assets.sv_downloadurl, or the mirror layout does not match. Test the URL in a browser: the .bsp must download from the exact path.overviews/ .bmp and .txt are missing or misnamed.From the server console force the map:
changelevel de_mymap
The server must load it without a Host_Error. Then join as a client from a machine that has never seen the map: you should download the assets over HTTP quickly and spawn into a fully-textured level with a working radar. If the download bar crawls, fast download is not wired up; if you spawn but hear no custom sounds, the sound/ assets are missing from either the server or the mirror. Once maps rotate cleanly, tie the rotation to player count with your map-vote plugin and confirm entries match between mapcycle.txt and the vote list.
Adding one map is manual; adding fifty is a script. When you drop a pack in, the failure mode changes from "one wrong path" to "one of these fifty maps is missing an asset and crashes the rotation at 3am". Two habits make a pack safe. First, verify every .bsp is actually present and named as the mapcycle expects:
cd /home/steam/hlds/cstrike while read m; do [ -f "maps/$m.bsp" ] || echo "MISSING: $m"; done < mapcycle.txt
Anything printed is a mapcycle entry with no map file — it will break rotation when reached. Second, mirror the entire pack to fast download in one pass and generate the .bz2 copies so clients are not pulling megabytes over the game channel:
find maps -name "*.bsp" -exec bzip2 -k {} \;
Do the same for large sound/ and models/ assets the maps add. The uncompressed originals stay on the game server; only the mirror serves the .bz2. A pack installed this way either boots clean or tells you exactly which map is incomplete before a player ever finds out the hard way.