using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using BITKit.IO; using BITKit.UX; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UIElements; using YooAsset; using Debug = UnityEngine.Debug; namespace BITKit { public class BITFramework : MonoBehaviour { private static System.Diagnostics.Stopwatch Stopwatch; [RuntimeInitializeOnLoadMethod] private static void Reload() { Stopwatch = new Stopwatch(); #if UNITY_EDITOR #else SplashScreen.Stop(SplashScreen.StopBehavior.StopImmediate); #endif } // [SerializeField] private AssetReference serviceReference; // private async void Start() // { // if(InitializationState is not InitializationState.None)return; // InitializationState = InitializationState.Initializing; // var asyncOperationHandle = serviceReference.LoadAssetAsync(); // await UniTask.WaitUntil(() => asyncOperationHandle.IsDone); // DontDestroyOnLoad(Instantiate(asyncOperationHandle.Result)); // Stopwatch.Stop(); // BIT4Log.Log($"BITFramework加载完成,耗时:{Stopwatch.ElapsedMilliseconds}ms"); // } [SerializeReference, SubclassSelector] private IReference addressableName; [SerializeReference, SubclassSelector] private IReference packageName = new Reference("DefaultPackages"); [SerializeReference, SubclassSelector] private IRemoteServices remoteServices; [SerializeReference, SubclassSelector] private IBuildinQueryServices buildinQueryServices; [SerializeField] private Optional loadEntryScene; [SerializeField] private UIDocument document; [SerializeField] private bool isOffline; [SerializeField] private bool IsEditorSimulateMode; [SerializeField] private UnityEvent,Action> afterInitialize=new(); [SerializeField] private UnityEvent onGetCurrentVersion; [UXBindPath("progress-bar",true)] private ProgressBar _progressBar; [UXBindPath("progress-fill",true)] private VisualElement _progressFill; [UXBindPath("progress-label")] private Label _progressLabel; private Action _setProgressValue; private Action _setProgressLabel; private async void Start() { try { #if UNITY_EDITOR #else IsEditorSimulateMode = false; #endif UXUtils.Inject(this); if (_progressBar is not null) { _setProgressValue = value => _progressBar.value = value; }else if (_progressFill is not null) { _setProgressValue = value => _progressFill.style.width = new Length() { value = value*100, unit = LengthUnit.Percent }; } _setProgressLabel = value => _progressLabel.text = value; _setProgressValue?.Invoke(0f); _setProgressLabel?.Invoke("正在初始化资源系统..."); var stopwatch = new Stopwatch(); stopwatch.Start(); DontDestroyOnLoad(gameObject); // 初始化资源系统 YooAssets.Initialize(); // 创建默认的资源包 var package = YooAssets.TryGetPackage(packageName.Value) ?? YooAssets.CreatePackage(packageName.Value); // 设置该资源包为默认的资源包,可以使用YooAssets相关加载接口加载该资源包内容。 YooAssets.SetDefaultPackage(package); InitializeParameters initParameters = new HostPlayModeParameters { BuildinQueryServices = buildinQueryServices, RemoteServices = remoteServices }; #if UNITY_EDITOR if (IsEditorSimulateMode) { var editorParameters = new EditorSimulateModeParameters { SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild("ScriptableBuildPipeline", packageName.Value) }; initParameters = editorParameters; }else #endif if (isOffline) { initParameters = new OfflinePlayModeParameters(); } InitializationOperation initOperation = null; try { initOperation = package.InitializeAsync(initParameters); _progressLabel.text ="正在初始化资源系统..."; } catch (Exception e) { _progressLabel.text =e.Message; initParameters = new HostPlayModeParameters { BuildinQueryServices = buildinQueryServices, RemoteServices = remoteServices }; initOperation = package.InitializeAsync(initParameters); } while (initOperation.IsDone is false) { await UniTask.NextFrame(destroyCancellationToken); //_progressBar.value =initOperation.Progress; _setProgressValue?.Invoke(initOperation.Progress); } try { _progressLabel.text="正在更新资源包版本..."; var operation = package.UpdatePackageVersionAsync(); try { onGetCurrentVersion.Invoke(package.GetPackageVersion()); } catch (Exception e) { BIT4Log.LogException(e); } while (operation.IsDone is false) { await UniTask.NextFrame(destroyCancellationToken); //_progressBar.value = operation.Progress; _setProgressValue?.Invoke(operation.Progress); } if (operation.Status == EOperationStatus.Succeed) { //更新成功 string packageVersion = operation.PackageVersion; Debug.Log($"Updated package Version : {packageVersion}"); _progressLabel.text="正在更新资源包清单..."; var manifestOperation = package.UpdatePackageManifestAsync(packageVersion); await manifestOperation.ToUniTask(); if (manifestOperation.Status == EOperationStatus.Succeed) { //更新成功 int downloadingMaxNum = 10; int failedTryAgain = 3; var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain); //没有需要下载的资源 if (downloader.TotalDownloadCount != 0) { //需要下载的文件总数和总大小 int totalDownloadCount = downloader.TotalDownloadCount; long totalDownloadBytes = downloader.TotalDownloadBytes; downloader.OnDownloadProgressCallback = (downloadedCount, downloadedBytes, downloadCount, downloadBytes) => { //下载进度 float progress = (float)downloadedBytes / downloadBytes; //下载速度 float speed = 1; //剩余时间 float remainTime = (downloadCount - downloadedCount) / speed; _setProgressValue?.Invoke(progress); _setProgressLabel?.Invoke($"下载速度:{speed}KB/s,剩余时间:{remainTime}s"); }; downloader.OnDownloadErrorCallback=(fileName,error) => { _setProgressLabel?.Invoke(error); }; //注册回调方法 // downloader.OnDownloadErrorCallback = OnDownloadErrorFunction; // downloader.OnDownloadProgressCallback = OnDownloadProgressUpdateFunction; // downloader.OnDownloadOverCallback = OnDownloadOverFunction; // downloader.OnStartDownloadFileCallback = OnStartDownloadFileFunction; //开启下载 downloader.BeginDownload(); await downloader; //检测下载结果 if (downloader.Status != EOperationStatus.Succeed) { //更新失败 Debug.LogError(operation.Error); _progressLabel.text =operation.Error; } } } else { //更新失败 Debug.LogError(operation.Error); _progressLabel.text =operation.Error; } } else { //更新失败 Debug.LogError(operation.Error); _progressLabel.text =operation.Error; } } catch (Exception e) { BIT4Log.LogException(e); _progressLabel.text =e.Message; } _setProgressLabel?.Invoke("资源系统初始化完成,后处理中..."); afterInitialize.Invoke(_setProgressValue,_setProgressLabel); _setProgressLabel?.Invoke("资源系统初始化完成,后处理完成"); if (addressableName is not null) { _progressLabel.text ="正在初始化Framework"; var frameworkHandle = YooAssets.LoadAssetAsync(addressableName.Value); while (frameworkHandle.IsDone is false) { await UniTask.NextFrame(destroyCancellationToken); //_progressBar.value=frameworkHandle.Progress; _setProgressValue?.Invoke(frameworkHandle.Progress); } var framework = Instantiate(frameworkHandle.AssetObject); DontDestroyOnLoad(framework); _progressLabel.text="已加载完成"; BIT4Log.Log("BITFramework加载完成,耗时:" + stopwatch.ElapsedMilliseconds + "ms"); } stopwatch.Stop(); YooAssetUtils.RegisterPackage(packageName.Value); YooAssetUtils.RegisterResourcePackage(package); if (loadEntryScene.Allow) { _progressLabel.text="正在加载场景..."; await package.LoadSceneAsync(loadEntryScene.Value); if (document) Destroy(document); } else { if (document) Destroy(document); SceneManager.LoadScene(1); } } catch (Exception e) { await UniTask.SwitchToMainThread(); _progressBar.value =0; _progressLabel.text = e.Message; } } private void OnDestroy() { YooAssets.Destroy(); } } [Serializable] public sealed class GameQueryServices : IBuildinQueryServices { public bool Query(string packageName, string fileName) { // 注意:fileName包含文件格式 return StreamingAssetsHelper.FileExists(packageName, fileName); } public bool Query(string packageName, string fileName, string fileCRC)=>Query(packageName,fileName); } [Serializable] public sealed class LocalQueryServices : IBuildinQueryServices { public readonly string Path; public LocalQueryServices(string path) { Path = path; } public bool Query(string packageName, string fileName, string fileCRC) { return File.Exists(System.IO.Path.Combine(Path, fileName)); } } /// /// 远端资源地址查询服务类 /// [Serializable] public sealed class RemoteServices : IRemoteServices { [SerializeField] private string _defaultHostServer; [SerializeField] private string _fallbackHostServer; public RemoteServices(){} 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}"; } } }