mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-05-22 08:20:18 +00:00
refactor : 重构代码
This commit is contained in:
@@ -19,7 +19,7 @@ namespace YooAsset.Editor
|
||||
buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
|
||||
buildParameters.BuildinFileRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot();
|
||||
buildParameters.BuildPipeline = EBuildPipeline.EditorSimulateBuildPipeline.ToString();
|
||||
buildParameters.BuildBundleType = (int)EBuildBundleType.VirtualBundle;
|
||||
buildParameters.BuildBundleType = (int)EBundleType.VirtualBundle;
|
||||
buildParameters.BuildTarget = EditorUserBuildSettings.activeBuildTarget;
|
||||
buildParameters.PackageName = packageName;
|
||||
buildParameters.PackageVersion = "Simulate";
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace YooAsset.Editor
|
||||
/// <summary>
|
||||
/// 资源包加密服务类
|
||||
/// </summary>
|
||||
public IEncryptionServices EncryptionServices;
|
||||
public IBundleEncryptionServices EncryptionServices;
|
||||
|
||||
/// <summary>
|
||||
/// 资源清单加密服务类
|
||||
@@ -146,7 +146,7 @@ namespace YooAsset.Editor
|
||||
string message = BuildLogger.GetErrorMessage(ErrorCode.BuildPipelineIsNullOrEmpty, "Build pipeline is null or empty !");
|
||||
throw new Exception(message);
|
||||
}
|
||||
if (BuildBundleType == (int)EBuildBundleType.Unknown)
|
||||
if (BuildBundleType == (int)EBundleType.Unknown)
|
||||
{
|
||||
string message = BuildLogger.GetErrorMessage(ErrorCode.BuildBundleTypeIsUnknown, $"Build bundle type is unknown {BuildBundleType} !");
|
||||
throw new Exception(message);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace YooAsset.Editor
|
||||
string buildinRootDirectory = buildParametersContext.GetBuildinRootDirectory();
|
||||
string buildPackageName = buildParametersContext.Parameters.PackageName;
|
||||
var manifestServices = buildParametersContext.Parameters.ManifestRestoreServices;
|
||||
CatalogTools.CreateCatalogFile(manifestServices, buildPackageName, buildinRootDirectory);
|
||||
CatalogFileTools.CreateFile(manifestServices, buildPackageName, buildinRootDirectory);
|
||||
|
||||
// 刷新目录
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace YooAsset.Editor
|
||||
|
||||
// 创建新补丁清单
|
||||
PackageManifest manifest = new PackageManifest();
|
||||
manifest.FileVersion = ManifestDefine.FileVersion;
|
||||
manifest.FileVersion = PackageManifestDefine.FileVersion;
|
||||
manifest.EnableAddressable = buildMapContext.Command.EnableAddressable;
|
||||
manifest.SupportExtensionless = buildMapContext.Command.SupportExtensionless;
|
||||
manifest.LocationToLower = buildMapContext.Command.LocationToLower;
|
||||
@@ -71,7 +71,7 @@ namespace YooAsset.Editor
|
||||
{
|
||||
string fileName = YooAssetSettingsData.GetManifestJsonFileName(buildParameters.PackageName, buildParameters.PackageVersion);
|
||||
string filePath = $"{packageOutputDirectory}/{fileName}";
|
||||
ManifestTools.SerializeToJson(filePath, manifest);
|
||||
PackageManifestTools.SerializeToJson(filePath, manifest);
|
||||
BuildLogger.Log($"Create package manifest file: {filePath}");
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace YooAsset.Editor
|
||||
{
|
||||
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(buildParameters.PackageName, buildParameters.PackageVersion);
|
||||
packagePath = $"{packageOutputDirectory}/{fileName}";
|
||||
ManifestTools.SerializeToBinary(packagePath, manifest, buildParameters.ManifestProcessServices);
|
||||
PackageManifestTools.SerializeToBinary(packagePath, manifest, buildParameters.ManifestProcessServices);
|
||||
packageHash = HashUtility.FileCRC32(packagePath);
|
||||
BuildLogger.Log($"Create package manifest file: {packagePath}");
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace YooAsset.Editor
|
||||
{
|
||||
ManifestContext manifestContext = new ManifestContext();
|
||||
byte[] bytesData = FileUtility.ReadAllBytes(packagePath);
|
||||
manifestContext.Manifest = ManifestTools.DeserializeFromBinary(bytesData, buildParameters.ManifestRestoreServices);
|
||||
manifestContext.Manifest = PackageManifestTools.DeserializeFromBinary(bytesData, buildParameters.ManifestRestoreServices);
|
||||
context.SetContextObject(manifestContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace YooAsset.Editor
|
||||
string pipelineOutputDirectory = buildParametersContext.GetPipelineOutputDirectory();
|
||||
foreach (var bundleInfo in buildMapContext.Collection)
|
||||
{
|
||||
EncryptFileInfo fileInfo = new EncryptFileInfo();
|
||||
BundleEncryptionContext fileInfo = new BundleEncryptionContext();
|
||||
fileInfo.BundleName = bundleInfo.BundleName;
|
||||
fileInfo.FileLoadPath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
|
||||
var encryptResult = encryptionServices.Encrypt(fileInfo);
|
||||
|
||||
@@ -54,8 +54,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
string bundleName = bundleInfo.BundleName;
|
||||
string fileHash = bundleInfo.PackageFileHash;
|
||||
string fileExtension = ManifestTools.GetRemoteBundleFileExtension(bundleName);
|
||||
string fileName = ManifestTools.GetRemoteBundleFileName(outputNameStyle, bundleName, fileExtension, fileHash);
|
||||
string fileExtension = PackageManifestTools.GetRemoteBundleFileExtension(bundleName);
|
||||
string fileName = PackageManifestTools.GetRemoteBundleFileName(outputNameStyle, bundleName, fileExtension, fileHash);
|
||||
bundleInfo.PackageDestFilePath = $"{packageOutputDirectory}/{fileName}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
public class EncryptionNone : IEncryptionServices
|
||||
public class EncryptionNone : IBundleEncryptionServices
|
||||
{
|
||||
public EncryptResult Encrypt(EncryptFileInfo fileInfo)
|
||||
public BundleEncryptionResult Encrypt(BundleEncryptionContext fileInfo)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -46,13 +46,13 @@ namespace YooAsset.Editor
|
||||
/// <summary>
|
||||
/// 创建资源包加密服务类实例
|
||||
/// </summary>
|
||||
protected IEncryptionServices CreateEncryptionServicesInstance()
|
||||
protected IBundleEncryptionServices CreateEncryptionServicesInstance()
|
||||
{
|
||||
var className = AssetBundleBuilderSetting.GetPackageEncyptionServicesClassName(PackageName, PipelineName);
|
||||
var classTypes = EditorTools.GetAssignableTypes(typeof(IEncryptionServices));
|
||||
var classTypes = EditorTools.GetAssignableTypes(typeof(IBundleEncryptionServices));
|
||||
var classType = classTypes.Find(x => x.FullName.Equals(className));
|
||||
if (classType != null)
|
||||
return (IEncryptionServices)Activator.CreateInstance(classType);
|
||||
return (IBundleEncryptionServices)Activator.CreateInstance(classType);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
@@ -184,7 +184,7 @@ namespace YooAsset.Editor
|
||||
protected PopupField<Type> CreateEncryptionServicesField(VisualElement container)
|
||||
{
|
||||
// 资源包加密服务类
|
||||
var classTypes = EditorTools.GetAssignableTypes(typeof(IEncryptionServices));
|
||||
var classTypes = EditorTools.GetAssignableTypes(typeof(IBundleEncryptionServices));
|
||||
if (classTypes.Count > 0)
|
||||
{
|
||||
var className = AssetBundleBuilderSetting.GetPackageEncyptionServicesClassName(PackageName, PipelineName);
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace YooAsset.Editor
|
||||
buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
|
||||
buildParameters.BuildinFileRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot();
|
||||
buildParameters.BuildPipeline = PipelineName.ToString();
|
||||
buildParameters.BuildBundleType = (int)EBuildBundleType.AssetBundle;
|
||||
buildParameters.BuildBundleType = (int)EBundleType.AssetBundle;
|
||||
buildParameters.BuildTarget = BuildTarget;
|
||||
buildParameters.PackageName = PackageName;
|
||||
buildParameters.PackageVersion = _buildVersionField.value;
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace YooAsset.Editor
|
||||
buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
|
||||
buildParameters.BuildinFileRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot();
|
||||
buildParameters.BuildPipeline = PipelineName.ToString();
|
||||
buildParameters.BuildBundleType = (int)EBuildBundleType.VirtualBundle;
|
||||
buildParameters.BuildBundleType = (int)EBundleType.VirtualBundle;
|
||||
buildParameters.BuildTarget = BuildTarget;
|
||||
buildParameters.PackageName = PackageName;
|
||||
buildParameters.PackageVersion = _buildVersionField.value;
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace YooAsset.Editor
|
||||
buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
|
||||
buildParameters.BuildinFileRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot();
|
||||
buildParameters.BuildPipeline = PipelineName.ToString();
|
||||
buildParameters.BuildBundleType = (int)EBuildBundleType.RawBundle;
|
||||
buildParameters.BuildBundleType = (int)EBundleType.RawBundle;
|
||||
buildParameters.BuildTarget = BuildTarget;
|
||||
buildParameters.PackageName = PackageName;
|
||||
buildParameters.PackageVersion = _buildVersionField.value;
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace YooAsset.Editor
|
||||
buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
|
||||
buildParameters.BuildinFileRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot();
|
||||
buildParameters.BuildPipeline = PipelineName.ToString();
|
||||
buildParameters.BuildBundleType = (int)EBuildBundleType.AssetBundle;
|
||||
buildParameters.BuildBundleType = (int)EBundleType.AssetBundle;
|
||||
buildParameters.BuildTarget = BuildTarget;
|
||||
buildParameters.PackageName = PackageName;
|
||||
buildParameters.PackageVersion = _buildVersionField.value;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace YooAsset.Editor
|
||||
|
||||
private EViewMode _viewMode;
|
||||
private string _searchKeyWord;
|
||||
private DebugReport _currentReport;
|
||||
private DiagnosticReport _currentReport;
|
||||
private RemotePlayerSession _currentPlayerSession;
|
||||
|
||||
private double _lastRepaintTime = 0;
|
||||
@@ -147,9 +147,9 @@ namespace YooAsset.Editor
|
||||
EditorConnection.instance.Initialize();
|
||||
EditorConnection.instance.RegisterConnection(OnHandleConnectionEvent);
|
||||
EditorConnection.instance.RegisterDisconnection(OnHandleDisconnectionEvent);
|
||||
EditorConnection.instance.Register(RemoteDebuggerDefine.kMsgPlayerSendToEditor, OnHandlePlayerMessage);
|
||||
RemoteEditorConnection.Instance.Initialize();
|
||||
RemoteEditorConnection.Instance.Register(RemoteDebuggerDefine.kMsgPlayerSendToEditor, OnHandlePlayerMessage);
|
||||
EditorConnection.instance.Register(DiagnosticSystemDefine.PlayerToEditorMessageId, OnHandlePlayerMessage);
|
||||
MockEditorConnection.Instance.Initialize();
|
||||
MockEditorConnection.Instance.Register(DiagnosticSystemDefine.PlayerToEditorMessageId, OnHandlePlayerMessage);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -161,8 +161,8 @@ namespace YooAsset.Editor
|
||||
// 远程调试
|
||||
EditorConnection.instance.UnregisterConnection(OnHandleConnectionEvent);
|
||||
EditorConnection.instance.UnregisterDisconnection(OnHandleDisconnectionEvent);
|
||||
EditorConnection.instance.Unregister(RemoteDebuggerDefine.kMsgPlayerSendToEditor, OnHandlePlayerMessage);
|
||||
RemoteEditorConnection.Instance.Unregister(RemoteDebuggerDefine.kMsgPlayerSendToEditor);
|
||||
EditorConnection.instance.Unregister(DiagnosticSystemDefine.PlayerToEditorMessageId, OnHandlePlayerMessage);
|
||||
MockEditorConnection.Instance.Unregister(DiagnosticSystemDefine.PlayerToEditorMessageId);
|
||||
_playerSessions.Clear();
|
||||
}
|
||||
public void Update()
|
||||
@@ -192,11 +192,11 @@ namespace YooAsset.Editor
|
||||
private void OnHandlePlayerMessage(MessageEventArgs args)
|
||||
{
|
||||
int playerId = args.playerId;
|
||||
var debugReport = DebugReport.Deserialize(args.data);
|
||||
var debugReport = DiagnosticReport.Deserialize(args.data);
|
||||
|
||||
if (debugReport.DebuggerVersion != RemoteDebuggerDefine.DebuggerVersion)
|
||||
if (debugReport.DebuggerVersion != DiagnosticSystemDefine.DebuggerVersion)
|
||||
{
|
||||
Debug.LogWarning($"Debugger versions are inconsistent : {debugReport.DebuggerVersion} != {RemoteDebuggerDefine.DebuggerVersion}");
|
||||
Debug.LogWarning($"Debugger versions are inconsistent : {debugReport.DebuggerVersion} != {DiagnosticSystemDefine.DebuggerVersion}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,23 +254,23 @@ namespace YooAsset.Editor
|
||||
private void OnRecordToggleValueChange(ChangeEvent<bool> evt)
|
||||
{
|
||||
// 发送采集数据的命令
|
||||
RemoteCommand command = new RemoteCommand();
|
||||
command.CommandType = (int)ERemoteCommand.SampleAuto;
|
||||
command.CommandParam = evt.newValue ? "open" : "close";
|
||||
byte[] data = RemoteCommand.Serialize(command);
|
||||
EditorConnection.instance.Send(RemoteDebuggerDefine.kMsgEditorSendToPlayer, data);
|
||||
RemoteEditorConnection.Instance.Send(RemoteDebuggerDefine.kMsgEditorSendToPlayer, data);
|
||||
RemoteDebugCommand command = new RemoteDebugCommand();
|
||||
command.CommandType = (int)EDebugCommandType.AutoSampling;
|
||||
command.Parameter = evt.newValue ? "open" : "close";
|
||||
byte[] data = RemoteDebugCommand.Serialize(command);
|
||||
EditorConnection.instance.Send(DiagnosticSystemDefine.EditorToPlayerMessageId, data);
|
||||
MockEditorConnection.Instance.Send(DiagnosticSystemDefine.EditorToPlayerMessageId, data);
|
||||
}
|
||||
|
||||
private void SampleBtn_onClick()
|
||||
{
|
||||
// 发送采集数据的命令
|
||||
RemoteCommand command = new RemoteCommand();
|
||||
command.CommandType = (int)ERemoteCommand.SampleOnce;
|
||||
command.CommandParam = string.Empty;
|
||||
byte[] data = RemoteCommand.Serialize(command);
|
||||
EditorConnection.instance.Send(RemoteDebuggerDefine.kMsgEditorSendToPlayer, data);
|
||||
RemoteEditorConnection.Instance.Send(RemoteDebuggerDefine.kMsgEditorSendToPlayer, data);
|
||||
RemoteDebugCommand command = new RemoteDebugCommand();
|
||||
command.CommandType = (int)EDebugCommandType.SampleOnce;
|
||||
command.Parameter = string.Empty;
|
||||
byte[] data = RemoteDebugCommand.Serialize(command);
|
||||
EditorConnection.instance.Send(DiagnosticSystemDefine.EditorToPlayerMessageId, data);
|
||||
MockEditorConnection.Instance.Send(DiagnosticSystemDefine.EditorToPlayerMessageId, data);
|
||||
}
|
||||
private void ExportBtn_clicked()
|
||||
{
|
||||
@@ -284,16 +284,16 @@ namespace YooAsset.Editor
|
||||
if (resultPath != null)
|
||||
{
|
||||
// 注意:排序保证生成配置的稳定性
|
||||
foreach (var packageData in _currentReport.PackageDatas)
|
||||
foreach (var packageData in _currentReport.PackageDataList)
|
||||
{
|
||||
packageData.ProviderInfos.Sort();
|
||||
foreach (var providerInfo in packageData.ProviderInfos)
|
||||
{
|
||||
providerInfo.DependBundles.Sort();
|
||||
providerInfo.DependentBundles.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
string filePath = $"{resultPath}/{nameof(DebugReport)}_{_currentReport.FrameCount}.json";
|
||||
string filePath = $"{resultPath}/{nameof(DiagnosticReport)}_{_currentReport.FrameCount}.json";
|
||||
string fileContent = JsonUtility.ToJson(_currentReport, true);
|
||||
FileUtility.WriteAllText(filePath, fileContent);
|
||||
Debug.Log($"Debug report file saved : {filePath}");
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace YooAsset.Editor
|
||||
{
|
||||
internal class RemotePlayerSession
|
||||
{
|
||||
private readonly Queue<DebugReport> _reports = new Queue<DebugReport>();
|
||||
private readonly Queue<DiagnosticReport> _reports = new Queue<DiagnosticReport>();
|
||||
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
@@ -55,7 +55,7 @@ namespace YooAsset.Editor
|
||||
/// <summary>
|
||||
/// 添加一个调试报告
|
||||
/// </summary>
|
||||
public void AddDebugReport(DebugReport report)
|
||||
public void AddDebugReport(DiagnosticReport report)
|
||||
{
|
||||
if (report == null)
|
||||
Debug.LogWarning("Invalid debug report data !");
|
||||
@@ -68,7 +68,7 @@ namespace YooAsset.Editor
|
||||
/// <summary>
|
||||
/// 获取调试报告
|
||||
/// </summary>
|
||||
public DebugReport GetDebugReport(int rangeIndex)
|
||||
public DiagnosticReport GetDebugReport(int rangeIndex)
|
||||
{
|
||||
if (_reports.Count == 0)
|
||||
return null;
|
||||
|
||||
@@ -13,12 +13,12 @@ namespace YooAsset.Editor
|
||||
{
|
||||
private class ProviderTableData : DefaultTableData
|
||||
{
|
||||
public DebugPackageData PackageData;
|
||||
public DebugProviderInfo ProviderInfo;
|
||||
public DiagnosticPackageData PackageData;
|
||||
public DiagnosticProviderInfo ProviderInfo;
|
||||
}
|
||||
private class DependTableData : DefaultTableData
|
||||
{
|
||||
public DebugBundleInfo BundleInfo;
|
||||
public DiagnosticBundleInfo BundleInfo;
|
||||
}
|
||||
|
||||
private VisualTreeAsset _visualAsset;
|
||||
@@ -125,13 +125,13 @@ namespace YooAsset.Editor
|
||||
_providerTableView.AddColumn(column);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var columnStyle = new ColumnStyle(100);
|
||||
columnStyle.Stretchable = false;
|
||||
columnStyle.Searchable = false;
|
||||
columnStyle.Sortable = true;
|
||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
||||
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||
column.MakeCell = () =>
|
||||
{
|
||||
var label = new Label();
|
||||
@@ -206,7 +206,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
StyleColor textColor;
|
||||
var providerTableData = data as ProviderTableData;
|
||||
if (providerTableData.ProviderInfo.Status == EOperationStatus.Failed.ToString())
|
||||
if (providerTableData.ProviderInfo.Status == EOperationStatus.Failed.ToString() ||
|
||||
providerTableData.ProviderInfo.Status == EOperationStatus.Aborted.ToString())
|
||||
textColor = new StyleColor(Color.yellow);
|
||||
else
|
||||
textColor = new StyleColor(Color.white);
|
||||
@@ -280,7 +281,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
StyleColor textColor;
|
||||
var dependTableData = data as DependTableData;
|
||||
if (dependTableData.BundleInfo.Status == EOperationStatus.Failed.ToString())
|
||||
if (dependTableData.BundleInfo.Status == EOperationStatus.Failed.ToString() ||
|
||||
dependTableData.BundleInfo.Status == EOperationStatus.Aborted.ToString())
|
||||
textColor = new StyleColor(Color.yellow);
|
||||
else
|
||||
textColor = new StyleColor(Color.white);
|
||||
@@ -296,7 +298,7 @@ namespace YooAsset.Editor
|
||||
/// <summary>
|
||||
/// 填充页面数据
|
||||
/// </summary>
|
||||
public void FillViewData(DebugReport debugReport)
|
||||
public void FillViewData(DiagnosticReport debugReport)
|
||||
{
|
||||
// 清空旧数据
|
||||
_providerTableView.ClearAll(false, true);
|
||||
@@ -304,7 +306,7 @@ namespace YooAsset.Editor
|
||||
|
||||
// 填充数据源
|
||||
_sourceDatas = new List<ITableData>(1000);
|
||||
foreach (var packageData in debugReport.PackageDatas)
|
||||
foreach (var packageData in debugReport.PackageDataList)
|
||||
{
|
||||
foreach (var providerInfo in packageData.ProviderInfos)
|
||||
{
|
||||
@@ -313,10 +315,10 @@ namespace YooAsset.Editor
|
||||
rowData.ProviderInfo = providerInfo;
|
||||
rowData.AddAssetPathCell("PackageName", packageData.PackageName);
|
||||
rowData.AddStringValueCell("AssetPath", providerInfo.AssetPath);
|
||||
rowData.AddStringValueCell("SpawnScene", providerInfo.SpawnScene);
|
||||
rowData.AddStringValueCell("BeginTime", providerInfo.BeginTime);
|
||||
rowData.AddLongValueCell("LoadingTime", providerInfo.LoadingTime);
|
||||
rowData.AddLongValueCell("RefCount", providerInfo.RefCount);
|
||||
rowData.AddStringValueCell("SpawnScene", providerInfo.OriginScene);
|
||||
rowData.AddStringValueCell("StartTime", providerInfo.StartTime);
|
||||
rowData.AddLongValueCell("LoadingTime", providerInfo.ElapsedMS);
|
||||
rowData.AddLongValueCell("RefCount", providerInfo.ReferenceCount);
|
||||
rowData.AddStringValueCell("Status", providerInfo.Status.ToString());
|
||||
_sourceDatas.Add(rowData);
|
||||
}
|
||||
@@ -372,18 +374,18 @@ namespace YooAsset.Editor
|
||||
private void OnProviderTableViewSelectionChanged(ITableData data)
|
||||
{
|
||||
var providerTableData = data as ProviderTableData;
|
||||
DebugPackageData packageData = providerTableData.PackageData;
|
||||
DebugProviderInfo providerInfo = providerTableData.ProviderInfo;
|
||||
DiagnosticPackageData packageData = providerTableData.PackageData;
|
||||
DiagnosticProviderInfo providerInfo = providerTableData.ProviderInfo;
|
||||
|
||||
// 填充依赖数据
|
||||
var sourceDatas = new List<ITableData>(providerInfo.DependBundles.Count);
|
||||
foreach (var bundleName in providerInfo.DependBundles)
|
||||
var sourceDatas = new List<ITableData>(providerInfo.DependentBundles.Count);
|
||||
foreach (var bundleName in providerInfo.DependentBundles)
|
||||
{
|
||||
var dependBundleInfo = packageData.GetBundleInfo(bundleName);
|
||||
var rowData = new DependTableData();
|
||||
rowData.BundleInfo = dependBundleInfo;
|
||||
rowData.AddStringValueCell("DependBundles", dependBundleInfo.BundleName);
|
||||
rowData.AddLongValueCell("RefCount", dependBundleInfo.RefCount);
|
||||
rowData.AddLongValueCell("RefCount", dependBundleInfo.ReferenceCount);
|
||||
rowData.AddStringValueCell("Status", dependBundleInfo.Status.ToString());
|
||||
sourceDatas.Add(rowData);
|
||||
}
|
||||
|
||||
@@ -13,16 +13,16 @@ namespace YooAsset.Editor
|
||||
{
|
||||
private class BundleTableData : DefaultTableData
|
||||
{
|
||||
public DebugPackageData PackageData;
|
||||
public DebugBundleInfo BundleInfo;
|
||||
public DiagnosticPackageData PackageData;
|
||||
public DiagnosticBundleInfo BundleInfo;
|
||||
}
|
||||
private class UsingTableData : DefaultTableData
|
||||
{
|
||||
public DebugProviderInfo ProviderInfo;
|
||||
public DiagnosticProviderInfo ProviderInfo;
|
||||
}
|
||||
private class ReferenceTableData : DefaultTableData
|
||||
{
|
||||
public DebugBundleInfo BundleInfo;
|
||||
public DiagnosticBundleInfo BundleInfo;
|
||||
}
|
||||
|
||||
private VisualTreeAsset _visualAsset;
|
||||
@@ -151,7 +151,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
StyleColor textColor;
|
||||
var bundleTableData = data as BundleTableData;
|
||||
if (bundleTableData.BundleInfo.Status == EOperationStatus.Failed.ToString())
|
||||
if (bundleTableData.BundleInfo.Status == EOperationStatus.Failed.ToString() ||
|
||||
bundleTableData.BundleInfo.Status == EOperationStatus.Aborted.ToString())
|
||||
textColor = new StyleColor(Color.yellow);
|
||||
else
|
||||
textColor = new StyleColor(Color.white);
|
||||
@@ -208,13 +209,13 @@ namespace YooAsset.Editor
|
||||
_usingTableView.AddColumn(column);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var columnStyle = new ColumnStyle(100);
|
||||
columnStyle.Stretchable = false;
|
||||
columnStyle.Searchable = false;
|
||||
columnStyle.Sortable = true;
|
||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
||||
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||
column.MakeCell = () =>
|
||||
{
|
||||
var label = new Label();
|
||||
@@ -267,7 +268,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
StyleColor textColor;
|
||||
var usingTableData = data as UsingTableData;
|
||||
if (usingTableData.ProviderInfo.Status == EOperationStatus.Failed.ToString())
|
||||
if (usingTableData.ProviderInfo.Status == EOperationStatus.Failed.ToString() ||
|
||||
usingTableData.ProviderInfo.Status == EOperationStatus.Aborted.ToString())
|
||||
textColor = new StyleColor(Color.yellow);
|
||||
else
|
||||
textColor = new StyleColor(Color.white);
|
||||
@@ -341,7 +343,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
StyleColor textColor;
|
||||
var feferenceTableData = data as ReferenceTableData;
|
||||
if (feferenceTableData.BundleInfo.Status == EOperationStatus.Failed.ToString())
|
||||
if (feferenceTableData.BundleInfo.Status == EOperationStatus.Failed.ToString() ||
|
||||
feferenceTableData.BundleInfo.Status == EOperationStatus.Aborted.ToString())
|
||||
textColor = new StyleColor(Color.yellow);
|
||||
else
|
||||
textColor = new StyleColor(Color.white);
|
||||
@@ -357,7 +360,7 @@ namespace YooAsset.Editor
|
||||
/// <summary>
|
||||
/// 填充页面数据
|
||||
/// </summary>
|
||||
public void FillViewData(DebugReport debugReport)
|
||||
public void FillViewData(DiagnosticReport debugReport)
|
||||
{
|
||||
// 清空旧数据
|
||||
_bundleTableView.ClearAll(false, true);
|
||||
@@ -366,7 +369,7 @@ namespace YooAsset.Editor
|
||||
|
||||
// 填充数据源
|
||||
_sourceDatas = new List<ITableData>(1000);
|
||||
foreach (var packageData in debugReport.PackageDatas)
|
||||
foreach (var packageData in debugReport.PackageDataList)
|
||||
{
|
||||
foreach (var bundleInfo in packageData.BundleInfos)
|
||||
{
|
||||
@@ -375,7 +378,7 @@ namespace YooAsset.Editor
|
||||
rowData.BundleInfo = bundleInfo;
|
||||
rowData.AddAssetPathCell("PackageName", packageData.PackageName);
|
||||
rowData.AddStringValueCell("BundleName", bundleInfo.BundleName);
|
||||
rowData.AddLongValueCell("RefCount", bundleInfo.RefCount);
|
||||
rowData.AddLongValueCell("RefCount", bundleInfo.ReferenceCount);
|
||||
rowData.AddStringValueCell("Status", bundleInfo.Status.ToString());
|
||||
_sourceDatas.Add(rowData);
|
||||
}
|
||||
@@ -443,16 +446,16 @@ namespace YooAsset.Editor
|
||||
var sourceDatas = new List<ITableData>(1000);
|
||||
foreach (var providerInfo in packageData.ProviderInfos)
|
||||
{
|
||||
foreach (var dependBundleName in providerInfo.DependBundles)
|
||||
foreach (var dependBundleName in providerInfo.DependentBundles)
|
||||
{
|
||||
if (dependBundleName == selectBundleInfo.BundleName)
|
||||
{
|
||||
var rowData = new UsingTableData();
|
||||
rowData.ProviderInfo = providerInfo;
|
||||
rowData.AddStringValueCell("UsingAssets", providerInfo.AssetPath);
|
||||
rowData.AddStringValueCell("SpawnScene", providerInfo.SpawnScene);
|
||||
rowData.AddStringValueCell("BeginTime", providerInfo.BeginTime);
|
||||
rowData.AddLongValueCell("RefCount", providerInfo.RefCount);
|
||||
rowData.AddStringValueCell("SpawnScene", providerInfo.OriginScene);
|
||||
rowData.AddStringValueCell("StartTime", providerInfo.StartTime);
|
||||
rowData.AddLongValueCell("RefCount", providerInfo.ReferenceCount);
|
||||
rowData.AddStringValueCell("Status", providerInfo.Status);
|
||||
sourceDatas.Add(rowData);
|
||||
break;
|
||||
@@ -466,13 +469,13 @@ namespace YooAsset.Editor
|
||||
// 填充ReferenceTableView
|
||||
{
|
||||
var sourceDatas = new List<ITableData>(1000);
|
||||
foreach (string referenceBundleName in selectBundleInfo.ReferenceBundles)
|
||||
foreach (string referenceBundleName in selectBundleInfo.ReferencedByBundles)
|
||||
{
|
||||
var bundleInfo = packageData.GetBundleInfo(referenceBundleName);
|
||||
var rowData = new ReferenceTableData();
|
||||
rowData.BundleInfo = bundleInfo;
|
||||
rowData.AddStringValueCell("BundleName", bundleInfo.BundleName);
|
||||
rowData.AddLongValueCell("RefCount", bundleInfo.RefCount);
|
||||
rowData.AddLongValueCell("RefCount", bundleInfo.ReferenceCount);
|
||||
rowData.AddStringValueCell("Status", bundleInfo.Status.ToString());
|
||||
sourceDatas.Add(rowData);
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
private class OperationTableData : DefaultTableData
|
||||
{
|
||||
public DebugPackageData PackageData;
|
||||
public DebugOperationInfo OperationInfo;
|
||||
public DiagnosticPackageData PackageData;
|
||||
public DiagnosticOperationInfo OperationInfo;
|
||||
}
|
||||
|
||||
private VisualTreeAsset _visualAsset;
|
||||
@@ -147,13 +147,13 @@ namespace YooAsset.Editor
|
||||
_operationTableView.AddColumn(column);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var columnStyle = new ColumnStyle(100);
|
||||
columnStyle.Stretchable = false;
|
||||
columnStyle.Searchable = false;
|
||||
columnStyle.Sortable = true;
|
||||
var column = new TableColumn("BeginTime", "Begin Time", columnStyle);
|
||||
var column = new TableColumn("StartTime", "Start Time", columnStyle);
|
||||
column.MakeCell = () =>
|
||||
{
|
||||
var label = new Label();
|
||||
@@ -168,14 +168,14 @@ namespace YooAsset.Editor
|
||||
_operationTableView.AddColumn(column);
|
||||
}
|
||||
|
||||
// ProcessTime
|
||||
// ElapsedMS
|
||||
{
|
||||
var columnStyle = new ColumnStyle(130);
|
||||
columnStyle.Stretchable = false;
|
||||
columnStyle.Searchable = false;
|
||||
columnStyle.Sortable = true;
|
||||
columnStyle.Units = "ms";
|
||||
var column = new TableColumn("ProcessTime", "Process Time", columnStyle);
|
||||
var column = new TableColumn("ElapsedMS", "Elapsed MS", columnStyle);
|
||||
column.MakeCell = () =>
|
||||
{
|
||||
var label = new Label();
|
||||
@@ -207,7 +207,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
StyleColor textColor;
|
||||
var operationTableData = data as OperationTableData;
|
||||
if (operationTableData.OperationInfo.Status == EOperationStatus.Failed.ToString())
|
||||
if (operationTableData.OperationInfo.Status == EOperationStatus.Failed.ToString() ||
|
||||
operationTableData.OperationInfo.Status == EOperationStatus.Aborted.ToString())
|
||||
textColor = new StyleColor(Color.yellow);
|
||||
else
|
||||
textColor = new StyleColor(Color.white);
|
||||
@@ -259,19 +260,19 @@ namespace YooAsset.Editor
|
||||
_bottomToolbar.Add(button);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
ToolbarButton button = new ToolbarButton();
|
||||
button.text = "BeginTime";
|
||||
button.text = "StartTime";
|
||||
button.style.flexGrow = 0;
|
||||
button.style.width = 100;
|
||||
_bottomToolbar.Add(button);
|
||||
}
|
||||
|
||||
// ProcessTime
|
||||
// ElapsedMS
|
||||
{
|
||||
ToolbarButton button = new ToolbarButton();
|
||||
button.text = "ProcessTime (ms)";
|
||||
button.text = "ElapsedMS";
|
||||
button.style.flexGrow = 0;
|
||||
button.style.width = 130;
|
||||
_bottomToolbar.Add(button);
|
||||
@@ -299,7 +300,7 @@ namespace YooAsset.Editor
|
||||
/// <summary>
|
||||
/// 填充页面数据
|
||||
/// </summary>
|
||||
public void FillViewData(DebugReport debugReport)
|
||||
public void FillViewData(DiagnosticReport debugReport)
|
||||
{
|
||||
// 清空旧数据
|
||||
_operationTableView.ClearAll(false, true);
|
||||
@@ -308,7 +309,7 @@ namespace YooAsset.Editor
|
||||
|
||||
// 填充数据源
|
||||
_sourceDatas = new List<ITableData>(1000);
|
||||
foreach (var packageData in debugReport.PackageDatas)
|
||||
foreach (var packageData in debugReport.PackageDataList)
|
||||
{
|
||||
foreach (var operationInfo in packageData.OperationInfos)
|
||||
{
|
||||
@@ -319,8 +320,8 @@ namespace YooAsset.Editor
|
||||
rowData.AddStringValueCell("OperationName", operationInfo.OperationName);
|
||||
rowData.AddLongValueCell("Priority", operationInfo.Priority);
|
||||
rowData.AddDoubleValueCell("Progress", operationInfo.Progress);
|
||||
rowData.AddStringValueCell("BeginTime", operationInfo.BeginTime);
|
||||
rowData.AddLongValueCell("LoadingTime", operationInfo.ProcessTime);
|
||||
rowData.AddStringValueCell("StartTime", operationInfo.StartTime);
|
||||
rowData.AddLongValueCell("ElapsedMS", operationInfo.ElapsedMS);
|
||||
rowData.AddStringValueCell("Status", operationInfo.Status.ToString());
|
||||
rowData.AddStringValueCell("Desc", operationInfo.OperationDesc);
|
||||
_sourceDatas.Add(rowData);
|
||||
@@ -377,8 +378,8 @@ namespace YooAsset.Editor
|
||||
private void OnOperationTableViewSelectionChanged(ITableData data)
|
||||
{
|
||||
var operationTableData = data as OperationTableData;
|
||||
DebugPackageData packageData = operationTableData.PackageData;
|
||||
DebugOperationInfo operationInfo = operationTableData.OperationInfo;
|
||||
DiagnosticPackageData packageData = operationTableData.PackageData;
|
||||
DiagnosticOperationInfo operationInfo = operationTableData.OperationInfo;
|
||||
|
||||
TreeNode rootNode = new TreeNode(operationInfo);
|
||||
FillTreeData(operationInfo, rootNode);
|
||||
@@ -408,20 +409,20 @@ namespace YooAsset.Editor
|
||||
container.Add(label);
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var label = new Label();
|
||||
label.name = "BeginTime";
|
||||
label.name = "StartTime";
|
||||
label.style.flexGrow = 0f;
|
||||
label.style.width = 100;
|
||||
label.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||
container.Add(label);
|
||||
}
|
||||
|
||||
// ProcessTime
|
||||
// ElapsedMS
|
||||
{
|
||||
var label = new Label();
|
||||
label.name = "ProcessTime";
|
||||
label.name = "ElapsedMS";
|
||||
label.style.flexGrow = 0f;
|
||||
label.style.width = 130;
|
||||
label.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||
@@ -450,7 +451,7 @@ namespace YooAsset.Editor
|
||||
}
|
||||
private void BindTreeViewItem(VisualElement container, object userData)
|
||||
{
|
||||
var operationInfo = (DebugOperationInfo)userData;
|
||||
var operationInfo = (DiagnosticOperationInfo)userData;
|
||||
|
||||
// OperationName
|
||||
{
|
||||
@@ -464,22 +465,23 @@ namespace YooAsset.Editor
|
||||
label.text = operationInfo.Progress.ToString();
|
||||
}
|
||||
|
||||
// BeginTime
|
||||
// StartTime
|
||||
{
|
||||
var label = container.Q<Label>("BeginTime");
|
||||
label.text = operationInfo.BeginTime;
|
||||
var label = container.Q<Label>("StartTime");
|
||||
label.text = operationInfo.StartTime;
|
||||
}
|
||||
|
||||
// ProcessTime
|
||||
// ElapsedMS
|
||||
{
|
||||
var label = container.Q<Label>("ProcessTime");
|
||||
label.text = operationInfo.ProcessTime.ToString();
|
||||
var label = container.Q<Label>("ElapsedMS");
|
||||
label.text = operationInfo.ElapsedMS.ToString();
|
||||
}
|
||||
|
||||
// Status
|
||||
{
|
||||
StyleColor textColor;
|
||||
if (operationInfo.Status == EOperationStatus.Failed.ToString())
|
||||
if (operationInfo.Status == EOperationStatus.Failed.ToString() ||
|
||||
operationInfo.Status == EOperationStatus.Aborted.ToString())
|
||||
textColor = new StyleColor(Color.yellow);
|
||||
else
|
||||
textColor = new StyleColor(Color.white);
|
||||
@@ -495,9 +497,9 @@ namespace YooAsset.Editor
|
||||
label.text = operationInfo.OperationDesc;
|
||||
}
|
||||
}
|
||||
private void FillTreeData(DebugOperationInfo parentOperation, TreeNode rootNode)
|
||||
private void FillTreeData(DiagnosticOperationInfo parentOperation, TreeNode rootNode)
|
||||
{
|
||||
foreach (var childOperation in parentOperation.Childs)
|
||||
foreach (var childOperation in parentOperation.Children)
|
||||
{
|
||||
var childNode = new TreeNode(childOperation);
|
||||
rootNode.AddChild(childNode);
|
||||
|
||||
@@ -277,7 +277,7 @@ namespace YooAsset.Editor
|
||||
if (dependTableData.BundleInfo.Encrypted)
|
||||
return;
|
||||
|
||||
if (_buildReport.Summary.BuildBundleType == (int)EBuildBundleType.AssetBundle)
|
||||
if (_buildReport.Summary.BuildBundleType == (int)EBundleType.AssetBundle)
|
||||
{
|
||||
string rootDirectory = Path.GetDirectoryName(_reportFilePath);
|
||||
string filePath = $"{rootDirectory}/{dependTableData.BundleInfo.FileName}";
|
||||
|
||||
@@ -348,7 +348,7 @@ namespace YooAsset.Editor
|
||||
if (bundleTableData.BundleInfo.Encrypted)
|
||||
return;
|
||||
|
||||
if (_buildReport.Summary.BuildBundleType == (int)EBuildBundleType.AssetBundle)
|
||||
if (_buildReport.Summary.BuildBundleType == (int)EBundleType.AssetBundle)
|
||||
{
|
||||
string rootDirectory = Path.GetDirectoryName(_reportFilePath);
|
||||
string filePath = $"{rootDirectory}/{bundleTableData.BundleInfo.FileName}";
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
[Serializable]
|
||||
internal class DebugPackageData
|
||||
{
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName;
|
||||
|
||||
public List<DebugProviderInfo> ProviderInfos = new List<DebugProviderInfo>(1000);
|
||||
public List<DebugBundleInfo> BundleInfos = new List<DebugBundleInfo>(1000);
|
||||
public List<DebugOperationInfo> OperationInfos = new List<DebugOperationInfo>(1000);
|
||||
|
||||
|
||||
[NonSerialized]
|
||||
public Dictionary<string, DebugBundleInfo> BundleInfoDic = new Dictionary<string, DebugBundleInfo>();
|
||||
private bool _isParse = false;
|
||||
|
||||
/// <summary>
|
||||
/// 获取调试资源包信息类
|
||||
/// </summary>
|
||||
public DebugBundleInfo GetBundleInfo(string bundleName)
|
||||
{
|
||||
// 解析数据
|
||||
if (_isParse == false)
|
||||
{
|
||||
_isParse = true;
|
||||
foreach (var bundleInfo in BundleInfos)
|
||||
{
|
||||
if (BundleInfoDic.ContainsKey(bundleInfo.BundleName) == false)
|
||||
{
|
||||
BundleInfoDic.Add(bundleInfo.BundleName, bundleInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BundleInfoDic.TryGetValue(bundleName, out DebugBundleInfo value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogError($"Can not found {nameof(DebugBundleInfo)} : {bundleName}");
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源系统调试信息
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class DebugReport
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试器版本
|
||||
/// </summary>
|
||||
public string DebuggerVersion = RemoteDebuggerDefine.DebuggerVersion;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏帧
|
||||
/// </summary>
|
||||
public int FrameCount;
|
||||
|
||||
/// <summary>
|
||||
/// 调试的包裹数据列表
|
||||
/// </summary>
|
||||
public List<DebugPackageData> PackageDatas = new List<DebugPackageData>(10);
|
||||
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// </summary>
|
||||
public static byte[] Serialize(DebugReport debugReport)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonUtility.ToJson(debugReport));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
public static DebugReport Deserialize(byte[] data)
|
||||
{
|
||||
return JsonUtility.FromJson<DebugReport>(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,11 @@ using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 描述资源包的运行时诊断信息
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal struct DebugBundleInfo : IComparer<DebugBundleInfo>, IComparable<DebugBundleInfo>
|
||||
internal struct DiagnosticBundleInfo : IComparer<DiagnosticBundleInfo>, IComparable<DiagnosticBundleInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源包名称
|
||||
@@ -15,23 +18,23 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 引用计数
|
||||
/// </summary>
|
||||
public int RefCount;
|
||||
public int ReferenceCount;
|
||||
|
||||
/// <summary>
|
||||
/// 加载状态
|
||||
/// 资源包的加载状态
|
||||
/// </summary>
|
||||
public string Status;
|
||||
|
||||
/// <summary>
|
||||
/// 谁引用了该资源包
|
||||
/// 该资源包被谁引用
|
||||
/// </summary>
|
||||
public List<string> ReferenceBundles;
|
||||
public List<string> ReferencedByBundles;
|
||||
|
||||
public int CompareTo(DebugBundleInfo other)
|
||||
public int CompareTo(DiagnosticBundleInfo other)
|
||||
{
|
||||
return Compare(this, other);
|
||||
}
|
||||
public int Compare(DebugBundleInfo a, DebugBundleInfo b)
|
||||
public int Compare(DiagnosticBundleInfo a, DiagnosticBundleInfo b)
|
||||
{
|
||||
return string.CompareOrdinal(a.BundleName, b.BundleName);
|
||||
}
|
||||
@@ -4,41 +4,44 @@ using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 描述异步操作的运行时诊断信息
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal struct DebugOperationInfo : IComparer<DebugOperationInfo>, IComparable<DebugOperationInfo>
|
||||
internal struct DiagnosticOperationInfo : IComparer<DiagnosticOperationInfo>, IComparable<DiagnosticOperationInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务名称
|
||||
/// 异步操作的名称
|
||||
/// </summary>
|
||||
public string OperationName;
|
||||
|
||||
/// <summary>
|
||||
/// 任务说明
|
||||
/// 异步操作的说明
|
||||
/// </summary>
|
||||
public string OperationDesc;
|
||||
|
||||
/// <summary>
|
||||
/// 优先级
|
||||
/// 异步操作的优先级
|
||||
/// </summary>
|
||||
public uint Priority;
|
||||
|
||||
/// <summary>
|
||||
/// 任务进度
|
||||
/// </summary>
|
||||
public float Progress;
|
||||
|
||||
/// <summary>
|
||||
/// 任务开始的时间
|
||||
/// 开始的时间
|
||||
/// </summary>
|
||||
public string BeginTime;
|
||||
public string StartTime;
|
||||
|
||||
/// <summary>
|
||||
/// 处理耗时(单位:毫秒)
|
||||
/// </summary>
|
||||
public long ProcessTime;
|
||||
public long ElapsedMS;
|
||||
|
||||
/// <summary>
|
||||
/// 任务状态
|
||||
/// 异步操作的执行进度
|
||||
/// </summary>
|
||||
public float Progress;
|
||||
|
||||
/// <summary>
|
||||
/// 异步操作的执行状态
|
||||
/// </summary>
|
||||
public string Status;
|
||||
|
||||
@@ -46,13 +49,13 @@ namespace YooAsset
|
||||
/// 子任务列表
|
||||
/// TODO : Serialization depth limit 10 exceeded
|
||||
/// </summary>
|
||||
public List<DebugOperationInfo> Childs;
|
||||
public List<DiagnosticOperationInfo> Children;
|
||||
|
||||
public int CompareTo(DebugOperationInfo other)
|
||||
public int CompareTo(DiagnosticOperationInfo other)
|
||||
{
|
||||
return Compare(this, other);
|
||||
}
|
||||
public int Compare(DebugOperationInfo a, DebugOperationInfo b)
|
||||
public int Compare(DiagnosticOperationInfo a, DiagnosticOperationInfo b)
|
||||
{
|
||||
return string.CompareOrdinal(a.OperationName, b.OperationName);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 包裹的诊断数据容器
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class DiagnosticPackageData
|
||||
{
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName;
|
||||
|
||||
/// <summary>
|
||||
/// 资源加载的诊断信息列表
|
||||
/// </summary>
|
||||
public List<DiagnosticProviderInfo> ProviderInfos = new List<DiagnosticProviderInfo>(1000);
|
||||
|
||||
/// <summary>
|
||||
/// 资源包的诊断信息列表
|
||||
/// </summary>
|
||||
public List<DiagnosticBundleInfo> BundleInfos = new List<DiagnosticBundleInfo>(1000);
|
||||
|
||||
/// <summary>
|
||||
/// 异步操作的诊断信息列表
|
||||
/// </summary>
|
||||
public List<DiagnosticOperationInfo> OperationInfos = new List<DiagnosticOperationInfo>(1000);
|
||||
|
||||
private readonly Dictionary<string, DiagnosticBundleInfo> _bundleInfoDict = new Dictionary<string, DiagnosticBundleInfo>();
|
||||
private bool _isParsed = false;
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源包的诊断信息
|
||||
/// </summary>
|
||||
public DiagnosticBundleInfo GetBundleInfo(string bundleName)
|
||||
{
|
||||
// 解析数据
|
||||
if (_isParsed == false)
|
||||
{
|
||||
_isParsed = true;
|
||||
foreach (var bundleInfo in BundleInfos)
|
||||
{
|
||||
if (_bundleInfoDict.ContainsKey(bundleInfo.BundleName) == false)
|
||||
{
|
||||
_bundleInfoDict.Add(bundleInfo.BundleName, bundleInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_bundleInfoDict.TryGetValue(bundleName, out DiagnosticBundleInfo value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogError($"Cannot find {nameof(DiagnosticBundleInfo)} : {bundleName}");
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,54 +4,52 @@ using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 描述资源加载的运行时诊断信息
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal struct DebugProviderInfo : IComparer<DebugProviderInfo>, IComparable<DebugProviderInfo>
|
||||
internal struct DiagnosticProviderInfo : IComparer<DiagnosticProviderInfo>, IComparable<DiagnosticProviderInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// 包裹名
|
||||
/// </summary>
|
||||
public string PackageName { set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源对象路径
|
||||
/// </summary>
|
||||
public string AssetPath;
|
||||
|
||||
/// <summary>
|
||||
/// 资源出生的场景
|
||||
/// 资源加载时所在的场景
|
||||
/// </summary>
|
||||
public string SpawnScene;
|
||||
public string OriginScene;
|
||||
|
||||
/// <summary>
|
||||
/// 资源加载开始时间
|
||||
/// </summary>
|
||||
public string BeginTime;
|
||||
public string StartTime;
|
||||
|
||||
/// <summary>
|
||||
/// 加载耗时(单位:毫秒)
|
||||
/// </summary>
|
||||
public long LoadingTime;
|
||||
public long ElapsedMS;
|
||||
|
||||
/// <summary>
|
||||
/// 引用计数
|
||||
/// </summary>
|
||||
public int RefCount;
|
||||
public int ReferenceCount;
|
||||
|
||||
/// <summary>
|
||||
/// 加载状态
|
||||
/// 资源的加载状态
|
||||
/// </summary>
|
||||
public string Status;
|
||||
|
||||
/// <summary>
|
||||
/// 依赖的资源包列表
|
||||
/// </summary>
|
||||
public List<string> DependBundles;
|
||||
public List<string> DependentBundles;
|
||||
|
||||
public int CompareTo(DebugProviderInfo other)
|
||||
public int CompareTo(DiagnosticProviderInfo other)
|
||||
{
|
||||
return Compare(this, other);
|
||||
}
|
||||
public int Compare(DebugProviderInfo a, DebugProviderInfo b)
|
||||
public int Compare(DiagnosticProviderInfo a, DiagnosticProviderInfo b)
|
||||
{
|
||||
return string.CompareOrdinal(a.AssetPath, b.AssetPath);
|
||||
}
|
||||
50
Assets/YooAsset/Runtime/DiagnosticSystem/DiagnosticReport.cs
Normal file
50
Assets/YooAsset/Runtime/DiagnosticSystem/DiagnosticReport.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源系统的诊断报告
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class DiagnosticReport
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试器版本
|
||||
/// </summary>
|
||||
public string DebuggerVersion = DiagnosticSystemDefine.DebuggerVersion;
|
||||
|
||||
/// <summary>
|
||||
/// 报告发生的游戏帧
|
||||
/// </summary>
|
||||
public int FrameCount;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹数据列表
|
||||
/// </summary>
|
||||
public List<DiagnosticPackageData> PackageDataList = new List<DiagnosticPackageData>(10);
|
||||
|
||||
/// <summary>
|
||||
/// 序列化诊断报告为字节数组
|
||||
/// </summary>
|
||||
/// <param name="report">要序列化的诊断报告</param>
|
||||
/// <returns>UTF-8 编码的 JSON 字节数组</returns>
|
||||
public static byte[] Serialize(DiagnosticReport report)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonUtility.ToJson(report));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从字节数组反序列化诊断报告
|
||||
/// </summary>
|
||||
/// <param name="data">UTF-8 编码的 JSON 字节数组</param>
|
||||
/// <returns>反序列化后的诊断报告</returns>
|
||||
public static DiagnosticReport Deserialize(byte[] data)
|
||||
{
|
||||
return JsonUtility.FromJson<DiagnosticReport>(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 诊断系统的常量定义
|
||||
/// </summary>
|
||||
internal class DiagnosticSystemDefine
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试器版本号
|
||||
/// </summary>
|
||||
public const string DebuggerVersion = "1.0";
|
||||
|
||||
/// <summary>
|
||||
/// Player 向 Editor 发送消息的标识符
|
||||
/// </summary>
|
||||
public static readonly Guid PlayerToEditorMessageId = new Guid("e34a5702dd353724aa315fb8011f08c3");
|
||||
|
||||
/// <summary>
|
||||
/// Editor 向 Player 发送消息的标识符
|
||||
/// </summary>
|
||||
public static readonly Guid EditorToPlayerMessageId = new Guid("4d1926c9df5b052469a1c63448b7609a");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 远程调试命令类型
|
||||
/// </summary>
|
||||
internal enum EDebugCommandType
|
||||
{
|
||||
/// <summary>
|
||||
/// 采样一次
|
||||
/// </summary>
|
||||
SampleOnce = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 持续采样
|
||||
/// </summary>
|
||||
AutoSampling = 1,
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f88823353464474faf7b020a76f9b2d
|
||||
guid: 773cefd0e4f22f745b88d25c930f6493
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
102
Assets/YooAsset/Runtime/DiagnosticSystem/MockEditorConnection.cs
Normal file
102
Assets/YooAsset/Runtime/DiagnosticSystem/MockEditorConnection.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 模拟的 Editor 连接
|
||||
/// 在 Editor 模式下模拟 EditorConnection 的行为,用于本地调试
|
||||
/// </summary>
|
||||
internal class MockEditorConnection
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnRuntimeInitialize()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static MockEditorConnection _instance;
|
||||
|
||||
/// <summary>
|
||||
/// 获取单例实例
|
||||
/// </summary>
|
||||
public static MockEditorConnection Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new MockEditorConnection();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<Guid, UnityAction<MessageEventArgs>> _messageHandlers = new Dictionary<Guid, UnityAction<MessageEventArgs>>();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化连接,清空所有已注册的消息处理器
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
_messageHandlers.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息处理回调
|
||||
/// </summary>
|
||||
/// <param name="messageID">消息标识符</param>
|
||||
/// <param name="callback">收到消息时的回调函数</param>
|
||||
public void Register(Guid messageID, UnityAction<MessageEventArgs> callback)
|
||||
{
|
||||
if (messageID == Guid.Empty)
|
||||
throw new ArgumentException("messageID is empty.");
|
||||
|
||||
if (_messageHandlers.ContainsKey(messageID) == false)
|
||||
_messageHandlers.Add(messageID, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注销消息处理回调
|
||||
/// </summary>
|
||||
/// <param name="messageID">消息标识符</param>
|
||||
public void Unregister(Guid messageID)
|
||||
{
|
||||
if (_messageHandlers.ContainsKey(messageID))
|
||||
_messageHandlers.Remove(messageID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向 Player 端发送消息
|
||||
/// </summary>
|
||||
/// <param name="messageID">消息标识符</param>
|
||||
/// <param name="data">消息数据</param>
|
||||
public void Send(Guid messageID, byte[] data)
|
||||
{
|
||||
if (messageID == Guid.Empty)
|
||||
throw new ArgumentException("messageID is empty.");
|
||||
|
||||
// 接收对方的消息
|
||||
MockPlayerConnection.Instance.HandleEditorMessage(messageID, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理来自 Player 端的消息
|
||||
/// </summary>
|
||||
/// <param name="messageID">消息标识符</param>
|
||||
/// <param name="data">消息数据</param>
|
||||
internal void HandlePlayerMessage(Guid messageID, byte[] data)
|
||||
{
|
||||
if (_messageHandlers.TryGetValue(messageID, out UnityAction<MessageEventArgs> value))
|
||||
{
|
||||
var args = new MessageEventArgs();
|
||||
args.playerId = 0;
|
||||
args.data = data;
|
||||
value?.Invoke(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Assets/YooAsset/Runtime/DiagnosticSystem/MockPlayerConnection.cs
Normal file
102
Assets/YooAsset/Runtime/DiagnosticSystem/MockPlayerConnection.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 模拟的 Player 连接
|
||||
/// 在 Editor 模式下模拟 PlayerConnection 的行为,用于本地调试
|
||||
/// </summary>
|
||||
internal class MockPlayerConnection
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnRuntimeInitialize()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static MockPlayerConnection _instance;
|
||||
|
||||
/// <summary>
|
||||
/// 获取单例实例
|
||||
/// </summary>
|
||||
public static MockPlayerConnection Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new MockPlayerConnection();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<Guid, UnityAction<MessageEventArgs>> _messageHandlers = new Dictionary<Guid, UnityAction<MessageEventArgs>>();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化连接,清空所有已注册的消息处理器
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
_messageHandlers.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息处理回调
|
||||
/// </summary>
|
||||
/// <param name="messageID">消息标识符</param>
|
||||
/// <param name="callback">收到消息时的回调函数</param>
|
||||
public void Register(Guid messageID, UnityAction<MessageEventArgs> callback)
|
||||
{
|
||||
if (messageID == Guid.Empty)
|
||||
throw new ArgumentException("messageID is empty.");
|
||||
|
||||
if (_messageHandlers.ContainsKey(messageID) == false)
|
||||
_messageHandlers.Add(messageID, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注销消息处理回调
|
||||
/// </summary>
|
||||
/// <param name="messageID">消息标识符</param>
|
||||
public void Unregister(Guid messageID)
|
||||
{
|
||||
if (_messageHandlers.ContainsKey(messageID))
|
||||
_messageHandlers.Remove(messageID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向 Editor 端发送消息
|
||||
/// </summary>
|
||||
/// <param name="messageID">消息标识符</param>
|
||||
/// <param name="data">消息数据</param>
|
||||
public void Send(Guid messageID, byte[] data)
|
||||
{
|
||||
if (messageID == Guid.Empty)
|
||||
throw new ArgumentException("messageID is empty.");
|
||||
|
||||
// 接收对方的消息
|
||||
MockEditorConnection.Instance.HandlePlayerMessage(messageID, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理来自 Editor 端的消息
|
||||
/// </summary>
|
||||
/// <param name="messageID">消息标识符</param>
|
||||
/// <param name="data">消息数据</param>
|
||||
internal void HandleEditorMessage(Guid messageID, byte[] data)
|
||||
{
|
||||
if (_messageHandlers.TryGetValue(messageID, out UnityAction<MessageEventArgs> value))
|
||||
{
|
||||
var args = new MessageEventArgs();
|
||||
args.playerId = 0;
|
||||
args.data = data;
|
||||
value?.Invoke(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal enum ERemoteCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// 采样一次
|
||||
/// </summary>
|
||||
SampleOnce = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 自动采集
|
||||
/// </summary>
|
||||
SampleAuto = 1,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class RemoteCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// 命令类型
|
||||
/// </summary>
|
||||
public int CommandType;
|
||||
|
||||
/// <summary>
|
||||
/// 命令附加参数
|
||||
/// </summary>
|
||||
public string CommandParam;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// </summary>
|
||||
public static byte[] Serialize(RemoteCommand command)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonUtility.ToJson(command));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
public static RemoteCommand Deserialize(byte[] data)
|
||||
{
|
||||
return JsonUtility.FromJson<RemoteCommand>(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 远程调试行为组件
|
||||
/// 负责接收 Editor 命令并发送诊断数据
|
||||
/// </summary>
|
||||
internal class RemoteDebugBehaviour : MonoBehaviour
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnRuntimeInitialize()
|
||||
{
|
||||
_sampleOnce = false;
|
||||
_autoSampling = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static bool _sampleOnce = false;
|
||||
private static bool _autoSampling = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
MockPlayerConnection.Instance.Initialize();
|
||||
#endif
|
||||
}
|
||||
private void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
MockPlayerConnection.Instance.Register(DiagnosticSystemDefine.EditorToPlayerMessageId, HandleEditorMessage);
|
||||
#else
|
||||
PlayerConnection.instance.Register(DiagnosticSystemDefine.EditorToPlayerMessageId, HandleEditorMessage);
|
||||
#endif
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
MockPlayerConnection.Instance.Unregister(DiagnosticSystemDefine.EditorToPlayerMessageId);
|
||||
#else
|
||||
PlayerConnection.instance.Unregister(DiagnosticSystemDefine.EditorToPlayerMessageId, HandleEditorMessage);
|
||||
#endif
|
||||
}
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (_autoSampling || _sampleOnce)
|
||||
{
|
||||
_sampleOnce = false;
|
||||
var debugReport = YooAssets.GetDebugReport();
|
||||
var data = DiagnosticReport.Serialize(debugReport);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
MockPlayerConnection.Instance.Send(DiagnosticSystemDefine.PlayerToEditorMessageId, data);
|
||||
#else
|
||||
PlayerConnection.instance.Send(DiagnosticSystemDefine.PlayerToEditorMessageId, data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleEditorMessage(MessageEventArgs args)
|
||||
{
|
||||
var command = RemoteDebugCommand.Deserialize(args.data);
|
||||
YooLogger.Log($"Handle remote command: {command.CommandType} Param: {command.Parameter}");
|
||||
if (command.CommandType == (int)EDebugCommandType.SampleOnce)
|
||||
{
|
||||
_sampleOnce = true;
|
||||
}
|
||||
else if (command.CommandType == (int)EDebugCommandType.AutoSampling)
|
||||
{
|
||||
if (command.Parameter == "open")
|
||||
_autoSampling = true;
|
||||
else
|
||||
_autoSampling = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(command.CommandType.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 远程调试命令
|
||||
/// 用于 Editor 向 Player 发送调试指令
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class RemoteDebugCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// 命令类型
|
||||
/// </summary>
|
||||
public int CommandType;
|
||||
|
||||
/// <summary>
|
||||
/// 命令附加参数
|
||||
/// </summary>
|
||||
public string Parameter;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 序列化命令为字节数组
|
||||
/// </summary>
|
||||
/// <param name="command">要序列化的远程调试命令</param>
|
||||
/// <returns>UTF-8 编码的 JSON 字节数组</returns>
|
||||
public static byte[] Serialize(RemoteDebugCommand command)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonUtility.ToJson(command));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从字节数组反序列化命令
|
||||
/// </summary>
|
||||
/// <param name="data">UTF-8 编码的 JSON 字节数组</param>
|
||||
/// <returns>反序列化后的远程调试命令</returns>
|
||||
public static RemoteDebugCommand Deserialize(byte[] data)
|
||||
{
|
||||
return JsonUtility.FromJson<RemoteDebugCommand>(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class RemoteDebuggerDefine
|
||||
{
|
||||
public const string DebuggerVersion = "2.3.3";
|
||||
public static readonly Guid kMsgPlayerSendToEditor = new Guid("e34a5702dd353724aa315fb8011f08c3");
|
||||
public static readonly Guid kMsgEditorSendToPlayer = new Guid("4d1926c9df5b052469a1c63448b7609a");
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class RemoteDebuggerInRuntime : MonoBehaviour
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnRuntimeInitialize()
|
||||
{
|
||||
_sampleOnce = false;
|
||||
_autoSample = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static bool _sampleOnce = false;
|
||||
private static bool _autoSample = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
RemotePlayerConnection.Instance.Initialize();
|
||||
#endif
|
||||
}
|
||||
private void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
RemotePlayerConnection.Instance.Register(RemoteDebuggerDefine.kMsgEditorSendToPlayer, OnHandleEditorMessage);
|
||||
#else
|
||||
PlayerConnection.instance.Register(RemoteDebuggerDefine.kMsgEditorSendToPlayer, OnHandleEditorMessage);
|
||||
#endif
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
RemotePlayerConnection.Instance.Unregister(RemoteDebuggerDefine.kMsgEditorSendToPlayer);
|
||||
#else
|
||||
PlayerConnection.instance.Unregister(RemoteDebuggerDefine.kMsgEditorSendToPlayer, OnHandleEditorMessage);
|
||||
#endif
|
||||
}
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (_autoSample || _sampleOnce)
|
||||
{
|
||||
_sampleOnce = false;
|
||||
var debugReport = YooAssets.GetDebugReport();
|
||||
var data = DebugReport.Serialize(debugReport);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
RemotePlayerConnection.Instance.Send(RemoteDebuggerDefine.kMsgPlayerSendToEditor, data);
|
||||
#else
|
||||
PlayerConnection.instance.Send(RemoteDebuggerDefine.kMsgPlayerSendToEditor, data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnHandleEditorMessage(MessageEventArgs args)
|
||||
{
|
||||
var command = RemoteCommand.Deserialize(args.data);
|
||||
YooLogger.Log($"On handle remote command : {command.CommandType} Param : {command.CommandParam}");
|
||||
if (command.CommandType == (int)ERemoteCommand.SampleOnce)
|
||||
{
|
||||
_sampleOnce = true;
|
||||
}
|
||||
else if (command.CommandType == (int)ERemoteCommand.SampleAuto)
|
||||
{
|
||||
if (command.CommandParam == "open")
|
||||
_autoSample = true;
|
||||
else
|
||||
_autoSample = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(command.CommandType.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class RemoteEditorConnection
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnRuntimeInitialize()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static RemoteEditorConnection _instance;
|
||||
public static RemoteEditorConnection Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new RemoteEditorConnection();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<Guid, UnityAction<MessageEventArgs>> _messageCallbacks = new Dictionary<Guid, UnityAction<MessageEventArgs>>();
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_messageCallbacks.Clear();
|
||||
}
|
||||
public void Register(Guid messageID, UnityAction<MessageEventArgs> callback)
|
||||
{
|
||||
if (messageID == Guid.Empty)
|
||||
throw new ArgumentException("messageID is empty !");
|
||||
|
||||
if (_messageCallbacks.ContainsKey(messageID) == false)
|
||||
_messageCallbacks.Add(messageID, callback);
|
||||
}
|
||||
public void Unregister(Guid messageID)
|
||||
{
|
||||
if (_messageCallbacks.ContainsKey(messageID))
|
||||
_messageCallbacks.Remove(messageID);
|
||||
}
|
||||
public void Send(Guid messageID, byte[] data)
|
||||
{
|
||||
if (messageID == Guid.Empty)
|
||||
throw new ArgumentException("messageID is empty !");
|
||||
|
||||
// 接收对方的消息
|
||||
RemotePlayerConnection.Instance.HandleEditorMessage(messageID, data);
|
||||
}
|
||||
|
||||
internal void HandlePlayerMessage(Guid messageID, byte[] data)
|
||||
{
|
||||
if (_messageCallbacks.TryGetValue(messageID, out UnityAction<MessageEventArgs> value))
|
||||
{
|
||||
var args = new MessageEventArgs();
|
||||
args.playerId = 0;
|
||||
args.data = data;
|
||||
value?.Invoke(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class RemotePlayerConnection
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnRuntimeInitialize()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static RemotePlayerConnection _instance;
|
||||
public static RemotePlayerConnection Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new RemotePlayerConnection();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<Guid, UnityAction<MessageEventArgs>> _messageCallbacks = new Dictionary<Guid, UnityAction<MessageEventArgs>>();
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_messageCallbacks.Clear();
|
||||
}
|
||||
public void Register(Guid messageID, UnityAction<MessageEventArgs> callback)
|
||||
{
|
||||
if (messageID == Guid.Empty)
|
||||
throw new ArgumentException("messageID is empty !");
|
||||
|
||||
if (_messageCallbacks.ContainsKey(messageID) == false)
|
||||
_messageCallbacks.Add(messageID, callback);
|
||||
}
|
||||
public void Unregister(Guid messageID)
|
||||
{
|
||||
if (_messageCallbacks.ContainsKey(messageID))
|
||||
_messageCallbacks.Remove(messageID);
|
||||
}
|
||||
public void Send(Guid messageID, byte[] data)
|
||||
{
|
||||
if (messageID == Guid.Empty)
|
||||
throw new ArgumentException("messageID is empty !");
|
||||
|
||||
// 接收对方的消息
|
||||
RemoteEditorConnection.Instance.HandlePlayerMessage(messageID, data);
|
||||
}
|
||||
|
||||
internal void HandleEditorMessage(Guid messageID, byte[] data)
|
||||
{
|
||||
if (_messageCallbacks.TryGetValue(messageID, out UnityAction<MessageEventArgs> value))
|
||||
{
|
||||
var args = new MessageEventArgs();
|
||||
args.playerId = 0;
|
||||
args.data = data;
|
||||
value?.Invoke(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义下载器的请求委托
|
||||
/// </summary>
|
||||
public delegate UnityWebRequest UnityWebRequestCreator(string url, string method);
|
||||
}
|
||||
@@ -9,39 +9,47 @@ namespace YooAsset
|
||||
/// 线程安全:内部使用 Dictionary 且未加锁,约定只在 Unity 主线程调用。
|
||||
/// 如需在多线程/回调线程调用,请在外层加锁或改为并发容器实现。
|
||||
/// </remarks>
|
||||
internal class WebRequestCounter
|
||||
internal class DownloadFailureCounter
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void OnRuntimeInitialize()
|
||||
{
|
||||
_requestFailedRecorder.Clear();
|
||||
_failureRecords.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 失败计数记录表(key = $"{packageName}_{eventName}")
|
||||
/// 失败计数记录表
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, int> _requestFailedRecorder = new Dictionary<string, int>(1000);
|
||||
/// <remarks>
|
||||
/// Key 格式:$"{packageName}_{eventName}"
|
||||
/// </remarks>
|
||||
private static readonly Dictionary<string, int> _failureRecords = new Dictionary<string, int>(1000);
|
||||
|
||||
/// <summary>
|
||||
/// 记录一次失败
|
||||
/// </summary>
|
||||
public static void RecordRequestFailed(string packageName, string eventName)
|
||||
/// <param name="packageName">资源包名称</param>
|
||||
/// <param name="eventName">事件名称</param>
|
||||
public static void RecordFailure(string packageName, string eventName)
|
||||
{
|
||||
string key = $"{packageName}_{eventName}";
|
||||
if (_requestFailedRecorder.ContainsKey(key) == false)
|
||||
_requestFailedRecorder.Add(key, 0);
|
||||
_requestFailedRecorder[key]++;
|
||||
if (_failureRecords.ContainsKey(key) == false)
|
||||
_failureRecords.Add(key, 0);
|
||||
_failureRecords[key]++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取失败次数
|
||||
/// </summary>
|
||||
public static int GetRequestFailedCount(string packageName, string eventName)
|
||||
/// <param name="packageName">资源包名称</param>
|
||||
/// <param name="eventName">事件名称</param>
|
||||
/// <returns>失败次数,如果未记录过则返回 0</returns>
|
||||
public static int GetFailureCount(string packageName, string eventName)
|
||||
{
|
||||
string key = $"{packageName}_{eventName}";
|
||||
if (_requestFailedRecorder.TryGetValue(key, out int count))
|
||||
if (_failureRecords.TryGetValue(key, out int count))
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
@@ -2,153 +2,6 @@ using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 下载器结束
|
||||
/// </summary>
|
||||
public struct DownloaderFinishData
|
||||
{
|
||||
/// <summary>
|
||||
/// 所属包裹名称
|
||||
/// </summary>
|
||||
public string PackageName;
|
||||
|
||||
/// <summary>
|
||||
/// 是否成功
|
||||
/// </summary>
|
||||
public bool Succeed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载器相关的更新数据
|
||||
/// </summary>
|
||||
public struct DownloadUpdateData
|
||||
{
|
||||
/// <summary>
|
||||
/// 所属包裹名称
|
||||
/// </summary>
|
||||
public string PackageName;
|
||||
|
||||
/// <summary>
|
||||
/// 下载进度 (0-1f)
|
||||
/// </summary>
|
||||
public float Progress;
|
||||
|
||||
/// <summary>
|
||||
/// 下载文件总数
|
||||
/// </summary>
|
||||
public int TotalDownloadCount;
|
||||
|
||||
/// <summary>
|
||||
/// 当前完成的下载文件数量
|
||||
/// </summary>
|
||||
public int CurrentDownloadCount;
|
||||
|
||||
/// <summary>
|
||||
/// 下载数据总大小(单位:字节)
|
||||
/// </summary>
|
||||
public long TotalDownloadBytes;
|
||||
|
||||
/// <summary>
|
||||
/// 当前完成的下载数据大小(单位:字节)
|
||||
/// </summary>
|
||||
public long CurrentDownloadBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载器相关的错误数据
|
||||
/// </summary>
|
||||
public struct DownloadErrorData
|
||||
{
|
||||
/// <summary>
|
||||
/// 所属包裹名称
|
||||
/// </summary>
|
||||
public string PackageName;
|
||||
|
||||
/// <summary>
|
||||
/// 下载失败的文件名称
|
||||
/// </summary>
|
||||
public string FileName;
|
||||
|
||||
/// <summary>
|
||||
/// 错误信息
|
||||
/// </summary>
|
||||
public string ErrorInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载器相关的文件数据
|
||||
/// </summary>
|
||||
public struct DownloadFileData
|
||||
{
|
||||
/// <summary>
|
||||
/// 所属包裹名称
|
||||
/// </summary>
|
||||
public string PackageName;
|
||||
|
||||
/// <summary>
|
||||
/// 下载的文件名称
|
||||
/// </summary>
|
||||
public string FileName;
|
||||
|
||||
/// <summary>
|
||||
/// 下载的文件大小
|
||||
/// </summary>
|
||||
public long FileSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入文件的信息
|
||||
/// </summary>
|
||||
public struct ImportFileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 本地文件路径
|
||||
/// </summary>
|
||||
public string FilePath;
|
||||
|
||||
/// <summary>
|
||||
/// 资源包名称
|
||||
/// </summary>
|
||||
public string BundleName;
|
||||
|
||||
/// <summary>
|
||||
/// 资源包GUID
|
||||
/// </summary>
|
||||
public string BundleGUID;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 下载请求状态
|
||||
/// </summary>
|
||||
internal enum EDownloadRequestStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 未开始
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// 进行中
|
||||
/// </summary>
|
||||
Running,
|
||||
|
||||
/// <summary>
|
||||
/// 已成功
|
||||
/// </summary>
|
||||
Succeed,
|
||||
|
||||
/// <summary>
|
||||
/// 已失败
|
||||
/// </summary>
|
||||
Failed,
|
||||
|
||||
/// <summary>
|
||||
/// 已中止
|
||||
/// </summary>
|
||||
Aborted,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件下载请求参数
|
||||
/// </summary>
|
||||
@@ -182,7 +35,7 @@ namespace YooAsset
|
||||
/// 2. 每次接收到下载数据时,看门狗计时器会重置。
|
||||
/// 3. 若在设定的时间范围内未收到任何数据,任务将被自动终止。
|
||||
/// </remarks>
|
||||
public readonly int WatchdogTime;
|
||||
public readonly int WatchdogTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// 文件保存路径
|
||||
@@ -193,7 +46,7 @@ namespace YooAsset
|
||||
/// 是否追加写入文件
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 配合 ResumeFromBytes 使用,用于断点续传场景。
|
||||
/// 配合 ResumeOffset 使用,用于断点续传场景。
|
||||
/// </remarks>
|
||||
public readonly bool AppendToFile;
|
||||
|
||||
@@ -206,34 +59,45 @@ namespace YooAsset
|
||||
/// 断点续传的起始字节(小于等于 0 表示不启用)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 推荐由后端自动设置 Range 请求头:"bytes={ResumeFromBytes}-"。
|
||||
/// 推荐由后端自动设置 Range 请求头:"bytes={ResumeOffset}-"。
|
||||
/// </remarks>
|
||||
public readonly long ResumeFromBytes;
|
||||
public readonly long ResumeOffset;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义请求头(可选)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 使用 AddRequestHeader 方法添加请求头。
|
||||
/// 注意:相同 key 重复添加会抛出异常。
|
||||
/// </remarks>
|
||||
public Dictionary<string, string> Headers;
|
||||
|
||||
/// <summary>
|
||||
/// 构造文件下载请求参数
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="savePath">文件保存路径</param>
|
||||
/// <param name="timeout">响应超时时间(秒),0 表示不应用超时</param>
|
||||
/// <param name="watchdogTimeout">看门狗超时时间(秒),0 表示禁用</param>
|
||||
/// <param name="appendToFile">是否追加写入文件(用于断点续传)</param>
|
||||
/// <param name="removeFileOnAbort">中止时是否删除目标文件</param>
|
||||
/// <param name="resumeOffset">断点续传的起始字节位置</param>
|
||||
public DownloadFileRequestArgs(
|
||||
string url,
|
||||
string savePath,
|
||||
int timeout,
|
||||
int watchdogTime,
|
||||
int watchdogTimeout,
|
||||
bool appendToFile = false,
|
||||
bool removeFileOnAbort = true,
|
||||
long resumeFromBytes = 0)
|
||||
long resumeOffset = 0)
|
||||
{
|
||||
URL = url;
|
||||
SavePath = savePath;
|
||||
Timeout = timeout;
|
||||
WatchdogTime = watchdogTime;
|
||||
WatchdogTimeout = watchdogTimeout;
|
||||
AppendToFile = appendToFile;
|
||||
RemoveFileOnAbort = removeFileOnAbort;
|
||||
ResumeFromBytes = resumeFromBytes;
|
||||
ResumeOffset = resumeOffset;
|
||||
Headers = null;
|
||||
}
|
||||
|
||||
@@ -281,23 +145,28 @@ namespace YooAsset
|
||||
/// 2. 每次接收到下载数据时,看门狗计时器会重置。
|
||||
/// 3. 若在设定的时间范围内未收到任何数据,任务将被自动终止。
|
||||
/// </remarks>
|
||||
public readonly int WatchdogTime;
|
||||
public readonly int WatchdogTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义请求头(可选)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 使用 AddRequestHeader 方法添加请求头。
|
||||
/// 注意:相同 key 重复添加会抛出异常。
|
||||
/// </remarks>
|
||||
public Dictionary<string, string> Headers;
|
||||
|
||||
/// <summary>
|
||||
/// 构造数据下载请求参数
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="options">通用请求参数</param>
|
||||
public DownloadDataRequestArgs(string url, int timeout, int watchdogTime)
|
||||
/// <param name="timeout">响应超时时间(秒),0 表示不应用超时</param>
|
||||
/// <param name="watchdogTimeout">看门狗超时时间(秒),0 表示禁用</param>
|
||||
public DownloadDataRequestArgs(string url, int timeout, int watchdogTimeout)
|
||||
{
|
||||
URL = url;
|
||||
Timeout = timeout;
|
||||
WatchdogTime = watchdogTime;
|
||||
WatchdogTimeout = watchdogTimeout;
|
||||
Headers = null;
|
||||
}
|
||||
|
||||
@@ -345,7 +214,7 @@ namespace YooAsset
|
||||
/// 2. 每次接收到下载数据时,看门狗计时器会重置。
|
||||
/// 3. 若在设定的时间范围内未收到任何数据,任务将被自动终止。
|
||||
/// </remarks>
|
||||
public readonly int WatchdogTime;
|
||||
public readonly int WatchdogTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// 禁用 Unity 的网络缓存
|
||||
@@ -368,22 +237,32 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 自定义请求头(可选)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 使用 AddRequestHeader 方法添加请求头。
|
||||
/// 注意:相同 key 重复添加会抛出异常。
|
||||
/// </remarks>
|
||||
public Dictionary<string, string> Headers;
|
||||
|
||||
/// <summary>
|
||||
/// 构造 AssetBundle 下载请求参数
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="timeout">响应超时时间(秒),0 表示不应用超时</param>
|
||||
/// <param name="watchdogTimeout">看门狗超时时间(秒),0 表示禁用</param>
|
||||
/// <param name="disableUnityWebCache">是否禁用 Unity 内置缓存</param>
|
||||
/// <param name="fileHash">文件哈希(启用缓存时必须提供)</param>
|
||||
/// <param name="unityCrc">Unity CRC 校验值</param>
|
||||
public DownloadAssetBundleRequestArgs(
|
||||
string url,
|
||||
int timeout,
|
||||
int watchdogTime,
|
||||
int watchdogTimeout,
|
||||
bool disableUnityWebCache = true,
|
||||
string fileHash = null,
|
||||
uint unityCrc = 0)
|
||||
{
|
||||
URL = url;
|
||||
Timeout = timeout;
|
||||
WatchdogTime = watchdogTime;
|
||||
WatchdogTimeout = watchdogTimeout;
|
||||
DisableUnityWebCache = disableUnityWebCache;
|
||||
FileHash = fileHash;
|
||||
UnityCRC = unityCrc;
|
||||
@@ -1,14 +1,20 @@
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class DownloadSystemHelper
|
||||
/// <summary>
|
||||
/// 下载系统工具类
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 提供跨平台的 URL 转换和判断功能。
|
||||
/// </remarks>
|
||||
internal class DownloadSystemTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取WWW加载本地资源的路径
|
||||
/// 转换为本地文件请求地址
|
||||
/// </summary>
|
||||
public static string ConvertToWWWPath(string path)
|
||||
/// <param name="path">本地文件路径</param>
|
||||
/// <returns>可用于 UnityWebRequest 的文件协议 URL</returns>
|
||||
public static string ToLocalURL(string path)
|
||||
{
|
||||
string url;
|
||||
|
||||
@@ -57,17 +63,19 @@ namespace YooAsset
|
||||
#elif UNITY_STANDALONE_LINUX
|
||||
url = StringUtility.Format("file:///root/{0}", path);
|
||||
#else
|
||||
throw new System.NotSupportedException($"[{nameof(DownloadSystemHelper.ConvertToWWWPath)}] not implemented platform: {UnityEngine.Application.platform}");
|
||||
throw new System.NotSupportedException($"Platform '{UnityEngine.Application.platform}' is not supported.");
|
||||
#endif
|
||||
|
||||
// For some special cases when users have special characters in their devices, url paths can not be identified correctly.
|
||||
// 处理特殊字符:用户设备路径可能包含特殊字符导致 URL 无法正确识别
|
||||
return url.Replace("+", "%2B").Replace("#", "%23").Replace("?", "%3F");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否请求的本地文件
|
||||
/// 判断是否为本地文件 URL
|
||||
/// </summary>
|
||||
public static bool IsRequestLocalFile(string url)
|
||||
/// <param name="url">要判断的 URL</param>
|
||||
/// <returns>如果是本地文件 URL 返回 true,否则返回 false</returns>
|
||||
public static bool IsLocalFileURL(string url)
|
||||
{
|
||||
//TODO UNITY_STANDALONE_OSX平台目前无法确定
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 下载请求状态
|
||||
/// </summary>
|
||||
internal enum EDownloadRequestStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 未开始
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// 进行中
|
||||
/// </summary>
|
||||
Running,
|
||||
|
||||
/// <summary>
|
||||
/// 已成功
|
||||
/// </summary>
|
||||
Succeed,
|
||||
|
||||
/// <summary>
|
||||
/// 已失败
|
||||
/// </summary>
|
||||
Failed,
|
||||
|
||||
/// <summary>
|
||||
/// 已中止
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 可能由用户主动调用 AbortRequest() 或看门狗超时触发。
|
||||
/// </remarks>
|
||||
Aborted,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8f72782591f59046a052b566bfa865e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,7 +6,7 @@ namespace YooAsset
|
||||
/// 可轮询的下载请求接口
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 上层通常会在每帧轮询 Status IsDone,并在完成后读取结果。
|
||||
/// 上层通常在每帧检查 IsDone 属性,完成后读取结果并调用 Dispose() 释放资源。
|
||||
/// </remarks>
|
||||
internal interface IDownloadRequest : IDisposable
|
||||
{
|
||||
@@ -18,6 +18,9 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 是否完成(成功/失败/中止)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 注意:访问此属性时会自动调用 PollingRequest() 进行轮询。
|
||||
/// </remarks>
|
||||
bool IsDone { get; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
DownloadSystem 是 YooAsset 资源管理系统的**底层网络下载层**,负责处理所有 HTTP 网络请求。该模块提供了统一的下载接口抽象,支持文件下载、断点续传、并发请求(由上层调度)、看门狗监控等功能。
|
||||
|
||||
### 可见性说明
|
||||
|
||||
DownloadSystem 属于 YooAsset Runtime 的内部基础模块,目录内大多数类型为 `internal`(仅供 YooAsset Runtime 内部程序集使用)。本文示例以"模块内部调用方式"展示;业务层建议优先通过 `ResourcePackage / FileSystem / ResourceManager` 等上层接口使用下载能力,避免直接依赖本模块的内部类型。
|
||||
|
||||
### 核心职责
|
||||
|
||||
- HTTP/HTTPS 文件下载
|
||||
@@ -16,7 +20,7 @@ DownloadSystem 是 YooAsset 资源管理系统的**底层网络下载层**,负
|
||||
|
||||
## 边界与上层协作
|
||||
|
||||
DownloadSystem 的职责是提供“可替换后端 + 统一请求接口 + 轮询式生命周期”的基础能力:
|
||||
DownloadSystem 的职责是提供"可替换后端 + 统一请求接口 + 轮询式生命周期"的基础能力:
|
||||
|
||||
- **本模块不负责并发队列/限流调度**:并发通常由上层同时创建多个 request 并自行控制并发数。
|
||||
- **本模块不负责重试/回退策略**:失败后的重试、切换 CDN、降级等策略通常由上层系统实现。
|
||||
@@ -41,20 +45,20 @@ DownloadSystem 的职责是提供“可替换后端 + 统一请求接口 + 轮
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 上层调用者 │
|
||||
│ (FileSystem / ResourceManager) │
|
||||
│ 上层调用者 │
|
||||
│ (FileSystem / ResourceManager) │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
│ IDownloadBackend │
|
||||
│ IDownloadBackend │
|
||||
│ (后端接口) │
|
||||
│ 定义网络库合约,工厂模式创建请求 │
|
||||
│ 定义网络库合约,工厂模式创建请求 │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
│ IDownloadRequest │
|
||||
│ IDownloadRequest │
|
||||
│ (请求接口) │
|
||||
│ 轮询式生命周期管理,状态机驱动 │
|
||||
│ 轮询式生命周期管理,状态机驱动 │
|
||||
└─────────────────────────┬───────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────▼───────────────────────────────┐
|
||||
@@ -79,22 +83,23 @@ DownloadSystem/
|
||||
│ ├── IDownloadBackend.cs # 后端接口(工厂模式)
|
||||
│ └── IDownloadRequest.cs # 请求接口层次结构
|
||||
│
|
||||
├── DefaultDownloadBackend/ # 默认后端实现
|
||||
├── UnityWebBackend/ # 默认后端实现
|
||||
│ ├── UnityWebRequestBackend.cs # UnityWebRequest 后端
|
||||
│ └── UnityWebRequestCreator.cs # UnityWebRequest 创建委托
|
||||
│
|
||||
├── DefaultDownloadRequest/ # 默认请求实现
|
||||
│ ├── UnityWebRequestDownloaderBase.cs # 基础下载器(抽象类)
|
||||
│ ├── UnityWebRequestFileDownloader.cs # 文件下载器
|
||||
│ ├── UnityWebRequestHeadDownloader.cs # HEAD 请求器
|
||||
│ ├── UnityWebRequestBytesDownloader.cs # 字节下载器
|
||||
│ ├── UnityWebRequestTextDownloader.cs # 文本下载器
|
||||
│ ├── UnityWebRequestAssetBundleDownloader.cs # AssetBundle 下载器
|
||||
│ └── VirtualFileDownloader.cs # 模拟下载器(编辑器用)
|
||||
├── UnityWebRequest/ # 默认请求实现
|
||||
│ ├── UnityWebRequestBase.cs # 基础下载器(抽象类)
|
||||
│ ├── UnityWebRequestFile.cs # 文件下载器
|
||||
│ ├── UnityWebRequestHead.cs # HEAD 请求器
|
||||
│ ├── UnityWebRequestBytes.cs # 字节下载器
|
||||
│ ├── UnityWebRequestText.cs # 文本下载器
|
||||
│ ├── UnityWebRequestAssetBundle.cs # AssetBundle 下载器
|
||||
│ └── SimulateRequestFile.cs # 模拟下载器(编辑器用)
|
||||
│
|
||||
├── DownloadSystemDefine.cs # 枚举、结构体定义
|
||||
├── DownloadSystemHelper.cs # 工具函数
|
||||
└── WebRequestCounter.cs # 请求失败计数器
|
||||
├── EDownloadRequestStatus.cs # 下载请求状态枚举
|
||||
├── DownloadRequestArgs.cs # 请求参数结构体定义
|
||||
├── DownloadSystemTools.cs # 工具函数
|
||||
└── DownloadFailureCounter.cs # 请求失败计数器
|
||||
```
|
||||
|
||||
---
|
||||
@@ -106,7 +111,7 @@ DownloadSystem/
|
||||
定义网络库实现的合约,通过工厂方法创建各类下载请求。
|
||||
|
||||
```csharp
|
||||
public interface IDownloadBackend
|
||||
internal interface IDownloadBackend : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 后端标识名称(用于日志/调试)
|
||||
@@ -133,13 +138,13 @@ public interface IDownloadBackend
|
||||
所有下载请求的通用接口,定义生命周期和状态管理。
|
||||
|
||||
```csharp
|
||||
public interface IDownloadRequest : IDisposable
|
||||
internal interface IDownloadRequest : IDisposable
|
||||
{
|
||||
// 元信息
|
||||
string URL { get; }
|
||||
|
||||
// 生命周期
|
||||
bool IsDone { get; } // 每次访问自动轮询
|
||||
bool IsDone { get; } // 访问时自动调用 PollingRequest()
|
||||
EDownloadRequestStatus Status { get; }
|
||||
|
||||
// 进度跟踪
|
||||
@@ -159,9 +164,9 @@ public interface IDownloadRequest : IDisposable
|
||||
|
||||
### 专化请求接口
|
||||
|
||||
| 接口 | 用途 | 特有属性 |
|
||||
| 接口 | 用途 | 特有能力 |
|
||||
|------|------|----------|
|
||||
| `IDownloadHeadRequest` | HEAD 请求,获取响应头 | `ETag`, `LastModified`, `ContentLength`, `ContentType` |
|
||||
| `IDownloadHeadRequest` | HEAD 请求,获取响应头 | `ETag`, `LastModified`, `ContentLength`, `ContentType`, `GetResponseHeader(name)` |
|
||||
| `IDownloadFileRequest` | 文件下载到本地 | `SavePath` |
|
||||
| `IDownloadBytesRequest` | 下载到内存(字节数组) | `byte[] Result` |
|
||||
| `IDownloadTextRequest` | 下载文本内容 | `string Result` |
|
||||
@@ -174,7 +179,7 @@ public interface IDownloadRequest : IDisposable
|
||||
### 请求状态枚举
|
||||
|
||||
```csharp
|
||||
public enum EDownloadRequestStatus
|
||||
internal enum EDownloadRequestStatus
|
||||
{
|
||||
None, // 未开始
|
||||
Running, // 进行中
|
||||
@@ -189,71 +194,97 @@ public enum EDownloadRequestStatus
|
||||
#### DownloadFileRequestArgs(文件下载参数)
|
||||
|
||||
```csharp
|
||||
public struct DownloadFileRequestArgs
|
||||
internal struct DownloadFileRequestArgs
|
||||
{
|
||||
public string URL; // 请求地址
|
||||
public int Timeout; // 响应超时(秒),0=无限制
|
||||
public int WatchdogTime; // 看门狗超时(秒)
|
||||
public readonly string URL; // 请求地址
|
||||
public readonly int Timeout; // 响应超时(秒),0=不应用超时
|
||||
public readonly int WatchdogTimeout; // 看门狗超时(秒),0=禁用
|
||||
|
||||
public string SavePath; // 文件保存路径
|
||||
public bool AppendToFile; // 追加写入(断点续传)
|
||||
public bool RemoveFileOnAbort; // 中止时删除文件
|
||||
public long ResumeFromBytes; // 断点续传起始位置
|
||||
public readonly string SavePath; // 文件保存路径
|
||||
public readonly bool AppendToFile; // 追加写入(断点续传)
|
||||
public readonly bool RemoveFileOnAbort; // 中止时删除文件
|
||||
public readonly long ResumeOffset; // 断点续传起始位置(>0 时推荐由后端设置 Range 头)
|
||||
|
||||
public Dictionary<string, string> Headers; // 自定义请求头
|
||||
public Dictionary<string, string> Headers; // 自定义请求头(可选)
|
||||
|
||||
public DownloadFileRequestArgs(
|
||||
string url,
|
||||
string savePath,
|
||||
int timeout,
|
||||
int watchdogTimeout,
|
||||
bool appendToFile = false,
|
||||
bool removeFileOnAbort = true,
|
||||
long resumeOffset = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 添加请求头(注意:相同 key 重复添加会抛异常)
|
||||
/// </summary>
|
||||
public void AddRequestHeader(string name, string value);
|
||||
}
|
||||
```
|
||||
|
||||
#### DownloadDataRequestArgs(数据下载参数)
|
||||
|
||||
```csharp
|
||||
public struct DownloadDataRequestArgs
|
||||
internal struct DownloadDataRequestArgs
|
||||
{
|
||||
public string URL; // 请求地址
|
||||
public int Timeout; // 响应超时(秒)
|
||||
public int WatchdogTime; // 看门狗超时(秒)
|
||||
public Dictionary<string, string> Headers; // 自定义请求头
|
||||
public readonly string URL; // 请求地址
|
||||
public readonly int Timeout; // 响应超时(秒),0=不应用超时
|
||||
public readonly int WatchdogTimeout; // 看门狗超时(秒),0=禁用
|
||||
public Dictionary<string, string> Headers; // 自定义请求头(可选)
|
||||
|
||||
public DownloadDataRequestArgs(string url, int timeout, int watchdogTimeout);
|
||||
|
||||
/// <summary>
|
||||
/// 添加请求头(注意:相同 key 重复添加会抛异常)
|
||||
/// </summary>
|
||||
public void AddRequestHeader(string name, string value);
|
||||
}
|
||||
```
|
||||
|
||||
#### DownloadAssetBundleRequestArgs(AssetBundle 下载参数)
|
||||
|
||||
```csharp
|
||||
public struct DownloadAssetBundleRequestArgs
|
||||
internal struct DownloadAssetBundleRequestArgs
|
||||
{
|
||||
public string URL; // 请求地址
|
||||
public int Timeout; // 响应超时
|
||||
public int WatchdogTime; // 看门狗超时
|
||||
public readonly string URL; // 请求地址
|
||||
public readonly int Timeout; // 响应超时(秒),0=不应用超时
|
||||
public readonly int WatchdogTimeout; // 看门狗超时(秒),0=禁用
|
||||
|
||||
public bool DisableUnityWebCache; // 禁用 Unity 缓存(推荐 true)
|
||||
public string FileHash; // 文件哈希(缓存启用时需要)
|
||||
public uint UnityCRC; // Unity CRC 校验值
|
||||
public readonly bool DisableUnityWebCache; // 禁用 Unity 缓存(默认 true)
|
||||
public readonly string FileHash; // 文件哈希(缓存启用时需要,且不能为空)
|
||||
public readonly uint UnityCRC; // Unity CRC 校验值
|
||||
|
||||
public Dictionary<string, string> Headers;
|
||||
public Dictionary<string, string> Headers; // 自定义请求头(可选)
|
||||
|
||||
public DownloadAssetBundleRequestArgs(
|
||||
string url,
|
||||
int timeout,
|
||||
int watchdogTimeout,
|
||||
bool disableUnityWebCache = true,
|
||||
string fileHash = null,
|
||||
uint unityCrc = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 添加请求头(注意:相同 key 重复添加会抛异常)
|
||||
/// </summary>
|
||||
public void AddRequestHeader(string name, string value);
|
||||
}
|
||||
```
|
||||
|
||||
#### DownloadSimulateRequestArgs(模拟下载参数)
|
||||
|
||||
```csharp
|
||||
public struct DownloadSimulateRequestArgs
|
||||
internal struct DownloadSimulateRequestArgs
|
||||
{
|
||||
public string URL; // 标识符
|
||||
public long FileSize; // 模拟文件大小
|
||||
public long DownloadSpeed; // 模拟速度(字节/秒),默认 1MB/s
|
||||
public readonly string URL; // 标识符
|
||||
public readonly long FileSize; // 模拟文件大小
|
||||
public readonly long DownloadSpeed; // 模拟速度(字节/秒),默认 1MB/s
|
||||
|
||||
public DownloadSimulateRequestArgs(string url, long fileSize, long downloadSpeed = 1024 * 1024);
|
||||
}
|
||||
```
|
||||
|
||||
### 回调数据结构体
|
||||
|
||||
| 结构体 | 用途 | 关键字段 |
|
||||
|--------|------|----------|
|
||||
| `DownloaderFinishData` | 下载完成回调 | `PackageName`, `Succeed` |
|
||||
| `DownloadUpdateData` | 进度更新回调 | `Progress`, `TotalDownloadBytes`, `CurrentDownloadBytes` |
|
||||
| `DownloadErrorData` | 下载错误回调 | `FileName`, `ErrorInfo` |
|
||||
| `DownloadFileData` | 文件完成回调 | `FileName`, `FileSize` |
|
||||
| `ImportFileInfo` | 导入文件元数据 | `FilePath`, `BundleName`, `BundleGUID` |
|
||||
|
||||
---
|
||||
|
||||
## 核心类说明
|
||||
@@ -278,7 +309,7 @@ UnityWebRequestCreator creator = (url, method) =>
|
||||
IDownloadBackend backend = new UnityWebRequestBackend(creator);
|
||||
```
|
||||
|
||||
### UnityWebRequestDownloaderBase
|
||||
### UnityWebRequestBase
|
||||
|
||||
抽象基类,封装所有下载器的通用逻辑。
|
||||
|
||||
@@ -300,12 +331,12 @@ None ──► SendRequest() ──► Running ──► PollingRequest() ──
|
||||
|
||||
| 下载器 | 实现接口 | 使用场景 |
|
||||
|--------|----------|----------|
|
||||
| `UnityWebRequestFileDownloader` | `IDownloadFileRequest` | 大文件下载到本地 |
|
||||
| `UnityWebRequestHeadDownloader` | `IDownloadHeadRequest` | 检查资源信息 |
|
||||
| `UnityWebRequestBytesDownloader` | `IDownloadBytesRequest` | 小文件内存加载 |
|
||||
| `UnityWebRequestTextDownloader` | `IDownloadTextRequest` | 文本文件下载 |
|
||||
| `UnityWebRequestAssetBundleDownloader` | `IDownloadAssetBundleRequest` | AB 包下载加载 |
|
||||
| `VirtualFileDownloader` | `IDownloadFileRequest` | 编辑器模拟下载 |
|
||||
| `UnityWebRequestFile` | `IDownloadFileRequest` | 大文件下载到本地 |
|
||||
| `UnityWebRequestHead` | `IDownloadHeadRequest` | 检查资源信息 |
|
||||
| `UnityWebRequestBytes` | `IDownloadBytesRequest` | 小文件内存加载 |
|
||||
| `UnityWebRequestText` | `IDownloadTextRequest` | 文本文件下载 |
|
||||
| `UnityWebRequestAssetBundle` | `IDownloadAssetBundleRequest` | AB 包下载加载 |
|
||||
| `SimulateRequestFile` | `IDownloadFileRequest` | 编辑器模拟下载 |
|
||||
|
||||
---
|
||||
|
||||
@@ -314,36 +345,38 @@ None ──► SendRequest() ──► Running ──► PollingRequest() ──
|
||||
### 基础文件下载
|
||||
|
||||
```csharp
|
||||
// 1. 创建后端和请求
|
||||
IDownloadBackend backend = new UnityWebRequestBackend();
|
||||
var args = new DownloadFileRequestArgs(
|
||||
url: "https://example.com/file.zip",
|
||||
savePath: "/path/to/save/file.zip",
|
||||
timeout: 30,
|
||||
watchdogTime: 0);
|
||||
IDownloadFileRequest request = backend.CreateFileRequest(args);
|
||||
|
||||
// 2. 发起并轮询
|
||||
request.SendRequest();
|
||||
while (!request.IsDone)
|
||||
IDownloadFileRequest request = null;
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
// 可选:显示进度
|
||||
float progress = request.DownloadProgress;
|
||||
}
|
||||
// 1. 创建请求
|
||||
var args = new DownloadFileRequestArgs(
|
||||
url: "https://example.com/file.zip",
|
||||
savePath: "/path/to/save/file.zip",
|
||||
timeout: 30,
|
||||
watchdogTimeout: 0);
|
||||
request = backend.CreateFileRequest(args);
|
||||
|
||||
// 3. 检查结果
|
||||
if (request.Status == EDownloadRequestStatus.Succeed)
|
||||
{
|
||||
Debug.Log("下载成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"下载失败: {request.Error}");
|
||||
}
|
||||
// 2. 发起并轮询
|
||||
request.SendRequest();
|
||||
while (!request.IsDone)
|
||||
{
|
||||
await Task.Yield();
|
||||
float progress = request.DownloadProgress;
|
||||
}
|
||||
|
||||
// 4. 清理资源
|
||||
request.Dispose();
|
||||
// 3. 检查结果
|
||||
if (request.Status == EDownloadRequestStatus.Succeed)
|
||||
Debug.Log("下载成功");
|
||||
else
|
||||
Debug.LogError($"下载失败: {request.Error}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 4. 清理资源
|
||||
request?.Dispose();
|
||||
backend.Dispose();
|
||||
}
|
||||
```
|
||||
|
||||
### 断点续传
|
||||
@@ -356,10 +389,10 @@ var args = new DownloadFileRequestArgs(
|
||||
url: url,
|
||||
savePath: savePath,
|
||||
timeout: 30,
|
||||
watchdogTime: 0,
|
||||
appendToFile: true, // 追加写入
|
||||
removeFileOnAbort: false, // 中止时保留文件
|
||||
resumeFromBytes: existingFileSize); // 断点位置
|
||||
watchdogTimeout: 0,
|
||||
appendToFile: true, // 追加写入
|
||||
removeFileOnAbort: false, // 中止时保留文件
|
||||
resumeOffset: existingFileSize); // 断点位置
|
||||
|
||||
IDownloadFileRequest request = backend.CreateFileRequest(args);
|
||||
request.SendRequest();
|
||||
@@ -373,7 +406,7 @@ var args = new DownloadFileRequestArgs(
|
||||
url: url,
|
||||
savePath: path,
|
||||
timeout: 30,
|
||||
watchdogTime: 30); // 30秒无数据自动中止
|
||||
watchdogTimeout: 30); // 30秒无数据自动中止
|
||||
|
||||
IDownloadFileRequest request = backend.CreateFileRequest(args);
|
||||
request.SendRequest();
|
||||
@@ -396,7 +429,7 @@ if (request.Status == EDownloadRequestStatus.Aborted)
|
||||
var args = new DownloadDataRequestArgs(
|
||||
url: "https://example.com/file.zip",
|
||||
timeout: 30,
|
||||
watchdogTime: 0);
|
||||
watchdogTimeout: 0);
|
||||
|
||||
IDownloadHeadRequest request = backend.CreateHeadRequest(args);
|
||||
request.SendRequest();
|
||||
@@ -422,7 +455,7 @@ if (request.Status == EDownloadRequestStatus.Succeed)
|
||||
var args = new DownloadDataRequestArgs(
|
||||
url: "https://example.com/data.json",
|
||||
timeout: 30,
|
||||
watchdogTime: 0);
|
||||
watchdogTimeout: 0);
|
||||
|
||||
IDownloadBytesRequest request = backend.CreateBytesRequest(args);
|
||||
request.SendRequest();
|
||||
@@ -495,7 +528,7 @@ IDownloadBackend (接口)
|
||||
│
|
||||
└── 未收到数据 ──► 计时器累加
|
||||
│
|
||||
└── 超过 WatchdogTime ──► AbortRequest()
|
||||
└── 超过 WatchdogTimeout ──► AbortRequest()
|
||||
```
|
||||
|
||||
---
|
||||
@@ -511,44 +544,49 @@ IDownloadRequest (基础接口)
|
||||
├── IDownloadTextRequest (文本下载)
|
||||
└── IDownloadAssetBundleRequest (AssetBundle 下载)
|
||||
|
||||
UnityWebRequestDownloaderBase (抽象基类)
|
||||
UnityWebRequestBase (抽象基类)
|
||||
│
|
||||
├── UnityWebRequestFileDownloader ──► IDownloadFileRequest
|
||||
├── UnityWebRequestHeadDownloader ──► IDownloadHeadRequest
|
||||
├── UnityWebRequestBytesDownloader ──► IDownloadBytesRequest
|
||||
├── UnityWebRequestTextDownloader ──► IDownloadTextRequest
|
||||
└── UnityWebRequestAssetBundleDownloader ──► IDownloadAssetBundleRequest
|
||||
├── UnityWebRequestFile ──► IDownloadFileRequest
|
||||
├── UnityWebRequestHead ──► IDownloadHeadRequest
|
||||
├── UnityWebRequestBytes ──► IDownloadBytesRequest
|
||||
├── UnityWebRequestText ──► IDownloadTextRequest
|
||||
└── UnityWebRequestAssetBundle ──► IDownloadAssetBundleRequest
|
||||
|
||||
VirtualFileDownloader (独立实现) ──► IDownloadFileRequest
|
||||
SimulateRequestFile (独立实现) ──► IDownloadFileRequest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 工具类
|
||||
|
||||
### DownloadSystemHelper
|
||||
### DownloadSystemTools
|
||||
|
||||
提供跨平台的工具函数:
|
||||
提供跨平台的 URL 转换和判断功能:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| `ConvertToWWWPath()` | 转换本地路径为 WWW 协议 URL |
|
||||
| `IsRequestLocalFile()` | 判断是否本地文件请求 |
|
||||
| 方法 | 参数 | 返回值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `ToLocalURL(path)` | `string path` 本地文件路径 | 可用于 UnityWebRequest 的文件协议 URL | 转换本地路径为文件协议 URL(自动处理特殊字符) |
|
||||
| `IsLocalFileURL(url)` | `string url` 要判断的 URL | `bool` 是否为本地文件 URL | 判断 URL 是否为 `file:` 或 `jar:file:` 协议 |
|
||||
|
||||
### WebRequestCounter
|
||||
### DownloadFailureCounter
|
||||
|
||||
请求失败计数器,用于诊断统计:
|
||||
网络请求失败计数器(诊断用):
|
||||
|
||||
- 线程安全:内部使用 `Dictionary` 且未加锁,约定只在主线程调用;如需多线程统计请在外层加锁或改造实现
|
||||
- Key 规则:`$"{packageName}_{eventName}"`
|
||||
- 统计口径:**仅统计网络请求失败**(`IDownloadRequest.Status != Succeed` 时记录),不统计内容为空、校验失败、解析失败等业务层失败
|
||||
- **线程安全**:内部使用 `Dictionary` 且未加锁,约定只在 Unity 主线程调用;如需在多线程/回调线程调用,请在外层加锁或改为并发容器实现
|
||||
- **Key 格式**:`$"{packageName}_{eventName}"`
|
||||
- **统计口径**:**仅统计网络请求失败**(`IDownloadRequest.Status != Succeed` 时记录),不统计内容为空、校验失败、解析失败等业务层失败
|
||||
|
||||
| 方法 | 参数 | 返回值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `RecordFailure(packageName, eventName)` | `string packageName` 资源包名称, `string eventName` 事件名称 | `void` | 记录一次失败 |
|
||||
| `GetFailureCount(packageName, eventName)` | `string packageName` 资源包名称, `string eventName` 事件名称 | `int` 失败次数(未记录过返回 0) | 获取失败次数 |
|
||||
|
||||
```csharp
|
||||
// 记录失败
|
||||
WebRequestCounter.RecordRequestFailed(packageName, eventName);
|
||||
DownloadFailureCounter.RecordFailure(packageName, eventName);
|
||||
|
||||
// 查询失败次数
|
||||
int count = WebRequestCounter.GetRequestFailedCount(packageName, eventName);
|
||||
int count = DownloadFailureCounter.GetFailureCount(packageName, eventName);
|
||||
```
|
||||
|
||||
---
|
||||
@@ -557,6 +595,7 @@ int count = WebRequestCounter.GetRequestFailedCount(packageName, eventName);
|
||||
|
||||
1. **资源释放**:使用完毕后务必调用 `Dispose()` 释放资源
|
||||
- `AbortRequest()` 仅用于中止请求与切换状态,不等同于释放资源;无论成功/失败/中止都需要 `Dispose()`
|
||||
- 第三方 `IDownloadBackend` 可能持有原生资源/线程/连接池等,上层在不再使用时也应调用 `backend.Dispose()`
|
||||
- 推荐使用 `try/finally` 确保释放(尤其是上层可能提前中止的场景)
|
||||
2. **断点续传**:需要服务器支持 `Range` 请求头和 `206 Partial Content` 响应
|
||||
- 若服务端不支持 Range 仍返回 200,全量内容可能会被追加写入,导致文件损坏
|
||||
@@ -565,3 +604,4 @@ int count = WebRequestCounter.GetRequestFailedCount(packageName, eventName);
|
||||
5. **驱动更新**:部分第三方网络库实现的 backend 可能需要每帧调用 `IDownloadBackend.Update()` 进行驱动
|
||||
6. **中止语义**:`Aborted` 可能来自用户主动 `AbortRequest()` 或看门狗超时;中止场景下 `HttpCode/Error` 可能为默认值(例如 0/空)
|
||||
7. **线程安全**:所有下载请求的创建和轮询应在主线程进行
|
||||
8. **模拟下载器**:`SimulateRequestFile` 仅用于模拟进度,不会落盘,且 `SavePath` 始终为 `null`;成功时 `HttpCode` 固定为 `200`
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public IDownloadHeadRequest CreateHeadRequest(DownloadDataRequestArgs args)
|
||||
{
|
||||
return new UnityWebRequestHeadDownloader(args, _webRequestCreator);
|
||||
return new UnityWebRequestHead(args, _webRequestCreator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,7 +72,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public IDownloadFileRequest CreateFileRequest(DownloadFileRequestArgs args)
|
||||
{
|
||||
return new UnityWebRequestFileDownloader(args, _webRequestCreator);
|
||||
return new UnityWebRequestFile(args, _webRequestCreator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -80,7 +80,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public IDownloadBytesRequest CreateBytesRequest(DownloadDataRequestArgs args)
|
||||
{
|
||||
return new UnityWebRequestBytesDownloader(args, _webRequestCreator);
|
||||
return new UnityWebRequestBytes(args, _webRequestCreator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -88,7 +88,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public IDownloadTextRequest CreateTextRequest(DownloadDataRequestArgs args)
|
||||
{
|
||||
return new UnityWebRequestTextDownloader(args, _webRequestCreator);
|
||||
return new UnityWebRequestText(args, _webRequestCreator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,7 +96,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public IDownloadAssetBundleRequest CreateAssetBundleRequest(DownloadAssetBundleRequestArgs args)
|
||||
{
|
||||
return new UnityWebRequestAssetBundleDownloader(args, _webRequestCreator);
|
||||
return new UnityWebRequestAssetBundle(args, _webRequestCreator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -104,7 +104,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public IDownloadFileRequest CreateSimulateRequest(DownloadSimulateRequestArgs args)
|
||||
{
|
||||
return new VirtualFileDownloader(args);
|
||||
return new SimulateRequestFile(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义 UnityWebRequest 创建委托
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 用于自定义 UnityWebRequest 的创建方式,例如添加证书验证、代理设置等。
|
||||
/// 通过 UnityWebRequestBackend 构造函数传入。
|
||||
/// </remarks>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="method">HTTP 方法(如 GET、HEAD)</param>
|
||||
/// <returns>自定义配置的 UnityWebRequest 实例</returns>
|
||||
public delegate UnityWebRequest UnityWebRequestCreator(string url, string method);
|
||||
}
|
||||
@@ -9,10 +9,10 @@ namespace YooAsset
|
||||
/// 用于编辑器模式下模拟下载进度,不进行实际网络请求。
|
||||
/// 根据配置的下载速度模拟进度变化。
|
||||
/// </remarks>
|
||||
internal sealed class VirtualFileDownloader : IDownloadFileRequest
|
||||
internal sealed class SimulateRequestFile : IDownloadFileRequest
|
||||
{
|
||||
private readonly DownloadSimulateRequestArgs _args;
|
||||
private double _lastUpdateTime;
|
||||
private double _lastTickTime;
|
||||
|
||||
/// <summary>
|
||||
/// 文件保存路径(模拟下载不需要)
|
||||
@@ -72,7 +72,7 @@ namespace YooAsset
|
||||
/// 构造模拟下载器
|
||||
/// </summary>
|
||||
/// <param name="args">模拟下载参数</param>
|
||||
public VirtualFileDownloader(DownloadSimulateRequestArgs args)
|
||||
public SimulateRequestFile(DownloadSimulateRequestArgs args)
|
||||
{
|
||||
_args = args;
|
||||
URL = args.URL;
|
||||
@@ -87,7 +87,7 @@ namespace YooAsset
|
||||
if (Status == EDownloadRequestStatus.None)
|
||||
{
|
||||
Status = EDownloadRequestStatus.Running;
|
||||
_lastUpdateTime = GetUnityEngineRealtime();
|
||||
_lastTickTime = TimeUtility.RealtimeSinceStartup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,9 +99,9 @@ namespace YooAsset
|
||||
if (Status != EDownloadRequestStatus.Running)
|
||||
return;
|
||||
|
||||
double currentTime = GetUnityEngineRealtime();
|
||||
double deltaTime = currentTime - _lastUpdateTime;
|
||||
_lastUpdateTime = currentTime;
|
||||
double currentTime = TimeUtility.RealtimeSinceStartup;
|
||||
double deltaTime = currentTime - _lastTickTime;
|
||||
_lastTickTime = currentTime;
|
||||
|
||||
// 计算本帧下载的字节数
|
||||
long downloadBytes = (long)(_args.DownloadSpeed * deltaTime);
|
||||
@@ -137,14 +137,5 @@ namespace YooAsset
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
private double GetUnityEngineRealtime()
|
||||
{
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
return UnityEngine.Time.realtimeSinceStartupAsDouble;
|
||||
#else
|
||||
return UnityEngine.Time.realtimeSinceStartup;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace YooAsset
|
||||
/// 下载并加载 Unity AssetBundle 资源包。
|
||||
/// 支持 Unity 内置缓存机制和 CRC 校验。
|
||||
/// </remarks>
|
||||
internal sealed class UnityWebRequestAssetBundleDownloader : UnityWebRequestDownloaderBase, IDownloadAssetBundleRequest
|
||||
internal sealed class UnityWebRequestAssetBundle : UnityWebRequestBase, IDownloadAssetBundleRequest
|
||||
{
|
||||
private readonly DownloadAssetBundleRequestArgs _args;
|
||||
private DownloadHandlerAssetBundle _downloadHandler;
|
||||
@@ -26,7 +26,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
/// <param name="args">AssetBundle 下载参数</param>
|
||||
/// <param name="webRequestCreator">UnityWebRequest 创建器(可选)</param>
|
||||
public UnityWebRequestAssetBundleDownloader(DownloadAssetBundleRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
public UnityWebRequestAssetBundle(DownloadAssetBundleRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
: base(args.URL, webRequestCreator)
|
||||
{
|
||||
_args = args;
|
||||
@@ -38,10 +38,10 @@ namespace YooAsset
|
||||
protected override void CreateWebRequest()
|
||||
{
|
||||
_downloadHandler = CreateAssetBundleDownloadHandler();
|
||||
_webRequest = CreateUnityWebRequestGet(URL);
|
||||
_webRequest = CreateGetRequest(URL);
|
||||
_webRequest.downloadHandler = _downloadHandler;
|
||||
_webRequest.disposeDownloadHandlerOnDispose = true;
|
||||
ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers);
|
||||
ConfigureRequest(_args.Timeout, _args.WatchdogTimeout, _args.Headers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,7 +76,7 @@ namespace YooAsset
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(_args.FileHash))
|
||||
throw new YooInternalException("File hash is null or empty !");
|
||||
throw new YooInternalException("File hash is null or empty.");
|
||||
|
||||
// 使用 Unity 缓存
|
||||
// 说明:The file hash defining the version of the asset bundle.
|
||||
@@ -11,16 +11,16 @@ namespace YooAsset
|
||||
/// 封装 UnityWebRequest 的通用下载逻辑,包括状态管理、进度追踪等。
|
||||
/// 子类只需实现 CreateWebRequest 方法来创建特定类型的下载请求。
|
||||
/// </remarks>
|
||||
internal abstract class UnityWebRequestDownloaderBase : IDownloadRequest
|
||||
internal abstract class UnityWebRequestBase : IDownloadRequest
|
||||
{
|
||||
private readonly UnityWebRequestCreator _webRequestCreator;
|
||||
protected UnityWebRequest _webRequest;
|
||||
|
||||
// 看门狗相关
|
||||
private int _watchdogTime = 0;
|
||||
private int _watchdogTimeout = 0;
|
||||
private bool _watchdogAborted = false;
|
||||
private long _lastDownloadBytes = -1;
|
||||
private double _lastGetDataTime;
|
||||
private double _lastDataReceivedTime;
|
||||
|
||||
#region 接口实现
|
||||
/// <summary>
|
||||
@@ -76,7 +76,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="webRequestCreator">UnityWebRequest 创建器(可选)</param>
|
||||
protected UnityWebRequestDownloaderBase(string url, UnityWebRequestCreator webRequestCreator)
|
||||
protected UnityWebRequestBase(string url, UnityWebRequestCreator webRequestCreator)
|
||||
{
|
||||
URL = url;
|
||||
_webRequestCreator = webRequestCreator;
|
||||
@@ -109,7 +109,7 @@ namespace YooAsset
|
||||
catch (Exception ex)
|
||||
{
|
||||
Status = EDownloadRequestStatus.Failed;
|
||||
Error = $"[{GetType().Name}] Failed to create web request : {ex.Message}";
|
||||
Error = $"[{GetType().Name}] Failed to create web request: {ex.Message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ namespace YooAsset
|
||||
DownloadProgress = _webRequest.downloadProgress;
|
||||
DownloadedBytes = (long)_webRequest.downloadedBytes;
|
||||
|
||||
CheckWatchdog();
|
||||
TickWatchdog();
|
||||
if (_webRequest.isDone == false)
|
||||
return;
|
||||
|
||||
@@ -144,12 +144,12 @@ namespace YooAsset
|
||||
else
|
||||
{
|
||||
Status = EDownloadRequestStatus.Failed;
|
||||
Error = $"[{GetType().Name}] URL: {URL} - 错误: {_webRequest.error}";
|
||||
Error = $"[{GetType().Name}] URL: {URL} - Error: {_webRequest.error}";
|
||||
OnRequestFailed();
|
||||
}
|
||||
|
||||
// 完成后释放
|
||||
DisposeWebRequest();
|
||||
CleanupWebRequest();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -170,7 +170,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeWebRequest();
|
||||
CleanupWebRequest();
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
/// <param name="requestUrl">请求地址</param>
|
||||
/// <returns>UnityWebRequest 实例</returns>
|
||||
protected UnityWebRequest CreateUnityWebRequestGet(string requestUrl)
|
||||
protected UnityWebRequest CreateGetRequest(string requestUrl)
|
||||
{
|
||||
if (_webRequestCreator != null)
|
||||
return _webRequestCreator.Invoke(requestUrl, UnityWebRequest.kHttpVerbGET);
|
||||
@@ -212,7 +212,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
/// <param name="requestUrl">请求地址</param>
|
||||
/// <returns>UnityWebRequest 实例</returns>
|
||||
protected UnityWebRequest CreateUnityWebRequestHead(string requestUrl)
|
||||
protected UnityWebRequest CreateHeadRequest(string requestUrl)
|
||||
{
|
||||
if (_webRequestCreator != null)
|
||||
return _webRequestCreator.Invoke(requestUrl, UnityWebRequest.kHttpVerbHEAD);
|
||||
@@ -221,21 +221,21 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用通用请求参数
|
||||
/// 配置通用请求参数
|
||||
/// </summary>
|
||||
protected void ApplyRequestOptions(int timeout, int watchdogTime, Dictionary<string, string> headers)
|
||||
protected void ConfigureRequest(int timeout, int watchdogTimeout, Dictionary<string, string> headers)
|
||||
{
|
||||
if (_webRequest == null)
|
||||
throw new YooInternalException("Web request is null !");
|
||||
throw new YooInternalException("Web request is null.");
|
||||
|
||||
// 设置看门狗超时时间
|
||||
_watchdogTime = watchdogTime;
|
||||
_watchdogTimeout = watchdogTimeout;
|
||||
|
||||
// 设置响应的超时时间
|
||||
if (timeout > 0)
|
||||
_webRequest.timeout = timeout;
|
||||
|
||||
// 设置响应头
|
||||
// 设置请求头
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
@@ -248,28 +248,23 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 检测看门狗
|
||||
/// </summary>
|
||||
private void CheckWatchdog()
|
||||
private void TickWatchdog()
|
||||
{
|
||||
if (_watchdogTime == 0)
|
||||
if (_watchdogTimeout == 0)
|
||||
return;
|
||||
if (_watchdogAborted)
|
||||
return;
|
||||
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartupAsDouble;
|
||||
#else
|
||||
double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartup;
|
||||
#endif
|
||||
|
||||
double realtimeSinceStartup = TimeUtility.RealtimeSinceStartup;
|
||||
if (DownloadedBytes != _lastDownloadBytes)
|
||||
{
|
||||
_lastDownloadBytes = DownloadedBytes;
|
||||
_lastGetDataTime = realtimeSinceStartup;
|
||||
_lastDataReceivedTime = realtimeSinceStartup;
|
||||
}
|
||||
else
|
||||
{
|
||||
double deltaTime = realtimeSinceStartup - _lastGetDataTime;
|
||||
if (deltaTime > _watchdogTime)
|
||||
double deltaTime = realtimeSinceStartup - _lastDataReceivedTime;
|
||||
if (deltaTime > _watchdogTimeout)
|
||||
{
|
||||
_watchdogAborted = true;
|
||||
AbortRequest(); //看门狗终止网络请求
|
||||
@@ -278,9 +273,9 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// 清理 WebRequest 资源
|
||||
/// </summary>
|
||||
private void DisposeWebRequest()
|
||||
private void CleanupWebRequest()
|
||||
{
|
||||
if (_webRequest != null)
|
||||
{
|
||||
@@ -9,7 +9,7 @@ namespace YooAsset
|
||||
/// <remarks>
|
||||
/// 将下载内容保存到内存中的字节数组。
|
||||
/// </remarks>
|
||||
internal sealed class UnityWebRequestBytesDownloader : UnityWebRequestDownloaderBase, IDownloadBytesRequest
|
||||
internal sealed class UnityWebRequestBytes : UnityWebRequestBase, IDownloadBytesRequest
|
||||
{
|
||||
private readonly DownloadDataRequestArgs _args;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
/// <param name="args">数据下载参数</param>
|
||||
/// <param name="webRequestCreator">UnityWebRequest 创建器(可选)</param>
|
||||
public UnityWebRequestBytesDownloader(DownloadDataRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
public UnityWebRequestBytes(DownloadDataRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
: base(args.URL, webRequestCreator)
|
||||
{
|
||||
_args = args;
|
||||
@@ -35,10 +35,10 @@ namespace YooAsset
|
||||
protected override void CreateWebRequest()
|
||||
{
|
||||
var handler = new DownloadHandlerBuffer();
|
||||
_webRequest = CreateUnityWebRequestGet(URL);
|
||||
_webRequest = CreateGetRequest(URL);
|
||||
_webRequest.downloadHandler = handler;
|
||||
_webRequest.disposeDownloadHandlerOnDispose = true;
|
||||
ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers);
|
||||
ConfigureRequest(_args.Timeout, _args.WatchdogTimeout, _args.Headers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -9,7 +9,7 @@ namespace YooAsset
|
||||
/// <remarks>
|
||||
/// 将下载内容保存到本地文件,支持断点续传和追加写入。
|
||||
/// </remarks>
|
||||
internal sealed class UnityWebRequestFileDownloader : UnityWebRequestDownloaderBase, IDownloadFileRequest
|
||||
internal sealed class UnityWebRequestFile : UnityWebRequestBase, IDownloadFileRequest
|
||||
{
|
||||
private readonly DownloadFileRequestArgs _args;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
/// <param name="args">文件下载参数</param>
|
||||
/// <param name="webRequestCreator">UnityWebRequest 创建器(可选)</param>
|
||||
public UnityWebRequestFileDownloader(DownloadFileRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
public UnityWebRequestFile(DownloadFileRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
: base(args.URL, webRequestCreator)
|
||||
{
|
||||
_args = args;
|
||||
@@ -40,17 +40,17 @@ namespace YooAsset
|
||||
var handler = new DownloadHandlerFile(_args.SavePath, _args.AppendToFile);
|
||||
handler.removeFileOnAbort = _args.RemoveFileOnAbort;
|
||||
|
||||
_webRequest = CreateUnityWebRequestGet(URL);
|
||||
_webRequest = CreateGetRequest(URL);
|
||||
_webRequest.downloadHandler = handler;
|
||||
_webRequest.disposeDownloadHandlerOnDispose = true;
|
||||
|
||||
// 断点续传:设置 Range 请求头
|
||||
if (_args.ResumeFromBytes > 0)
|
||||
if (_args.ResumeOffset > 0)
|
||||
{
|
||||
_webRequest.SetRequestHeader("Range", $"bytes={_args.ResumeFromBytes}-");
|
||||
_webRequest.SetRequestHeader("Range", $"bytes={_args.ResumeOffset}-");
|
||||
}
|
||||
|
||||
ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers);
|
||||
ConfigureRequest(_args.Timeout, _args.WatchdogTimeout, _args.Headers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace YooAsset
|
||||
/// 仅获取响应头信息,不下载实际内容。
|
||||
/// 用于检查资源是否存在、获取资源大小、检查缓存有效性等场景。
|
||||
/// </remarks>
|
||||
internal sealed class UnityWebRequestHeadDownloader : UnityWebRequestDownloaderBase, IDownloadHeadRequest
|
||||
internal sealed class UnityWebRequestHead : UnityWebRequestBase, IDownloadHeadRequest
|
||||
{
|
||||
// 注意:缓存响应头(因为 WebRequest 释放后无法获取)
|
||||
private Dictionary<string, string> _cachedResponseHeaders;
|
||||
@@ -69,7 +69,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
/// <param name="args">数据下载参数</param>
|
||||
/// <param name="webRequestCreator">UnityWebRequest 创建器(可选)</param>
|
||||
public UnityWebRequestHeadDownloader(DownloadDataRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
public UnityWebRequestHead(DownloadDataRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
: base(args.URL, webRequestCreator)
|
||||
{
|
||||
_args = args;
|
||||
@@ -98,9 +98,9 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
protected override void CreateWebRequest()
|
||||
{
|
||||
_webRequest = CreateUnityWebRequestHead(URL);
|
||||
_webRequest = CreateHeadRequest(URL);
|
||||
_webRequest.downloadHandler = null; // HEAD 请求不需要 DownloadHandler
|
||||
ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers);
|
||||
ConfigureRequest(_args.Timeout, _args.WatchdogTimeout, _args.Headers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -9,7 +9,7 @@ namespace YooAsset
|
||||
/// <remarks>
|
||||
/// 将下载内容解析为 UTF-8 文本字符串。
|
||||
/// </remarks>
|
||||
internal sealed class UnityWebRequestTextDownloader : UnityWebRequestDownloaderBase, IDownloadTextRequest
|
||||
internal sealed class UnityWebRequestText : UnityWebRequestBase, IDownloadTextRequest
|
||||
{
|
||||
private readonly DownloadDataRequestArgs _args;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
/// <param name="args">数据下载参数</param>
|
||||
/// <param name="webRequestCreator">UnityWebRequest 创建器(可选)</param>
|
||||
public UnityWebRequestTextDownloader(DownloadDataRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
public UnityWebRequestText(DownloadDataRequestArgs args, UnityWebRequestCreator webRequestCreator)
|
||||
: base(args.URL, webRequestCreator)
|
||||
{
|
||||
_args = args;
|
||||
@@ -35,10 +35,10 @@ namespace YooAsset
|
||||
protected override void CreateWebRequest()
|
||||
{
|
||||
var handler = new DownloadHandlerBuffer();
|
||||
_webRequest = CreateUnityWebRequestGet(URL);
|
||||
_webRequest = CreateGetRequest(URL);
|
||||
_webRequest.downloadHandler = handler;
|
||||
_webRequest.disposeDownloadHandlerOnDispose = true;
|
||||
ApplyRequestOptions(_args.Timeout, _args.WatchdogTime, _args.Headers);
|
||||
ConfigureRequest(_args.Timeout, _args.WatchdogTimeout, _args.Headers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -36,14 +36,6 @@ namespace YooAsset
|
||||
{
|
||||
return _fileSystem.GetBundleFilePath(_packageBundle);
|
||||
}
|
||||
public override byte[] ReadBundleFileData()
|
||||
{
|
||||
return _fileSystem.ReadBundleFileData(_packageBundle);
|
||||
}
|
||||
public override string ReadBundleFileText()
|
||||
{
|
||||
return _fileSystem.ReadBundleFileText(_packageBundle);
|
||||
}
|
||||
|
||||
public override FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo)
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace YooAsset
|
||||
if (_assetBundle == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs !";
|
||||
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs.";
|
||||
Status = EOperationStatus.Failed;
|
||||
return;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadAsset)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_assetInfo.AssetType == null)
|
||||
Result = _assetBundle.LoadAllAssets();
|
||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_request != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||
@@ -108,14 +108,7 @@ namespace YooAsset
|
||||
}
|
||||
internal override void InternalWaitForAsyncComplete()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (ExecuteWhileDone())
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RunBatchExecution();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ namespace YooAsset
|
||||
if (_assetBundle == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs !";
|
||||
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs.";
|
||||
Status = EOperationStatus.Failed;
|
||||
return;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadAsset)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_assetInfo.AssetType == null)
|
||||
Result = _assetBundle.LoadAsset(_assetInfo.AssetPath);
|
||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_request != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||
@@ -93,11 +93,11 @@ namespace YooAsset
|
||||
error = $"Failed to load asset : {_assetInfo.AssetPath} AssetType : null AssetBundle : {_packageBundle.BundleName}";
|
||||
else
|
||||
error = $"Failed to load asset : {_assetInfo.AssetPath} AssetType : {_assetInfo.AssetType} AssetBundle : {_packageBundle.BundleName}";
|
||||
YooLogger.Error(error);
|
||||
|
||||
_steps = ESteps.Done;
|
||||
Error = error;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = error;
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -108,14 +108,7 @@ namespace YooAsset
|
||||
}
|
||||
internal override void InternalWaitForAsyncComplete()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (ExecuteWhileDone())
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RunBatchExecution();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadScene)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 注意:场景同步加载方法不会立即加载场景,而是在下一帧加载。
|
||||
Result = SceneManager.LoadScene(_assetInfo.AssetPath, _loadParams);
|
||||
@@ -69,10 +69,10 @@ namespace YooAsset
|
||||
{
|
||||
if (_asyncOperation != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
//注意:场景加载无法强制异步转同步
|
||||
YooLogger.Error("The scene is loading asyn !");
|
||||
YooLogger.Error("The scene is loading asyn.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -107,7 +107,7 @@ namespace YooAsset
|
||||
internal override void InternalWaitForAsyncComplete()
|
||||
{
|
||||
//注意:场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
|
||||
InternalUpdate();
|
||||
RunOnceExecution();
|
||||
}
|
||||
public override void UnSuspendLoad()
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace YooAsset
|
||||
if (_assetBundle == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs !";
|
||||
Error = $"The bundle {_packageBundle.BundleName} has been destroyed due to unity engine bugs.";
|
||||
Status = EOperationStatus.Failed;
|
||||
return;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ namespace YooAsset
|
||||
|
||||
if (_steps == ESteps.LoadAsset)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
if (_assetInfo.AssetType == null)
|
||||
Result = _assetBundle.LoadAssetWithSubAssets(_assetInfo.AssetPath);
|
||||
@@ -71,7 +71,7 @@ namespace YooAsset
|
||||
{
|
||||
if (_request != null)
|
||||
{
|
||||
if (IsWaitForAsyncComplete)
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity asset.");
|
||||
@@ -108,14 +108,7 @@ namespace YooAsset
|
||||
}
|
||||
internal override void InternalWaitForAsyncComplete()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (ExecuteWhileDone())
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RunBatchExecution();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认的 AssetBundle 加载操作(非加密)
|
||||
/// 通用实现,适用于 BuiltinFileSystem 和 CacheFileSystem
|
||||
/// </summary>
|
||||
public class DefaultLoadAssetBundleOperation : LoadAssetBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadAssetBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private AssetBundleCreateRequest _createRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public DefaultLoadAssetBundleOperation(LoadAssetBundleOptions opionts) : base(opionts) { }
|
||||
internal override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadAssetBundle;
|
||||
}
|
||||
internal override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadAssetBundle)
|
||||
{
|
||||
if (IsWaitingForAsyncComplete)
|
||||
Result = AssetBundle.LoadFromFile(_options.FileLoadPath);
|
||||
else
|
||||
_createRequest = AssetBundle.LoadFromFileAsync(_options.FileLoadPath);
|
||||
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (_createRequest != null)
|
||||
{
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_createRequest.isDone == false)
|
||||
return;
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed to load asset bundle file : {_options.Bundle.BundleName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override void InternalWaitForAsyncComplete()
|
||||
{
|
||||
RunBatchExecution();
|
||||
}
|
||||
|
||||
public override AssetBundle LoadFromMemory()
|
||||
{
|
||||
byte[] fileData = FileUtility.ReadAllBytes(_options.FileLoadPath);
|
||||
if (fileData == null || fileData.Length == 0)
|
||||
return null;
|
||||
|
||||
return AssetBundle.LoadFromMemory(fileData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认的 AssetBundle 加载操作(加密)
|
||||
/// 通用实现,适用于 BuiltinFileSystem 和 CacheFileSystem
|
||||
/// </summary>
|
||||
public abstract class DefaultLoadAssetBundleFromOffsetOperation : LoadAssetBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadAssetBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private AssetBundleCreateRequest _createRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public DefaultLoadAssetBundleFromOffsetOperation(LoadAssetBundleOptions options) : base(options) { }
|
||||
internal override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadAssetBundle;
|
||||
}
|
||||
internal override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadAssetBundle)
|
||||
{
|
||||
ulong offset = GetFileOffset();
|
||||
if (IsWaitingForAsyncComplete)
|
||||
Result = AssetBundle.LoadFromFile(_options.FileLoadPath, 0, offset);
|
||||
else
|
||||
_createRequest = AssetBundle.LoadFromFileAsync(_options.FileLoadPath, 0, offset);
|
||||
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (_createRequest != null)
|
||||
{
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_createRequest.isDone == false)
|
||||
return;
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed to load asset bundle file : {_options.Bundle.BundleName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override void InternalWaitForAsyncComplete()
|
||||
{
|
||||
RunBatchExecution();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取偏移值
|
||||
/// </summary>
|
||||
protected abstract uint GetFileOffset();
|
||||
|
||||
public override AssetBundle LoadFromMemory()
|
||||
{
|
||||
int offset = (int)GetFileOffset();
|
||||
byte[] fileData = File.ReadAllBytes(_options.FileLoadPath);
|
||||
if (fileData == null || fileData.Length <= offset)
|
||||
return null;
|
||||
|
||||
// 跳过偏移量
|
||||
byte[] bundleData = new byte[fileData.Length - offset];
|
||||
Buffer.BlockCopy(fileData, offset, bundleData, 0, bundleData.Length);
|
||||
|
||||
return AssetBundle.LoadFromMemory(bundleData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认的 AssetBundle 加载操作(加密)
|
||||
/// 通用实现,适用于 CacheFileSystem
|
||||
/// </summary>
|
||||
public abstract class DefaultLoadAssetBundleFromMemoryOperation : LoadAssetBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckFilePath,
|
||||
LoadAssetBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private AssetBundleCreateRequest _createRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public DefaultLoadAssetBundleFromMemoryOperation(LoadAssetBundleOptions options) : base(options) { }
|
||||
internal override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckFilePath;
|
||||
}
|
||||
internal override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckFilePath)
|
||||
{
|
||||
string filePath = _options.FileLoadPath;
|
||||
if (IsSupportFileIO(filePath) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"FileIO not supported for builtin path : {filePath}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.LoadAssetBundle;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadAssetBundle)
|
||||
{
|
||||
byte[] fileData = File.ReadAllBytes(_options.FileLoadPath);
|
||||
byte[] rawData = DecryptData(fileData);
|
||||
if (rawData == null || rawData.Length == 0)
|
||||
{
|
||||
_steps = ESteps.None;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = "Decrypted raw data is null or empty.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsWaitingForAsyncComplete)
|
||||
Result = AssetBundle.LoadFromMemory(rawData);
|
||||
else
|
||||
_createRequest = AssetBundle.LoadFromMemoryAsync(rawData);
|
||||
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (_createRequest != null)
|
||||
{
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_createRequest.isDone == false)
|
||||
return;
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed to load asset bundle file : {_options.Bundle.BundleName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override void InternalWaitForAsyncComplete()
|
||||
{
|
||||
RunBatchExecution();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件数据解密
|
||||
/// </summary>
|
||||
protected abstract byte[] DecryptData(byte[] data);
|
||||
|
||||
public override AssetBundle LoadFromMemory()
|
||||
{
|
||||
byte[] fileData = File.ReadAllBytes(_options.FileLoadPath);
|
||||
byte[] rawData = DecryptData(fileData);
|
||||
if (rawData == null || rawData.Length == 0)
|
||||
return null;
|
||||
|
||||
return AssetBundle.LoadFromMemory(rawData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认的 AssetBundle 加载操作(加密)
|
||||
/// 通用实现,适用于 CacheFileSystem
|
||||
/// </summary>
|
||||
public abstract class DefaultLoadAssetBundleFromStreamOperation : LoadAssetBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckFilePath,
|
||||
LoadAssetBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private AssetBundleCreateRequest _createRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public DefaultLoadAssetBundleFromStreamOperation(LoadAssetBundleOptions options) : base(options) { }
|
||||
internal override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckFilePath;
|
||||
}
|
||||
internal override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckFilePath)
|
||||
{
|
||||
string filePath = _options.FileLoadPath;
|
||||
if (IsSupportFileIO(filePath) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"FileIO not supported for builtin path : {filePath}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.LoadAssetBundle;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadAssetBundle)
|
||||
{
|
||||
ManagedStream = CreateManagedFileStream();
|
||||
uint bufferSize = GetManagedReadBufferSize();
|
||||
|
||||
if (IsWaitingForAsyncComplete)
|
||||
Result = AssetBundle.LoadFromStream(ManagedStream, 0, bufferSize);
|
||||
else
|
||||
_createRequest = AssetBundle.LoadFromStreamAsync(ManagedStream, 0, bufferSize);
|
||||
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (_createRequest != null)
|
||||
{
|
||||
if (IsWaitingForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_createRequest.isDone == false)
|
||||
return;
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed to load asset bundle file : {_options.Bundle.BundleName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override void InternalWaitForAsyncComplete()
|
||||
{
|
||||
RunBatchExecution();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件流
|
||||
/// </summary>
|
||||
protected abstract FileStream CreateManagedFileStream();
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓冲池大小
|
||||
/// </summary>
|
||||
protected abstract uint GetManagedReadBufferSize();
|
||||
|
||||
/// <summary>
|
||||
/// 文件数据解密
|
||||
/// </summary>
|
||||
protected abstract byte[] DecryptData(byte[] data);
|
||||
|
||||
public override AssetBundle LoadFromMemory()
|
||||
{
|
||||
byte[] fileData = File.ReadAllBytes(_options.FileLoadPath);
|
||||
byte[] rawData = DecryptData(fileData);
|
||||
if (rawData == null || rawData.Length == 0)
|
||||
return null;
|
||||
|
||||
return AssetBundle.LoadFromMemory(rawData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b82b4b846083d34b958320b584d8d9b
|
||||
guid: 067ac2067f265624bac214127575d7d5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,249 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认的 AssetBundle 加载操作(非加密)
|
||||
/// 通用实现,适用于 WebRemoteFileSystem 和 WebServerFileSystem
|
||||
/// </summary>
|
||||
public class DefaultLoadWebAssetBundleOperation : LoadWebAssetBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CreateRequest,
|
||||
CheckRequest,
|
||||
TryAgain,
|
||||
Done,
|
||||
}
|
||||
|
||||
private IDownloadAssetBundleRequest _downloadAssetBundleRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
private int _requestCount = 0;
|
||||
private float _tryAgainTimer = 0;
|
||||
private int _failedTryAgain;
|
||||
|
||||
public DefaultLoadWebAssetBundleOperation(LoadWebAssetBundleOptions opionts) : base(opionts)
|
||||
{
|
||||
_failedTryAgain = opionts.FailedTryAgain;
|
||||
}
|
||||
internal override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CreateRequest;
|
||||
}
|
||||
internal override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 创建下载器
|
||||
if (_steps == ESteps.CreateRequest)
|
||||
{
|
||||
string url = GetRequestURL();
|
||||
var args = new DownloadAssetBundleRequestArgs(url, 0, _options.WatchdogTimeout, _options.DisableUnityWebCache, _options.Bundle.FileHash, _options.Bundle.UnityCRC);
|
||||
_downloadAssetBundleRequest = _options.DownloadBackend.CreateAssetBundleRequest(args);
|
||||
_downloadAssetBundleRequest.SendRequest();
|
||||
_steps = ESteps.CheckRequest;
|
||||
}
|
||||
|
||||
// 检测下载结果
|
||||
if (_steps == ESteps.CheckRequest)
|
||||
{
|
||||
Progress = _downloadAssetBundleRequest.DownloadProgress;
|
||||
DownloadedBytes = _downloadAssetBundleRequest.DownloadedBytes;
|
||||
DownloadProgress = _downloadAssetBundleRequest.DownloadProgress;
|
||||
if (_downloadAssetBundleRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadAssetBundleRequest.Status == EDownloadRequestStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
Result = _downloadAssetBundleRequest.Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_failedTryAgain > 0)
|
||||
{
|
||||
_steps = ESteps.TryAgain;
|
||||
YooLogger.Warning($"Failed download : {_downloadAssetBundleRequest.URL} Try again.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _downloadAssetBundleRequest.Error;
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
}
|
||||
|
||||
// 最终释放请求器
|
||||
_downloadAssetBundleRequest.Dispose();
|
||||
}
|
||||
|
||||
// 重新尝试下载
|
||||
if (_steps == ESteps.TryAgain)
|
||||
{
|
||||
_tryAgainTimer += Time.unscaledDeltaTime;
|
||||
if (_tryAgainTimer > 1f)
|
||||
{
|
||||
_tryAgainTimer = 0f;
|
||||
_failedTryAgain--;
|
||||
Progress = 0f;
|
||||
DownloadProgress = 0f;
|
||||
DownloadedBytes = 0;
|
||||
_steps = ESteps.CreateRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络请求地址
|
||||
/// </summary>
|
||||
protected string GetRequestURL()
|
||||
{
|
||||
// 轮流返回请求地址
|
||||
_requestCount++;
|
||||
if (_requestCount % 2 == 0)
|
||||
return _options.FallbackURL;
|
||||
else
|
||||
return _options.MainURL;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认的 AssetBundle 加载操作(加密)
|
||||
/// 通用实现,适用于 WebRemoteFileSystem 和 WebServerFileSystem
|
||||
/// </summary>
|
||||
public abstract class DefaultLoadWebAssetBundleFromMemoryOperation : LoadWebAssetBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CreateRequest,
|
||||
CheckRequest,
|
||||
TryAgain,
|
||||
Done,
|
||||
}
|
||||
|
||||
private IDownloadBytesRequest _downloadBytesRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
private int _requestCount = 0;
|
||||
private float _tryAgainTimer = 0;
|
||||
private int _failedTryAgain;
|
||||
|
||||
public DefaultLoadWebAssetBundleFromMemoryOperation(LoadWebAssetBundleOptions opionts) : base(opionts)
|
||||
{
|
||||
_failedTryAgain = opionts.FailedTryAgain;
|
||||
}
|
||||
internal override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CreateRequest;
|
||||
}
|
||||
internal override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 创建下载器
|
||||
if (_steps == ESteps.CreateRequest)
|
||||
{
|
||||
string url = GetRequestURL();
|
||||
var args = new DownloadDataRequestArgs(url, 0, _options.WatchdogTimeout);
|
||||
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
|
||||
_downloadBytesRequest.SendRequest();
|
||||
_steps = ESteps.CheckRequest;
|
||||
}
|
||||
|
||||
// 检测下载结果
|
||||
if (_steps == ESteps.CheckRequest)
|
||||
{
|
||||
Progress = _downloadBytesRequest.DownloadProgress;
|
||||
DownloadProgress = _downloadBytesRequest.DownloadProgress;
|
||||
DownloadedBytes = _downloadBytesRequest.DownloadedBytes;
|
||||
if (_downloadBytesRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
// 检查网络错误
|
||||
if (_downloadBytesRequest.Status == EDownloadRequestStatus.Succeed)
|
||||
{
|
||||
var rawData = Decryption(_downloadBytesRequest.Result);
|
||||
if (rawData == null || rawData.Length == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = "AssetBundle raw data is null or empty.";
|
||||
}
|
||||
else
|
||||
{
|
||||
AssetBundle assetBundle = AssetBundle.LoadFromMemory(rawData);
|
||||
if (assetBundle == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed load encrypted AssetBundle: {_options.Bundle.BundleName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
Result = assetBundle;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_failedTryAgain > 0)
|
||||
{
|
||||
_steps = ESteps.TryAgain;
|
||||
YooLogger.Warning($"Failed download : {_downloadBytesRequest.URL} Try again.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _downloadBytesRequest.Error;
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
}
|
||||
|
||||
// 最终释放请求器
|
||||
_downloadBytesRequest.Dispose();
|
||||
}
|
||||
|
||||
// 重新尝试下载
|
||||
if (_steps == ESteps.TryAgain)
|
||||
{
|
||||
_tryAgainTimer += Time.unscaledDeltaTime;
|
||||
if (_tryAgainTimer > 1f)
|
||||
{
|
||||
_tryAgainTimer = 0f;
|
||||
_failedTryAgain--;
|
||||
Progress = 0f;
|
||||
DownloadProgress = 0f;
|
||||
DownloadedBytes = 0;
|
||||
_steps = ESteps.CreateRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件数据解密
|
||||
/// </summary>
|
||||
protected abstract byte[] Decryption(byte[] data);
|
||||
|
||||
/// 获取网络请求地址
|
||||
/// </summary>
|
||||
protected string GetRequestURL()
|
||||
{
|
||||
// 轮流返回请求地址
|
||||
_requestCount++;
|
||||
if (_requestCount % 2 == 0)
|
||||
return _options.FallbackURL;
|
||||
else
|
||||
return _options.MainURL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff8a96dd005f55346986f8a98aff8c99
|
||||
guid: 05b4aa37709184a408090202f98b93d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载 AssetBundle 的 Operation 工厂委托
|
||||
/// </summary>
|
||||
public delegate LoadAssetBundleOperation LoadAssetBundleOperationFactory(bool bundleEncrypted, LoadAssetBundleOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// 加载 AssetBundle 的抽象基类
|
||||
/// 用户可继承此类实现自定义加载逻辑(如加密解密)
|
||||
/// </summary>
|
||||
public abstract class LoadAssetBundleOperation : AsyncOperationBase
|
||||
{
|
||||
protected readonly LoadAssetBundleOptions _options;
|
||||
|
||||
/// <summary>
|
||||
/// 加载结果:AssetBundle 对象
|
||||
/// </summary>
|
||||
public AssetBundle Result { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 托管流对象(如果使用流加载)
|
||||
/// 注意:流对象在资源包对象释放的时候会自动释放
|
||||
/// </summary>
|
||||
public Stream ManagedStream { get; protected set; }
|
||||
|
||||
public LoadAssetBundleOperation(LoadAssetBundleOptions options)
|
||||
{
|
||||
_options = options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 后备加载方法:从内存加载 AssetBundle
|
||||
/// 当主加载方式失败时,FileSystem 会调用此方法作为后备机制
|
||||
/// </summary>
|
||||
/// <returns>加载成功返回 AssetBundle 对象,失败返回 null</returns>
|
||||
public abstract AssetBundle LoadFromMemory();
|
||||
|
||||
/// <summary>
|
||||
/// 检查文件路径是否支持 FileIO 读取
|
||||
/// </summary>
|
||||
protected static bool IsSupportFileIO(string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
return true;
|
||||
if (filePath.StartsWith("jar:") || filePath.StartsWith("content:"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 立即完成(失败)的 AssetBundle 加载操作
|
||||
/// 用途:当 Factory 判定某种场景不支持(例如默认实现不支持加密包)时,返回该 Operation
|
||||
/// </summary>
|
||||
public sealed class LoadAssetBundleCompleteOperation : LoadAssetBundleOperation
|
||||
{
|
||||
private readonly string _error;
|
||||
|
||||
public LoadAssetBundleCompleteOperation(string error, LoadAssetBundleOptions options) : base(options)
|
||||
{
|
||||
_error = error;
|
||||
}
|
||||
internal override void InternalStart()
|
||||
{
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _error;
|
||||
}
|
||||
internal override void InternalUpdate()
|
||||
{
|
||||
}
|
||||
public override AssetBundle LoadFromMemory()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6d4ba58bf1a1bb4db469b2cdd741ad0
|
||||
guid: 32e01cb4600c49f42b8ec19be8f0fb22
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载 AssetBundle 的上下文信息
|
||||
/// </summary>
|
||||
public struct LoadAssetBundleOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件加载路径
|
||||
/// </summary>
|
||||
internal string FileLoadPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源包信息
|
||||
/// </summary>
|
||||
internal PackageBundle Bundle { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b866c4ec2f032aa4eb0d4f9094273100
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载 AssetBundle 的 Operation 工厂委托
|
||||
/// </summary>
|
||||
public delegate LoadWebAssetBundleOperation LoadWebAssetBundleOperationFactory(bool bundleEncrypted, LoadWebAssetBundleOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// 加载 AssetBundle 的抽象基类
|
||||
/// 用户可继承此类实现自定义加载逻辑(如加密解密)
|
||||
/// </summary>
|
||||
public abstract class LoadWebAssetBundleOperation : AsyncOperationBase
|
||||
{
|
||||
protected readonly LoadWebAssetBundleOptions _options;
|
||||
|
||||
/// <summary>
|
||||
/// 加载结果:AssetBundle 对象
|
||||
/// </summary>
|
||||
public AssetBundle Result { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下载进度
|
||||
/// </summary>
|
||||
public float DownloadProgress { protected set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 下载大小
|
||||
/// </summary>
|
||||
public long DownloadedBytes { protected set; get; }
|
||||
|
||||
public LoadWebAssetBundleOperation(LoadWebAssetBundleOptions options)
|
||||
{
|
||||
_options = options;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 立即完成(失败)的 AssetBundle 加载操作
|
||||
/// 用途:当 Factory 判定某种场景不支持(例如默认实现不支持加密包)时,返回该 Operation
|
||||
/// </summary>
|
||||
public sealed class LoadWebAssetBundleCompleteOperation : LoadWebAssetBundleOperation
|
||||
{
|
||||
private readonly string _error;
|
||||
|
||||
public LoadWebAssetBundleCompleteOperation(string error, LoadWebAssetBundleOptions options) : base(options)
|
||||
{
|
||||
_error = error;
|
||||
}
|
||||
internal override void InternalStart()
|
||||
{
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _error;
|
||||
}
|
||||
internal override void InternalUpdate()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f65d2f6038b95246b7a09cec4055b3a
|
||||
guid: f0fd9af541471154d9fc968abd450d31
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载 AssetBundle 的上下文信息
|
||||
/// </summary>
|
||||
public struct LoadWebAssetBundleOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源包信息
|
||||
/// </summary>
|
||||
internal PackageBundle Bundle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 失败后重试次数
|
||||
/// </summary>
|
||||
internal int FailedTryAgain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 看门狗超时时间
|
||||
/// </summary>
|
||||
internal int WatchdogTimeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下载后台接口
|
||||
/// </summary>
|
||||
internal IDownloadBackend DownloadBackend { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 禁用Unity的网络缓存
|
||||
/// </summary>
|
||||
internal bool DisableUnityWebCache { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 主资源地址
|
||||
/// </summary>
|
||||
internal string MainURL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备用资源地址
|
||||
/// </summary>
|
||||
internal string FallbackURL { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c79e03ac8bcbef4aa0e2eede5bf63fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -10,20 +10,10 @@ namespace YooAsset
|
||||
public abstract void UnloadBundleFile();
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源包文件的路径
|
||||
/// 获取资源包文件的本地路径
|
||||
/// </summary>
|
||||
public abstract string GetBundleFilePath();
|
||||
|
||||
/// <summary>
|
||||
/// 读取资源包文件的二进制数据
|
||||
/// </summary>
|
||||
public abstract byte[] ReadBundleFileData();
|
||||
|
||||
/// <summary>
|
||||
/// 读取资源包文件的文本数据
|
||||
/// </summary>
|
||||
public abstract string ReadBundleFileText();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载资源包内的资源对象
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user