[GUIDE] Instances and you

Idolon

they/them
aa
Feb 7, 2008
2,123
6,137
Instances are a really useful tool in mapping, and they're kinda a bit daunting and not particularly well documented! That's why I'm writing this guide. Knowing how to use instances can really help make your life a lot easier, both in terms of entity work and overall workload.

Instances are, at their core, nested vmfs. By using a func_instance, you can tell it to reference a map, which will then insert it into your current map. Let's take a look at func_instance itself:

5NM5DUf.png


Pitch Yaw Roll does the same thing that it always does for entities.

Fix Up Name is essentially a special name for your instance. More on that later.

VMF Filename is the map file to load. This is the main parameter to pay attention to. You can click Browse... to open up a file browser dialogue, which allows you to select what vmf you want to insert. However, it might not actually work! More on that in just a bit.

Entity Name Fix Up is an option that ties into Fix Up Name. Again, more on that later.

The Replace parameters are variables that you can configure inside of your instanced .vmf by using a func_instance_parms. More on that later.

So, what's up with the file browser dialogue not working? The instances use local filepath names so that you can put your mapsrc directory wherever you want without breaking all of the filenames. This path is defined in your gameinfo.txt, which is located in /tf (the same directory you find /maps, /materials, etc.) Let's open it up:

D9rQesB.png


You can see I've already changed my instance path. This is where things become a bit of a matter of personal preference. I have my path set to /mapsrc, meaning that I can make an instance of any of my vmfs inside that folder. Valve has theirs set to an /instances folder inside of mapsrc, meaning the vmfs have to be inside of /instances in order to be able to be referenced. You can set yours to whatever you want, but keep in mind that loading other people's maps might result in incorrect path names (and thus instances not appearing).

Now that we have that set up, let's try making an instance. What can we instance? Lights!

qH7LUnZ.png


I've copied over a light prefab (thanks Ravidge!) into its own .vmf, and saved it. Note that I've placed it on the origin of the map. Instances will appear in your map relative to the source vmf's origin. Let's see it in another map:

NN6tJaO.png


Boom! By adding a func_instance and selecting the light .vmf, we now have an instanced light. This is useful for several reasons! First of all, your light will never go off the grid. The light just appears relative to wherever the func_instance is, so you don't need to worry about using a skip brush to keep it in place.

Secondly, and more importantly, changing the source .vmf will change every func_instance version of it that ever gets referenced. If we have several lights in a hallway, and we want to change the lighting on every spotlight to brighten/darken the entire hallway, you only have to change the one spotlight in your instanced .vmf.

This also means you can run into issues if you use the same instances across multiple maps. I recommend keeping separate folder for instances for each individual map. It can also cause issues within the same map if you reuse the instance, so make sure you're careful. If you ever want to tweak an individual light, though, no worries! You can "collapse" an instance, which will just move the contents of the source .vmf into the actual map.

EDIT Dec 10 2020: I personally recommend only including the prop / effect in the instance, and putting the actual light entity in the map. This keeps your visuals consistent while making it very easy to tweak your light brightness values as needed.

DHxABUk.png


Thirdly, you can build stuff on a regular grid, and rotate it by any amount in the final map. This was done in Snowplow, which is explained well in this article (section 4: Collaboration). Super useful for complex geometry! However, you'll also want to watch out for how your instanced geometry cuts visleafs. Typically, if you have to use a func_instance to get off-grid geometry to work properly, you'll want to func_detail it all (there are exceptions!).

Ok, so what's up with Fix Up Name? It essentially serves as the instance's name, as if the instance itself was an entity. This would make a lot more sense if TF2 supported func_instance_io_proxy, but it doesn't, so we're gonna have to learn things the hard way!

The way the fix up name works is that it changes the name of all of the named entities inside of your instance based on a pattern defined by the Entity Name Fix Up parameter. Let's suppose that your instance has a logic_relay named Open, and your Fix Up Name is Door. If Entity Name Fix Up is set to Prefix, then Open will be renamed to Door-Open. Postfix will rename it to Open-Door. None will simply leave it as Open.

I've made a door from the ABS Pack into an instance, and put it into my map. Kaboom!

WkOzlIL.png


Inside of the instance, we have a func_door named door_any_large_dyn_1, and a prop_dynamic named door_any_large_dyn_1_prop. There's also a trigger volume, which sends some outputs:

zXj9sO4.png


Assuming that our func_instance is set to Prefix, and that it has a Fix Up Name of Door, the entities in the compiled map will be named Door-door_any_large_dyn_1 and Door-door_any_large_dyn_1_prop. Also, the outputs will be modified so that they have the prefixes. You don't need to give your entities these complex of names if you're working with instances, so entity names like "door" and "prop" are just fine.

This is super useful for instances that you want to work individually, but not with others. Without a name fix up, you'd have multiple entities with the same names! This can result in something like every respawn door opening and closing at the same time, since every door prop is named the same thing. If you don't want this sort of thing to happen, you'll want to make sure you don't give two instances the same fix up name.

It's also worth noting that if you don't give an entity a fix up name, the compiler will give it a unique one automatically (assuming that Entity Name Fix Up isn't set to None)! This means that you can also avoid the multiple-doors-opening sort of bugs by just not naming your instances altogether. The unique naming system works by giving the instance a Fix Up Name of instanceauto#, where # is a unique number id.

You'll want to pay attention to how this Fix Up Name stuff works so that you can use IO with instances properly. Suppose we have a logic_relay that we want to have kill the door's prop_dynamic. We'll try sending it an output:

qWcav3X.png


Our instance doesn't have any inputs! We would be able to configure some inputs for the instance if we had support for func_instance_io_proxy, but we don't. We'll have to do it by hand! There's two ways to reference an entity inside of an instance:

kCwGH23.png


You don't have to use both, either will work. There's some documentation about it on the VDC if you want something to copy/paste.

There's also another special thing you should know about naming entities inside of instances. If you put @ before an entity's name, it'll ignore name fix up entirely! This is useful for getting instances to send IO to entities in the "real" map. Let's say we want to have our door instance send an output to an entity named game_timer in our "real" map when it opens:

5lHp6WR.png


Because of how fix up names work, the door will actually try to send an output to Door-timer. However, if we name the timer @timer, the fix up won't happen, and the output will go through. (Note: The timer entity must actually be named @timer. You cannot reference 'timer' by targeting '@timer'.)

Now, let's talk parameters. You can use the special character $ to make something function as a variable. Let's take a look in our door instance.

alyMIDA.png


I've added $lip to the door's lip parameter. This doesn't actually do anything on its own, but we can configure it in our func_instance.

Xwf2sPn.png


By adding in $lip as a Replace parameter, anything named $lip in the instance will now get replaced with 50. It will also work in the middle of other names (for example, naming an entity in the instance cent_$lip would get it renamed to cent_50). I believe it will also work within the IO system, although I haven't tried it out myself.

You can make this a bit easier on yourself by inserting a func_instance_parms into your instanced vmf. This entity is fairly self explanatory, so I won't cover how to set it up. Once you're done, though, the $names in your instanced vmf will automatically appear in the Replace parameters of your func_instance. Good stuff!

It's also worth noting that name fix up still applies to $ things. If you want to use a Replace parameter to set something's parent, for example, you either have to use the None fix up style, or use @.

Some final caveats:

Instances may or may not support displacements. Proceed with caution if you want to use them.

Using the Postfix option for Entity Name Fix Up is really useful if you want to control a bunch of instances at once via wildcards. If you have a bunch of instances named Door01, Door02, Door03, etc. you can just send an output to Open-Door* to open them all at once. Not possible with the prefix option!

Rotations will get rotated relative to your instance's rotation. If you have a door that opens in the direction 0 0 0 in an instance, and rotate the instance 90 degrees, the door will open in the direction 0 90 0! Very useful.

If you want to remove the yellow tint from all of your instances, just use this:

PdHg6By.png


If you're struggling to understand what kind of stuff you can instance and what kind of stuff you can't, check out the sdk maps provided with Portal 2. Almost every single observation room, test element, elevator, and lighting setup is instanced! This keeps the look of things consistent, and also transfers bug fixes across every single map instantly.
 
Last edited:

Pocket

Half a Lambert is better than one.
aa
Nov 14, 2009
4,699
2,581
I wish instances had been commonly known back during the Artpass Contest, and they had left the instances non-collapsed. Loading up the map and getting messages to the effect that I had invalid solids and do I want Hammer to "fix" the problem by removing all my entities every single time just about broke me. (Plus, apparently at some point Hammer stopped asking and just did it anyway, so now all my source files are gone forever.)
 

LadyRaee

CHEERFULLY SUICIDAL
Sep 1, 2012
197
217
Displacements do not work? I use them in CS:GO and P2 instances and they work perfectly fine for me there.
 

Tumby

aa
May 12, 2013
1,087
1,196
I have heard from Alias that he uses displacements in instances 100% fine. Maybe it used to be a bug that got fixed but nobody ever checked it out again and just assumed it's still broken.
 

tyler

aa
Sep 11, 2013
5,100
4,621
Displacements are recorded as offsets relative to the origin. If you instance a displacement, it will appear in your vmf at the same coordinates as it does in your instance, regardless of where you actually place the instance in your map. In that sense they are broken, but also work fine if you set up your instances with displacements correctly.

If you use manifests, you actually do end up instancing each piece of your map, including displacements, and then compiling from that.
 

Tumby

aa
May 12, 2013
1,087
1,196
Alias is not placing his instance anywhere near the origin. It's even rotated.
 

hutty

aa
Mar 30, 2014
547
446
Something you may want to mention is that the @ symbol doesn't remove itself, and outside entities you point to from inside an instance need to also start with an @.

That had me confused for a while
 

Idolon

they/them
aa
Feb 7, 2008
2,123
6,137
Something you may want to mention is that the @ symbol doesn't remove itself, and outside entities you point to from inside an instance need to also start with an @.

That had me confused for a while
Added a note to clarify.
 

Micnax

Back from the dead (again)
aa
Apr 25, 2009
2,109
1,585
Also just a warning, including lights in an instance will add names to their fields, making them expensive and potentially causing massive errors if you use too many (the dynamic light hard limit). I tried doing instanced torch lighting for my map Hiddentomb and very quickly came across this.
 

Tumby

aa
May 12, 2013
1,087
1,196
That doesn't make sense. That would mean my maps have a million gigabyte of filesize because each surface has at least 6 named lights on it.
 

Idolon

they/them
aa
Feb 7, 2008
2,123
6,137
Lights are probably the thing I've used instances the most for and I've never had this error. My guess is that you're using animated lights (unnamed, but using the Appearance keyvalue for a flickering effect or something similar) and that VBSP gives the lights a name when collapsing the instances (which it probably shouldn't). You might be able to get around this by using the "None" fix-up name option.
 

Yabayabayaba

L5: Dapper Member
Jun 2, 2016
243
77
Question, Is it possible to somehow name instances? I know there is no option to do so, but a saw somewhere you can add a keyvalue targetname, but I have no Idea how to do so. I want to use this to parent instances, is it possible, how do I do it, is there a better way? Any help would be appreciated.
 

Crowbar

aa
Dec 19, 2015
1,455
1,298
You can't parent an instance - for it's not an entity engine handles, BSP puts whatever there is in the main map and the instance as it is becomes gone - but you can put a parentable thing inside an instance and reference that.
Of course in this case you only benefit from it being an instance if you're working at non orthogonal angles or need many synchronized, well, instances.
 

Yabayabayaba

L5: Dapper Member
Jun 2, 2016
243
77
I have found a work arround, I wanted to use instances because I need several Identical sections, an instance would make creation of my moving skybox simpler, and look better within the engine. I have decided to just expand my test map though