Search Unity

Set Addressable via C#

Discussion in 'Addressables' started by d_grass, May 3, 2019.

  1. d_grass

    d_grass

    Joined:
    Mar 6, 2018
    Posts:
    45
    Hello Everyone,

    i am searching a way to mark an prefab as addressable and also to set the id through C#.
    I can't find anything.

    Does anyone have a clue? I would be thankfull.

    Best Regards,
     
  2. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    Take a look at how our UI does things. It should be almost exclusively working through public APIs, so you could mimic it. AddressableAssetsSettingsGroupEditor is the main place, but there are lots of spots to look.
     
  3. d_grass

    d_grass

    Joined:
    Mar 6, 2018
    Posts:
    45
    Thank you for that clue, i will look further into it.
     
    unity_bill likes this.
  4. d_grass

    d_grass

    Joined:
    Mar 6, 2018
    Posts:
    45
    After your advise i looked further into it.

    In my opinion AddressableAssetsSettingsGroupEditor was not a good place to look after. But thank you it leads the way.
    Then i researched further and AssetInspectorGUI.cs was sounding promising.

    Then i implemented successfully easier access functions to edit addressable IDs (i will add them on the end for everybody who seeks an similar solution).

    I also want to mark them as adressables. In AssetInspectorGUI.cs is a function SetAaEntry which does this but it is using AddressableAssetUtility which is not accessable in another context. And i dont want to reimplement the moving of resources to groups and so on. @unity_bill could it be that you have another clue for me?

    [Following code can be ignored when an better solution come up. This code was created at version 0.8.6 Addressables System]
    Code (CSharp):
    1. public static class AddressableEditorExtension
    2. {
    3.     /// <summary>
    4.     /// Set Addressables Key/ID of an gameObject.
    5.     /// </summary>
    6.     /// <param name="gameObject">GameObject to set Key/ID</param>
    7.     /// <param name="id">Key/ID</param>
    8.     public static void SetAddressableID(this GameObject gameObject, string id)
    9.     {
    10.         SetAddressableID(gameObject as Object, id);
    11.     }
    12.  
    13.     /// <summary>
    14.     /// Set Addressables Key/ID of an object.
    15.     /// </summary>
    16.     /// <param name="o">Object to set Key/ID</param>
    17.     /// <param name="id">Key/ID</param>
    18.     public static void SetAddressableID(this Object o, string id)
    19.     {
    20.         if (id.Length == 0)
    21.         {
    22.             Debug.LogWarning($"Can not set an empty adressables ID.");
    23.         }
    24.         AddressableAssetEntry entry = GetAddressableAssetEntry(o);
    25.         if (entry != null)
    26.         {
    27.             entry.address = id;
    28.         }
    29.     }
    30.  
    31.     /// <summary>
    32.     /// Get Addressables Key/ID of an gameObject.
    33.     /// </summary>
    34.     /// <param name="gameObject">gameObject to recive addressables Key/ID</param>
    35.     /// <returns>Addressables Key/ID</returns>
    36.     public static string GetAddressableID(this GameObject gameObject)
    37.     {
    38.         return GetAddressableID(gameObject as Object);
    39.     }
    40.  
    41.     /// <summary>
    42.     /// Get Addressables Key/ID of an object.
    43.     /// </summary>
    44.     /// <param name="o">object to recive addressables Key/ID</param>
    45.     /// <returns>Addressables Key/ID</returns>
    46.     public static string GetAddressableID(this Object o)
    47.     {
    48.         AddressableAssetEntry entry = GetAddressableAssetEntry(o);
    49.         if (entry != null)
    50.         {
    51.             return entry.address;
    52.         }
    53.         return "";
    54.     }
    55.  
    56.     /// <summary>
    57.     /// Get addressable asset entry of an object.
    58.     /// </summary>
    59.     /// <param name="o">>object to recive addressable asset entry</param>
    60.     /// <returns>addressable asset entry</returns>
    61.     public static AddressableAssetEntry GetAddressableAssetEntry(Object o)
    62.     {
    63.         AddressableAssetSettings aaSettings = AddressableAssetSettingsDefaultObject.Settings;
    64.  
    65.         AddressableAssetEntry entry = null;
    66.         string guid = string.Empty;
    67.         long localID = 0;
    68.         string path;
    69.  
    70.         bool foundAsset = AssetDatabase.TryGetGUIDAndLocalFileIdentifier(o, out guid, out localID);
    71.         path = AssetDatabase.GUIDToAssetPath(guid);
    72.  
    73.         if (foundAsset && (path.ToLower().Contains("assets")))
    74.         {
    75.             if (aaSettings != null)
    76.             {
    77.                 entry = aaSettings.FindAssetEntry(guid);
    78.             }
    79.         }
    80.  
    81.         if (entry != null)
    82.         {
    83.             return entry;
    84.         }
    85.  
    86.         return null;
    87.     }
    88. }
     
    Last edited: May 23, 2019
    Yuri-Cruz, Ronsu900, tuccci and 4 others like this.
  5. KosaJr

    KosaJr

    Joined:
    Jan 3, 2017
    Posts:
    10
    Have You found maybe a way to mark asset as "Adressable" from code? I want to mark every scriptableObject created from script, but I don't know how to do this.
    Cheers.
     
  6. Jobus

    Jobus

    Joined:
    Jun 7, 2013
    Posts:
    7
    I wrote something like this some weeks ago. I have customized my Addressables package a bit, so it's possible that something in this example is inaccessible, but give it a shot.

    Code (CSharp):
    1. [MenuItem("Tools/Refresh Addressables")]
    2. public static void RefreshAddressables()
    3. {
    4.     var settings = AddressableAssetSettingsDefaultObject.Settings;
    5.     var group = settings.DefaultGroup;
    6.     var guids = AssetDatabase.FindAssets("t:ScriptableObject", new[] {"Assets/ScriptableObjects"});
    7.  
    8.     var entriesAdded = new List<AddressableAssetEntry>();
    9.     for (int i = 0; i < guids.Length; i++)
    10.     {
    11.         var entry = settings.CreateOrMoveEntry(guids[i], group, readOnly: false, postEvent: false));
    12.         entry.address = AssetDatabase.GUIDToAssetPath(guids[i]);
    13.         entry.labels.Add("MyLabel");
    14.    
    15.         entriesAdded.Add(entry);
    16.     }
    17.  
    18.     settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesAdded, true);
    19. }
    Note that this will put them all flat in the default group root. I recommend you make a new group which you then get by changing line 5: var group = settings.FindGroup("My Group")

    Passing readOnly: true to CreateOrMoveEntry will fade out the entries in the Addressables panel so they can't be manually edited, if so wished.

    Edit: Since people seem to find my example useful, here's an updated one that clears old entries and labels for easier automation (in my old example, if you move an already registered asset and then run the method again, it will not update its address):
    Code (CSharp):
    1. [MenuItem("Tools/Refresh Addressables")]
    2. public static void RefreshAddressables()
    3. {
    4.     var settings = AddressableAssetSettingsDefaultObject.Settings;
    5.     var group = settings.FindGroup("My Group");
    6.     var guids = AssetDatabase.FindAssets("t:ScriptableObject", new[] {"Assets/ScriptableObjects"});
    7.  
    8.     var entriesAdded = new List<AddressableAssetEntry>();
    9.     for (int i = 0; i < guids.Length; i++)
    10.     {
    11.         var entry = settings.CreateOrMoveEntry(guids[i], group, readOnly: false, postEvent: false));
    12.         entry.address = AssetDatabase.GUIDToAssetPath(guids[i]);
    13.         entry.labels.Clear();
    14.         entry.labels.Add("MyLabel");
    15.    
    16.         entriesAdded.Add(entry);
    17.     }
    18.  
    19.     foreach (AddressableAssetEntry entry in group.entries.Except(entriesAdded).ToArray())
    20.         group.RemoveAssetEntry(entry);
    21.  
    22.     settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesAdded, true);
    23. }
    But make sure you use a custom group (update line 5 with your group name) for it exclusively since otherwise it would clear out all your manually added entries too.
     
    Last edited: Feb 9, 2021
  7. KosaJr

    KosaJr

    Joined:
    Jan 3, 2017
    Posts:
    10
    @Jobus
    That was really helpfull! I've got what I want, many thanks! :_
     
  8. Favo-Yang

    Favo-Yang

    Joined:
    Apr 4, 2011
    Posts:
    464
  9. IEdge

    IEdge

    Joined:
    Mar 25, 2017
    Posts:
    51
    Favo-Yang likes this.
  10. vonchor

    vonchor

    Joined:
    Jun 30, 2009
    Posts:
    249
    I suppose this is a bit of a necro-post, but my use case was a little different. As part of a custom editor workflow for a Tilemaps related project I wanted to be able to mark assets addressable from code, just to make workflow easier (ie don't have to remember to tick the box on assets created during the workflow).

    I wanted something like:

    public static bool AddAssetToAddressables(Object target, string filter)

    No deletions, just adding.

    So I went thru the editor code (HT to Jetbrains' decompiler) and created something that works fine for that use case. But I'm a little confused: I don't believe that I can post it without violating the Unity license as it's derived from editor code. For my own use and not for distribution is a different matter, but can someone from Unity advise on whether it's OK to post it? It's confusing as about a year ago (in this thread) the advice was to inspect editor code...

    It seems a shame as examples for Addressables don't explain how to do this.
     
    Endahs and ImpossibleRobert like this.
  11. Endahs

    Endahs

    Joined:
    Sep 16, 2014
    Posts:
    94
    I hope you can, because I too am looking for something like this.
     
  12. FloBeber

    FloBeber

    Joined:
    Jun 9, 2015
    Posts:
    166
    @Jobus Thanks for sharing your code. Though, it seems to be working only on non-scene assets. Is there any way to mark a scene asset as Adressable from code?
     
  13. Jobus

    Jobus

    Joined:
    Jun 7, 2013
    Posts:
    7
    @FlorianBernard On line 6 in my example, you need to change the parameters to t:Scene and new[] {"Assets/Scenes"} (or wherever you are storing you scene assets).
     
  14. FloBeber

    FloBeber

    Joined:
    Jun 9, 2015
    Posts:
    166
    @Jobus Thanks for the reply.

    Though, I just got it working. Not sure what the issue was o_O (but I'm definitely not using AssetDatabase.FindAssets)

    Here's is the extension code if anyone's interested (make sure you're using it on an asset coming from AssetDatabase.LoadAssetAtPath):

    Code (CSharp):
    1. public static class AddressableExtensions
    2. {
    3.     public static void SetAddressableGroup(this Object obj, string groupName)
    4.     {
    5.         var settings = AddressableAssetSettingsDefaultObject.Settings;
    6.  
    7.         if (settings)
    8.         {
    9.             var group = settings.FindGroup(groupName);
    10.             if (!group)
    11.                 group = settings.CreateGroup(groupName, false, false, true, null, typeof(ContentUpdateGroupSchema), typeof(BundledAssetGroupSchema));
    12.  
    13.             var assetpath = AssetDatabase.GetAssetPath(obj);
    14.             var guid = AssetDatabase.AssetPathToGUID(assetpath);
    15.  
    16.             var e = settings.CreateOrMoveEntry(guid, group, false, false);
    17.             var entriesAdded = new List<AddressableAssetEntry> {e};
    18.  
    19.             group.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesAdded, false, true);
    20.             settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesAdded, true, false);
    21.         }
    22.     }
    23. }