代码重构

This commit is contained in:
何冠峰
2026-04-28 10:52:01 +08:00
parent 5b81269090
commit 67745c899a
161 changed files with 3164 additions and 4144 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
using System.Runtime.CompilerServices;
// 外部友元
[assembly: InternalsVisibleTo("YooAsset.EditorExtension")]
[assembly: InternalsVisibleTo("YooAsset.Extension.Editor")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor")]

View File

@@ -36,7 +36,8 @@ namespace YooAsset.Editor
// 清空首包资源目录
if (copyOption == EBundledCopyOption.ClearAndCopyAll || copyOption == EBundledCopyOption.ClearAndCopyByTags)
{
EditorFileUtility.ClearFolder(bundledRootDirectory);
EditorFileUtility.DeleteDirectory(bundledRootDirectory);
EditorFileUtility.CreateDirectory(bundledRootDirectory);
}
// 拷贝补丁清单文件

View File

@@ -7,6 +7,7 @@ namespace YooAsset.Editor
[Serializable]
public class EditorAssetInfo : IComparable<EditorAssetInfo>
{
[NonSerialized]
private string _fileExtension = null;
/// <summary>

View File

@@ -118,28 +118,6 @@ namespace YooAsset.Editor
File.Copy(sourcePath, destPath, overwrite);
}
/// <summary>
/// 清空文件夹
/// </summary>
/// <param name="directoryPath">要清理的文件夹路径</param>
public static void ClearFolder(string directoryPath)
{
if (Directory.Exists(directoryPath) == false)
return;
string[] allFiles = Directory.GetFiles(directoryPath);
for (int i = 0; i < allFiles.Length; i++)
{
File.Delete(allFiles[i]);
}
string[] allFolders = Directory.GetDirectories(directoryPath);
for (int i = 0; i < allFolders.Length; i++)
{
Directory.Delete(allFolders[i], true);
}
}
/// <summary>
/// 获取文件字节大小
/// </summary>

View File

@@ -187,7 +187,7 @@
identification within third-party archives.
Copyright 2018-2021 何冠峰
Copyright 2021-2025 TuYoo Games
Copyright 2021-2026 TuYoo Games
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,12 +1,12 @@
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
// 内部友元
[assembly: InternalsVisibleTo("YooAsset.Editor")]
[assembly: InternalsVisibleTo("YooAsset.Test")]
[assembly: InternalsVisibleTo("YooAsset.Test.Editor")]
[assembly: InternalsVisibleTo("YooAsset.Tests")]
[assembly: InternalsVisibleTo("YooAsset.Tests.Editor")]
// 外部友元
[assembly: InternalsVisibleTo("YooAsset.MiniGame")]
[assembly: InternalsVisibleTo("YooAsset.RuntimeExtension")]
[assembly: InternalsVisibleTo("YooAsset.EditorExtension")]
[assembly: InternalsVisibleTo("YooAsset.Extension")]
[assembly: InternalsVisibleTo("YooAsset.Extension.Editor")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor")]

View File

@@ -8,7 +8,7 @@ namespace YooAsset
/// <summary>
/// 异步操作基类
/// </summary>
public abstract class AsyncOperationBase : IEnumerator, IComparable<AsyncOperationBase>
public abstract partial class AsyncOperationBase : IEnumerator, IComparable<AsyncOperationBase>
{
private List<AsyncOperationBase> _children;
private Action<AsyncOperationBase> _completedCallback;

View File

@@ -25,5 +25,13 @@ namespace YooAsset
/// 已失败
/// </summary>
Failed,
#if YOOASSET_LEGACY_API
/// <summary>
/// v2.3 兼容别名
/// </summary>
[System.Obsolete("Use Succeeded instead.")]
Succeed = Succeeded,
#endif
}
}

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// 按资源地址清理缓存文件
/// </summary>
/// <remarks>
/// ClearParameter 类型string / string[] / List<string>
/// ClearParameter 类型string / array / list
/// </remarks>
internal class EvictionByLocationsPolicy : ICacheEvictionPolicy
{

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// 按标签清理缓存文件
/// </summary>
/// <remarks>
/// ClearParameter 类型string / string[] / List<string>
/// ClearParameter 类型string / array / list
/// </remarks>
internal class EvictionByTagsPolicy : ICacheEvictionPolicy
{

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 0f79d08cddb5196408cff10f6750ae69
guid: da061aaa46527ed44a052b269aeeaeb0
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,191 @@
#if YOOASSET_LEGACY_API
// YooAsset v2.3 兼容层 - DownloaderOperation 兼容
// 通过 partial class 为 DownloaderOperation 补充 v2.3 的旧式回调属性和 BeginDownload 方法。
using System;
namespace YooAsset
{
#region v2.3
/// <summary>
/// v2.3 下载器结束回调委托
/// </summary>
[Obsolete("Use DownloadCompleted event instead.")]
public delegate void DownloaderFinish(DownloaderFinishData data);
/// <summary>
/// v2.3 下载进度更新回调委托
/// </summary>
[Obsolete("Use DownloadProgressChanged event instead.")]
public delegate void DownloadUpdateDelegate(DownloadUpdateData data);
/// <summary>
/// v2.3 下载错误回调委托(重命名以避免与 v3 event DownloadError 冲突)
/// </summary>
[Obsolete("Use DownloadError event instead.")]
public delegate void DownloadErrorDelegate(DownloadErrorData data);
/// <summary>
/// v2.3 开始下载文件回调委托
/// </summary>
[Obsolete("Use DownloadFileStarted event instead.")]
public delegate void DownloadFileBeginDelegate(DownloadFileData data);
/// <summary>
/// v2.3 下载器结束数据
/// </summary>
[Obsolete("Use DownloadCompletedEventArgs instead.")]
public struct DownloaderFinishData
{
public string PackageName;
public bool Succeed;
}
/// <summary>
/// v2.3 下载进度更新数据
/// </summary>
[Obsolete("Use DownloadProgressChangedEventArgs instead.")]
public struct DownloadUpdateData
{
public string PackageName;
public float Progress;
public int TotalDownloadCount;
public int CurrentDownloadCount;
public long TotalDownloadBytes;
public long CurrentDownloadBytes;
}
/// <summary>
/// v2.3 下载错误数据
/// </summary>
[Obsolete("Use DownloadErrorEventArgs instead.")]
public struct DownloadErrorData
{
public string PackageName;
public string FileName;
public string ErrorInfo;
}
/// <summary>
/// v2.3 下载文件数据
/// </summary>
[Obsolete("Use DownloadFileStartedEventArgs instead.")]
public struct DownloadFileData
{
public string PackageName;
public string FileName;
public long FileSize;
}
#endregion
public abstract partial class DownloaderOperation
{
private DownloaderFinish _downloadFinishCallback;
private DownloadUpdateDelegate _downloadUpdateCallback;
private DownloadErrorDelegate _downloadErrorCallback;
private DownloadFileBeginDelegate _downloadFileBeginCallback;
private bool _finishBridged;
private bool _updateBridged;
private bool _errorBridged;
private bool _fileBeginBridged;
[Obsolete("Use DownloadCompleted event instead.")]
public DownloaderFinish DownloadFinishCallback
{
get => _downloadFinishCallback;
set
{
_downloadFinishCallback = value;
if (!_finishBridged && value != null)
{
_finishBridged = true;
DownloadCompleted += args =>
{
_downloadFinishCallback?.Invoke(new DownloaderFinishData
{
PackageName = args.PackageName,
Succeed = args.Succeeded
});
};
}
}
}
[Obsolete("Use DownloadProgressChanged event instead.")]
public DownloadUpdateDelegate DownloadUpdateCallback
{
get => _downloadUpdateCallback;
set
{
_downloadUpdateCallback = value;
if (!_updateBridged && value != null)
{
_updateBridged = true;
DownloadProgressChanged += args =>
{
_downloadUpdateCallback?.Invoke(new DownloadUpdateData
{
PackageName = args.PackageName,
Progress = args.Progress,
TotalDownloadCount = args.TotalDownloadCount,
CurrentDownloadCount = args.CurrentDownloadCount,
TotalDownloadBytes = args.TotalDownloadBytes,
CurrentDownloadBytes = args.CurrentDownloadBytes
});
};
}
}
}
[Obsolete("Use DownloadError event instead.")]
public DownloadErrorDelegate DownloadErrorCallback
{
get => _downloadErrorCallback;
set
{
_downloadErrorCallback = value;
if (!_errorBridged && value != null)
{
_errorBridged = true;
DownloadError += args =>
{
_downloadErrorCallback?.Invoke(new DownloadErrorData
{
PackageName = args.PackageName,
FileName = args.FileName,
ErrorInfo = args.ErrorInfo
});
};
}
}
}
[Obsolete("Use DownloadFileStarted event instead.")]
public DownloadFileBeginDelegate DownloadFileBeginCallback
{
get => _downloadFileBeginCallback;
set
{
_downloadFileBeginCallback = value;
if (!_fileBeginBridged && value != null)
{
_fileBeginBridged = true;
DownloadFileStarted += args =>
{
_downloadFileBeginCallback?.Invoke(new DownloadFileData
{
PackageName = args.PackageName,
FileName = args.FileName,
FileSize = args.FileSize
});
};
}
}
}
[Obsolete("Use StartDownload() instead.")]
public void BeginDownload() => StartDownload();
}
}
#endif

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ec9d17e765ccd4642aa3aa9ca0580799
guid: 5c410769c5f99174897f030039b64116
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,293 @@
#if YOOASSET_LEGACY_API
// YooAsset v2.3 兼容层 - 文件系统参数兼容
// 通过 partial class 为 FileSystemParameters 补充 v2.3 旧工厂方法,
// 并恢复 FileSystemParametersDefine、IRemoteServices、IManifestRestoreServices 等旧类型。
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace YooAsset
{
#region FileSystemParameters partial
public partial class FileSystemParameters
{
/// <summary>
/// v2.3 属性名,转发到 v3 的 FileSystemTypeName
/// </summary>
[Obsolete("Use FileSystemTypeName instead.")]
public string FileSystemClass
{
get { return FileSystemTypeName; }
}
/// <summary>
/// 兼容 v2.3 REMOTE_SERVICES 参数对象
/// </summary>
[Obsolete("Use AddParameter(EFileSystemParameter.RemoteService, IRemoteService) instead.")]
public void AddParameter(string paramName, IRemoteServices value)
{
if (paramName == FileSystemParametersDefine.REMOTE_SERVICES && value != null)
AddParameter(paramName, new RemoteServicesAdapter(value));
else
AddParameter(paramName, (object)value);
}
/// <summary>
/// 兼容 v2.3 MANIFEST_SERVICES 参数对象
/// </summary>
[Obsolete("Use AddParameter(EFileSystemParameter.ManifestDecryptor, IManifestDecryptor) instead.")]
public void AddParameter(string paramName, IManifestRestoreServices value)
{
if (paramName == FileSystemParametersDefine.MANIFEST_SERVICES && value != null)
AddParameter(paramName, new ManifestRestoreServicesAdapter(value));
else
AddParameter(paramName, (object)value);
}
/// <summary>
/// 兼容 v2.3 INSTALL_CLEAR_MODE 枚举值
/// </summary>
[Obsolete("Use AddParameter(EFileSystemParameter.InstallCleanupMode, EInstallCleanupMode) instead.")]
public void AddParameter(string paramName, EOverwriteInstallClearMode value)
{
if (paramName == FileSystemParametersDefine.INSTALL_CLEAR_MODE)
AddParameter(paramName, (EInstallCleanupMode)(int)value);
else
AddParameter(paramName, (object)value);
}
/// <summary>
/// v2.3 旧拼写入口,转发到 CreateDefaultBuiltinFileSystemParameters
/// </summary>
[Obsolete("Use CreateDefaultBuiltinFileSystemParameters instead. IDecryptionServices is no longer supported; pass null or migrate to IBundleDecryptor.")]
public static FileSystemParameters CreateDefaultBuildinFileSystemParameters(IDecryptionServices decryptionServices = null, string packageRoot = null)
{
return CreateDefaultBuiltinFileSystemParameters(packageRoot);
}
/// <summary>
/// v2.3 缓存文件系统入口,转发到 CreateDefaultSandboxFileSystemParameters
/// </summary>
[Obsolete("Use CreateDefaultSandboxFileSystemParameters instead. IDecryptionServices is no longer supported; pass null or migrate to IBundleDecryptor.")]
public static FileSystemParameters CreateDefaultCacheFileSystemParameters(IRemoteServices remoteServices, IDecryptionServices decryptionServices = null, string packageRoot = null)
{
var adapter = remoteServices != null ? new RemoteServicesAdapter(remoteServices) : null;
return CreateDefaultSandboxFileSystemParameters(adapter, packageRoot);
}
/// <summary>
/// v2.3 WebServer 文件系统入口
/// </summary>
[Obsolete("Use CreateDefaultWebServerFileSystemParameters(bool) instead. IWebDecryptionServices is no longer supported.")]
public static FileSystemParameters CreateDefaultWebServerFileSystemParameters(IWebDecryptionServices decryptionServices, bool disableUnityWebCache = false)
{
return CreateDefaultWebServerFileSystemParameters(disableUnityWebCache);
}
/// <summary>
/// v2.3 WebRemote 文件系统入口
/// </summary>
[Obsolete("Use CreateDefaultWebRemoteFileSystemParameters(IRemoteService, bool) instead. IWebDecryptionServices is no longer supported.")]
public static FileSystemParameters CreateDefaultWebRemoteFileSystemParameters(IRemoteServices remoteServices, IWebDecryptionServices decryptionServices = null, bool disableUnityWebCache = false)
{
var adapter = remoteServices != null ? new RemoteServicesAdapter(remoteServices) : null;
return CreateDefaultWebRemoteFileSystemParameters(adapter, disableUnityWebCache);
}
}
#endregion
#region FileSystemParametersDefine
/// <summary>
/// v2.3 文件系统参数常量定义
/// </summary>
[Obsolete("Use EFileSystemParameter enum instead.")]
public static class FileSystemParametersDefine
{
public const string FILE_VERIFY_LEVEL = "FileVerifyLevel";
public const string FILE_VERIFY_MAX_CONCURRENCY = "FileVerifyMaxConcurrency";
public const string INSTALL_CLEAR_MODE = "InstallCleanupMode";
public const string REMOTE_SERVICES = "RemoteService";
public const string DECRYPTION_SERVICES = "DECRYPTION_SERVICES";
public const string MANIFEST_SERVICES = "ManifestDecryptor";
public const string APPEND_FILE_EXTENSION = "APPEND_FILE_EXTENSION";
public const string DISABLE_CATALOG_FILE = "DISABLE_CATALOG_FILE";
public const string DISABLE_UNITY_WEB_CACHE = "DisableUnityWebCache";
public const string DISABLE_ONDEMAND_DOWNLOAD = "DownloadDisableOndemand";
public const string DOWNLOAD_MAX_CONCURRENCY = "DownloadMaxConcurrency";
public const string DOWNLOAD_MAX_REQUEST_PER_FRAME = "DownloadMaxRequestPerFrame";
public const string DOWNLOAD_WATCH_DOG_TIME = "DownloadWatchdogTimeout";
public const string RESUME_DOWNLOAD_MINMUM_SIZE = "DownloadResumeMinimumSize";
public const string RESUME_DOWNLOAD_RESPONSE_CODES = "RESUME_DOWNLOAD_RESPONSE_CODES";
public const string VIRTUAL_WEBGL_MODE = "VirtualWebglMode";
public const string VIRTUAL_DOWNLOAD_MODE = "VirtualDownloadMode";
public const string VIRTUAL_DOWNLOAD_SPEED = "VirtualDownloadSpeed";
public const string ASYNC_SIMULATE_MIN_FRAME = "AsyncSimulateMinFrame";
public const string ASYNC_SIMULATE_MAX_FRAME = "AsyncSimulateMaxFrame";
public const string COPY_BUILDIN_PACKAGE_MANIFEST = "CopyBuiltinPackageManifest";
public const string COPY_BUILDIN_PACKAGE_MANIFEST_DEST_ROOT = "CopyBuiltinPackageManifestDestRoot";
public const string COPY_LOCAL_FILE_SERVICES = "COPY_LOCAL_FILE_SERVICES";
public const string UNPACK_FILE_SYSTEM_ROOT = "UnpackFileSystemRoot";
}
#endregion
#region EOverwriteInstallClearMode
/// <summary>
/// v2.3 覆盖安装清理模式v3 改为 EInstallCleanupMode
/// </summary>
[Obsolete("Use EInstallCleanupMode instead.")]
public enum EOverwriteInstallClearMode
{
None = 0,
ClearAllCacheFiles = 1,
ClearAllBundleFiles = 2,
ClearAllManifestFiles = 3,
}
#endregion
#region IRemoteServices
/// <summary>
/// v2.3 远端资源地址查询服务接口
/// </summary>
[Obsolete("Implement IRemoteService instead.")]
public interface IRemoteServices
{
string GetRemoteMainURL(string fileName);
string GetRemoteFallbackURL(string fileName);
}
/// <summary>
/// 将 v2.3 IRemoteServices 适配为 v3 IRemoteService
/// </summary>
internal sealed class RemoteServicesAdapter : IRemoteService
{
private readonly IRemoteServices _legacy;
public RemoteServicesAdapter(IRemoteServices legacy)
{
_legacy = legacy;
}
public IReadOnlyList<string> GetRemoteUrls(string fileName)
{
var urls = new List<string>(2);
string main = _legacy.GetRemoteMainURL(fileName);
if (!string.IsNullOrEmpty(main))
urls.Add(main);
string fallback = _legacy.GetRemoteFallbackURL(fileName);
if (!string.IsNullOrEmpty(fallback))
urls.Add(fallback);
return urls;
}
}
#endregion
#region IManifestRestoreServices
/// <summary>
/// v2.3 资源清单文件处理服务接口
/// </summary>
[Obsolete("Implement IManifestDecryptor instead.")]
public interface IManifestRestoreServices
{
byte[] RestoreManifest(byte[] fileData);
}
/// <summary>
/// 将 v2.3 IManifestRestoreServices 适配为 v3 IManifestDecryptor
/// </summary>
internal sealed class ManifestRestoreServicesAdapter : IManifestDecryptor
{
private readonly IManifestRestoreServices _legacy;
public ManifestRestoreServicesAdapter(IManifestRestoreServices legacy)
{
_legacy = legacy;
}
public byte[] Decrypt(byte[] fileData)
{
return _legacy.RestoreManifest(fileData);
}
}
#endregion
#region IDecryptionServices / IWebDecryptionServices
/// <summary>
/// v2.3 解密文件信息(仅用于旧接口编译兼容)
/// </summary>
[Obsolete("v3 has split decryption into dedicated decryptor interfaces. Manual migration required.")]
public struct DecryptFileInfo
{
public string BundleName;
public string FileLoadPath;
public uint FileLoadCRC;
}
/// <summary>
/// v2.3 解密结果(仅用于旧接口编译兼容)
/// </summary>
[Obsolete("v3 has split decryption into dedicated decryptor interfaces. Manual migration required.")]
public struct DecryptResult
{
public AssetBundle Result;
public AssetBundleCreateRequest CreateRequest;
public Stream ManagedStream;
}
/// <summary>
/// v2.3 加密文件解密服务接口(仅用于编译兼容,无法自动转换为 v3 解密器)
/// </summary>
[Obsolete("v3 has split decryption into IBundleOffsetDecryptor, IBundleMemoryDecryptor, IBundleStreamDecryptor. Manual migration required.")]
public interface IDecryptionServices
{
DecryptResult LoadAssetBundle(DecryptFileInfo fileInfo);
DecryptResult LoadAssetBundleAsync(DecryptFileInfo fileInfo);
DecryptResult LoadAssetBundleFallback(DecryptFileInfo fileInfo);
byte[] ReadFileData(DecryptFileInfo fileInfo);
string ReadFileText(DecryptFileInfo fileInfo);
}
/// <summary>
/// v2.3 Web 解密文件信息(仅用于旧接口编译兼容)
/// </summary>
[Obsolete("v3 no longer supports IWebDecryptionServices. Manual migration required.")]
public struct WebDecryptFileInfo
{
public string BundleName;
public uint FileLoadCRC;
public byte[] FileData;
}
/// <summary>
/// v2.3 Web 解密结果(仅用于旧接口编译兼容)
/// </summary>
[Obsolete("v3 no longer supports IWebDecryptionServices. Manual migration required.")]
public struct WebDecryptResult
{
public AssetBundle Result;
}
/// <summary>
/// v2.3 Web 解密服务接口(仅用于编译兼容,无法自动转换为 v3 解密器)
/// </summary>
[Obsolete("v3 no longer supports IWebDecryptionServices. Manual migration required.")]
public interface IWebDecryptionServices
{
WebDecryptResult LoadAssetBundle(WebDecryptFileInfo fileInfo);
}
#endregion
}
#endif

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b974d3d744622f3499d026f99074cd72
guid: a0283a72bdff8b54b93d9807ba038dbf
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,207 @@
#if YOOASSET_LEGACY_API
// YooAsset v2.3 兼容层 - Handle 类兼容
// 通过 partial class 为各 Handle 类补充 v2.3 的旧属性和方法。
using System;
using System.Threading.Tasks;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// v2.3 下载状态结构体v3 已移除)
/// </summary>
[Obsolete("DownloadStatus has been removed in v3.")]
public struct DownloadStatus
{
public bool IsDone;
public float Progress;
public long TotalBytes;
public long DownloadedBytes;
public static DownloadStatus CreateDefaultStatus()
{
return new DownloadStatus();
}
}
#region HandleBase -- LastError / Task / GetDownloadStatus
public abstract partial class HandleBase
{
private TaskCompletionSource<object> _taskCompletionSource;
/// <summary>
/// v2.3: handle.LastError
/// </summary>
[Obsolete("Use Error instead.")]
public string LastError => Error;
/// <summary>
/// v2.3: handle.Task (System.Threading.Tasks.Task)
/// </summary>
[Obsolete("Use 'await handle' directly instead.")]
public Task Task
{
get
{
if (CheckValidWithWarning() == false)
return null;
if (_taskCompletionSource == null)
{
_taskCompletionSource = new TaskCompletionSource<object>();
if (Provider.IsDone)
{
_taskCompletionSource.TrySetResult(null);
}
else
{
Provider.Completed += delegate (AsyncOperationBase op)
{
_taskCompletionSource.TrySetResult(null);
};
}
}
return _taskCompletionSource.Task;
}
}
/// <summary>
/// v2.3: handle.GetDownloadStatus()
/// </summary>
[Obsolete("GetDownloadStatus is no longer supported in v3.")]
public DownloadStatus GetDownloadStatus()
{
return DownloadStatus.CreateDefaultStatus();
}
}
#endregion
#region SceneHandle -- UnSuspend / UnloadAsync
public sealed partial class SceneHandle
{
/// <summary>
/// v2.3: sceneHandle.UnSuspend() -> v3: AllowSceneActivation()
/// </summary>
[Obsolete("Use AllowSceneActivation() instead.")]
public bool UnSuspend() => AllowSceneActivation();
/// <summary>
/// v2.3: sceneHandle.UnloadAsync() -> v3: UnloadSceneAsync()
/// </summary>
[Obsolete("Use UnloadSceneAsync() instead.")]
public UnloadSceneOperation UnloadAsync() => UnloadSceneAsync();
}
#endregion
#region RawFileHandle -- GetRawFileData / GetRawFileText
public sealed partial class RawFileHandle
{
/// <summary>
/// v2.3: rawFileHandle.GetRawFileData()
/// </summary>
[Obsolete("Read file manually via GetRawFilePath().")]
public byte[] GetRawFileData()
{
if (CheckValidWithWarning() == false) return null;
return System.IO.File.ReadAllBytes(GetRawFilePath());
}
/// <summary>
/// v2.3: rawFileHandle.GetRawFileText()
/// </summary>
[Obsolete("Read file manually via GetRawFilePath().")]
public string GetRawFileText()
{
if (CheckValidWithWarning() == false) return null;
return System.IO.File.ReadAllText(GetRawFilePath());
}
}
#endregion
#region AssetHandle -- Instantiate
public sealed partial class AssetHandle
{
/// <summary>
/// v2.3: handle.InstantiateSync(parent)
/// </summary>
[Obsolete("Use InstantiateSync(InstantiateOptions) instead.")]
public GameObject InstantiateSync(Transform parent)
{
var options = new InstantiateOptions(true, parent, false);
return InstantiateSync(options);
}
/// <summary>
/// v2.3: handle.InstantiateSync(parent, worldPositionStays)
/// </summary>
[Obsolete("Use InstantiateSync(InstantiateOptions) instead.")]
public GameObject InstantiateSync(Transform parent, bool worldPositionStays)
{
var options = new InstantiateOptions(true, parent, worldPositionStays);
return InstantiateSync(options);
}
/// <summary>
/// v2.3: handle.InstantiateSync(position, rotation)
/// </summary>
[Obsolete("Use InstantiateSync(InstantiateOptions) instead.")]
public GameObject InstantiateSync(Vector3 position, Quaternion rotation)
{
var options = new InstantiateOptions(true, position, rotation);
return InstantiateSync(options);
}
/// <summary>
/// v2.3: handle.InstantiateSync(position, rotation, parent)
/// </summary>
[Obsolete("Use InstantiateSync(InstantiateOptions) instead.")]
public GameObject InstantiateSync(Vector3 position, Quaternion rotation, Transform parent)
{
var options = new InstantiateOptions(true, parent, position, rotation);
return InstantiateSync(options);
}
/// <summary>
/// v2.3: handle.InstantiateAsync(parent, actived)
/// </summary>
[Obsolete("Use InstantiateAsync(InstantiateOptions) instead.")]
public InstantiateOperation InstantiateAsync(Transform parent, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, false);
return InstantiateAsync(options);
}
/// <summary>
/// v2.3: handle.InstantiateAsync(parent, worldPositionStays, actived)
/// </summary>
[Obsolete("Use InstantiateAsync(InstantiateOptions) instead.")]
public InstantiateOperation InstantiateAsync(Transform parent, bool worldPositionStays, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, worldPositionStays);
return InstantiateAsync(options);
}
/// <summary>
/// v2.3: handle.InstantiateAsync(position, rotation, actived)
/// </summary>
[Obsolete("Use InstantiateAsync(InstantiateOptions) instead.")]
public InstantiateOperation InstantiateAsync(Vector3 position, Quaternion rotation, bool actived = true)
{
var options = new InstantiateOptions(actived, position, rotation);
return InstantiateAsync(options);
}
/// <summary>
/// v2.3: handle.InstantiateAsync(position, rotation, parent, actived)
/// </summary>
[Obsolete("Use InstantiateAsync(InstantiateOptions) instead.")]
public InstantiateOperation InstantiateAsync(Vector3 position, Quaternion rotation, Transform parent, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, position, rotation);
return InstantiateAsync(options);
}
}
#endregion
}
#endif

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 41ab464f315df234fb40b0c24e97ee23
guid: 2c3bc780b23878f4f952d53fe28bf325
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,219 @@
#if YOOASSET_LEGACY_API
// YooAsset v2.3 兼容层 - Operation 类型
// 提供 v2.3 的 InitializeParameters 类族、Operation 包装类、ImportFileInfo 和 GameAsyncOperation。
using System;
namespace YooAsset
{
#region InitializeParameters
/// <summary>
/// v2.3 初始化参数基类
/// </summary>
[Obsolete("Use specific Options classes (e.g. EditorSimulateModeOptions) instead.")]
public abstract class InitializeParameters
{
public int BundleLoadingMaxConcurrency = int.MaxValue;
public bool AutoUnloadBundleWhenUnused = false;
public bool WebGLForceSyncLoadAsset = false;
}
/// <summary>
/// v2.3 编辑器模拟模式初始化参数
/// </summary>
[Obsolete("Use EditorSimulateModeOptions instead.")]
public class EditorSimulateModeParameters : InitializeParameters
{
public FileSystemParameters EditorFileSystemParameters;
}
/// <summary>
/// v2.3 离线运行模式初始化参数
/// </summary>
[Obsolete("Use OfflinePlayModeOptions instead.")]
public class OfflinePlayModeParameters : InitializeParameters
{
public FileSystemParameters BuildinFileSystemParameters;
}
/// <summary>
/// v2.3 联机运行模式初始化参数
/// </summary>
[Obsolete("Use HostPlayModeOptions instead.")]
public class HostPlayModeParameters : InitializeParameters
{
public FileSystemParameters BuildinFileSystemParameters;
public FileSystemParameters CacheFileSystemParameters;
}
/// <summary>
/// v2.3 WebGL 运行模式初始化参数
/// </summary>
[Obsolete("Use WebPlayModeOptions instead.")]
public class WebPlayModeParameters : InitializeParameters
{
public FileSystemParameters WebServerFileSystemParameters;
public FileSystemParameters WebRemoteFileSystemParameters;
}
/// <summary>
/// v2.3 自定义运行模式初始化参数
/// </summary>
[Obsolete("Use CustomPlayModeOptions instead.")]
public class CustomPlayModeParameters : InitializeParameters
{
public readonly System.Collections.Generic.List<FileSystemParameters> FileSystemParameterList = new System.Collections.Generic.List<FileSystemParameters>();
}
#endregion
#region LegacyOperationWrapper
/// <summary>
/// v2.3 Operation 包装基类,将 v3 的 AsyncOperationBase 转发为旧类型。
/// </summary>
[Obsolete("Use v3 operation types directly.")]
public class LegacyOperationWrapper : AsyncOperationBase
{
private bool _isDone = false;
protected readonly AsyncOperationBase _operation;
internal LegacyOperationWrapper(AsyncOperationBase op)
{
_operation = op;
}
protected override void InternalStart()
{
}
protected override void InternalUpdate()
{
if (_isDone)
return;
if (IsWaitForCompletion)
_operation.WaitForCompletion();
_operation.UpdateOperation();
Progress = _operation.Progress;
if (_operation.IsDone == false)
return;
_isDone = true;
if (_operation.Status == EOperationStatus.Succeeded)
SetResult();
else
SetError(_operation.Error);
}
protected override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
#endregion
#region Legacy Operations
[Obsolete("Use InitializePackageOperation instead.")]
public class InitializationOperation : LegacyOperationWrapper
{
internal InitializationOperation(InitializePackageOperation op) : base(op) { }
}
[Obsolete("Use DestroyPackageOperation instead.")]
public class DestroyOperation : LegacyOperationWrapper
{
internal DestroyOperation(DestroyPackageOperation op) : base(op) { }
}
[Obsolete("Use LoadPackageManifestOperation instead.")]
public class UpdatePackageManifestOperation : LegacyOperationWrapper
{
internal UpdatePackageManifestOperation(LoadPackageManifestOperation op) : base(op) { }
}
[Obsolete("Use PrefetchManifestOperation instead.")]
public class PreDownloadContentOperation : LegacyOperationWrapper
{
private readonly PrefetchManifestOperation _prefetchOp;
internal PreDownloadContentOperation(PrefetchManifestOperation op) : base(op)
{
_prefetchOp = op;
}
[Obsolete("Use PrefetchManifestOperation.CreateResourceDownloader(ResourceDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateResourceDownloader(int downloadingMaxNumber, int failedTryAgain)
{
var options = new ResourceDownloaderOptions(downloadingMaxNumber, failedTryAgain);
return _prefetchOp.CreateResourceDownloader(options);
}
[Obsolete("Use PrefetchManifestOperation.CreateResourceDownloader(ResourceDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateResourceDownloader(string tag, int downloadingMaxNumber, int failedTryAgain)
{
string[] tags = new string[] { tag };
var options = new ResourceDownloaderOptions(tags, downloadingMaxNumber, failedTryAgain);
return _prefetchOp.CreateResourceDownloader(options);
}
[Obsolete("Use PrefetchManifestOperation.CreateResourceDownloader(ResourceDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateResourceDownloader(string[] tags, int downloadingMaxNumber, int failedTryAgain)
{
var options = new ResourceDownloaderOptions(tags, downloadingMaxNumber, failedTryAgain);
return _prefetchOp.CreateResourceDownloader(options);
}
}
#endregion
#region ImportFileInfo
/// <summary>
/// v2.3 导入文件信息
/// </summary>
[Obsolete("Use ImportBundleInfo instead.")]
public struct ImportFileInfo
{
public string FilePath;
public string BundleName;
public string BundleGUID;
}
#endregion
#region GameAsyncOperation
/// <summary>
/// v2.3 游戏异步操作基类v3 已移除)
/// </summary>
[Obsolete("GameAsyncOperation has been removed in v3. Use AsyncOperationBase directly.")]
public abstract class GameAsyncOperation : AsyncOperationBase
{
protected override void InternalStart()
{
OnStart();
}
protected override void InternalUpdate()
{
OnUpdate();
}
protected override void InternalAbort()
{
OnAbort();
}
protected override void InternalWaitForCompletion()
{
OnWaitForAsyncComplete();
}
protected abstract void OnStart();
protected abstract void OnUpdate();
protected abstract void OnAbort();
protected virtual void OnWaitForAsyncComplete() { }
protected new bool IsBusy
{
get { return AsyncOperationSystem.IsBusy; }
}
protected void Abort()
{
AbortOperation();
}
}
#endregion
}
#endif

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 19ed2b81fece5b84fa771a5eeb108572
guid: f16ea24f57c29f74babb8169fb1fa7a6
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,334 @@
#if YOOASSET_LEGACY_API
// YooAsset v2.3 兼容层 - ResourcePackage 兼容方法
// 通过 partial class 为 ResourcePackage 补充 v2.3 的旧接口。
using System;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// v2.3 缓存清理模式v3 改用字符串参数)
/// </summary>
[Obsolete("Use string-based ClearCacheOptions instead.")]
public enum EFileClearMode
{
ClearAllBundleFiles,
ClearUnusedBundleFiles,
ClearBundleFilesByLocations,
ClearBundleFilesByTags,
ClearAllManifestFiles,
ClearUnusedManifestFiles,
}
public partial class ResourcePackage
{
#region /
[Obsolete("Use InitializePackageAsync(options) instead.")]
public InitializationOperation InitializeAsync(InitializeParameters parameters)
{
if (parameters is EditorSimulateModeParameters esp)
{
var options = new EditorSimulateModeOptions();
options.BundleLoadingMaxConcurrency = esp.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = esp.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = esp.WebGLForceSyncLoadAsset;
options.EditorFileSystemParameters = esp.EditorFileSystemParameters;
var operation = InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(PackageName, wrapper);
return wrapper;
}
else if (parameters is OfflinePlayModeParameters opp)
{
var options = new OfflinePlayModeOptions();
options.BundleLoadingMaxConcurrency = opp.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = opp.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = opp.WebGLForceSyncLoadAsset;
options.BuiltinFileSystemParameters = opp.BuildinFileSystemParameters;
var operation = InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(PackageName, wrapper);
return wrapper;
}
else if (parameters is HostPlayModeParameters hpp)
{
var options = new HostPlayModeOptions();
options.BundleLoadingMaxConcurrency = hpp.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = hpp.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = hpp.WebGLForceSyncLoadAsset;
options.BuiltinFileSystemParameters = hpp.BuildinFileSystemParameters;
options.CacheFileSystemParameters = hpp.CacheFileSystemParameters;
var operation = InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(PackageName, wrapper);
return wrapper;
}
else if (parameters is WebPlayModeParameters wpp)
{
var options = new WebPlayModeOptions();
options.BundleLoadingMaxConcurrency = wpp.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = wpp.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = wpp.WebGLForceSyncLoadAsset;
options.WebServerFileSystemParameters = wpp.WebServerFileSystemParameters;
options.WebRemoteFileSystemParameters = wpp.WebRemoteFileSystemParameters;
var operation = InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(PackageName, wrapper);
return wrapper;
}
else if (parameters is CustomPlayModeParameters cpp)
{
var options = new CustomPlayModeOptions();
options.BundleLoadingMaxConcurrency = cpp.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = cpp.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = cpp.WebGLForceSyncLoadAsset;
foreach (var fsp in cpp.FileSystemParameterList)
options.FileSystemParameterList.Add(fsp);
var operation = InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(PackageName, wrapper);
return wrapper;
}
else
{
throw new NotImplementedException($"Unsupported InitializeParameters type: {parameters.GetType().Name}");
}
}
[Obsolete("Use DestroyPackageAsync() instead.")]
public DestroyOperation DestroyAsync()
{
var operation = DestroyPackageAsync();
var wrapper = new DestroyOperation(operation);
AsyncOperationSystem.StartOperation(AsyncOperationSystem.GlobalSchedulerName, wrapper);
return wrapper;
}
#endregion
#region /
[Obsolete("Use RequestPackageVersionAsync(RequestPackageVersionOptions) instead.")]
public RequestPackageVersionOperation RequestPackageVersionAsync(bool appendTimeTicks, int timeout)
{
var options = new RequestPackageVersionOptions(appendTimeTicks, timeout);
return RequestPackageVersionAsync(options);
}
[Obsolete("Use LoadPackageManifestAsync(LoadPackageManifestOptions) instead.")]
public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout = 60)
{
var options = new LoadPackageManifestOptions(packageVersion, timeout);
var operation = LoadPackageManifestAsync(options);
var wrapper = new UpdatePackageManifestOperation(operation);
AsyncOperationSystem.StartOperation(PackageName, wrapper);
return wrapper;
}
[Obsolete("Use PrefetchManifestAsync(PrefetchManifestOptions) instead.")]
public PreDownloadContentOperation PreDownloadContentAsync(string packageVersion, int timeout = 60)
{
var options = new PrefetchManifestOptions(packageVersion, timeout);
var op = PrefetchManifestAsync(options);
var wrapper = new PreDownloadContentOperation(op);
AsyncOperationSystem.StartOperation(PackageName, wrapper);
return wrapper;
}
#endregion
#region
[Obsolete("Use ClearCacheAsync(ClearCacheOptions) instead.")]
public ClearCacheOperation ClearCacheFilesAsync(string fileClearMode, object clearParam = null)
{
var options = new ClearCacheOptions(fileClearMode, clearParam);
return ClearCacheAsync(options);
}
[Obsolete("Use ClearCacheAsync(ClearCacheOptions) instead.")]
public ClearCacheOperation ClearCacheFilesAsync(EFileClearMode clearMode, object clearParam = null)
{
var options = new ClearCacheOptions(clearMode.ToString(), clearParam);
return ClearCacheAsync(options);
}
#endregion
#region
[Obsolete("Use UnloadUnusedAssetsAsync(UnloadUnusedAssetsOptions) instead.")]
public UnloadUnusedAssetsOperation UnloadUnusedAssetsAsync(int loopCount)
{
var options = new UnloadUnusedAssetsOptions(loopCount);
return UnloadUnusedAssetsAsync(options);
}
#endregion
#region
[Obsolete("Use GetDownloadSize() instead.")]
public bool IsNeedDownloadFromRemote(string location)
{
return GetDownloadSize(location) > 0;
}
[Obsolete("Use GetDownloadSize() instead.")]
public bool IsNeedDownloadFromRemote(AssetInfo assetInfo)
{
return GetDownloadSize(assetInfo) > 0;
}
[Obsolete("Use IsLocationValid() instead.")]
public bool CheckLocationValid(string location)
{
return IsLocationValid(location);
}
[Obsolete("Use GetAssetInfoByGuid() instead.")]
public AssetInfo GetAssetInfoByGUID(string assetGUID)
{
return GetAssetInfoByGuid(assetGUID);
}
[Obsolete("Use GetAssetInfoByGuid() instead.")]
public AssetInfo GetAssetInfoByGUID(string assetGUID, Type type)
{
return GetAssetInfoByGuid(assetGUID, type);
}
#endregion
#region
[Obsolete("Use CreateResourceDownloader(ResourceDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateResourceDownloader(int downloadingMaxNumber, int failedTryAgain)
{
var options = new ResourceDownloaderOptions(downloadingMaxNumber, failedTryAgain);
return CreateResourceDownloader(options);
}
[Obsolete("Use CreateResourceDownloader(ResourceDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateResourceDownloader(string tag, int downloadingMaxNumber, int failedTryAgain)
{
string[] tags = new string[] { tag };
var options = new ResourceDownloaderOptions(tags, downloadingMaxNumber, failedTryAgain);
return CreateResourceDownloader(options);
}
[Obsolete("Use CreateResourceDownloader(ResourceDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateResourceDownloader(string[] tags, int downloadingMaxNumber, int failedTryAgain)
{
var options = new ResourceDownloaderOptions(tags, downloadingMaxNumber, failedTryAgain);
return CreateResourceDownloader(options);
}
[Obsolete("Use CreateResourceDownloader(BundleDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateBundleDownloader(string location, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
var assetInfo = ConvertLocationToAssetInfo(location, null);
var options = new BundleDownloaderOptions(assetInfo, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return CreateResourceDownloader(options);
}
[Obsolete("Use CreateResourceDownloader(BundleDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateBundleDownloader(string location, int downloadingMaxNumber, int failedTryAgain)
{
return CreateBundleDownloader(location, false, downloadingMaxNumber, failedTryAgain);
}
[Obsolete("Use CreateResourceDownloader(BundleDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateBundleDownloader(string[] locations, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
List<AssetInfo> assetInfos = new List<AssetInfo>(locations.Length);
foreach (var location in locations)
{
var assetInfo = ConvertLocationToAssetInfo(location, null);
assetInfos.Add(assetInfo);
}
var options = new BundleDownloaderOptions(assetInfos.ToArray(), recursiveDownload, downloadingMaxNumber, failedTryAgain);
return CreateResourceDownloader(options);
}
[Obsolete("Use CreateResourceDownloader(BundleDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateBundleDownloader(string[] locations, int downloadingMaxNumber, int failedTryAgain)
{
return CreateBundleDownloader(locations, false, downloadingMaxNumber, failedTryAgain);
}
[Obsolete("Use CreateResourceDownloader(BundleDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateBundleDownloader(AssetInfo assetInfo, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
AssetInfo[] assetInfos = new AssetInfo[] { assetInfo };
var options = new BundleDownloaderOptions(assetInfos, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return CreateResourceDownloader(options);
}
[Obsolete("Use CreateResourceDownloader(BundleDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateBundleDownloader(AssetInfo assetInfo, int downloadingMaxNumber, int failedTryAgain)
{
return CreateBundleDownloader(assetInfo, false, downloadingMaxNumber, failedTryAgain);
}
[Obsolete("Use CreateResourceDownloader(BundleDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateBundleDownloader(AssetInfo[] assetInfos, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
var options = new BundleDownloaderOptions(assetInfos, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return CreateResourceDownloader(options);
}
[Obsolete("Use CreateResourceDownloader(BundleDownloaderOptions) instead.")]
public ResourceDownloaderOperation CreateBundleDownloader(AssetInfo[] assetInfos, int downloadingMaxNumber, int failedTryAgain)
{
return CreateBundleDownloader(assetInfos, false, downloadingMaxNumber, failedTryAgain);
}
#endregion
#region
[Obsolete("Use CreateResourceUnpacker(ResourceUnpackerOptions) instead.")]
public ResourceUnpackerOperation CreateResourceUnpacker(int unpackingMaxNumber, int failedTryAgain)
{
var options = new ResourceUnpackerOptions(unpackingMaxNumber, failedTryAgain);
return CreateResourceUnpacker(options);
}
[Obsolete("Use CreateResourceUnpacker(ResourceUnpackerOptions) instead.")]
public ResourceUnpackerOperation CreateResourceUnpacker(string tag, int unpackingMaxNumber, int failedTryAgain)
{
string[] tags = new string[] { tag };
var options = new ResourceUnpackerOptions(tags, unpackingMaxNumber, failedTryAgain);
return CreateResourceUnpacker(options);
}
[Obsolete("Use CreateResourceUnpacker(ResourceUnpackerOptions) instead.")]
public ResourceUnpackerOperation CreateResourceUnpacker(string[] tags, int unpackingMaxNumber, int failedTryAgain)
{
var options = new ResourceUnpackerOptions(tags, unpackingMaxNumber, failedTryAgain);
return CreateResourceUnpacker(options);
}
#endregion
#region
[Obsolete("Use CreateResourceImporter(BundleImporterOptions) instead.")]
public ResourceImporterOperation CreateResourceImporter(string[] filePaths, int importerMaxNumber, int failedTryAgain)
{
ImportFileInfo[] fileInfos = new ImportFileInfo[filePaths.Length];
for (int i = 0; i < filePaths.Length; i++)
{
ImportFileInfo fileInfo = new ImportFileInfo();
fileInfo.FilePath = filePaths[i];
fileInfos[i] = fileInfo;
}
return CreateResourceImporter(fileInfos, importerMaxNumber, failedTryAgain);
}
[Obsolete("Use CreateResourceImporter(BundleImporterOptions) instead.")]
public ResourceImporterOperation CreateResourceImporter(ImportFileInfo[] fileInfos, int importerMaxNumber, int failedTryAgain)
{
ImportBundleInfo[] bundleInfos = new ImportBundleInfo[fileInfos.Length];
for (int i = 0; i < fileInfos.Length; i++)
{
bundleInfos[i] = new ImportBundleInfo(
filePath: fileInfos[i].FilePath,
bundleName: fileInfos[i].BundleName,
bundleGuid: fileInfos[i].BundleGUID);
}
var options = new BundleImporterOptions(bundleInfos, importerMaxNumber, failedTryAgain);
return CreateResourceImporter(options);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fcb10923f246d8844b4980dcb84bec86
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
#if YOOASSET_LEGACY_API
// YooAsset v2.3 兼容层 - YooAssets 静态类兼容
// 通过 partial class 为 YooAssets 补充 v2.3 的旧静态属性和方法。
using System;
using System.Collections.Generic;
using System.Linq;
namespace YooAsset
{
public static partial class YooAssets
{
/// <summary>
/// v2.3: YooAssets.Initialized
/// </summary>
[Obsolete("Use IsInitialized instead.")]
public static bool Initialized => IsInitialized;
/// <summary>
/// v2.3: YooAssets.GetAllPackages()
/// </summary>
[Obsolete("Use GetPackages() instead.")]
public static List<ResourcePackage> GetAllPackages()
{
return GetPackages().ToList();
}
/// <summary>
/// v2.3: YooAssets.TryGetPackage(string)
/// </summary>
[Obsolete("Use TryGetPackage(string, out ResourcePackage) instead.")]
public static ResourcePackage TryGetPackage(string packageName)
{
TryGetPackage(packageName, out var package);
return package;
}
/// <summary>
/// v2.3: YooAssets.RemovePackage(ResourcePackage)
/// </summary>
[Obsolete("Use RemovePackage(string) instead.")]
public static bool RemovePackage(ResourcePackage package)
{
try
{
RemovePackage(package.PackageName);
return true;
}
catch
{
return false;
}
}
/// <summary>
/// v2.3: YooAssets.SetOperationSystemMaxTimeSlice(long)
/// </summary>
[Obsolete("Use SetAsyncOperationMaxTimeSlice() instead.")]
public static void SetOperationSystemMaxTimeSlice(long milliseconds)
{
SetAsyncOperationMaxTimeSlice(milliseconds);
}
/// <summary>
/// v2.3: YooAssets.SetDownloadSystemUnityWebRequest(delegate)
/// </summary>
[Obsolete("This API has been removed in v3.")]
public static void SetDownloadSystemUnityWebRequest(object createDelegate)
{
throw new System.NotImplementedException();
}
/// <summary>
/// v2.3: YooAssets.StartOperation(GameAsyncOperation)
/// </summary>
[Obsolete("GameAsyncOperation has been removed in v3.")]
public static void StartOperation(GameAsyncOperation operation)
{
AsyncOperationSystem.StartOperation(AsyncOperationSystem.GlobalSchedulerName, operation);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 93e9bc10b05be8b42a704832abed581d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,230 @@
# YooAsset v2.3 → v3.x 迁移指南
本兼容层允许大部分 v2.3 业务代码在 v3.x 下**零修改编译通过**。所有兼容 API 均标记了 `[Obsolete]`,编译时会输出警告提示迁移到 v3 新接口。
## 启用兼容层
兼容代码默认**不参与编译**,需要手动添加编译宏才能启用:
**Unity Editor**`Edit → Project Settings → Player → Scripting Define Symbols`,添加 `YOOASSET_LEGACY_API`
添加后重新编译即可生效。当所有业务代码已迁移到 v3 新接口后,移除该宏即可彻底关闭兼容层。
---
## 一、API 对照表(自动兼容,无需修改代码)
### 1.1 枚举与状态
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `EOperationStatus.Succeed` | `EOperationStatus.Succeeded` |
| `EFileClearMode.ClearAllBundleFiles` | `"ClearAllBundleFiles"` (字符串) |
| `EPlayMode.HostPlayMode` | 已移除(用 Options 类代替) |
| `handle.GetDownloadStatus()` | 已移除 |
### 1.2 HandleBase
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `handle.LastError` | `handle.Error` |
| `await handle.Task` | `await handle` |
| `handle.GetDownloadStatus()` | 已移除 |
### 1.3 SceneHandle
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `sceneHandle.UnSuspend()` | `sceneHandle.AllowSceneActivation()` |
| `sceneHandle.UnloadAsync()` | `sceneHandle.UnloadSceneAsync()` |
### 1.4 RawFileHandle
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `rawHandle.GetRawFileData()` | `File.ReadAllBytes(rawHandle.GetRawFilePath())` |
| `rawHandle.GetRawFileText()` | `File.ReadAllText(rawHandle.GetRawFilePath())` |
### 1.5 AssetHandle 实例化
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `handle.InstantiateSync(parent)` | `handle.InstantiateSync(new InstantiateOptions(...))` |
| `handle.InstantiateSync(parent, worldPositionStays)` | 同上 |
| `handle.InstantiateSync(position, rotation)` | 同上 |
| `handle.InstantiateSync(position, rotation, parent)` | 同上 |
| `handle.InstantiateAsync(parent, actived)` | `handle.InstantiateAsync(new InstantiateOptions(...))` |
| `handle.InstantiateAsync(parent, worldPositionStays, actived)` | 同上 |
| `handle.InstantiateAsync(position, rotation, actived)` | 同上 |
| `handle.InstantiateAsync(position, rotation, parent, actived)` | 同上 |
### 1.6 DownloaderOperation
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `downloader.BeginDownload()` | `downloader.StartDownload()` |
| `downloader.DownloadFinishCallback = ...` | `downloader.DownloadCompleted += ...` |
| `downloader.DownloadUpdateCallback = ...` | `downloader.DownloadProgressChanged += ...` |
| `downloader.DownloadErrorCallback = ...` | `downloader.DownloadError += ...` |
| `downloader.DownloadFileBeginCallback = ...` | `downloader.DownloadFileStarted += ...` |
> **注意**v2.3 的 `DownloadError` 委托名与 v3 的 `DownloadError` event 冲突,已重命名为 `DownloadErrorDelegate`。如果你的旧代码中直接引用了 `DownloaderOperation.DownloadError` 委托类型,需要改为 `DownloadErrorDelegate`。
### 1.7 ResourcePackage
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `package.InitializeAsync(parameters)` | `package.InitializePackageAsync(options)` |
| `package.DestroyAsync()` | `package.DestroyPackageAsync()` |
| `package.RequestPackageVersionAsync(bool, int)` | `package.RequestPackageVersionAsync(options)` |
| `package.UpdatePackageManifestAsync(version, timeout)` | `package.LoadPackageManifestAsync(options)` |
| `package.PreDownloadContentAsync(version, timeout)` | `package.PrefetchManifestAsync(options)` |
| `package.ClearCacheFilesAsync(mode, param)` | `package.ClearCacheAsync(options)` |
| `package.UnloadUnusedAssetsAsync(loopCount)` | `package.UnloadUnusedAssetsAsync(options)` |
| `package.IsNeedDownloadFromRemote(location)` | `package.GetDownloadSize(location) > 0` |
| `package.CheckLocationValid(location)` | `package.IsLocationValid(location)` |
| `package.GetAssetInfoByGUID(guid)` | `package.GetAssetInfoByGuid(guid)` |
| `package.CreateResourceDownloader(maxNum, retry)` | `package.CreateResourceDownloader(options)` |
| `package.CreateBundleDownloader(...)` | `package.CreateResourceDownloader(bundleOptions)` |
| `package.CreateResourceUnpacker(maxNum, retry)` | `package.CreateResourceUnpacker(options)` |
| `package.CreateResourceImporter(paths, maxNum, retry)` | `package.CreateResourceImporter(bundleImporterOptions)` |
### 1.8 YooAssets 静态类
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `YooAssets.Initialized` | `YooAssets.IsInitialized` |
| `YooAssets.GetAllPackages()` | `YooAssets.GetPackages()` |
| `YooAssets.TryGetPackage(name)` 返回 null | `YooAssets.TryGetPackage(name, out pkg)` |
| `YooAssets.RemovePackage(package)` 传入实例 | `YooAssets.RemovePackage(packageName)` 传入字符串 |
| `YooAssets.SetOperationSystemMaxTimeSlice(ms)` | `YooAssets.SetAsyncOperationMaxTimeSlice(ms)` |
| `YooAssets.SetDownloadSystemUnityWebRequest(...)` | 已移除 |
| `YooAssets.StartOperation(gameAsyncOp)` | 已移除 |
### 1.9 文件系统参数
| v2.3 写法 | v3 新写法 |
|-----------|----------|
| `params.FileSystemClass` | `params.FileSystemTypeName` |
| `CreateDefaultBuildinFileSystemParameters(decryptSvc, root)` | `CreateDefaultBuiltinFileSystemParameters(root)` |
| `CreateDefaultCacheFileSystemParameters(remoteSvc, decryptSvc, root)` | `CreateDefaultSandboxFileSystemParameters(remoteService, root)` |
| `CreateDefaultWebServerFileSystemParameters(webDecryptSvc, disableCache)` | `CreateDefaultWebServerFileSystemParameters(disableCache)` |
| `CreateDefaultWebRemoteFileSystemParameters(remoteSvc, webDecryptSvc, disableCache)` | `CreateDefaultWebRemoteFileSystemParameters(remoteService, disableCache)` |
| `FileSystemParametersDefine.XXX` 常量 | `EFileSystemParameter.Xxx` 枚举 |
| `IRemoteServices` | `IRemoteService` |
| `IManifestRestoreServices` | `IManifestDecryptor` |
| `EOverwriteInstallClearMode` | `EInstallCleanupMode` |
| `AddParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteSvc)` | 自动包装为 `IRemoteService` |
| `AddParameter(FileSystemParametersDefine.MANIFEST_SERVICES, manifestSvc)` | 自动包装为 `IManifestDecryptor` |
| `AddParameter(FileSystemParametersDefine.INSTALL_CLEAR_MODE, oldMode)` | 自动转换为 `EInstallCleanupMode` |
### 1.10 其他旧类型
| v2.3 类型 | v3 对应 |
|----------|---------|
| `InitializeParameters` 及子类 | `EditorSimulateModeOptions` 等 Options 类 |
| `InitializationOperation` | `InitializePackageOperation` |
| `DestroyOperation` | `DestroyPackageOperation` |
| `UpdatePackageManifestOperation` | `LoadPackageManifestOperation` |
| `PreDownloadContentOperation` | `PrefetchManifestOperation` |
| `GameAsyncOperation` | 已移除(用 `AsyncOperationBase` |
| `ImportFileInfo` | `ImportBundleInfo` |
| `DownloaderFinishData` | `DownloadCompletedEventArgs` |
| `DownloadUpdateData` | `DownloadProgressChangedEventArgs` |
| `DownloadErrorData` | `DownloadErrorEventArgs` |
| `DownloadFileData` | `DownloadFileStartedEventArgs` |
| `DownloadStatus` | 已移除 |
---
## 二、需要手动迁移的项(无法自动兼容)
### 2.1 默认包裹快捷 API已彻底移除
v2.3 中 `YooAssets.SetDefaultPackage()` 及其关联的约 50 个静态快捷方法已在 v3 中**完全移除,不提供兼容**
```csharp
// v2.3 写法 -- 不再支持
YooAssets.SetDefaultPackage(package);
YooAssets.LoadAssetAsync<GameObject>("Assets/Prefabs/Hero.prefab");
// v3 写法 -- 必须通过 ResourcePackage 实例调用
var package = YooAssets.GetPackage("DefaultPackage");
package.LoadAssetAsync<GameObject>("Assets/Prefabs/Hero.prefab");
```
**迁移建议**:全局搜索 `YooAssets.Load``YooAssets.GetAssetInfo``YooAssets.SetDefaultPackage` 等调用,替换为 `package.Xxx(...)` 形式。
### 2.2 DownloadError 委托名冲突
v2.3 的 `DownloaderOperation.DownloadError` 委托类型与 v3 的 `DownloadError` event 同名,兼容层已将旧委托重命名为 `DownloadErrorDelegate`
### 2.3 LoadSceneAsync 的 suspendLoad 参数语义反转
v2.3 的 `LoadSceneAsync(..., bool suspendLoad, ...)` 与 v3 的 `LoadSceneAsync(..., bool allowSceneActivation, ...)` 参数类型签名完全相同,仅参数名和语义相反(`suspendLoad=true` 等价于 `allowSceneActivation=false`)。由于方法签名冲突,无法通过兼容层自动处理。
```csharp
// v2.3 写法
package.LoadSceneAsync("scene", LoadSceneMode.Single, LocalPhysicsMode.None, suspendLoad: true, 100);
// v3 写法 -- 注意 bool 语义反转
package.LoadSceneAsync("scene", LoadSceneMode.Single, LocalPhysicsMode.None, allowSceneActivation: false, 100);
```
### 2.4 ClearCacheFilesOperation 类型名冲突
v2.3 的 `ClearCacheFilesOperation` 与 v3 内部同名类冲突,无法提供兼容包装类。如果旧代码中显式引用了该类型名,需改为 `ClearCacheOperation`。通过 `package.ClearCacheFilesAsync(...)` 调用并用 `var` 接收返回值的写法不受影响。
### 2.5 UnloadAllAssetsOptions 写法变更
v2.3 是 `class` + 公有可变字段v3 是 `readonly struct` + 构造函数。此场景极少出现。
### 2.6 文件系统参数迁移
#### 解密服务接口重构(必须手动迁移)
v2.3 的 `IDecryptionServices``IWebDecryptionServices` 在 v3 中已拆分为多个专用接口:
| v2.3 | v3 |
|------|-----|
| `IDecryptionServices.LoadAssetBundle()` | `IBundleOffsetDecryptor``IBundleStreamDecryptor` |
| `IDecryptionServices.LoadAssetBundleAsync()` | 同上 |
| `IDecryptionServices.LoadAssetBundleFallback()` | `IBundleMemoryDecryptor` |
| `IDecryptionServices.ReadFileData()` / `ReadFileText()` | 已移除 |
| `IWebDecryptionServices` | 已移除,无替代 |
兼容层保留了 `IDecryptionServices``IWebDecryptionServices` 及相关 `DecryptFileInfo` / `DecryptResult` 类型签名以避免编译错误,但**不会自动转换为 v3 解密器**。旧工厂方法中传入的 `decryptionServices` 参数会被忽略。
```csharp
// v2.3 写法
var fsp = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(myDecryptSvc);
// 兼容层编译通过,但 myDecryptSvc 不生效!
// 迁移方法:实现 IBundleOffsetDecryptor 等新接口,通过 EFileSystemParameter 添加
var fsp = FileSystemParameters.CreateDefaultBuiltinFileSystemParameters();
fsp.AddParameter(EFileSystemParameter.AssetbundleDecryptor, myNewDecryptor);
```
#### 已移除的参数常量
以下 `FileSystemParametersDefine` 常量在 v3 中无稳定等价参数,兼容层保留了常量值但 v3 文件系统不会识别:
- `APPEND_FILE_EXTENSION` — 已移除
- `DISABLE_CATALOG_FILE` — 已移除
- `COPY_LOCAL_FILE_SERVICES` — 已移除
- `RESUME_DOWNLOAD_RESPONSE_CODES` — 已移除
#### 旧内部文件系统类名
v2.3 中通过字符串引用的内部文件系统类名在 v3 中已变更:
| v2.3 类名 | v3 类名 |
|-----------|---------|
| `DefaultEditorFileSystem` | `EditorFileSystem` |
| `DefaultBuildinFileSystem` | `BuiltinFileSystem` |
| `DefaultCacheFileSystem` | `SandboxFileSystem` |
| `DefaultWebServerFileSystem` | `WebServerFileSystem` |
| `DefaultWebRemoteFileSystem` | `WebRemoteFileSystem` |
如果旧代码中手写了类名字符串(如 `new FileSystemParameters("YooAsset.DefaultCacheFileSystem", root)`),需改为 v3 工厂方法或更新类名。

View File

@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 2aba4dc1069712d4da0976a70c62e040
DefaultImporter:
guid: f0c6ef1d5368f6a4ca479c94b91ceb81
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:

View File

@@ -9,7 +9,9 @@ namespace YooAsset
[Serializable]
internal class DiagnosticPackageData
{
[NonSerialized]
private readonly Dictionary<string, DiagnosticBundleInfo> _bundleInfoDict = new Dictionary<string, DiagnosticBundleInfo>();
[NonSerialized]
private bool _isParsed = false;
/// <summary>

View File

@@ -19,24 +19,11 @@ namespace YooAsset
if (string.IsNullOrEmpty(filePath))
throw new YooInternalException("File path is null or empty.");
if (IsLocalFileUrl(filePath))
return EscapeSpecialCharacters(filePath);
string url;
#if UNITY_WEBGL
if (IsLocalFileUrl(filePath))
url = filePath;
#elif UNITY_ANDROID
url = new System.Uri(filePath).ToString();
#elif UNITY_OPENHARMONY
// 注意:由于鸿蒙系统的特殊性,需要判断双形态
if (UnityEngine.Application.streamingAssetsPath.StartsWith("jar:file://"))
url = StringUtility.Format("jar:file://{0}", filePath);
else
url = new System.Uri(filePath).ToString();
#else
url = new System.Uri(filePath).ToString();
#endif
url = CreateLocalFileUrl(filePath);
return EscapeSpecialCharacters(url);
}
@@ -60,6 +47,20 @@ namespace YooAsset
return false;
}
private static string CreateLocalFileUrl(string filePath)
{
#if UNITY_WEBGL
return filePath;
#elif UNITY_OPENHARMONY
// 注意:由于鸿蒙系统的特殊性,需要判断双形态
if (UnityEngine.Application.streamingAssetsPath.StartsWith("jar:file://"))
return $"jar:file://{filePath}";
else
return new System.Uri(filePath).ToString();
#else
return new System.Uri(filePath).ToString();
#endif
}
private static string EscapeSpecialCharacters(string url)
{
// 处理特殊字符:用户设备路径可能包含特殊字符导致 URL 无法正确识别

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// <summary>
/// 提供文件系统的创建参数与工厂方法
/// </summary>
public class FileSystemParameters
public partial class FileSystemParameters
{
internal readonly Dictionary<string, object> _createParameters = new Dictionary<string, object>(100);

View File

@@ -165,7 +165,7 @@ namespace YooAsset
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(null);
DownloadBackend = new UnityWebRequestBackend();
// 创建默认的下载重试策略
if (DownloadRetryPolicy == null)

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// <summary>
/// 全资源句柄,用于加载资源包内所有资源对象。
/// </summary>
public sealed class AllAssetsHandle : HandleBase
public sealed partial class AllAssetsHandle : HandleBase
{
private System.Action<AllAssetsHandle> _callback;

View File

@@ -5,7 +5,7 @@ namespace YooAsset
/// <summary>
/// 资源句柄,用于管理单个资源对象的加载和访问。
/// </summary>
public sealed class AssetHandle : HandleBase
public sealed partial class AssetHandle : HandleBase
{
private System.Action<AssetHandle> _callback;

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// <summary>
/// 资源句柄基类,提供资源加载状态查询和释放功能。
/// </summary>
public abstract class HandleBase : IEnumerator, IDisposable
public abstract partial class HandleBase : IEnumerator, IDisposable
{
private readonly AssetInfo _assetInfo;

View File

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 原生文件句柄,用于访问未经 Unity 处理的原始文件。
/// </summary>
public sealed class RawFileHandle : HandleBase
public sealed partial class RawFileHandle : HandleBase
{
private System.Action<RawFileHandle> _callback;

View File

@@ -5,7 +5,7 @@ namespace YooAsset
/// <summary>
/// 场景句柄,用于管理场景的加载、激活和卸载。
/// </summary>
public sealed class SceneHandle : HandleBase
public sealed partial class SceneHandle : HandleBase
{
private System.Action<SceneHandle> _callback;

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// <summary>
/// 子资源句柄,用于管理资源包内子资源对象的加载和访问。
/// </summary>
public sealed class SubAssetsHandle : HandleBase
public sealed partial class SubAssetsHandle : HandleBase
{
private System.Action<SubAssetsHandle> _callback;

View File

@@ -35,10 +35,12 @@ namespace YooAsset
_handle = handle;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.LoadObject;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
@@ -140,10 +142,12 @@ namespace YooAsset
}
#endif
}
/// <inheritdoc />
protected override void InternalWaitForCompletion()
{
ExecuteBatch();
}
/// <inheritdoc />
protected override string InternalGetDescription()
{
var assetInfo = _handle.GetAssetInfo();

View File

@@ -28,10 +28,12 @@ namespace YooAsset
_resourceManager = resourceManager;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.CheckOptions;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)

View File

@@ -42,10 +42,12 @@ namespace YooAsset
throw new YooInternalException($"Unexpected provider type: '{provider.GetType().Name}'.");
}
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.CheckError;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
@@ -106,6 +108,7 @@ namespace YooAsset
SetResult();
}
}
/// <inheritdoc />
protected override string InternalGetDescription()
{
return $"SceneName: {_provider.LoadedSceneName}";

View File

@@ -22,11 +22,13 @@ namespace YooAsset
_resourceManager = resourceManager;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.UnloadUnused;
_loopCounter = _options.MaxLoopCount;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
@@ -51,10 +53,12 @@ namespace YooAsset
}
}
}
/// <inheritdoc />
protected override void InternalWaitForCompletion()
{
ExecuteBatch();
}
/// <inheritdoc />
protected override string InternalGetDescription()
{
return $"MaxLoopCount: {_options.MaxLoopCount}";

View File

@@ -28,10 +28,12 @@ namespace YooAsset
_host = host;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.Prepare;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
@@ -98,6 +100,7 @@ namespace YooAsset
}
}
}
/// <inheritdoc />
protected override string InternalGetDescription()
{
return $"ClearMethod: {_options.ClearMethod}";

View File

@@ -26,11 +26,12 @@ namespace YooAsset
_resourcePackage = resourcePackage;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.CheckInitStatus;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
@@ -99,6 +100,7 @@ namespace YooAsset
SetResult();
}
}
/// <inheritdoc />
protected override string InternalGetDescription()
{
return $"PackageVersion: {_resourcePackage.GetPackageVersion()}";

View File

@@ -6,7 +6,7 @@ namespace YooAsset
/// <summary>
/// 下载操作基类,提供资源下载、暂停、恢复和取消功能。
/// </summary>
public abstract class DownloaderOperation : AsyncOperationBase
public abstract partial class DownloaderOperation : AsyncOperationBase
{
private enum ESteps
{
@@ -99,11 +99,13 @@ namespace YooAsset
// 统计下载信息
CalculateStatistics();
}
/// <inheritdoc />
protected override void InternalStart()
{
YooLogger.Log($"Beginning download of {TotalDownloadCount} files ({TotalDownloadBytes} bytes).");
_steps = ESteps.Check;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)

View File

@@ -29,10 +29,12 @@ namespace YooAsset
_package = package;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.SetPlayMode;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
@@ -137,6 +139,7 @@ namespace YooAsset
}
}
}
/// <inheritdoc />
protected override string InternalGetDescription()
{
return $"PlayMode: {_playMode}";

View File

@@ -7,8 +7,6 @@ namespace YooAsset
/// </summary>
public abstract class InitializePackageOptions
{
protected InitializePackageOptions() { }
/// <summary>
/// 同时加载Bundle文件的最大并发数
/// </summary>

View File

@@ -28,10 +28,12 @@ namespace YooAsset
_host = host;
_parametersList = parametersList;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.Prepare;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)

View File

@@ -25,10 +25,12 @@ namespace YooAsset
_host = host;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.CheckParams;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
@@ -95,6 +97,7 @@ namespace YooAsset
}
}
}
/// <inheritdoc />
protected override string InternalGetDescription()
{
return $"PackageVersion: {_options.PackageVersion}";

View File

@@ -30,10 +30,12 @@ namespace YooAsset
_host = host;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.CheckParams;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)

View File

@@ -29,10 +29,12 @@ namespace YooAsset
_host = host;
_options = options;
}
/// <inheritdoc />
protected override void InternalStart()
{
_steps = ESteps.RequestPackageVersion;
}
/// <inheritdoc />
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)

View File

@@ -72,11 +72,16 @@ namespace YooAsset
/// </summary>
[NonSerialized]
public readonly List<int> ReferrerBundleIDs = new List<int>(10);
[NonSerialized]
private readonly HashSet<int> _referrerBundleIDs = new HashSet<int>();
[NonSerialized]
private PackageManifest _manifest;
[NonSerialized]
private bool _isInitialized;
[NonSerialized]
private int _bundleType;
[NonSerialized]
private string _fileName;
@@ -166,6 +171,7 @@ namespace YooAsset
}
#region
[NonSerialized]
private List<string> _debugReferrerBundleNames;
/// <summary>

View File

@@ -401,7 +401,7 @@ namespace YooAsset
/// <summary>
/// 将资源GUID转换为资源信息
/// </summary>
/// <param name="assetGUID">资源GUID</param>
/// <param name="assetGuid">资源GUID</param>
/// <param name="assetType">资源类型</param>
/// <returns>返回资源信息对象,如果转换失败会返回一个无效的资源信息。</returns>
public AssetInfo ConvertAssetGuidToAssetInfo(string assetGuid, System.Type assetType)

View File

@@ -9,7 +9,7 @@ namespace YooAsset
/// <summary>
/// 资源包裹类
/// </summary>
public class ResourcePackage
public partial class ResourcePackage
{
private InitializePackageOperation _initializeOp;
private ResourceManager _resourceManager;

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: cda191ef75dc59f408545d8f7d3644b0
guid: 682ac5046f4686946b0003a449638651
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,61 @@
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(GameObjectReference))]
public class GameObjectReferenceDrawer : PropertyDrawer
{
private const float LineSpacing = 2f;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
SerializedProperty packageNameProp = property.FindPropertyRelative("_packageName");
SerializedProperty assetGUIDProp = property.FindPropertyRelative("_assetGUID");
EditorGUI.BeginProperty(position, label, property);
{
float lineHeight = EditorGUIUtility.singleLineHeight;
Rect line = new Rect(position.x, position.y, position.width, lineHeight);
// 绘制 PackageName
packageNameProp.stringValue = EditorGUI.TextField(line, "Package Name", packageNameProp.stringValue);
// 加载 GameObject
string assetGUID = assetGUIDProp.stringValue;
GameObject current = null;
if (string.IsNullOrEmpty(assetGUID) == false)
{
string assetPath = AssetDatabase.GUIDToAssetPath(assetGUID);
if (string.IsNullOrEmpty(assetPath) == false)
current = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
}
// 绘制 GameObject
line.y += lineHeight + LineSpacing;
GameObject newAsset = (GameObject)EditorGUI.ObjectField(line, "Game Object", current, typeof(GameObject), false);
if (newAsset != current)
{
if (newAsset == null)
{
assetGUIDProp.stringValue = "";
}
else
{
string newPath = AssetDatabase.GetAssetPath(newAsset);
if (string.IsNullOrEmpty(newPath) == false)
assetGUIDProp.stringValue = AssetDatabase.AssetPathToGUID(newPath);
}
}
// 绘制 AssetGUID
line.y += lineHeight + LineSpacing;
EditorGUI.BeginDisabledGroup(true);
EditorGUI.TextField(line, "Asset GUID", assetGUIDProp.stringValue);
EditorGUI.EndDisabledGroup();
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.singleLineHeight * 3 + LineSpacing * 2;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 53eb285fc3a7b614089a000f8c9c738c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,17 +1,31 @@
using System;
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
/// <summary>
/// 提供构建缓存清理菜单入口
/// </summary>
internal class ClearBuildCacheWindow
{
private const string SBPEditorAssemblyName = "Unity.ScriptableBuildPipeline.Editor";
private const string SBPBuildCacheTypeName = "UnityEditor.Build.Pipeline.Utilities.BuildCache";
[MenuItem("Tools/Clear Build Cache", false, 2)]
public static void OpenWindow()
{
// 清空SBP构建缓存
UnityEditor.Build.Pipeline.Utilities.BuildCache.PurgeCache(false);
var buildCacheType = Type.GetType($"{SBPBuildCacheTypeName}, {SBPEditorAssemblyName}");
if (buildCacheType != null)
{
EditorAssemblyUtility.InvokePublicStaticMethod(buildCacheType, "PurgeCache", false);
}
else
{
Debug.LogWarning($"Failed to find type: {SBPBuildCacheTypeName}");
}
// 删除AssetDependDB文件
string projectPath = YooAsset.Editor.EditorPathUtility.GetProjectPath();
@@ -20,6 +34,8 @@ namespace YooAsset.Editor
{
File.Delete(databaseFilePath);
}
Debug.Log("Clear build cache succeeded !");
}
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -6,16 +6,19 @@ using UnityEditor;
namespace YooAsset.Editor
{
public class CreateBuildinCatalogWindow : EditorWindow
/// <summary>
/// 提供内置资源清单生成工具窗口
/// </summary>
public class CreateBuiltinCatalogWindow : EditorWindow
{
static CreateBuildinCatalogWindow _thisInstance;
static CreateBuiltinCatalogWindow _thisInstance;
[MenuItem("Tools/内置清单生成工具Catalog", false, 101)]
[MenuItem("Tools/Builtin Catalog Generator", false, 101)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(CreateBuildinCatalogWindow), false, "内置清单生成工具", true) as CreateBuildinCatalogWindow;
_thisInstance = EditorWindow.GetWindow(typeof(CreateBuiltinCatalogWindow), false, "Builtin Catalog Generator", true) as CreateBuiltinCatalogWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
@@ -27,7 +30,7 @@ namespace YooAsset.Editor
{
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择内置资源目录", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Select Builtin Resource Directory", GUILayout.MaxWidth(150)))
{
string resultPath = EditorUtility.OpenFolderPanel("Find", "Assets/", "StreamingAssets");
if (!string.IsNullOrEmpty(resultPath))
@@ -38,7 +41,7 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(_directoryRoot) == false)
{
if (GUILayout.Button("生成Catalog文件", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Generate Catalog File", GUILayout.MaxWidth(150)))
{
CreateCatalogFile(_directoryRoot);
}
@@ -47,6 +50,13 @@ namespace YooAsset.Editor
private void CreateCatalogFile(string directoryRoot)
{
// 检查目录是否存在
if (Directory.Exists(directoryRoot) == false)
{
Debug.LogError("Selected directory does not exist.");
return;
}
// 搜索所有Package目录
List<string> packageRoots = GetPackageRoots(directoryRoot);
foreach (var packageRoot in packageRoots)
@@ -55,26 +65,20 @@ namespace YooAsset.Editor
string packageName = directoryInfo.Name;
try
{
bool result = BuiltinCatalogHelper.CreateFile(null, packageName, packageRoot); //TODO 自行处理解密
bool result = BuiltinCatalogHelper.CreateFile(null, packageName, packageRoot); // TODO: 根据业务需求处理清单解密
if (result == false)
{
Debug.LogError($"Create package {packageName} catalog file failed ! See the detail error in console !");
Debug.LogError($"Failed to create a catalog file for package '{packageName}'. See Console for details.");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Create package {packageName} catalog file failed ! {ex.Message}");
Debug.LogError($"Failed to create a catalog file for package '{packageName}': {ex.Message}.");
}
}
}
private List<string> GetPackageRoots(string rootPath)
{
// 检查目录是否存在
if (Directory.Exists(rootPath) == false)
{
throw new DirectoryNotFoundException($"目录不存在: {rootPath}");
}
// 搜索所有 .version 文件(包含子目录)
string[] versionFiles = Directory.GetFiles(
rootPath,

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -6,16 +6,19 @@ using UnityEditor;
namespace YooAsset.Editor
{
/// <summary>
/// 提供空资源清单生成工具窗口
/// </summary>
public class CreateEmptyCatalogWindow : EditorWindow
{
static CreateEmptyCatalogWindow _thisInstance;
[MenuItem("Tools/空清单生成工具Catalog", false, 102)]
[MenuItem("Tools/Empty Catalog Generator", false, 102)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(CreateEmptyCatalogWindow), false, "空清单生成工具", true) as CreateEmptyCatalogWindow;
_thisInstance = EditorWindow.GetWindow(typeof(CreateEmptyCatalogWindow), false, "Empty Catalog Generator", true) as CreateEmptyCatalogWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
@@ -32,9 +35,9 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(_packageName) == false)
{
if (GUILayout.Button("生成空的Catalog文件", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Generate Empty Catalog File", GUILayout.MaxWidth(150)))
{
string outputPath = EditorDialogUtility.OpenFolderPanel("输出目录", "Assets/");
string outputPath = EditorDialogUtility.OpenFolderPanel("Output Directory", "Assets/");
if (string.IsNullOrEmpty(outputPath) == false)
{
CreateEmptyCatalogFile(outputPath);
@@ -50,12 +53,12 @@ namespace YooAsset.Editor
bool result = BuiltinCatalogHelper.CreateEmptyFile(_packageName, string.Empty, outputPath);
if (result == false)
{
Debug.LogError($"Create package {_packageName} catalog file failed ! See the detail error in console !");
Debug.LogError($"Failed to create a catalog file for package '{_packageName}'. See Console for details.");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Create package {_packageName} catalog file failed ! {ex.Message}");
Debug.LogError($"Failed to create a catalog file for package '{_packageName}': {ex.Message}.");
}
}
}

View File

@@ -8,6 +8,9 @@ using UnityEditor.UIElements;
using UnityEngine.UIElements;
using YooAsset.Editor;
/// <summary>
/// 提供自定义构建管线的编辑器视图
/// </summary>
[BuildPipelineAttribute("CustomBuildPipeline")]
internal class CustomBuildPipelineViewer : LegacyBuildPipelineViewer
{

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using YooAsset.Editor;
/// <summary>
/// 按文件名生成资源定位地址
/// </summary>
[DisplayName("定位地址: 文件名.智能尾缀")]
public class AddressByFileNameAndExt : IAddressRule
{
/// <inheritdoc/>
public string GetAssetAddress(AddressRuleData data)
{
var extension = Path.GetExtension(data.AssetPath);
if (extension == ".asset")
{
var asset = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(data.AssetPath);
if (asset == null)
throw new InvalidOperationException($"Asset not found: '{data.AssetPath}'.");
var assetType = asset.GetType();
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(data.AssetPath);
return fileNameWithoutExtension + $".{assetType.Name.ToLowerInvariant()}";
}
return Path.GetFileName(data.AssetPath);
}
}

View File

@@ -1,25 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using YooAsset.Editor;
[DisplayName("定位地址: 文件名.智能尾缀")]
public class AddressByFileNameAndExt : IAddressRule
{
public string GetAssetAddress(AddressRuleData data)
{
var ext = Path.GetExtension(data.AssetPath);
if (ext == ".asset")
{
var a = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(data.AssetPath);
if (a == null) return ".errortype";
var type = a.GetType();
var dt = Path.GetFileNameWithoutExtension(data.AssetPath);
return dt + $".{type.Name.ToLowerInvariant()}";
}
return Path.GetFileName(data.AssetPath);
}
}

View File

@@ -1,20 +1,24 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using YooAsset.Editor;
/// <summary>
/// 将特效纹理按首字符分组到资源包
/// </summary>
[DisplayName("打包特效纹理(自定义)")]
public class PackEffectTexture : IBundlePackRule
{
private const string PackDirectory = "Assets/Effect/Textures/";
/// <inheritdoc/>
BundlePackRuleResult IBundlePackRule.GetPackRuleResult(BundlePackRuleData data)
{
string assetPath = data.AssetPath;
if (assetPath.StartsWith(PackDirectory) == false)
throw new Exception($"Only support folder : {PackDirectory}");
throw new ArgumentException($"Only support folder: {PackDirectory}", nameof(data));
string assetName = Path.GetFileName(assetPath).ToLower();
string firstChar = assetName.Substring(0, 1);
@@ -24,9 +28,13 @@ public class PackEffectTexture : IBundlePackRule
}
}
/// <summary>
/// 按视频资源路径生成原始文件资源包
/// </summary>
[DisplayName("打包视频(自定义)")]
public class PackVideo : IBundlePackRule
{
/// <inheritdoc/>
public BundlePackRuleResult GetPackRuleResult(BundlePackRuleData data)
{
string bundleName = RemoveExtension(data.AssetPath);

View File

@@ -1,14 +1,17 @@
using System.Collections.Generic;
using System.Collections.Generic;
#if YOO_MACRO_SUPPORT
namespace YooAsset.Editor
{
public class MacroDefine
/// <summary>
/// 提供 YooAsset 版本相关的脚本宏定义
/// </summary>
public static class MacroDefine
{
/// <summary>
/// YooAsset版本宏定义
/// YooAsset 版本宏定义集合
/// </summary>
public static readonly List<string> Macros = new List<string>()
public static IReadOnlyList<string> Macros { get; } = new List<string>()
{
"YOO_ASSET_2",
"YOO_ASSET_2_3",

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@@ -8,6 +8,9 @@ using UnityEditor;
#if YOO_MACRO_SUPPORT
namespace YooAsset.Editor
{
/// <summary>
/// 在生成 C# 工程文件时注入 YooAsset 版本宏定义
/// </summary>
[InitializeOnLoad]
public class MacroProcessor : AssetPostprocessor
{
@@ -41,7 +44,7 @@ namespace YooAsset.Editor
}
/// <summary>
/// 处理宏定义
/// 处理工程文件中的宏定义
/// </summary>
private static bool ProcessDefineConstants(XmlElement element)
{
@@ -76,7 +79,7 @@ namespace YooAsset.Editor
}
/// <summary>
/// 检工程是否引用了YooAsset
/// 检工程是否引用了 YooAsset
/// </summary>
private static bool IsCSProjectReferenced(XmlElement element)
{
@@ -93,7 +96,11 @@ namespace YooAsset.Editor
if (childNode.Name != "Reference" && childNode.Name != "ProjectReference")
continue;
string include = childNode.Attributes["Include"].Value;
XmlAttribute includeAttribute = childNode.Attributes["Include"];
if (includeAttribute == null)
continue;
string include = includeAttribute.Value;
if (include.Contains("YooAsset"))
return true;
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@@ -9,10 +9,13 @@ using UnityEngine;
#if YOO_MACRO_SUPPORT
namespace YooAsset.Editor.Experiment
{
/// <summary>
/// 通过 csc.rsp 文件注入 YooAsset 版本宏定义
/// </summary>
[InitializeOnLoad]
public class RspGenerator
{
// csc.rsp文件路径
// Unity 编译器响应文件路径
private static string RspFilePath => Path.Combine(Application.dataPath, "csc.rsp");
static RspGenerator()
@@ -23,7 +26,7 @@ namespace YooAsset.Editor.Experiment
/// <summary>
/// 更新 csc.rsp 文件
/// </summary>
private static void UpdateRspFile(List<string> addMacros, List<string> removeMacros)
private static void UpdateRspFile(IReadOnlyList<string> addMacros, IReadOnlyList<string> removeMacros)
{
var existingDefines = new HashSet<string>();
var otherLines = new List<string>();
@@ -34,24 +37,26 @@ namespace YooAsset.Editor.Experiment
// 2. 添加新宏
if (addMacros != null && addMacros.Count > 0)
{
addMacros.ForEach(x =>
foreach (var x in addMacros)
{
if (existingDefines.Contains(x) == false)
existingDefines.Add(x);
});
}
}
// 3. 移除指定宏
if (removeMacros != null && removeMacros.Count > 0)
{
removeMacros.ForEach(x =>
foreach (var x in removeMacros)
{
existingDefines.Remove(x);
});
}
}
// 4. 重新生成内容
WriteRspFile(existingDefines, otherLines);
bool changed = WriteRspFile(existingDefines, otherLines);
if (changed == false)
return;
// 5. 刷新AssetDatabase
AssetDatabase.Refresh();
@@ -59,7 +64,7 @@ namespace YooAsset.Editor.Experiment
}
/// <summary>
/// 读取csc.rsp文件,返回宏定义和其他行
/// 读取 csc.rsp 文件中的宏定义和其他行
/// </summary>
private static void ReadRspFile(HashSet<string> defines, List<string> others)
{
@@ -92,7 +97,8 @@ namespace YooAsset.Editor.Experiment
/// <summary>
/// 重新写入 csc.rsp 文件
/// </summary>
private static void WriteRspFile(HashSet<string> defines, List<string> others)
/// <returns>文件内容发生变化时返回 true</returns>
private static bool WriteRspFile(HashSet<string> defines, List<string> others)
{
StringBuilder sb = new StringBuilder();
if (others != null && others.Count > 0)
@@ -108,7 +114,16 @@ namespace YooAsset.Editor.Experiment
}
}
File.WriteAllText(RspFilePath, sb.ToString());
string newContent = sb.ToString();
if (File.Exists(RspFilePath))
{
string oldContent = File.ReadAllText(RspFilePath);
if (oldContent == newContent)
return false;
}
File.WriteAllText(RspFilePath, newContent);
return true;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -6,16 +6,19 @@ using UnityEditor;
namespace YooAsset.Editor
{
/// <summary>
/// 提供补丁包差异比对工具窗口
/// </summary>
public class PackageComparatorWindow : EditorWindow
{
static PackageComparatorWindow _thisInstance;
[MenuItem("Tools/补丁包比对工具", false, 103)]
[MenuItem("Tools/Patch Package Comparator", false, 103)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(PackageComparatorWindow), false, "补丁包比对工具", true) as PackageComparatorWindow;
_thisInstance = EditorWindow.GetWindow(typeof(PackageComparatorWindow), false, "Patch Package Comparator", true) as PackageComparatorWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
@@ -32,7 +35,7 @@ namespace YooAsset.Editor
{
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择补丁包1", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Select Patch Package 1", GUILayout.MaxWidth(150)))
{
string resultPath = EditorUtility.OpenFilePanel("Find", "Assets/", "bytes");
if (string.IsNullOrEmpty(resultPath))
@@ -44,7 +47,7 @@ namespace YooAsset.Editor
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择补丁包2", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Select Patch Package 2", GUILayout.MaxWidth(150)))
{
string resultPath = EditorUtility.OpenFilePanel("Find", "Assets/", "bytes");
if (string.IsNullOrEmpty(resultPath))
@@ -56,17 +59,26 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(_manifestPath1) == false && string.IsNullOrEmpty(_manifestPath2) == false)
{
if (GUILayout.Button("比对差异", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Compare Differences", GUILayout.MaxWidth(150)))
{
try
{
ComparePackage(_changeList, _newList);
}
catch (System.Exception ex)
{
_changeList.Clear();
_newList.Clear();
Debug.LogError($"Failed to compare patch packages: {ex.Message}.");
}
}
}
EditorGUILayout.Space();
using (new EditorGUI.DisabledScope(false))
{
int totalCount = _changeList.Count;
EditorGUILayout.Foldout(true, $"差异列表 ( {totalCount} )");
EditorGUILayout.Foldout(true, $"Changed Bundles ( {totalCount} )");
EditorGUI.indentLevel = 1;
_scrollPos1 = EditorGUILayout.BeginScrollView(_scrollPos1);
@@ -84,7 +96,7 @@ namespace YooAsset.Editor
using (new EditorGUI.DisabledScope(false))
{
int totalCount = _newList.Count;
EditorGUILayout.Foldout(true, $"新增列表 ( {totalCount} )");
EditorGUILayout.Foldout(true, $"New Bundles ( {totalCount} )");
EditorGUI.indentLevel = 1;
_scrollPos2 = EditorGUILayout.BeginScrollView(_scrollPos2);
@@ -104,13 +116,13 @@ namespace YooAsset.Editor
changeList.Clear();
newList.Clear();
// 加载补丁清单1
// 加载基准补丁清单
byte[] bytesData1 = FileUtility.ReadAllBytes(_manifestPath1);
PackageManifest manifest1 = PackageManifestHelper.DeserializeManifestFromBinary(bytesData1, null); //TODO 自行处理解密
PackageManifest manifest1 = PackageManifestHelper.DeserializeManifestFromBinary(bytesData1, null); // TODO: 根据业务需求处理清单解密
// 加载补丁清单1
// 加载待比对补丁清单
byte[] bytesData2 = FileUtility.ReadAllBytes(_manifestPath2);
PackageManifest manifest2 = PackageManifestHelper.DeserializeManifestFromBinary(bytesData2, null); //TODO 自行处理解密
PackageManifest manifest2 = PackageManifestHelper.DeserializeManifestFromBinary(bytesData2, null); // TODO: 根据业务需求处理清单解密
// 拷贝文件列表
foreach (var bundle2 in manifest2.BundleList)
@@ -132,7 +144,7 @@ namespace YooAsset.Editor
changeList.Sort((x, y) => string.Compare(x.BundleName, y.BundleName));
newList.Sort((x, y) => string.Compare(x.BundleName, y.BundleName));
Debug.Log("资源包差异比对完成!");
Debug.Log("Package comparison completed.");
}
}
}

View File

@@ -4,16 +4,19 @@ using UnityEditor;
namespace YooAsset.Editor
{
/// <summary>
/// 提供补丁包导入工具窗口
/// </summary>
public class PackageImporterWindow : EditorWindow
{
static PackageImporterWindow _thisInstance;
[MenuItem("Tools/补丁包导入工具", false, 104)]
[MenuItem("Tools/Patch Package Importer", false, 104)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(PackageImporterWindow), false, "补丁包导入工具", true) as PackageImporterWindow;
_thisInstance = EditorWindow.GetWindow(typeof(PackageImporterWindow), false, "Patch Package Importer", true) as PackageImporterWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
@@ -26,7 +29,12 @@ namespace YooAsset.Editor
{
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择补丁包", GUILayout.MaxWidth(150)))
_packageName = EditorGUILayout.TextField("Package Name", _packageName);
EditorGUILayout.EndHorizontal();
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Select Patch Package", GUILayout.MaxWidth(150)))
{
string resultPath = EditorUtility.OpenFilePanel("Find", "Assets/", "bytes");
if (!string.IsNullOrEmpty(resultPath))
@@ -37,54 +45,84 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(_manifestPath) == false)
{
if (GUILayout.Button("导入补丁包(全部文件)", GUILayout.MaxWidth(150)))
if (GUILayout.Button("Import Patch Package (All Files)", GUILayout.MaxWidth(150)))
{
if (string.IsNullOrEmpty(_packageName))
{
Debug.LogError("Package name is empty.");
return;
}
try
{
string streamingAssetsRoot = BundleBuilderHelper.GetStreamingAssetsRoot();
EditorFileUtility.ClearFolder(streamingAssetsRoot);
CopyPackageFiles(_manifestPath);
}
catch (System.Exception ex)
{
Debug.LogError($"Failed to import patch package '{_packageName}': {ex.Message}.");
}
finally
{
AssetDatabase.Refresh();
}
}
}
}
private void CopyPackageFiles(string manifestFilePath)
{
string manifestFileName = Path.GetFileNameWithoutExtension(manifestFilePath);
string outputDirectory = Path.GetDirectoryName(manifestFilePath);
string sourceRoot = Path.GetDirectoryName(manifestFilePath);
if (string.IsNullOrEmpty(sourceRoot))
throw new DirectoryNotFoundException("Patch package directory does not exist.");
string versionFileName = YooAssetConfiguration.GetPackageVersionFileName(_packageName);
string versionSourcePath = Path.Combine(sourceRoot, versionFileName);
string packageVersion = File.ReadAllText(versionSourcePath).Trim();
string manifestFileName = YooAssetConfiguration.GetManifestBinaryFileName(_packageName, packageVersion);
string hashFileName = YooAssetConfiguration.GetPackageHashFileName(_packageName, packageVersion);
string selectedFileName = Path.GetFileName(manifestFilePath);
if (selectedFileName != manifestFileName)
throw new InvalidDataException($"Selected manifest file '{selectedFileName}' does not match expected manifest file '{manifestFileName}'.");
string destRoot = Path.Combine(BundleBuilderHelper.GetStreamingAssetsRoot(), _packageName);
// 清空旧目录
EditorFileUtility.DeleteDirectory(destRoot);
EditorFileUtility.CreateDirectory(destRoot);
// 拷贝核心文件
{
string sourcePath = $"{outputDirectory}/{manifestFileName}.bytes";
string destPath = $"{BundleBuilderHelper.GetStreamingAssetsRoot()}/{_packageName}/{manifestFileName}.bytes";
string sourcePath = Path.Combine(sourceRoot, manifestFileName);
string destPath = Path.Combine(destRoot, manifestFileName);
EditorFileUtility.CopyFile(sourcePath, destPath, true);
}
{
string sourcePath = $"{outputDirectory}/{manifestFileName}.hash";
string destPath = $"{BundleBuilderHelper.GetStreamingAssetsRoot()}/{_packageName}/{manifestFileName}.hash";
string sourcePath = Path.Combine(sourceRoot, hashFileName);
string destPath = Path.Combine(destRoot, hashFileName);
EditorFileUtility.CopyFile(sourcePath, destPath, true);
}
{
string fileName = YooAssetConfiguration.GetPackageVersionFileName(_packageName);
string sourcePath = $"{outputDirectory}/{fileName}";
string destPath = $"{BundleBuilderHelper.GetStreamingAssetsRoot()}/{_packageName}/{fileName}";
string sourcePath = versionSourcePath;
string destPath = Path.Combine(destRoot, versionFileName);
EditorFileUtility.CopyFile(sourcePath, destPath, true);
}
// 加载补丁清单
byte[] bytesData = FileUtility.ReadAllBytes(manifestFilePath);
PackageManifest manifest = PackageManifestHelper.DeserializeManifestFromBinary(bytesData, null); //TODO 自行处理解密
PackageManifest manifest = PackageManifestHelper.DeserializeManifestFromBinary(bytesData, null); // TODO: 根据业务需求处理清单解密
// 拷贝文件列表
int fileCount = 0;
foreach (var packageBundle in manifest.BundleList)
{
fileCount++;
string sourcePath = $"{outputDirectory}/{packageBundle.GetFileName()}";
string destPath = $"{BundleBuilderHelper.GetStreamingAssetsRoot()}/{_packageName}/{packageBundle.GetFileName()}";
string fileName = packageBundle.GetFileName();
string sourcePath = Path.Combine(sourceRoot, fileName);
string destPath = Path.Combine(destRoot, fileName);
EditorFileUtility.CopyFile(sourcePath, destPath, true);
}
Debug.Log($"补丁包拷贝完成,一共拷贝了{fileCount}个资源文件");
AssetDatabase.Refresh();
Debug.Log($"Patch package copy completed. Copied {fileCount} bundle files.");
}
}
}

View File

@@ -5,23 +5,26 @@ using YooAsset.Editor;
namespace YooAsset
{
/// <summary>
/// 在应用构建前生成内置资源清单
/// </summary>
public class PreprocessBuildCatalog : UnityEditor.Build.IPreprocessBuildWithReport
{
/// <summary>
/// 构建预处理回调顺序
/// </summary>
public int callbackOrder { get { return 0; } }
/// <summary>
/// 在构建应用程序前自动生成内置资源目录文件。
/// 原理搜索StreamingAssets目录下的所有资源文件将这些文件信息写入文件然后在运行时做查询用途。
/// </summary>
/// <inheritdoc/>
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{
YooLogger.Log("Begin to create catalog file !");
YooLogger.Log("Starting catalog file generation.");
string rootPath = BundleBuilderHelper.GetStreamingAssetsRoot();
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists == false)
{
Debug.LogWarning($"Can not found StreamingAssets root directory : {rootPath}");
Debug.LogWarning("StreamingAssets root directory does not exist.");
return;
}
@@ -30,18 +33,18 @@ namespace YooAsset
foreach (var subDirectory in subDirectories)
{
string packageName = subDirectory.Name;
string pacakgeDirectory = subDirectory.FullName;
string packageDirectory = subDirectory.FullName;
try
{
bool result = BuiltinCatalogHelper.CreateFile(null, packageName, pacakgeDirectory); //TODO 自行处理解密
bool result = BuiltinCatalogHelper.CreateFile(null, packageName, packageDirectory); // TODO: 根据业务需求处理清单解密
if (result == false)
{
Debug.LogError($"Create package {packageName} catalog file failed ! See the detail error in console !");
Debug.LogError($"Failed to create a catalog file for package '{packageName}'. See Console for details.");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Create package {packageName} catalog file failed ! {ex.Message}");
Debug.LogError($"Failed to create a catalog file for package '{packageName}': {ex.Message}.");
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
@@ -7,28 +7,51 @@ using UnityEngine.Rendering;
using UnityEditor;
using YooAsset.Editor;
/// <summary>
/// 封装 Unity 编辑器中的 ShaderVariantCollection 反射调用
/// </summary>
public static class ShaderVariantCollectionHelper
{
/// <summary>
/// 清空当前编辑器记录的着色器变种集合
/// </summary>
public static void ClearCurrentShaderVariantCollection()
{
EditorAssemblyUtility.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "ClearCurrentShaderVariantCollection");
}
/// <summary>
/// 保存当前编辑器记录的着色器变种集合
/// </summary>
/// <param name="savePath">保存目标路径</param>
public static void SaveCurrentShaderVariantCollection(string savePath)
{
EditorAssemblyUtility.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "SaveCurrentShaderVariantCollection", savePath);
}
/// <summary>
/// 当前着色器变种集合中的着色器数量
/// </summary>
/// <returns>着色器数量</returns>
public static int GetCurrentShaderVariantCollectionShaderCount()
{
return (int)EditorAssemblyUtility.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetCurrentShaderVariantCollectionShaderCount");
}
/// <summary>
/// 当前着色器变种集合中的变种数量
/// </summary>
/// <returns>变种数量</returns>
public static int GetCurrentShaderVariantCollectionVariantCount()
{
return (int)EditorAssemblyUtility.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetCurrentShaderVariantCollectionVariantCount");
}
/// <summary>
/// 获取着色器的变种总数量
/// 获取指定着色器资源的变种总数量
/// </summary>
/// <param name="assetPath">着色器资源路径</param>
/// <returns>变种总数量的字符串表示</returns>
public static string GetShaderVariantCount(string assetPath)
{
Shader shader = AssetDatabase.LoadAssetAtPath<Shader>(assetPath);

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
@@ -7,50 +7,70 @@ using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;
/// <summary>
/// 着色器变种集合的可序列化清单
/// </summary>
[Serializable]
public class ShaderVariantCollectionManifest
{
/// <summary>
/// 单个着色器变种的序列化信息
/// </summary>
[Serializable]
public class ShaderVariantElement : IComparable<ShaderVariantElement>
{
/// <summary>
/// 用于稳定排序的组合键
/// </summary>
public string SortValue { private set; get; }
/// <summary>
/// Pass type to use in this variant.
/// 变种使用的渲染通道类型
/// </summary>
public PassType PassType;
/// <summary>
/// Array of shader keywords to use in this variant.
/// 变种使用的着色器关键字数组
/// </summary>
public string[] Keywords;
/// <summary>
/// 生成排序键
/// </summary>
public void MakeSortValue()
{
string combineKeyword = string.Empty;
for (int i = 0; i < Keywords.Length; i++)
{
if (i == 0)
combineKeyword = Keywords[0];
combineKeyword = Keywords[i];
else
combineKeyword = $"{combineKeyword}+{Keywords[0]}";
combineKeyword = $"{combineKeyword}+{Keywords[i]}";
}
SortValue = $"{PassType}+{combineKeyword}";
}
/// <inheritdoc/>
public int CompareTo(ShaderVariantElement other)
{
return SortValue.CompareTo(other.SortValue);
}
}
/// <summary>
/// 单个着色器及其变种列表的序列化信息
/// </summary>
[Serializable]
public class ShaderVariantInfo : IComparable<ShaderVariantInfo>
{
/// <summary>
/// 用于稳定排序的组合键
/// </summary>
public string SortValue { private set; get; }
/// <summary>
/// 着色器资源路径.
/// 着色器资源路径
/// </summary>
public string AssetPath;
@@ -69,10 +89,15 @@ public class ShaderVariantCollectionManifest
/// </summary>
public List<ShaderVariantElement> ShaderVariantElements = new List<ShaderVariantElement>(1000);
/// <summary>
/// 生成排序键
/// </summary>
public void MakeSortValue()
{
SortValue = AssetPath + "+" + ShaderName;
}
/// <inheritdoc/>
public int CompareTo(ShaderVariantInfo other)
{
return SortValue.CompareTo(other.SortValue);
@@ -81,33 +106,36 @@ public class ShaderVariantCollectionManifest
/// <summary>
/// Number of shaders in this collection
/// 清单中的着色器总数
/// </summary>
public int ShaderTotalCount;
/// <summary>
/// Number of total varians in this collection
/// 清单中的变种总数
/// </summary>
public int VariantTotalCount;
/// <summary>
/// Shader variants info list.
/// 着色器变种信息列表
/// </summary>
public List<ShaderVariantInfo> ShaderVariantInfos = new List<ShaderVariantInfo>(1000);
/// <summary>
/// 添加着色器变种信息
/// </summary>
/// <param name="assetPath">着色器资源路径</param>
/// <param name="shaderName">着色器名称</param>
/// <param name="passType">渲染通道类型</param>
/// <param name="keywords">着色器关键字数组</param>
public void AddShaderVariant(string assetPath, string shaderName, PassType passType, string[] keywords)
{
// 排序Keyword列表
List<string> temper = new List<string>(keywords);
temper.Sort();
List<string> sortedKeywords = new List<string>(keywords);
sortedKeywords.Sort();
var info = GetOrCreateShaderVariantInfo(assetPath, shaderName);
ShaderVariantElement element = new ShaderVariantElement();
element.PassType = passType;
element.Keywords = temper.ToArray();
element.Keywords = sortedKeywords.ToArray();
element.MakeSortValue();
info.ShaderVariantElements.Add(element);
info.ShaderVariantCount++;
@@ -126,20 +154,22 @@ public class ShaderVariantCollectionManifest
}
if (selectList.Count != 1)
throw new Exception("Should never get here !");
throw new InvalidOperationException($"Unexpected duplicate ShaderVariantInfo entries (count={selectList.Count}).");
return selectList[0];
}
/// <summary>
/// 解析SVC文件并将数据写入到清单
/// 从 ShaderVariantCollection 提取清单数据
/// </summary>
/// <param name="svc">待解析的着色器变种集合</param>
/// <returns>提取后的着色器变种清单</returns>
public static ShaderVariantCollectionManifest Extract(ShaderVariantCollection svc)
{
if (svc == null)
throw new ArgumentNullException(nameof(svc));
var manifest = new ShaderVariantCollectionManifest();
manifest.ShaderTotalCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
manifest.VariantTotalCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();
using (var so = new SerializedObject(svc))
{
@@ -149,30 +179,23 @@ public class ShaderVariantCollectionManifest
for (int i = 0; i < shaderArray.arraySize; ++i)
{
var shaderRef = shaderArray.FindPropertyRelative($"data[{i}].first");
var shaderVariantsArray = shaderArray.FindPropertyRelative($"data[{i}].second.variants");
if (shaderRef != null && shaderRef.propertyType == SerializedPropertyType.ObjectReference && shaderVariantsArray != null && shaderVariantsArray.isArray)
{
var shader = shaderRef.objectReferenceValue as Shader;
if (shader == null)
{
throw new Exception("Invalid shader in ShaderVariantCollection file.");
}
throw new InvalidOperationException("Invalid shader in ShaderVariantCollection file.");
string shaderAssetPath = AssetDatabase.GetAssetPath(shader);
string shaderName = shader.name;
// 添加变种信息
var shaderVariantsArray = shaderArray.FindPropertyRelative($"data[{i}].second.variants");
for (int j = 0; j < shaderVariantsArray.arraySize; ++j)
{
var propKeywords = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].keywords");
var propPassType = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].passType");
if (propKeywords != null && propPassType != null && propKeywords.propertyType == SerializedPropertyType.String)
{
string[] keywords = propKeywords.stringValue.Split(' ');
PassType pathType = (PassType)propPassType.intValue;
manifest.AddShaderVariant(shaderAssetPath, shaderName, pathType, keywords);
}
}
string[] keywords = propKeywords.stringValue.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
PassType passType = (PassType)propPassType.intValue;
manifest.AddShaderVariant(shaderAssetPath, shaderName, passType, keywords);
}
}
}
@@ -185,6 +208,13 @@ public class ShaderVariantCollectionManifest
shaderVariantInfo.ShaderVariantElements.Sort();
}
// 统计数量
foreach (var shaderVariantInfo in manifest.ShaderVariantInfos)
{
manifest.VariantTotalCount += shaderVariantInfo.ShaderVariantElements.Count;
}
manifest.ShaderTotalCount = manifest.ShaderVariantInfos.Count;
return manifest;
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -8,6 +8,9 @@ using UnityEditor;
using UnityEditor.SceneManagement;
using YooAsset.Editor;
/// <summary>
/// 收集资源包裹中材质产生的着色器变种
/// </summary>
public static class ShaderVariantCollector
{
private enum ESteps
@@ -34,21 +37,33 @@ public static class ShaderVariantCollector
/// <summary>
/// 开始收集
/// 启动着色器变种收集流程
/// </summary>
/// <param name="savePath">收集结果保存路径,扩展名必须为 .shadervariants。</param>
/// <param name="packageName">参与收集的资源包裹名称</param>
/// <param name="processMaxNum">每批处理的材质数量</param>
/// <param name="completedCallback">收集完成后的回调</param>
public static void Run(string savePath, string packageName, int processMaxNum, Action completedCallback)
{
if (_steps != ESteps.None)
return;
if (EditorSceneUtility.HasDirtyScenes())
{
UnityEngine.Debug.LogError("Unsaved scenes detected. Save all scenes before collecting shader variants.");
return;
}
if (Path.HasExtension(savePath) == false)
savePath = $"{savePath}.shadervariants";
if (Path.GetExtension(savePath) != ".shadervariants")
throw new System.Exception("Shader variant file extension is invalid.");
throw new System.ArgumentException("Shader variant file extension is invalid.", nameof(savePath));
if (string.IsNullOrEmpty(packageName))
throw new System.Exception("Package name is null or empty !");
throw new System.ArgumentNullException(nameof(packageName));
if (processMaxNum <= 0)
throw new System.ArgumentOutOfRangeException(nameof(processMaxNum), "Process capacity must be greater than zero.");
// 注意:先删除再保存,否则ShaderVariantCollection内容将无法及时刷新
// Unity 对同名 ShaderVariantCollection 的刷新存在延迟,先删除旧资源再写入新结果。
AssetDatabase.DeleteAsset(savePath);
EditorFileUtility.CreateFileDirectory(savePath);
_savePath = savePath;
@@ -67,6 +82,17 @@ public static class ShaderVariantCollector
}
private static void EditorUpdate()
{
try
{
InternalUpdate();
}
catch (Exception ex)
{
Finish(false, ex);
}
}
private static void InternalUpdate()
{
if (_steps == ESteps.None)
return;
@@ -75,14 +101,14 @@ public static class ShaderVariantCollector
{
ShaderVariantCollectionHelper.ClearCurrentShaderVariantCollection();
_steps = ESteps.CollectAllMaterial;
return; //等待一帧
return; // 等待一帧,让编辑器完成清理。
}
if (_steps == ESteps.CollectAllMaterial)
{
_allMaterials = GetAllMaterials();
_steps = ESteps.CollectVariants;
return; //等待一帧
return; // 等待一帧,让材质列表收集结果稳定。
}
if (_steps == ESteps.CollectVariants)
@@ -119,7 +145,7 @@ public static class ShaderVariantCollector
if (_steps == ESteps.WaitingDone)
{
// 注意:一定要延迟保存才会起效
// Unity 需要等待若干帧后才能把当前变种集合写入资源文件。
if (_elapsedTime.ElapsedMilliseconds > WaitMilliseconds)
{
_elapsedTime.Stop();
@@ -129,9 +155,7 @@ public static class ShaderVariantCollector
ShaderVariantCollectionHelper.SaveCurrentShaderVariantCollection(_savePath);
CreateManifest();
UnityEngine.Debug.Log($"搜集SVC完毕");
EditorApplication.update -= EditorUpdate;
_completedCallback?.Invoke();
Finish(true);
}
}
}
@@ -164,7 +188,7 @@ public static class ShaderVariantCollector
result.Add(assetPath);
}
}
EditorDialogUtility.DisplayProgressBar("搜集所有材质球", ++progressValue, collectResult.CollectAssets.Count);
EditorDialogUtility.DisplayProgressBar("Collect All Materials", ++progressValue, collectResult.CollectAssets.Count);
}
EditorDialogUtility.ClearProgressBar();
@@ -175,7 +199,7 @@ public static class ShaderVariantCollector
{
Camera camera = Camera.main;
if (camera == null)
throw new System.Exception("Not found main camera.");
throw new System.InvalidOperationException("Main camera is missing.");
// 设置主相机
float aspect = camera.aspect;
@@ -208,13 +232,19 @@ public static class ShaderVariantCollector
{
x++;
}
EditorDialogUtility.DisplayProgressBar("照射所有材质球", ++progressValue, materials.Count);
EditorDialogUtility.DisplayProgressBar("Render All Materials", ++progressValue, materials.Count);
}
EditorDialogUtility.ClearProgressBar();
}
private static GameObject CreateSphere(string assetPath, Vector3 position, int index)
{
var material = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
if (material == null)
{
UnityEngine.Debug.LogWarning($"Material not found: '{assetPath}'.");
return null;
}
var shader = material.shader;
if (shader == null)
return null;
@@ -229,11 +259,12 @@ public static class ShaderVariantCollector
{
foreach (var go in _allSpheres)
{
if (go != null)
GameObject.DestroyImmediate(go);
}
_allSpheres.Clear();
// 尝试释放编辑器加载的资源
// 材质扫描会加载编辑器资源,收集结束后主动释放以降低内存占用。
EditorUtility.UnloadUnusedAssetsImmediate(true);
}
private static void CreateManifest()
@@ -251,4 +282,39 @@ public static class ShaderVariantCollector
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
private static void Finish(bool success, Exception exception = null)
{
try
{
if (success)
UnityEngine.Debug.Log("Shader variant collection completed.");
else
UnityEngine.Debug.LogError($"Shader variant collection failed: {exception}.");
_completedCallback?.Invoke();
}
finally
{
Cleanup();
}
}
private static void Cleanup()
{
EditorApplication.update -= EditorUpdate;
EditorDialogUtility.ClearProgressBar();
if (_elapsedTime != null)
{
_elapsedTime.Stop();
_elapsedTime = null;
}
DestroyAllSpheres();
_savePath = null;
_packageName = null;
_processMaxNum = 0;
_completedCallback = null;
_allMaterials = null;
_steps = ESteps.None;
}
}

View File

@@ -1,29 +1,54 @@
using UnityEngine;
using UnityEngine;
using UnityEditor;
/// <summary>
/// 保存着色器变种收集工具的编辑器偏好设置
/// </summary>
public class ShaderVariantCollectorSetting : ScriptableObject
{
private const string DefaultSavePath = "Assets/MyShaderVariants.shadervariants";
public static string GeFileSavePath(string packageName)
/// <summary>
/// 查询收集结果保存路径
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <returns>收集结果保存路径</returns>
public static string GetFileSavePath(string packageName)
{
string key = $"{Application.productName}_{packageName}_GeFileSavePath";
string key = $"{Application.productName}_{packageName}_GetFileSavePath";
return EditorPrefs.GetString(key, DefaultSavePath);
}
/// <summary>
/// 设置收集结果保存路径
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <param name="savePath">收集结果保存路径</param>
public static void SetFileSavePath(string packageName, string savePath)
{
string key = $"{Application.productName}_{packageName}_GeFileSavePath";
string key = $"{Application.productName}_{packageName}_GetFileSavePath";
EditorPrefs.SetString(key, savePath);
}
public static int GeProcessCapacity(string packageName)
/// <summary>
/// 查询单批处理容量
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <returns>单批处理容量</returns>
public static int GetProcessCapacity(string packageName)
{
string key = $"{Application.productName}_{packageName}_GeProcessCapacity";
string key = $"{Application.productName}_{packageName}_GetProcessCapacity";
return EditorPrefs.GetInt(key, 1000);
}
/// <summary>
/// 设置单批处理容量
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <param name="capacity">单批处理容量</param>
public static void SetProcessCapacity(string packageName, int capacity)
{
string key = $"{Application.productName}_{packageName}_GeProcessCapacity";
string key = $"{Application.productName}_{packageName}_GetProcessCapacity";
EditorPrefs.SetInt(key, capacity);
}
}

View File

@@ -1,140 +1,115 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using YooAsset.Editor;
/// <summary>
/// 提供着色器变种收集工具窗口
/// </summary>
public class ShaderVariantCollectorWindow : EditorWindow
{
[MenuItem("Tools/着色器变种收集器", false, 100)]
[MenuItem("Tools/Shader Variant Collector", false, 100)]
public static void OpenWindow()
{
ShaderVariantCollectorWindow window = GetWindow<ShaderVariantCollectorWindow>("着色器变种收集工具", true);
ShaderVariantCollectorWindow window = GetWindow<ShaderVariantCollectorWindow>("Shader Variant Collector", true);
window.minSize = new Vector2(800, 600);
}
private Button _collectButton;
private TextField _collectOutputField;
private Label _currentShaderCountField;
private Label _currentVariantCountField;
private SliderInt _processCapacitySlider;
private PopupField<string> _packageField;
private List<string> _packageNames;
private int _packageIndex;
private string _currentPackageName;
private string _collectOutputPath;
private int _processCapacity;
public void CreateGUI()
private void OnEnable()
{
try
{
VisualElement root = this.rootVisualElement;
// 加载布局文件
var visualAsset = UxmlLoader.LoadWindowUxml<ShaderVariantCollectorWindow>();
if (visualAsset == null)
return;
visualAsset.CloneTree(root);
// 包裹名称列表
_packageNames = GetBuildPackageNames();
_currentPackageName = _packageNames[0];
// 文件输出目录
_collectOutputField = root.Q<TextField>("CollectOutput");
_collectOutputField.SetValueWithoutNotify(ShaderVariantCollectorSetting.GeFileSavePath(_currentPackageName));
_collectOutputField.RegisterValueChangedCallback(evt =>
{
ShaderVariantCollectorSetting.SetFileSavePath(_currentPackageName, _collectOutputField.value);
});
// 收集的包裹
var packageContainer = root.Q("PackageContainer");
if (_packageNames.Count > 0)
{
int defaultIndex = GetDefaultPackageIndex(_currentPackageName);
_packageField = new PopupField<string>(_packageNames, defaultIndex);
_packageField.label = "Package";
_packageField.style.width = 350;
_packageField.RegisterValueChangedCallback(evt =>
{
_currentPackageName = _packageField.value;
});
packageContainer.Add(_packageField);
_packageIndex = 0;
_currentPackageName = _packageNames[_packageIndex];
RefreshPackageSettings();
}
else
}
private void OnGUI()
{
_packageField = new PopupField<string>();
_packageField.label = "Package";
_packageField.style.width = 350;
packageContainer.Add(_packageField);
EditorGUILayout.Space(4);
bool hasPackages = _packageNames.Count > 0;
// Package
EditorGUI.BeginDisabledGroup(!hasPackages);
{
int newIndex = EditorGUILayout.Popup("Package", _packageIndex, _packageNames.ToArray());
if (newIndex != _packageIndex && hasPackages)
{
_packageIndex = newIndex;
_currentPackageName = _packageNames[_packageIndex];
RefreshPackageSettings();
}
}
EditorGUI.EndDisabledGroup();
// Save path
string newPath = EditorGUILayout.TextField("Save Path", _collectOutputPath);
if (newPath != _collectOutputPath)
{
_collectOutputPath = newPath;
if (!string.IsNullOrEmpty(_currentPackageName))
ShaderVariantCollectorSetting.SetFileSavePath(_currentPackageName, _collectOutputPath);
}
// 容器值
_processCapacitySlider = root.Q<SliderInt>("ProcessCapacity");
_processCapacitySlider.SetValueWithoutNotify(ShaderVariantCollectorSetting.GeProcessCapacity(_currentPackageName));
#if !UNITY_2020_3_OR_NEWER
_processCapacitySlider.label = $"Capacity ({_processCapacitySlider.value})";
_processCapacitySlider.RegisterValueChangedCallback(evt =>
{
ShaderVariantCollectorSetting.SetProcessCapacity(_currentPackageName, _processCapacitySlider.value);
_processCapacitySlider.label = $"Capacity ({_processCapacitySlider.value})";
});
#else
_processCapacitySlider.RegisterValueChangedCallback(evt =>
{
ShaderVariantCollectorSetting.SetProcessCapacity(_currentPackageName, _processCapacitySlider.value);
});
#endif
// Shader / variant counts
int shaderCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
int variantCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();
EditorGUILayout.LabelField("Current Shader Count", shaderCount.ToString());
EditorGUILayout.LabelField("Current Variant Count", variantCount.ToString());
_currentShaderCountField = root.Q<Label>("CurrentShaderCount");
_currentVariantCountField = root.Q<Label>("CurrentVariantCount");
// 变种收集按钮
_collectButton = root.Q<Button>("CollectButton");
_collectButton.clicked += CollectButton_clicked;
}
catch (Exception e)
// Process capacity slider
int newCapacity = EditorGUILayout.IntSlider("Capacity", _processCapacity, 10, 1000);
if (newCapacity != _processCapacity)
{
Debug.LogError(e.ToString());
}
}
private void Update()
{
if (_currentShaderCountField != null)
{
int currentShaderCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
_currentShaderCountField.text = $"Current Shader Count : {currentShaderCount}";
_processCapacity = newCapacity;
if (!string.IsNullOrEmpty(_currentPackageName))
ShaderVariantCollectorSetting.SetProcessCapacity(_currentPackageName, _processCapacity);
}
if (_currentVariantCountField != null)
GUILayout.FlexibleSpace();
// Collect button
EditorGUI.BeginDisabledGroup(!hasPackages);
{
int currentVariantCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();
_currentVariantCountField.text = $"Current Variant Count : {currentVariantCount}";
Color defaultColor = GUI.backgroundColor;
GUI.backgroundColor = new Color(0.16f, 0.42f, 0.16f, 1f);
if (GUILayout.Button("Collect", GUILayout.Height(50)))
{
CollectButtonClicked();
}
GUI.backgroundColor = defaultColor;
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.Space(4);
}
private void CollectButton_clicked()
private void CollectButtonClicked()
{
string savePath = ShaderVariantCollectorSetting.GeFileSavePath(_currentPackageName);
int processCapacity = _processCapacitySlider.value;
ShaderVariantCollector.Run(savePath, _currentPackageName, processCapacity, null);
if (string.IsNullOrEmpty(_currentPackageName))
{
Debug.LogError("Package name is empty.");
return;
}
// 构建包裹相关
private int GetDefaultPackageIndex(string packageName)
{
for (int index = 0; index < _packageNames.Count; index++)
{
if (_packageNames[index] == packageName)
{
return index;
string savePath = ShaderVariantCollectorSetting.GetFileSavePath(_currentPackageName);
ShaderVariantCollector.Run(savePath, _currentPackageName, _processCapacity, null);
}
}
return 0;
private void RefreshPackageSettings()
{
if (string.IsNullOrEmpty(_currentPackageName))
return;
_collectOutputPath = ShaderVariantCollectorSetting.GetFileSavePath(_currentPackageName);
_processCapacity = ShaderVariantCollectorSetting.GetProcessCapacity(_currentPackageName);
}
private List<string> GetBuildPackageNames()
{

View File

@@ -1,11 +0,0 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<uie:Toolbar name="Toolbar" style="display: flex; flex-direction: row-reverse;" />
<ui:VisualElement name="CollectContainer">
<ui:TextField picking-mode="Ignore" label="文件保存路径" name="CollectOutput" style="height: 22px;" />
<ui:VisualElement name="PackageContainer" style="height: 24px;" />
<ui:Label text="Current Shader Count" display-tooltip-when-elided="true" name="CurrentShaderCount" style="height: 20px; padding-left: 4px;" />
<ui:Label text="Current Variant Count" display-tooltip-when-elided="true" name="CurrentVariantCount" style="height: 20px; padding-left: 4px;" />
<ui:SliderInt picking-mode="Ignore" label="Capacity" value="9999" high-value="1000" name="ProcessCapacity" low-value="10" show-input-field="true" />
<ui:Button text="开始搜集" display-tooltip-when-elided="true" name="CollectButton" style="height: 50px; background-color: rgb(40, 106, 42); margin-top: 10px;" />
</ui:VisualElement>
</ui:UXML>

View File

@@ -1,10 +0,0 @@
fileFormatVersion: 2
guid: 9bff4878063eaf04dab8713e1e662ac5
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@@ -0,0 +1,20 @@
{
"name": "YooAsset.Extension.Editor",
"rootNamespace": "",
"references": [
"YooAsset",
"YooAsset.Editor",
"YooAsset.Extension"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d8e79e975991a7547b8ab3d52127065d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,6 @@
fileFormatVersion: 2
guid: 4fdc3ec5aeab28849a55f4ec8619e04c
guid: 1a5b8e8a252caf44eabfaf319fb4b2dc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:

View File

@@ -0,0 +1,38 @@
using System.Collections;
using UnityEngine;
using YooAsset;
/// <summary>
/// 演示如何使用 GameObjectReference 弱引用加载并实例化游戏对象
/// </summary>
public class AssetReferenceSample : MonoBehaviour
{
[SerializeField]
private GameObjectReference _reference;
private IEnumerator Start()
{
if (_reference.RuntimeKeyIsValid() == false)
{
yield break;
}
AssetHandle handle = _reference.LoadAssetAsync();
yield return handle;
if (handle.Status == EOperationStatus.Succeeded)
{
GameObject instance = handle.InstantiateSync(new InstantiateOptions(true, transform, false));
if (instance == null)
Debug.LogError($"Failed to instantiate GameObject reference '{_reference.AssetGUID}'.");
}
else
{
Debug.LogError($"Failed to load GameObject reference '{_reference.AssetGUID}': {handle.Error}.");
}
}
private void OnDestroy()
{
_reference.ReleaseAsset();
}
}

View File

@@ -0,0 +1,75 @@
using System;
using UnityEngine;
using YooAsset;
/// <summary>
/// 游戏对象弱引用,序列化时只保存资源 GUID
/// </summary>
[Serializable]
public class GameObjectReference
{
[SerializeField]
private string _packageName = "DefaultPackage";
[SerializeField]
private string _assetGUID = "";
[NonSerialized]
private AssetHandle _handle;
/// <summary>
/// 资源所属的包裹名称
/// </summary>
public string PackageName => _packageName;
/// <summary>
/// 资源 GUID
/// </summary>
public string AssetGUID => _assetGUID;
/// <summary>
/// 检查运行时引用键是否有效
/// </summary>
public bool RuntimeKeyIsValid()
{
if (string.IsNullOrEmpty(_packageName) || string.IsNullOrEmpty(_assetGUID))
return false;
var package = YooAssets.GetPackage(_packageName);
var assetInfo = package.GetAssetInfoByGuid(_assetGUID, typeof(GameObject));
return assetInfo.IsValid;
}
/// <summary>
/// 异步加载引用的游戏对象
/// </summary>
/// <returns>加载操作句柄</returns>
public AssetHandle LoadAssetAsync()
{
if (_handle != null)
throw new InvalidOperationException("GameObject reference has already been loaded. Release it first.");
if (string.IsNullOrEmpty(_packageName))
throw new ArgumentException("Package name is not set.", nameof(_packageName));
if (string.IsNullOrEmpty(_assetGUID))
throw new ArgumentException("Asset GUID is not set.", nameof(_assetGUID));
var package = YooAssets.GetPackage(_packageName);
var assetInfo = package.GetAssetInfoByGuid(_assetGUID, typeof(GameObject));
_handle = package.LoadAssetAsync(assetInfo);
return _handle;
}
/// <summary>
/// 释放已加载的资源句柄
/// </summary>
public void ReleaseAsset()
{
if (_handle == null)
return;
_handle.Release();
_handle = null;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15552077c0d6ff441a4cd62af62b7d5a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,502 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
#region InitializeParameters
/// <summary>
/// 初始化参数
/// </summary>
public abstract class InitializeParameters
{
/// <summary>
/// 同时加载Bundle文件的最大并发数
/// </summary>
public int BundleLoadingMaxConcurrency = int.MaxValue;
/// <summary>
/// 当资源引用计数为零的时候自动释放资源包
/// </summary>
public bool AutoUnloadBundleWhenUnused = false;
/// <summary>
/// WebGL平台强制同步加载资源对象
/// </summary>
public bool WebGLForceSyncLoadAsset = false;
}
/// <summary>
/// 编辑器下模拟运行模式的初始化参数
/// </summary>
public class EditorSimulateModeParameters : InitializeParameters
{
public FileSystemParameters EditorFileSystemParameters;
}
/// <summary>
/// 离线运行模式的初始化参数
/// </summary>
public class OfflinePlayModeParameters : InitializeParameters
{
public FileSystemParameters BuiltinFileSystemParameters;
}
/// <summary>
/// 联机运行模式的初始化参数
/// </summary>
public class HostPlayModeParameters : InitializeParameters
{
public FileSystemParameters BuiltinFileSystemParameters;
public FileSystemParameters CacheFileSystemParameters;
}
/// <summary>
/// WebGL运行模式的初始化参数
/// </summary>
public class WebPlayModeParameters : InitializeParameters
{
public FileSystemParameters WebServerFileSystemParameters;
public FileSystemParameters WebRemoteFileSystemParameters;
}
#endregion
#region InitializationOperation
public class InitializationOperation : AsyncOperationBase
{
private bool _isDone = false;
private readonly InitializePackageOperation _operation;
internal InitializationOperation(InitializePackageOperation op)
{
_operation = op;
}
protected override void InternalStart()
{
}
protected override void InternalUpdate()
{
if (_isDone)
return;
_operation.UpdateOperation();
if (_operation.IsDone == false)
return;
_isDone = true;
if (_operation.Status == EOperationStatus.Succeeded)
SetResult();
else
SetError(_operation.Error);
}
}
#endregion
#region DestroyOperation
public class DestroyOperation : AsyncOperationBase
{
private bool _isDone = false;
private readonly DestroyPackageOperation _operation;
internal DestroyOperation(DestroyPackageOperation op)
{
_operation = op;
}
protected override void InternalStart()
{
}
protected override void InternalUpdate()
{
if (_isDone)
return;
_operation.UpdateOperation();
if (_operation.IsDone == false)
return;
_isDone = true;
if (_operation.Status == EOperationStatus.Succeeded)
SetResult();
else
SetError(_operation.Error);
}
}
#endregion
#region UpdatePackageManifestOperation
public class UpdatePackageManifestOperation : AsyncOperationBase
{
private bool _isDone = false;
private readonly LoadPackageManifestOperation _operation;
internal UpdatePackageManifestOperation(LoadPackageManifestOperation op)
{
_operation = op;
}
protected override void InternalStart()
{
}
protected override void InternalUpdate()
{
if (_isDone)
return;
_operation.UpdateOperation();
if (_operation.IsDone == false)
return;
_isDone = true;
if (_operation.Status == EOperationStatus.Succeeded)
SetResult();
else
SetError(_operation.Error);
}
}
#endregion
#region ImportFileInfo
public struct ImportFileInfo
{
/// <summary>
/// 本地文件路径
/// </summary>
public string FilePath;
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 资源包GUID
/// </summary>
public string BundleGuid;
}
#endregion
public static class CompatibleResourcePackage
{
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static InitializationOperation InitializeAsync(this ResourcePackage package, InitializeParameters parameters)
{
if (parameters is EditorSimulateModeParameters)
{
var initializeParameters = parameters as EditorSimulateModeParameters;
var options = new EditorSimulateModeOptions();
options.BundleLoadingMaxConcurrency = initializeParameters.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = initializeParameters.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = initializeParameters.WebGLForceSyncLoadAsset;
options.EditorFileSystemParameters = initializeParameters.EditorFileSystemParameters;
var operation = package.InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
else if (parameters is OfflinePlayModeParameters)
{
var initializeParameters = parameters as OfflinePlayModeParameters;
var options = new OfflinePlayModeOptions();
options.BundleLoadingMaxConcurrency = initializeParameters.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = initializeParameters.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = initializeParameters.WebGLForceSyncLoadAsset;
options.BuiltinFileSystemParameters = initializeParameters.BuiltinFileSystemParameters;
var operation = package.InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
else if (parameters is HostPlayModeParameters)
{
var initializeParameters = parameters as HostPlayModeParameters;
var options = new HostPlayModeOptions();
options.BundleLoadingMaxConcurrency = initializeParameters.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = initializeParameters.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = initializeParameters.WebGLForceSyncLoadAsset;
options.BuiltinFileSystemParameters = initializeParameters.BuiltinFileSystemParameters;
options.CacheFileSystemParameters = initializeParameters.CacheFileSystemParameters;
var operation = package.InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
else if (parameters is WebPlayModeParameters)
{
var initializeParameters = parameters as WebPlayModeParameters;
var options = new WebPlayModeOptions();
options.BundleLoadingMaxConcurrency = initializeParameters.BundleLoadingMaxConcurrency;
options.AutoUnloadBundleWhenUnused = initializeParameters.AutoUnloadBundleWhenUnused;
options.WebGLForceSyncLoadAsset = initializeParameters.WebGLForceSyncLoadAsset;
options.WebServerFileSystemParameters = initializeParameters.WebServerFileSystemParameters;
options.WebRemoteFileSystemParameters = initializeParameters.WebRemoteFileSystemParameters;
var operation = package.InitializePackageAsync(options);
var wrapper = new InitializationOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
else
{
throw new System.NotImplementedException();
}
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static DestroyOperation DestroyAsync(this ResourcePackage package)
{
var operation = package.DestroyPackageAsync();
var wrapper = new DestroyOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static RequestPackageVersionOperation RequestPackageVersionAsync(this ResourcePackage package, bool appendTimeTicks = true, int timeout = 60)
{
var options = new RequestPackageVersionOptions(appendTimeTicks, timeout);
return package.RequestPackageVersionAsync(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static UpdatePackageManifestOperation UpdatePackageManifestAsync(this ResourcePackage package, string packageVersion, int timeout = 60)
{
var options = new LoadPackageManifestOptions(packageVersion, timeout);
var operation = package.LoadPackageManifestAsync(options);
var wrapper = new UpdatePackageManifestOperation(operation);
AsyncOperationSystem.StartOperation(package.PackageName, wrapper);
return wrapper;
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static PrefetchManifestOperation PreDownloadContentAsync(this ResourcePackage package, string packageVersion, int timeout = 60)
{
var options = new PrefetchManifestOptions(packageVersion, timeout);
return package.PrefetchManifestAsync(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ClearCacheOperation ClearCacheFilesAsync(this ResourcePackage package, string fileClearMode, object clearParam = null)
{
var options = new ClearCacheOptions(fileClearMode, clearParam);
return package.ClearCacheAsync(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static UnloadUnusedAssetsOperation UnloadUnusedAssetsAsync(this ResourcePackage package, int loopCount)
{
var options = new UnloadUnusedAssetsOptions(loopCount);
return package.UnloadUnusedAssetsAsync(options);
}
#region
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateResourceDownloader(this ResourcePackage package, int downloadingMaxNumber, int failedTryAgain)
{
var options = new ResourceDownloaderOptions(downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateResourceDownloader(this ResourcePackage package, string tag, int downloadingMaxNumber, int failedTryAgain)
{
string[] tags = new string[] { tag };
var options = new ResourceDownloaderOptions(tags, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateResourceDownloader(this ResourcePackage package, string[] tags, int downloadingMaxNumber, int failedTryAgain)
{
var options = new ResourceDownloaderOptions(tags, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, string location, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
var assetInfo = package.ConvertLocationToAssetInfo(location, null);
var options = new BundleDownloaderOptions(assetInfo, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, string location, int downloadingMaxNumber, int failedTryAgain)
{
return package.CreateBundleDownloader(location, false, downloadingMaxNumber, failedTryAgain);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, string[] locations, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
List<AssetInfo> assetInfos = new List<AssetInfo>(locations.Length);
foreach (var location in locations)
{
var assetInfo = package.ConvertLocationToAssetInfo(location, null);
assetInfos.Add(assetInfo);
}
var options = new BundleDownloaderOptions(assetInfos.ToArray(), recursiveDownload, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, string[] locations, int downloadingMaxNumber, int failedTryAgain)
{
return package.CreateBundleDownloader(locations, false, downloadingMaxNumber, failedTryAgain);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, AssetInfo assetInfo, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
AssetInfo[] assetInfos = new AssetInfo[] { assetInfo };
var options = new BundleDownloaderOptions(assetInfos, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, AssetInfo assetInfo, int downloadingMaxNumber, int failedTryAgain)
{
return package.CreateBundleDownloader(assetInfo, false, downloadingMaxNumber, failedTryAgain);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, AssetInfo[] assetInfos, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{
var options = new BundleDownloaderOptions(assetInfos, recursiveDownload, downloadingMaxNumber, failedTryAgain);
return package.CreateResourceDownloader(options);
}
public static ResourceDownloaderOperation CreateBundleDownloader(this ResourcePackage package, AssetInfo[] assetInfos, int downloadingMaxNumber, int failedTryAgain)
{
return package.CreateBundleDownloader(assetInfos, false, downloadingMaxNumber, failedTryAgain);
}
#endregion
#region
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceUnpackerOperation CreateResourceUnpacker(this ResourcePackage package, int unpackingMaxNumber, int failedTryAgain)
{
var options = new ResourceUnpackerOptions(unpackingMaxNumber, failedTryAgain);
return package.CreateResourceUnpacker(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceUnpackerOperation CreateResourceUnpacker(this ResourcePackage package, string tag, int unpackingMaxNumber, int failedTryAgain)
{
string[] tags = new string[] { tag };
var options = new ResourceUnpackerOptions(tags, unpackingMaxNumber, failedTryAgain);
return package.CreateResourceUnpacker(options);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceUnpackerOperation CreateResourceUnpacker(this ResourcePackage package, string[] tags, int unpackingMaxNumber, int failedTryAgain)
{
var options = new ResourceUnpackerOptions(tags, unpackingMaxNumber, failedTryAgain);
return package.CreateResourceUnpacker(options);
}
#endregion
#region
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceImporterOperation CreateResourceImporter(this ResourcePackage package, string[] filePaths, int importerMaxNumber, int failedTryAgain)
{
ImportFileInfo[] fileInfos = new ImportFileInfo[filePaths.Length];
for (int i = 0; i < filePaths.Length; i++)
{
ImportFileInfo fileInfo = new ImportFileInfo();
fileInfo.FilePath = filePaths[i];
fileInfos[i] = fileInfo;
}
return package.CreateResourceImporter(fileInfos, importerMaxNumber, failedTryAgain);
}
/// <summary>
/// 兼容Yoo2版本
/// </summary>
public static ResourceImporterOperation CreateResourceImporter(this ResourcePackage package, ImportFileInfo[] fileInfos, int importerMaxNumber, int failedTryAgain)
{
ImportBundleInfo[] bundleInfos = new ImportBundleInfo[fileInfos.Length];
for (int i = 0; i < fileInfos.Length; i++)
{
bundleInfos[i] = new ImportBundleInfo(
filePath: fileInfos[i].FilePath,
bundleName: fileInfos[i].BundleName,
bundleGuid: fileInfos[i].BundleGuid);
}
var options = new BundleImporterOptions(bundleInfos, importerMaxNumber, failedTryAgain);
return package.CreateResourceImporter(options);
}
#endregion
}
public static class CompatibleAssetHandle
{
public static GameObject InstantiateSync(this AssetHandle handle, Transform parent)
{
var options = new InstantiateOptions(true, parent, false);
return handle.InstantiateSync(options);
}
public static GameObject InstantiateSync(this AssetHandle handle, Transform parent, bool worldPositionStays)
{
var options = new InstantiateOptions(true, parent, worldPositionStays);
return handle.InstantiateSync(options);
}
public static GameObject InstantiateSync(this AssetHandle handle, Vector3 position, Quaternion rotation)
{
var options = new InstantiateOptions(true, position, rotation);
return handle.InstantiateSync(options);
}
public static GameObject InstantiateSync(this AssetHandle handle, Vector3 position, Quaternion rotation, Transform parent)
{
var options = new InstantiateOptions(true, parent, position, rotation);
return handle.InstantiateSync(options);
}
public static InstantiateOperation InstantiateAsync(this AssetHandle handle, Transform parent, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, false);
return handle.InstantiateAsync(options);
}
public static InstantiateOperation InstantiateAsync(this AssetHandle handle, Transform parent, bool worldPositionStays, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, worldPositionStays);
return handle.InstantiateAsync(options);
}
public static InstantiateOperation InstantiateAsync(this AssetHandle handle, Vector3 position, Quaternion rotation, bool actived = true)
{
var options = new InstantiateOptions(actived, position, rotation);
return handle.InstantiateAsync(options);
}
public static InstantiateOperation InstantiateAsync(this AssetHandle handle, Vector3 position, Quaternion rotation, Transform parent, bool actived = true)
{
var options = new InstantiateOptions(actived, parent, position, rotation);
return handle.InstantiateAsync(options);
}
}

View File

@@ -3,11 +3,16 @@ using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 提供资源句柄的扩展方法
/// </summary>
public static class AssetHandleExtension
{
/// <summary>
/// 等待异步执行完毕
/// 等待资源加载操作完成
/// </summary>
/// <param name="thisHandle">等待完成的资源句柄</param>
/// <returns>已完成等待的资源句柄</returns>
public static AssetHandle WaitForAsyncOperationComplete(this AssetHandle thisHandle)
{
thisHandle.WaitForAsyncComplete();

View File

@@ -3,8 +3,16 @@ using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 提供资源句柄基类的扩展方法
/// </summary>
public static class HandleBaseExtension
{
/// <summary>
/// 检查句柄是否已成功完成
/// </summary>
/// <param name="thisHandle">待检查的句柄</param>
/// <returns>句柄已完成且状态为成功时返回 true。</returns>
public static bool IsSucceed(this HandleBase thisHandle)
{
return thisHandle.IsDone && thisHandle.Status == EOperationStatus.Succeeded;

View File

@@ -1,156 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using YooAsset;
/// <summary>
/// 拷贝内置清单文件到沙盒目录
/// </summary>
public class CopyBuildinManifestOperation : AsyncOperationBase
{
private enum ESteps
{
None,
CheckHashFile,
UnpackHashFile,
CheckManifestFile,
UnpackManifestFile,
Done,
}
private readonly string _packageName;
private readonly string _packageVersion;
private readonly IDownloadBackend _backend;
private IDownloadFileRequest _hashFileRequest;
private IDownloadFileRequest _manifestFileRequest;
private ESteps _steps = ESteps.None;
public CopyBuildinManifestOperation(string packageName, string packageVersion)
{
_packageName = packageName;
_packageVersion = packageVersion;
_backend = new UnityWebRequestBackend();
}
protected override void InternalStart()
{
_steps = ESteps.CheckHashFile;
}
protected override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckHashFile)
{
string hashFilePath = GetCacheHashFilePath();
if (File.Exists(hashFilePath))
{
_steps = ESteps.CheckManifestFile;
return;
}
_steps = ESteps.UnpackHashFile;
}
if (_steps == ESteps.UnpackHashFile)
{
if(_hashFileRequest == null)
{
string sourcePath = GetBuildinHashFilePath();
string destPath = GetCacheHashFilePath();
string url = DownloadUrlHelper.ToLocalFileUrl(sourcePath);
var args = new DownloadFileRequestArgs(url, 60, 0, destPath);
_hashFileRequest = _backend.CreateFileRequest(args);
_hashFileRequest.SendRequest();
}
if (_hashFileRequest.IsDone == false)
return;
if (_hashFileRequest.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.CheckManifestFile;
}
else
{
_steps = ESteps.Done;
SetError(_hashFileRequest.Error);
}
}
if (_steps == ESteps.CheckManifestFile)
{
string manifestFilePath = GetCacheManifestFilePath();
if (File.Exists(manifestFilePath))
{
_steps = ESteps.Done;
SetResult();
return;
}
_steps = ESteps.UnpackManifestFile;
}
if (_steps == ESteps.UnpackManifestFile)
{
if (_manifestFileRequest == null)
{
string sourcePath = GetBuildinManifestFilePath();
string destPath = GetCacheManifestFilePath();
string url = DownloadUrlHelper.ToLocalFileUrl(sourcePath);
var args = new DownloadFileRequestArgs(url, 60, 0, destPath);
_manifestFileRequest = _backend.CreateFileRequest(args);
_manifestFileRequest.SendRequest();
}
if (_manifestFileRequest.IsDone == false)
return;
if (_manifestFileRequest.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.Done;
SetResult();
}
else
{
_steps = ESteps.Done;
SetError(_manifestFileRequest.Error);
}
}
}
private string GetBuildinYooRoot()
{
return YooAssetConfiguration.GetDefaultBuiltinRoot();
}
private string GetBuildinHashFilePath()
{
string fileRoot = GetBuildinYooRoot();
string fileName = YooAssetConfiguration.GetPackageHashFileName(_packageName, _packageVersion);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
private string GetBuildinManifestFilePath()
{
string fileRoot = GetBuildinYooRoot();
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(_packageName, _packageVersion);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
private string GetCacheYooRoot()
{
return YooAssetConfiguration.GetDefaultCacheRoot();
}
private string GetCacheHashFilePath()
{
string fileRoot = GetCacheYooRoot();
string fileName = YooAssetConfiguration.GetPackageHashFileName(_packageName, _packageVersion);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
private string GetCacheManifestFilePath()
{
string fileRoot = GetCacheYooRoot();
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(_packageName, _packageVersion);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
}

View File

@@ -17,7 +17,6 @@ public class GetBuildinPackageVersionOperation : AsyncOperationBase
}
private readonly string _packageName;
private readonly IDownloadBackend _backend;
private IDownloadTextRequest _downloadTextRequest;
private ESteps _steps = ESteps.None;
@@ -26,10 +25,16 @@ public class GetBuildinPackageVersionOperation : AsyncOperationBase
/// </summary>
public string PackageVersion { private set; get; }
/// <summary>
/// 创建内置资源清单版本查询操作实例
/// </summary>
/// <param name="packageName">资源包裹名称</param>
public GetBuildinPackageVersionOperation(string packageName)
{
if (string.IsNullOrEmpty(packageName))
throw new System.ArgumentNullException(nameof(packageName));
_packageName = packageName;
_backend = new UnityWebRequestBackend();
}
protected override void InternalStart()
{
@@ -47,7 +52,7 @@ public class GetBuildinPackageVersionOperation : AsyncOperationBase
string filePath = GetBuildinPackageVersionFilePath();
string url = DownloadUrlHelper.ToLocalFileUrl(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_downloadTextRequest = _backend.CreateTextRequest(args);
_downloadTextRequest = new UnityWebRequestText(args, null);
_downloadTextRequest.SendRequest();
}
@@ -67,6 +72,14 @@ public class GetBuildinPackageVersionOperation : AsyncOperationBase
}
}
}
protected override void InternalDispose()
{
if (_downloadTextRequest != null)
{
_downloadTextRequest.Dispose();
_downloadTextRequest = null;
}
}
private string GetBuildinYooRoot()
{

View File

@@ -20,13 +20,20 @@ public class GetCacheBundleSizeOperation : AsyncOperationBase
private ESteps _steps = ESteps.None;
/// <summary>
/// 总大小单位字节
/// 缓存文件总大小单位字节
/// </summary>
public long TotalSize = 0;
public long TotalSize { private set; get; }
/// <summary>
/// 创建缓存文件大小统计操作实例
/// </summary>
/// <param name="packageName">资源包裹名称</param>
public GetCacheBundleSizeOperation(string packageName)
{
if (string.IsNullOrEmpty(packageName))
throw new System.ArgumentNullException(nameof(packageName));
_packageName = packageName;
}
protected override void InternalStart()

View File

@@ -4,6 +4,10 @@ using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 按资源标签加载一组资源对象
/// </summary>
/// <typeparam name="TObject">资源对象的 Unity 类型</typeparam>
public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObject : UnityEngine.Object
{
private enum ESteps
@@ -18,15 +22,26 @@ public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObjec
private readonly string _tag;
private ESteps _steps = ESteps.None;
private List<AssetHandle> _handles;
private List<TObject> _assetObjects;
/// <summary>
/// 资源对象集合
/// 加载成功的资源对象集合
/// </summary>
public List<TObject> AssetObjects { private set; get; }
public IReadOnlyList<TObject> AssetObjects { get { return _assetObjects; } }
/// <summary>
/// 创建按标签加载资源对象的操作实例
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <param name="tag">资源标签</param>
public LoadAssetsByTagOperation(string packageName, string tag)
{
if (string.IsNullOrEmpty(packageName))
throw new System.ArgumentNullException(nameof(packageName));
if (string.IsNullOrEmpty(tag))
throw new System.ArgumentNullException(nameof(tag));
_packageName = packageName;
_tag = tag;
}
@@ -65,7 +80,7 @@ public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObjec
index++;
}
AssetObjects = new List<TObject>(_handles.Count);
_assetObjects = new List<TObject>(_handles.Count);
foreach (var handle in _handles)
{
if (handle.Status == EOperationStatus.Succeeded)
@@ -73,21 +88,21 @@ public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObjec
var assetObject = handle.AssetObject as TObject;
if (assetObject != null)
{
AssetObjects.Add(assetObject);
_assetObjects.Add(assetObject);
}
else
{
string error = $"资源类型转换失败:{handle.AssetObject.name}";
Debug.LogError($"{error}");
AssetObjects.Clear();
string error = $"Asset type cast failed: {handle.AssetObject.name}";
Debug.LogError(error);
_assetObjects.Clear();
SetFailed(error);
return;
}
}
else
{
Debug.LogError($"{handle.Error}");
AssetObjects.Clear();
Debug.LogError(handle.Error);
_assetObjects.Clear();
SetFailed(handle.Error);
return;
}
@@ -108,10 +123,13 @@ public class LoadAssetsByTagOperation<TObject> : AsyncOperationBase where TObjec
}
/// <summary>
/// 释放资源句柄
/// 释放加载过程中创建的资源句柄
/// </summary>
public void ReleaseHandle()
{
if (_handles == null)
return;
foreach (var handle in _handles)
{
handle.Release();

View File

@@ -4,8 +4,21 @@ using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 提供资源包裹的游戏对象加载扩展方法
/// </summary>
public static class YooAssetsExtension
{
/// <summary>
/// 加载并实例化游戏对象
/// </summary>
/// <param name="package">发起加载的资源包裹</param>
/// <param name="location">资源定位地址</param>
/// <param name="position">实例化位置</param>
/// <param name="rotation">实例化旋转</param>
/// <param name="parent">实例化父节点</param>
/// <param name="destroyGoOnRelease">释放句柄时是否销毁实例对象</param>
/// <returns>游戏对象加载操作句柄</returns>
public static LoadGameObjectOperation LoadGameObjectAsync(this ResourcePackage package, string location, Vector3 position, Quaternion rotation, Transform parent, bool destroyGoOnRelease = false)
{
var operation = new LoadGameObjectOperation(package.PackageName, location, position, rotation, parent, destroyGoOnRelease);
@@ -14,6 +27,9 @@ public static class YooAssetsExtension
}
}
/// <summary>
/// 加载并实例化游戏对象的操作
/// </summary>
public class LoadGameObjectOperation : AsyncOperationBase
{
private enum ESteps
@@ -25,7 +41,7 @@ public class LoadGameObjectOperation : AsyncOperationBase
private readonly string _packageName;
private readonly string _location;
private readonly Vector3 _positon;
private readonly Vector3 _position;
private readonly Quaternion _rotation;
private readonly Transform _parent;
private readonly bool _destroyGoOnRelease;
@@ -33,16 +49,29 @@ public class LoadGameObjectOperation : AsyncOperationBase
private ESteps _steps = ESteps.None;
/// <summary>
/// 加载的游戏对象
/// 加载并实例化后的游戏对象
/// </summary>
public GameObject Go { private set; get; }
public GameObject GameObjectInstance { private set; get; }
/// <summary>
/// 创建游戏对象加载操作实例
/// </summary>
/// <param name="packageName">资源包裹名称</param>
/// <param name="location">资源定位地址</param>
/// <param name="position">实例化位置</param>
/// <param name="rotation">实例化旋转</param>
/// <param name="parent">实例化父节点</param>
/// <param name="destroyGoOnRelease">释放句柄时是否销毁实例对象</param>
public LoadGameObjectOperation(string packageName, string location, Vector3 position, Quaternion rotation, Transform parent, bool destroyGoOnRelease = false)
{
if (string.IsNullOrEmpty(packageName))
throw new System.ArgumentNullException(nameof(packageName));
if (string.IsNullOrEmpty(location))
throw new System.ArgumentNullException(nameof(location));
_packageName = packageName;
_location = location;
_positon = position;
_position = position;
_rotation = rotation;
_parent = parent;
_destroyGoOnRelease = destroyGoOnRelease;
@@ -70,12 +99,12 @@ public class LoadGameObjectOperation : AsyncOperationBase
if (_handle.Status != EOperationStatus.Succeeded)
{
SetError(_handle.Error);
SetError($"Failed to load GameObject '{_location}': {_handle.Error}.");
_steps = ESteps.Done;
}
else
{
Go = _handle.InstantiateSync(_positon, _rotation, _parent);
GameObjectInstance = _handle.InstantiateSync(new InstantiateOptions(true, _parent, _position, _rotation));
SetResult();
_steps = ESteps.Done;
}
@@ -83,7 +112,7 @@ public class LoadGameObjectOperation : AsyncOperationBase
}
/// <summary>
/// 释放资源句柄
/// 释放加载过程中创建的资源句柄
/// </summary>
public void ReleaseHandle()
{
@@ -93,8 +122,8 @@ public class LoadGameObjectOperation : AsyncOperationBase
if (_destroyGoOnRelease)
{
if (Go != null)
GameObject.Destroy(Go);
if (GameObjectInstance != null)
GameObject.Destroy(GameObjectInstance);
}
}
}

View File

@@ -1,16 +1,21 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using YooAsset;
public class OperationHelper
/// <summary>
/// 提供业务自定义操作的启动入口
/// </summary>
public static class OperationHelper
{
/// <summary>
/// 开始一个业务实现的自定义异步任务
/// 启动业务自定义操作
/// </summary>
public static void StartOperation(AsyncOperationBase operation)
/// <param name="packageName">调度器或资源包裹名称</param>
/// <param name="operation">待启动的操作实例</param>
public static void StartOperation(string packageName, AsyncOperationBase operation)
{
AsyncOperationSystem.StartOperation(AsyncOperationSystem.GlobalSchedulerName, operation);
AsyncOperationSystem.StartOperation(packageName, operation);
}
}

View File

@@ -1,73 +0,0 @@
using UnityEngine;
using YooAsset;
#if UNITY_EDITOR
[UnityEditor.CustomEditor(typeof(GameObjectAssetReference), true)]
public class GameObjectAssetReferenceInspector : UnityEditor.Editor
{
private bool _init = false;
private GameObject _cacheObject;
public override void OnInspectorGUI()
{
GameObjectAssetReference mono = (GameObjectAssetReference)target;
if (_init == false)
{
_init = true;
if (string.IsNullOrEmpty(mono.AssetGUID) == false)
{
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(mono.AssetGUID);
if (string.IsNullOrEmpty(assetPath) == false)
{
_cacheObject = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
}
}
}
GameObject go = (GameObject)UnityEditor.EditorGUILayout.ObjectField(_cacheObject, typeof(GameObject), false);
if (go != _cacheObject)
{
_cacheObject = go;
string assetPath = UnityEditor.AssetDatabase.GetAssetPath(go);
mono.AssetGUID = UnityEditor.AssetDatabase.AssetPathToGUID(assetPath);
UnityEditor.EditorUtility.SetDirty(target);
}
UnityEditor.EditorGUILayout.LabelField("Asset GUID", mono.AssetGUID);
}
}
#endif
public class GameObjectAssetReference : MonoBehaviour
{
[HideInInspector]
public string AssetGUID = "";
private AssetHandle _handle;
public void Start()
{
var package = YooAssets.GetPackage("DefaultPackage");
var assetInfo = package.GetAssetInfoByGuid(AssetGUID);
_handle = package.LoadAssetAsync(assetInfo);
_handle.Completed += Handle_Completed;
}
public void OnDestroy()
{
if (_handle != null)
{
_handle.Release();
_handle = null;
}
}
private void Handle_Completed(AssetHandle handle)
{
if (handle.Status == EOperationStatus.Succeeded)
{
handle.InstantiateSync(this.transform);
}
}
}

View File

@@ -1,19 +1,13 @@
using System;
using UnityEngine;
using YooAsset;
/// <summary>
/// 演示操作生命周期监控的接入位置
/// </summary>
public static class OperationMonitor
{
/// <summary>
/// 注册操作生命周期回调
/// </summary>
public static void RegisterOperationCallback()
{
}
private static void OperationStartCallback(string packageName, AsyncOperationBase operation)
{
Debug.Log($"Operation start : {operation.GetType().Name}");
}
private static void OperationFinishCallback(string packageName, AsyncOperationBase operation)
{
Debug.Log($"Operation finish : {operation.GetType().Name}");
// TODO: 当前版本不支持全局操作回调注册,请根据业务需求自行实现监控逻辑。
}
}

View File

@@ -1,24 +1,36 @@
using System;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using YooAsset;
/// <summary>
/// 响应 Unity 图集请求并通过资源包裹加载 SpriteAtlas
/// </summary>
public class SpriteAtlasLoader : MonoBehaviour
{
private Dictionary<string, SpriteAtlas> _loadedAtlas = new Dictionary<string, SpriteAtlas>(1000);
private List<AssetHandle> _loadHandles = new List<AssetHandle>(1000);
/// <summary>
/// 注册图集请求回调
/// </summary>
public void Awake()
{
SpriteAtlasManager.atlasRequested += RequestAtlas;
}
/// <summary>
/// 注销图集请求回调并释放已加载图集句柄
/// </summary>
public void OnDestroy()
{
SpriteAtlasManager.atlasRequested -= RequestAtlas;
foreach (var handle in _loadHandles)
{
handle.Release();
}
_loadHandles.Clear();
}
private void RequestAtlas(string atlasName, Action<SpriteAtlas> callback)
@@ -33,7 +45,9 @@ public class SpriteAtlasLoader : MonoBehaviour
var loadHandle = package.LoadAssetSync<SpriteAtlas>(atlasName);
if (loadHandle.Status != EOperationStatus.Succeeded)
{
Debug.LogWarning($"Failed to load sprite atlas : {atlasName} ! {loadHandle.Error}");
Debug.LogWarning($"Failed to load sprite atlas '{atlasName}': {loadHandle.Error}.");
loadHandle.Release();
callback.Invoke(null);
return;
}

View File

@@ -1,12 +1,15 @@
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
/// <summary>
/// 记录 UI 面板依赖的图集资源
/// </summary>
public class PanelManifest : MonoBehaviour
{
/// <summary>
/// 面板自动引用的图集
/// 面板依赖的图集列表
/// </summary>
public List<SpriteAtlas> ReferencesAtlas = new List<SpriteAtlas>();
}

Some files were not shown because too many files have changed in this diff Show More