Unity 变体探秘

起因:我们在打Bundle 的时候出现了同一个AB里面有相同文件名字的文件(虽然路径不同),具体报错如下:

14:22:18 Building AssetBundle failed because hash collision was detected in the deterministic id generation.
14:22:18 Conflict happened between Asset "Assets/Game/GameAsset/RofConfig/HMT/RofBonus.json" and "Assets/Game/GameAsset/RofConfig/SEA/RofBonus.json

上面报错的两个文件可以看到是文件名相同,文件夹相同
 
我们代码里面打包的代码如下,会发现我们指定了变体Variant值,


        assetBundleBuilds.Add(new AssetBundleBuild()
        {
            assetBundleName = "Data",
            assetBundleVariant = "Summer",
            ......

同时打包的参数是用的Hash值
 

  var options =
                BuildAssetBundleOptions.DeterministicAssetBundle |
                BuildAssetBundleOptions.StrictMode |
                BuildAssetBundleOptions.ChunkBasedCompression;

Unity API 解释,这里的Hash值居然是根据文件名字生成的,而不是meta 里面的hash值(开始在这里也掉坑了),真奇葩的设定

  //
        // 摘要:
        //     Builds an asset bundle using a hash for the id of the object stored in the asset
        //     bundle.
        DeterministicAssetBundle = 16,

所以就会出现开始的虽然在不同的文件夹下也会报错提示Hash冲突的情况了。

这里研究下变体的运行原理

打包,场景下依赖其中的某个变体Data.Spring ,如下有三个变体 Data.Spring ; Data.Summer; Data.Fall ,打包代码如下

#if UNITY_EDITOR
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class Build
{
    [MenuItem("Tools/Build")]
	static void PlatformBuild()
    {
        Caching.ClearCache();
        var assetBundleBuilds = new List<AssetBundleBuild>();
        assetBundleBuilds.Add(new AssetBundleBuild()
        {
            assetBundleName = "Level",
            assetBundleVariant = "",
            assetNames = new string[] {
                "Assets/Level.unity",
            },
        });

        assetBundleBuilds.Add(new AssetBundleBuild()
        {
            assetBundleName = "Data1",
            assetBundleVariant = "Spring",
            assetNames = new string[] {
                "Assets/Data/Spring/Main.jpg",
                "Assets/Data/Spring/Text.prefab",
                "Assets/Data/Spring/String.txt",
                "Assets/Data/Spring/Color.asset",
            },
        });
        
        assetBundleBuilds.Add(new AssetBundleBuild()
        {
            assetBundleName = "Data",
            assetBundleVariant = "Fall",
            assetNames = new string[] {
               "Assets/Data/Fall/Text.prefab",
               "Assets/Data/Fall/Main.jpg",
               "Assets/Data/Fall/String.txt",
               "Assets/Data/Fall/Color.asset",
            },
        });

        assetBundleBuilds.Add(new AssetBundleBuild()
        {
            assetBundleName = "Data",
            assetBundleVariant = "Summer",
            assetNames = new string[] {
                "Assets/Data/Summer/Main.jpg",
                "Assets/Data/Summer/Text.prefab",
                "Assets/Data/Summer/String.txt",
                "Assets/Data/Summer/Color.asset",
            },
        });

        var path = Path.GetFullPath(Application.dataPath + "/../Build");
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        BuildPipeline.BuildAssetBundles(path,
            assetBundleBuilds.ToArray(), 
            BuildAssetBundleOptions.ForceRebuildAssetBundle,
            BuildTarget.StandaloneWindows64);

        if (!UnityEditorInternal.InternalEditorUtility.inBatchMode)
        {
            System.Diagnostics.Process.Start(path);
        }
    }
}
#endif

加载,通过Theme切换不同场景变体,会发现我们怎么切换都能加载到争取的资源

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Loader : MonoBehaviour {

    public enum Theme
    {
        Spring,
        Fuck,
        Summer
    }

    public Theme loadTheme = Theme.Spring;
    IEnumerator Start()
    {
        var root = Application.dataPath + "/../Build";
        var themePath = root + "/data." + loadTheme.ToString().ToLower();
        var levelPath = root + "/level";

        var ab = AssetBundle.LoadFromFile(themePath);
        foreach (var assetName in ab.GetAllAssetNames())
        {
            Debug.LogFormat("Assets: {0}", assetName);
        }

        AssetBundle.LoadFromFile(levelPath);
        yield return SceneManager.LoadSceneAsync("Level", LoadSceneMode.Additive);
    }
}

我们截取打包的AB进行分析 level.manifest 依赖关系如下,可以看到Level 依赖的是data.spring 这个AB

Assets:
- Assets/Level.unity
Dependencies:
- C:/Users/Admin/Desktop/Unity-AssetBundleVariantsExample-master/Build/data.spring

当我们切换到其他枚举去加载的时候同样可以很正确的加载到资源,那么引擎是怎么能找到这个正确的Data.Fall  或者 Data.Summer 的AB的呢?** 答案是变体的内部唯一值是相同的 ** 
Unity 变体探秘

所以在我们加载的时候就能正确找到对应的资源了

 

 

 

 

 

 

 

 

 

 

上一篇:python内置函数:enumerate()


下一篇:【CF453C】Little Pony and Summer Sun Celebration