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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Question Is instance ID persistent for assets?

Discussion in 'Scripting' started by gwiazdorrr, May 5, 2023.

  1. gwiazdorrr

    gwiazdorrr

    Joined:
    Sep 29, 2014
    Posts:
    102
    I needed a way to generate some ID for assets (including nested ones) in edit-time. So far I've been using a hash of GlobalObjectId, but now it seems to me that using instance ID as it is, without any hashing, would be even better.

    This what docs have to say about instance ID persistence:

    And this is what I believed for the longest time, treating instance ID as a volatile and session-dependent.

    However, here comes LazyLoadReference - based on the source code, it is merely a wrapper for instance ID with some IsPersistent checks for safety. There are no native components to this, no magic. For this type to work, both in the editor and in a build, across multiple sessions, it requires instance ID to remain the same. This means that instance ID is persistent for persistent objects and can be used to identify those objects safely.

    Am I missing something? Are there any other reasons to stay away from instance ID in this situation?
     
  2. gwiazdorrr

    gwiazdorrr

    Joined:
    Sep 29, 2014
    Posts:
    102
    It seems there's some magic involved after all. Despite
    LazyLoadReference
    being merely a wrapper over instance ID, it is serialized as full reference (guid, fileId, type). So it seems the internal instance ID is assigned as
    LazyLoadReference
    is being deserialized.

    With this component in, instance ID can (and seems it does) change for each session, be it editor or build.

    Sorry if I got anyone's hopes up!
     
    Bunny83 likes this.
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,541
    Quote from the source code:
    Code (CSharp):
    1.     // Notes:
    2.     //  - *** The memory layout of this struct must be identical to the native type: AssetReferenceMemoryLayout. ***
    3.     //  - Not using bindings file as we don't want a wrapper class in this situation. but it must mirror it's native counter part to a 'T'.
    4.     //----------------------------------------------------------------------------------------------------------------------
    5.  
    So there is most likely "some native magic" happening :)
     
    orionsyndrome and gwiazdorrr like this.
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    I often use the asset id, specifically from GlobalObjectId, for various things as well. And this is how I do it.

    First I created a SerializableGuid struct that mirrors System.Guid:
    https://github.com/lordofduct/space...acepuppy.core/Runtime/src/SerializableGuid.cs

    Note that there is also a ConfigAttribute in it like so:
    Code (csharp):
    1.         public class ConfigAttribute : System.Attribute
    2.         {
    3.             public bool AllowZero;
    4.             /// <summary>
    5.             /// Attempts to make the guid match the guid associated with the asset this is on.
    6.             /// Note this only works if it's on an asset that exists on disk (ScriptableObject, Prefab).
    7.             /// Also it means guids will match across all scripts that are on a prefab with this flagged. (since the prefab only has one guid)
    8.             /// Really... this should be mainly done with ScriptableObjects only, Prefab's are just a
    9.             /// sort of bonus but with caveats.
    10.             ///
    11.             /// New instances created via 'Instantiate' or 'CreateInstance' will not get anything.
    12.             /// This is editor time only for assets on disk!
    13.             /// </summary>
    14.             public bool LinkToAsset;
    15.  
    16.             /// <summary>
    17.             /// Attempts to make the guid match the targetObjectId & targetPrefabId of the GlobalObjectId from the object
    18.             /// for the upper and lower portions of the guid respectively. If LinkToAsset is true, that takes precedance to this.
    19.             /// </summary>
    20.             public bool LinkToGlobalObjectId;
    21.         }
    And then I have the PropertyDrawer for this struct that not only draws the guid correctly (rather than as a bunch of byte fields), but also a postprocessor that will associate my assets for me automatically:
    https://github.com/lordofduct/space...or/src/Core/SerializableGuidPropertyDrawer.cs

    And then I can simply link it up like so:
    https://github.com/lordofduct/space.../Runtime/src/Project/QueryableAssetSet.cs#L25
    https://github.com/lordofduct/space...py.triggers/Runtime/src/ProxyMediator.cs#L122

    upload_2023-5-5_20-15-26.png

    upload_2023-5-5_20-15-38.png

    This works pretty nice when intermingling with Addressables, since Addressables can be configured to work with asset guid's as well (and if I recall correctly defaults to that behaviour).