S2ZE - Map Porting Guide
Source 2 Zombie Escape
Map Porting Guide
Discord: https://discord.gg/s2ze (back up link)
Github: https://github.com/Source2ZE
Last Update: 2025 / 07 / 24
Contents
-1.1 - Import Tool Not Functioning 5
-1.2 - Missing Material Fatal Error 5
1.2.2.1 - Logging the Import Tool 11
1.3.2 - Missing Entities From .fgd 14
1.3.3 - prop_exploding_barrel 15
1.5.1 - Skybox Water Transition 18
1.6 - Cubemap & Light Probe 20
1.6.2 - Changing Cubemap Resolution 22
1.9 - SourceTS (new VScript) 25
1.10.2 - Changing Voxel Size 26
1.11.1 - Multi-layered Minimap 28
1.12.1 - Patching the Particle Editor 30
1.12.2 - Particle Rendering 30
1.12.3 - Importing Particles 32
1.14.2 - Recreating env_sun 36
1.18- Packing the Map with the Steam Workshop 40
1.18.2 - Uploading to the Steam Workshop 41
1.18.3 - Notes about the Steam Workshop 43
2.1.2.1 - Setting up CS2Fixes Offline in Tools Mode 46
2.5.2 - Stationary and Dynamic Lights 53
2.9.1 - Reducing Map File Size 58
2.9.1.1 - Lightmap resolution 58
2.9.1.2 - Bake lightning on props 58
2.10.1 - Manual Import of Models 59
2.10.2 - Adjusting CSM Properties 61
2.10.3 - Adding Tree Sways on Foliage Props 61
2.10.4 - Creating CS2-compatible .svg 62
3.0 - Examples of ported maps and their CSGO counterparts 64
This section was supposed to be a temporary section set up in response to the update on 5th December. However, the update on 14th December made porting new maps basically impossible (without applying a workaround at least). So this section will be set up in a more organized manner like the other sections in this guide.
As the contents of this section is vital for you to know, and since they are not really about procedures to take when porting a map, it will remain here with an awkward numbering of '-1'.
Since the update on 14th December, the import tool will simply not work. It now fails to read a CS:GO .vpk file, meaning the importer cannot import base CS:GO assets.
The current workaround is finding vpk.signatures in game/bin/win64, and have it named something else.
In an update on 5th December, Valve has set any missing textures present in a map (and hence substituting them as the error texture) as a fatal error of the game. As you can imagine, this will result in fatal shutdown on a live server as well, making the map totally unplayable both offline and online. This also occurs for workshop submitted maps.
The error message when loading a map with missing textures.
For reference, this is the current set up in the gameinfo.gi file, in which the key value of "ErrorMaterialIsFatalError" "1" is present. It is speculative about the reason why this was deemed necessary by Valve, however one thing for certain is that this requires the utmost attention when porting a map (at least for the time being).
The solution is simple - replace any missing textures from the map. This can be done relatively easily by loading the map in tools mode and inputting mat_print_error_materials into the console. As the name suggests, this command will print out the name of the materials that are encountering errors when the map is loading. You can then look for lines that end with [Error Resource] and hopefully identify the missing texture(s) you have.
If you want to test your map for missing materials afterwards, you can run the game without tools mode and load the map with map_workshop <addon> <map> in the console. With this you do not have to upload the map to the workshop whilst testing the map as if it was uploaded.
Update on 14th December 2023 and 7th February 2024: With this update, Valve has deleted some (presumably unused) assets in mirage and inferno. The Arms Race update has also deleted more CS2 assets. As you can imagine, this did cause some maps using these assets to crash after the update. With that in mind, this is a PSA that current stable ports can become obsolete in future updates in a similar fashion.
This is the porting guidelines as outlined by Source 2 Zombie Escape, which you may choose to follow when working on your own port.
In the end, this is not the ultimate guide to porting and likewise you should not treat it as one. Not only are there new features added (or existing ones taken away) with every CS2 update, every now and then we are also discovering cool methods to exploit many of the new S2 features. And of course, there also may be errors that we did not spot when writing this guide!
If you do not understand some parts of the guide or if you have some suggestions, then feel free to join us in our discord and share your thoughts with us! We are always open to porters who want to create high quality ports for CS2.
This section will list the minimum work required to have the map to be at a playable state for CS2.
In S1, many Zombie Escape maps had serverside adjustments made to the map with strippers. Strippers were mainly used to fix issues within the map without having to compile the map for a new version.
When porting stripper-dependent maps to CS2, the modifications made by these stripper configs need to be implemented into the map. Not only is this required since a stripper equivalent feature is not present in CS2 (yet), but maps should never depend on strippers in the long-term since it is another file that a server has to manage for.
Fortunately, we have written a Python script that will make this process much easier. With the stripper applier, or Stripplier, any modifications made within a stripper config will automatically apply to a .vmf file. More information is written on the Github page, but to briefly describe its procedures:
TIP: All entities modified by the script will be given "strippered" "1" keyvalue so that you can easily filter for them via the Entity Report menu.
Make sure you check if all changes are correctly applied, save the .vmf file at least once, and the map should be almost ready to port.
Note: You can choose to implement stripper fixes manually, but naturally this is not recommended as this creates more opportunity for errors to be made.
Within CS2 files, Valve has included the tool necessary to port CS:GO maps to CS2. Instructions on how to set up and use the import script, and the fix-ups you should do to the ported .vmap is described on the dedicated page on VDC.
This section will present you with additional information you should know when using the import tool.
Before using the import tool, here are some points that you should watch out for and make changes in S1 hammer when necessary:
The import tool is not exactly the most stable tool in the world, and can be prone to failures when porting a map. Here are some issues we have encountered, and solutions we have found to work reliably:
Another caveat of the import tool is that it does not perform any logging, meaning you will lose all console outputs from the import tool after you close the console window. Furthermore, as Windows Terminal is limited to 9,999 lines of output, any outputs beyond the most recent 9,999 outputs will not be recoverable when the import tool completes. This is fairly troublesome as it may result in you missing out on important console outputs, which could help later when fixing the ported map.
Fortunately, you can use Windows Powershell to generate a log file of the import tool. You only need to add an extra argument to the importing commands, such that:
<Python import commands> | tee <name of log>.txt
where you would use the same commands for the import tool in place of the angular brackets. To launch Powershell, you can type 'powershell' instead of 'cmd' in the Windows Explorer address bar.
As a further example, the full command should be similar to:
python import_map_community.py "<s1 directory>" "<s1 contents>" "<s2 directory>" addon_name map_name -usebsp | tee output.txt
This will create a log file named output.txt within the directory where you have ran the import tool.
You will have to enter 'y' for a couple of times when an user input is requested. Do note that it will not always display a message asking for an user input, in which case you should still input with 'y' in the blank newline. When the importing process does begin, you can let the tool continue normally.
Note: The log text file will be overwritten if a same name is used every time the import tool is executed. To prevent any overwrites, you may choose to move the log file to the relevant addon folder every the import tool finishes running. Otherwise, you can give a full directory (starting from the volume) to the log file instead.
After the import tool finishes porting your map, you should follow these steps so that you have easier time making modifications to the map in CS2 hammer:
Note: An env_sky entity is also created at world origin, so make sure you don't delete everything at the world origin. In fact, you should move the env_sky entity into your map.
Note: We have listed more CS2 issues in our Github.
Many S1 entities do not currently work as intended in S2, or they are outright removed with S2. This section will highlight these entities and provide a suitable replacement if applicable.
There are quite a few missing entities in CS2 (compared to CSGO), here are a few common ones with their potential replacement
Some entities are missing from hammer .fgd files, but they can be made to work again after substituting them from CS:GO. These entities are:
The following section will explain how to re-enable filter_activator_team.
The entity is missing in hammer from base.fgd. The .fgd for this entity can be copied directly from CS:GO .fgd, or alternatively can be copied from below:
@FilterClass base(BaseFilter) size(-8 -8 -8, 8 8 8) = filter_activator_team :
"A filter that filters by the team of the activator."
[
filterteam(choices) : "Filter Team Number" : 2 : "The team number to filter by. If the filter mode is Allow, only entities whose "+
"team number matches the given team will pass the filter. If the filter mode is Disallow, "+
"all entities EXCEPT those whose team number matches the given team will pass the filter." =
[
2 : "Terrorist"
3 : "Counter-Terrorist"
]
]
For consistency, this block can be pasted in near other filter_* entities in the base.fgd. If you have no idea what this means and would rather play it safe, then place this block at the end of base.fgd.
The default model of this entity is currently missing in CS2, which causes the entity to not function correctly in game. We expect this to be fixed when the Danger Zone gamemode ships.
To fix the issue for now, you can manually import the barrel model with procedures as described in the model section. After the model (and the material) is manually ported, you have to place these assets in the exact same directory as CS:GO.
The Orientation Style of Face the Direction of Motion needs some modifications in CS2. First, you have to create at least one more path_track before the corner, which will reduce the time the tracktrain turns around the corner. Then, set Change angles to Near path tracks so that the tracktrain turns at a gradual pace. You can refer to the screenshot of the configuration in hammer for a visual example.
This is a screenshot from ze_boatescape101’s .vmap with the aforementioned method.
The hurting mechanism works, but the particles do not show. You can fix this by replacing the particles directly with info_particle_system.
This entity does not work as intended. You can attempt to fix this by having the sparks on an info_particle_system enabled via a logic_timer, or using a looping spark particle.
If you have any path_particle_rope in your map, this will show as an obsolete entity in your map. Fortunately, the fix is easy as replaced them to path_particle_rope_clientside.
These are some of the quirks that exist in the current version of CS2. Until CS2 is fully released (and realistically for a few years after release), you should not consider this list to be final. Any solutions to these problems are only suggestive, and should not be used for the majority of the cases (since Valve may patch these later). The list will be updated whenever necessary.
Note: On a live server, most of these issues could be remedied with our metamod plugin CS2Fixes. To try to test your port offline with CS2Fixes enabled, refer to the section dedicated to CS2Fixes.
Water in CS2 is done by having the water mesh be a func_water. The texture configuration is still the same - only the top face has the water texture and the rest of the faces must be nodraw.
Note: If you are looking for a replacement for func_water_analog then refer to the section on missing S1 entities.
If the map has a transition the main map and the skybox on a large body of water (e.g. to create a perception of 'infinite water'), then you will have to do extra work to make the transition smooth. The old S1 method of just aligning the textures will not work as effectively anymore.
In short, we will be making use of cubemaps, and changing the properties of the water texture for a gradual transition of the water into the skybox. More information about cubemaps and how to place them in the map will be discussed in the next section.
First, extend the water mesh in the main map by about 512 units beyond the skybox into the void, into directions where the water is in the skybox. For example, if the map is surrounded by water then you want to extend the water mesh in your main map into all four cardinal directions. The amount of units to extend is arbitrary - the deeper the extension the more gradual the transition will be.
Next, place at least one env_combined_light_probe_volume above the body of water in the skybox. This is to ensure that the skybox fade has a proper reference to refer to. Make sure that this light probe volume is near the water mesh in the skybox.
Finally, you have to edit the properties of the water texture in the Material Editor. Assuming that the texture has the correct water shader, the texture will have additional settings that can be modified under the tab of Map Settings. Within this tab, you have to change the values of Map UV Min and Map UV Max; these are the minimum and maximum coordinates (in x and y coordinates) of the water mesh in the main map. When in doubt, you can set these coordinates to some extreme values.
Example configuration of the water texture Map Settings properties
Afterwards, you have to play around with the other settings within the Map Settings tab until you observe a nice transition between the main map and skybox water textures.
Before and after comparison shots in ze_voodoo_islands
Note: You may notice some granularity in the transition. This is unfixable because of how transparency is projected in S2.
Note: If you need to have water transitions made at multiple locations (and heights) within your map, then you have to duplicate the water texture and change Map UV Min/Max to each individual cases.
In S2, a new entity env_combined_light_probe_volume calculates light probes for object lighting and builds cubemap textures within a single volume. This entity is mandatory when making a CS2 map, as otherwise props, player models, and view models will be unlit (aside from dynamic light sources).
Normally, maps imported by the import tool will have few of these entities placed in the map. However, the placements made by the import tool are not optimal, so it is much preferred if you place these entities by yourself from scratch.
The placement is similar to how you would place env_cubemap in S1 - the white spheric gizmo should be placed in an open space about 64 units above the floor - the eye height of players in CS2.
The volume of env_combined_light_probe_volume is adjusted by moving the arrow gizmos for each axis. The volume of this entity does not have to follow the exact geometry of the enclosing areas, but do make sure the volume covers the enclosing areas completely.
The above screenshot is an example from ze_tkara’s .vmap. The white outlines show the boundaries of each volume. The blue box is a selected volume, where you can adjust the dimensions of the volume.
How many env_combined_light_probe_volume you need is entirely dependent on how much time you are willing to spend on them. As a general rule of thumb, you want to have at least one env_combined_light_probe_volume for every unique room, hallway, area, etc. Do note that cubemaps are one of the things that take most of your map file size. The resolution can be changed and will be discussed a bit further down in the guide.
Note: make sure to build your cubemaps at least once. Otherwise, any textures with specular indirect (i.e. cubemaps) enabled will show purple-hint and the map could be prone to crashing!
Note: If you want to just have either a cubemap or a light probe you can use env_cubemap_box or env_light_probe_volume respectively.
Unlike env_cubemap in S1, cubemaps in S2 can optionally be blended with other cubemaps, allowing for smooth transitions between different cubemaps. This is most noticeable on your viewmodel and shiny surfaces.
The extent of these blends are set with Edge Fade Dist parameter, where each input box represents the units from the edge of the volume in each dimensional axis where cubemap blending is enabled. Here is a section within Valve's wiki explaining more about cubemap blends.
Here is a screenshot from ze_hidden_fortress’s .vmap. It shows off the blended edges as mentioned above.
Note: Cubemap blending can be very expensive with overlapping cubemap blends you have on a surface. Use cubemap blending sparingly, only along edges where a blend is necessary, and try not to overlap more than 3 cubemap blends.
One of the things that bloats CS2 maps are cubemaps. If you are looking to reduce the file size of your map, this is the first thing you would want to work on.
To reduce the resolution of cubemaps, go to gameinfo.gi found in csgo_core/ directory. Search for EnvironmentMapFaceSize within the file, and replace the value with the resolution you desire, but do note that this must be in powers of 2 (32, 64, 128, 256, 512,...). For reference, the default value is 256.
Note: Changing this resolution may result in your game ignoring roughness on various textures. This also affects textures in official Valve maps as well.
Every custom sound or music that you wish to add to your map now has to be defined as a soundevent in your custom soundevent .vsndevts file. This .sndevts file has to be located in content/<addon name>/soundevents/.
Before doing anything with the soundevent file, first you have to make sure that the sound files (.mp3, .wav) are located in the correct directory. This is not different from S1 however, you just have to ensure that all sounds are within contents/<addon name>/sounds/ directory.
Note: In CS:GO sound files were located in csgo/sound/ folder; notice the spelling difference between sound and sounds!
If you have created your addon via the tools launch menu, then an example .sndevts file called 'soundevents_addon.vsndevts' will automatically be created for you in the correct directory. Within this example file, you can find a few pre-defined soundevents that you may choose to modify or create new soundevents upon. This file also has detailed comments explaining some of key soundevent parameters, so you should take a few minutes off to read these comments. You will also find a list of all the dsp reverb presets should you want a different echo profile in your map, or perhaps switch between presets depending on the area.
Note: If you wish to hear your custom soundevents in hammer and in game, then your .vsndevts file has to be named soundevents_addon.vsndevts. Only soundevent files of this name is read automatically read by the game in addons.
TIP: If you cannot hear your custom sounds in hammer even if your soundevent file is named as soundevents_addon.sndevts, then double check if the syntax within the file is correct and that the sounds have actually compiled to .vsnd_c.
To play these custom sounds, simply create a point_soundevent entity which references a custom soundevent you have created. ambient_generic is now considered obsolete and should not be used.
TIP: You can set the volume of a soundevent higher than 1 to a maximum of 10. Don’t tell Luffaren that!
As a side note, in CS2 there are three different types of soundevents: csgo_mega, csgo_music, and csgo_3d. csgo_mega is a general soundevent type that you would use for the majority of sounds, csgo_music is specifically used for music, and csgo_3d for other general ambient sounds.
Any input that changes the animation sequence on a prop_dynamic will be broken, as the input has a slightly different name in S2. Make sure you replace these for any animated props you may have in your map.
Sometimes, your ported map may be missing some models. This can happen due to the import tool failing to import a specific model, or the import tool simply did not recognize that the model is present in the map. In any case, this subsection will cover the different methods you can use to have these models ported successfully.
On a relevant note, a missing model can be seen with the default error model both in hammer and in game. Furthermore, the list of missing models in your map can be seen when compiling your map. Any missing models are shown with red error messages near the beginning of the compilation window.
The import tool may not have properly imported some models that are present in your map; most notably any gib models that spawns from a breakable model. In this case, you can try using cs_mdl_importer.exe which is included with your game files. This executable can be called from anywhere if the importer is set up correctly, but if the importer is not set up correctly then you can find it in game\bin\win64 and run it directly.
First, you have to create a .txt file that lists all the models that you require importing in terms of their directory; e.g. in some format of models/some_folder/some_model.mdl. If you want to import multiple models at once, you have to list each model directories on separate lines. Once the list is done, simply execute the tool with the command prompt by using the command below:
cs_mdl_import -i <path_to_s1_csgo> -o <path_to_cs2_addon> -l <path_to_list.txt>
If some models fail to import with either of the methods mentioned above, then you have to import the model manually. The detailed procedures are written in the later section.
Note: With the arms race update, Valve has enabled use of a new scripting language using Javascript/Typescript. The previous version of this section describing the old VScript using Lua, and patching it for unofficial support has been deleted.
This update seems to have brought a bunch of content for map-based scripting, which evidently means this section will be rewritten, adding more guides and tips as we learn more about it.
As you may know already, how visibility works in CS2 is completely different. In CS2, VIS is calculated by using voxel and these voxels are then merged into "chunks". These chunks then determine the visibility a player can have.
Unfortunately, the new VIS may introduce new problems to your port, especially if your map has multiple isolated areas. If you have compiled your port at this point, you may have noticed that you can see objects through the skybox when you should normally not be seeing them.
If the object that is drawn through different areas is small (i.e. a single mesh or something similar), you can disable Mesh Merging in the object's properties window. This is done because all static geometries (including meshes, props) are merged into chunks primarily by VIS, but other factors, including materials, can merge geometries that are largely separated from each other as well. Thus by specifically disabling Mesh Merging we can skip this behavior and force the object to not merge with other objects.
Note: This usually works best with individual objects. If you have an entire area displaying through the skybox, then you should continue on to the next subsection.
func_areaportal and func_areaportalwindow do not exist in CS2 anymore. As such, hiding certain areas (e.g. behind skybox) is now extremely problematic.
The current solution to areaportals is to manipulate VIS blocks so that a line of sight is blocked between the current area and the area you want to hide. For this, we use visibility_hint entity to cut VIS manually - we can define the Hint Type to specify what kind of operation a visibility_hint should do:
A configuration that we think works the best is to have two visibility_hint's that cuts VIS blocks along an equal axis, and have another visibility_hint around the area where the axis-cut visiblity_hint's are placed. These should usually be placed perpendicular to the direction of your map's gameplay; think of how you would use areaportals in S1.
Note: Unfortunately, VIS is something that we do not completely understand yet. If you think that you have a better solution then please do let us know!
If your map has many large areas (and we mean large, like areas spanning couple of thousands of units) then you may have already noticed that the duration of VIS compilation takes an extremely long time. This is because the default voxel size for VIS compilation is at 8 units, so maps with large areas will have more voxel volumes to calculate for.
Fortunately, an entity exists where you can dynamically set the VIS voxel size within a specified volume, using visibility_hint. The method of operation works similarly to a lightprobing volume, where you can change the volume by dragging the gizmos in each axis. Then within the entity properties window, you are able to set the Hint Type which you can then change the resolution, or reversely equivalent the voxel size within the volume. The range extends from voxel size of 8 (default in CS2) to 256.
To change the voxel size in the entire map, simply create one visibility_hint that encompasses the map. Although the compiler may show the default voxel size of 8, the hint will work properly when projecting the compiled vis later, and the hint voxel size should also show in the compiler as well.
TIP: We recommend values of either 16 or 32, as these values have worked well from our experiences. Going further than this number may introduce more VIS issues.
A consequence of having higher voxel size is that you may introduce new VIS issues between different areas. To avoid this, make sure areas are being separated by no less units than the VIS voxel size; e.g. a 20 unit gap between rooms when using 32 voxel size would be bad.
Creating a minimap in CS2 is fairly "automatic", in a sense that the entire process of creating minimap files is done by the tool. However, you still have to do some extra steps to ensure that the minimap is displayed correctly in game.
Before generating a minimap, you first have to create cs_minimap_boundaries at two opposite boundaries of your map so that the volume within these two entities covers your entire map. For example, place one at the minimum coordinates, and one at the maximum. The selection volume from these two entities should cover your entire map.
To generate a minimap, you can tick compile minimap on load parameter in the compilation window, and run your map from hammer (or build if cs_minimap_boundaries's are not yet present in your map). Alternatively, you can generate a minimap in game by typing minimap_create in console.
Note: The resolution of minimaps can be changed by putting cs_minimap_create_output_size x in console, where x is the resolution that you want (default is 512). Do note that the maximum resolution of the minimap generation is limited to your current game resolution.
The minimap texture is saved in content/<addon name>/panorama/images/overheadmaps/<map_name>_radar.tga. However, the minimap material has to be made into a Valve texture and also needs some additional parameters to have it properly displayed in game.
Create a new Generic or a Csgo Composite Generic material in the Material Editor, and save the material in the same directory and the same name as the raw minimap .tga file. Next, import the minimal .tga as the color texture. When using the Generic material, you have to toggle on the Translucent parameter in the left hand side menu. Save the material and compile it. If you navigate to your addon folder in game/ directory, you should find the compiled minimap texture there.
TIP: You can create radars with transparent backgrounds when using the Csgo Composite Generic material, but an alpha channels needs to be established in the minimap image.
Note: If you do not see either materials in the list, tick “dev shaders” at the bottom.
If the minimap was compiled successfully, then you may realize that the compiled materials are given a unique suffix. You have to delete this suffix so that the name of the compiled material becomes <map_name>_tga.vtex_c.
If you now run your map in game, you should see the minimap displayed correctly.
Note: You may have to restart your game for the minimap to be properly displayed.
For more complex maps, it is likely that the map will have overlapping areas across different heights, which may necessitate the use of a multi-layered minimap. Fortunately, this is still supported in CS2 and the process of generating one is not much different than from CS:GO.
In short, you have to generate a minimap image for each desired layer, and define these layers in the .txt file under game/csgo_addons/<addon name>/resource/overview/. This text file will have the same name as your map.
First, follow the steps in the previous section for a single-layered minimap, and generate the aforementioned text file. This step will automatically calculate the minimap positioning and scaling based on the cs_minimap_boundaries's you have placed in the map. If you have verified that this text file has been generated, then you can carry on to the next step.
Note: This initial minimap generation must include the entire map in the x-y plane - i.e., you cannot adjust the minimap positioning and scaling for each layer.
Next, the actual minimap image for each layer will need to be generated. Navigate to this text file, and add the following at the end of the first block:
"verticalsections"
{
"1"
{
"AltitudeMin" "-16000"
"AltitudeMax" "x"
}
"2"
{
"AltitudeMin" "x+1"
"AltitudeMax" "y"
}
//repeat until…
"n"
{
"AltitudeMin" "z"
"AltitudeMax" "16000"
}
}
Each block inside the “verticalsections” will be the layers you want to generate; you have to find the minimum and maximum altitude values manually. These layers are ordered in the ascending order, and any overlap of ranges is not tolerated (notice x+1 for the minimum value for layer 2). The numbering of layers 1, 2, …, n is just an example - it will not make any difference if the naming is changed.
Note: You should aim to use the least number of layers possible. The minimap images are fairly large in file size, and having many layers will bloat your port unnecessarily.
Now, do a generation of the minimap via the compile window or the in-game console command. If done correctly, the minimap image for each layer will be generated in the content folder. All that is required at this point is to create a .vmat file for each layer, do the compiling, and remove the unnecessary suffix on the compiled material.
This section will be dedicated to using particles in your port, and how to manipulate them with the CS2 Particle Editor.
Although the Particle Editor has been part of the CS2 tools since the limited beta, it is unfortunately locked away by Valve for an unknown reason.
Fortunately, it can be unlocked easily by modifying your game files. The Particle Editor can be enabled by editing game/bin/sdkenginetools.txt where you find the Particle Editor entry and remove the following 4 lines:
m_ExcludeFromMods =
[
"csgo",
]
Note: Just like with VScript, there could be a strategical reason from Valve why the Particle Editor is locked away.
Note: Particle Editor requires a whole new guide of its own. If you need a tutorial about using the Particle Editor, then this video of the S1 particle editor may be a good starting point for you. The new particle editor has significantly more features in comparison, the vast majority of which completely lack documentation.
Particles and particle systems remain relatively the same as in CS:GO. However, particles in CS2 make use of OIT (Order-independent transparency) sorting, which unfortunately cause heavy performance drops when looking at even the most simple particles.
Fortunately, enabling certain particle properties in the Particle Editor (which needs patching to use them) can greatly improve performance for a little to no impact to the visuals of the particles.
Before continuing on, you may want to look at the visual difference between enabling depth feathering on a particle - they essentially enable particles to blend more naturally with the world and minimising abrupt cut-off's.
Showing the difference between depth feathering disabled and enabled on a particle.
For now, there are four distinctive configurations that you can have on a particle:
For Zombie Escape, it is extremely unlikely that a smoke grenade will ever be used within the map. Thus, almost all particles should make use of game overlay pass if depth feathering is not an issue. If not, you should prioritise using bloom pass and then mixed resolution rendering if the particle also happens to be dark. For other game modes, using mixed resolution rendering is recommended.
Note: This can only be done on custom particles; you cannot modify base CS2 particles, unless they have been extracted using Source 2 Viewer.
Note: The list above is not a definitive list. There may be better configurations that we are simply not aware of yet.
With one of the recent updates, the import tool is no longer able to import particles. This means that any particles that your map used in S1 cannot be imported yet using the import tool. For now, there are a couple of methods you can try.
The first is to replace particles with ones that are provided with base CS2. Just be aware that some particles do not work as they are simple direct import from CS:GO.
The second is to use an older version of the import tool (not recommended), or to use a third-party import tool such as kristiker's source1import. Note, you should still use Valve's import tool to port your map, and use this third-party tool to import particles only. The material of the particle will not be properly imported, and so those textures will need to be converted for S2 manually.
The last option is to remake particles completely from scratch with the Particle Editor. Unfortunately, this is not an optimal solution as making particles is not particularly easy (and tedious), and as of now Particle Editor is locked away by default.
Control points offer a powerful method of manipulating properties of a particle from the same system. Although control points are not new with S2, they now have the ability to accept inputs from control points to modify the particle system, such as their spawn rates or colors. In other words, control points offer an upgrade from S1, where in S1 a particle had to have multiple copies for minuscule changes.
The following example below is our recreation of func_dustmotes in CS2 as a particle. At the fundamental level, this particle has the initializer of ‘Position within sphere random’, emitter of ‘Continuous emitter’, and renderer of ‘Sprite renderer’. In the Particle Editor, we are able to modify some properties of the particle to take in values from a control point.
In this example, the x-axis of CP #2 controls the radius of particle generation, y-axis of CP #2 controls how many particles are generated per second, and CP #3 allows tinting of particle colors.
In hammer, using info_particle_system in this instance, we are able to define the control points we wish to use and give corresponding values. Note, how the same particle system has been used in both info_particle_system.
We input the control points and the corresponding values to customize the same particle with different properties.
After a quick compilation, we are able to see the clear differences between these two systems as shown in the screenshot below:
Two different particles using the same system.
Naturally, these are not the only properties that can accept control points, which further highlights the true power of them in CS2.
As mentioned previously in the section about missing entities in S2, many func entities that use particles are no longer supported in CS2. As you may expect with our replacement for func_dustmotes above, Easter has created a prefab of many particle systems (amongst others) to replace more missing entities.
Example use of rain particle prefab and its modification for snow in our ports.
Items can sometimes be crucial for the map flow of Zombie Escape maps. It is a mechanism that is simple to implement, and yet can bring big variety between each run depending on how the items are used. This section will introduce some issues exclusive to CS2, and the solutions regarding them.
TIP: Make sure that the items are imported correctly! Broken outputs are fairly common in items, and remember that the import tool does not handle them correctly.
func_button kills teammates on moving objects
For some unknown reason, players that “collide” with a func_button on a moving object, specifically func_movelinear, will cause collision damage upon them.
You can replace any func_movelinear which players have to stand on into a func_tracktrain instead.
Item holder cannot see the item
This is because the items are attached to you, and since the textures on the items are not using the character shader they will become invisible to the item holder.
As you may have guessed, the fix is creating a duplicate texture that the item uses, and setting them to use Csgo Character shader.
Playing sounds on the item
As ambient_generic is obsolete, a new method is needed to play sounds on items.
You can use snd_event_point, and have the Source Entity Name point to the func_physbox. Note, you should not target the weapon itself.
Placing grenades in the map
Due to an oversight within the game itself, any grenade that is picked up by a player will not be intractable unless scrolling through the entire inventory.
Create a new key with String Property Type in the Object Properties menu of the grenade, and insert subclass_name as the key. The value for each grenade is listed below:
43 Flashbang
44 HE grenade
45 Smoke grenade
46 Molotov
47 Decoy
48 Incendiary grenade
Skybox has seen some changes in the transition from CS:GO to CS2. This section will highlight some of the crucial changes.
Unlike S1, skybox textures are no longer solid - players are now able to fall out of the map through any skybox faces. This unfortunately is not a good behavior for Zombie Escape, since unlike the base game, zombies are often capable of reaching these areas via knockback boosts.
Fortunately, it is rather easy to add clips to all skybox faces. Simply select all faces with skybox texture in face mode, copy paste them, and change their texture to a clip texture.
With the removal of env_sun from .fgd, the Sun has to be replaced by a mesh placed inside the map instead. This was an intentional change made by Valve, as how env_sun generated its effects were expensive, and they realized a simple sun mesh in the skybox was an adequate replacement with some bloom in post processing.
Note: It is recommended to create the Sun mesh in the skybox. Due to the large scaling of the skybox compared to the main map, the skybox will be better at recreating the far perceived distance of the Sun.
First, create a circular mesh at the world origin. Then, copy the angle keyvalue from light_environment and apply it to the mesh. At this point the mesh is rotated 90° off from the desired angles.
Switch to local coordinates, and rotate the mesh until the arrow from light_environment is perpendicular to the mesh. If done correctly, the orientation between the light_environment and the mesh should look like the screenshot below.
The desired orientation between light_environment and the mesh.
You can now drag the mesh to the very edge of the map. Simply replace the mesh texture to a suitable material; many materials that have ‘sun’ in their name are a good choice. At this point, you should experiment with different materials, having multiple stacked meshes, and or changing the scale to create the Sun that looks reasonably good.
Note: Although it is possible to have these meshes beyond the hammer grid, it is recommended to have them within. Some transparent materials (to recreate the sun glare for example) may not display properly if placed beyond the grid.
With the remake of the Zombie:Reloaded plugin into CS2 with Zombie:Reborn, a new feature has been added that allows mappers to disable (and re-enable) zombie respawns at will, typically with a 'nuke' at the end of the map. This replaces the old trigger_hurt based automatic “repeat kill detectors”, which were often vulnerable to false positives.
To modify zombie respawns, create an additional output on whatever entity that triggers the nuke such that:
Action: <OnWhatever>
Target: zr_toggle_respawn
Output: choose one output listed below:
Disable - disable zombie respawn (does nothing if already disabled)
Enable - enable zombie respawn (does nothing if already enabled)
Delay: you can have whatever value here for the delay of the output.
Note: Trigger output still exists for legacy purposes. However, there have been instances where the Trigger output would unintentionally re-enable zombie respawns, such as when triggered via a trigger_once. Thus, it is not recommended to use the Trigger output.
It is very important to not miss this step! If this is not set up correctly, then zombies will infinitely respawn in a loop on live servers, which will make your port unplayable.
Note: A map may have multiple ways of triggering the nuke; make sure this output is added to all such entities!
TIP: A possible way of testing zombie respawn toggles offline is to create a logic_relay with the same name of zr_toggle_respawn in your map. Within this relay, you can add an output that prints to console / chat whenever zombie respawns is modified. Make sure you delete the relay before publishing your map though, otherwise your messages will still print on live servers.
TIP: With this new feature in ZR, it would technically be possible to enable zombie respawns again by using the same outputs and continue to toggle as many times as you desire. Perhaps you can use this feature to implement a unique ZE gameplay into your map?
In many Zombie Escape maps, a level system may be present which divides the entire map into smaller segments. This allowed maps to have a sense of progression and to prevent maps being tediously long for average players to play through. In S1, a level system was made from various of methods - using tricks with permanent entities, using VScript, or using the notorious physics based system.
In S2, we have found another system that is much cleaner to use, and easier to understand for more novice mappers. Essentially, the new system exploits the fact that any entity in the skybox map (that is usually not permanent) becomes permanent - any information that is stored in an entity is kept throughout all rounds.
We exploit this fact and create a math_counter in the skybox which stores the progression of levels. For every new round, we force the math_counter to output its value to a logic_case, which in turn relays outputs to set up the desired level. A prefab to the skybox level system can be found here.
We really encourage mappers to use this new level system, or to replace existing ones in ported maps. This system is much more intuitive to understand and as such is less prone to mistakes. This system also does not require you to understand VScript or advanced entity works, and isn’t susceptible to random breakage.
Note: It has been discovered that having an improperly built nav mesh has a great potential to lag out on a server, especially at a higher player count and/or in a large enough map. As both conditions are true in majority of Zombie Escape maps, we recommend you to not compile a nav mesh at all - having a nav mesh does not make a difference on a live server.
Unlike S1, a .nav is not generated automatically when the game detects that your map is missing a .nav file. Instead, launching maps without a .nav file in CS2 will do absolutely nothing; no bots will be able to spawn into the map.
To generate a .nav file, you need to place at least one point_nav_walkable near player spawns. If there are multiple spawning areas, then you have to make sure to have at least one point_nav_walkable per spawning area. Do note that this is the absolute minimum required to compile nav.
With the release of the Workshop for CS2, having all assets of the map packed, and sharing the map with other players have become easier for mappers.
For some mappers, uploading maps to the Workshop could already be familiar from CS:GO. For Zombie Escape (and likely other community gamemode) mappers however, this will likely be their first time using the Steam Workshop. Whatever your familiarity with the Workshop may be, this section will introduce how to upload maps to the Workshop and explain which assets are automatically packed with the upload.
When you upload a map addon to the workshop, the file gameinfo.gi, which is located in game/csgo/, will dictate which paths within your addon game folder are whitelisted - i.e. which paths will be automatically packed into your map.
In the default configuration, files in these directories are packed (i.e. "include"):
maps
cfg/maps
materials
models
panorama/images/overheadmaps
particles
resource/overviews
scripts/vscripts
sounds
soundevents
lighting/postprocessing
postprocess
addoninfo.txt
Files in these directories are not packed (i.e. "exclude"):
maps/content_examples
Although the whitelist list is pretty comprehensive, it does miss out on couple of paths that may improve the quality of the map. For example, in the current default configuration, any files required for the loading screen will not be packed.
As you may have guessed, you can add new lines, edit or delete existing lines to make modifications to the whitelist. Carrying on the example of loading screen files, you will be able to pack those files by changing "panorama/images/overheadmaps" into "panorama". Do note that all paths has to be relative to the game folder of your addon.
Here are some noteworthy mentions when uploading to the workshop:
After the final compilation of your map, and after you made sure everything is working correctly, you will be uploading the map to the steam workshop so that it becomes public for other players to play on.
Fortunately, the steam workshop is very streamlined and easy to use, with an added advantage that as a mapper uploading is really all you need to do - distribution of files are done automatically by the workshop. With that said, let us go through the steps of uploading a map to the steam workshop.
In the asset browser, look for the 'Counter-Strike 2 Workshop Manager', or click on the logo as shown in the image below.
If the manager pops up, you would have to create a New Submission to upload your addon. After the pop up page for a submission opens up, you can now select the addon you want to upload, and give some descriptions about the map. Don't worry if this page seems a bit barebones to you (becaust it is), you will be able to edit your submission once it has been uploaded.
Example submission of ze_sorrento_escape_p
Some notes about each field:
Note: You can edit these settings later via the workshop manager.
After the addon has been submitted, a steam moderator will then review your submission. This can take any time between a few minutes to a day. In most cases this will just be an extra waiting time you can spend treating yourself a nice cup of coffee, or finally the time to clean your room for once.
Note: During this review period the visibility of the submission is automatically set to 'Hidden', so any other people with the link to your submission will not be able to see or subscribe to your submission.
TIP: Any edits that you make to your submission will require another review - this includes minor things such as changing the description or adding a few more images. You do not have to wait until a review is completed to make edits to your submission!
Note: The steam workshop moderation is actually fairly lenient, provided that you follow Steam's rules and guidelines.
Assuming things go well, you are done! Your submission would have passed the review and the visibility will be set back to whichever you have chosen when submitting.
If you are familiar about uploading to the Steam workshop already, then you can skip this section. For Zombie Escape mappers however, you should be aware of these difference between the old distribution method (FastDL) and the Steam workshop.
Take these considerations with a grain of salt though, as some are about running maps on a server, but nonetheless are things a mapper should be aware of.
This section will cover how you can further improve the map to make sure you use the most out of the new S2 features, and overall make the map more pleasing to look at.
As CS2 modding matures more and more, many useful tools and programs have been created to aid mappers (and porters alike). This guide will briefly cover the highlights of some CS2 tools, although as you may guess this guide will not do justice in showcasing the full capabilities of the tools that are introduced here.
“Source 2 Viewer is a powerful tool that allows you to browse VPK archives, view, extract, and decompile Source 2 assets, including maps, models, materials, textures, sounds, and more. This open-source project is based entirely on a reverse engineered effort as there is no Source 2 SDK.”
As stated in their introductory message, Source 2 Viewer is an extremely powerful tool that will likely accompany you in all mapping and or porting projects that you may do. When compared to S1 tools, it is essentially a combination of BSPSource (decompiling for .vmap and embedded assets), GCFScape (view and extract within a .vpk file), VIDE (view entity lump information), and more. Although the tool currently does not have extensive documentation (for mappers), the tool itself is very intuitive and easy to use.
Here are some instances where you may use Source 2 Viewer for your port:
Irradiance of de_mirage in the closed beta before the lightmap was optimized. Notice how a few meshes takes up a good chunk of the lightmap, which reduces the available lightmap space for the rest of the map. (credit: @Angel in S2ZE discord)
Although CS2Fixes mainly acts as the fundamental plugin to run Zombie Escape servers, it offers many features that porters can use. You can find the detailed documentation for mappers on our github page.
Note: Although tempting, you should not use these features when creating new maps. These features are only implemented to be a community fix for many features that CS2 does not support anymore.
Likewise, the installation guide of CS2Fixes can be found on the main github page. However, running the game in tools mode will simply crash when loading the Workshop Tools.
The fix is simple - create a folder such that content/csgo/addons/metamod/ exists.
These new entities can be placed in your map to give more cinematic views during various phases of a game match: team_select, counterterrorist_team_intro, terrorist_team_intro, and end_of_match.
We rcommended for you to use team_select (replaces point_viewcontrol). This is because if team_select is not used, the team selection camera centers to the world origin, which may be in the void depending on the map.
end_of_match shows a 'MVP' screen similar to panorama CS:GO end of match screen - this is not mandatory as some servers may choose to skip this screen and move to the next map early.
Do not use any team intros cameras. These may interfere with maps that play music early in the round, and are unlikely to work properly in Zombie Escape servers with 64 players. In fact, due to the issue it causes with music, the intro cameras would most likely be disabled on live servers.
The character placements shown in hammer are exactly the same in game.
As a complimentary entity to env_gradient_fog, env_cubemap_fog creates fog within the skybox, which provides a nice blend between the world and skybox. The parameters are similar to that of an env_gradient_fog except that this entity calculates color directly from the skybox.
You can check ze_antartika comparison shots to see this entity in effect.
Note: env_cubemap_fog does not give fog to the skybox texture itself.
The player light map resolution texture, 'tools/playerlightmapres', is a mesh entity texture that increases lightmap resolution to faces within and around the lightmapres volume. This is a nice way to have sharper light resolutions within playable areas where they do matter.
Note: Areas further away from lightmapres volumes will gradually have lower lightmap resolution - either create volumes for all playable areas or use none at all.
If your map has heavy fog, you may have noticed that the fog does not apply to players, or at least that the fog does not apply as heavily.
Fortunately, an entity exists where you can change the visibility settings applied on players with env_player_visibility. Below you can see the difference the entity can make in a fog heavy map.
Left: Default player visibility settings in a fog heavy map. Right: Adjusted player visibility settings with bots at the same locations.
The recommended values for each settings are:
Although adding custom contents to your map's loading screen is not a new feature, some work needs to be done to have them working in CS2.
Having your custom images displayed in the loading screen works differently in S2, because you have to compile your images before they can be used in game.
First, place your custom image into content/<addon name>/panorama/images/map_icons/screenshots/1080p/. In the Material Editor, create a new Csgo Composite Generic material, and set its color texture with the screenshot image.
Note: If you do not see the Csgo Composite Generic material, untick 'show recommended materials' and tick 'show dev materials' at the bottom of the texture types menu.
After everything is set up correctly, you can save the material under the same directory but following a strict naming format of:
<map_name>_png or <map_name>_1_png (up to 9).
As the naming format suggests, you may have up to 10 custom loading screen images.
Note: Unlike S1, you have to have at least 2 images to have them display consistently throughout all map loads. If you provide only one image, the game will inconsistently display your image because the game chooses from all possible 10 loading screens it can load with.
You can compile the materials and see if the image is compiled with .vtex file suffix in game/<addon name>/panorama/images/map_icons/screenshots/1080p/. If the compiled image is not found in the directory, then you should double check if you have followed the previous steps correctly.
If the images were compiled successfully, then you may realize that the compiled materials are given a unique suffix. You have to delete this suffix so that the name becomes equal to what you have saved the original material with.
TIP: When loading a map, the right-hand side of the screen will be used to display map information; in other words, the right-hand side of an image is relatively hidden in the loading screen.
Fortunately, implementing a custom map icon follows the same step as in CS:GO. If you have the .svg file ready, then all you have to do is to place it in content/panorama/images/map_icons/ folder. The name of the .svg should not be changed - i.e it is still called as 'map_icon_<name of map>.svg', where you would replace the brackets with the name of your map.
Afterwards, you have to compile and check that the compiled svg .vsvg_c file is generated in the game/ folder. The .svg file can be force compiled in the Asset Browser.
Note: If you are creating a new .svg, or otherwise have difficulties displaying the .svg properly in the loading screen, you should refer to the section on creating a CS2-compatible .svg.
Likewise, adding custom map loading text is the same as in CS:GO. The text .txt file does not need any compilation however, and can be directly placed in game/maps/ folder as '<name of map>.txt', replacing the brackets with the name of your map.
Note: As of writing this guide, HTML formatting does not work.
A good trick to know when using the Asset Browser is that only native CS2 assets can be seen by filtering for csgo in the addon filter menu.
To reduce the filesize of the map, you should try to replace textures to base CS2 textures. Likewise, the new CS2 textures make use of new PBR features and as such are at a much higher quality. Replacing textures can done by finding similar substitutions. Unless it is a texture that is extremely iconic, not many people will recognize the differences.
In certain instances, CS2 may already have the equivalent texture to an imported texture - these textures can be seen in the Asset Browser by filtering for the Overridden Asset and Read-Only Asset tags, as seen below:
Unfortunately, your map will be using the imported texture meaning the map would be unnecessarily bloated. These duplicate textures have to be deleted by using the filters explained above.
Check out the comparison shots in ze_antartika and ze_PUTA for a visual example of changing textures to CS2 ones.
A similar explanation follows to the reason why models should be replaced with CS2 models; it is very likely that the imported models from CS:GO are at a lower quality than native CS2 models. As such, you can use the same filters as above to look for any duplicate models in your addon. Naturally, same exceptions apply - iconic models (e.g. mako reactor) should ideally be kept.
All imported foliage models, however, will lose support for env_wind sways. These should be all replaced by CS2 foliage models. However, not all CS2 foliage models will support env_wind sways, so do trial and error until you find a foliage model that fits with your needs
Note: If you cannot find a suitable replacement for foliage models, you can attempt to add tree sway support to the imported model yourself. Be aware that this is an advanced technique that requires use of blender.
Improving lighting to make use of new CS2 lighting features should always be your top priority as these can significantly improve the quality of the map.
For that reason, it is important to understand what different lightning options do:
Note: There is a limit of 4 overlapping stationary lights at any given luxel, which may include one for light_environment (unless baked shadowing is disabled, or for any VIS clusters that are "indoors") - any more stationary lights will not show up properly and cause lighting artefacts!
TIP: If you would like to have the additional layer for stationary light, you can disable Baked Shadowing in light_environment so that you can use the extra channel normally reserved for light_environment in outdoor areas. Be warned that this will disable CSM (or in laymans term this will disable shadows casted from the light_environment).
Thus, as of the writing this guide, having medium or low video settings will may disable any non-stationary lights if dynamic shadows is enabled.
Should you need to view the baked lighting lightmap within your map, you can use Source 2 Viewer (ValveResourceFormat) to open the map .vpk file, and navigate to lightmaps/irradiance.vtex. If there are any abnormally large faces in the lightmap, you may want to take a closer look at the map and optimise.
Static lights in your map should have bake specular to cubemaps enabled. This allows the light itself to be reflected on reflective surfaces via cubemaps.
You can see examples of specular lightning in ze_ELEVATOR_escape and ze_hidden_fortress comparison shots.
Any lights that you need to change at run time should at least be a stationary light. It should be dynamic light if the light needs to change positions as well.
A stationary/dynamic light can support dynamic shadows by enabling Baked Shadowing. This will allow shadows to be dynamically drawn from players (including yourself), prop objects, or any moving entities.
TIP: Once again, you can disable Baked Shadowing in light_environment so that you gain an extra layer of dynamic shadows that you can use instead. Use this only if your map does not depend on CSM from light_environment, for example it’s nighttime without a moon or the sky is cloudy.
Check out how having dynamic shadows enabled changes the visuals of an area in ze_hypernova.
TIP: You can adjust the properties of CSM from a light_environment, which is disabled in hammer by default. More information on how to patch is mentioned in the later section.
Note: changing the angle does not impact the brightness of the light.
You can see how fluorescent lights are made with light_omni2 in ze_ELEVATOR_escape and ze_saw.
TIP: light_omni2 is a very powerful light entity in source 2 with the most customization possible.
Note: by default light_spot will be non-static with dynamic shadows enabled.
Note: Unlike S1, it is now possible to have these light entities directly inside the lightning models instead. In fact, this would be the most preferred method of doing lightning as demonstrated in ze_STRANGE_escape.
Strictly speaking, post processing is not a new feature with CS2, but the new tool makes it significantly easier to change post processing effects and observe the changes in real time both in hammer and in game. Furthermore, bloom is significantly improved when compared to S1, to the point that glow sprites around lights are no longer needed and can be removed altogether.
TIP: When creating a new post processing file, you should use both Tone Mapping and Bloom together. With Bloom you can set how much bloom should be given off from bright light sources and selfillum materials, and with Tone Mapping you can adjust the general brightness and intensity of them.
Applying post processing into your map requires use of a new mesh entity called post_processing_volume. These volumes have to cover the areas you want post processing to be enabled. Alternatively, if you want it to be enabled across the entire map then you can tick the 'Master' parameter.
How post processing can affect the visuals of a map can be seen in ze_chronus and ze_PUTA.
This section will veer a bit off from Zombie Escape and discuss about elements from other movement based community gamemodes.
Edge bugs (where players seemingly "lose all momentum" at the end or even in the middle of a surf ramp) are much more prominent in CS2. This of course defeats the purpose of the surf gamemode, and within a ZE map this can make a map be unplayable. This gets progressively worse on ramps with bad mesh geometry, such as ones generated from the import tool.
With a little preparation before using the import tool howerver, the frequency of such happening can be greatly reduced. This is with converting surf ramps temporarily into func_brush, so that their S1 geometry stays in tact during the import of the map.
Although many of the material parameters are not much different from S1, the new Material Editor likewise makes editing materials much easier, and allows viewing the changes in hammer and also in game immediately as well.
Some CS:GO materials and many custom materials will likely have textures without any details. Depending on the type of texture, the quality of the materials can be greatly improved with some extra work. Here are some key layers you should know about and understand what effects they provide:
The left-hand side menu shows the material features, for example enabling transparency via translucent/alphatest, or enabling specular lighting from cubemaps and stationary/dynamic lights.
These examples are only scratching the surface, it will be worth your time to go through each of the parameters and observe what effects they give in game!
Comparison shots of ze_ELEVATOR_escape and ze_saw will show you how much a single texture can be improved. Additionally, ze_PUTA modifies textures on lamp models to give a more realistic lighting from those lamp models.
This section will explain the optimisation methods you can take to make your map more accessible to players. Hopefully this section will see more entries as we do more ports, especially after the full release of CS2.
CS2 will supposedly not have any size limitation to a map upload (in contrast to the 150 mb limit for CS:GO FastDL), except for a 2 GB size limit when uploading to the workshop. In any case, we highly recommend compressing the map size as much as reasonably possible, for example to help players with slower internet speeds.
Potential methods of reducing the cubemap resolution and removing .los files before uploading to workshop has been discussed already, but if applicable, your port can be reduced in file size even more.
You can, when compiling the map, choose the appropriate lightmap scale (512, 1k, 2k, etc.) for the size and complexity of a map. The higher the lightmap resolution, the more space it will take up in the final .vpk. A simple map with only a couple of rooms would not need a 8k lightmap!
By default, lightning on props are baked onto the lightmap. Not only does this occupy a section of the lightmap which can be used on world meshes, we have found that props using baked lightning increases the size of the map as well.
By disabling Baked Lightning on props, the prop will be forced to use lightning using light probes insetad. This will result in slightly worser lightning, however in most of the cases it will be 'good enough' that most players will not notice during gameplay.
TIP: Disabling Baked Lightning is most beneficial for props that have large textures, for example with foliage models.
This method was more prominent in S1, but still is applicable in S2. Essentially, you reduce the bitrate of a sound file to a cheaper but acceptable quality. Although you do not have to be as strict in S2, you should still attempt this method if a sound file uses extremely high quality music for no valid reason.
In reality, it is more likely you will encounter the opposite when porting CS:GO maps; many music files had to have lower quality to meet with the FastDL size limit. In this case, you can attempt to identify the source of music and redownload them at a higher quality. Remember, the quality of the map is still something you have to consider when porting a map.
Since the Arms Race update, a new option has been added to the compile menu under Steam Audio. This will enhance the quality of audio within the map, at the cost of extra file size.
Naturally, for Zombie Escape maps, this feature is completely unnecessary and its use should be refrained. This is because Zombie Escape maps are usually busy in audio, for example together with the map music. Most importantly however, Zombie Escape is a casual gamemode where having good audio quality is not necessary at all, and most players would likely not even notice the improvements this feature may add.
This section lists topics that are too long to be included with the main text and/or was not deemed to be a required knowledge when porting.
Although some knowledge about S1 models helps with the process, it is not necessary to know when porting simple models to S2.
If you already have the model files that you want to import, then you can skip this step. If not, then you have to search for these model files. If the model you want to import is a native CS:GO model, then you have to use an extractor tool such as GCFscape to extract model files from pak01_dir.vpk found in your csgo/ folder.
Note: "model files" in this instance mean a combination of 4 files in total of the same name. Older source models have 5 files or a different combination.
Next, you have to decompile these models to obtain their .smd files. To do this, you have to use Crowbar, a tool that is used for everything related to S1 models. More information about how to set up the tool and how to operate is found on the official guide made by its developer.
From Crowbar, we only need to obtain .smd files, which may be a singular or multiple files depending on the prop that is being imported. The table below shows which .smd files you should tick for in the decompile tab of Crowbar. If are not familiar with Crowbar, leave everything else at default settings.
All props | Reference mesh SMD file (This is the actual model) |
Props that have collisions | Physics mesh SMD file (This is the collision model) |
Props that have animations | Bone animation SMD file (This stores information about how the model should transform throughout time; i.e. animations) |
If you have done the decompilation successfully, you now will have .smd files of the model and a bunch of other unimportant files. Move these .smd files into the CS2 addons folder, making sure that you keep the same model directories as CS:GO (you cannot open files that are outside of the addons folder).
Open up ModelDoc and create a new .vmdl file in the same directory of the original .mdl. Afterwards, you can follow this guide written in mapcore to import the decompiled .smd files into ModelDoc. Even though we use different import model files, the process of adding in imported model meshes in ModelDoc is still the same.
If all .smd are imported correctly, you should now be able to compile the model. After compiling the model, you can use the ModelDoc window to see if all prop properties have been implemented correctly. If applicable, you can now add other properties to the prop and compile again.
If you are unsure or get stuck, then you are always welcome to ask for help in our discord!
Editing CSM properties is by default disabled in csgo.fgd. If you wish to modify CSM, you will need to edit the file.
First, search for the block for light_environment. Afterwards, delete all the lines with (remove_key) in them.
If you launch hammer after completing the modification, you will find new parameters you can edit with light_environment.
Note: Editing the distance is a bit of a give and take; higher distance will increase the reach of the cascade layer at the cost of resolution. A good starting distance values are 1024, 512, 256, and 128 for cascade layers 1, 2, 3, and 4 respectively.
This requires use of blender (with a vertex coloring addon, such as Vertex Color Master for Blender, or any modeling software) to change the vertex colors on foliage meshes. Unless you have experience with them already, we recommend that you replace the problematic foliage props with CS2 ones.
When applying colors to the meshes, red should be used for the general sway of the tree, and blue should be used for individual flutters of leaves. First, apply a gradient from black to red from the bottom to the top of the foliage; darker colors represent less sway. Afterwards, apply blue to the edges of each branches/stems of the foliage mesh
In the end you would need to have a general red hue near the base of the branches, whilst the end of branches to be of blue hue - refer to the image below.
Example vertex coloring on a tree foliage model.
While porting your map, you may have decided to create a map icon for the loading screen and may have encountered some problems. Or it could be that the .svg that used to work in CS:GO seems to no longer work in CS2. This section aims to provide a solution for such issues.
To briefly describe the problem, the paths (i.e. the shapes) in .svg files can be defined in absolute or relative coordinates. If the .svg is written in relative coordinates, only the first layer will be displayed in CS2; it is presumed that the .svg interpreter in CS2 does not support translating the relative coordinates over the multiple layers. More technical explanation can be found here.
If you know how to use a svg vector editor, then the fix is pretty simple. Simply set the preferences of your editor to use absolute coordinates, move around the layers a bit so that you can save the .svg, and you should see it fixed immediately in CS2.
If you do not know how to use one however, it is recommended to use this png to svg converter as this converter will output a .svg in absolute coordinates. This will reduce the quality of the map icon, however it will not be perceivable on the loading screen itself.
Obviously, the main purpose of ports is that you convert maps from older games using as much of the new CS2 features as possible, while not changing much of the core gameplay or visuals of the ported map. This is the core mentality of the Source2 Zombie Escape ports, to simply increase the quality of the map and only making adjustments to make the map be playable in CS2.
However, and especially when working on your own port as / on behalf of the original mapper, you may choose to bring in additions to the map that deviates from the original map. In the end, it is up to your own discretion to decide the changes you want to bring to the ported map. With that said however, you should abide by as much of the original mapper's wishes as possible, as they are the ones that allowed you to port the maps in the first place.
This section will display comparison screenshots from a couple of ported Zombie Escape maps, listed in the alphabetical order. Hopefully these comparison screenshots provide you a better idea of the potentials S2 can achieve, and convince you to spend more time to substantially increase the quality of your port!
Showing off the new cs_office snow texture which replaced the previous ground texture, and with some additional shininess as well. Notice how the treeline in the skybox has adapted colors from the skybox.
Overall bloom and dustmote improvements in caverns, in addition to having swaying trees in the outside areas.
PBR enhanced textures that have parallax cubemaps, and further enhanced by general bloom improvements.
PBR enhanced floor with better bloom and postprocessing. This fire here is a stationary light that casts real time speculars.
Overhauled lighting using the new Source2 light entities, including enabling dynamic shadows to cast shadows from the fans. Further modified materials for extra shininess on surfaces with parallax cubemaps.
Almost entirely re-textured with CS2 materials, and many ported materials and models are revamped to match with CS2 quality. General improvement on lightning as well for more realistic lightning casting.
Improved textures using PBR shininess and revamped lightning for more realism.
(We are aware of the weird lightning cutoff on the ground!)
Revamped lighting by using a more realistic approach where light is emitted directly from the light-sources.
4.0 - Obsolete Guidelines
This hidden section will list any (potential) obsolete information that was only valid in the past versions of the game or the workshop tools; i.e. you should not be following any information present in this part. This section is only made for historical records.
In a situation where a future update revalidates a certain section, or if we find out that some information in this part is useful again, then they will be moved back into the main body of the guide as needed.
4.1 - env_soundscape at Player Spawn
Sounds have seen a massive change with S2, where now all sounds, including any custom sounds you may have, are all played with soundevents.
If you have tried compiling your map already, you may have noticed this issue when you launched your map in game - all sounds have echos regardless of whether you are indoors or outdoors. This is because every new round stops all soundevents played in the previous round, and this results in a state where no soundevents are playing in the new round.
To fix this issue, we simply need to add an env_soundscape near player spawns - this can even be an empty sound as we just need to have a soundevent playing at the start of each round.
From our tests, we have found that soundevents that have a dsp preset of reverb_22_outsideOpen provide the best quality for the in game sounds. This can be done by creating a custom soundevent (explained in the next subsection) and setting the dsp preset directly. Below is an example soundevent that you can use for your custom .sndevts file:
"Your.Soundevent.Name.Here"
{
type = "csgo_mega"
vsnd_files_track_01 = "sounds/common/null.vsnd"
override_dsp_preset = true
dsp_preset = "reverb_22_outsideOpen"
}
Simply have the env_soundscape refer to this soundevent (make sure to tick Override with soundevent), and set the radius of the env_soundscape to -1. A radius of -1 will allow the soundevent to play for all players that have a direct line of sight to the entity.
If you cannot get the env_soundscape to have a line of sight with all player spawns, or if the player spawns are divided into multiple areas, then you may choose to duplicate it for each spawn area, or set a suitable radius instead. If choosing a custom radius, ensure that the entity completely covers all player spawn points. Alternatively, you can use a trigger_soundscape in conjunction with an env_soundscape_triggerable.
Note: There are a plethora of soundevents available in base CS2. Our example above is only a recommendation, so feel free to use any other existing soundevents that you think gives better in-game audio qualities.
4.2 - Manual Packing into Standalone .vpk File
In release version of CS2, we expect that uploading your map to the workshop will automatically pack all necessary assets to your map. If true, you can simply upload your map to workshop without needing to change anything else (but perhaps you can try to improve the map a bit more with the next main section?).
However, there may be instances where you would rather have the map exported as a standalone .vpk file. For example, Zombie Escape servers in the future may use another method for file distribution (like fastdl in CS:GO). This section will introduce you to the steps you have to take to manually pack the map.
4.2.1 - Precaching Soundevent Files
As mentioned in the section about custom soundevents, you have to rename your .sndevts file to something other than 'soundevents_addon.vsndevts' when you are manually packing the map. Unfortunately, this in return will stop playing your custom sounds in game as any .vsndevts file other than 'soundevents_addon.vsndevts' will need to be precached in advance.
Precaching soundevents follows similar to CS:GO, as in using VScript to precache soundevents. You create a .lua VScript file with a Precache function within and place the script in game/<addon name>/scripts/vscripts/. This script then needs to be referenced by an entity in your map which will persist throughout all rounds, for example with a logic_auto. The script file itself must have a content similar to below:
function Precache(context)
PrecacheResource("soundevents/<custom name>.vsndevts", context)
end
where you input the name of your own .vsndevts file replacing the angular brackets.
Naturally, this will require you to patch VScript as well which you can find in the section about patching VScript.
4.2.2 - Manual Packing
Thankfully with the new addons system with S2, your game assets folder will never be contaminated, nor will assets from different addons contaminate with each other. This makes manual packing of your map easier (and cleaner) than in S1.
Your addon folder in the game/ directory is essentially what you need to pack your map into a .vpk file. The map is packed into a .vpk file by dragging the parent folder which contains all map assets into vpk.exe located in the Counter Strike: Global Offensive/bin/ folder.
Note: This vpk.exe is located in your CS:GO game folder, not your CS2 game folder.
However, your addon folder will also contain extra files that do not need to be packed; for example .los (lines of sight) files which are generated during the VIS compile step and are not needed in-game. Furthermore, your addon folder may contain compiled assets that your map no longer uses.
To remedy this issue, you can use an auto map packer made by a member of S2ZE to automatically pack the map or to detect assets the map uses and have them manually packed instead. When using the auto map packer, all assets that the map uses (including the 3D skybox vpk and all its assets) except for sounds and soundevent files will be made ready for you. You can move the sounds and soundevents folder by yourself after the packer is executed.
If you want to test if the map has been packed successfully, you have to unload the map addon first (or open the non-tools standalone CS2) and then launch your map. Additionally, you can use GCFScape to see the contents of your packed .vpk file.
Note: You can pack the map manually without using any tools, but this is really not recommended for a simple reason that you may miss unused assets when filtering manually.
3 September 2023
11 September 2023
12 September 2023
18 September 2023
26 Septebmer 2023
27 September 2023
5 October 2023
15 October 2023
3 November 2023
Workshop! Updates!
7 November 2023
8 November 2023
9 November 2023
11 November 2023
15 November 2023
17 November 2023
30 November 2023
5 December 2023
7 December 2023
14 December 2023
16 December 2023
19 December 2023
27 December 2023
28 December 2023
6 January 2024
13 January 2024
7 February 2024
Arms race!
11 February 2024
20 February 2024
25 February 2024
5 March 2024
11 May 2024
Major update! (to the guide, not the game)
12 May 2024
16 May 2024
29 May 2024
2 August 2024
9 September 2024
12 December 2024
26 January 2025
Happy (late) new year!
24 February 2025
24 July 2025