srctools.vmf

VMF Library

Wraps property_parser tree in a set of classes which smartly handle specifics of VMF files.

srctools.vmf.conv_kv(
val: str | int | bool | float | VecBase | Vec_tuple | Tuple[float, float, float] | Angle | FrozenAngle | Matrix | FrozenMatrix,
) str

Convert a type into a string matching Valve’s syntax.

srctools.vmf.overlay_bounds(
over: Entity,
) Tuple[Vec, Vec]

Compute the bounding box of an overlay.

srctools.vmf.make_overlay(
vmf: VMF,
normal: Vec,
origin: Vec,
uax: Vec,
vax: Vec,
material: str,
surfaces: Iterable[Side],
u_repeat: float = 1,
v_repeat: float = 1,
swap: bool = False,
render_order: int = 0,
) Entity

Generate an overlay on an axis-aligned surface.

Parameters:
  • origin – The center point of the overlay.

  • uax – The direction and distance for the texture’s width (right).

  • vax – The direction and distance for the texture’s height (up).

  • normal – The normal of the surface.

  • material – The material used.

  • u_repeat – Defines how many times to repeat the texture in the U direction.

  • v_repeat – Defines how many times to repeat the texture in the V direction.

  • swap – If true, the texture will be rotated 90.

srctools.vmf.localise_overlay(
over: Entity,
origin: VecBase | Vec_tuple | Tuple[float, float, float],
angles: Angle | FrozenAngle | Matrix | FrozenMatrix | None = None,
) None

Rotate an overlay like what is done in instances.

class srctools.vmf.VMF(
map_info: Mapping[str, str] = srctools.EmptyMapping,
preserve_ids: bool = False,
)

Represents a VMF file, and holds counters for various IDs used.

Has functions for searching for specific entities or brushes, and converts to/from a property_parser tree.

The dictionaries by_target and by_class allow quickly getting a set of entities with the given class or targetname.

add_brush(
item: Solid | PrismFace,
) None

Add a world brush to this map.

remove_brush(brush: Solid) None

Remove a world brush from this map.

add_ent(item: Entity) None

Add an entity to the map.

The entity should have been created with this VMF as a parent.

remove_ent(item: Entity) None

Remove an entity from the map.

After this is called, the entity will no longer be exported. The object still exists, so it can be reused.

add_brushes(
brushes: Iterable[Solid],
) None

Add multiple brushes to the map.

add_ents(
ents: Iterable[Entity],
) None

Add multiple entities to the map.

create_ent(
classname: str,
**kargs: str | int | bool | float | VecBase | Vec_tuple | Tuple[float, float, float] | Angle | FrozenAngle | Matrix | FrozenMatrix,
) Entity

Convenience method to allow creating point entities.

This constructs an entity, adds it to the map, and then returns it. A classname must be passed!

create_visgroup(
name: str,
color: Vec | Tuple[int, int, int] = (255, 255, 255),
) VisGroup

Convenience method for creating visgroups.

static parse(
tree: Keyvalues | str,
preserve_ids: bool = False,
) VMF

Convert a property_parser tree into VMF classes.

export(
*,
inc_version: bool = True,
minimal: bool = False,
disp_multiblend: bool = True,
) str
export(
dest_file: IO[str],
*,
inc_version: bool = True,
minimal: bool = False,
disp_multiblend: bool = True,
) None

Serialises the object’s contents into a VMF file.

  • If no file is given the map will be returned as a string.

  • By default, this will increment the map’s version - disable inc_version to suppress this.

  • If minimal is True, several blocks will be skipped (Viewsettings, cameras, cordons and visgroups)

  • disp_multiblend controls whether displacements produce their multiblend data (added in ASW), or if it is stripped.

  • named_cordons controls if multiple cordons may be used (post L4D), or if only a single cordon is allowed.

iter_wbrushes(
world: bool = True,
detail: bool = True,
) Iterator[Solid]

Iterate through all world and detail solids in the map.

iter_wfaces(
world: bool = True,
detail: bool = True,
) Iterator[Side]

Iterate through the faces of world and detail solids.

iter_ents(
**cond: str,
) Iterator[Entity]

Iterate through entities having the given keyvalue values.

iter_ents_tags(
vals: Mapping[str, str] = srctools.EmptyMapping,
tags: Mapping[str, str] = srctools.EmptyMapping,
) Iterator[Entity]

Iterate through all entities.

The returned entities must have exactly the given keyvalue values, and have keyvalues containing the tags.

iter_inputs(
name: str,
) Iterator[Output]

Loop through all Outputs which target the named entity.

  • Allows using * at beginning/end

search(
name: str,
) Iterator[Entity]

Yield all entities that fit this search string.

This can be the exact targetname, end-* matching, or the exact classname.

make_prism(
p1: Vec | FrozenVec,
p2: Vec | FrozenVec,
mat: str = 'tools/toolsnodraw',
) PrismFace

Create an axis-aligned brush connecting the two points.

A PrismFaces tuple will be returned which contains the six faces, as well as the solid. All faces will be textured with ‘mat’.

make_hollow(
p1: Vec | FrozenVec,
p2: Vec | FrozenVec,
thick: float = 16,
mat: str = 'tools/toolsnodraw',
inner_mat: str = '',
) List[Solid]

Create 6 brushes to surround the given region.

If inner_mat is not specified, it’s set to mat.

class srctools.vmf.Camera(
vmf_file: VMF,
pos: Vec,
targ: Vec,
)

Represents one of several cameras which can be swapped between.

targ_ent(ent: Entity) None

Point the camera at an entity.

is_active() bool

Is this camera in use?

set_active() None

Set this to be the map’s active camera

set_inactive_all() None

Disable all cameras in this map.

classmethod parse(
vmf_file: VMF,
tree: Keyvalues,
) Camera

Read a camera from a property_parser tree.

copy() Camera

Duplicate this camera object.

remove() None

Delete this camera from the map.

export(
buffer: IO[str],
ind: str = '',
) None

Export the camera to the VMF file.

class srctools.vmf.Cordon(
vmf_file: VMF,
min_: Vec,
max_: Vec,
is_active: bool = True,
name: str = 'Cordon',
)

Represents one cordon volume.

classmethod parse(
vmf_file: VMF,
tree: Keyvalues,
) Cordon

Parse a cordon from the VMF file.

export(
buffer: IO[str],
ind: str = '',
) None

Write the cordon into the VMF.

copy() Cordon

Duplicate this cordon.

remove() None

Remove this cordon from the map.

class srctools.vmf.VisGroup(
vmf: VMF,
name: str,
id: int = -1,
color: Vec = NOTHING,
child_groups: List[VisGroup] = NOTHING,
)

Defines one visgroup.

classmethod parse(
vmf: VMF,
props: Keyvalues,
) VisGroup

Parse a visgroup from the VMF file.

export(
buffer: IO[str],
ind: str = '',
) None

Write out the VMF text for a visgroup

set_visible(target: bool) None

Find all objects with this ID, and set them to the given visibility.

child_ents() Iterator[Entity]

Yields Entities in this visgroup.

child_solids() Iterator[Solid]

Yields Solids in this visgroup.

copy(
vmf: VMF | None = None,
group_mapping: MutableMapping[int, int] = srctools.EmptyMapping,
des_id: int = -1,
) VisGroup

Duplicate this visgroup and all children.

class srctools.vmf.Solid(
map: VMF,
id: int = -1,
sides: List[Side] = NOTHING,
visgroup_ids=(),
hidden: bool = False,
group_id: int | None = None,
vis_shown: bool = True,
vis_auto_shown: bool = True,
cordon_solid: int | None = None,
editor_color: Vec = NOTHING,
)

A single brush, serving as both world brushes and brush entities.

copy(
des_id: int = -1,
vmf_file: VMF | None = None,
side_mapping: MutableMapping[int, int] = srctools.EmptyMapping,
keep_vis: bool = True,
) Solid

Duplicate this brush.

classmethod parse(
vmf_file: VMF,
tree: Keyvalues,
hidden: bool = False,
) Solid

Parse a Property tree into a Solid object.

export(
buffer: IO[str],
ind: str = '',
disp_multiblend: bool = True,
include_groups: bool = True,
) None

Generate the strings needed to define this brush.

  • disp_multiblend controls whether displacements produce their multiblend data (added in ASW), or if it is stripped.

  • include_groups specifies if visgroup/group values are included. This is not allowed inside brush entities.

remove() None

Remove this brush from the map.

get_bbox() Tuple[Vec, Vec]

Get two vectors representing the space this brush takes up.

get_origin(
bbox_min: Vec | None = None,
bbox_max: Vec | None = None,
) Vec

Calculates a vector representing the exact center of this brush.

translate(
diff: VecBase | Vec_tuple | Tuple[float, float, float],
) None

Move this solid by the specified vector.

localise(
origin: VecBase | Vec_tuple | Tuple[float, float, float],
angles: Angle | FrozenAngle | Matrix | FrozenMatrix | None = None,
) None

Shift this brush by the given origin/angles.

point_inside(
point: VecBase | Vec_tuple | Tuple[float, float, float],
threshold: float = 1e-06,
) bool

Check if the specified point is inside the brush.

The threshold controls tolerance - a point is still counted if it is this far away from the surface.

class srctools.vmf.Side(
vmf_file: VMF,
planes: List[Vec],
des_id: int = -1,
lightmap: int = 16,
smoothing: int = 0,
mat: str = 'tools/toolsnodraw',
rotation: float = 0,
uaxis: UVAxis | None = None,
vaxis: UVAxis | None = None,
disp_power: Literal[0, 1, 2, 3, 4] = 0,
)

A brush face.

property is_disp: bool

Returns whether this is a displacement or not.

property disp_size: int

Return the number of vertexes in each direction of a displacement.

classmethod parse(
vmf_file: VMF,
tree: Keyvalues,
) Side

Parse the property tree into a Side object.

classmethod from_plane(
vmf: VMF,
position: VecBase | Vec_tuple | Tuple[float, float, float],
normal: VecBase | Vec_tuple | Tuple[float, float, float],
material: str = 'tools/toolsnodraw',
) Side

Generate a new brush face, aligned to the specified plane.

The normal vector points out of the face. This calculates a valid texture alignment, but does not specify an exact result.

copy(
des_id: int = -1,
vmf_file: VMF | None = None,
side_mapping: MutableMapping[int, int] = srctools.EmptyMapping,
) Side

Duplicate this brush side.

des_id is the id which is desired for the new side. map is the VMF to add the new side to (defaults to the same map). If passed, side_mapping will be updated with an old -> new ID pair.

export(
buffer: IO[str],
ind: str = '',
disp_multiblend: bool = True,
) None

Generate the strings required to define this side in a VMF.

  • disp_multiblend controls whether displacements produce their multiblend data (added in CSGO), or if it is skipped.

get_bbox() Tuple[Vec, Vec]

Generate the highest and lowest points these planes form.

get_origin() Vec

Calculates a vector representing the exact center of this plane.

translate(
diff: VecBase | Vec_tuple | Tuple[float, float, float],
) None

Move this side by the specified vector.

  • A tuple can be passed in instead if desired.

localise(
origin: VecBase | Vec_tuple | Tuple[float, float, float],
angles: Matrix | FrozenMatrix | Angle | FrozenAngle | None = None,
) None

Shift the face by the given origin and angles.

This preserves texture offsets.

disp_get_tri_verts(
x: int,
y: int,
) Tuple[DispVertex, DispVertex, DispVertex, DispVertex, DispVertex, DispVertex]

Return the locations of the triangle vertexes.

This is a set of 6 verts, representing the two triangles in order. See 2013 SDK src/public/builddisp.cpp:896-965.

plane_desc() str

Return a string which describes this face.

This is for use in texture randomisation.

normal() Vec

Compute the unit vector which extends perpendicular to the face.

property scale

Set both scale attributes easily.

property offset

Set both offset attributes easily.

class srctools.vmf.Entity(
vmf_file: VMF,
keys: Mapping[str, str | int | bool | float | VecBase | Vec_tuple | Tuple[float, float, float] | Angle | FrozenAngle | Matrix | FrozenMatrix] = srctools.EmptyMapping,
fixup: Iterable[FixupValue] = (),
ent_id: int = -1,
outputs: Iterable[Output] = (),
solids: Iterable[Solid] = (),
hidden: bool = False,
groups: Iterable[int] = (),
vis_ids: Iterable[int] = (),
vis_shown: bool = True,
vis_auto_shown: bool = True,
logical_pos: str | None = None,
editor_color: Vec | Tuple[int, int, int] = (255, 255, 255),
comments: str = '',
)

A representation of either a point or brush entity.

Creation:

Supports ent[key] operations to read and write keyvalues. To read instance $replace values operate on entity.fixup[var].

property keys: _KeyDict

Access the internal keyvalues dict.

This use is deprecated, the entity is a MutableMapping. It can also be called to get a keys view, as with other mappings.

property fixup: EntityFixup

Access $replace variables on instances.

copy(
des_id: int = -1,
vmf_file: VMF | None = None,
side_mapping: MutableMapping[int, int] = srctools.EmptyMapping,
keep_vis: bool = True,
) Entity

Duplicate this entity entirely, including solids and outputs.

static parse(
vmf_file: VMF,
tree_list: Keyvalues,
hidden: bool = False,
_worldspawn: bool = False,
) Entity

Parse a property tree into an Entity object.

_worldspawn indicates if this is the worldspawn entity, which additionally contains the entity group definitions.

is_brush() bool

Is this Entity a brush entity?

export(
buffer: IO[str],
ind: str = '',
disp_multiblend: bool = True,
_is_worldspawn: bool = False,
) None

Generate the strings needed to create this entity.

  • disp_multiblend controls whether displacements produce their multiblend data (added in ASW), or if it is skipped.

  • _is_worldspawn is used interally to generate the special worldspawn block.

sides() Iterable[Side]

Iterate through all our brush sides.

add_out(*outputs: Output) None

Add the outputs to our list.

output_targets() Set[str]

Return a set of the targetnames this entity triggers.

remove() None

Remove this entity from the map.

make_unique(
unnamed_prefix: str = '',
) Entity

Ensure this entity is uniquely named, by adding a numeric suffix.

If the entity doesn’t start with a name, it will use the parameter.

get(key: str, /) str
get(
key: str,
/,
default: str | T,
) str | T

Allow using [] syntax to search for keyvalues.

  • This will return ‘’ if the value is not present.

  • It ignores case-matching, but will use the first given version of a key.

  • If used via Entity.get() the default argument is available.

  • A tuple can be passed for the default to be set, inside the [] syntax.

clear() None

Remove all keyvalues from an item.

clear_keys() None

Remove all keyvalues from an item.

get_key(key: object) bool

Determine if a value exists for the given key.

get_bbox() Tuple[Vec, Vec]

Get two vectors representing the space this entity takes up.

get_origin() Vec

Return a vector representing the center of this entity’s brushes.

class srctools.vmf.EntityGroup(
vmf: VMF,
id: int = -1,
shown: bool = True,
auto_shown: bool = True,
color: Vec = NOTHING,
)

Represents the ‘group’ blocks in worldspawn.

This allows the grouping of brushes.

classmethod parse(
vmf_file: VMF,
props: Keyvalues,
) EntityGroup

Parse an entity group from the VMF file.

copy(
vmf: VMF | None = None,
) EntityGroup

Duplicate an entity group.

export(
buffer: IO[str],
ind: str,
) None

Write out a group into a VMF file.

class srctools.vmf.DispFlag(
value,
names=None,
*,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)

Bases: Flag

Per-displacement flags, configuring collisions.

Does NOT match the file values, since those are inverted.

COLL_NONE = 0
COLL_PHYSICS = 1
COLL_PLAYER_NPC = 2
COLL_BULLET = 4
COLL_ALL = 7
SUBDIV = 8
SUBDIV_COLL_ALL = 15
class srctools.vmf.TriangleTag(
value,
names=None,
*,
module=None,
qualname=None,
type=None,
start=1,
boundary=None,
)

Bases: Flag

Two flags set on all displacement triangles.

If walkable, it is shallow enough to stand on. If buildable, TF2 Engineers can place buildings.

STEEP = 0
WALKABLE = 1
BUILDABLE = 9

Alias: FLAT

class srctools.vmf.DispVertex(
x: int,
y: int,
normal: ~srctools.math.Vec = NOTHING,
distance: float = 0,
offset: ~srctools.math.Vec = NOTHING,
offset_norm: ~srctools.math.Vec = NOTHING,
alpha: float = 0.0,
triangle_a: ~srctools.vmf.TriangleTag = <TriangleTag.BUILDABLE: 9>,
triangle_b: ~srctools.vmf.TriangleTag = <TriangleTag.BUILDABLE: 9>,
multi_blend: ~srctools.vmf.Vec4 = Vec4(x=0.0,
y=0.0,
z=0.0,
w=0.0),
multi_alpha: ~srctools.vmf.Vec4 = Vec4(x=0.0,
y=0.0,
z=0.0,
w=0.0),
multi_colors: ~typing.List[~srctools.math.Vec] | None = None,
)

A vertex in dislacements.

class srctools.vmf.PrismFace(
solid: Solid,
top: Side,
bottom: Side,
north: Side,
south: Side,
east: Side,
west: Side,
)

Return value for VMF.make_prism().

This can be inded with an axis-aligned Vec or 3-tuple normal to fetch a side.

solid: Solid

The generated brush.

top: Side

The +z side of the brush.

bottom: Side

The -z side of the brush.

north: Side

The +y side of the brush.

south: Side

The -y side of the brush.

east: Side

The +x side of the brush.

west: Side

The -x side of the brush.

class srctools.vmf.UVAxis(
x: float,
y: float,
z: float,
offset: float = 0.0,
scale: float = 0.25,
)

Values saved into Side.uaxis and Side.vaxis.

These define the alignment of textures on a face.

classmethod parse(value: str) UVAxis

Parse a UV axis from a string.

copy() UVAxis

Return a duplicate of this axis.

vec() Vec

Return the axis as a vector.

rotate(
angles: Angle | FrozenAngle | Matrix | FrozenMatrix,
) UVAxis

Rotate the axis by some orientation.

This doesn’t alter texture offsets.

localise(
origin: VecBase | Vec_tuple | Tuple[float, float, float],
angles: Angle | FrozenAngle | Matrix | FrozenMatrix,
) UVAxis

Rotate and translate the texture coordinates.

class srctools.vmf.EntityFixup(
fixup: Iterable[FixupValue] = (),
)

A specialised mapping which keeps track of the variable indexes.

This treats variable names case-insensitively, and optionally allows writing variables with $ signs in front. The case of the first assigned name for each key is preserved.

Additionally, lookups never fail - returning ‘’ instead. Pass in a non-string default or use in to distinguish,.

get(var: str) str
get(
var: str,
default: str | T,
) str | T

Get the value of an instance $replace variable.

If not found, the default will be returned (an empty string).

copy_values() List[FixupValue]

Generate a list that can be passed to the constructor.

clear() None

Wipe all the $fixup values.

setdefault(
var: str,
/,
default: str = '',
) str
setdefault(
var: str,
/,
default: ValidKV_T,
) str | ValidKV_T

Return $key, but if not present set it to the default and return that.

items() ItemsView[str, str]

Provides a view over all variable-value pairs.

values() ValuesView[str]

Provides a view over all variable values.

export(
buffer: IO[str],
ind: str,
) None

Export all the fixup values into the VMF.

substitute(
text: str,
default: str | None = None,
*,
allow_invert: bool = False,
) str

Substitute the fixup variables into the provided string.

Variables are found based on the defined values, so constructions such as val$varval are valid (with no delimiter indicating the end of variables). Longer matches are preferred. If the name after $ is not found at all, a KeyError is raised, or if default is provided it is substituted.

Any key is valid if defined in the instance, but only a-z, 0-9 and _ is detected for the default functionality.

If allow_invert is enabled, a variable can additionally be specified like !$var to cause it to be inverted when substituted.

int(
key: str,
def_: int | T = 0,
) int | T

Return the value of an integer key.

Equivalent to int(fixup[key]), but with a default value if missing or invalid.

float(
key: str,
def_: float | T = 0.0,
) float | T

Return the value of an integer key.

Equivalent to float(fixup[key]), but with a default value if missing or invalid.

bool(
key: str,
def_: bool | T = False,
) bool | T

Return a fixup interpreted as a boolean.

The value may be case-insensitively ‘true’, ‘false’, ‘1’, ‘0’, ‘T’, ‘F’, ‘y’, ‘n’, ‘yes’, or ‘no’.

vec(
key: str,
x: float = 0.0,
y: float = 0.0,
z: float = 0.0,
) Vec

Return the given fixup, converted to a vector.

class srctools.vmf.FixupValue(var: str, value: str, id: int)

One $fixup variable with its replacement.

class srctools.vmf.Output(
out: str,
targ: Entity | str,
inp: str,
param: str | int | bool | float | VecBase | Vec_tuple | Tuple[float, float, float] | Angle | FrozenAngle | Matrix | FrozenMatrix = '',
delay: float = 0.0,
*,
times: int = -1,
only_once: bool = False,
inst_out: str | None = None,
inst_in: str | None = None,
comma_sep: bool = False,
)

An output from one entity pointing to another.

When parsing, either the post-L4D 0x1B character can be used, or the previous , delimiters can be used. For commas, extraneous ones will be treated as part of the parameters.

SEP: Final = '\x1b'

The character used to separate output values, after L4D. Before then commas (,) were used.

output: str

The output which triggers this.

inst_out: str | None

The local entity for an instance output (instance:name;Output)

target: str

The target entity.

input: str

The input to fire.

inst_in: str | None

The local entity we are really triggering in instance inputs (instance:name;Input)

params: str

Parameters to give the input, or "" for none.

delay: float

The number of seconds before the output should fire.

times: int

The number of times to fire before being deleted. -1 means forever, Hammer only uses -1 and 1.

comma_sep: bool

Use a comma as a separator, instead of the OUTPUT_SEP character.

property only_once: bool

Instead of setting times, this provides an interface like how Hammer does.

classmethod parse(
prop: Keyvalues,
) Output

Convert the VMF Property into an Output object.

classmethod combine(
first: Output,
second: Output,
) Output

Combine two outputs into a merged form.

This is suitable for combining a Trigger and OnTriggered pair into one, or similar values.

static parse_name(
name: str,
) Tuple[str | None, str]

Extract the instance name from values of the form:

‘instance:local_name;Command’ This then returns a local_name, command tuple. If not of this form, the first value will be None.

exp_out() str

Combine the instance name with the output if necessary.

exp_in() str

Combine the instance name with the input if necessary.

export(
buffer: IO[str],
ind: str = '',
) None

Generate the text required to define this output in the VMF.

as_keyvalue() str

Generate the text form of the output.

copy() Output

Duplicate this Output object.

gen_addoutput(delim: str = ',') str

Return the parameter needed to create this output via AddOutput.

This assumes the target instance uses Prefix fixup, if inst_in is set.

srctools.vmf.OUTPUT_SEP: Final = '\x1b'

The character used to separate output values, after L4D. Before then commas (,) were used. This is also available as Output.SEP.