Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Object Picker Window: Ability to Pick a Prefab With Matching Component

Discussion in 'Editor Workflows' started by msfredb7, Jun 29, 2023.

  1. msfredb7

    msfredb7

    Joined:
    Nov 1, 2012
    Posts:
    143
    When serializing a reference to a component, the object picker in the inspector will only show available matches in the current scene. No prefabs are shown.

    upload_2023-6-29_11-57-4.png

    upload_2023-6-29_12-2-49.png

    This is a major pain point in our project's pipeline because assets cannot be discovered easily. This causes people to create duplicate assets, waste time searching, etc.

    There is no good alternative from my understanding (no, using ScriptableObjects is not a good alternative because they don't support composition and variants like prefabs).
     

    Attached Files:

  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    Actually, that is expected behaviour. A script on a prefab is serialized with the prefab. Since the prefab asset is a serialized object (meaning: not instantiated), you cannot assign parts of it to an object in the scene.

    Assuming it were possible to assign that script to an active game object in the scene, then Unity would have to somehow instantiate the prefab (when? where to?) since the script might depend on other prefab objects.

    I have a hunch that this setup isn't ideal from an architectural point of view. Given that these are "settings" it sounds like they could, or should, be objects of their own and not tied to prefabs. This means ScriptableObjects naturally but could really be any serializable data. Any such custom data scripts (regular classes) support composition naturally, and overrides can be implemented through either inheritance - or value overrides / modifiers which could be objects of their own, taking an input and providing an output. I'm thinking functional programming style here, like LINQ.

    It's maybe too late for this project, but the current issue isn't going to go away, so you may have to make a hard choice: keep it as is or redesign the data architecture (in short: decoupling it from actual objects). Perhaps there's a third or fourth alternative though.
     
  3. msfredb7

    msfredb7

    Joined:
    Nov 1, 2012
    Posts:
    143
    This has been possible for as long as I can remember using Unity. E.g. If you have an "EnemySpawner" gameObject in your scene, it can reference its enemy prefabs by GameObject, but also by component (given that the component is on the root of the prefab).
    Code (CSharp):
    1. // both of these options work, but only GameObject will show prefabs in the ObjectPicker.
    2. // For the component, you have to link the reference manually.
    3. [SerializedField] List<GameObject> enemyPrefabs;
    4. [SerializedField] List<EnemyComponent> enemyPrefabs;
    Yes, Unity creates a prefab instance anytime you reference a prefab directly. E.g. You can always do this: myReferencedPrefab.GetComponents<X>()...DoSomething(). Even if the game is not running.

    Maybe I'm misunderstanding your suggestion, but this does not replicate the feature of data-driven composition and inheritance that prefabs provide.
     
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,186
    This feature already exists! Here's from my current prototype project:

    upload_2023-6-30_12-29-42.png

    upload_2023-6-30_12-25-10.png

    In order to activate it, use a recent enough Unity version (I'm on 2022.2), and go to preferences->search. On the bottom, turn on the advanced search engine:

    upload_2023-6-30_12-26-2.png

    Note: The "advanced search engine" is QuickSearch. It has some downsides - the biggest one is that it has to maintain a search index. This means that unlike the "classic" search, the first time you open it and any time you open it after there has been large changes to the project, it'll spend some time to index your files. Luckily this happens off the main thread, so it doesn't make the editor hang.
     
    msfredb7 likes this.
  5. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    Indeed, this is working (ComponentOnPrefab is a script on TestPrefab):
    upload_2023-6-30_12-26-7.png

    This goes completely against my notion of how one would reference a prefab that it never occured to me that this was legal. It hurts to imagine doing that though. Probably because the reverse isn't possible: a prefab referencing an Object in the scene.

    And also because, if you can use the GameObject reference to the prefab, you can write your scripts to just use the prefab rather than relying on a reference to another script. Like this for example:
    Code (CSharp):
    1. var prefabComponent = someGameObject.GetComponent<ComponentOnPrefab>();
    Yes it does. It's straightforward to make a code-only hierarchical data structure that supports composition (references to other classes), inheritance (subclassing), versioning (instances of "value modifier" classes). The only part that isn't a no-brainer is the versioning, as it requires routing calls of "GetValue()" to any registered value modifier instances. But it's the same principle that makes things like "quad damage" work. At runtime "GetDamageValue()" is passing the base damage value first through all modifiers (if any) before returning it. If there's currently a modifier listed that does quad damage it would simply implement this:

    IValueModifier.GetModifiedValue(float damage) => damage * 4f;

    I can't say how that kind of data structure would fit into the current project setup though.
     
  6. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,186
    What?

    We've been doing that for like a decade. I think it's very common in tutorials. The whole point is to say "hey, this field only accepts prefabs that have a specific script on them".

    The most common way I can think of is to have a public ParticleSystem field, so you can just
    Instantiate(prefab, position).Play();


    There's a fundamental downside here in that you can't distinguish at runtime directly between prefab references and scene references with a proper API (you just have to know that the check is
    .gameObject.scene.IsValid()
    ), but that's also the case with GameObject references, so it's not a new problem.
     
    msfredb7 likes this.
  7. msfredb7

    msfredb7

    Joined:
    Nov 1, 2012
    Posts:
    143
    Oh wow! I know and use Quick Search but I had no idea it could replace the object picker. This is great! Thanks.
     
  8. msfredb7

    msfredb7

    Joined:
    Nov 1, 2012
    Posts:
    143
    I resolved the Thread.
    But out of curiosity, what do you meant here?
    Maybe we're misunderstanding each other. By data-driven, I meant the OPPOSITE of "code-only structure". Creating a prefab, assembling components, creating variants. This is all "designing a structure from data", no code change required.
     
  9. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    Possibly. :)

    The thing I imagine is that you set up a class hierarchy just as if it were a database, except expressed in code. You do have to change the code to introduce new tables (scripts) and columns (fields) but I figure that would also be required with the components you currently have in prefabs.

    Unity can visualize this kind of data structure out of the box via Inspector, so once set up there's no need to modify the code. With a tool like Odin it can be made comfortable to edit too.

    I haven't used this together with prefab variants so I'm not sure what it would take to make this work in that scenario. But I'm guessing nothing besides ensuring the values are serialized fields and all collections are also serializable by Unity.

    Perhaps, in the end, it's possibly the same concept except I wouldn't have the data as a component (MonoBehaviour) but rather regular classes or structs, such that the same data can be used in different MonoBehaviour scripts or ScriptableObjects. The latter would provide the default values, the MonoBehaviour "instantiates" the base data obtained from the ScriptableObject and modifies it, and in variants you can further modify these values. Any value that a designer decides to change in the SO globally would then be updated in all prefabs except where overridden.
     
  10. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    I am so familiar with this in regards to in-scene objects but ... it really never occured to me that this was legal or desirable for prefab assets. o_O

    I do wonder if that hasn't saved me a ton of headaches given that while it restricts which prefabs are accepted, it would also not let you pick a prefab asset from the object picker window as the OP mentioned. Perhaps that's why I never considered it to be working in the first place?
     
  11. msfredb7

    msfredb7

    Joined:
    Nov 1, 2012
    Posts:
    143
    Would you have any clue as to why my assets still don't show up ?
    upload_2023-6-30_11-48-27.png
    The components are on the root (you can see them linked in the Eras list).

    Could you show a screenshot of your Search Provider settings?

    EDIT: Nevermind! The Indexing was just not complete. I wish they'd display an "incomplete results" warning in the window.
     
    Last edited: Jun 30, 2023
  12. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,186
    If you have feedback for Quick Search, you can post in the official thread