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:
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:
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!
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:
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.
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!
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:
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:
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:
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:
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.
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.
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:
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.
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:
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:
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!
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:
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.
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!
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:
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:
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:
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:
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.
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.
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:
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: