VMAP
.vmap is the file format for uncompiled Source2 maps when they are being edited in Hammer.
It is a DMX file under binary encoding version 9 with the format name vmap, Hammer can export a plain text version if you go to File -> Save Copy As Text
Compiling a vmap produces the .vmap_c the game loads, which is a different format, see Compiled maps.
Source2 Viewer can decompile compiled maps (.vmap_c usually contained within a VPK) into a .vmap
Datamodel.NET can be used to read and write kv2 files including vmaps, using C#.
An implemented version of the vmap format as described here can be found in the source code of
VRF (s2v), used for vmap_c decompilation.
Vmap example
The following is a simple vmap in plain text format from
Counter-Strike 2 consisting of a hammer mesh and an entity.
The Root of a vmap DMX file is CMapRootElement
In the text encoding of DMX, when an Element is only referenced once, it will be directly inserted as a value of the property that references it, when it's referenced multiple times, it will be extracted and put into the Root element, and everything referencing it will reference its UUID.
Vmap example (external page due to the large size)
Format versions
The current format version is 40. Hammer contains an updater with one step per version, so any older file is upgraded step by step while it loads, and saving writes it back at version 40. A file only needs to be valid for the version it declares.
The steps that changed the structure of the file rather than individual entity keys:
| Version | Change |
|---|---|
| 3 | MapClass renamed to MapNode |
| 5 | CVisibilityMgr with nodes and hiddenFlags |
| 6 | CMapSolid and CHammerMesh become CMapMesh, dmemesh becomes mesh |
| 7 | CMapRootElement and rootSelectionSet |
| 8 | Vertex paint moves into CDmePolygonMeshDataStream streams |
| 10 | connections becomes connectionsData, prefabs get variableOverrideNames and variableOverrideValues |
| 23 | variableTypes becomes variableTypeNames on CMapVariableSet |
| 28 | mapUsageType on CMapWorld, replacing backgroundMap |
| 29 | physicsSimplificationOverride and physicsSimplificationError on CMapMesh |
| 30 | Paths and cables (CMapPath, CMapPathNode, CMapCable) |
| 31 | disableShadows2 becomes disableShadows on meshes |
| 39 | prefab_has_runtime_entity_by_default on the world |
Most other steps rewrite keys inside entity_properties after an FGD change, such as light, sky, cubemap and scripted sequence keys.
Which game introduced which version, and game specific vmap nodes such as the
Dota 2 tile grid, are not documented yet.
How Hammer builds the file
Every object in a map is a Datamodel element, an instance of a CDmElement subclass inside Hammer. Saving the map is saving those elements, so the file mirrors Hammer's classes: the class name of each element is the name of the C++ class that created it, and the attributes are that class's members.
An attribute reaches the file in one of three ways, which is why the naming of attributes is so inconsistent.
Bound attributes
A class binds some of its members as attributes when it is constructed, base class first. These always exist on the element, from the moment it is created: nodeID, children, meshData, relayPlugData. Their names are whatever the programmer wrote, mostly camelCase.
Tool properties
Everything shown in the Object Properties panel is a tool property, described by a static property table per class. The table holds the display name, the category, and optionally a serialization name that differs from the property name: the property force hidden is saved as force_hidden, editor only as editorOnly, transform locked as transformLocked, and the mesh colour rendercolor as tintColor. A few properties are marked as not serialized at all, such as a mesh's name, the world's Map Type and a cordon's Cordon Name, because the value is stored elsewhere or only exists in the panel.
Tool properties are copied onto the element when the map is saved, after the bound attributes, and read back from it on load. The transform properties origin, angles and scales are the clearest case: Hammer keeps them as plain members of CMapPoint, and they become attributes only because CMapNode's property table lists them.
Markup
A few classes write extra attributes through their own save code, outside both mechanisms. The data array of a mesh data stream and the nodeData of a smart prop are written this way.
Attribute order
Because of the split, a freshly saved element lists all bound attributes of its class chain first and all tool properties after them, which is the order seen in the example. A file Hammer loaded keeps the order it came with, and Hammer accepts any order, so the order carries no meaning and other tools need not reproduce it.
Class hierarchy
Hammer's map classes form one chain, and each class in the file inherits the attributes of every class above it. Abstract classes never appear as a class name in a file, but their attributes do.
CDmElement
└── CMapAtom abstract, adds nothing to the file
└── CMapPoint abstract, owns origin, angles, scales
└── CMapNode id, children, variables, transform, visibility
├── CMapEntityIONode abstract, entity IO
│ ├── CMapGameDataNode abstract, entity key values
│ │ ├── CMapEntity
│ │ │ ├── CMapPath
│ │ │ │ └── CMapCable
│ │ │ └── CMapPathNode
│ │ └── CMapWorld
│ └── CMapInstance
│ ├── CMapPrefab
│ └── CMapProxyInstance
├── CMapGroup
│ └── CMapSpawnGroup
│ └── CMapWorldLayer
├── CMapMeshBase abstract, lighting and build settings
│ └── CMapMesh
│ ├── CMapStaticOverlay
│ └── CMapTileMesh
├── CMapBox
│ ├── CMapCordon
│ └── CMapTerrain
├── CMapNavData
├── CMapSmartProp
└── CVisibilityMgr
CMapRootElement, CMapSelectionSet, CStoredCamera, CStoredCameras, CMapVariableSet and the polygon mesh elements derive from CDmElement directly and are not nodes.
Vmap file structure
A list of vmap DMX nodes can be found below, this list is based on a
Counter-Strike 2 version 40 vmap. Inherited attributes are only listed on the class that introduces them.
The naming convention of attributes in vmaps is all over the place, some of the cases used include:
- flatcase
- camelCase
- PascalCase
- snake_case
m_member variable notation
The reason is in How Hammer builds the file.
"$prefix_element$"
The prefix element section is a DataModel feature allowing formats to store metadata, in vmaps it is used to store the map thumbnail and asset references.
"$prefix_element$"
{
"id" "elementid" "836b03ef-c2a5-41a2-a13e-308a114a46b7"
"asset_preview_thumbnail" "binary"
"
FFD8FFE000104A46494600010101006000600000FFDB004300030202030202030303030403030405
0805050404050A070706080C0A0C0C0B0A0B0B0D...(shortened for example)
"
"asset_preview_thumbnail_format" "string" "jpg"
"map_asset_references" "string_array"
[
"materials/dev/reflectivity_30.vmat"
]
}
-
asset_preview_thumbnail <
binary>
A binary blow storing the map thumbnail image. -
asset_preview_thumbnail_format <
string>
Stores the format of the asset_preview_thumbnail image. -
map_asset_references <
string_array>
An array of every asset used in this map.
DMElement
Not a vmap node, but the base DataModel element that every other node inherits from, All nodes have these properties.
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
- id <
elementid>
A UUID V4 ID used to refer to this node.
CMapRootElement
This is the main element of the vmap, it contains a few map specific properties and helper objects, and the main "world" object. All Elements which are referenced more than once will be put inside of this Root node.
"CMapRootElement"
{
"isprefab" "bool" "0"
"editorbuild" "int" "10533"
"editorversion" "int" "400"
"itemFile" "string" ""
"defaultcamera" "CStoredCamera"
"3dcameras" "CStoredCameras"
"world" "CMapWorld"
"visbility" "CVisibilityMgr"
"mapVariables" "CMapVariableSet"
"rootSelectionSet" "CMapSelectionSet"
"m_ReferencedMeshSnapshots" "element_array"
[
]
"m_bIsCordoning" "bool" "0"
"m_bCordonsVisible" "bool" "0"
"nodeInstanceData" "element_array"
[
]
}
-
isprefab <
bool>
If the map is a prefab or not. -
editorbuild <
int>
The build number that you can view inHelp -> About. -
editorversion <
int>
The editor version that wrote the file. Current Hammer writes 400. -
itemFile <
string>
The item file the map uses, a
Dota 2 feature. Empty otherwise. -
defaultcamera <
[CStoredCamera](#cstoredcamera)>
The default editor camera. -
3dcameras <
[CStoredCameras](#cstoredcameras)>
A list of other editor cameras. -
world <
CMapWorld>
An Element containing Elements or referenced to Elements which make up the map like entities, meshes, etc.. Hammer refuses to load a file whose root has no world. -
visbility <
CVisibilityMgr>
Yes you read that right, this Element is hilariously misspelled asvisbilityinstead ofvisibility, the misspelling is in Hammer itself so it is part of the format. It keeps track of what is hidden in the map, from quick hide, selection sets, etc.. -
mapVariables <
CMapVariableSet>
Map variables, they can be set in theMap -> MapProperties -> Map Variablestab. -
rootSelectionSet <CMapSelectionSet>
A hidden selection set which contains all other selection sets. -
m_ReferencedMeshSnapshots <
element_array>
Mesh snapshots referenced by this map. -
m_bIsCordoning <
bool>
If the cordon tool is active. -
m_bCordonsVisible <
bool>
If the cordon tool is visible. -
nodeInstanceData <
element_array>
Per node instance data for things like hammer preview lighting
CMapAtom
Anything that belongs to a map document. It never appears as a class name and adds nothing to the file, it is Hammer's layer for the undo and listener hooks.
CMapPoint
Inherits from CMapAtom
A map atom with a transform, relative to the parent node. It never appears as a class name, every node has these attributes.
"CMapPoint"
{
"origin" "vector3" "0 0 0"
"angles" "qangle" "0 0 0"
"scales" "vector3" "1 1 1"
}
-
origin <
vector3>
The origin of the node in Hammer units. -
angles <
qangle>
The angles of the node in euler angles. -
scales <
vector3>
The scales of the node.
CMapNode
Inherits from CMapPoint
The base class of everything in the map tree. It never appears as a class name itself, but every node has these properties. nodeID, referenceID, children, variableTargetKeys and variableNames are bound attributes, the rest are tool properties from the Transform and Visibility groups of Object Properties.
"CMapNode"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"nodeID" "int" "1"
"referenceID" "uint64" "0x0"
"children" "element_array"
"variableTargetKeys" "string_array"
"variableNames" "string_array"
"origin" "vector3" "0 0 0"
"angles" "qangle" "0 0 0"
"scales" "vector3" "1 1 1"
"transformLocked" "bool" "0"
"transformPin" "DmElement"
"force_hidden" "bool" "0"
"editorOnly" "bool" "0"
"customVisGroup" "string" ""
"randomSeed" "int" "1519914072"
}
-
nodeID <
int>
The ID of this node, can be seen in Hammer in the Outliner. Selection sets and overlays refer to nodes by it. -
referenceID <
uint64>
A 64 bit id that stays stable across prefab and instance boundaries, which is what transform pins target. Hammer will load maps just fine with this always being 0. -
children <
element_array>
All the children of this node, they can be other nodes directly (when the node only exists once) or UUID references to other nodes -
variableTargetKeys <
string_array>
variableNames <string_array>
Two parallel arrays: each entry names a property of this node and the map variable that drives it. -
transformLocked<
bool>
If true, stops the origin, angles or scales of this object from being changed in Hammer, the option to toggle this in the UI shows in the Transform group inObject Properties -
transformPin <CMapNodeTransformPin>
ThePinned Tosetting, only written when the node is pinned to another node. -
force_hidden <
bool>
If true it will force this object to not be visibile to VIS, shown in the Visibility group inObject Properties -
editorOnly <
bool>
If true it will force this object to not be compiled into the map, useful for developer only messages, shown in the Visibility group inObject Properties -
customVisGroup <
string>
Will add a custom Vis group in theAuto Vis Groupspanel, this object will show under it, useful for organisation. Shown in the Visibility group inObject Properties -
randomSeed <
int>
The seed of the node's random values, for features such as smart prop evaluation. Hammer picks one when the node is created.
CMapTransformPin
The Pinned To setting of a node: another node this one follows, found by its referenceID. It is written as a plain DmElement.
"transformPin" "DmElement"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"referenceName" "string" ""
"targetReferenceID" "uint64" "0x0"
"offsetOrigin" "vector3" "0 0 0"
"offsetAngles" "qangle" "0 0 0"
"pinAngles" "bool" "1"
"twoWay" "bool" "0"
}
-
referenceName <
string>
The name of the target node. -
targetReferenceID <
uint64>
ThereferenceIDof the target node. -
offsetOrigin <
vector3>
The position offset kept from the target. -
offsetAngles <
qangle>
The rotation offset kept from the target. -
pinAngles <
bool>
Whether the rotation follows the target as well as the position. -
twoWay <
bool>
Whether moving this node moves the target too.
CMapEntityIONode
Inherits from CMapNode
An abstract class, the base of every node that takes part in entity IO: CMapEntity, CMapWorld, CMapInstance and CMapPrefab. Both attributes are bound.
"relayPlugData" "DmePlugList" ""
"connectionsData" "element_array" ""
-
relayPlugData <DmePlugList>
The relay plugs of the node, used when a prefab exposes inputs and outputs. -
connectionsData <
element_array>
IO Outputs, contains DmeConnectionData elements.
CMapGameDataNode
Inherits from CMapEntityIONode
An abstract class, the base of CMapEntity and CMapWorld, the two nodes that carry entity keyvalues and know the FGD.
"entity_properties" "EditGameClassProps" ""
- entity_properties <EditGameClassProps>
A string -> string dictionary of entity keyvalues. The element is created by the class itself rather than bound, and its keys are reconciled with the FGD class definition whenever the class name changes.
DmePlugList
The relay plugs of a node, as four parallel arrays. They are empty for ordinary entities, a prefab uses them to expose the inputs and outputs of the entities inside it, which the compiler turns into prefab_relays.
"relayPlugData" "DmePlugList"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"names" "string_array"
[
]
"dataTypes" "int_array"
[
]
"plugTypes" "int_array"
[
]
"descriptions" "string_array"
[
]
}
-
names <
string_array>
The name of each plug. -
dataTypes <
int_array>
The data type of each plug. -
plugTypes <
int_array>
Whether each plug is an input or an output. -
descriptions <
string_array>
The description of each plug.
DmeConnectionData
An entity Output.
"DmeConnectionData"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"outputName" "string" "OnUser1"
"targetType" "int" "7"
"targetName" "string" "!self"
"inputName" "string" "FireUser1"
"overrideParam" "string" "overrideExample"
"delay" "float" "0"
"timesToFire" "int" "-1"
}
-
outputName <
string>
The name of the output. -
targetType <
int>
How the target name is matched, from theEntityIOTargetTypeenum.7isEntityNameOrClassName, which is what Hammer writes for a normal connection, including one that targets!self. See FGD files. -
targetName <
string>
The name of the entity being targeted. -
inputName <
string>
The name of the input on the entity being targeted. -
overrideParam <
string>
The value being passed along with the output. -
delay <
float>
The amount of time before the output is fired. -
timesToFire <
int>
How many times to refire the output.
EditGameClassProps
A string -> string dictionary storing entity keyvalues, seems to just be a standard kv2 element, which can act as a string dictionary. Every value is stored as a string, the compiler converts each one to the type the FGD declares.
CMapEntity
Inherits from CMapGameDataNode
A point or brush entity. Its only attributes of its own are two bound ones, brush entities keep their geometry as CMapMesh children.
"CMapEntity"
{
"id" "elementid" "180bd7ef-8347-4a97-b1cb-38b16877ca6b"
"hitNormal" "vector3" "0 0 1"
"isProceduralEntity" "bool" "0"
}
-
hitNormal <
vector3>
The surface normal the entity was dropped onto when it was placed. -
isProceduralEntity <
bool>
Whether the entity was generated by a tool rather than placed by hand.
CMapWorld
Inherits from CMapGameDataNode
This is the main element that contains everything in the vmap, its also the entity you edit when you change properties in Map -> Map Properties, it becomes the worldspawn entity at runtime.
"world" "CMapWorld"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"children" "element_array"
"variableTargetKeys" "string_array"
"variableNames" "string_array"
"relayPlugData" "DmePlugList"
"connectionsData" "element_array"
"nextDecalID" "int" "0"
"fixupEntityNames" "bool" "1"
"mapUsageType" "string" "standard"
"origin" "vector3" "0 0 0"
"angles" "qangle" "0 0 0"
"scales" "vector3" "1 1 1"
"transformLocked" "bool" "0"
"force_hidden" "bool" "0"
"editorOnly" "bool" "0"
"customVisGroup" "string" ""
"randomSeed" "int" "1641157616"
"entity_properties" "EditGameClassProps"
}
-
children <
element_array>
The children of CMapWorld are everything contained in the map, in the text encoding of DMX if a node is referenced only once, its inserted directly, if it is referenced more than once, it will be put into the Root element, in this case CMapRootElement and it will be referenced by its UUID. -
nextDecalID <
int>
The next free decal id, handed out as decals are placed. -
fixupEntityNames <
bool>
Whether prefabs placed in this map fix up their entity names by default, shown asFixup Entity Names By Defaultin the map properties. -
mapUsageType <
string>
The type of the map, shown asMap Typein the map properties and stored as the name of the enum value.-
standard
For normal maps. -
background
For CS2 background UI maps. -
skybox
For 3D skyboxes. -
minigame
Used in Dota 2 for Crownfall Act 4. -
sharedenvironment
Unknown.
-
-
randomSeed <
int>
See CMapNode.
CStoredCamera
An editor camera.
"defaultcamera" "CStoredCamera"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"position" "vector3" "-291.7109680176 -261.1103210449 217.3533782959"
"lookat" "vector3" "-291.8317871094 -260.2921142578 216.7912902832"
}
-
position <
vector3>
The position of the camera. -
lookat <
vector3>
This is the origin offset by one unit along the look vector.
CStoredCameras
The editor cameras stored in the vmap.
When are multiple editor cameras stored in the vmap?
"3dcameras" "CStoredCameras"
{
"id" "elementid" "21382dc1-34f4-4dc1-b017-0f431fddfdd5"
"activecamera" "int" "-1"
"cameras" "element_array"
}
-
activecamera <
int>
The current active camera index. -
cameras <
element_array>
An array of CStoredCamera elements.
CVisibilityMgr
Inherits from CMapNode
Manages hiding nodes. It is a node only because it inherits the node class, its transform is never used and stays at 0 0 0.
"visbility" "CVisibilityMgr"
{
"id" "elementid" "ce0026f6-da81-41e3-9267-3d2bdadba660"
"nodeID" "int" "0"
"referenceID" "uint64" "0x0"
"children" "element_array"
"variableTargetKeys" "string_array"
"variableNames" "string_array"
"nodes" "element_array"
"hiddenFlags" "int_array" `
"origin" "vector3" "0 0 0"
"angles" "qangle" "0 0 0"
"scales" "vector3" "1 1 1"
"transformLocked" "bool" "0"
"force_hidden" "bool" "0"
"editorOnly" "bool" "0"
"customVisGroup" "string" ""
"randomSeed" "int" "634985197"
}
-
nodes <
element_array>
Every node in the map which can be hidden. -
hiddenFlags <
int_array>
Per node hide flags, this array indexes into thenodeselement array.-
0
Visible. -
1
Selection set. -
2
Unknown. -
3
Unknown. -
4
Quick hide.
-
CMapSelectionSet
A selection set.
"CMapSelectionSet"
{
"id" "elementid" "2fa0034b-467f-4a4f-aa22-a432a2fee57c"
"children" "element_array"
"selectionSetName" "string" "selectionset"
"selectionSetData" "CObjectSelectionSetDataElement"
},
-
children <
element_array>
Selection sets can contain other selection sets, this is not selected objects, those are stored in selectionSetData. -
selectionSetName <
string>
The name of the selection set. -
selectionSetData <DMElement>
The data of the selection set, it seems to be an opaque element but it only takesCObjectSelectionSetDataElementandCFaceSelectionSetDataElement
CObjectSelectionSetDataElement
"selectionSetData" "CObjectSelectionSetDataElement"
{
"id" "elementid" "ab42b08e-ab9b-4d9f-b2c7-299b165b1f2e"
"name" "string" "objectSelectionSetData"
"selectedObjects" "element_array"
}
-
name <
string>
The name of the selection set data element. doesn't seem like the user can set this, its alwaysobjectSelectionSetData, may be used to tell which data object selectionSetData contains in their DMX implementation? -
selectedObjects <
element_array>
A list of the objects contained in this selection set.
CFaceSelectionSetDataElement
"selectionSetData" "CFaceSelectionSetDataElement"
{
"id" "elementid" "fe928e85-ae50-4034-8016-7ff0cdf77a64"
"name" "string" "faceSelectionSetData"
"meshes" "element_array"
"faces" "int_array"
}
-
name <
string>
The name of the selection set data element. doesn't seem like the user can set this, its alwaysfaceSelectionSetData, may be used to tell which data object selectionSetData contains in their DMX implementation? -
meshes <
element_array>
A list of the meshes contained in this selection set. -
faces <
int_array>
A list of mesh faces contained in this selection set.
CEdgeSelectionSetDataElement
The mesh edges a CMapSelectionSet selects.
"CEdgeSelectionSetDataElement"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"edges" "int_array"
"meshes" "element_array"
}
-
edges <
int_array>
Half edge indices into the meshes ofmeshes. -
meshes <
element_array>
The CMapMesh nodes that own the selected edges.
CVertexSelectionSetDataElement
The mesh vertices a CMapSelectionSet selects.
"CVertexSelectionSetDataElement"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"vertices" "int_array"
"meshes" "element_array"
}
-
vertices <
int_array>
Vertex indices into the meshes ofmeshes. -
meshes <
element_array>
The CMapMesh nodes that own the selected vertices.
CMapPrefab
Inherits from CMapInstance
A prefab, an instance whose contents come from another map file. variableOverrideNames and variableOverrideValues are bound, the rest are tool properties.
"CMapPrefab"
{
"id" "elementid" "5e3176dd-3b19-4f28-8318-7ebaa88b9a90"
"nodeID" "int" "6"
"referenceID" "uint64" "0xdadc15530f843d58"
"children" "element_array"
"variableTargetKeys" "string_array"
"variableNames" "string_array"
"relayPlugData" "DmePlugList"
"connectionsData" "element_array"
"target" "element" ""
"variableOverrideNames" "string_array"
"variableOverrideValues" "string_array"
"origin" "vector3" "0 0 0"
"angles" "qangle" "0 0 0"
"scales" "vector3" "1 1 1"
"transformLocked" "bool" "0"
"force_hidden" "bool" "0"
"editorOnly" "bool" "0"
"customVisGroup" "string" ""
"randomSeed" "int" "1910343828"
"tintColor" "color" "255 255 255 255"
"visexclude" "bool" "0"
"targetMapPath" "string" "maps/prefabs/s2wikiprefab.vmap"
"targetName" "string" ""
"fixupEntityNames" "bool" "1"
"useTargetNameAsPrefix" "bool" "0"
"loadIfNested" "bool" "1"
"prefabRuntimeEntity" "bool" "0"
"loadAtRuntime" "bool" "0"
}
-
target <
element>
Inherited from CMapInstance, unused and empty since the contents come from the file. -
variableOverrideNames <
string_array>
variableOverrideValues <string_array>
Two parallel arrays: the map variables of the prefab file this placement overrides, and the values it gives them. -
targetMapPath <
string>
The map to load. -
targetName <
string>
The name given to the prefab instance, used as the entity name prefix whenuseTargetNameAsPrefixis set. -
fixupEntityNames <
bool>
If enabled, any entity target names within the prefab will have a prefix applied to ensure they are unique. This prevents any issues with entities in two different prefabs having name collisions. -
useTargetNameAsPrefix <
bool>
If this is enabled and name fixup is enabled, the prefix used for name fixup will be the prefab target name instead of the unique id. If the target name is empty then the prefab the unique id will still be used as the prefix. Note that if two prefabs use the same target name for their prefix it will be possible to have entities inside the prefabs end up with name collisions. -
loadIfNested <
bool>
If enabled the prefab will be loaded when it is the child of another prefab, if disabled, this prefab will not be loaded if it is the child of another prefab. -
prefabRuntimeEntity <
bool>
Whether the prefab compiles into apoint_prefabentity of its own, shown asCreate Prefab Runtime Entity. -
loadAtRuntime <
bool>
If enabled the prefab will not be baked into the parent map during map compile, but instead will be dynamically loaded in the game. This requires the target map to be compiled separately. Additionally this requires support for dynamic loading of maps by the game, which may not be supported by all games and game systems. Do not use without checking to see if this is fully supported by the game you are working on.
CMapInstance
Inherits from CMapEntityIONode
An instance. target is bound, tintColor and visexclude are tool properties.
"CMapInstance"
{
"id" "elementid" "b4c5ff57-756d-4fad-b2c4-7c3599acd5d1"
"nodeID" "int" "9"
"referenceID" "uint64" "0xa644a071fe2a1342"
"variableTargetKeys" "string_array"
"variableNames" "string_array"
"relayPlugData" "DmePlugList"
"connectionsData" "element_array"
"target" "element" "d3c5aac9-c6b0-4ca0-a74f-1bad53097d65"
"origin" "vector3" "-328 -80 24"
"angles" "qangle" "0 0 0"
"scales" "vector3" "1 1 1"
"transformLocked" "bool" "0"
"force_hidden" "bool" "0"
"editorOnly" "bool" "0"
"customVisGroup" "string" ""
"randomSeed" "int" "1789577885"
"tintColor" "color" "255 255 255 255"
"visexclude" "bool" "0"
}
-
target <
element>\ A CMapGroup element containing all the objects inside of this instance. -
tintColor <
color>\ If this color is set, all objects inside of the instance will be tinted. -
visexclude <
bool>\ If true, everything inside of the instance will be excluded from vis.
CMapGroup
Inherits from CMapNode
A group which can contain nodes. It binds nothing of its own, its one tool property is the deformation mode.
"CMapGroup"
{
"id" "elementid" "d3c5aac9-c6b0-4ca0-a74f-1bad53097d65"
"deformationMode" "int" "1"
}
- deformationMode <
int>
How the group's contents deform when the group is transformed, shown asDeformation Modein the Transform group.
CMapWorldLayer
Inherits from CMapGroup
A world layer, a group that compiles into a layer of its own. worldLayerName is bound.
"CMapWorldLayer"
{
"id" "elementid" "d3c5aac9-c6b0-4ca0-a74f-1bad53097d65"
"worldLayerName" "string" "layer"
}
- worldLayerName <
string>
The name of the layer.
CMapVariableSet
Stores map variables.
"mapVariables" "CMapVariableSet"
{
"id" "elementid" "80fdfd0c-3ea4-4519-9e66-23fafdc20d60"
"variableNames" "string_array"
"variableValues" "string_array"
"variableTypeNames" "string_array"
"variableTypeParameters" "string_array"
"variableGroupNames" "string_array"
"m_ChoiceGroups" "element_array"
"variableAndChoiceOrder" "int_array"
}
-
variableNames <
string_array>
The name of the map variable. -
variableValues <
string_array>
The value of the map variable. -
variableTypeNames <
string_array>
The type of the map variable, likestring. -
variableTypeParameters <
string_array>
The type paremeter of the map variable, not sure what this is. -
variableGroupNames <
string_array>
The group each variable is shown under. -
m_ChoiceGroups <
element_array>
Not sure what this does either, but takes a CMapVariableChoiceGroup object. -
variableAndChoiceOrder <
int_array>
The display order of the variables and choice groups.
CMapVariableChoiceGroup
A map variable choice group.
"CMapVariableChoiceGroup"
{
"id" "elementid" "795f358a-afb8-4f98-993b-0fd940de5aae"
"name" "string" "newChoiceGroup"
"m_ChoiceVariables" "string_array"
"m_Choices" "element_array"
"m_ActiveValue" "string" ""
"m_GroupName" "string" ""
}
-
name <
string>
The name of the choice group. -
m_ChoiceVariables <
string_array>
The names of the variables the choice drives. -
m_Choices <
element_array>
The choices, each a plain element holding the values of the choice variables. -
m_ActiveValue <
string>
The name of the active choice, empty for none. -
m_GroupName <
string>
The name shown for the group.
CMapPath
Inherits from CMapEntity
A spline of CMapPathNode children, the base of cables and particle paths.
"CMapPath"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"interpolationType" "int" "0"
"closedLoop" "bool" "0"
"particleSnapshotSpacing" "float" "16"
}
-
interpolationType <
int>
How the spline interpolates between its nodes. -
closedLoop <
bool>
Whether the last node connects back to the first. -
particleSnapshotSpacing <
float>
Distance between the points a particle snapshot samples along the path.
CMapPathNode
Inherits from CMapEntity
One control point of a CMapPath.
"CMapPathNode"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"inTangent" "vector3" "0 0 0"
"outTangent" "vector3" "0 0 0"
"inTangentType" "int" "1"
"outTangentType" "int" "1"
}
-
inTangent <
vector3>
Tangent of the spline entering this node. -
outTangent <
vector3>
Tangent of the spline leaving this node. -
inTangentType <
int>
HowinTangentis computed. -
outTangentType <
int>
HowoutTangentis computed.
CMapCable
Inherits from CMapPath
A cable rendered as a tube swept along a CMapPath.
"CMapCable"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"materialName" "string" ""
"tintColor" "color" "255 255 255 255"
"lightingOriginName" "string" ""
"numSides" "int" "4"
"tessellationSpacing" "float" "16"
"radius" "float" "0.5"
"flipFaces" "bool" "0"
"textureOrientation" "int" "0"
"textureScale" "float" "0.25"
"textureRepeatsCircumference" "float" "1"
"textureOffsetAlongPath" "float" "0"
"textureOffsetCircumference" "float" "0"
"collisionEnabled" "bool" "0"
"physicsSimplificationError" "float" "2"
"visOccluder" "bool" "0"
}
-
materialName <
string>
Material of the cable. -
tintColor <
color>
Tint applied to the cable. -
lightingOriginName <
string>
Name of the entity the cable takes its lighting from, empty for none. -
numSides <
int>
Number of sides of the tube. -
tessellationSpacing <
float>
Distance between the rings of the tube along the path. -
radius <
float>
Radius of the tube. -
flipFaces <
bool>
Whether the tube faces inwards. -
textureOrientation <
int>
Whether the texture runs along the path (0) or around it (1). -
textureScale <
float>
Texture repeats per unit along the path. -
textureRepeatsCircumference <
float>
Texture repeats around the circumference. -
textureOffsetAlongPath <
float>
Texture offset along the path. -
textureOffsetCircumference <
float>
Texture offset around the circumference. -
collisionEnabled <
bool>
Whether the cable gets physics geometry. -
physicsSimplificationError <
float>
Error the physics simplification is allowed to introduce. -
visOccluder <
bool>
Whether the cable occludes what is behind it.
CMapCordon
Inherits from CMapNode
The cordon box, named cordon. Its transform is the box: origin is its centre and scales its size. It adds no attributes of its own.
CMapNavData
Inherits from CMapNode
Node holding the navigation mesh generation settings of the map.
"CMapNavData"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"navData" "CDmeNavData"
}
- navData <CDmeNavData>
The settings.
CDmeNavData
Navigation mesh generation settings. Per agent hull values are parallel arrays with settingsAgentNumHulls entries.
"navData" "CDmeNavData"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"settingsUseProjectDefaults" "bool" "1"
"settingsTileSize" "float" "128"
"settingsCellSize" "float" "1.5"
"settingsCellHeight" "float" "2"
"settingsRegionMinSize" "int" "8"
"settingsRegionMergeSize" "int" "20"
"settingsDetailSampleDist" "float" "120"
"settingsDetailSampleMaxError" "float" "2"
"settingsVertsPerPoly" "int" "4"
"settingsEdgeMaxLen" "int" "1200"
"settingsEdgeMaxError" "float" "45"
"settingsSmallAreaOnEdgeRemovalSize" "float" "-1"
"settingsAgentHullPreset" "string" ""
"settingsAgentHullsVDataOverride" "string" ""
"settingsAgentNumHulls" "int" "1"
"settingsAgentEnabled" "bool_array"
"settingsAgentRadius" "float_array"
"settingsAgentHeight" "float_array"
"settingsAgentShortHeightEnabled" "bool_array"
"settingsAgentShortHeight" "float_array"
"settingsAgentCrawlEnabled" "bool_array"
"settingsAgentCrawlHeight" "float_array"
"settingsAgentMaxClimb" "float_array"
"settingsAgentMaxSlope" "int_array"
"settingsAgentMaxJumpDownDist" "float_array"
"settingsAgentMaxJumpHorizDistBase" "float_array"
"settingsAgentMaxJumpUpDist" "float_array"
"settingsAgentBorderErosion" "int_array"
}
-
settingsUseProjectDefaults <
bool>
Whether the project defaults override the settings stored here. -
settingsTileSize <
float>
Size of a navigation tile, in units. -
settingsCellSize <
float>
Size of a voxel cell, in units. -
settingsCellHeight <
float>
Height of a voxel cell, in units. -
settingsRegionMinSize <
int>
Smallest region kept, in cells. -
settingsRegionMergeSize <
int>
Regions smaller than this are merged, in cells. -
settingsDetailSampleDist <
float>
Sampling distance of the detail mesh. -
settingsDetailSampleMaxError <
float>
Error the detail mesh is allowed to introduce. -
settingsVertsPerPoly <
int>
Maximum vertices per navigation polygon. -
settingsEdgeMaxLen <
int>
Longest polygon edge, in cells. -
settingsEdgeMaxError <
float>
Error an edge is allowed to deviate from the geometry. -
settingsSmallAreaOnEdgeRemovalSize <
float>
Areas on edges smaller than this are removed, -1 to keep them. -
settingsAgentHullPreset <
string>
Name of the agent hull preset, empty for none. -
settingsAgentHullsVDataOverride <
string>
Path of the vdata overriding the agent hulls, empty for none. -
settingsAgentNumHulls <
int>
Number of agent hulls. -
settingsAgentEnabled <
bool_array>
Whether each hull is generated. -
settingsAgentRadius <
float_array>
Radius of each hull. -
settingsAgentHeight <
float_array>
Height of each hull. -
settingsAgentShortHeightEnabled <
bool_array>
Whether each hull has a crouching height. -
settingsAgentShortHeight <
float_array>
Crouching height of each hull. -
settingsAgentCrawlEnabled <
bool_array>
Whether each hull has a crawling height. -
settingsAgentCrawlHeight <
float_array>
Crawling height of each hull. -
settingsAgentMaxClimb <
float_array>
Highest step each hull can climb. -
settingsAgentMaxSlope <
int_array>
Steepest slope each hull can walk, in degrees. -
settingsAgentMaxJumpDownDist <
float_array>
Furthest each hull can jump down. -
settingsAgentMaxJumpHorizDistBase <
float_array>
Furthest each hull can jump horizontally. -
settingsAgentMaxJumpUpDist <
float_array>
Highest each hull can jump up. -
settingsAgentBorderErosion <
int_array>
Cells eroded from the border for each hull, -1 for the default.
CMapSmartProp
Inherits from CMapNode
A smart prop placed in the map, evaluated by Hammer into the props it stands for.
"CMapSmartProp"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"smartPropFilename" "string" ""
"tintColor" "color" "255 255 255 255"
"evaluationLocked" "bool" "0"
"constrainToPrefab" "bool" "0"
"shapeReferences" "element_array"
"alpha" "int" "255"
"cullDistance" "float" "0"
"fadeStartDistance" "float" "-1"
"lightingOriginName" "string" ""
"disableShadows" "int" "0"
"bakedLigthtingMode" "int" "-1"
"lightmapScaleBias" "int" "0"
"bakeLightingDoubleSided" "bool" "0"
"emissiveLightingEnabled" "bool" "1"
"emissiveLightingBoost" "float" "1"
"collisionMode" "int" "-1"
"collisionPropertyOverride" "string" ""
"isVisOccluder" "bool" "0"
"renderToCubeMaps" "bool" "1"
"disabledInLowQuality" "bool" "0"
"bakeToWorld" "bool" "0"
"disableMerging" "bool" "0"
"renderWithDynamic" "bool" "0"
"nodeData" "DMElement"
}
-
smartPropFilename <
string>
Path of the smart prop definition. -
tintColor <
color>
Tint applied to the evaluated props. -
evaluationLocked <
bool>
Whether Hammer keeps the current evaluation instead of re-evaluating on changes. -
constrainToPrefab <
bool>
Whether the evaluation is constrained to the prefab the smart prop sits in. -
shapeReferences <
element_array>
Nodes the smart prop shapes itself around, each wrapped in a plain element with a "value" attribute. -
alpha <
int>
Render alpha, 0 to 255. -
cullDistance <
float>
Distance beyond which the props are culled, 0 for never. -
fadeStartDistance <
float>
Distance at which the props start fading out, -1 to never fade. -
lightingOriginName <
string>
Name of the entity the props take their lighting from, empty for none. -
disableShadows <
int>
Shadow casting mode, 0 to cast shadows. -
bakedLigthtingMode <
int>
How the props take part in baked lighting, -1 for the default. Hammer stores this attribute with the misspelled name. -
lightmapScaleBias <
int>
Lightmap resolution bias of the props. -
bakeLightingDoubleSided <
bool>
Whether both sides of the props receive baked lighting. -
emissiveLightingEnabled <
bool>
Whether emissive materials on the props light the scene when baking. -
emissiveLightingBoost <
float>
Multiplier on the emissive light the props contribute when baking. -
collisionMode <
int>
Collision mode of the props, -1 for the default. -
collisionPropertyOverride <
string>
Collision property overriding the one of the props' materials, empty for none. -
isVisOccluder <
bool>
Whether the props occlude what is behind them. -
renderToCubeMaps <
bool>
Whether the props appear in cubemap renders. -
disabledInLowQuality <
bool>
Whether the props are left out at low quality settings. -
bakeToWorld <
bool>
Whether the props are baked into the world geometry. -
disableMerging <
bool>
Whether the compiler must not merge the props with others. -
renderWithDynamic <
bool>
Whether the props render in the dynamic pass. -
nodeData <
element>
The evaluated state of the smart prop, a plain "DmElement" named "nodeData" holding its parameters and configuration.
CDmeNodeInstanceData
Baked per vertex lighting of one node, stored in the root's nodeInstanceData and named after the node id.
"CDmeNodeInstanceData"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"vertexLightingData" "color_array"
"vertexLightingPositions" "vector3_array"
"vertexLightingNormals" "vector3_array"
}
-
vertexLightingData <
color_array>
Baked light colour per vertex. -
vertexLightingPositions <
vector3_array>
Position of each baked vertex. -
vertexLightingNormals <
vector3_array>
Normal of each baked vertex.
CDmeReferencedMeshSnapshot
The render geometry of a model the map references, kept so that vertex paint can be applied to it.
"CDmeReferencedMeshSnapshot"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"m_MeshResourceName" "string" ""
"m_DrawCalls" "element_array"
}
-
m_MeshResourceName <
string>
Path of the model. -
m_DrawCalls <
element_array>
List of CDmeDrawCallSnapshot elements, one per draw call of the model.
CDmeDrawCallSnapshot
The vertices of one draw call of a CDmeReferencedMeshSnapshot.
"CDmeDrawCallSnapshot"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"m_Positions" "vector3_array"
"m_Normals" "vector3_array"
"m_Texcoords" "vector2_array"
"m_nHash" "int" "0"
"m_Material" "string" ""
}
-
m_Positions <
vector3_array>
Vertex positions. -
m_Normals <
vector3_array>
Vertex normals. -
m_Texcoords <
vector2_array>
Vertex texture coordinates. -
m_nHash <
int>
Hash of the draw call, used to match it to the compiled model. -
m_Material <
string>
Material of the draw call.
CDmExtraVertexData
Vertex paint applied to a prop entity, stored on the entity as "extra_vertex_data".
"CDmExtraVertexData"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"m_ExtraStreams" "element_array"
}
- m_ExtraStreams <
element_array>
List of CDmExtraVertexStream elements, one per painted draw call.
CDmExtraVertexStream
Vertex paint of one draw call of a prop.
"CDmExtraVertexStream"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"m_nDrawCallIndex" "int" "0"
"m_nMeshIndex" "int" "0"
"m_pVertexData" "element" ""
}
-
m_nDrawCallIndex <
int>
Index of the draw call within the mesh. -
m_nMeshIndex <
int>
Index of the mesh within the model. -
m_pVertexData <
element>
A "DmeVertexData" element holding the painted streams, such as "VertexPaintTintColor" and "PerVertexLighting", each with an "Indices" array.
The following mesh related nodes will only be explained in shortas they are quite complex, an in-depth explanation can be found in the Hammer meshes section of this page.
CMapMeshBase
Inherits from CMapNode
An abstract class holding the lighting and build settings shared by meshes, overlays and tile meshes. It never appears as a class name. It binds nothing, every attribute is a tool property from the Lighting and Build groups of Object Properties.
"CMapMeshBase"
{
"disableShadows" "int" "0"
"bakelighting" "bool" "1"
"cubeMapName" "string" ""
"emissiveLightingEnabled" "bool" "1"
"emissiveLightingBoost" "float" "1"
"lightingDummy" "bool" "0"
"bakeLightDoubleSided" "bool" "0"
"visexclude" "bool" "0"
"disablemerging" "bool" "0"
"renderwithdynamic" "bool" "0"
"renderToCubemaps" "bool" "1"
"keep_vertices" "bool" "0"
"fademindist" "float" "-1"
"fademaxdist" "float" "0"
"disableHeightDisplacement" "bool" "0"
}
-
disableShadows <
int>
Which shadows the mesh casts, shown asCast Shadows.-
0
Enabled. -
1
No shadows. -
2
Only realtime shadows. -
3
Only baked shadows.
-
-
bakelighting <
bool>
When true the mesh receives baked lighting. -
cubeMapName <
string>
Used to manually assign a named env_cubemap, env_cubemap_box or env_combined_light_probe_volume to a mesh.infoThis forces the mesh into a slower rendering path and does not support the explicit assignment of lightprobes. Use with caution.
-
emissiveLightingEnabled <
bool>
Allow this mesh to emit lighting. Note that this only works on materials with Self Illum parameters, and is only visible in the GPU Path Tracing Preview and in the final lightmap bake. -
emissiveLightingBoost <
float>
Used to boost emissive lighting from a mesh. Note that boosting emissive on smaller meshes can create more lighting artifacts/noise. -
lightingDummy <
bool>
Causes the mesh to contribute to lighting, but not render in the final map. -
bakeLightDoubleSided <
bool>
Whether both sides of the mesh are lit in the bake. Not present in older files. -
visexclude <
bool>
When true forces this mesh to not contribute to VIS. -
disablemerging <
bool>
When true, disables compile time mesh merging, meaning this mesh wont merge with meshes sharing the same material. -
renderwithdynamic <
bool>
When true causes this mesh to render in the dynamic pass, with other dynamic entities like players. -
renderToCubemaps <
bool>
Whether the mesh appears in cubemap renders. -
keep_vertices <
bool>
When true the compiler keeps the mesh's vertices instead of welding them, passed to the model builder askeep_vertices. -
fademindist <
float>
The distance at which this mesh will start to fade. -
fademaxdist <
float>
The distance at which this mesh is entirely invisible. -
disableHeightDisplacement <
bool>
When true it disables displacement.
CMapMesh
Inherits from CMapMeshBase
A Hammer mesh.
Inherited properties will be ommited below due to the large size of this node. meshData is bound, everything else is a tool property, the mesh name shown in the panel is not serialized.
"CMapMesh"
{
"id" "elementid" "581ccd67-3a41-4d2a-b6b0-8cf6fbbe493e"
"meshData" "CDmePolygonMesh"
"smoothingAngle" "float" "40"
"tintColor" "color" "255 255 255 255"
"renderAmt" "int" "255"
"physicsType" "string" "default"
"physicsCollisionProperty" "string" ""
"physicsGroup" "string" ""
"physicsInteractsAs" "string" ""
"physicsInteractsWith" "string" ""
"physicsInteractsExclude" "string" ""
"physicsIncludedDetailLayers" "element_array"
"physicsMissingDetailLayers" "element_array"
"physicsSimplificationOverride" "bool" "0"
"physicsSimplificationError" "float" "0"
}
-
meshData <
CDmePolygonMesh>
A CDmePolygonMesh element storing all the polygon mesh information. -
smoothingAngle <
float>
The minimum angle for an edge to automatically become smooth. -
tintColor <
color>
Tints the mesh. The property is calledrendercolorin Hammer and saved under this name. -
renderAmt <
int>
The alpha transparency of the mesh, 0 to 255. -
physicsType <
string>
The physics type of the mesh. Hammer stores an enum and writes its name.-
none
Not solid. -
default
Seems to bemeshby default. -
convex_single
A single convex hull -
convex_multi
Multiple convex hulls (per piece?) -
mesh
A triangle mesh.
-
-
physicsCollisionProperty <
string>
If specified, provides the name of an entry in scripts/collision_properties.txt that specifies the collision group and interaction layers to use, rather than those specified in the material. -
physicsGroup <
string>
Directly specifies the name of a collision group to assign to the mesh, replaces any group specified by the material or collision property. -
physicsInteractsAs <
string>
Specifies additional interaction layers to append to the set of Interacts As layers assigned to the mesh. -
physicsInteractsWith <
string>
Specifies additional interaction layers to append to the set of Interacts With layers assigned to the mesh. -
physicsInteractsExclude <
string>
Specifies additional interaction layers to append to the set of Interacts With layers assigned to the mesh. -
physicsIncludedDetailLayers <
element_array>
physicsMissingDetailLayers <element_array>
The detail layers the mesh's physics includes and lacks. Written by newer Hammer builds only. -
physicsSimplificationOverride <
bool>
WhetherphysicsSimplificationErroroverrides the default simplification. -
physicsSimplificationError <
float>
The error permitted when simplifying the geometry of this mesh into a physics mesh.
CMapStaticOverlay
Inherits from CMapMesh
A decal that uses its own Hammer mesh to project onto geometry. projectionTargets is bound, the rest are tool properties.
"CMapStaticOverlay"
{
"id" "elementid" "581ccd67-3a41-4d2a-b6b0-8cf6fbbe493e"
"projectionTargets" "int_array"
"renderOrder" "int" "0"
"disabledInLowQuality" "bool" "0"
"useBaseNormals" "bool" "0"
"projectionFar" "float" "128"
"MaterialAdjustmentParamsStruct" "DmElement"
"projectOnBackFaces" "bool" "0"
"backFacingAngle" "float" "90"
"projectionMode" "int" "0"
}
-
projectionTargets <
int_array>
ThenodeIDs of the nodes the overlay projects onto, used in projection mode 3. -
renderOrder <
int>
The order among overlapping overlays. -
disabledInLowQuality <
bool>
Whether the overlay is skipped in low quality mode. -
useBaseNormals <
bool>
Whether the overlay is shaded with the normals of the surface it projects onto. -
projectionFar <
float>
How far the overlay projects, in Hammer units. -
MaterialAdjustmentParamsStruct <CMapOverlayMaterialAdjustmentParams>
The material adjustments of the overlay, as a plainDmElement. -
projectOnBackFaces <
bool>
Whether faces pointing away from the overlay receive it. -
backFacingAngle <
float>
The maximum angle between the overlay and a face for the face to receive it, in degrees. -
projectionMode <
int>
What the overlay projects onto: everything (0), world geometry (1), models (2) or the nodes inprojectionTargets(3).
CMapOverlayMaterialAdjustmentParams
The material adjustments of a CMapStaticOverlay.
"MaterialAdjustmentParamsStruct" "DmElement"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"ColorBrightness" "float" "0.5"
"ColorContrast" "float" "0.5"
"ColorAlpha" "float" "1"
"RoughnessBrightness" "float" "0.5"
"RoughnessContrast" "float" "0.5"
"ShadingAlpha" "float" "1"
"NormalIntensity" "float" "0.75"
"RoughnessMetalnessOverride" "bool" "0"
"NormalBlendOverride" "bool" "1"
}
-
ColorBrightness <
float>
Colour brightness adjustment, 0.5 for none. -
ColorContrast <
float>
Colour contrast adjustment, 0.5 for none. -
ColorAlpha <
float>
Opacity of the colour. -
RoughnessBrightness <
float>
Roughness brightness adjustment, 0.5 for none. -
RoughnessContrast <
float>
Roughness contrast adjustment, 0.5 for none. -
ShadingAlpha <
float>
Opacity of the shading. -
NormalIntensity <
float>
Strength of the decal's normal map. -
RoughnessMetalnessOverride <
bool>
Whether the decal's roughness and metalness replace the surface's. -
NormalBlendOverride <
bool>
Whether the decal's normals blend over the surface's.
CDmePolygonMesh
This element contains all of the half-edge polygon data of a hammer mesh. Every attribute is bound.
"meshData" "CDmePolygonMesh"
{
"id" "elementid" "d4460070-41c1-4483-a0b1-b850b32eccc4"
"name" "string" "meshData"
"vertexEdgeIndices" "int_array"
"vertexDataIndices" "int_array"
"edgeVertexIndices" "int_array"
"edgeOppositeIndices" "int_array"
"edgeNextIndices" "int_array"
"edgeFaceIndices" "int_array"
"edgeDataIndices" "int_array"
"edgeVertexDataIndices" "int_array"
"faceEdgeIndices" "int_array"
"faceDataIndices" "int_array"
"materials" "string_array"
"vertexData" "CDmePolygonMeshDataArray"
"faceVertexData" "CDmePolygonMeshDataArray"
"edgeData" "CDmePolygonMeshDataArray"
"faceData" "CDmePolygonMeshDataArray"
"subdivisionData" "CDmePolygonMeshSubdivisionData"
}
-
name <
string>
Seems to always bemeshData. -
vertexEdgeIndices <
int_array>
An index to one of the half-edges starting from this vertex. -
vertexDataIndices <
int_array>
Index to theVertexDatastreams. -
edgeVertexIndices <
int_array>
The destination vertex of this half-edge. -
edgeOppositeIndices <
int_array>
Index to the twin of this half-edge. -
edgeNextIndices <
int_array>
Index to the half-edge that this half-edge points to. -
edgeFaceIndices <
int_array>
Index to the face this half-edge is part of, -1 if the half edge is next to the void (external half-edge). -
edgeDataIndices <
int_array>
Per half-edge index toEdgeDatastreams. -
edgeVertexDataIndices <
int_array>
Per half-edge index toFaceVertexDatastreams. -
faceEdgeIndices <
int_array>
Per face index to one of the inner edges encapsulating this face. This effectively is what encodes faces in the mesh, one entry here is one face. -
faceDataIndices <
int_array>
Per Face index toFaceDatastreams. -
materials <
string_array>
A list of every material used in the mesh, without duplicates, this will be indexed into bymeshindexin theFaceDatastream. -
vertexData <
CDmePolygonMeshDataArray>
Stores vertex positions. -
faceVertexData <
CDmePolygonMeshDataArray>
Stores per half-edge information for face vertex uv, normal, tangent, etc. -
edgeData <
CDmePolygonMeshDataArray>
Stores edge data such as soft or hard normals. -
faceData <
CDmePolygonMeshDataArray>
Stores face data such as texture scale, UV offset, material, lightmap bias. -
subdivisionData <CDmePolygonMeshSubdivisionData>
Data representing the subdivided surface of the mesh.
CDmePolygonMeshDataArray
An array of CDmePolygonMeshDataStream elements.
"vertexData" "CDmePolygonMeshDataArray"
{
"id" "elementid" "fe15bacb-f08e-4500-a7dd-99144aca5567"
"size" "int" "4"
"streams" "element_array"
}
-
size <
int>
The amount of elements in the arrays. -
streams <
element_array>
An array ofCDmePolygonMeshDataStreamelements.
CDmePolygonMeshDataStream
A data stream. Everything but data is bound, data is markup written by the stream's own save code, which is why it can be an array of any type.
"CDmePolygonMeshDataStream"
{
"id" "elementid" "0766ecc4-d5d4-45b6-bb90-b688e786bc5c"
"name" "string" "position:0"
"standardAttributeName" "string" "position"
"semanticName" "string" "position"
"semanticIndex" "int" "0"
"vertexBufferLocation" "int" "0"
"dataStateFlags" "int" "3"
"subdivisionBinding" "element" ""
"data" "vector3_array"
}
-
name <
string>
Seems to besemanticName:semanticIndex, not sure why they store this separately here. -
standardAttributeName <
string>
Seems to be the same as semanticName. -
semanticName <
string>
The name of the stream.Known names:
- position
- normal
- tangent
- texcoord
- lightmapScaleBias
- flags
- materialindex
- textureAxisU
- textureAxisV
- textureScale
- VertexPaintBlendParams
- VertexPaintTintColor
-
semanticIndex <
int>
Index of the stream. -
vertexBufferLocation <
int>
The slot the stream occupies in the vertex buffer. -
dataStateFlags <
int>
Flags describing how the stream is stored. -
subdivisionBinding <
element>
Seems related to how data on subdivided meshes is handled, a CDmePolygonMeshSubdivisiondataBinding when set. -
data <
int | vector2_array | vector3_array | vector4_array>
The data stored in this stream, can be an int, vector2, vector3, or vector4 array.
CDmePolygonMeshSubdivisionData
Subdivision state of a CDmePolygonMesh.
"CDmePolygonMeshSubdivisionData"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"subdivisionLevels" "int_array"
"streams" "element_array"
}
-
subdivisionLevels <
int_array>
Subdivision level per half edge. -
streams <
element_array>
Array of CDmePolygonMeshDataStream.
CDmePolygonMeshSubdivisiondataBinding
Binds a CDmePolygonMeshDataStream to the subdivision data that drives it.
"subdivisionBinding" "CDmePolygonMeshSubdivisiondataBinding"
{
"id" "elementid" "53f14a8f-0ac6-4fba-a836-7d85d70bf641"
"targetDataType" "int" "-1"
"targetStreamIndex" "int" "-1"
"streamSourceType" "int" "0"
}
-
targetDataType <
int>
Mesh component the target stream belongs to, -1 for none. -
targetStreamIndex <
int>
Index of the target stream within its component, -1 for none. -
streamSourceType <
int>
Where the subdivided values come from.
Hammer meshes
Source2 Hammer is also a modeling tool allowing users to create complex 3D meshes, due to this the format for its meshes is quite complex.
Explanation of half-edge meshes
Hammer meshes are stored in a format known as a half-edge data structure, this format is widely used to represent polygonal meshes by many DCC apps such as Blender due to its efficient manipulation of topology and ability to handle polygons with an arbitrary amount of sides, making it easy to edit the mesh.
Below is an example of how a simple quad is represented using half edges, the blue half edges are internal edges, and the green ones are external.

Topology limitations
It is impossible to represent non-manifold meshes such as a Möbius strip as a hammer mesh!
Due to the nature of half-edge meshes, it can only represent manifold geometry, arbitrary 3D triangle meshes used in video game levels can and will often violate this, in which case converting from arbitrary triangle meshes to half-edge meshes needs careful sanitisation of the topology! When using the "Convert Models To Hammer Mesh" option, Hammer usually simply deletes the offending faces. Due to this it is not recommended to be used for converting complex models to hammer meshes.
Below is a list of potential topology issues you might encounter while converting triangle meshes to half-edge meshes, taken out of Hammer's system for doing this.
- Face specified an edge which already had two faces attached (this will fail because half-edge only supports two faces being linked by an edge, due to only ever being two twins forming one edge by definition.).
- Face specified a vertex which had edges attached, but none that were open.
- Face specified a vertex that had multiple open edges and did not connect to any existing edge.
- Face specified two edges that are connected by a vertex but have one or more existing edges separating them.
Anatomy of a Hammer mesh
This section will go over how meshes are stored in the vmap, and how to read them.
Explanation of CDmePolygonMesh
This element stores all the half-edge information describing the mesh, below is an example of a mesh describing a simple quad.
The mesh below is missing all data streams apart from vertexData which contains vertex positions, this is the only stream strictly necessary to the explanation.
"meshData" "CDmePolygonMesh"
{
"id" "elementid" "d4460070-41c1-4483-a0b1-b850b32eccc4"
"name" "string" "meshData"
"vertexEdgeIndices" "int_array"
[
"7", "1", "5", "3"
]
"vertexDataIndices" "int_array"
[
"0", "1", "2", "3"
]
"edgeVertexIndices" "int_array"
[
"1", "0", "3", "1", "2", "3", "0", "2"
]
"edgeOppositeIndices" "int_array"
[
"1", "0", "3", "2", "5", "4", "7", "6"
]
"edgeNextIndices" "int_array"
[
"2", "7", "4", "1", "6", "3", "0", "5"
]
"edgeFaceIndices" "int_array"
[
"0", "-1", "0", "-1", "0", "-1", "0", "-1"
]
"edgeDataIndices" "int_array"
[
"0", "0", "1", "1", "2", "2", "3", "3"
]
"edgeVertexDataIndices" "int_array"
[
"1", "0", "3", "2", "5", "4", "7", "6"
]
"faceEdgeIndices" "int_array"
[
"6"
]
"faceDataIndices" "int_array"
[
"0"
]
"materials" "string_array"
[
"materials/dev/reflectivity_30.vmat"
]
"vertexData" "CDmePolygonMeshDataArray"
{
"id" "elementid" "fe15bacb-f08e-4500-a7dd-99144aca5567"
"size" "int" "4"
"streams" "element_array"
[
"CDmePolygonMeshDataStream"
{
"id" "elementid" "0766ecc4-d5d4-45b6-bb90-b688e786bc5c"
"name" "string" "position:0"
"standardAttributeName" "string" "position"
"semanticName" "string" "position"
"semanticIndex" "int" "0"
"vertexBufferLocation" "int" "0"
"dataStateFlags" "int" "3"
"subdivisionBinding" "element" ""
"data" "vector3_array"
[
"-64 -64 0",
"64 -64 0",
"-64 64 0",
"64 64 0"
]
}
]
}
}
At first glance this might seem intimidating, but its actually quite easy to read, we will show how to read the mesh manually and sketch it "on paper" which is really helpful for debugging but this explanation should also be easily translatable to code.
First, we need to look at the vertexData stream, and plot the vertex positions in the data field, and index them as we go.
An easy way to do this is by just pasting the positions into the origin field of a hammer entity.
Here's the result:

Next, we want to draw out the half edges, for this we need to look at the edgeVertexIndices and edgeFaceIndices lists.
In edgeVertexIndices the first index is 1, this means that the first half-edge points at the second vertex, the vertex with index 1.
Next, we want to determine if this in an internal or external half edge, for this we need to look at edgeFaceIndices, the first index is 0, which means the half-edge is part of the first (and only) face meaning its internal.
This might not seem like enough to determine which half edge is pointing to vertex index 1, but it is, due to the winding order of internal half-edges always being clockwise, and external half edges always being in the opposite direction of internal ones, we only have two candidates.

As seen in the image above, since we already determined that our half-edge is internal, which means its on the inside of the face, this narrows it down to one half edge.
Great! we have now read our first half-edge, we will also need to index these so write down a 0 next to this one, now on to the second one, we can repeat the steps from above.
In edgeVertexIndices the second index is 0, this means that the second half-edge points at the first vertex.
In edgeFaceIndices the second index is -1, this means that the second half-edge is an external half edge.
We can apply the same logic from above to arrive at this:

We can verify our work by checking the edgeOppositeIndices array, the first index is 1 and the second is 0, this means that the first half-edge is opposing the second, and the second is opposing the first, which matches our image.
We will now skip ahead to the next two half edges.

Now that we have half-edges on multiple sides of the face, we can further check our work by looking at the edgeNextIndices array.
The first index is 2 meaning the first half-edge points to the half-edge with index 2, checking half-edge index 3 in that array we can see its meant to point to half-edge index 1, our image aligns with this which means it is correct!
We can now skip to the finished image.

Reading polygon data out of hammer meshes from code
If you just want to read the polygon data, reading the meshes from code is quite easy, its similar to the process from above but much simpler.
Vertices are simply contained in the vertexData stream, and to get indices we just need a simple do while loop.
Example of reading the entire mesh, as explained above faceEdgeIndices stores one of the internal half edges of every face, so we want to loop this.
// an array to store faces, which are arrays of vertex indices
List<List<int>> faces = []
// go trough all faceEdgeIndices
for (int i = 0; i < faceEdgeIndices.Count; i++)
{
// stores the indices of the current face
List<int> faceIndices = [];
// edgeNextIndices gives us the half edge that out current half edge is pointing do, here we simply start with the half edge from the current faceEdgeIndices index (faceEdge)
// and then keep looping, finding the next half edge and setting that as our next, until next == faceEdge, this means that we did a full loop around the face, and extraced all indices
// as we loop we store edgeVertexIndices[nextFaceEdge] into faceIndices, this gives us our face indices because edgeVertexIndices is the index of the vertex that the edge starts from
var faceEdge = faceEdgeIndices[i];
var nextFaceEdge = faceEdge;
do
{
faceIndices.Add(edgeVertexIndices[nextFaceEdge]);
nextFaceEdge = mesh.meshData.edgeNextIndices[nextFaceEdge];
}
while (nextFaceEdge != faceEdge);
faces.Add(faceIndices);
}
Reading other data like normals and UVs is left as an exercise for the reader.
If you want to render these meshes, you will first need to convert the n-sided polygon faces to triangles. A good algorithm for this is Ear Clipping
Compiled maps
The compiler does not keep the vmap. Its world builder walks the node tree and writes the world, its world nodes and the entity lumps as separate resources, and the other builders (physics, vis, navigation, baked lighting, Steam Audio) add theirs.
While doing so it adds keys to some entities that never exist in a Hammer authored map: precomputed_vis_clusters on lights, precomputed_shadowmap_* and precomputed_depth_pyramid_* on stationary lights, and light_probe_atlas_x, light_probe_atlas_y and light_probe_atlas_z on light probe volumes. A decompiler has to drop them, since Hammer recomputes all of them on the next compile.