using System.Collections.Generic;
using UnityEngine;
namespace XGame.Framework.Asset
{
//internal partial class AssetBundleLoader
//{
//}
///
/// AssetBundleLoader已加载的Bundle仓库
///
internal class BundleRepository
{
///
/// 已加载的Bundle
/// key:bundleName
///
private Dictionary BundleMap { set; get; }
///
/// 已加载的Asset的InstanceId
/// UnityEngine.Object用InstanceId代替HashCode,hash值可能出现重复
///
private Dictionary UsingHashCodeMap { set; get; }
///
/// 等待卸载的Asset
///
private Dictionary UnusedAssetMap { set; get; }
public BundleRepository()
{
BundleMap = new Dictionary();
UsingHashCodeMap = new Dictionary();
UnusedAssetMap = new Dictionary();
}
#region Bundle
public bool ContainsBundle(string bundleName)
{
return BundleMap.ContainsKey(bundleName);
}
public void AddBundle(BundleAsset bundleAsset)
{
if (bundleAsset == null)
{
AssetsLog.Warn("Bundle Repository Add Invalid Bundle.");
return;
}
var bundleName = bundleAsset.AddressableName;
if (BundleMap.ContainsKey(bundleName))
{
AssetsLog.Warn($"Add Bundle Repeat. Name:{bundleName}");
return;
}
BundleMap.Add(bundleName, bundleAsset);
}
public BundleAsset GetBundle(string bundleName)
{
BundleMap.TryGetValue(bundleName, out var bundle);
return bundle;
}
public void RemoveBundle(string bundleName)
{
BundleMap.Remove(bundleName);
}
public void RetainBundle(string bundleName)
{
if (BundleMap.TryGetValue(bundleName, out var bundle))
{
bundle.Retain();
}
}
public void ReleaseBundle(string bundleName)
{
if (BundleMap.TryGetValue(bundleName, out var bundle))
{
bundle.Release();
}
}
#endregion
#region AssetHashCode
public bool RegistAssetHash(int hashCode, string addressableName)
{
if (!UsingHashCodeMap.ContainsKey(hashCode))
{
UsingHashCodeMap.Add(hashCode, addressableName);
return true;
}
AssetsLog.Warn($"Bundle asset hash repeat. Hash:{hashCode} Last:{UsingHashCodeMap[hashCode]} Next:{addressableName}");
return false;
}
// ReSharper disable once IdentifierTypo
public void UnRegistAssetHash(int hashCode)
{
if (UsingHashCodeMap.ContainsKey(hashCode))
{
UsingHashCodeMap.Remove(hashCode);
}
}
public string GetAssetNameByHash(int hashCode)
{
UsingHashCodeMap.TryGetValue(hashCode, out var addressableName);
return addressableName;
}
public bool ContainsAssetHash(int hashCode)
{
return UsingHashCodeMap.ContainsKey(hashCode);
}
public bool ContainsAsset(string addressableName)
{
return UsingHashCodeMap.ContainsValue(addressableName);
}
#endregion
#region UnusedAsset
public bool ContainsUnusedAsset(string addressableName)
{
UnusedAssetMap.TryGetValue(addressableName, out var asset);
return asset != null;
}
public void PushUnusedAsset(Object source)
{
if (source == null) return;
var instanceId = source.GetInstanceID();
var addressableName = GetAssetNameByHash(instanceId);
if (string.IsNullOrEmpty(addressableName))
{
AssetsLog.Debug($"Object is unregistered. Hash:{instanceId} Name:{source.name}");
return;
}
if (UnusedAssetMap.ContainsKey(addressableName))
{
AssetsLog.Debug($"Object had in map. But add repeat. Name:{addressableName} Next:{instanceId} Last:{UnusedAssetMap[addressableName]?.GetInstanceID()}");
return;
}
UnusedAssetMap.Add(addressableName, source);
}
public Object PopUnusedAsset(string addressableName)
{
if (UnusedAssetMap.TryGetValue(addressableName, out var source))
{
UnusedAssetMap.Remove(addressableName);
}
return source;
}
public void UnloadUnusedAssets(System.Func isReferencing, System.Action onUnloadAsset)
{
//释放未被引用的Asset
var unloadList = new List();
foreach (var item in UnusedAssetMap)
{
var addressableName = item.Key;
if (!isReferencing(item.Key))
{
unloadList.Add(addressableName);
}
}
foreach (var addressableName in unloadList)
{
var asset = UnusedAssetMap[addressableName];
var instanceId = asset?.GetInstanceID() ?? 0;
UnRegistAssetHash(instanceId);
UnusedAssetMap.Remove(addressableName);
onUnloadAsset?.Invoke(addressableName);
asset.Unload();
//if (asset is Component || asset is GameObject || asset is AssetBundle)
//{
// //非独立资源
// //Object.Destroy(asset);
//}
//else
//{
// //独立资源才能使用Resources.UnloadAsset
// Resources.UnloadAsset(asset);
//}
AssetsLog.Debug($"Resources UnloadAsset: {addressableName}");
}
unloadList.Clear();
//释放引用计数为零的Bundle
foreach (var bundleItem in BundleMap)
{
if (bundleItem.Value.Reference <= 0)
{
unloadList.Add(bundleItem.Key);
}
}
foreach (var bundlePath in unloadList)
{
var bundleAsset = BundleMap[bundlePath];
BundleMap.Remove(bundlePath);
bundleAsset.Dispose();
AssetsLog.Debug($"AssetBundle Unload: {bundlePath}");
}
unloadList.Clear();
Resources.UnloadUnusedAssets();
}
#endregion
public void Dispose()
{
foreach (var asset in UnusedAssetMap)
{
asset.Value.Unload();
//Resources.UnloadAsset(asset.Value);
}
UnusedAssetMap.Clear();
foreach (var it in BundleMap)
{
it.Value.Dispose();
}
BundleMap.Clear();
UsingHashCodeMap.Clear();
}
}
}