Search Unity

Suggestion: Technique to make immutable prefab children more, er, mutable?

Discussion in 'Prefabs' started by StunAustralia, Jul 30, 2018.

  1. StunAustralia

    StunAustralia

    Joined:
    Jul 1, 2018
    Posts:
    33
    [heavily edited from original text (but not intent) to make it clearer it's a suggestion not a complaint and to add background as to where I was coming from]


    Current Situation

    We can have prefabs nested within other prefabs which give tremendous update power - a sci-fi corridor prefab can contain a nested door prefab. If the door prefab has more flashing lights added.. whoosh - all through the scene the doors change even if they're in different corridor prefabs. Fantatstic! Grey box heaven!

    Limitations

    The door prefab (above) can't be changed or removed from the hierarchy - it's immutable - that is, once it's containing corridor is placed in the scene, that door will always be a part of it.

    I'm increasingly finding this a real limitation. I can see it works great if the level designer never has to change the 'kit'... e.g. sci-fi corridor where you want different doors.. easy - corridor Variant prefabs that contain different door prefabs.

    However... for a reasonable amount of variation this implies a LOT of top-level combination prefabs made up.. this corridor with this door prefab, this panel prefab and this light prefab, now another with this door, this panel but that light prefab, etc.

    Guess I was hoping for the LD to take a corridor and just switch out the light prefab (probably with another crafted Variant of that light) ... as it stands, they can't as the light is an immutable nested prefab. The CAN disable the existing light prefab and drag another into the same place, but that gets messy.​


    Suggestion:

    I've been thinking whether there's a way to make prefab children less immutable, but in-keeping with what's already there...

    So... is this workable, desirable and internally compatible with the new workflow?
    • The child objects of a prefab are still serialised as they are now (in place, in sequence, etc) to allow for the internals to work , but;

    • Allow the child "slot" on the instance be overridden like any other property override on a prefab (ie, it's always there in the hierarchy view, but another object can be dragged onto it (or assigned in script) or it can be 'deleted' which basically sets it value to a 'no object here' value recognised by the internals.

    Naturally, I don't know the internals of the serialiser, but based on great talk I saw once, I know the ordering of things is something that's crucially important to maintain so as guarantee deserialisation gets you back where you started, and also doens't kill source control with a million changes if things aren't serialised consistently ... but I'm hoping this suggestion would mean all 'slots' are maintained in the right order so:
    • no change means things serialise exactly the same way

    • an override to a 'slot' means only that part of the serialisation will change (as it should) but the rest would remain unchanged and in sequence (as is consistent).

    If this is possible, unless it's trivial I wouldn't suggest holding up the current system to implement it - this current system has plenty of power and immediate benefits.

    Interested to hear what others think, or whether the immutability of children is not an issue for anyone else, or is absolutely desired.

    Thanks folks :)
     
    Last edited: Jul 31, 2018
    Epsilon_Delta likes this.
  2. SevenPointRed

    SevenPointRed

    Joined:
    Feb 3, 2016
    Posts:
    218
    Sounds like it would just be easier to code. Just create a placeholder with an enum or something that would load whatever light/door you wanted in that position?
     
  3. StunAustralia

    StunAustralia

    Joined:
    Jul 1, 2018
    Posts:
    33
    @SevenPointRed

    Your suggestion is effectively what I've been booting around for a few days and where I've run into the limitations I describe. It's possible I now have white line fever and can't make my brain take a step back and refocus :confused:

    So, here are the issues I seemed to consistently run into while trying an approach similar to the one you described:

    It boils down to either you:
    • create the objects at run time
      (say your placeholder GO parent creates a light) at run time - where you'd:
    1. not be able to see it at edit time... ok for lights, bad for doors!

    2. be adding processing at run time for what your LD already knew at design time was going to be there
    • OR - create the objects at edit time
      where if you create one of your 'enum' child objects as part of the prefab, the LD can no longer change the "enum" value to replace the child, as the original child (contained in the prefab) is now immutable and even the script that created it can't change it.

    If there's a third/hybrid way you can think of, that would be really valuable to me as it's precisely the cant-set-in-a-prefab-because-it's-then-set-in-concrete vs the do-it-all-at-run-time-in-a-script choice that the new workflow seems to impose.

    o_O
     
  4. SevenPointRed

    SevenPointRed

    Joined:
    Feb 3, 2016
    Posts:
    218
    I've not used the new prefab system enough to know about the edit time restrictions, so im thinking aloud.
    Could you have an editor script that creates the target prefab, from the enum, outside of the prefab transform. It could then either be deleted when you hit play via a postprocess script or added into the correct transform on awake?

    Edit: this all sounds really hacky but I'm used to hacky with Unitys systems :)
     
  5. StunAustralia

    StunAustralia

    Joined:
    Jul 1, 2018
    Posts:
    33
    @SevenPointRed

    Well, unless I'm doing something very wrong, the new "nesting prefabs" system allows you to create a prefab that contains other prefabs along with other standard GameObjects, etc. Which is great! But... the nested (child) prefabs can't be removed or replaced once the main prefab is in the scene... either manually or through script. (this is the essential "hmmm" of my original post)

    Interesting thought! I'll think on that one some more :) But I suspect it'll ultimately run into the same issues :(

    Seems to me every system that's ever been written to make things "easy" has a million hacks because "easy" really means "easy-if-you-do-it-exactly-according-to-what-we-envisioned"... but when your vision differs, hacks are inevitable. It's the nature of the beast .... ultimate flexibility means everything has to be set up from scratch... and takes you further and further from a structured framework to the point you may as well write the entire system yourself.

    Having offered that defence as an immutable rule... a few more hooks in the API would definitely cut down the hacky and up the productivity ;)
     
  6. Epsilon_Delta

    Epsilon_Delta

    Joined:
    Mar 14, 2018
    Posts:
    258
    This is actually what I thought prefab variants would be. They are great, but they would be greater still, if we could remove children from hierarchy and remove components freely (and possibly from their instances in the scene, too). Is this impossible to implement?
     
  7. StunAustralia

    StunAustralia

    Joined:
    Jul 1, 2018
    Posts:
    33
    I'd love a dev to answer so we'd know if there is a workaround or maybe tell us how they envisage that working...

    I've got some workarounds I'm trying out... but calling them hacky would be an understatement. In fact, I only code them in the dead of night in a crypt less I get drummed out of the programmer's guild and have my stack overflow card ceremonially torn up...

    :)
     
  8. StunAustralia

    StunAustralia

    Joined:
    Jul 1, 2018
    Posts:
    33
    I was considering just creating a new post with the exact same content.... I would really like to hear a dev's response to this.... just crickets.

    So, come ON. I beta tested it. I have provided feedback. In fact, I spent some time writing some detailed feedback, provided reasoning, suggested improvements. I didn't spit-the-dummy as we say here, nor did I question the abilities or motives of the developers. Perfect feedback!

    This post deserves a reply from the devs even if that reply is "Read it carefully, understood it fully, considered it thoroughly and rejected it utterly... because...."
     
  9. hunterofakara

    hunterofakara

    Joined:
    Oct 4, 2018
    Posts:
    21
    Based on the original post, I have a rough idea/suggestion that might help partially:
    Variant swap/creation in scene - the ability to swap one prefab instance with an instance of another, and have common property overrides applied across.

    Example:
    Corridors with nested door prefabs in scene.
    You try to delete door or such: Can't remove/rearrange children on prefab instance.
    In addition to option to open prefab editor or cancel, there'd be 2 new buttons:
    1. Apply changes and update source prefab asset (This'd save the door removal in the original prefab and affect all corridors. Handy in some cases to save having to do this change in the prefab editor, but not what you'd want in this case.)
    2. Create as new/variant. This would be the equivilant of dragging the instance to the same folder as it's asset but also have the attempted change (door removal) applied to the created asset. Ideally, should also be an option to create as a variant of the original when used on a variant (make a sibling variant).
    Further changes could then be applied to the variant (updating all doorless corridors) or made as a new variant.

    Either manually or as above, you now have a variant without a door in one spot, and all the rest of the corridors are the original prefab (or different variants).

    Here's the swapin/out part:
    Option to swap a corridor instance with an instance of one of it's variants. (Maybe in the right click menu?)
    Once you select a variant it'd be created in the same place, and (optionally) any overrides applied that can be applied to the variant are transferred over.
    If both had a light and you'd set that particular corridor's light blue, the variant without the door would be made and it's light also set blue.
    If the door's color was changed, that change is discarded as there's no door to apply it to in the variant.


    Not sure if there's a way for us to intercept/replace the "Cannot restructure Prefab instance" menu, but the swap menu part should be possible via custom scripts.

    Something like this could help if you wanted the same change in several locations, but is still be impractical for unique hierarchy changes (Which sounds like it might be easier to unpack/composite the prefab nesting manually in the scene as needed?).