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(); } } }