Instances and you

Discussion in 'Tutorials & Resources' started by Idolon, Jul 2, 2015.

  1. Idolon

    aa Idolon the worst admin

    Messages:
    1,548
    Positive Ratings:
    4,437
    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:

    [​IMG]

    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:

    [​IMG]

    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!

    [​IMG]

    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:

    [​IMG]

    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.

    [​IMG]

    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!

    [​IMG]

    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:

    [​IMG]

    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:

    [​IMG]

    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:

    [​IMG]

    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:

    [​IMG]

    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: always reference @timer, not just 'timer.' The @ character is not removed.)

    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.

    [​IMG]

    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.

    [​IMG]

    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:

    [​IMG]

    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.
     
    • Thanks Thanks x 26
    • Useful Useful x 1
    Last edited: Feb 6, 2017
  2. Pocket

    aa Pocket func_croc

    Messages:
    4,489
    Positive Ratings:
    2,219
    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.)
     
  3. sevin

    aa sevin

    Messages:
    959
    Positive Ratings:
    663
    CS:GO also uses instances extensively. Cool to finally know why and how they work! Thanks ido!
     
  4. LadyRaee

    LadyRaee CHEERFULLY SUICIDAL

    Messages:
    201
    Positive Ratings:
    194
    Displacements do not work? I use them in CS:GO and P2 instances and they work perfectly fine for me there.
     
  5. Tumbolisu

    aa Tumbolisu  I ⌄ I 

    Messages:
    947
    Positive Ratings:
    930
    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.
     
  6. tyler

    aa tyler snail prince, master of a ruined tower

    Messages:
    5,034
    Positive Ratings:
    3,989
    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.
     
  7. Tumbolisu

    aa Tumbolisu  I ⌄ I 

    Messages:
    947
    Positive Ratings:
    930
    Alias is not placing his instance anywhere near the origin. It's even rotated.
     
  8. tyler

    aa tyler snail prince, master of a ruined tower

    Messages:
    5,034
    Positive Ratings:
    3,989
  9. Tumbolisu

    aa Tumbolisu  I ⌄ I 

    Messages:
    947
    Positive Ratings:
    930
    The fact that neither of us two has checked if it works just further proves my theory.
     
  10. Mikroscopic

    aa Mikroscopic

    Messages:
    604
    Positive Ratings:
    613
    Do instances seal the map?
     
  11. Exactol

    aa Exactol Certified Hammer Hacker

    Messages:
    399
    Positive Ratings:
    462
    Yes, instances can seal maps
     
  12. hutty

    aa hutty

    Messages:
    471
    Positive Ratings:
    373
    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
     
  13. Idolon

    aa Idolon the worst admin

    Messages:
    1,548
    Positive Ratings:
    4,437
    Added a note to clarify.
     
    • Thanks Thanks x 1
  14. Micnax

    aa Micnax I maek map

    Messages:
    2,057
    Positive Ratings:
    1,387
    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.
     
  15. Tumbolisu

    aa Tumbolisu  I ⌄ I 

    Messages:
    947
    Positive Ratings:
    930
    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.
     
  16. Idolon

    aa Idolon the worst admin

    Messages:
    1,548
    Positive Ratings:
    4,437
    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.
     
  17. Yabayabayaba

    Yabayabayaba L5: Dapper Member

    Messages:
    247
    Positive Ratings:
    73
    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.
     
  18. Crowbar

    aa Crowbar perfektoberfest

    Messages:
    1,439
    Positive Ratings:
    1,186
    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.
     
  19. Yabayabayaba

    Yabayabayaba L5: Dapper Member

    Messages:
    247
    Positive Ratings:
    73
    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
     
  20. Tumbolisu

    aa Tumbolisu  I ⌄ I 

    Messages:
    947
    Positive Ratings:
    930
    Point_Template might be a thing you should check out.