/// <summary>
        /// 修复客户端
        /// </summary>
        public void FixClient()
        {
            // 清空缓存
            PatchHelper.ClearSandbox();

            // 重启游戏
#if UNITY_EDITOR
            UnityEditor.EditorApplication.isPlaying = false;
#else
            Application.Quit();
#endif
        }
예제 #2
0
        /// <summary>
        /// 读取缓存文件
        /// </summary>
        public static PatchCache LoadCache()
        {
            if (PatchHelper.CheckSandboxCacheFileExist() == false)
            {
                return(new PatchCache());
            }

            MotionLog.Log("Load cache from disk.");
            string filePath = PatchHelper.GetSandboxCacheFilePath();
            string jsonData = FileUtility.ReadFile(filePath);

            return(JsonUtility.FromJson <PatchCache>(jsonData));
        }
        public IEnumerator Download()
        {
            // 获取最新的游戏版本号
            {
                string url  = _patcher.GetWebServerIP();
                string post = _patcher.GetWebPostData();
                PatchHelper.Log(ELogLevel.Log, $"Request game version : {url} : {post}");
                WebPostRequest download = new WebPostRequest(url, post);
                yield return(download.DownLoad());

                //Check fatal
                if (download.States != EWebRequestStates.Success)
                {
                    download.Dispose();
                    PatchEventDispatcher.SendGameVersionRequestFailedMsg();
                    yield break;
                }

                string responseData = download.GetResponse();
                _patcher.ParseResponseData(responseData);
                download.Dispose();
            }

            int newResourceVersion = _patcher.RequestedResourceVersion;
            int oldResourceVersion = _patcher.SandboxPatchManifest.Version;

            // 检测强更安装包
            string appInstallURL = _patcher.GetForceInstallAppURL();

            if (string.IsNullOrEmpty(appInstallURL) == false)
            {
                PatchHelper.Log(ELogLevel.Log, $"Found new APP can be install : {_patcher.GameVersion.ToString()}");
                PatchEventDispatcher.SendFoundForceInstallAPPMsg(_patcher.GameVersion.ToString(), appInstallURL);
                yield break;
            }

            // 检测资源版本是否变化
            if (newResourceVersion == oldResourceVersion)
            {
                PatchHelper.Log(ELogLevel.Log, $"Resource version is not change.");
                _patcher.Switch(EPatchStates.DownloadOver.ToString());
            }
            else
            {
                PatchHelper.Log(ELogLevel.Log, $"Resource version is change : {oldResourceVersion} -> {newResourceVersion}");
                _patcher.SwitchNext();
            }
        }
예제 #4
0
        private WebFileRequest CreateDownloader(PatchBundle element)
        {
            // 注意:资源版本号只用于确定下载路径
            string url      = _patcher.GetWebDownloadURL(element.Version.ToString(), element.Hash);
            string savePath = PatchHelper.MakeSandboxCacheFilePath(element.Hash);

            FileUtility.CreateFileDirectory(savePath);

            // 创建下载器
            MotionLog.Log($"Beginning to download web file : {url}");
            WebFileRequest download = new WebFileRequest(url, savePath);

            download.UserData = element;
            download.DownLoad();
            return(download);
        }
예제 #5
0
        private WebFileRequest CreateDownloader(PatchBundle patchBundle)
        {
            // 注意:资源版本号只用于确定下载路径
            string mainURL     = _patcherMgr.GetPatchDownloadURL(patchBundle.Version, patchBundle.Hash);
            string fallbackURL = _patcherMgr.GetPatchDownloadFallbackURL(patchBundle.Version, patchBundle.Hash);
            string savePath    = PatchHelper.MakeSandboxCacheFilePath(patchBundle.Hash);

            FileUtility.CreateFileDirectory(savePath);

            // 创建下载器
            MotionLog.Log($"Beginning to download web file : {patchBundle.BundleName} URL : {mainURL}");
            WebFileRequest download = WebFileSystem.GetWebFileRequest(mainURL, fallbackURL, savePath, _failedTryAgain);

            download.UserData = patchBundle;
            return(download);
        }
        void IFsmNode.OnEnter()
        {
            PatchEventDispatcher.SendPatchStatesChangeMsg(EPatchStates.ParseSandboxPatchManifest);

            // 读取并解析沙盒内的补丁清单
            if (PatchHelper.CheckSandboxPatchManifestFileExist())
            {
                string filePath    = AssetPathHelper.MakePersistentLoadPath(PatchDefine.PatchManifestFileName);
                string fileContent = PatchHelper.ReadFile(filePath);

                PatchHelper.Log(ELogLevel.Log, $"Parse sandbox patch file.");
                _patcher.ParseSandboxPatchManifest(fileContent);
            }
            else
            {
                _patcher.ParseSandboxPatchManifest(_patcher.AppPatchManifest);
            }

            _patcher.SwitchNext();
        }
        private IEnumerator DownLoad()
        {
            // 解析APP里的补丁清单
            string         filePath   = AssetPathHelper.MakeStreamingLoadPath(PatchDefine.PatchManifestFileName);
            string         url        = AssetPathHelper.ConvertToWWWPath(filePath);
            WebDataRequest downloader = new WebDataRequest(url);

            yield return(downloader.DownLoad());

            if (downloader.States == EWebRequestStates.Success)
            {
                PatchHelper.Log(ELogLevel.Log, "Parse app patch manifest.");
                _patcher.ParseAppPatchManifest(downloader.GetText());
                downloader.Dispose();
                _patcher.SwitchNext();
            }
            else
            {
                throw new System.Exception($"Fatal error : Failed download file : {url}");
            }
        }
예제 #8
0
        private bool CheckContentIntegrity(string md5, uint crc32, long size)
        {
            string filePath = PatchHelper.MakeSandboxCacheFilePath(md5);

            if (File.Exists(filePath) == false)
            {
                return(false);
            }

            // 校验沙盒里的补丁文件
            if (_verifyLevel == EVerifyLevel.Size)
            {
                long fileSize = FileUtility.GetFileSize(filePath);
                if (fileSize == size)
                {
                    return(true);
                }
            }
            else if (_verifyLevel == EVerifyLevel.MD5)
            {
                string fileHash = HashUtility.FileMD5(filePath);
                if (fileHash == md5)
                {
                    return(true);
                }
            }
            else if (_verifyLevel == EVerifyLevel.CRC32)
            {
                uint fileHash = HashUtility.FileCRC32(filePath);
                if (fileHash == crc32)
                {
                    return(true);
                }
            }
            else
            {
                throw new NotImplementedException(_verifyLevel.ToString());
            }
            return(false);
        }
        string IBundleServices.GetAssetBundleLoadPath(string manifestPath)
        {
            PatchManifest patchManifest;

            if (_patcher.WebPatchManifest != null)
            {
                patchManifest = _patcher.WebPatchManifest;
            }
            else
            {
                patchManifest = _patcher.SandboxPatchManifest;
            }

            // 尝试获取变体资源清单路径
            manifestPath = _variantCollector.TryGetVariantManifestPath(manifestPath);

            // 注意:可能从APP内加载,也可能从沙盒内加载
            PatchElement element;

            if (patchManifest.Elements.TryGetValue(manifestPath, out element))
            {
                // 先查询APP内的资源
                PatchElement appElement;
                if (_patcher.AppPatchManifest.Elements.TryGetValue(manifestPath, out appElement))
                {
                    if (appElement.MD5 == element.MD5)
                    {
                        return(AssetPathHelper.MakeStreamingLoadPath(manifestPath));
                    }
                }

                // 如果APP里不存在或者MD5不匹配,则从沙盒里加载
                return(AssetPathHelper.MakePersistentLoadPath(manifestPath));
            }
            else
            {
                PatchHelper.Log(ELogLevel.Warning, $"Not found element in patch manifest : {manifestPath}");
                return(AssetPathHelper.MakeStreamingLoadPath(manifestPath));
            }
        }
        private IEnumerator Download()
        {
            // 从网络上解析最新的补丁清单
            int            newResourceVersion = _patcher.RequestedResourceVersion;
            string         url      = _patcher.GetWebDownloadURL(newResourceVersion.ToString(), PatchDefine.PatchManifestFileName);
            WebDataRequest download = new WebDataRequest(url);

            yield return(download.DownLoad());

            // Check fatal
            if (download.States != EWebRequestStates.Success)
            {
                download.Dispose();
                PatchEventDispatcher.SendWebPatchManifestDownloadFailedMsg();
                yield break;
            }

            PatchHelper.Log(ELogLevel.Log, $"Parse web patch manifest.");
            _patcher.ParseWebPatchManifest(download.GetText());
            download.Dispose();
            _patcher.SwitchNext();
        }
예제 #11
0
        /// <summary>
        /// 获取AssetBundle的加载信息
        /// </summary>
        public AssetBundleInfo GetAssetBundleInfo(string bundleName)
        {
            if (_localPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle patchBundle))
            {
                // 查询APP资源
                if (_appPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle appPatchBundle))
                {
                    if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash)
                    {
                        string          appLoadPath = AssetPathHelper.MakeStreamingLoadPath(appPatchBundle.Hash);
                        AssetBundleInfo bundleInfo  = new AssetBundleInfo(bundleName, appLoadPath, appPatchBundle.Version, appPatchBundle.IsEncrypted);
                        return(bundleInfo);
                    }
                }

                // 查询缓存资源
                // 注意:如果沙盒内缓存文件不存在,那么将会从服务器下载
                string sandboxLoadPath = PatchHelper.MakeSandboxCacheFilePath(patchBundle.Hash);
                if (_cache.Contains(patchBundle.Hash))
                {
                    AssetBundleInfo bundleInfo = new AssetBundleInfo(bundleName, sandboxLoadPath, patchBundle.Version, patchBundle.IsEncrypted);
                    return(bundleInfo);
                }
                else
                {
                    string          remoteURL         = GetPatchDownloadURL(patchBundle.Version, patchBundle.Hash);
                    string          remoteFallbackURL = GetPatchDownloadFallbackURL(patchBundle.Version, patchBundle.Hash);
                    AssetBundleInfo bundleInfo        = new AssetBundleInfo(bundleName, sandboxLoadPath, remoteURL, remoteFallbackURL, patchBundle.Version, patchBundle.IsEncrypted);
                    return(bundleInfo);
                }
            }
            else
            {
                MotionLog.Warning($"Not found bundle in patch manifest : {bundleName}");
                AssetBundleInfo bundleInfo = new AssetBundleInfo(bundleName, string.Empty);
                return(bundleInfo);
            }
        }
        private IEnumerator Download()
        {
            // 注意:等所有文件下载完毕后,下载并替换补丁清单
            int            newResourceVersion = _patcher.RequestedResourceVersion;
            string         url      = _patcher.GetWebDownloadURL(newResourceVersion.ToString(), PatchDefine.PatchManifestFileName);
            string         savePath = AssetPathHelper.MakePersistentLoadPath(PatchDefine.PatchManifestFileName);
            WebFileRequest download = new WebFileRequest(url, savePath);

            yield return(download.DownLoad());

            if (download.States != EWebRequestStates.Success)
            {
                download.Dispose();
                PatchEventDispatcher.SendWebPatchManifestDownloadFailedMsg();
                yield break;
            }
            else
            {
                PatchHelper.Log(ELogLevel.Log, "Web patch manifest is download.");
                download.Dispose();
                _patcher.SwitchNext();
            }
        }
예제 #13
0
        /// <summary>
        /// 获取AssetBundle的加载信息
        /// </summary>
        public AssetBundleInfo GetAssetBundleInfo(string bundleName)
        {
            if (_localPatchManifest.Elements.TryGetValue(bundleName, out PatchElement element))
            {
                // 查询内置资源
                if (_appPatchManifest.Elements.TryGetValue(bundleName, out PatchElement appElement))
                {
                    if (appElement.IsDLC() == false && appElement.MD5 == element.MD5)
                    {
                        string          appLoadPath = AssetPathHelper.MakeStreamingLoadPath(appElement.MD5);
                        AssetBundleInfo bundleInfo  = new AssetBundleInfo(bundleName, appLoadPath, string.Empty, appElement.Version, appElement.IsEncrypted);
                        return(bundleInfo);
                    }
                }

                // 查询缓存资源
                // 注意:如果沙盒内缓存文件不存在,那么将会从服务器下载
                string sandboxLoadPath = PatchHelper.MakeSandboxCacheFilePath(element.MD5);
                if (_cache.Contains(element.MD5))
                {
                    AssetBundleInfo bundleInfo = new AssetBundleInfo(bundleName, sandboxLoadPath, string.Empty, element.Version, element.IsEncrypted);
                    return(bundleInfo);
                }
                else
                {
                    string          remoteURL  = GetWebDownloadURL(element.Version.ToString(), element.MD5);
                    AssetBundleInfo bundleInfo = new AssetBundleInfo(bundleName, sandboxLoadPath, remoteURL, element.Version, element.IsEncrypted);
                    return(bundleInfo);
                }
            }
            else
            {
                MotionLog.Warning($"Not found element in patch manifest : {bundleName}");
                AssetBundleInfo bundleInfo = new AssetBundleInfo(bundleName, string.Empty);
                return(bundleInfo);
            }
        }
예제 #14
0
        /// <summary>
        /// 异步初始化
        /// </summary>
        public IEnumerator InitializeAync(PatchManagerImpl patcher)
        {
            // 处理沙盒被污染
            ProcessSandboxDirty();

            // 分析APP内的补丁清单
            {
                string         filePath   = AssetPathHelper.MakeStreamingLoadPath(PatchDefine.PatchManifestBytesFileName);
                string         url        = AssetPathHelper.ConvertToWWWPath(filePath);
                WebDataRequest downloader = new WebDataRequest(url);
                yield return(downloader.DownLoad());

                if (downloader.States == EWebRequestStates.Success)
                {
                    MotionLog.Log("Parse app patch manifest.");
                    patcher.ParseAppPatchManifest(downloader.GetData());
                    downloader.Dispose();
                }
                else
                {
                    throw new System.Exception($"Fatal error : Failed download file : {url}");
                }
            }

            // 分析沙盒内的补丁清单
            if (PatchHelper.CheckSandboxPatchManifestFileExist())
            {
                string filePath = AssetPathHelper.MakePersistentLoadPath(PatchDefine.PatchManifestBytesFileName);
                byte[] fileData = File.ReadAllBytes(filePath);
                MotionLog.Log($"Parse sandbox patch file.");
                patcher.ParseSandboxPatchManifest(fileData);
            }
            else
            {
                patcher.ParseSandboxPatchManifest(patcher.AppPatchManifest);
            }
        }
예제 #15
0
        /// <summary>
        /// 异步初始化
        /// </summary>
        public IEnumerator InitializeAsync()
        {
            MotionLog.Log($"Beginning to initialize patch manager.");

            // 加载缓存
            _cache = PatchCache.LoadCache();

            // 检测沙盒被污染
            // 注意:在覆盖安装的时候,会保留沙盒目录里的文件,所以需要强制清空
            {
                // 如果是首次打开,记录APP版本号
                if (PatchHelper.CheckSandboxCacheFileExist() == false)
                {
                    _cache.CacheAppVersion = Application.version;
                    _cache.SaveCache();
                }
                else
                {
                    // 每次启动时比对APP版本号是否一致
                    if (_cache.CacheAppVersion != Application.version)
                    {
                        MotionLog.Warning($"Cache is dirty ! Cache version is {_cache.CacheAppVersion}, APP version is {Application.version}");
                        ClearCache();

                        // 重新写入最新的APP版本号
                        _cache.CacheAppVersion = Application.version;
                        _cache.SaveCache();
                    }
                }
            }

            // 加载APP内的补丁清单
            MotionLog.Log($"Load app patch manifest.");
            {
                string        filePath   = AssetPathHelper.MakeStreamingLoadPath(PatchDefine.PatchManifestFileName);
                string        url        = AssetPathHelper.ConvertToWWWPath(filePath);
                WebGetRequest downloader = new WebGetRequest(url);
                downloader.DownLoad();
                yield return(downloader);

                if (downloader.HasError())
                {
                    downloader.ReportError();
                    downloader.Dispose();
                    throw new System.Exception($"Fatal error : Failed download file : {url}");
                }

                // 解析补丁清单
                string jsonData = downloader.GetText();
                _appPatchManifest = PatchManifest.Deserialize(jsonData);
                downloader.Dispose();
            }

            // 加载沙盒内的补丁清单
            MotionLog.Log($"Load sandbox patch manifest.");
            if (PatchHelper.CheckSandboxPatchManifestFileExist())
            {
                string filePath = AssetPathHelper.MakePersistentLoadPath(PatchDefine.PatchManifestFileName);
                string jsonData = File.ReadAllText(filePath);
                _localPatchManifest = PatchManifest.Deserialize(jsonData);
            }
            else
            {
                _localPatchManifest = _appPatchManifest;
            }
        }
예제 #16
0
        private IEnumerator Download()
        {
            // 注意:开发者需要在下载前检测磁盘空间不足

            // 计算下载文件的总大小
            int  totalDownloadCount     = _patcher.DownloadList.Count;
            long totalDownloadSizeBytes = 0;

            foreach (var element in _patcher.DownloadList)
            {
                totalDownloadSizeBytes += element.SizeBytes;
            }

            // 开始下载列表里的所有资源
            PatchHelper.Log(ELogLevel.Log, $"Begine download web files : {_patcher.DownloadList.Count}");
            long currentDownloadSizeBytes = 0;
            int  currentDownloadCount     = 0;

            foreach (var element in _patcher.DownloadList)
            {
                // 注意:资源版本号只用于确定下载路径
                string url      = _patcher.GetWebDownloadURL(element.Version.ToString(), element.Name);
                string savePath = AssetPathHelper.MakePersistentLoadPath(element.Name);
                element.SavePath = savePath;
                FileUtility.CreateFileDirectory(savePath);

                // 创建下载器
                WebFileRequest download = new WebFileRequest(url, savePath);
                yield return(download.DownLoad());                //文件依次加载(在一个文件加载完毕后加载下一个)

                PatchHelper.Log(ELogLevel.Log, $"Web file is download : {savePath}");

                // 检测是否下载失败
                if (download.States != EWebRequestStates.Success)
                {
                    PatchEventDispatcher.SendWebFileDownloadFailedMsg(url, element.Name);
                    yield break;
                }

                // 立即释放加载器
                download.Dispose();
                currentDownloadCount++;
                currentDownloadSizeBytes += element.SizeBytes;
                PatchEventDispatcher.SendDownloadFilesProgressMsg(totalDownloadCount, currentDownloadCount, totalDownloadSizeBytes, currentDownloadSizeBytes);
            }

            // 验证下载文件的大小
            if (_patcher.CheckLevel == ECheckLevel.CheckSize)
            {
                foreach (var element in _patcher.DownloadList)
                {
                    long fileSize = FileUtility.GetFileSize(element.SavePath);
                    if (fileSize != element.SizeBytes)
                    {
                        PatchHelper.Log(ELogLevel.Error, $"Web file size check failed : {element.Name}");
                        PatchEventDispatcher.SendWebFileCheckFailedMsg(element.Name);
                        yield break;
                    }
                }
            }

            // 验证下载文件的MD5
            if (_patcher.CheckLevel == ECheckLevel.CheckMD5)
            {
                foreach (var element in _patcher.DownloadList)
                {
                    string md5 = HashUtility.FileMD5(element.SavePath);
                    if (md5 != element.MD5)
                    {
                        PatchHelper.Log(ELogLevel.Error, $"Web file md5 check failed : {element.Name}");
                        PatchEventDispatcher.SendWebFileCheckFailedMsg(element.Name);
                        yield break;
                    }
                }
            }

            // 最后清空下载列表
            _patcher.DownloadList.Clear();
            _patcher.SwitchNext();
        }
        private IEnumerator Download()
        {
            // 如果忽略资源版本,那么每次启动都会下载补丁清单
            bool ignoreResourceVersion = _patcher.IgnoreResourceVersion;

            // 新安装的用户首次启动游戏(包括覆盖安装的用户)
            // 注意:请求的补丁清单会在下载流程结束的时候,自动保存在沙盒里。
            bool firstStartGame = PatchHelper.CheckSandboxPatchManifestFileExist() == false;

            // 检测资源版本是否变化
            int newResourceVersion = _patcher.RequestedResourceVersion;
            int oldResourceVersion = _patcher.LocalResourceVersion;

            if (ignoreResourceVersion == false && firstStartGame == false && newResourceVersion == oldResourceVersion)
            {
                MotionLog.Log($"Resource version is not change.");
                _patcher.Switch(EPatchStates.PatchDone);
            }
            else
            {
                // 从远端请求补丁清单
                _requestCount++;
                string        url      = GetRequestURL(ignoreResourceVersion, newResourceVersion, PatchDefine.PatchManifestFileName);
                WebGetRequest download = new WebGetRequest(url);
                download.SendRequest();
                yield return(download);

                // Check fatal
                if (download.HasError())
                {
                    download.ReportError();
                    download.Dispose();
                    PatchEventDispatcher.SendPatchManifestRequestFailedMsg();
                    yield break;
                }

                // 解析补丁清单
                _patcher.ParseRemotePatchManifest(download.GetText());
                download.Dispose();

                // 如果发现了新的安装包
                if (_patcher.FoundNewApp)
                {
                    string requestedGameVersion = _patcher.RequestedGameVersion.ToString();
                    MotionLog.Log($"Found new APP can be install : {requestedGameVersion}");
                    PatchEventDispatcher.SendFoundNewAppMsg(_patcher.ForceInstall, _patcher.AppURL, requestedGameVersion);
                }
                else
                {
                    if (firstStartGame)
                    {
                        MotionLog.Log("First start game.");
                    }
                    if (newResourceVersion != oldResourceVersion)
                    {
                        MotionLog.Log($"Resource version is change : {oldResourceVersion} -> {newResourceVersion}");
                    }
                    _patcher.SwitchNext();
                }
            }
        }