源码-调试与诊断工具

篇章:04-源码深度-编辑器模块
阅读时间:约 25 分钟
前置知识:了解清单与报告


一、引言

本章将深入解析 YooAsset 调试与诊断工具的源码实现。YooAsset 提供了多个调试和诊断工具,包括 AssetBundle Debugger、Asset Scanner、Runtime Debugger 等。这些工具帮助开发者诊断资源管理问题、分析 Bundle 结构、排查性能瓶颈。

本章将从源码层面深入解析这些调试诊断工具的设计和实现。


二、AssetBundle Debugger

2.1 Debugger 的作用

AssetBundle Debugger 是 YooAsset 的核心调试工具:

功能

  • 查看 Bundle 列表
  • 查看 Bundle 详细信息
  • 查看 Bundle 之间的依赖关系
  • 查看资源地址映射
  • 模拟加载资源

使用场景

  • 构建后查看 Bundle 结构
  • 分析 Bundle 依赖问题
  • 优化资源打包
  • 排查资源加载问题

2.2 Debugger 的实现

public class AssetBundleDebugger
{
    private PackageManifest _manifest;
    
    public void LoadManifest(string manifestPath)
    {
        _manifest = PackageManifest.LoadFromFile(manifestPath);
    }
    
    public List<PackageBundle> GetAllBundles()
    {
        return _manifest?.BundleList.Bundles;
    }
    
    public PackageBundle GetBundle(string bundleName)
    {
        return _manifest?.BundleList.Bundles.FirstOrDefault(b => b.BundleName == bundleName);
    }
    
    public List<PackageBundle> GetBundleDependencies(string bundleName)
    {
        var bundle = GetBundle(bundleName);
        if (bundle == null) return new List<PackageBundle>();
        
        return bundle.DependIDs
            .Select(id => _manifest.BundleList.Bundles.FirstOrDefault(b => b.BundleID == id))
            .Where(b => b != null)
            .ToList();
    }
    
    public List<PackageBundle> GetBundleDependents(string bundleName)
    {
        var bundle = GetBundle(bundleName);
        if (bundle == null) return new List<PackageBundle>();
        
        return _manifest.BundleList.Bundles
            .Where(b => b.DependIDs.Contains(bundle.BundleID))
            .ToList();
    }
}

加载 Manifest 详解

Debugger 需要先加载 PackageManifest,然后基于 PackageManifest 提供调试功能。

获取 Bundle 列表详解

获取所有 Bundle 的列表,并显示 Bundle 的详细信息。

获取依赖关系详解

根据 Bundle 的依赖关系,获取依赖的 Bundle 和被依赖的 Bundle。

2.3 Debugger Window

AssetBundleDebuggerWindow 是 Debugger 的 UI 窗口:

public class AssetBundleDebuggerWindow : EditorWindow
{
    [MenuItem("YooAsset/AssetBundle Debugger")]
    public static void Open()
    {
        AssetBundleDebuggerWindow window = GetWindow<AssetBundleDebuggerWindow>();
        window.titleContent = new GUIContent("AssetBundle Debugger");
        window.Show();
    }
    
    private void OnGUI()
    {
        // 绘制 UI
        DrawToolbar();
        DrawBundleList();
        DrawBundleDetails();
    }
}

打开窗口详解

通过菜单项 YooAsset/AssetBundle Debugger 打开调试窗口。

绘制 UI 详解

窗口主要分为三个区域:工具栏、Bundle 列表、Bundle 详情。

工具栏详解

工具栏包括加载 Manifest、刷新、搜索等功能。

Bundle 列表详解

Bundle 列表显示所有 Bundle 的概要信息,包括名称、大小、Hash 等。

Bundle 详情详解

Bundle 详情显示选中 Bundle 的详细信息,包括资源列表、依赖关系等。

2.4 Debugger 的高级功能

模拟加载

public class AssetBundleDebugger
{
    public AssetBundle SimulateLoadBundle(string bundleName)
    {
        // 模拟加载 Bundle,不实际加载文件
        return null;
    }
}

模拟加载功能允许开发者在不实际加载资源的情况下模拟加载流程,便于调试。

依赖分析

public class AssetBundleDebugger
{
    public DependencyGraph AnalyzeDependencies()
    {
        var graph = new DependencyGraph();
        foreach (var bundle in _manifest.BundleList.Bundles)
        {
            graph.AddNode(bundle.BundleName);
            foreach (var depId in bundle.DependIDs)
            {
                var depBundle = _manifest.BundleList.Bundles.FirstOrDefault(b => b.BundleID == depId);
                if (depBundle != null)
                {
                    graph.AddEdge(bundle.BundleName, depBundle.BundleName);
                }
            }
        }
        return graph;
    }
}

依赖分析功能分析所有 Bundle 的依赖关系,生成依赖图。


三、Asset Scanner

3.1 Scanner 的作用

Asset Scanner 是 YooAsset 的资源扫描器:

功能

  • 扫描项目中所有资源
  • 分析资源依赖关系
  • 检测未使用的资源
  • 检测资源冗余
  • 检测大文件

使用场景

  • 定期清理未使用资源
  • 优化资源打包
  • 减小包体大小
  • 提高资源管理效率

3.2 Scanner 的实现

public class AssetScanner
{
    public ScanReport Scan(string folderPath)
    {
        ScanReport report = new ScanReport();
        
        // 1. 扫描所有资源
        var assets = GetAllAssets(folderPath);
        
        // 2. 分析每个资源
        foreach (var asset in assets)
        {
            var assetInfo = new AssetInfo();
            assetInfo.Path = asset;
            assetInfo.Dependencies = AssetDatabase.GetDependencies(asset, true).ToList();
            assetInfo.FileSize = new FileInfo(asset).Length;
            
            report.Assets.Add(assetInfo);
        }
        
        // 3. 检测未使用的资源
        report.UnusedAssets = DetectUnusedAssets(report.Assets);
        
        // 4. 检测冗余资源
        report.RedundantAssets = DetectRedundantAssets(report.Assets);
        
        // 5. 检测大文件
        report.LargeAssets = DetectLargeAssets(report.Assets, 1024 * 1024);
        
        return report;
    }
    
    private List<string> GetAllAssets(string folderPath)
    {
        var guids = AssetDatabase.FindAssets(string.Empty, new[] { folderPath });
        return guids.Select(AssetDatabase.GUIDToAssetPath).ToList();
    }
}

扫描资源详解

使用 AssetDatabase.FindAssets 扫描指定文件夹下的所有资源。

分析资源详解

为每个资源创建 AssetInfo,包含资源路径、依赖关系、文件大小等。

检测未使用资源详解

使用反射 API 扫描所有引用关系,找出未被引用的资源。

检测冗余资源详解

找出被多次打包的资源,提示开发者提取为共享资源。

检测大文件详解

找出超过指定大小的资源,提示开发者优化或压缩。

3.3 Scanner Window

AssetScannerWindow 是 Scanner 的 UI 窗口:

public class AssetScannerWindow : EditorWindow
{
    [MenuItem("YooAsset/Asset Scanner")]
    public static void Open()
    {
        AssetScannerWindow window = GetWindow<AssetScannerWindow>();
        window.titleContent = new GUIContent("Asset Scanner");
        window.Show();
    }
    
    private void OnGUI()
    {
        DrawFolderSelection();
        DrawScanOptions();
        DrawScanButton();
        DrawScanResults();
    }
}

打开窗口详解

通过菜单项 YooAsset/Asset Scanner 打开扫描窗口。

绘制 UI 详解

窗口包括文件夹选择、扫描选项、扫描按钮、扫描结果等区域。

扫描选项详解

扫描选项包括检测未使用资源、检测冗余资源、检测大文件等。

3.4 扫描结果展示

扫描结果通过 ScanReport 展示:

public class ScanReport
{
    public List<AssetInfo> Assets = new List<AssetInfo>();
    public List<string> UnusedAssets = new List<string>();
    public List<string> RedundantAssets = new List<string>();
    public List<string> LargeAssets = new List<string>();
    public ScanStatistics Statistics = new ScanStatistics();
}

public class ScanStatistics
{
    public int TotalAssetCount;
    public long TotalFileSize;
    public int UnusedAssetCount;
    public long UnusedFileSize;
    public int RedundantAssetCount;
    public long RedundantFileSize;
}

统计信息详解

统计信息包括总资源数、总文件大小、未使用资源数、未使用文件大小等。

未使用资源详解

未使用资源列表显示未被引用的资源。

冗余资源详解

冗余资源列表显示被多次打包的资源。

大文件详解

大文件列表显示超过指定大小的资源。


四、Runtime Debugger

4.1 Runtime Debugger 的作用

Runtime Debugger 是 YooAsset 的运行时调试器:

功能

  • 查看运行时已加载的 Bundle
  • 查看运行时已加载的资源
  • 查看运行时缓存信息
  • 查看运行时下载信息
  • 监控资源加载性能

使用场景

  • 运行时调试
  • 性能分析
  • 内存分析
  • 问题排查

4.2 Runtime Debugger 的实现

Runtime Debugger 通过 Runtime 端的接口实现:

public class RuntimeDebugger
{
    public static DebugInfo GetDebugInfo(ResourcePackage package)
    {
        DebugInfo info = new DebugInfo();
        
        // 1. 获取 Provider 信息
        var providers = package.ResourceManager.ProviderCache;
        foreach (var kvp in providers)
        {
            info.LoadedProviders.Add(CreateProviderInfo(kvp.Value));
        }
        
        // 2. 获取 Bundle 信息
        var bundleLoaders = package.ResourceManager.BundleLoaders;
        foreach (var kvp in bundleLoaders)
        {
            info.LoadedBundles.Add(CreateBundleInfo(kvp.Value));
        }
        
        // 3. 获取缓存信息
        info.CacheInfo = package.CacheSystem.GetDebugInfo();
        
        // 4. 获取下载信息
        info.DownloadInfo = package.DownloadManager.GetDebugInfo();
        
        return info;
    }
}

Provider 信息详解

获取所有已加载的 Provider 信息,包括 Provider 状态、引用计数、加载进度等。

Bundle 信息详解

获取所有已加载的 Bundle 信息,包括 Bundle 状态、文件大小、引用计数等。

缓存信息详解

获取缓存系统的信息,包括缓存文件、缓存大小、缓存命中率等。

下载信息详解

获取下载管理器的信息,包括下载任务、下载进度、下载速度等。

4.3 Runtime Debugger Window

RuntimeDebuggerWindow 是 Runtime Debugger 的 UI 窗口:

public class RuntimeDebuggerWindow : EditorWindow
{
    [MenuItem("YooAsset/Runtime Debugger")]
    public static void Open()
    {
        RuntimeDebuggerWindow window = GetWindow<RuntimeDebuggerWindow>();
        window.titleContent = new GUIContent("Runtime Debugger");
        window.Show();
    }
    
    private void OnGUI()
    {
        DrawPackageSelection();
        DrawProviderList();
        DrawBundleList();
        DrawCacheInfo();
        DrawDownloadInfo();
    }
}

打开窗口详解

通过菜单项 YooAsset/Runtime Debugger 打开运行时调试窗口。

绘制 UI 详解

窗口包括 Package 选择、Provider 列表、Bundle 列表、缓存信息、下载信息等。

4.4 实时监控

Runtime Debugger 支持实时监控:

public class RuntimeDebuggerWindow
{
    private void OnEnable()
    {
        // 启动定时刷新
        EditorApplication.update += OnEditorUpdate;
    }
    
    private void OnDisable()
    {
        EditorApplication.update -= OnEditorUpdate;
    }
    
    private void OnEditorUpdate()
    {
        if (EditorApplication.timeSinceStartup - _lastUpdateTime > _refreshInterval)
        {
            Repaint();
            _lastUpdateTime = EditorApplication.timeSinceStartup;
        }
    }
}

定时刷新详解

使用 EditorApplication.update 定时刷新窗口,显示最新的运行时信息。

刷新间隔详解

刷新间隔默认为 1 秒,可根据需要调整。


五、性能分析工具

5.1 性能分析的重要性

性能分析是调试诊断的重要部分:

  • 找出资源加载的性能瓶颈
  • 优化资源加载流程
  • 提高游戏性能

5.2 性能分析的实现

public class PerformanceProfiler
{
    private Dictionary<string, List<float>> _loadTimes = new Dictionary<string, List<float>>();
    
    public void RecordLoadTime(string assetPath, float loadTime)
    {
        if (!_loadTimes.ContainsKey(assetPath))
            _loadTimes[assetPath] = new List<float>();
        _loadTimes[assetPath].Add(loadTime);
    }
    
    public PerformanceReport GenerateReport()
    {
        var report = new PerformanceReport();
        
        foreach (var kvp in _loadTimes)
        {
            var stats = new LoadTimeStats();
            stats.AssetPath = kvp.Key;
            stats.AverageLoadTime = kvp.Value.Average();
            stats.MaxLoadTime = kvp.Value.Max();
            stats.MinLoadTime = kvp.Value.Min();
            stats.LoadCount = kvp.Value.Count;
            
            report.LoadTimeStats.Add(stats);
        }
        
        // 按平均加载时间排序
        report.LoadTimeStats = report.LoadTimeStats
            .OrderByDescending(s => s.AverageLoadTime)
            .ToList();
        
        return report;
    }
}

加载时间记录详解

记录每个资源的加载时间,统计平均、最大、最小加载时间。

性能报告生成详解

生成性能报告,按平均加载时间排序,便于找出加载慢的资源。

5.3 Unity Profiler 集成

YooAsset 集成了 Unity Profiler:

public class AssetProfiler
{
    public static void BeginSample(string name)
    {
        UnityEngine.Profiling.Profiler.BeginSample(name);
    }
    
    public static void EndSample()
    {
        UnityEngine.Profiling.Profiler.EndSample();
    }
}

Profiler 详解

使用 Unity 的 Profiler API 进行性能采样。

自定义 Profiler 详解

开发者可以自定义 Profiler 标签,便于在 Unity Profiler 中识别 YooAsset 的耗时。

5.4 Memory Profiler 集成

YooAsset 支持 Memory Profiler 集成:

public class MemoryProfiler
{
    public static long GetMemoryUsage()
    {
        return UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong();
    }
    
    public static long GetBundleMemoryUsage()
    {
        long total = 0;
        // 累计所有 Bundle 的内存使用
        return total;
    }
}

内存使用详解

通过 Unity Profiler API 获取内存使用情况。

Bundle 内存详解

累计所有已加载 Bundle 的内存使用。


六、总结

本章深入解析了 YooAsset 调试与诊断工具的源码实现,包括:

  • AssetBundle Debugger:查看 Bundle 信息、分析依赖关系
  • Asset Scanner:扫描资源、检测未使用资源、检测冗余资源
  • Runtime Debugger:查看运行时信息、实时监控
  • 性能分析工具:性能采样、Profiler 集成、Memory Profiler 集成

通过这些调试诊断工具,开发者可以方便地诊断和解决 YooAsset 使用过程中的问题。


上一篇清单与报告
下一篇运行时入口与初始化

Logo

CANN开发者社区旨在汇聚广大开发者,围绕CANN架构重构、算子开发、部署应用优化等核心方向,展开深度交流与思想碰撞,携手共同促进CANN开放生态突破!

更多推荐