Search Unity

ETA on deleting single Addressables groups

Discussion in 'Addressables' started by TheFudge, Apr 23, 2019.

  1. TheFudge

    TheFudge

    Joined:
    Apr 28, 2014
    Posts:
    39
    Thanks for the great update, Finally the GetDownloadSize() reports the correct download size.

    Is there an ETA on when an Addressable Group can be removed from persistent data onits own? The only way I see currently is to delete every Addressable ever downloaded. I would like the user to decide if he does want the group data or if he thinks he does not need it.

    Regards
     
  2. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    I'm not sure what you're asking. You mean removing bundles for the downloaded cache? And choosing which bundles based on the group the addressable was in?

    -Bill
     
  3. TheFudge

    TheFudge

    Joined:
    Apr 28, 2014
    Posts:
    39
    Yes.
    In our project we have a list of 3D objects with animations. Each object has its data stored in an Addressable asset bundle group. That group gets downloaded if the user wants to view the animation.
    But we want the user to be able to delete a single group instead of every assetbundle ever downloaded.

    As I understand it currently this is not possible as Asset Bundles use one Chache and not multiple chaches and no information on where the data is stored.

    What would work is a path on where something is stored in the cache. Then we could Delete it like a normal file.
    ~Edit: Files are locked by the Caching system, so that option is not an option :(
     
    Last edited: Apr 25, 2019
  4. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    Ah, I see. I could add something like that to the to-do. It would not be based on group, but on key. Basically, as a counter-interface to `DownloadDependencies(key)`, there would be something like a `CleanCache(key)`.

    That usecase makes sense. We'll look into it.

    Thanks for the idea.
     
    CodeBombQuinn likes this.
  5. HarryHodgson

    HarryHodgson

    Joined:
    Jan 21, 2014
    Posts:
    2
    Hi @unity_bill,

    Any ETA on the feature you described? I was really hoping to have it before December.

    Thanks,
    Harry
     
    Last edited: Sep 20, 2019
  6. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    970
    To be honest, if you are really pushed for time, it should not be too hard to implement a version of this yourself in the mean time. Merging changes to the addressables system has not been particularly onerous for us.
     
    unity_bill likes this.
  7. HugoClip

    HugoClip

    Joined:
    Feb 28, 2018
    Posts:
    52
    Here's a quick snippet to get you started, not sure if this how to interact with the cache, but it's the API that I found.

    Code (CSharp):
    1. private void ClearCache(object key)
    2. {
    3.     if (!GetResourceLocations(key, typeof(object), out IList<IResourceLocation> locations))
    4.         return;
    5.  
    6.     foreach(IResourceLocation loc in locations)
    7.     {
    8.         foreach(IResourceLocation dep in loc.Dependencies)
    9.         {
    10.             if (dep.Data is AssetBundleRequestOptions bundleData)
    11.             {
    12.                 Caching.ClearCachedVersion(bundleData.BundleName, Hash128.Parse(bundleData.Hash));
    13.             }
    14.         }
    15.     }
    16. }
     
    unity_bill likes this.
  8. HarryHodgson

    HarryHodgson

    Joined:
    Jan 21, 2014
    Posts:
    2
    Thanks @HugoClip for the code snippet, it has been very helpful. But it has not solved everything.

    If i have the addressables A, B and C. Where the addressable C is a dependency of both A and B.

    Then i delete addressable A with the above method, then i believe C will also be deleted as it does not check for other addressables that are dependent on it.
    Therefore breaking the addressable B by removing its dependency.

    Are you aware of any Addressable API that can (at runtime) return a list of addressable keys that are dependant on an addressble?
    This will then allow me to skip on deleting the dependency if the list contains any other keys that are not the key im trying to delete.

    p.s A ETA from Bill would still be helpful to me as it could potentially save me time.

    Thanks,
    Harry
     
  9. HugoClip

    HugoClip

    Joined:
    Feb 28, 2018
    Posts:
    52
    Afaik there is not addressable API to do that.
    But I have put together this, beware as I haven't tested, still it it a starting point for your code.

    Code (CSharp):
    1. public class ResourceLocatorComparor : IEqualityComparer<IResourceLocation>
    2. {
    3.     public bool Equals(IResourceLocation x, IResourceLocation y)
    4.     {
    5.         return x.InternalId == y.InternalId;
    6.     }
    7.  
    8.     public int GetHashCode(IResourceLocation obj)
    9.     {
    10.         return obj.InternalId.GetHashCode();
    11.     }
    12.  
    13. }
    14.  
    15.  
    16. private IList<string> GetDeps(object key)
    17. {
    18.     if (!GetResourceLocations(key, typeof(object), out IList<IResourceLocation> locations))
    19.         return null;
    20.  
    21.     var dependentAssetBundles = new HashSet<IResourceLocation>(new ResourceLocatorComparor());
    22.  
    23.     foreach(IResourceLocation loc in locations)
    24.     {
    25.         foreach(IResourceLocation dep in loc.Dependencies)
    26.         {
    27.             if (dep.ResourceType == typeof(IAssetBundleResource))
    28.             {
    29.                 dependentAssetBundles.Add(dep);
    30.             }
    31.         }
    32.     }
    33.  
    34.     //get the catalog locations
    35.     ResourceLocationMap map = ResourceLocators[0] as ResourceLocationMap;
    36.  
    37.     //exclude everything that is an asset bundle
    38.     var allNonAssetBundleLocs = map.Locations.Values.SelectMany(l => l).Where(loc => loc.ResourceType != typeof(IAssetBundleResource));
    39.  
    40.     //remove duplicates
    41.     var uniqueAllNonAssetBundleLocs = new HashSet<IResourceLocation>(allNonAssetBundleLocs, new ResourceLocatorComparor());
    42.  
    43.     //check all locations that depend on those asset bundles
    44.     var dependantLocationsFromGivenKey = uniqueAllNonAssetBundleLocs.Where(loc =>
    45.         loc.HasDependencies && loc.Dependencies.ToList().Any(depLoc => dependentAssetBundles.Contains(depLoc)));
    46.  
    47.     return dependantLocationsFromGivenKey.Select(loc => loc.PrimaryKey).ToList();
    48. }
     
  10. Dust999Games

    Dust999Games

    Joined:
    Jan 10, 2014
    Posts:
    7
    Hi, Bill we just trying to make this feature into our game. Have you any progress in this?

    Or maybe you can suggest any solution how can I delete the addressable assets at mobile devices for increasing free space?
     
    Last edited: Oct 11, 2019
    TextusGames likes this.
  11. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    This I really like. but it seems it does not quite solve the problem (or could likely cause extra downloads)

    This second version I don't like as much. Not the code itself (looks good!) but the fact that it would likely be a very expensive bit of code to run for large projects.


    All in all, I'm liking this less and less. For example, say you had this scenario:

    Key "tank" -> bundleA, bundleB
    key "tree" -> bundleC, bundleB

    now, at some point, you say you want to ClearCache("tank"). The cheap solution is obviously no good, because it'd delete bundleB. So that's out. But what if we do the expensive solution. It'll remove bundleA, but not bundleB because "tree" needs it.

    Now some time later, you say ClearCache("tree"). Ideally, this would clear C & B, because you already told us you don't need tree anymore. But we won't know that. So we'll delete bundleC, but not bundleB.

    And this is a very clean example. In reality, there will be so many cross dependencies that a ClearCache would rarely give you something you actually wanted or found beneficial.


    I think the better answer is a feature we are working on for keys removed or changed in the catalog. This would, on catalog update, remove bundles no longer referenced. Say you had the above tree & tank example. Now you do a content update, and "tank" no longer exists. Our code would remove "bundleA". Or maybe "tank" was updated, and pointed now to bundleA2 and bundleB2. That would remove "bundleA" in that scenario as well.
    This feature isn't done, but will likely be done far sooner than the ClearCache API.

    At least that's my current opinion based on my understanding of the feature, because...
    a) you can write your own code to do it
    b) it adds danger of introducing bugs and causing re-downloads of valid data
    c) i don't actually see it as being useful in many real world scenarios.


    I could be wrong though. feel free to reply and convince me otherwise.
     
  12. HugoClip

    HugoClip

    Joined:
    Feb 28, 2018
    Posts:
    52
    You are right, I don't really like that solution too :)
    I mean besides iterating all the locations for every key, it's also does a bunch of expensive checks for every dependency, so it's bound to explode.

    It would be very helpful to have that "changed keys" feature, maybe some method that receives 2 resource locators and returns the differences. Currently I have that somewhat implemented but I'm not sure if I'm happy with the result, I'm just doing a_old.dep[0].hash != a_new.dep[0].hash to check if they were modified.

    One thing I really want is for that feature to be optional, at the moment I have a fallback system that can easily fallback to older catalogs, deleting older bundles may not be desirable in this situation.