HAARFTE/Assets/DemoGame/GameScript/Loader/Res/InitializePackage.cs

419 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections;
using System.IO;
using Cysharp.Threading.Tasks;
using UnityEngine;
using YooAsset;
using ZC;
namespace Unity.Loader
{
public class InitializePackage
{
[SerializeField] EPlayMode playMode;
[SerializeField] private string packageName = "DefaultPackage";
[SerializeField] private string buildPipeline;
string packageVersion;
private Action iniFinishCallback;
public InitializePackage(EPlayMode playMode, string packageName = "DefaultPackage", Action iniFinishCallback = null)
{
this.playMode = playMode;
this.packageName = packageName;
buildPipeline = EDefaultBuildPipeline.BuiltinBuildPipeline.ToString();
this.iniFinishCallback = iniFinishCallback;
YooAssets.Initialize();
#if ENABLE_WEBGL || PLATFORM_WEBGL
YooAssets.SetCacheSystemDisableCacheOnWebGL();
#endif
EventManager.Instance.Subscribe(UpdatePackageCallbackEventArgs.EventId, UpdatePackageCallbackEvent);
this.InitPackage().Forget();
}
private void UpdatePackageCallbackEvent(object sender, GameEventArgs e)
{
var args = e as UpdatePackageCallbackEventArgs;
switch (args.callbackType)
{
case UpdatePackageCallbackType.:
this.InitPackage().Forget();
break;
case UpdatePackageCallbackType.:
this.BeginDownload().Forget();
break;
case UpdatePackageCallbackType.:
this.UpdatePackageVersion().Forget();
break;
case UpdatePackageCallbackType.:
this.UpdateManifest().Forget();
break;
case UpdatePackageCallbackType.:
this.BeginDownload().Forget();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
public async UniTask InitPackage()
{
await UniTask.Delay(500);
// 创建资源包裹类
var package = YooAssets.TryGetPackage(packageName);
if (package == null)
package = YooAssets.CreatePackage(packageName);
// 编辑器下的模拟模式
InitializationOperation initializationOperation = null;
if (playMode == EPlayMode.EditorSimulateMode)
{
var createParameters = new EditorSimulateModeParameters();
createParameters.SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild(buildPipeline, packageName);
initializationOperation = package.InitializeAsync(createParameters);
}
// 单机运行模式
if (playMode == EPlayMode.OfflinePlayMode)
{
var createParameters = new OfflinePlayModeParameters();
createParameters.DecryptionServices = new FileStreamDecryption();
initializationOperation = package.InitializeAsync(createParameters);
}
// 联机运行模式
if (playMode == EPlayMode.HostPlayMode)
{
string defaultHostServer = GetHostServerURL();
string fallbackHostServer = GetHostServerURL();
var createParameters = new HostPlayModeParameters();
createParameters.DecryptionServices = new FileStreamDecryption();
createParameters.BuildinQueryServices = new GameQueryServices();
createParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
initializationOperation = package.InitializeAsync(createParameters);
}
// WebGL运行模式
if (playMode == EPlayMode.WebPlayMode)
{
string defaultHostServer = GetHostServerURL();
string fallbackHostServer = GetHostServerURL();
var createParameters = new WebPlayModeParameters();
// createParameters.DecryptionServices = new FileStreamDecryption();
createParameters.BuildinQueryServices = new GameQueryServices();
createParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
initializationOperation = package.InitializeAsync(createParameters);
}
await initializationOperation;
// 如果初始化失败弹出提示界面
if (initializationOperation.Status != EOperationStatus.Succeed)
{
Debug.LogWarning($"{initializationOperation.Error}");
Debug.Log("初始化失败!");
// PatchEventDefine.InitializeFailed.SendEventMessage();
EventManager.Instance.FireNow(this, new InitializeFailedEventArgs());
}
else
{
var version = initializationOperation.PackageVersion;
Debug.Log($"Init resource package version : {version}");
// _machine.ChangeState<FsmUpdatePackageVersion>();
await this.UpdatePackageVersion();
}
}
#region Helper
/// <summary>
/// 获取资源服务器地址
/// </summary>
string GetHostServerURL()
{
//string hostServerIP = "http://10.0.2.2"; //安卓模拟器地址
string hostServerIP = "http://192.168.0.124:8080";
string appVersion = "v1.0";
#if UNITY_EDITOR
if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.Android)
return $"{hostServerIP}/CDN/Android/{appVersion}";
else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.iOS)
return $"{hostServerIP}/CDN/IPhone/{appVersion}";
else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.WebGL)
return $"{hostServerIP}/CDN/WebGL/{appVersion}";
else
return $"{hostServerIP}/CDN/PC/{appVersion}";
#else
if (Application.platform == RuntimePlatform.Android)
return $"{hostServerIP}/CDN/Android/{appVersion}";
else if (Application.platform == RuntimePlatform.IPhonePlayer)
return $"{hostServerIP}/CDN/IPhone/{appVersion}";
else if (Application.platform == RuntimePlatform.WebGLPlayer)
return $"{hostServerIP}/CDN/WebGL/{appVersion}";
else
return $"{hostServerIP}/CDN/PC/{appVersion}";
#endif
}
/// <summary>
/// 远端资源地址查询服务类
/// </summary>
class RemoteServices : IRemoteServices
{
private readonly string _defaultHostServer;
private readonly string _fallbackHostServer;
public RemoteServices(string defaultHostServer, string fallbackHostServer)
{
_defaultHostServer = defaultHostServer;
_fallbackHostServer = fallbackHostServer;
}
string IRemoteServices.GetRemoteMainURL(string fileName)
{
return $"{_defaultHostServer}/{fileName}";
}
string IRemoteServices.GetRemoteFallbackURL(string fileName)
{
return $"{_fallbackHostServer}/{fileName}";
}
}
/// <summary>
/// 资源文件流加载解密类
/// </summary>
class FileStreamDecryption : IDecryptionServices
{
/// <summary>
/// 同步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
/// </summary>
AssetBundle IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo, out Stream managedStream)
{
BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
managedStream = bundleStream;
return AssetBundle.LoadFromStream(bundleStream, fileInfo.ConentCRC, GetManagedReadBufferSize());
}
/// <summary>
/// 异步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
/// </summary>
AssetBundleCreateRequest IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo, out Stream managedStream)
{
BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
managedStream = bundleStream;
return AssetBundle.LoadFromStreamAsync(bundleStream, fileInfo.ConentCRC, GetManagedReadBufferSize());
}
private static uint GetManagedReadBufferSize()
{
return 1024;
}
}
/// <summary>
/// 资源文件偏移加载解密类
/// </summary>
class FileOffsetDecryption : IDecryptionServices
{
/// <summary>
/// 同步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
/// </summary>
AssetBundle IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo, out Stream managedStream)
{
managedStream = null;
return AssetBundle.LoadFromFile(fileInfo.FileLoadPath, fileInfo.ConentCRC, GetFileOffset());
}
/// <summary>
/// 异步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
/// </summary>
AssetBundleCreateRequest IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo, out Stream managedStream)
{
managedStream = null;
return AssetBundle.LoadFromFileAsync(fileInfo.FileLoadPath, fileInfo.ConentCRC, GetFileOffset());
}
private static ulong GetFileOffset()
{
return 32;
}
}
/// <summary>
/// 资源文件解密流
/// </summary>
public class BundleStream : FileStream
{
public const byte KEY = 64;
public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access, share)
{
}
public BundleStream(string path, FileMode mode) : base(path, mode)
{
}
public override int Read(byte[] array, int offset, int count)
{
var index = base.Read(array, offset, count);
for (int i = 0; i < array.Length; i++)
{
array[i] ^= KEY;
}
return index;
}
}
#endregion
public async UniTask UpdatePackageVersion()
{
Debug.Log("获取最新的资源版本 !");
await UniTask.Delay(100);
var package = YooAssets.GetPackage(packageName);
var operation = package.UpdatePackageVersionAsync();
await operation;
if (operation.Status != EOperationStatus.Succeed)
{
Debug.LogWarning(operation.Error);
Debug.Log("获取最新的资源版本失败!");
// PatchEventDefine.PackageVersionUpdateFailed.SendEventMessage();
EventManager.Instance.FireNow(this, new PackageVersionUpdateFailedEventArgs());
}
else
{
packageVersion = operation.PackageVersion;
await this.UpdateManifest();
}
}
public async UniTask UpdateManifest()
{
Debug.Log("更新资源清单!");
await UniTask.Delay(100);
var package = YooAssets.GetPackage(packageName);
bool savePackageVersion = true;
var operation = package.UpdatePackageManifestAsync(packageVersion, savePackageVersion);
await operation;
if (operation.Status != EOperationStatus.Succeed)
{
Debug.LogWarning(operation.Error);
Debug.Log("更新资源清单失败!");
// PatchEventDefine.PatchManifestUpdateFailed.SendEventMessage();
EventManager.Instance.FireNow(this, new PatchManifestUpdateFailedEventArgs());
return;
}
else
{
await this.CreateDownloader();
}
}
ResourceDownloaderOperation downloader;
public async UniTask CreateDownloader()
{
Debug.Log("创建补丁下载器!");
await UniTask.Delay(100);
var package = YooAssets.GetPackage(packageName);
int downloadingMaxNum = 10;
int failedTryAgain = 3;
downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);
if (downloader.TotalDownloadCount == 0)
{
Debug.Log("Not found any download files !");
await this.UpdaterDone();
}
else
{
// 发现新更新文件后,挂起流程系统
// 注意:开发者需要在下载前检测磁盘空间不足
int totalDownloadCount = downloader.TotalDownloadCount;
long totalDownloadBytes = downloader.TotalDownloadBytes;
// PatchEventDefine.FoundUpdateFiles.SendEventMessage(totalDownloadCount, totalDownloadBytes);
EventManager.Instance.FireNow(this, new FoundUpdateFilesEventArgs(totalDownloadCount, totalDownloadBytes));
// await this.BeginDownload();
}
}
public async UniTask BeginDownload()
{
Debug.Log("开始下载补丁文件!");
downloader.OnDownloadErrorCallback = DownloadErrorCallback;
downloader.OnDownloadProgressCallback = DownloadProgressCallback;
downloader.BeginDownload();
await downloader;
// 检测下载结果
if (downloader.Status != EOperationStatus.Succeed)
return;
await this.DownloadFinish();
void DownloadErrorCallback(string fileName, string error)
{
Debug.Log($"下载补丁出错!{error}");
EventManager.Instance.FireNow(this, new WebFileDownloadFailedEventArgs(fileName, error));
}
void DownloadProgressCallback(int totaldownloadcount, int currentdownloadcount, long totaldownloadbytes, long currentdownloadbytes)
{
Debug.Log($"下载进度:{currentdownloadcount}/{totaldownloadcount} , {currentdownloadbytes}/{totaldownloadbytes}");
EventManager.Instance.FireNow(this, new DownloadProgressUpdateEventArgs(totaldownloadcount,
currentdownloadcount,
totaldownloadbytes,
currentdownloadbytes));
}
}
public async UniTask DownloadFinish()
{
Debug.Log("下载补丁文件完成!");
await this.ClearPackageCache();
}
public async UniTask ClearPackageCache()
{
Debug.Log("清理未使用的缓存文件!");
var package = YooAssets.GetPackage(packageName);
var operation = package.ClearUnusedCacheFilesAsync();
operation.Completed += Operation_Completed;
await UniTask.Yield();
}
private void Operation_Completed(AsyncOperationBase obj)
{
this.UpdaterDone().Forget();
}
public async UniTask UpdaterDone()
{
// 设置默认的资源包
var gamePackage = YooAssets.GetPackage("DefaultPackage");
YooAssets.SetDefaultPackage(gamePackage);
Debug.Log("流程更新完毕!");
this.iniFinishCallback?.Invoke();
EventManager.Instance.FireNow(this, new UpdaterDoneEventArgs());
await UniTask.Yield();
}
}
}