Search Unity

Getting the Addressable Address/GUID

Discussion in 'Addressables' started by daxiongmao, Jan 14, 2020.

  1. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    Is there anyway for a prefab or game object to get the guid it was created from at run-time?

    Having started using the addressable system i can get the guid etc during runtime and assign asset references through editor code.

    The issues i am running into are with dynamic level creation. I have the guids of the items i want to load and spawn. That works fine. But once the item is instantiated i don't see a way that the instantiated game objects knows where it came from.

    So my solution now is I have added an extra component that basically just stores an asset reference to its self. So if i wanted to serialize the current level, i can get the guid of the current object to recreate it again later.

    I think this will work ok, just wanted to see if there was another way.
     
    saferusmail likes this.
  2. jRocket

    jRocket

    Joined:
    Jul 12, 2012
    Posts:
    700
    I would like to know this as well. In my case, I have a class with a bunch of AssetReferences, which I usually set at design-time. But in some cases I may want to manually specify the AssetReference at runtime, which requires a guid. I already have the asset and the address, I just want to make an AssetReference out of them so it can work with the rest of my system. Sadly, AssetReference.Asset is read-only.
     
  3. Arthur-LVGameDev

    Arthur-LVGameDev

    Joined:
    Mar 14, 2016
    Posts:
    228
  4. IggyZuk

    IggyZuk

    Joined:
    Jan 17, 2015
    Posts:
    43
  5. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    +1

    // Edit: To elaborate, storing the Address on an Instance (something that you created through Instantiate from a Prefab you loaded via Adressables) might be a bit much, but it would be nice to get the Address back from the actual asset (i.e. the prefab, or any other thing you have loaded). This would be nice for scenes that were loaded via Addressables as well, e.g. like @daxiongmao said for the purpose of saving your game state.
     
    Last edited: Mar 11, 2021
  6. saferusmail

    saferusmail

    Joined:
    Jul 24, 2020
    Posts:
    2
    +1

    Found what i looked for here https://docs.unity3d.com/ScriptReference/AssetDatabase.TryGetGUIDAndLocalFileIdentifier.html

    So, this code works well for me:
    Code (CSharp):
    1. public CraftingResourceData resource;
    2. public AssetReferenceT<CraftingResourceData> craftingResourceRef;
    3.  
    4. protected override void OnBeforeSerialize()
    5. {
    6.      base.OnBeforeSerialize();
    7.      AssetDatabase.TryGetGUIDAndLocalFileIdentifier(resource, out string guid, out long localId);
    8.             craftingResourceRef = new AssetReferenceCraftingResourceData(guid);
    9. }
     
    Last edited: Mar 11, 2021
    anycolourulike likes this.
  7. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    @saferusmail This won't work like you think. AssetDatabase is part of the UnityEditor namespace and is not available at runtime.
    That code does work for doing things in the editor and i use it various places in some of my tools. But doesn't solve the issue at runtime.

    What I have been using is a component that stores the reference. This works as well when instantiating something because that component is duplicated and the asset reference is the same. Allowing me to serialize the asset ref and then my other custom state. And when deserializing the state i can use that guid to instantiate the asset using a asset reference or Address.

    I believe this data exists already in the addressable system. Since it does internal tracking of references and the release methods. It would be nice to be able to get the guid of an asset that was instantiated by the addressable system. But once the asset reference is not available there is no way to match the game object to the runtime guid that the asset reference contains.

    AssetReference -> Gameobject
    Need a way to then to
    GameObject -> AssetReference (GUID)
     
  8. Snowdrama

    Snowdrama

    Joined:
    May 10, 2014
    Posts:
    28
    I would also like this. I'm working on a save state system that uses addressables to load the save state.

    I have an interface ISavable on my Enemies for example
    Code (CSharp):
    1. public interface ISavable
    2. {
    3.       public void Save(ref SaveState saveState);
    4. }
    In the save function I save the game object's addressable address

    Code (CSharp):
    1. public void Enemy: MonoBehaviour, ISavable
    2. {
    3.     public string address;
    4.  
    5.     public void Save(ref SaveState saveState)
    6.     {
    7.         saveState.enemies.Add(new Entity(){
    8.             prefabAddress = address
    9.         });
    10.     }
    11. }
    Right now I store the address manually as a string, but what I'd like to do is be able to use an AssetReference so I don't have any spelling errors, or have to manually update the string field if the address changes.

    Code (CSharp):
    1. public void Enemy: MonoBehaviour, ISavable
    2. {
    3.     public AssetReference assetRef;
    4.  
    5.     public void Save(ref SaveState saveState)
    6.     {
    7.         saveState.enemies.Add(new Entity(){
    8.             prefabAddress = assetRef.AssetAddress
    9.         });
    10.     }
    11. }
    Then in load game you could do something like this:
    Code (CSharp):
    1. public void LoadGame: MonoBehaviour, ISavable
    2. {
    3.     public AssetReference assetRef;
    4.  
    5.     public void Save(SaveState saveState)
    6.     {
    7.         foreach(var entity in saveState.enemies)
    8.         {
    9.              Addressables.LoadAssetAsync<GameObject>(entity.prefabAddress).Completed += (AsyncOpperationHandle<GameObject> obj) => {
    10.                  Instantiate(obj.Result);
    11.              }
    12.         }
    13.     }
    14. }
    Being able to get the address from an asset reference would be extremely useful for my case
     
  9. jRocket

    jRocket

    Joined:
    Jul 12, 2012
    Posts:
    700
    I don't know how you're doing serialization, but I had no trouble directly serializing the AssetReference directly.
     
    Snowdrama likes this.
  10. Snowdrama

    Snowdrama

    Joined:
    May 10, 2014
    Posts:
    28
    Currently I'm simply using the JsonUtility to convert to json and writing that to the persistent data path for save games. I was unaware that you could serialize the asset reference itself, I'll have to try this.
     
  11. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    I think what you want to do should be easy since it seems like you will have the asset reference on your instantiated objects. Just use it or i think you can get the runtimeId or something like that will give you guid you need to reload it.

    I basically do this same thing, but requires anything you create from an addressable to have this extra component on it.

    Where if you just instantiated from an addressable and the resulting gameobject does not have this extra component on it. There is no way to know if it came from an addressable at that point.

    Some earlier versions of the addressable had issues with the editor and the asserreference point to its self.. Made the editor flicker.

    From other things i have read, the addressable system is kind of already keeping a mapping of instantiated objects to the reference they came from for reference counting etc. So having a way to query that for a given game object could be nice. But isn't necessary if you keep a self addressable reference on your objects that you can query when need to serialize.
     
  12. Snowdrama

    Snowdrama

    Joined:
    May 10, 2014
    Posts:
    28
    Exactly in my case it seems like I can just serialize the asset reference and be all set. Since the prefab the assetReference refers to contains an AssetReference to itself.

    Code (CSharp):
    1. public class Entity {
    2.     public AssetReference assetReference;
    3. }
    4.  
    5. public class SaveData {
    6.     public List<Entity> enemies;
    7. }
    8.  
    9. public void Enemy: MonoBehaviour, ISavable
    10. {
    11.     public AssetReference address;
    12.  
    13.     public void Save(ref SaveState saveState)
    14.     {
    15.         saveState.enemies.Add(new Entity(){
    16.             assetReference = assetReference
    17.         });
    18.     }
    19. }
    20.  
    21. public class LevelLoader(){
    22.     public SaveData saveData;
    23.  
    24.     public void LoadGame(){
    25.         //I'll assume I already loaded from JSON to the SaveData struct
    26.         foreach(var entity in saveData.enemies){
    27.             Addressables.LoadAssetAsync(entity.assetReference);
    28.          }
    29.     }
    30. }
    31.  
    Update: Serializing directly does not work when using something like Json.Net, the Unity Serializer silently ignores some properties like OperationHandle. I am using Json.Net now due to needing to serialize dictionaries and serializing an AssetReference errors for example:

    Code (CSharp):
    1. Error getting value from 'Result' on 'UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle'.
    2. Error getting value from 'Task' on 'UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle'.
    3. Error getting value from 'Status' on 'UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle'.
    So without coming up with a fix for it, I would still need to be able to get the AssetGUID from the asset reference like mentioned.
     
    Last edited: May 12, 2021
  13. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    anycolourulike likes this.
  14. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    Looking at your code above you would want your entity to just have a string assetGuid instead of the actual AssetReference.

    I am assuming that is just psuedo code above. Since there are things missing like async/await and some variable names are wrong.
    But your loader wouldn't change too much except you would construct a new AssetReference from the save guid and then do the async load.