/// <summary>
        /// write manifest into target path.
        /// </summary>
        static void WriteManifestFile(string path, IBundleBuildResults bundleResults, BuildTarget target, string remoteURL)
        {
            var manifest = new AssetbundleBuildManifest();

            manifest.BuildTarget = target.ToString();

            //we use unity provided dependency result for final check
            var deps = bundleResults.BundleInfos.ToDictionary(kv => kv.Key, kv => kv.Value.Dependencies.ToList());

            foreach (var result in bundleResults.BundleInfos)
            {
                var bundleInfo = new AssetbundleBuildManifest.BundleInfo();
                bundleInfo.BundleName   = result.Key;
                bundleInfo.Dependencies = Utility.CollectBundleDependencies(deps, result.Key);
                bundleInfo.Hash         = result.Value.Hash;
                bundleInfo.Size         = new FileInfo(result.Value.FileName).Length;
                manifest.BundleInfos.Add(bundleInfo);
            }

            //sort by size
            manifest.BundleInfos.Sort((a, b) => b.Size.CompareTo(a.Size));
            var manifestString = JsonUtility.ToJson(manifest);

            manifest.GlobalHash = Hash128.Compute(manifestString);
            manifest.BuildTime  = DateTime.UtcNow.Ticks;
            manifest.RemoteURL  = remoteURL;
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            File.WriteAllText(Utility.CombinePath(path, AssetbundleBuildSettings.ManifestFileName), JsonUtility.ToJson(manifest, true));
        }
Example #2
0
        /// <summary>
        /// acutally download assetbundles load from cache if cached
        /// </summary>
        /// <param name="manifest">manifest you get from GetManifest() function</param>
        /// <param name="subsetNames">names that you interested among full bundle list(optional)</param>
        public static BundleAsyncOperation <bool> DownloadAssetBundles(AssetbundleBuildManifest manifest, IEnumerable <string> subsetNames = null)
        {
            var result = new BundleAsyncOperation <bool>();

            s_Helper.StartCoroutine(CoDownloadAssetBundles(manifest, subsetNames, result));
            return(result);
        }
        /// <summary>
        /// acutally download assetbundles load from cache if cached
        /// </summary>
        /// <param name="hardUnload">hard unload reloaded bundle</param>
        /// <returns>returns bundle has been reloaded</returns>
        public static BundleAsyncOperation <bool> DownloadAssetBundles(AssetbundleBuildManifest manifest, bool hardUnload = false)
        {
            var result = new BundleAsyncOperation <bool>();

            s_Helper.StartCoroutine(CoDownloadAssetBundles(manifest, hardUnload, result));
            return(result);
        }
        /// <summary>
        /// get last cached manifest, to support offline play
        /// </summary>
        /// <returns></returns>
        public static bool TryGetCachedManifest(out AssetbundleBuildManifest manifest)
        {
            var path = Path.Combine(Application.persistentDataPath, CACHED_MANIFEST_FILE_NAME);
            var cachedManifestJson = string.Empty;

            if (File.Exists(path))
            {
                cachedManifestJson = File.ReadAllText(path);
            }
            return(AssetbundleBuildManifest.TryParse(cachedManifestJson, out manifest));
        }
        static IEnumerator CoGetManifest(BundleAsyncOperation <AssetbundleBuildManifest> result)
        {
            if (!Initialized)
            {
                Debug.LogError("Do Initialize first");
                result.Done(BundleErrorCode.NotInitialized);
                yield break;
            }

#if UNITY_EDITOR
            if (UseAssetDatabase)
            {
                result.Result = new AssetbundleBuildManifest();
                result.Done(BundleErrorCode.Success);
                yield break;
            }
#endif

            var manifestReq = UnityWebRequest.Get(Utility.CombinePath(RemoteURL, AssetbundleBuildSettings.ManifestFileName).Replace('\\', '/'));
            yield return(manifestReq.SendWebRequest());

            if (result.IsCancelled)
            {
                manifestReq.Dispose();
                yield break;
            }

            if (manifestReq.isHttpError || manifestReq.isNetworkError)
            {
                result.Done(BundleErrorCode.NetworkError);
                yield break;
            }

            var remoteManifestJson = manifestReq.downloadHandler.text;
            manifestReq.Dispose();

            if (!AssetbundleBuildManifest.TryParse(remoteManifestJson, out var remoteManifest))
            {
                result.Done(BundleErrorCode.ManifestParseError);
                yield break;
            }

            result.Result = remoteManifest;
            result.Done(BundleErrorCode.Success);
        }
        public static bool TryParse(string json, out AssetbundleBuildManifest manifest)
        {
            if (string.IsNullOrEmpty(json))
            {
                manifest = default;
                return(false);
            }

            try
            {
                manifest = JsonUtility.FromJson <AssetbundleBuildManifest>(json);
                return(true);
            }
            catch
            {
                manifest = default;
                return(false);
            }
        }
        //Get download size of
        public static long GetDownloadSize(AssetbundleBuildManifest manifest)
        {
            if (!Initialized)
            {
                throw new System.Exception("BundleManager is not initialized");
            }

            long totalSize = 0;

            for (int i = 0; i < manifest.BundleInfos.Count; i++)
            {
                var bundleInfo  = manifest.BundleInfos[i];
                var localBundle = s_LocalBundles.TryGetValue(bundleInfo.BundleName, out var localHash) && localHash == bundleInfo.Hash;
                if (!localBundle && !Caching.IsVersionCached(bundleInfo.AsCached))
                {
                    totalSize += bundleInfo.Size;
                }
            }

            return(totalSize);
        }
Example #8
0
        /// <summary>
        /// Get download size of entire bundles(except cached)
        /// </summary>
        /// <param name="manifest">manifest you get from GetManifest() function</param>
        /// <param name="subsetNames">names that you interested among full bundle list(optional)</param>
        /// <returns></returns>
        public static long GetDownloadSize(AssetbundleBuildManifest manifest, IEnumerable <string> subsetNames = null)
        {
            if (!Initialized)
            {
                throw new System.Exception("BundleManager is not initialized");
            }

            long totalSize = 0;

            var bundleInfoList = subsetNames == null ? manifest.BundleInfos : manifest.CollectSubsetBundleInfoes(subsetNames);

            for (int i = 0; i < bundleInfoList.Count; i++)
            {
                var bundleInfo     = bundleInfoList[i];
                var uselocalBundle = s_LocalBundles.TryGetValue(bundleInfo.BundleName, out var localHash) && localHash == bundleInfo.Hash;
                if (!uselocalBundle && !Caching.IsVersionCached(bundleInfo.AsCached))
                {
                    totalSize += bundleInfo.Size;
                }
            }

            return(totalSize);
        }
Example #9
0
        static IEnumerator CoDownloadAssetBundles(AssetbundleBuildManifest manifest, IEnumerable <string> subsetNames, BundleAsyncOperation <bool> result)
        {
            if (!Initialized)
            {
                Debug.LogError("Do Initialize first");
                result.Done(BundleErrorCode.NotInitialized);
                yield break;
            }

#if UNITY_EDITOR
            if (UseAssetDatabase)
            {
                result.Done(BundleErrorCode.Success);
                yield break;
            }
#endif

            var bundlesToUnload    = new HashSet <string>(s_AssetBundles.Keys);
            var downloadBundleList = subsetNames == null ? manifest.BundleInfos : manifest.CollectSubsetBundleInfoes(subsetNames);
            var bundleReplaced     = false; //bundle has been replaced

            result.SetIndexLength(downloadBundleList.Count);

            for (int i = 0; i < downloadBundleList.Count; i++)
            {
                result.SetCurrentIndex(i);
                var bundleInfo = downloadBundleList[i];

                //remove from the set so we can track bundles that should be cleared
                bundlesToUnload.Remove(bundleInfo.BundleName);

                var islocalBundle = s_LocalBundles.TryGetValue(bundleInfo.BundleName, out var localHash) && localHash == bundleInfo.Hash;
                var isCached      = Caching.IsVersionCached(bundleInfo.AsCached);
                result.SetCachedBundle(isCached);

                var loadURL = islocalBundle ? Utility.CombinePath(LocalURL, bundleInfo.BundleName) : Utility.CombinePath(RemoteURL, bundleInfo.BundleName);
                if (LogMessages)
                {
                    Debug.Log($"Loading Bundle Name : {bundleInfo.BundleName}, loadURL {loadURL}, isLocalBundle : {islocalBundle}, isCached {isCached}");
                }
                LoadedBundle previousBundle;

                if (s_AssetBundles.TryGetValue(bundleInfo.BundleName, out previousBundle) && previousBundle.Hash == bundleInfo.Hash)
                {
                    if (LogMessages)
                    {
                        Debug.Log($"Loading Bundle Name : {bundleInfo.BundleName} Complete - load skipped");
                    }
                }
                else
                {
                    var bundleReq = islocalBundle ? UnityWebRequestAssetBundle.GetAssetBundle(loadURL) : UnityWebRequestAssetBundle.GetAssetBundle(loadURL, bundleInfo.AsCached);
                    var operation = bundleReq.SendWebRequest();
                    while (!bundleReq.isDone)
                    {
                        result.SetProgress(operation.progress);
                        yield return(null);
                    }

                    if (bundleReq.isNetworkError || bundleReq.isHttpError)
                    {
                        result.Done(BundleErrorCode.NetworkError);
                        yield break;
                    }

                    if (s_AssetBundles.TryGetValue(bundleInfo.BundleName, out previousBundle))
                    {
                        bundleReplaced = true;
                        previousBundle.Bundle.Unload(false);
                        if (previousBundle.RequestForReload != null)
                        {
                            previousBundle.RequestForReload.Dispose(); //dispose reload bundle
                        }
                        s_AssetBundles.Remove(bundleInfo.BundleName);
                    }

                    var loadedBundle = new LoadedBundle(bundleInfo, loadURL, DownloadHandlerAssetBundle.GetContent(bundleReq), islocalBundle);
                    s_AssetBundles.Add(bundleInfo.BundleName, loadedBundle);
                    CollectSceneNames(loadedBundle);
                    if (LogMessages)
                    {
                        Debug.Log($"Loading Bundle Name : {bundleInfo.BundleName} Complete");
                    }
                    bundleReq.Dispose();
                }
            }

            //let's drop unknown bundles loaded
            foreach (var name in bundlesToUnload)
            {
                var bundleInfo = s_AssetBundles[name];
                bundleInfo.Bundle.Unload(false);
                if (bundleInfo.RequestForReload != null)
                {
                    bundleInfo.RequestForReload.Dispose(); //dispose reload bundle
                }
                s_AssetBundles.Remove(bundleInfo.Name);
            }

            //bump entire bundles' usage timestamp
            //we use manifest directly to find out entire list
            for (int i = 0; i < manifest.BundleInfos.Count; i++)
            {
                var cachedInfo = manifest.BundleInfos[i].AsCached;
                if (Caching.IsVersionCached(cachedInfo))
                {
                    Caching.MarkAsUsed(cachedInfo);
                }
            }

            if (LogMessages)
            {
                Debug.Log($"CacheUsed Before Cleanup : {Caching.defaultCache.spaceOccupied} bytes");
            }
            Caching.ClearCache(600); //as we bumped entire list right before clear, let it be just 600
            if (LogMessages)
            {
                Debug.Log($"CacheUsed After CleanUp : {Caching.defaultCache.spaceOccupied} bytes");
            }

            PlayerPrefs.SetString("CachedManifest", JsonUtility.ToJson(manifest));
            GlobalBundleHash = manifest.GlobalHash.ToString();
            result.Result    = bundleReplaced;
            result.Done(BundleErrorCode.Success);
        }
Example #10
0
 /// <summary>
 /// get last cached manifest, to support offline play
 /// </summary>
 /// <returns></returns>
 public static bool TryGetCachedManifest(out AssetbundleBuildManifest manifest)
 {
     return(AssetbundleBuildManifest.TryParse(PlayerPrefs.GetString("CachedManifest", string.Empty), out manifest));
 }
Example #11
0
        static IEnumerator CoInitalizeLocalBundles(BundleAsyncOperation result, bool autoReloadBundle)
        {
            if (Initialized)
            {
                result.Done(BundleErrorCode.Success);
                yield break;
            }

            AutoReloadBundle = autoReloadBundle;

            if (LogMessages)
            {
                Debug.Log($"LocalURL : {LocalURL}");
            }

            foreach (var kv in s_AssetBundles)
            {
                kv.Value.Bundle.Unload(false);
            }
            s_SceneNames.Clear();
            s_AssetBundles.Clear();
            s_LocalBundles.Clear();

            var manifestReq = UnityWebRequest.Get(Utility.CombinePath(LocalURL, AssetbundleBuildSettings.ManifestFileName));

            yield return(manifestReq.SendWebRequest());

            if (manifestReq.isHttpError || manifestReq.isNetworkError)
            {
                result.Done(BundleErrorCode.NetworkError);
                yield break;
            }

            if (!AssetbundleBuildManifest.TryParse(manifestReq.downloadHandler.text, out var localManifest))
            {
                result.Done(BundleErrorCode.ManifestParseError);
                yield break;
            }

            //cached version is recent one.
            var cacheIsValid = AssetbundleBuildManifest.TryParse(PlayerPrefs.GetString("CachedManifest", string.Empty), out var cachedManifest) &&
                               cachedManifest.BuildTime > localManifest.BuildTime;

            result.SetIndexLength(localManifest.BundleInfos.Count);
            for (int i = 0; i < localManifest.BundleInfos.Count; i++)
            {
                result.SetCurrentIndex(i);
                result.SetCachedBundle(true);
                AssetbundleBuildManifest.BundleInfo bundleInfoToLoad;
                AssetbundleBuildManifest.BundleInfo cachedBundleInfo = default;
                var localBundleInfo = localManifest.BundleInfos[i];

                bool useLocalBundle =
                    !cacheIsValid ||                                                                      //cache is not valid or...
                    !cachedManifest.TryGetBundleInfo(localBundleInfo.BundleName, out cachedBundleInfo) || //missing bundle or...
                    !Caching.IsVersionCached(cachedBundleInfo.AsCached);                                  //is not cached no unusable.

                bundleInfoToLoad = useLocalBundle ? localBundleInfo : cachedBundleInfo;
                var loadPath = Utility.CombinePath(LocalURL, bundleInfoToLoad.BundleName);

                var bundleReq = UnityWebRequestAssetBundle.GetAssetBundle(loadPath, bundleInfoToLoad.Hash);
                var bundleOp  = bundleReq.SendWebRequest();
                while (!bundleOp.isDone)
                {
                    result.SetProgress(bundleOp.progress);
                    yield return(null);
                }

                if (!bundleReq.isHttpError && !bundleReq.isNetworkError)
                {
                    var loadedBundle = new LoadedBundle(bundleInfoToLoad, loadPath, DownloadHandlerAssetBundle.GetContent(bundleReq), useLocalBundle);
                    s_AssetBundles.Add(localBundleInfo.BundleName, loadedBundle);
                    CollectSceneNames(loadedBundle);

                    if (LogMessages)
                    {
                        Debug.Log($"Local bundle Loaded - Name : {localBundleInfo.BundleName}, Hash : {bundleInfoToLoad.Hash }");
                    }
                }
                else
                {
                    result.Done(BundleErrorCode.NetworkError);
                    yield break;
                }

                bundleReq.Dispose();
                s_LocalBundles.Add(localBundleInfo.BundleName, localBundleInfo.Hash);
            }

            RemoteURL = Utility.CombinePath(localManifest.RemoteURL, localManifest.BuildTarget);
#if UNITY_EDITOR
            if (s_EditorBuildSettings.EmulateWithoutRemoteURL)
            {
                RemoteURL = "file://" + Utility.CombinePath(s_EditorBuildSettings.RemoteOutputPath, UnityEditor.EditorUserBuildSettings.activeBuildTarget.ToString());
            }
#endif
            Initialized = true;
            if (LogMessages)
            {
                Debug.Log($"Initialize Success \nRemote URL : {RemoteURL} \nLocal URL : {LocalURL}");
            }
            result.Done(BundleErrorCode.Success);
        }
        static IEnumerator CoDownloadAssetBundles(AssetbundleBuildManifest remoteManifest, bool hardUnload, BundleAsyncOperation <bool> result)
        {
            if (!Initialized)
            {
                Debug.LogError("Do Initialize first");
                result.Done(BundleErrorCode.NotInitialized);
                yield break;
            }

            if (UseAssetDatabase)
            {
                result.Done(BundleErrorCode.Success);
                yield break;
            }

            var startTime = Time.realtimeSinceStartup;

            result.SetIndexLength(remoteManifest.BundleInfos.Count);
            bool bundleReplaced = false; //bundle has been replaced

            for (int i = 0; i < remoteManifest.BundleInfos.Count; i++)
            {
                result.SetCurrentIndex(i);
                var bundleInfo  = remoteManifest.BundleInfos[i];
                var localBundle = s_LocalBundles.TryGetValue(bundleInfo.BundleName, out var localHash) && localHash == bundleInfo.Hash;
                var isCached    = Caching.IsVersionCached(bundleInfo.AsCached);
                result.SetCachedBundle(isCached);

                var loadURL = localBundle ? Path.Combine(LocalURL, bundleInfo.BundleName) : Path.Combine(RemoteURL, bundleInfo.BundleName);
                if (LogMessages)
                {
                    Debug.Log($"Loading Bundle Name : {bundleInfo.BundleName}, loadURL {loadURL}, isLocalBundle : {localBundle}, isCached {isCached}");
                }
                LoadedBundle previousBundle;

                if (s_AssetBundles.TryGetValue(bundleInfo.BundleName, out previousBundle) && previousBundle.Hash == bundleInfo.Hash)
                {
                    if (LogMessages)
                    {
                        Debug.Log($"Loading Bundle Name : {bundleInfo.BundleName} Complete - load skipped");
                    }
                }
                else
                {
                    var bundleReq = localBundle ? UnityWebRequestAssetBundle.GetAssetBundle(loadURL) : UnityWebRequestAssetBundle.GetAssetBundle(loadURL, bundleInfo.AsCached);
                    var operation = bundleReq.SendWebRequest();
                    while (!bundleReq.isDone)
                    {
                        result.SetProgress(operation.progress);
                        yield return(null);
                    }

                    if (bundleReq.isNetworkError || bundleReq.isHttpError)
                    {
                        result.Done(BundleErrorCode.NetworkError);
                        yield break;
                    }

                    if (s_AssetBundles.TryGetValue(bundleInfo.BundleName, out previousBundle))
                    {
                        bundleReplaced = true;
                        previousBundle.Bundle.Unload(hardUnload);
                        if (previousBundle.RequestForReload != null)
                        {
                            previousBundle.RequestForReload.Dispose(); //dispose reload bundle
                        }
                        s_AssetBundles.Remove(bundleInfo.BundleName);
                    }

                    var loadedBundle = new LoadedBundle(bundleInfo, loadURL, DownloadHandlerAssetBundle.GetContent(bundleReq), localBundle);
                    s_AssetBundles.Add(bundleInfo.BundleName, loadedBundle);
                    CollectSceneNames(loadedBundle);
                    if (LogMessages)
                    {
                        Debug.Log($"Loading Bundle Name : {bundleInfo.BundleName} Complete");
                    }
                    bundleReq.Dispose();
                }

                Caching.MarkAsUsed(bundleInfo.AsCached);
            }

            var timeTook = Time.realtimeSinceStartup - startTime;

            if (LogMessages)
            {
                Debug.Log($"CacheUsed Before Cleanup : {Caching.defaultCache.spaceOccupied} bytes");
            }
            Caching.ClearCache((int)timeTook + 600);
            if (LogMessages)
            {
                Debug.Log($"CacheUsed After CleanUp : {Caching.defaultCache.spaceOccupied} bytes");
            }

            PlayerPrefs.SetString("CachedManifest", JsonUtility.ToJson(remoteManifest));
            GlobalBundleHash = remoteManifest.GlobalHash.ToString();
            result.Result    = bundleReplaced;
            result.Done(BundleErrorCode.Success);
        }