Skip to main content

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.

info

Source2 Viewer iconSource2 Viewer can decompile compiled maps (.vmap_c usually contained within a VPK) into a .vmap
GitHub iconDatamodel.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 GitHub iconVRF (s2v), used for vmap_c decompilation.

Vmap example

The following is a simple vmap in plain text format from Counter-Strike 2 iconCounter-Strike 2 consisting of a hammer mesh and an entity.

info

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:

VersionChange
3MapClass renamed to MapNode
5CVisibilityMgr with nodes and hiddenFlags
6CMapSolid and CHammerMesh become CMapMesh, dmemesh becomes mesh
7CMapRootElement and rootSelectionSet
8Vertex paint moves into CDmePolygonMeshDataStream streams
10connections becomes connectionsData, prefabs get variableOverrideNames and variableOverrideValues
23variableTypes becomes variableTypeNames on CMapVariableSet
28mapUsageType on CMapWorld, replacing backgroundMap
29physicsSimplificationOverride and physicsSimplificationError on CMapMesh
30Paths and cables (CMapPath, CMapPathNode, CMapCable)
31disableShadows2 becomes disableShadows on meshes
39prefab_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.

TODO

Which game introduced which version, and game specific vmap nodes such as the Dota 2 iconDota 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 iconCounter-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 in Help -> 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 iconDota 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 as visbility instead of visibility, 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 the Map -> MapProperties -> Map Variables tab.

  • 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 in Object Properties

  • transformPin <CMapNodeTransformPin>
    The Pinned To setting, 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 in Object 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 in Object Properties

  • customVisGroup <string>
    Will add a custom Vis group in the Auto Vis Groups panel, this object will show under it, useful for organisation. Shown in the Visibility group in Object 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>
    The referenceID of 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 the EntityIOTargetType enum. 7 is EntityNameOrClassName, 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 as Fixup Entity Names By Default in the map properties.

  • mapUsageType <string>
    The type of the map, shown as Map Type in 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.

TODO

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 the nodes element 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 takes CObjectSelectionSetDataElement and CFaceSelectionSetDataElement

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 always objectSelectionSetData, 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 always faceSelectionSetData, 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 of meshes.

  • 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 of meshes.

  • 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 when useTargetNameAsPrefix is 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 a point_prefab entity of its own, shown as Create 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 as Deformation Mode in 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, like string.

  • 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>
    How inTangent is computed.

  • outTangentType <int>
    How outTangent is 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"
}

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"
}

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.

info

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 as Cast 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.

    info

    This 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 as keep_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 called rendercolor in 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 be mesh by 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>
    Whether physicsSimplificationError overrides 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>
    The nodeIDs 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 plain DmElement.

  • 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 in projectionTargets (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 be meshData.

  • vertexEdgeIndices <int_array>
    An index to one of the half-edges starting from this vertex.

  • vertexDataIndices <int_array>
    Index to the VertexData streams.

  • 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 to EdgeData streams.

  • edgeVertexDataIndices <int_array>
    Per half-edge index to FaceVertexData streams.

  • 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 to FaceData streams.

  • materials <string_array>
    A list of every material used in the mesh, without duplicates, this will be indexed into by meshindex in the FaceData stream.

  • 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 of CDmePolygonMeshDataStream elements.

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 be semanticName: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"
}

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. half-edge example

info

This site offers a great interactive playground showcasing how half-edge meshes work.
An implementation of how to write hammer meshes can be found in the map decompilation code of GitHub iconVRF (s2v)

From this point on it will be assumed that you have at least a basic understanding of half-edge meshes.

Topology limitations

warning

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.

note

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.

info

An easy way to do this is by just pasting the positions into the origin field of a hammer entity.

Here's the result:

Reading half edge mesh example 1

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.

Reading half edge mesh example 2

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:

Reading half edge mesh example 3

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.

Reading half edge mesh example 4

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 half edge mesh example 5

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.

info

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.