Loxodon Framework Bundle是一个非常好用的AssetBundle加载器,也是一个AssetBundle冗余分析工具。它能够自动管理AssetBundle之间复杂的依赖关系,它通过引用计数来维护AssetBundle之间的依赖。你既可以预加载一个AssetBundle,自己管理它的释放,也可以直接通过异步的资源加载函数直接加载资源,资源加载函数会自动去查找资源所在的AB包,自动加载AB,使用完后又会自动释放AB。 它还支持弱缓存,如果对象模板已经在缓存中,则不需要重新去打开AB。它支持多种加载方式,WWW加载,UnityWebRequest加载,File方式的加载等等(在Unity5.6以上版本,请不要使用WWW加载器,它会产生内存峰值)。它提供了一个AssetBundle的打包界面,支持加密AB包(只建议加密敏感资源,因为会影响性能)。同时它也绕开了Unity3D早期版本的一些bug,比如多个协程并发加载同一个资源,在android系统会出错。它的冗余分析是通过解包AssetBundle进行的,这比在编辑器模式下分析的冗余更准确。
下载地址:AssetStore 下载
QQ群:622321589
整个项目面向接口设计,任何组件都是可以自定义或者可选的,下图是我默认的一个示例。
IResources CreateResources()
{
IResources resources = null;
#if UNITY_EDITOR
if (SimulationSetting.IsSimulationMode)
{
Debug.Log("Use SimulationResources. Run In Editor");
/* Create a PathInfoParser. */
//IPathInfoParser pathInfoParser = new SimplePathInfoParser("@");
IPathInfoParser pathInfoParser = new SimulationAutoMappingPathInfoParser();
/* Create a BundleManager */
IBundleManager manager = new SimulationBundleManager();
/* Create a BundleResources */
resources = new SimulationResources(pathInfoParser, manager);
}
else
#endif
{
/* Create a BundleManifestLoader. */
IBundleManifestLoader manifestLoader = new BundleManifestLoader();
/* Loads BundleManifest. */
BundleManifest manifest = manifestLoader.Load(BundleUtil.GetReadOnlyDirectory() + BundleSetting.ManifestFilename);
//manifest.ActiveVariants = new string[] { "", "sd" };
manifest.ActiveVariants = new string[] { "", "hd" };
/* Create a PathInfoParser. */
//IPathInfoParser pathInfoParser = new SimplePathInfoParser("@");
IPathInfoParser pathInfoParser = new AutoMappingPathInfoParser(manifest);
/* Create a BundleLoaderBuilder */
//ILoaderBuilder builder = new WWWBundleLoaderBuilder(new Uri(BundleUtil.GetReadOnlyDirectory()), false);
/* AES128_CBC_PKCS7 */
RijndaelCryptograph rijndaelCryptograph = new RijndaelCryptograph(128, Encoding.ASCII.GetBytes(this.key), Encoding.ASCII.GetBytes(this.iv));
/* Use a custom BundleLoaderBuilder */
ILoaderBuilder builder = new CustomBundleLoaderBuilder(new Uri(BundleUtil.GetReadOnlyDirectory()), false, rijndaelCryptograph);
/* Create a BundleManager */
IBundleManager manager = new BundleManager(manifest, builder);
/* Create a BundleResources */
resources = new BundleResources(pathInfoParser, manager);
}
return resources;
}
AssetBundle资源可以存在Unity3D的缓存中,也可以存在持久化目录中或者在StreamingAssets目录中,关于如何存储资源,一般和项目怎么更新资源有关系,在我的CustomBundleLoaderBuilder中,你可以自定义自己的加载规则和选择使用自己喜欢的加载器(WWW、UnityWebRequest、File等)。
using System;
using Loxodon.Framework.Bundles;
namespace Loxodon.Framework.Examples.Bundle
{
public class CustomBundleLoaderBuilder : AbstractLoaderBuilder
{
private bool useCache;
private IDecryptor decryptor;
public CustomBundleLoaderBuilder(Uri baseUri, bool useCache) : this(baseUri, useCache, null)
{
}
public CustomBundleLoaderBuilder(Uri baseUri, bool useCache, IDecryptor decryptor) : base(baseUri)
{
this.useCache = useCache;
this.decryptor = decryptor;
}
public override BundleLoader Create(BundleManager manager, BundleInfo bundleInfo, BundleLoader[] dependencies)
{
//Customize the rules for finding assets.
Uri loadBaseUri = this.BaseUri; //eg: http://your ip/bundles
if (this.useCache && BundleUtil.ExistsInCache(bundleInfo))
{
//Load assets from the cache of Unity3d.
loadBaseUri = this.BaseUri;
#if UNITY_5_4_OR_NEWER
return new UnityWebRequestBundleLoader(new Uri(loadBaseUri, bundleInfo.Filename), bundleInfo, dependencies, manager, this.useCache);
#else
return new WWWBundleLoader(new Uri(loadBaseUri, bundleInfo.Filename), bundleInfo, dependencies, manager, this.useCache);
#endif
}
if (BundleUtil.ExistsInStorableDirectory(bundleInfo))
{
//Load assets from the "Application.persistentDataPath/bundles" folder.
/* Path: Application.persistentDataPath + "/bundles/" + bundleInfo.Filename */
loadBaseUri = new Uri(BundleUtil.GetStorableDirectory());
}
#if !UNITY_WEBGL || UNITY_EDITOR
else if (BundleUtil.ExistsInReadOnlyDirectory(bundleInfo))
{
//Load assets from the "Application.streamingAssetsPath/bundles" folder.
/* Path: Application.streamingAssetsPath + "/bundles/" + bundleInfo.Filename */
loadBaseUri = new Uri(BundleUtil.GetReadOnlyDirectory());
}
#endif
if (bundleInfo.IsEncrypted)
{
if (this.decryptor != null && bundleInfo.Encoding.Equals(decryptor.AlgorithmName))
return new CryptographBundleLoader(new Uri(loadBaseUri, bundleInfo.Filename), bundleInfo, dependencies, manager, decryptor);
throw new NotSupportedException(string.Format("Not support the encryption algorithm '{0}'.", bundleInfo.Encoding));
}
//Loads assets from an Internet address if it does not exist in the local directory.
#if UNITY_5_4_OR_NEWER
if (this.IsRemoteUri(loadBaseUri))
return new UnityWebRequestBundleLoader(new Uri(loadBaseUri, bundleInfo.Filename), bundleInfo, dependencies, manager, this.useCache);
else
return new FileAsyncBundleLoader(new Uri(loadBaseUri, bundleInfo.Filename), bundleInfo, dependencies, manager);
#else
return new WWWBundleLoader(new Uri(loadBaseUri, bundleInfo.Filename), bundleInfo, dependencies, manager, this.useCache);
#endif
}
}
}
加载资源是根据资源的路径来加载的,如果你选择了路径自动映射的路径解析器,那么通过资源的路径,就可以自动找到所在的AssetBundle包。下面是资源加载的示例。
void Load(string[] names)
{
IProgressResult<float, GameObject[]> result = resources.LoadAssetsAsync<GameObject>(names);
result.Callbackable().OnProgressCallback(p =>
{
Debug.LogFormat("Progress:{0}%", p * 100);
});
result.Callbackable().OnCallback((r) =>
{
try
{
if (r.Exception != null)
throw r.Exception;
foreach (GameObject template in r.Result)
{
GameObject.Instantiate(template);
}
}
catch (Exception e)
{
Debug.LogErrorFormat("Load failure.Error:{0}", e);
}
});
}
2.通过回调方式加载场景
void LoadSceneByCallback(string sceneName)
{
ISceneLoadingResult<Scene> result = this.resources.LoadSceneAsync(sceneName);
result.AllowSceneActivation = false;
result.OnProgressCallback(p =>
{
//Debug.LogFormat("Loading {0}%", (p * 100));
});
result.OnStateChangedCallback(state =>
{
if (state == LoadState.Failed)
Debug.LogFormat("Loads scene '{0}' failure.Error:{1}", sceneName, result.Exception);
else if (state == LoadState.Completed)
Debug.LogFormat("Loads scene '{0}' completed.", sceneName);
else if (state == LoadState.AssetBundleLoaded)
Debug.LogFormat("The AssetBundle has been loaded.");
else if (state == LoadState.SceneActivationReady)
{
Debug.LogFormat("Ready to activate the scene.");
result.AllowSceneActivation = true;
}
});
}
3.通过协程的方式加载场景
IEnumerator LoadSceneByCoroutine(string sceneName)
{
ISceneLoadingResult<Scene> result = this.resources.LoadSceneAsync(sceneName);
while (!result.IsDone)
{
//Debug.LogFormat("Loading {0}%", (result.Progress * 100));
yield return null;
}
if (result.Exception != null)
{
Debug.LogFormat("Loads scene '{0}' failure.Error:{1}", sceneName, result.Exception);
}
else
{
Debug.LogFormat("Loads scene '{0}' completed.", sceneName);
}
}
我提供了一个AssetBundle资源下载的示例,它通过最新版本的资源索引库Manifest.dat ,查找本地不存在的AB资源,然后通过网络下载本地缺失的AB资源。
IEnumerator Download()
{
this.downloading = true;
try
{
IProgressResult<Progress, BundleManifest> manifestResult = this.downloader.DownloadManifest(BundleSetting.ManifestFilename);
yield return manifestResult.WaitForDone();
if (manifestResult.Exception != null)
{
Debug.LogFormat("Downloads BundleManifest failure.Error:{0}", manifestResult.Exception);
yield break;
}
BundleManifest manifest = manifestResult.Result;
IProgressResult<float, List<BundleInfo>> bundlesResult = this.downloader.GetDownloadList(manifest);
yield return bundlesResult.WaitForDone();
List<BundleInfo> bundles = bundlesResult.Result;
if (bundles == null || bundles.Count <= 0)
{
Debug.LogFormat("Please clear cache and remove StreamingAssets,try again.");
yield break;
}
IProgressResult<Progress, bool> downloadResult = this.downloader.DownloadBundles(bundles);
downloadResult.Callbackable().OnProgressCallback(p =>
{
Debug.LogFormat("Downloading {0:F2}KB/{1:F2}KB {2:F3}KB/S", p.GetCompletedSize(UNIT.KB), p.GetTotalSize(UNIT.KB), p.GetSpeed(UNIT.KB));
});
yield return downloadResult.WaitForDone();
if (downloadResult.Exception != null)
{
Debug.LogFormat("Downloads AssetBundle failure.Error:{0}", downloadResult.Exception);
yield break;
}
Debug.Log("OK");
if (this.resources != null)
{
//update BundleManager's manifest
BundleManager manager = (this.resources as BundleResources).BundleManager as BundleManager;
manager.BundleManifest = manifest;
}
#if UNITY_EDITOR
UnityEditor.EditorUtility.OpenWithDefaultApp(BundleUtil.GetStorableDirectory());
#endif
}
finally
{
this.downloading = false;
}
}
下面是这个项目在AssetStore上的介绍
AssetBundle Manager for Unity3D
Loxodon Framework Bundle is an AssetBundle manager.It provides a functionality that can automatically manage/load an AssetBundle and its dependencies from local or remote location.Asset Dependency Management including BundleManifest that keep track of every AssetBundle and all of their dependencies. An AssetBundle Simulation Mode which allows for iterative testing of AssetBundles in a the Unity editor without ever building an AssetBundle.
The Loxodon Framework Bundle includes all the source code, it works alone, or works with the Loxodon Framework, AssetBundles-Browser.
For tutorials,examples and support,please see the project.You can also discuss the project in the Unity Forums.
The asset redundancy analyzer can help you find the redundant assets included in the AssetsBundles.Create a fingerprint for the asset by collecting the characteristic data of the asset. Find out the redundant assets in all AssetBundles by fingerprint comparison.it only supports the AssetBundle of Unity 5.6 or higher.
For More Information Contact Us at: yangpc.china@gmail.com
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。