I Had all my Npc's prefab packed into assetbundle with all dependencies,but when I finished loading all dependencies of one npc and instantiate it into scene, some times the animation clip on it can't be played. I print animator.GetCurrentAnimatorClipInfo(0).Length and I found it is 0.So it seems that I had lost all animation clip of this animator. The funny thing is that it doesn't happed on all npc,and I can't find any differences between them.
I used following codes to attached assetbundle name to all assets.
private void SelectionAndAssetsListChange()
{
EditorUtility.ClearProgressBar();
selection = Selection.objects;
//assets = new AssetImporter[selection.Length];
if (selection.Length > 0)
{
for (int i = 0; i < selection.Length; i++)
{
string assetPath = AssetDatabase.GetAssetPath(selection[i]);
string[] dps = AssetDatabase.GetDependencies(assetPath);
int length = dps.Length;
int index = 0;
foreach (var dp in dps)
{
if (EditorUtility.DisplayCancelableProgressBar("Changing Assets's ab name ", "Changing No." + index + "/" + length, (float)index / length))
{
EditorUtility.ClearProgressBar();
return;
}
if (dp.EndsWith(".cs"))
continue;
AssetImporter dpAsset = AssetImporter.GetAtPath(dp);
string assetNameDPs = dp.Substring("Assets".Length + 1);
assetNameDPs = assetNameDPs.Replace(Path.GetExtension(assetNameDPs), ".data");
assetNameDPs = Path.Combine("assetbundle", assetNameDPs);
assetNameDPs = assetNameDPs.Replace("\\", "/");
dpAsset.assetBundleName = assetNameDPs;
index++;
}
EditorUtility.ClearProgressBar();
}
}
}
Following Codes are used to load assetbundle ,i used 2 dictionaries TempABGO_Dict and TempDPSAB_Dict to make sure make sure it doesn't double load.
IEnumerator SingleTempGOABLoad(string abName)
{
string path = Application.streamingAssetsPath + "/" + abName;
if (!File.Exists(path))
{
Debug.Log("Can't find path:" + path);
yield break;
}
Debug.Log(" 1 SingleTempGOABLoad :" + abName);
if (TempABGO_Dict.ContainsKey(abName))
yield break;
string[] allDps = mainManifest.GetAllDependencies(abName);
for (int i = 0; i < allDps.Length; i++)
if (TempDPSAB_Dict.ContainsKey(allDps[i]))
{
TempDPSAB_Dict[allDps[i]].refCount++;
}
else
{
DpsContainer dc = new DpsContainer(null, allDps[i]);
TempDPSAB_Dict[allDps[i]] = dc;
StartCoroutine(SingleDpsABLoad(allDps[i]));
yield return 0;
}
for (int i = 0; i < allDps.Length; i++)
yield return new WaitUntil(() => TempDPSAB_Dict[allDps[i]].finishLoad);
yield return 0;
AssetBundleCreateRequest ab = AssetBundle.LoadFromFileAsync(path);
yield return ab;
GameObject go = null;
AssetBundleRequest abReq = ab.assetBundle.LoadAllAssetsAsync<GameObject>();
yield return abReq;
go = (GameObject)abReq.asset;
TempABGO_Dict[abName] = new TempPrefabABPair(ab.assetBundle, go, allDps);
}
IEnumerator SingleDpsABLoad(string abName)
{
DpsContainer dc = TempDPSAB_Dict[abName];
AssetBundleCreateRequest ab = null;
ab = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + abName);
yield return ab;
dc.AB = ab.assetBundle;
AssetBundleRequest rq = ab.assetBundle.LoadAllAssetsAsync();
yield return rq;
dc.finishLoad = true;
}
This is what I used to build BuildAssetBundles.
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, compressMode, EditorUserBuildSettings.activeBuildTarget);
First more a general note, you can use
yield return null;
and you can also probably reduce the amount of those a lot e.g. before and after
within the
forloop etc.And then within in your
SingleDpsABLoadyou do not wait for theto actually finish! You just continue to immediately set
so you might just be lucky that sometimes the rest of the redundant
in the for loop etc are just delay enough to actually manage to load it in time ^^
So you probably could rather do something like