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

Get equivalent gameObject inside prefab Asset from instance

Discussion in 'Prefabs' started by mashiro11, Sep 9, 2020.

  1. mashiro11

    mashiro11

    Joined:
    Dec 2, 2017
    Posts:
    7
    Don't know if the title is clear enough, but lets say I have a Prefab with a (possible) nested prefab inside of it. I want to have access / modify / identify the nested one:
    Assets/.../ParentWithNested.prefab:
    v |PGO| : parent prefab gameObject
    ....>|NGO| : nested (prefab) gameObject <- wanted reference

    Do NOT want this:
    Assets/.../Nested.prefab:
    >|NGO| : nested

    What I have: A component inside NGO gameObject.

    Problems I'm aware of:
    1- in PrefabStage, PGO is no longer treated as a prefab;
    2- maybe as consequence of 1, GetCorrespondingObjectFromSource() returns the reference to the Nested.prefab;
    3- object instances on PrefabStage are just.. instances. Having a reference to the instance is not the same as having the reference from within the parent prefab.
     
  2. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,877
    It's not quite clear from WHERE you want this reference, but here's some things that might help.

    If you have your PGO in your scene (not in Prefab Mode) then it has NGO as a child. If you use PrefabUtility.GetCorrespondingObjectFromSource on this NGO GameObject in the scene, you'll get get the NGO GameObject inside the ParentWithNested.prefab Prefab Asset. This NGO GameObject is a Prefab instance.

    If you use PrefabUtility.GetCorrespondingObjectFromSource on that returned GameObject, then you get the NGO GameObject inside the Nested.prefab Prefab Asset. This NGO GameObject is not a Prefab instance, since it's the original source.

    If you had more levels of nesting, the chain could go on further.

    Prefab Mode for which Prefab? I assume you mean when ParentWithNested.prefab is open in Prefab Mode. And yes, when opening the contents of a Prefab in Prefab Mode, the contents are not themselves a Prefab.

    That's right. If what you want is to go from a given object in Prefab Mode to the equivalent object in the asset that's open in Prefab Mode, there's no simple way to do that, since the opened content doesn't know which Prefab it comes from.

    I think the above answers this as well.
     
    mashiro11 likes this.
  3. mashiro11

    mashiro11

    Joined:
    Dec 2, 2017
    Posts:
    7
    Thank you for your reply!
    I'm developing a tool for this particular component intended to work on both Main mode and PrefabMode, but in a way it would always change the prefab asset.

    This tool is meant to bind two assets: this NGO inside PGO and, lets say Outside.asset, which is a scriptableObject that needs to hold reference to this NGO. It needs to check if Outside.asset is already bound to another component before binding is allowed, alerting user as soon as Ouside.asset is selected.

    That's exactly the case.

    So that is the problem I'm facing. I can determine whether or not it is on prefab mode and whether or not it is NGO's or PGO's prefab mode, but can not get NGO equivalent reference on asset that Outside.asset needs in case it is on prefab mode.
     
  4. mashiro11

    mashiro11

    Joined:
    Dec 2, 2017
    Posts:
    7
    Figured out a workaround, but that's dependent on two things:
    - previous knoledge on sibling state;
    - using UnityEditor.Experimental.SceneManagement.PrefabUtility;

    Code (CSharp):
    1. T GetEquivalentOnAsset<T>(T component)
    2.     {
    3.         int siblingIndex = component.transform.GetSiblingIndex();
    4.  
    5. //  use path to load asset
    6.         string prefabAssetPath = PrefabStageUtility.GetCurrentPrefabStage().prefabAssetPath;
    7.         GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>( prefabAssetPath );
    8.      
    9. return prefabAsset.transform.GetChild(siblingIndex).GetComponent<T>();
    10.     }
    [EDIT]
    Updates:

    The above solution made it work while the editor was running. As a bad surprise, today when I opened the project again, all references done this way (Outside.asset reference to NGO inside ParentWithPrefab.prefab and this NGO reference to Outside.asset) were lost.
    Looking at .prefab, .asset and .meta yml files I noticed it seems to have the references there, but for some reason they are not being loaded with the editor.

    Outside.asset:
    ...

    _guid: 8d71ae0b948000444b8704322a7a7e8b

    _pointer: {
    fileID: 3861198144423494386
    ,
    guid: 4afe9a7431e5d884ea11399c4a2ca8fd
    ,
    type: 3}
    //_pointer is the variable with the reference


    PGO.prefab.meta:
    fileFormatVersion: 2
    guid: 4afe9a7431e5d884ea11399c4a2ca8fd

    PrefabImporter:
    externalObjects: {}
    userData:
    assetBundleName:
    assetBundleVariant:

    PGO.prefab:
    ...
    // this is where _pointer should reference
    --- !u!1001 &4562471376339172768
    PrefabInstance:
    m_ObjectHideFlags: 0
    serializedVersion: 2
    m_Modification:
    m_TransformParent: {fileID: 1601517838514771521}
    m_Modifications:
    ...
    // this is the reference back to Outside.asset
    - target: {fileID: 775917427368656724, guid: 260a5a68900b21142b78dd95c1d37917,
    type: 3}
    propertyPath: _outside
    value:
    objectReference: {fileID: 11400000,
    guid: 8d71ae0b948000444b8704322a7a7e8b
    ,
    type: 2}
    - target: {fileID: 775917427368656724, guid: 260a5a68900b21142b78dd95c1d37917,
    type: 3}
    propertyPath: debug
    value: 0
    objectReference: {fileID: 0}
    m_RemovedComponents: []
    m_SourcePrefab: {fileID: 100100000, guid: 260a5a68900b21142b78dd95c1d37917, type: 3}
     
    Last edited: Sep 10, 2020