YooAsset的API封装记录
前言
公司同事最近在用YooAsset去做热更逻辑的处理,我正好使用到他所涉及的部分逻辑,也就沿用YooAsset方案了。我个人使用的过程中,对YooAsset做了额外的封装处理。本篇文章就是我个人封装YooAsset的API的代码记录。如果你觉得我写得有问题,我欢迎你来指出我的错误。
我要事先说明一件事情,下面给出的代码,我并没有做完全的验证,这是因为这些代码是从我最近的项目中提炼并优化后的产物。因为我最近对应的项目停工了,而我自己还在忙其他的项目。所以我现在没时间去做验证。我深知我自己后面在这热乎劲过去后就不会去做了,所以我还是写了。
环境
Unity2022.3.62f3c1
Windows11
YooAsset 2.3.18
Mini Game 2.3.18
UniTask 2.5.11
项目简述
我这次经手的项目要发布到多个平台:安卓平台,微信小游戏平台和抖音小游戏平台。所以我这次的封装涉及到多平台的适配。因为YooAsset本身就对小游戏平台有对应的支持即其Sample的Mini
Game。因此对于小程序平台,我直接使用Mini Game设定的宏来区分。
YooAsset封装
在提出主要代码之前,我还要先说明一些额外的操作。这是在我个人使用的过程中遇到的问题,而这没办法用YooAsset提供的接口来解决。首先是在我本地模拟的时候,在WebGL平台下会出现文件丢失的问题。本质是因为我没有事先创建Catalog文件。所以我写了下面的代码来辅助创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 using System;using System.IO;using System.Text;using UnityEngine;using YooAsset;namespace Common { public static class WebServerEmptyCatalogHelper { private const uint FileSign = 0x133C5EE ; private const string FileVersion = "1.0.0" ; public static void EnsureEmptyCatalog (string packageName ) { string builtinRoot = GetBuiltinRoot(); string packageDir = Path.Combine(builtinRoot, packageName); string catalogPath = Path.Combine(packageDir, "BuildinCatalog.bytes" ); if (File.Exists(catalogPath)) { Debug.Log($"[WebServerEmptyCatalogHelper] Catalog 文件已存在,跳过生成: {catalogPath} " ); return ; } try { if (!Directory.Exists(packageDir)) Directory.CreateDirectory(packageDir); byte [] catalogBytes = BuildEmptyCatalogBinary(packageName); File.WriteAllBytes(catalogPath, catalogBytes); Debug.Log($"[WebServerEmptyCatalogHelper] 成功生成空 Catalog: {catalogPath} (0 个内置资源)" ); } catch (Exception e) { Debug.LogError($"[WebServerEmptyCatalogHelper] 生成 Catalog 失败: {e.Message} " ); } } private static byte [] BuildEmptyCatalogBinary (string packageName ) { using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms, Encoding.UTF8)) { writer.Write(FileSign); WriteUTF8(writer, FileVersion); WriteUTF8(writer, packageName); WriteUTF8(writer, "0.0.0" ); writer.Write(0 ); writer.Flush(); return ms.ToArray(); } } private static void WriteUTF8 (BinaryWriter writer, string value ) { if (string .IsNullOrEmpty(value )) { writer.Write((ushort )0 ); return ; } byte [] bytes = Encoding.UTF8.GetBytes(value ); if (bytes.Length > ushort .MaxValue) throw new FormatException($"WriteUTF8 length cannot be greater than {ushort .MaxValue} " ); writer.Write((ushort )bytes.Length); writer.Write(bytes); } private static string GetBuiltinRoot () { string defaultFolder = YooAssetSettingsData.GetDefaultYooFolderName(); if (string .IsNullOrEmpty(defaultFolder)) return Application.streamingAssetsPath; else return Path.Combine(Application.streamingAssetsPath, defaultFolder); } } }
除此之外,我还遇到了一个问题————无法加载本地已有的包。我的游戏更偏向于单机性质类的,本身用YooAsset就很奇怪。但是为了减少包体大小,YooAsset又是必须的。所以我需求完成这个奇怪的需求。即如果存在本地包,而玩家网络不好的时候,优先加载本地的资源,保证玩家先去玩。我用AI帮助我生成了下面的5个代码块,来实现这个需求。因为其使用了YooAsset内部的代码,所以你要先做一些预先操作。选择一个空文件夹,在Unity中创建一个Assembly Definition Reference,并将其Assembly Definition设定为YooAsset的Assembly Definition。代码块实现如下:
OfflineFirstRequestPackageVersionOperation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 using System.IO;namespace YooAsset { internal class OfflineFirstRequestPackageVersionOperation : FSRequestPackageVersionOperation { private enum ESteps { None, RequestRemoteVersion, LoadLocalVersion, Done, } private readonly DefaultCacheFileSystem _cacheFileSystem; private readonly bool _appendTimeTicks; private readonly int _timeout; private FSRequestPackageVersionOperation _remoteVersionOp; private ESteps _steps = ESteps.None; internal OfflineFirstRequestPackageVersionOperation (DefaultCacheFileSystem cacheFileSystem, bool appendTimeTicks, int timeout ) { _cacheFileSystem = cacheFileSystem; _appendTimeTicks = appendTimeTicks; _timeout = timeout; } internal override void InternalStart () { _steps = ESteps.RequestRemoteVersion; } internal override void InternalUpdate () { if (_steps == ESteps.None || _steps == ESteps.Done) return ; if (_steps == ESteps.RequestRemoteVersion) { if (_remoteVersionOp == null ) { _remoteVersionOp = _cacheFileSystem.RequestPackageVersionAsync(_appendTimeTicks, _timeout); _remoteVersionOp.StartOperation(); AddChildOperation(_remoteVersionOp); } _remoteVersionOp.UpdateOperation(); Progress = _remoteVersionOp.Progress; if (_remoteVersionOp.IsDone == false ) return ; if (_remoteVersionOp.Status == EOperationStatus.Succeed) { _steps = ESteps.Done; PackageVersion = _remoteVersionOp.PackageVersion; Status = EOperationStatus.Succeed; } else { YooLogger.Warning($"Request remote version failed : {_remoteVersionOp.Error} , fallback to local." ); _steps = ESteps.LoadLocalVersion; } } if (_steps == ESteps.LoadLocalVersion) { string localVersion = FindCachedVersion(); if (string .IsNullOrEmpty(localVersion) == false ) { _steps = ESteps.Done; PackageVersion = localVersion; Status = EOperationStatus.Succeed; } else { _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = "Request remote version failed and no cached version found." ; } } } internal override string InternalGetDesc () { return $"OfflineFirst request version : {_cacheFileSystem.PackageName} " ; } private string FindCachedVersion () { string manifestRoot = _cacheFileSystem.GetCacheManifestFilesRoot(); if (Directory.Exists(manifestRoot) == false ) return string .Empty; string prefix = _cacheFileSystem.PackageName + "_" ; string [] files = Directory.GetFiles(manifestRoot, prefix + "*.bytes" , SearchOption.TopDirectoryOnly); if (files == null || files.Length == 0 ) return string .Empty; string fileName = Path.GetFileName(files[0 ]); string version = fileName.Substring(prefix.Length); version = version.Substring(0 , version.Length - ".bytes" .Length); return version; } } }
OfflineFirstLoadPackageManifestOperation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 using System.IO;namespace YooAsset { internal class OfflineFirstLoadPackageManifestOperation : FSLoadPackageManifestOperation { private enum ESteps { None, LoadRemoteManifest, LoadLocalManifest, Done, } private readonly DefaultCacheFileSystem _cacheFileSystem; private readonly string _packageVersion; private readonly int _timeout; private LoadCachePackageManifestOperation _localLoadOp; private FSLoadPackageManifestOperation _remoteLoadOp; private ESteps _steps = ESteps.None; internal OfflineFirstLoadPackageManifestOperation (DefaultCacheFileSystem cacheFileSystem, string packageVersion, int timeout ) { _cacheFileSystem = cacheFileSystem; _packageVersion = packageVersion; _timeout = timeout; } internal override void InternalStart () { _steps = ESteps.LoadRemoteManifest; } internal override void InternalUpdate () { if (_steps == ESteps.None || _steps == ESteps.Done) return ; if (_steps == ESteps.LoadRemoteManifest) { if (_remoteLoadOp == null ) { _remoteLoadOp = _cacheFileSystem.LoadPackageManifestAsync(_packageVersion, _timeout); _remoteLoadOp.StartOperation(); AddChildOperation(_remoteLoadOp); } _remoteLoadOp.UpdateOperation(); Progress = _remoteLoadOp.Progress; if (_remoteLoadOp.IsDone == false ) return ; if (_remoteLoadOp.Status == EOperationStatus.Succeed) { _steps = ESteps.Done; Manifest = _remoteLoadOp.Manifest; Status = EOperationStatus.Succeed; } else { YooLogger.Warning($"Load remote manifest failed : {_remoteLoadOp.Error} , fallback to local." ); _steps = ESteps.LoadLocalManifest; } } if (_steps == ESteps.LoadLocalManifest) { if (_localLoadOp == null ) { string packageHash = ReadLocalPackageHash(); _localLoadOp = new LoadCachePackageManifestOperation(_cacheFileSystem, _packageVersion, packageHash); _localLoadOp.StartOperation(); AddChildOperation(_localLoadOp); } _localLoadOp.UpdateOperation(); Progress = _localLoadOp.Progress; if (_localLoadOp.IsDone == false ) return ; if (_localLoadOp.Status == EOperationStatus.Succeed) { _steps = ESteps.Done; Manifest = _localLoadOp.Manifest; Status = EOperationStatus.Succeed; } else { _steps = ESteps.Done; Status = EOperationStatus.Failed; Error = _localLoadOp.Error; } } } internal override string InternalGetDesc () { return $"OfflineFirst load manifest : {_packageVersion} " ; } private string ReadLocalPackageHash () { string hashFilePath = _cacheFileSystem.GetCachePackageHashFilePath(_packageVersion); if (File.Exists(hashFilePath) == false ) return string .Empty; string content = FileUtility.ReadAllText(hashFilePath); return string .IsNullOrEmpty(content) ? string .Empty : content; } } }
OfflineFirstFileSystemFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 using YooAsset;namespace YooAssetExtend { public static class OfflineFirstFileSystemFactory { public static FileSystemParameters CreateFileSystemParameters (IRemoteServices remoteServices, string packageRoot = null ) { string fileSystemClass = "YooAsset.OfflineFirstFileSystem, YooAsset" ; var fileSystemParams = new FileSystemParameters(fileSystemClass, packageRoot); fileSystemParams.AddParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices); return fileSystemParams; } } }
OfflineFirstInitializeOperation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 namespace YooAsset { internal class OfflineFirstInitializeOperation : FSInitializeFileSystemOperation { private readonly OfflineFirstFileSystem _fileSystem; private readonly FSInitializeFileSystemOperation _cacheInitOp; internal OfflineFirstInitializeOperation (OfflineFirstFileSystem fileSystem, FSInitializeFileSystemOperation cacheInitOp ) { _fileSystem = fileSystem; _cacheInitOp = cacheInitOp; } internal override void InternalStart () { _cacheInitOp.StartOperation(); AddChildOperation(_cacheInitOp); } internal override void InternalUpdate () { _cacheInitOp.UpdateOperation(); Progress = _cacheInitOp.Progress; if (_cacheInitOp.IsDone == false ) return ; if (_cacheInitOp.Status == EOperationStatus.Succeed) { Status = EOperationStatus.Succeed; } else { Status = EOperationStatus.Failed; Error = _cacheInitOp.Error; } } internal override string InternalGetDesc () { return $"OfflineFirstFileSystem initialize : {_fileSystem.PackageName} " ; } } }
OfflineFirstInitializeOperation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 namespace YooAsset { internal class OfflineFirstFileSystem : IFileSystem { private readonly DefaultCacheFileSystem _cacheFileSystem; private string _packageRoot; public string PackageRoot { private set ; get ; } public string PackageName { private set ; get ; } public string FileRoot { get { return _packageRoot; } } public int FileCount { get { return _cacheFileSystem != null ? _cacheFileSystem.FileCount : 0 ; } } public OfflineFirstFileSystem () { _cacheFileSystem = new DefaultCacheFileSystem(); } #region IFileSystem 实现 public FSInitializeFileSystemOperation InitializeFileSystemAsync () { var operation = new OfflineFirstInitializeOperation(this , _cacheFileSystem.InitializeFileSystemAsync()); return operation; } public FSLoadPackageManifestOperation LoadPackageManifestAsync (string packageVersion, int timeout ) { return new OfflineFirstLoadPackageManifestOperation(_cacheFileSystem, packageVersion, timeout); } public FSRequestPackageVersionOperation RequestPackageVersionAsync (bool appendTimeTicks, int timeout ) { return new OfflineFirstRequestPackageVersionOperation(_cacheFileSystem, appendTimeTicks, timeout); } public FSClearCacheFilesOperation ClearCacheFilesAsync (PackageManifest manifest, ClearCacheFilesOptions options ) { return _cacheFileSystem.ClearCacheFilesAsync(manifest, options); } public FSDownloadFileOperation DownloadFileAsync (PackageBundle bundle, DownloadFileOptions options ) { return _cacheFileSystem.DownloadFileAsync(bundle, options); } public FSLoadBundleOperation LoadBundleFile (PackageBundle bundle ) { return _cacheFileSystem.LoadBundleFile(bundle); } public void SetParameter (string name, object value ) { _cacheFileSystem.SetParameter(name, value ); } public void OnCreate (string packageName, string packageRoot ) { PackageName = packageName; PackageRoot = packageRoot; _cacheFileSystem.OnCreate(packageName, packageRoot); _packageRoot = _cacheFileSystem.FileRoot; } public void OnDestroy () { _cacheFileSystem.OnDestroy(); } public bool Belong (PackageBundle bundle ) { return _cacheFileSystem.Belong(bundle); } public bool Exists (PackageBundle bundle ) { return _cacheFileSystem.Exists(bundle); } public bool NeedDownload (PackageBundle bundle ) { return _cacheFileSystem.NeedDownload(bundle); } public bool NeedUnpack (PackageBundle bundle ) { return _cacheFileSystem.NeedUnpack(bundle); } public bool NeedImport (PackageBundle bundle ) { return _cacheFileSystem.NeedImport(bundle); } public string GetBundleFilePath (PackageBundle bundle ) { return _cacheFileSystem.GetBundleFilePath(bundle); } public byte [] ReadBundleFileData (PackageBundle bundle ) { return _cacheFileSystem.ReadBundleFileData(bundle); } public string ReadBundleFileText (PackageBundle bundle ) { return _cacheFileSystem.ReadBundleFileText(bundle); } #endregion } }
接下来就是主要实现。
YooAssetRemoteServices
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using YooAsset;namespace Common { public class YooAssetRemoteServices : IRemoteServices { private readonly string _defaultHostServer; private readonly string _fallbackHostServer; public YooAssetRemoteServices (string defaultHostServer, string fallbackHostServer ) { _defaultHostServer = defaultHostServer; _fallbackHostServer = fallbackHostServer; } string IRemoteServices.GetRemoteMainURL(string fileName) { return $"{_defaultHostServer} /{fileName} " ; } string IRemoteServices.GetRemoteFallbackURL(string fileName) { return $"{_fallbackHostServer} /{fileName} " ; } } }
YooAssetServer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 using Common.Data;using Cysharp.Threading.Tasks;using System.Collections;using System.Collections.Generic;using System.IO;using UnityEngine;using YooAsset;namespace Common { public class YooAssetServer { #if UNITY_WEBGL private static string PackageUrl = "https://...." ; private static string BackUpPackageUrl = "https://...." ; #else private static string PackageUrl = "https://...." ; private static string BackUpPackageUrl = "https://...." ; #endif private Dictionary<string , ResourcePackage> loadedPackages = new Dictionary<string , ResourcePackage>(); public YooAssetServer () { if (!YooAssets.Initialized) YooAssets.Initialize(); } public void Init () { if (!YooAssets.Initialized) YooAssets.Initialize(); } #if UNITY_EDITOR public bool TestLoad { private get ; set ; } private async UniTask<bool > InitializeLocalPackage (string packageName ) { var package = YooAssets.TryGetPackage(packageName); if (package == null ) { package = YooAssets.CreatePackage(packageName); } InitializationOperation initializationOperation = null ; var buildResult = EditorSimulateModeHelper.SimulateBuild(packageName); var packageRoot = buildResult.PackageRootDirectory; var createParameters = new EditorSimulateModeParameters(); createParameters.EditorFileSystemParameters = FileSystemParameters.CreateDefaultEditorFileSystemParameters(packageRoot); initializationOperation = package.InitializeAsync(createParameters); await initializationOperation.ToUniTask(); if (initializationOperation.Status != EOperationStatus.Succeed) { Debug.Log("初始化资源包失败" ); return false ; } var getVersion = package.RequestPackageVersionAsync(); await getVersion.ToUniTask(); if (getVersion.Status != EOperationStatus.Succeed) { Debug.Log("请求资源版本失败" ); return false ; } var packageVersion = getVersion.PackageVersion; var getManifest = package.UpdatePackageManifestAsync(packageVersion); await getManifest.ToUniTask(); if (getManifest.Status != EOperationStatus.Succeed) { Debug.Log("更新资源清单失败" ); return false ; } loadedPackages[packageName] = package; return true ; } #endif private async UniTask<bool > RemotePackageInitialize (string packagesName ) { bool ans = true ; var url = PackageUrl.TrimEnd('/' ) + "/" + packagesName; var backUpUrl = BackUpPackageUrl.TrimEnd('/' ) + "/" + packagesName; var packageCacheUrl = Path.Combine(PlatformDataUtility.FullUserDataPath, packagesName); var remoteServices = new YooAssetRemoteServices(url, backUpUrl); #if UNITY_EDITOR var package = YooAssets.CreatePackage(packagesName); InitializeParameters createParameters; #if UNITY_WEBGL { WebServerEmptyCatalogHelper.EnsureEmptyCatalog(packagesName); var webParams = new WebPlayModeParameters(); var webServerFileSystemParams = FileSystemParameters.CreateDefaultWebServerFileSystemParameters(); var webRemoteFileSystemParams = FileSystemParameters.CreateDefaultWebRemoteFileSystemParameters(remoteServices); webParams.WebServerFileSystemParameters = webServerFileSystemParams; webParams.WebRemoteFileSystemParameters = webRemoteFileSystemParams; createParameters = webParams; } #else { var hostParams = new HostPlayModeParameters(); var buildinFileSystemParams = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(); buildinFileSystemParams.AddParameter(FileSystemParametersDefine.DISABLE_CATALOG_FILE, true ); var cacheFileSystemParams = FileSystemParameters.CreateDefaultCacheFileSystemParameters(remoteServices, null , packageCacheUrl); hostParams.BuildinFileSystemParameters = buildinFileSystemParams; hostParams.CacheFileSystemParameters = cacheFileSystemParams; createParameters = hostParams; } #endif var initializationOperation = package.InitializeAsync(createParameters); await initializationOperation.ToUniTask(); if (initializationOperation.Status != EOperationStatus.Succeed) { Debug.LogError($"{packagesName} 初始化失败" ); ans = false ; } else { Debug.Log($"{packagesName} 初始化成功" ); await PackageUpdate(package); } #else var package = YooAssets.TryGetPackage(packagesName); if (package == null ) package = YooAssets.CreatePackage(packagesName); InitializeParameters createParameters; #if DOUYINMINIGAME // 抖音 var parameters = new WebPlayModeParameters(); parameters.WebServerFileSystemParameters = TiktokFileSystemCreater.CreateFileSystemParameters(packageCacheUrl, remoteServices); createParameters = parameters; #elif WEIXINMINIGAME // 微信 var parameters = new WebPlayModeParameters(); parameters.WebServerFileSystemParameters = WechatFileSystemCreater.CreateFileSystemParameters(packageCacheUrl, remoteServices); createParameters = parameters; #else // 现在来说就是安卓平台 var parameters = new HostPlayModeParameters(); parameters.BuildinFileSystemParameters = null ; parameters.CacheFileSystemParameters = OfflineFirstFileSystemFactory.CreateFileSystemParameters(remoteServices, packageCacheUrl); createParameters = parameters; #endif var initializationOperation = package.InitializeAsync(createParameters); await initializationOperation.ToUniTask(); if (initializationOperation.Status != EOperationStatus.Succeed) { ans = false ; } else { await PackageUpdate(package); } #endif if (ans) loadedPackages[packagesName] = YooAssets.GetPackage(packagesName); else loadedPackages.Remove(packagesName); return ans; } public async UniTask<bool > InitializePackage (string packagesName ) { if (loadedPackages.ContainsKey(packagesName)) { if (loadedPackages[packagesName] != null ) { Debug.LogError("包体正在加载,请勿重复初始化" ); return false ; } else return true ; } loadedPackages[packagesName] = null ; #if UNITY_EDITOR if (TestLoad) return await RemotePackageInitialize(packagesName); return await InitializeLocalPackage(packagesName); #else return await RemotePackageInitialize(packagesName); #endif } public bool ExistOrLoadingPackage (string packageName ) { return loadedPackages.ContainsKey(packageName); } public bool IsLoadedPackage (string packageName ) { return loadedPackages.ContainsKey(packageName) && loadedPackages[packageName] != null ; } public ResourcePackage GetPackage (string packageName ) { if (loadedPackages.ContainsKey(packageName)) { return loadedPackages[packageName]; } return null ; } public AssetHandle LoadRes <T >(string packageName,string url ) where T : Object { var package = GetPackage(packageName); if (package == null ) return null ; T obj = null ; var handle = YooAssets.LoadAssetSync(url, typeof (T)); if (handle.Status == EOperationStatus.Succeed) { obj = handle.AssetObject as T; #if UNITY_EDITOR if (obj == null ) { Debug.LogError(handle.AssetObject.GetType()); return null ; } #endif } return handle; } public async UniTask <AssetHandle > LoadResAsync <T >(string packageName, string url ) where T : Object { var package = GetPackage(packageName); if (package == null ) return null ; T obj = null ; var handle = YooAssets.LoadAssetAsync(url, typeof (T)); await handle.ToUniTask(); if (handle.Status == EOperationStatus.Succeed) { obj = handle.AssetObject as T; #if UNITY_EDITOR if (obj == null ) { Debug.LogError(handle.AssetObject.GetType()); return null ; } #endif } return handle; } public IEnumerator UnloadUnuseAssetPackageRes (string packageName ) { if (loadedPackages.ContainsKey(packageName)) { var package = loadedPackages[packageName]; if (package != null ) yield return package.UnloadUnusedAssetsAsync(); } } public IEnumerator UnloadUnuseAssetAllLoadPackageRes () { foreach (var package in loadedPackages.Values) { if (package != null ) yield return package.UnloadUnusedAssetsAsync(); } } #region 通用的更新流程 private async UniTask<bool > PackageUpdate (ResourcePackage package ) { var version = await RequestPackageVersion(package); var ans = !string .IsNullOrEmpty(version); int step = 1 ; while (ans && step <= 3 ) { switch (step) { case 1 : ans = await UpdatePackageManifest(package, version); break ; case 2 : ans = await CheckAndDownloadFiles(package); break ; case 3 : await ClearCacheFiles(package); break ; } step++; } if (!ans) { Debug.Log("更新失败" ); } return ans; } private async UniTask<string > RequestPackageVersion (ResourcePackage package ) { string ans = "" ; var operation = package.RequestPackageVersionAsync(); await operation.ToUniTask(); if (operation.Status != EOperationStatus.Succeed) { Debug.LogError(package.PackageName + "请求资源版本失败:" + operation.Error); } else ans = operation.PackageVersion; return ans; } private async UniTask<bool > UpdatePackageManifest (ResourcePackage package, string packageVersion ) { var operation = package.UpdatePackageManifestAsync(packageVersion); await operation.ToUniTask(); if (operation.Status != EOperationStatus.Succeed) { Debug.LogError($"{package.PackageName} 更新资源清单失败:{operation.Error} " ); return false ; } return true ; } private async UniTask<bool > CheckAndDownloadFiles (ResourcePackage package ) { int downloadingMaxNum = 10 ; int failedTryAgain = 3 ; var _downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain); if (_downloader.TotalDownloadCount == 0 ) { Debug.Log("没有文件需要下载" ); return true ; } int totalDownloadCount = _downloader.TotalDownloadCount; long totalDownloadBytes = _downloader.TotalDownloadBytes; Debug.Log($"发现需要下载的文件: {totalDownloadCount} 个, 总大小: {totalDownloadBytes} 字节" ); return await DownloadFiles(_downloader); } private async UniTask<bool > DownloadFiles (ResourceDownloaderOperation _downloader ) { _downloader.DownloadErrorCallback = (errorData) => { Debug.LogError($"下载文件失败: {errorData.FileName} , {errorData.ErrorInfo} " ); }; _downloader.BeginDownload(); await _downloader.ToUniTask(); if (_downloader.Status != EOperationStatus.Succeed) { return false ; } return true ; } private async UniTask ClearCacheFiles (ResourcePackage _package ) { var operation = _package.ClearCacheFilesAsync(EFileClearMode.ClearUnusedBundleFiles); await operation.ToUniTask(); } #endregion } }
闲言碎语
我干到一半就感觉不对劲了,这不如我直接上传到github仓库里。但是我已经写了一部分了,那就算了。