前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一个非常好用的AssetBundle资源加载器

一个非常好用的AssetBundle资源加载器

原创
作者头像
Loxodon Studio
修改2019-02-28 18:24:27
2.6K0
修改2019-02-28 18:24:27
举报

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

整个项目面向接口设计,任何组件都是可以自定义或者可选的,下图是我默认的一个示例。

        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;
        }
  • 自定义AB的查询规则

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包。下面是资源加载的示例。

  1. 通过回调的方式加载一个资源
        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.

Asset Redundancy Analyzer

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.

Tested in Unity 3D on the following platforms: PC/Mac/Linux Android IOS UWP(Windows 10) WebGL

Key features:

  • Support encryption and decoding of the AssetBundle files(支持AssetBundle文件的加密和解密);
  • Use reference counting to manage the dependencies of AssetBundle(使用引用计数来管理AssetBundle的依赖关系);
  • Automatically unloading AssetBundle with reference count 0 by destructor or "Dispose" method(当引用计数为0时,通过析构函数或者Dispose函数自动卸载AssetBundle);
  • Use weak cache to optimize load performance(使用弱缓存来优化加载性能);
  • Interface-oriented programming, you can customize the loader and file search rules for the AssetBundle(面向接口编程,可以自定义加载器,自定义AssetBundle的查找规则);
  • Support for simulating loading in the editor without building AssetBundles(在编辑器下,支持模拟AssetBundle的方式加载资源以方便测试);
  • Supports the unpacking and the redundancy analysis of the AssetBundle(支持通过AssetBundle包来分析资源冗余,这比在Editor模式分析的冗余更准确);

For More Information Contact Us at: yangpc.china@gmail.com

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 打包工具介绍
  • 使用示例
  • Asset Redundancy Analyzer
  • Tested in Unity 3D on the following platforms: PC/Mac/Linux Android IOS UWP(Windows 10) WebGL
  • Key features:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档