diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem.meta
new file mode 100644
index 0000000..cff102c
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ccb22c5c90bfe2f43a0f83f873dd6646
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/ByteGameFileSystem.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/ByteGameFileSystem.cs
new file mode 100644
index 0000000..db00534
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/ByteGameFileSystem.cs
@@ -0,0 +1,219 @@
+#if UNITY_WEBGL
+using System.Collections.Generic;
+using UnityEngine;
+using YooAsset;
+using StarkSDKSpace;
+
+public static class ByteGameFileSystemCreater
+{
+ public static FileSystemParameters CreateWechatFileSystemParameters(IRemoteServices remoteServices)
+ {
+ string fileSystemClass = $"{nameof(ByteGameFileSystem)},YooAsset.RuntimeExtension";
+ var fileSystemParams = new FileSystemParameters(fileSystemClass, null);
+ fileSystemParams.AddParameter("REMOTE_SERVICES", remoteServices);
+ return fileSystemParams;
+ }
+}
+
+///
+/// 抖音小游戏文件系统
+/// 参考:https://developer.open-douyin.com/docs/resource/zh-CN/mini-game/develop/guide/know
+///
+internal class ByteGameFileSystem : IFileSystem
+{
+ private class WebRemoteServices : IRemoteServices
+ {
+ private readonly string _webPackageRoot;
+ protected readonly Dictionary _mapping = new Dictionary(10000);
+
+ public WebRemoteServices(string buildinPackRoot)
+ {
+ _webPackageRoot = buildinPackRoot;
+ }
+ string IRemoteServices.GetRemoteMainURL(string fileName)
+ {
+ return GetFileLoadURL(fileName);
+ }
+ string IRemoteServices.GetRemoteFallbackURL(string fileName)
+ {
+ return GetFileLoadURL(fileName);
+ }
+
+ private string GetFileLoadURL(string fileName)
+ {
+ if (_mapping.TryGetValue(fileName, out string url) == false)
+ {
+ string filePath = PathUtility.Combine(_webPackageRoot, fileName);
+ url = DownloadSystemHelper.ConvertToWWWPath(filePath);
+ _mapping.Add(fileName, url);
+ }
+ return url;
+ }
+ }
+
+ private readonly Dictionary _cacheFilePaths = new Dictionary(10000);
+ private StarkFileSystemManager _fileSystemManager;
+
+ ///
+ /// 包裹名称
+ ///
+ public string PackageName { private set; get; }
+
+ ///
+ /// 文件根目录
+ ///
+ public string FileRoot
+ {
+ get
+ {
+ return string.Empty;
+ }
+ }
+
+ ///
+ /// 文件数量
+ ///
+ public int FileCount
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ #region 自定义参数
+ ///
+ /// 自定义参数:远程服务接口
+ ///
+ public IRemoteServices RemoteServices { private set; get; } = null;
+ #endregion
+
+
+ public ByteGameFileSystem()
+ {
+ }
+ public virtual FSInitializeFileSystemOperation InitializeFileSystemAsync()
+ {
+ var operation = new BGFSInitializeOperation(this);
+ OperationSystem.StartOperation(PackageName, operation);
+ return operation;
+ }
+ public virtual FSLoadPackageManifestOperation LoadPackageManifestAsync(string packageVersion, int timeout)
+ {
+ var operation = new BGFSLoadPackageManifestOperation(this, packageVersion, timeout);
+ OperationSystem.StartOperation(PackageName, operation);
+ return operation;
+ }
+ public virtual FSRequestPackageVersionOperation RequestPackageVersionAsync(bool appendTimeTicks, int timeout)
+ {
+ var operation = new BGFSRequestPackageVersionOperation(this, timeout);
+ OperationSystem.StartOperation(PackageName, operation);
+ return operation;
+ }
+ public virtual FSClearAllBundleFilesOperation ClearAllBundleFilesAsync()
+ {
+ var operation = new FSClearAllBundleFilesCompleteOperation();
+ OperationSystem.StartOperation(PackageName, operation);
+ return operation;
+ }
+ public virtual FSClearUnusedBundleFilesOperation ClearUnusedBundleFilesAsync(PackageManifest manifest)
+ {
+ var operation = new FSClearUnusedBundleFilesCompleteOperation();
+ OperationSystem.StartOperation(PackageName, operation);
+ return operation;
+ }
+ public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadParam param)
+ {
+ param.MainURL = RemoteServices.GetRemoteMainURL(bundle.FileName);
+ param.FallbackURL = RemoteServices.GetRemoteFallbackURL(bundle.FileName);
+ var operation = new BGFSDownloadFileOperation(this, bundle, param);
+ OperationSystem.StartOperation(PackageName, operation);
+ return operation;
+ }
+ public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle)
+ {
+ var operation = new BGFSLoadBundleOperation(this, bundle);
+ OperationSystem.StartOperation(PackageName, operation);
+ return operation;
+ }
+ public virtual void UnloadBundleFile(PackageBundle bundle, object result)
+ {
+ AssetBundle assetBundle = result as AssetBundle;
+ if (assetBundle != null)
+ assetBundle.Unload(true);
+ }
+
+ public virtual void SetParameter(string name, object value)
+ {
+ if (name == "REMOTE_SERVICES")
+ {
+ RemoteServices = (IRemoteServices)value;
+ }
+ else
+ {
+ YooLogger.Warning($"Invalid parameter : {name}");
+ }
+ }
+ public virtual void OnCreate(string packageName, string rootDirectory)
+ {
+ PackageName = packageName;
+
+ // 注意:CDN服务未启用的情况下,使用抖音WEB服务器
+ if (RemoteServices == null)
+ {
+ string webRoot = PathUtility.Combine(Application.streamingAssetsPath, YooAssetSettingsData.Setting.DefaultYooFolderName, packageName);
+ RemoteServices = new WebRemoteServices(webRoot);
+ }
+
+ _fileSystemManager = StarkSDK.API.GetStarkFileSystemManager();
+ }
+ public virtual void OnUpdate()
+ {
+ }
+
+ public virtual bool Belong(PackageBundle bundle)
+ {
+ return true;
+ }
+ public virtual bool Exists(PackageBundle bundle)
+ {
+ return _fileSystemManager.AccessSync(bundle.FileName);
+ }
+ public virtual bool NeedDownload(PackageBundle bundle)
+ {
+ if (Belong(bundle) == false)
+ return false;
+
+ return Exists(bundle) == false;
+ }
+ public virtual bool NeedUnpack(PackageBundle bundle)
+ {
+ return false;
+ }
+ public virtual bool NeedImport(PackageBundle bundle)
+ {
+ return false;
+ }
+
+ public virtual byte[] ReadFileData(PackageBundle bundle)
+ {
+ throw new System.NotImplementedException();
+ }
+ public virtual string ReadFileText(PackageBundle bundle)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ #region 内部方法
+ private string GetFileLoadPath(PackageBundle bundle)
+ {
+ if (_cacheFilePaths.TryGetValue(bundle.BundleGUID, out string filePath) == false)
+ {
+ filePath = _fileSystemManager.GetLocalCachedPathForUrl(bundle.FileName);
+ _cacheFilePaths.Add(bundle.BundleGUID, filePath);
+ }
+ return filePath;
+ }
+ #endregion
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/ByteGameFileSystem.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/ByteGameFileSystem.cs.meta
new file mode 100644
index 0000000..ac1a607
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/ByteGameFileSystem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e6b4324eddc60f045aa271bc5bb50cc9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation.meta
new file mode 100644
index 0000000..7e4113c
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8cba5e0b26df8ee40a93d697f889e33d
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSDownloadFileOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSDownloadFileOperation.cs
new file mode 100644
index 0000000..611d685
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSDownloadFileOperation.cs
@@ -0,0 +1,101 @@
+#if UNITY_WEBGL
+using UnityEngine;
+using UnityEngine.Networking;
+using YooAsset;
+
+internal class BGFSDownloadFileOperation : DefaultDownloadFileOperation
+{
+ private ByteGameFileSystem _fileSystem;
+ private ESteps _steps = ESteps.None;
+
+ internal BGFSDownloadFileOperation(ByteGameFileSystem fileSystem, PackageBundle bundle, DownloadParam param) : base(bundle, param)
+ {
+ _fileSystem = fileSystem;
+ }
+ internal override void InternalOnStart()
+ {
+ _steps = ESteps.CreateRequest;
+ }
+ internal override void InternalOnUpdate()
+ {
+ // 创建下载器
+ if (_steps == ESteps.CreateRequest)
+ {
+ // 获取请求地址
+ _requestURL = GetRequestURL();
+
+ // 重置变量
+ ResetRequestFiled();
+
+ // 创建下载器
+ CreateWebRequest();
+
+ _steps = ESteps.CheckRequest;
+ }
+
+ // 检测下载结果
+ if (_steps == ESteps.CheckRequest)
+ {
+ DownloadProgress = _webRequest.downloadProgress;
+ DownloadedBytes = (long)_webRequest.downloadedBytes;
+ Progress = DownloadProgress;
+ if (_webRequest.isDone == false)
+ {
+ CheckRequestTimeout();
+ return;
+ }
+
+ // 检查网络错误
+ if (CheckRequestResult())
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Succeed;
+ }
+ else
+ {
+ _steps = ESteps.TryAgain;
+ }
+
+ // 注意:最终释放请求器
+ DisposeWebRequest();
+ }
+
+ // 重新尝试下载
+ if (_steps == ESteps.TryAgain)
+ {
+ if (FailedTryAgain <= 0)
+ {
+ Status = EOperationStatus.Failed;
+ _steps = ESteps.Done;
+ YooLogger.Error(Error);
+ return;
+ }
+
+ _tryAgainTimer += Time.unscaledDeltaTime;
+ if (_tryAgainTimer > 1f)
+ {
+ FailedTryAgain--;
+ _steps = ESteps.CreateRequest;
+ YooLogger.Warning(Error);
+ }
+ }
+ }
+
+ private void CreateWebRequest()
+ {
+ //TODO : 抖音小游戏没有找到预下载方法
+ _webRequest = UnityWebRequestAssetBundle.GetAssetBundle(_requestURL);
+ _webRequest.disposeDownloadHandlerOnDispose = true;
+ _webRequest.SendWebRequest();
+ }
+ private void DisposeWebRequest()
+ {
+ if (_webRequest != null)
+ {
+ //注意:引擎底层会自动调用Abort方法
+ _webRequest.Dispose();
+ _webRequest = null;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSDownloadFileOperation.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSDownloadFileOperation.cs.meta
new file mode 100644
index 0000000..b3abf50
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSDownloadFileOperation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0bdf53359f9e17b41b08982a2be2098c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSInitializeOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSInitializeOperation.cs
new file mode 100644
index 0000000..8beec7f
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSInitializeOperation.cs
@@ -0,0 +1,20 @@
+#if UNITY_WEBGL
+using YooAsset;
+
+internal partial class BGFSInitializeOperation : FSInitializeFileSystemOperation
+{
+ private readonly ByteGameFileSystem _fileSystem;
+
+ public BGFSInitializeOperation(ByteGameFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+ internal override void InternalOnStart()
+ {
+ Status = EOperationStatus.Succeed;
+ }
+ internal override void InternalOnUpdate()
+ {
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSInitializeOperation.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSInitializeOperation.cs.meta
new file mode 100644
index 0000000..e6e0ca6
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSInitializeOperation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 614227bf558da7149a7eb6de7dfa1a21
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadBundleOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadBundleOperation.cs
new file mode 100644
index 0000000..790f677
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadBundleOperation.cs
@@ -0,0 +1,102 @@
+#if UNITY_WEBGL
+using UnityEditor.PackageManager.Requests;
+using UnityEngine;
+using UnityEngine.Networking;
+using YooAsset;
+
+internal class BGFSLoadBundleOperation : FSLoadBundleOperation
+{
+ private enum ESteps
+ {
+ None,
+ LoadBundleFile,
+ Done,
+ }
+
+ private readonly ByteGameFileSystem _fileSystem;
+ private readonly PackageBundle _bundle;
+ private UnityWebRequest _webRequest;
+ private ESteps _steps = ESteps.None;
+
+ internal BGFSLoadBundleOperation(ByteGameFileSystem fileSystem, PackageBundle bundle)
+ {
+ _fileSystem = fileSystem;
+ _bundle = bundle;
+ }
+ internal override void InternalOnStart()
+ {
+ _steps = ESteps.LoadBundleFile;
+ }
+ internal override void InternalOnUpdate()
+ {
+ if (_steps == ESteps.None || _steps == ESteps.Done)
+ return;
+
+ if (_steps == ESteps.LoadBundleFile)
+ {
+ if (_webRequest == null)
+ {
+ string mainURL = _fileSystem.RemoteServices.GetRemoteMainURL(_bundle.FileName);
+ _webRequest = UnityWebRequestAssetBundle.GetAssetBundle(mainURL);
+ _webRequest.SendWebRequest();
+ }
+
+ DownloadProgress = _webRequest.downloadProgress;
+ DownloadedBytes = (long)_webRequest.downloadedBytes;
+ Progress = DownloadProgress;
+ if (_webRequest.isDone == false)
+ return;
+
+ if (CheckRequestResult())
+ {
+ _steps = ESteps.Done;
+ Result = (_webRequest.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
+ Status = EOperationStatus.Succeed;
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ }
+ }
+ }
+ internal override void InternalWaitForAsyncComplete()
+ {
+ if (_steps != ESteps.Done)
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = "WebGL platform not support sync load method !";
+ UnityEngine.Debug.LogError(Error);
+ }
+ }
+ public override void AbortDownloadOperation()
+ {
+ }
+
+ private bool CheckRequestResult()
+ {
+#if UNITY_2020_3_OR_NEWER
+ if (_webRequest.result != UnityWebRequest.Result.Success)
+ {
+ Error = _webRequest.error;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+#else
+ if (_webRequest.isNetworkError || _webRequest.isHttpError)
+ {
+ Error = _webRequest.error;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+#endif
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadBundleOperation.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadBundleOperation.cs.meta
new file mode 100644
index 0000000..2b1312a
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadBundleOperation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 19997de7b89b54445961e8b973f43ab3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadPackageManifestOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadPackageManifestOperation.cs
new file mode 100644
index 0000000..7a0d0b1
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadPackageManifestOperation.cs
@@ -0,0 +1,88 @@
+#if UNITY_WEBGL
+using YooAsset;
+
+internal class BGFSLoadPackageManifestOperation : FSLoadPackageManifestOperation
+{
+ private enum ESteps
+ {
+ None,
+ RequestRemotePackageHash,
+ LoadRemotePackageManifest,
+ Done,
+ }
+
+ private readonly ByteGameFileSystem _fileSystem;
+ private readonly string _packageVersion;
+ private readonly int _timeout;
+ private RequestByteGamePackageHashOperation _requestRemotePackageHashOp;
+ private LoadByteGamePackageManifestOperation _loadRemotePackageManifestOp;
+ private ESteps _steps = ESteps.None;
+
+
+ public BGFSLoadPackageManifestOperation(ByteGameFileSystem fileSystem, string packageVersion, int timeout)
+ {
+ _fileSystem = fileSystem;
+ _packageVersion = packageVersion;
+ _timeout = timeout;
+ }
+ internal override void InternalOnStart()
+ {
+ _steps = ESteps.RequestRemotePackageHash;
+ }
+ internal override void InternalOnUpdate()
+ {
+ if (_steps == ESteps.None || _steps == ESteps.Done)
+ return;
+
+ if (_steps == ESteps.RequestRemotePackageHash)
+ {
+ if (_requestRemotePackageHashOp == null)
+ {
+ _requestRemotePackageHashOp = new RequestByteGamePackageHashOperation(_fileSystem, _packageVersion, _timeout);
+ OperationSystem.StartOperation(_fileSystem.PackageName, _requestRemotePackageHashOp);
+ }
+
+ if (_requestRemotePackageHashOp.IsDone == false)
+ return;
+
+ if (_requestRemotePackageHashOp.Status == EOperationStatus.Succeed)
+ {
+ _steps = ESteps.LoadRemotePackageManifest;
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = _requestRemotePackageHashOp.Error;
+ }
+ }
+
+ if (_steps == ESteps.LoadRemotePackageManifest)
+ {
+ if (_loadRemotePackageManifestOp == null)
+ {
+ string packageHash = _requestRemotePackageHashOp.PackageHash;
+ _loadRemotePackageManifestOp = new LoadByteGamePackageManifestOperation(_fileSystem, _packageVersion, packageHash, _timeout);
+ OperationSystem.StartOperation(_fileSystem.PackageName, _loadRemotePackageManifestOp);
+ }
+
+ Progress = _loadRemotePackageManifestOp.Progress;
+ if (_loadRemotePackageManifestOp.IsDone == false)
+ return;
+
+ if (_loadRemotePackageManifestOp.Status == EOperationStatus.Succeed)
+ {
+ _steps = ESteps.Done;
+ Manifest = _loadRemotePackageManifestOp.Manifest;
+ Status = EOperationStatus.Succeed;
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = _loadRemotePackageManifestOp.Error;
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadPackageManifestOperation.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadPackageManifestOperation.cs.meta
new file mode 100644
index 0000000..7b4505f
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSLoadPackageManifestOperation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2850c0b0e742f824f9d1f12b7d68b806
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSRequestPackageVersionOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSRequestPackageVersionOperation.cs
new file mode 100644
index 0000000..0b2a91f
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSRequestPackageVersionOperation.cs
@@ -0,0 +1,60 @@
+#if UNITY_WEBGL
+using YooAsset;
+
+internal class BGFSRequestPackageVersionOperation : FSRequestPackageVersionOperation
+{
+ private enum ESteps
+ {
+ None,
+ RequestPackageVersion,
+ Done,
+ }
+
+ private readonly ByteGameFileSystem _fileSystem;
+ private readonly int _timeout;
+ private RequestByteGamePackageVersionOperation _requestWebPackageVersionOp;
+ private ESteps _steps = ESteps.None;
+
+
+ internal BGFSRequestPackageVersionOperation(ByteGameFileSystem fileSystem, int timeout)
+ {
+ _fileSystem = fileSystem;
+ _timeout = timeout;
+ }
+ internal override void InternalOnStart()
+ {
+ _steps = ESteps.RequestPackageVersion;
+ }
+ internal override void InternalOnUpdate()
+ {
+ if (_steps == ESteps.None || _steps == ESteps.Done)
+ return;
+
+ if (_steps == ESteps.RequestPackageVersion)
+ {
+ if (_requestWebPackageVersionOp == null)
+ {
+ _requestWebPackageVersionOp = new RequestByteGamePackageVersionOperation(_fileSystem, _timeout);
+ OperationSystem.StartOperation(_fileSystem.PackageName, _requestWebPackageVersionOp);
+ }
+
+ Progress = _requestWebPackageVersionOp.Progress;
+ if (_requestWebPackageVersionOp.IsDone == false)
+ return;
+
+ if (_requestWebPackageVersionOp.Status == EOperationStatus.Succeed)
+ {
+ _steps = ESteps.Done;
+ PackageVersion = _requestWebPackageVersionOp.PackageVersion;
+ Status = EOperationStatus.Succeed;
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = _requestWebPackageVersionOp.Error;
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSRequestPackageVersionOperation.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSRequestPackageVersionOperation.cs.meta
new file mode 100644
index 0000000..80e9802
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/BGFSRequestPackageVersionOperation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8210185faba92a3479bf6713abab1f19
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal.meta
new file mode 100644
index 0000000..6df9ad2
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 101c97835f86e9147993961f514caf2c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/LoadByteGamePackageManifestOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/LoadByteGamePackageManifestOperation.cs
new file mode 100644
index 0000000..395a5e3
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/LoadByteGamePackageManifestOperation.cs
@@ -0,0 +1,125 @@
+#if UNITY_WEBGL
+using YooAsset;
+
+internal class LoadByteGamePackageManifestOperation : AsyncOperationBase
+{
+ private enum ESteps
+ {
+ None,
+ RequestFileData,
+ VerifyFileData,
+ LoadManifest,
+ Done,
+ }
+
+ private readonly ByteGameFileSystem _fileSystem;
+ private readonly string _packageVersion;
+ private readonly string _packageHash;
+ private readonly int _timeout;
+ private UnityWebDataRequestOperation _webDataRequestOp;
+ private DeserializeManifestOperation _deserializer;
+ private int _requestCount = 0;
+ private ESteps _steps = ESteps.None;
+
+ ///
+ /// 包裹清单
+ ///
+ public PackageManifest Manifest { private set; get; }
+
+
+ internal LoadByteGamePackageManifestOperation(ByteGameFileSystem fileSystem, string packageVersion, string packageHash, int timeout)
+ {
+ _fileSystem = fileSystem;
+ _packageVersion = packageVersion;
+ _packageHash = packageHash;
+ _timeout = timeout;
+ }
+ internal override void InternalOnStart()
+ {
+ _requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(LoadByteGamePackageManifestOperation));
+ _steps = ESteps.RequestFileData;
+ }
+ internal override void InternalOnUpdate()
+ {
+ if (_steps == ESteps.None || _steps == ESteps.Done)
+ return;
+
+ if (_steps == ESteps.RequestFileData)
+ {
+ if (_webDataRequestOp == null)
+ {
+ string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion);
+ string url = GetRequestURL(fileName);
+ _webDataRequestOp = new UnityWebDataRequestOperation(url, _timeout);
+ OperationSystem.StartOperation(_fileSystem.PackageName, _webDataRequestOp);
+ }
+
+ Progress = _webDataRequestOp.Progress;
+ if (_webDataRequestOp.IsDone == false)
+ return;
+
+ if (_webDataRequestOp.Status == EOperationStatus.Succeed)
+ {
+ _steps = ESteps.VerifyFileData;
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = _webDataRequestOp.Error;
+ WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(LoadByteGamePackageManifestOperation));
+ }
+ }
+
+ if (_steps == ESteps.VerifyFileData)
+ {
+ string fileHash = HashUtility.BytesMD5(_webDataRequestOp.Result);
+ if (fileHash == _packageHash)
+ {
+ _steps = ESteps.LoadManifest;
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = "Failed to verify wechat package manifest file!";
+ }
+ }
+
+ if (_steps == ESteps.LoadManifest)
+ {
+ if (_deserializer == null)
+ {
+ _deserializer = new DeserializeManifestOperation(_webDataRequestOp.Result);
+ OperationSystem.StartOperation(_fileSystem.PackageName, _deserializer);
+ }
+
+ Progress = _deserializer.Progress;
+ if (_deserializer.IsDone == false)
+ return;
+
+ if (_deserializer.Status == EOperationStatus.Succeed)
+ {
+ _steps = ESteps.Done;
+ Manifest = _deserializer.Manifest;
+ Status = EOperationStatus.Succeed;
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = _deserializer.Error;
+ }
+ }
+ }
+
+ private string GetRequestURL(string fileName)
+ {
+ // 轮流返回请求地址
+ if (_requestCount % 2 == 0)
+ return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
+ else
+ return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/LoadByteGamePackageManifestOperation.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/LoadByteGamePackageManifestOperation.cs.meta
new file mode 100644
index 0000000..6bb1e19
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/LoadByteGamePackageManifestOperation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b648d648fa0c4e44d811b42b80891543
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageHashOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageHashOperation.cs
new file mode 100644
index 0000000..7cfb018
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageHashOperation.cs
@@ -0,0 +1,90 @@
+#if UNITY_WEBGL
+using YooAsset;
+
+internal class RequestByteGamePackageHashOperation : AsyncOperationBase
+{
+ private enum ESteps
+ {
+ None,
+ RequestPackageHash,
+ Done,
+ }
+
+ private readonly ByteGameFileSystem _fileSystem;
+ private readonly string _packageVersion;
+ private readonly int _timeout;
+ private UnityWebTextRequestOperation _webTextRequestOp;
+ private int _requestCount = 0;
+ private ESteps _steps = ESteps.None;
+
+ ///
+ /// 包裹哈希值
+ ///
+ public string PackageHash { private set; get; }
+
+
+ public RequestByteGamePackageHashOperation(ByteGameFileSystem fileSystem, string packageVersion, int timeout)
+ {
+ _fileSystem = fileSystem;
+ _packageVersion = packageVersion;
+ _timeout = timeout;
+ }
+ internal override void InternalOnStart()
+ {
+ _requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(RequestByteGamePackageHashOperation));
+ _steps = ESteps.RequestPackageHash;
+ }
+ internal override void InternalOnUpdate()
+ {
+ if (_steps == ESteps.None || _steps == ESteps.Done)
+ return;
+
+ if (_steps == ESteps.RequestPackageHash)
+ {
+ if (_webTextRequestOp == null)
+ {
+ string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion);
+ string url = GetRequestURL(fileName);
+ _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout);
+ OperationSystem.StartOperation(_fileSystem.PackageName, _webTextRequestOp);
+ }
+
+ Progress = _webTextRequestOp.Progress;
+ if (_webTextRequestOp.IsDone == false)
+ return;
+
+ if (_webTextRequestOp.Status == EOperationStatus.Succeed)
+ {
+ PackageHash = _webTextRequestOp.Result;
+ if (string.IsNullOrEmpty(PackageHash))
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = $"Wechat package hash file content is empty !";
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Succeed;
+ }
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = _webTextRequestOp.Error;
+ WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(RequestByteGamePackageHashOperation));
+ }
+ }
+ }
+
+ private string GetRequestURL(string fileName)
+ {
+ // 轮流返回请求地址
+ if (_requestCount % 2 == 0)
+ return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
+ else
+ return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageHashOperation.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageHashOperation.cs.meta
new file mode 100644
index 0000000..7a99745
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageHashOperation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 51a0e40e248b49a4783b3dca33a23cf1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageVersionOperation.cs b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageVersionOperation.cs
new file mode 100644
index 0000000..963deaf
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageVersionOperation.cs
@@ -0,0 +1,88 @@
+#if UNITY_WEBGL
+using YooAsset;
+
+internal class RequestByteGamePackageVersionOperation : AsyncOperationBase
+{
+ private enum ESteps
+ {
+ None,
+ RequestPackageVersion,
+ Done,
+ }
+
+ private readonly ByteGameFileSystem _fileSystem;
+ private readonly int _timeout;
+ private UnityWebTextRequestOperation _webTextRequestOp;
+ private int _requestCount = 0;
+ private ESteps _steps = ESteps.None;
+
+ ///
+ /// 包裹版本
+ ///
+ public string PackageVersion { private set; get; }
+
+
+ public RequestByteGamePackageVersionOperation(ByteGameFileSystem fileSystem, int timeout)
+ {
+ _fileSystem = fileSystem;
+ _timeout = timeout;
+ }
+ internal override void InternalOnStart()
+ {
+ _requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(RequestByteGamePackageVersionOperation));
+ _steps = ESteps.RequestPackageVersion;
+ }
+ internal override void InternalOnUpdate()
+ {
+ if (_steps == ESteps.None || _steps == ESteps.Done)
+ return;
+
+ if (_steps == ESteps.RequestPackageVersion)
+ {
+ if (_webTextRequestOp == null)
+ {
+ string fileName = YooAssetSettingsData.GetPackageVersionFileName(_fileSystem.PackageName);
+ string url = GetRequestURL(fileName);
+ _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout);
+ OperationSystem.StartOperation(_fileSystem.PackageName, _webTextRequestOp);
+ }
+
+ Progress = _webTextRequestOp.Progress;
+ if (_webTextRequestOp.IsDone == false)
+ return;
+
+ if (_webTextRequestOp.Status == EOperationStatus.Succeed)
+ {
+ PackageVersion = _webTextRequestOp.Result;
+ if (string.IsNullOrEmpty(PackageVersion))
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = $"Wechat package version file content is empty !";
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Succeed;
+ }
+ }
+ else
+ {
+ _steps = ESteps.Done;
+ Status = EOperationStatus.Failed;
+ Error = _webTextRequestOp.Error;
+ WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(RequestByteGamePackageVersionOperation));
+ }
+ }
+ }
+
+ private string GetRequestURL(string fileName)
+ {
+ // 轮流返回请求地址
+ if (_requestCount % 2 == 0)
+ return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
+ else
+ return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageVersionOperation.cs.meta b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageVersionOperation.cs.meta
new file mode 100644
index 0000000..be04d19
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/ByteGameFileSystem/Operation/internal/RequestByteGamePackageVersionOperation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a04c463fb00f60f499541fbb98e4fdc4
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Extension Sample/Runtime/YooAsset.RuntimeExtension.asmdef b/Assets/YooAsset/Samples~/Extension Sample/Runtime/YooAsset.RuntimeExtension.asmdef
index 1440681..3095837 100644
--- a/Assets/YooAsset/Samples~/Extension Sample/Runtime/YooAsset.RuntimeExtension.asmdef
+++ b/Assets/YooAsset/Samples~/Extension Sample/Runtime/YooAsset.RuntimeExtension.asmdef
@@ -3,7 +3,8 @@
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3",
- "GUID:5efd170ecd8084500bed5692932fe14e"
+ "GUID:5efd170ecd8084500bed5692932fe14e",
+ "GUID:0f8df04a5a494444eb8fa0504f6fb965"
],
"includePlatforms": [],
"excludePlatforms": [],