There should be a feature to let us keep only the latest versions of bundles when overwriting or updating builds. Removing the whole build cache and the re-adding all bundles seems to be the only solution for now.
This should be the case both when building data and also when downloading data.
Not using hashes helps when building, but it still poses a problem when downloading, because the bundles get extracted in a form of bundleName/bundleHash/ so it will preserve previous bundleHash subdirs.
Would be great, yes! I tried Caching.ClearAllCachedVersions(identifier); and Addressables.ClearDependencyCacheAsync(identifier); and neither worked in my unit tests I had to Caching.ClearCache(); everything.
Here’s my current code to solve this problem on android. haven’t tested it on IOS yet. It feels pretty hacky, i wish there was a cleaner solution too. This code assumes your bundle names don’t change and that you have “Append hash to filename” turned on for all your bundles.
private void ClearOldData()
{
Log.Debug("Caches before");
DebugUtility.PrintCacheSizes();
var bundleNames = new HashSet<string>();
var bundles = new HashSet<CachedAssetBundle>();
foreach (var loc in Addressables.ResourceLocators)
{
foreach (var key in loc.Keys)
{
if (loc.Locate(key, typeof(object), out var resourceLocations))
{
foreach (var l in resourceLocations)
{
if (l.HasDependencies)
{
foreach (var d in l.Dependencies)
{
var bundleName = Path.GetFileName(d.InternalId);
if (!bundleNames.Contains(bundleName))
{
if (d.Data is AssetBundleRequestOptions dependencyBundle)
{
bundleNames.Add(bundleName);
bundles.Add(new CachedAssetBundle(bundleName, Hash128.Parse(dependencyBundle.Hash)));
}
}
}
}
}
}
else
{
Log.Error("Failed to locate " + key);
}
}
}
var cache = Caching.GetCacheAt(0);
var path = cache.path;
Log.Debug("Cache Path: " + path);
var bundlesToRemove = new List<CachedAssetBundle>();
try
{
var folders = Directory.GetDirectories(path);
foreach (var folder in folders)
{
var folderName = new DirectoryInfo(folder).Name;
if (!bundles.Any(x => x.name.Contains(folderName)))
{
Log.Debug("Found old bundle: " + folderName);
var hash = folderName.Split('_').Last();
var cachBundle = new CachedAssetBundle(folderName, Hash128.Parse(hash));
bundlesToRemove.Add(cachBundle);
}
}
}
catch(Exception e)
{
#if UNITY_EDITOR
Log.Debug("No cache directory found in Editor.");
#else
Log.Error("Failed to get old bundles when trying to ClearOldData " + e.ToString());
#endif
}
foreach (var bundle in bundlesToRemove)
{
var hashes = new List<Hash128>();
var bundleName = bundle.name;
Caching.GetCachedVersions(bundleName, hashes);
if (hashes.Count > 0)
{
var success = Caching.ClearCachedVersion(bundleName, bundle.hash);
if (success)
{
Log.Debug("Cleared old bundle " + bundleName);
}
else
{
Log.Warn("failed to delete bundle " + bundleName);
}
}
else
{
Debug.Log("bundle " + bundleName + " " + bundle.hash + " found no cached versions");
}
}
Log.Debug("Caches after");
DebugUtility.PrintCacheSizes();
}
Edit: The following code is obsolete. You can set clear cache behavior to Clear when new version is loaded
@LilMako17 solution seem to not work anymore or dont work with my setting.
So here my updated code.
We take all our addressable location add their hash to a list.
After we iterate on all the sub folder in the cache.
If the sub folder is not in our hash list we delete it
static void ClearOldData()
{
var bundlesHash = new HashSet<string>();
foreach (var loc in Addressables.ResourceLocators)
{
foreach (var key in loc.Keys)
{
if (!loc.Locate(key, typeof(object), out var resourceLocations))
continue;
foreach (var d in resourceLocations.Where(l => l.HasDependencies).SelectMany(l => l.Dependencies))
{
if (d.Data is AssetBundleRequestOptions dependencyBundle)
bundlesHash.Add(dependencyBundle.Hash);
}
}
}
var path = Caching.GetCacheAt(0).path;
if (!Directory.Exists(path))
return;
foreach (var directory in Directory.GetDirectories(path).SelectMany(Directory.GetDirectories))
{
if (!bundlesHash.Contains(new DirectoryInfo(directory).Name))
Directory.Delete(directory, true);
}
}