Home > front end >  Instantiate game object loaded from assetbundle lost animation clip
Instantiate game object loaded from assetbundle lost animation clip

Time:02-01

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

CodePudding user response:

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

AssetBundleCreateRequest ab = AssetBundle.LoadFromFileAsync(path);

within the for loop etc.

And then within in your SingleDpsABLoadyou do not wait for the

ab = AssetBundle.LoadFromFileAsync(....);

to actually finish! You just continue to immediately set

dc.finihed = true

so you might just be lucky that sometimes the rest of the redundant

yield return 0;

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

IEnumerator SingleDpsABLoad(DpsContainer dpsContainer)
{
    var path = Path.Combine(Application.streamingAssetsPath, dpsContainer.abName);

    if (!File.Exists(path))
    {
        Debug.LogError("Can't find path:"   path);
        yield break;
    }

    var ab = AssetBundle.LoadFromFileAsync(path);  

    // actually wait until the async operation is done
    yield return ab;

    // can also make that one async
    yield return ab.assetBundle.LoadAllAssetsAsync();

    dpsContainer.AB = ab.assetBundle;
    dpsContainer.finishLoad = true;
}

IEnumerator SingleTempGOABLoad(string abName)
{
    Debug.Log(" 1 SingleTempGOABLoad :"   abName);

    // personally I would start with that check here already
    var path = Path.Combine(Application.streamingAssetsPath, abName);

    if (!File.Exists(path))
    {
        Debug.Log("Can't find path:"   path);
        yield break;
    }
    
    if (TempABGO_Dict.ContainsKey(abName)) yield break;

    var allDps = mainManifest.GetAllDependencies(abName);
         
    foreach (var dps in allDps)
    {
        if (TempDPSAB_Dict.TryGetValue(dps, out var dpsContainer))
        {
            dpsContainer.refCount  ;
        }
        else
        {
            dpsContainer = new DpsContainer(null, dps);
            
            TempDPSAB_Dict[dps] = dpsContainer;
            StartCoroutine(SingleDpsABLoad(dps));
        }
    }
    
    // using System.Linq
    yield return new WaitUntil(() => TempDPSAB_Dict.All(kvp => kvp.Value.finishLoad));
   

    var ab = AssetBundle.LoadFromFileAsync(path);
    yield return ab;

    var abReq = ab.assetBundle.LoadAllAssetsAsync<GameObject>();
    yield return abReq;

    var go = (GameObject)abReq.asset;
   
    TempABGO_Dict[abName] = new TempPrefabABPair(ab.assetBundle, go, allDps));
}
  • Related