// Load asset from the given assetBundle.
        public static ITask <T> LoadAssetAsync <T>(string assetBundleName, string assetName) where T : Object
        {
            log.Info("Loading {0} from {1} bundle...", assetName, assetBundleName);

#if UNITY_EDITOR
            if (SimulateAssetBundleInEditor)
            {
                string[] assetPaths = AssetDatabase.GetAssetPathsFromAssetBundleAndAssetName(assetBundleName, assetName);
                if (assetPaths.Length != 0)
                {
                    return(Task.FromResult(AssetDatabase.LoadAssetAtPath <T>(assetPaths[0])));
                }
                var message = "There is no asset with name \"{0}\" in {1}".With(assetName, assetBundleName);
                log.Error(message);
                return(Task.FromError <T>(new Exception(message)));
            }
#endif
            ITask <LoadedAssetBundle> task;
            if (typeof(T) == typeof(AssetBundleManifest))
            {
                task = LoadAssetBundleInternal(assetBundleName, true);
            }
            else
            {
                task = RemapVariantName(assetBundleName).Then(bundleName => LoadAssetBundleAsync(bundleName));
            }
            var assetTask = task.Then(bundle => AsyncManager.AddOperation(bundle.AssetBundle.LoadAssetAsync <T>(assetName)));
            assetTask.Then(() => log.Info("Loaded {0} from {1}", assetName, assetBundleName));
            return(assetTask.Then(request => request.asset as T));
        }
        // Load level from the given assetBundle.
        public static ITask LoadLevelAsync(string assetBundleName, string levelName, LoadSceneMode loadMode = LoadSceneMode.Single)
        {
            log.Info("Loading {0} from {1} bundle...", levelName, assetBundleName);

#if UNITY_EDITOR
            if (SimulateAssetBundleInEditor)
            {
                string[] levelPaths = AssetDatabase.GetAssetPathsFromAssetBundleAndAssetName(assetBundleName, levelName);
                if (levelPaths.Length == 0)
                {
                    //TODO: The error needs to differentiate that an asset bundle name doesn't exist from that there right scene does not exist in the asset bundle...
                    return(Task.FromError(new Exception("There is no scene with name \"" + levelName + "\" in " + assetBundleName)));
                }
                return(AsyncManager.AddOperation(SceneManager.LoadSceneAsync(levelPaths[0], loadMode)));
            }
#endif
            return(RemapVariantName(assetBundleName)
                   .Then(bundleName => LoadAssetBundleAsync(bundleName))
                   .Then(bundle => AsyncManager.AddOperation(SceneManager.LoadSceneAsync(levelName, loadMode))));
        }
        // Where we actually load the assetbundles from the local disk.
        static ITask <LoadedAssetBundle> LoadAssetBundleInternal(string assetBundleName, bool isManifest)
        {
            // Already loaded.
            var name = SeperatorRegex.Replace(assetBundleName, "/");
            ITask <LoadedAssetBundle> bundle;

            if (AssetBundles.TryGetValue(name, out bundle))
            {
                bundle.Then(b => b.ReferencedCount++);
                return(bundle);
            }

            ITask <string> pathTask;

            if (isManifest)
            {
                pathTask = Task.FromResult(BundleUtility.GetLocalBundlePath(name));
            }
            else
            {
                pathTask = Manifest.Then(manfiest => {
                    if (manfiest == null)
                    {
                        return(null);
                    }
                    foreach (var path in manfiest[name].Paths)
                    {
                        var fullPath = BundleUtility.GetLocalBundlePath(path);
                        if (File.Exists(fullPath))
                        {
                            return(fullPath);
                        }
                    }
                    throw new FileNotFoundException("No valid path for asset bundle {0} could be found.".With(name));
                });
            }
            // For manifest assetbundle, always download it as we don't have hash for it.
            var task = pathTask.Then(path => {
                var operation = AssetBundle.LoadFromFileAsync(path);
                return(AsyncManager.AddOperation(operation).Then(request => {
                    var assetBundle = request.assetBundle;
                    if (assetBundle == null)
                    {
                        throw new Exception("{0} is not a valid asset bundle.".With(name));
                    }
                    LoadedAssetBundle loadedBundle;
                    if (isManifest)
                    {
                        loadedBundle = new LoadedAssetBundle(
                            new BundleMetadata(assetBundleName,
                                               new Hash128(),
                                               Enumerable.Empty <BundleMetadata>(),
                                               Enumerable.Empty <string>()),
                            assetBundle);
                    }
                    else
                    {
                        loadedBundle = new LoadedAssetBundle(Manifest.Result[name], assetBundle);
                    }
                    log.Info("Loaded bundle \"{0}\" from {1}.", name, path);
                    return loadedBundle;
                }));
            });

            AssetBundles.Add(name, task);
            return(task);
        }