Files
FlowScope/My project/Assets/FlowScope/Editor/FlowScopeDiagnosticsWindow.cs
2026-06-04 11:33:59 +08:00

269 lines
9.2 KiB
C#

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
namespace FlowScope.Editor
{
public sealed class FlowScopeDiagnosticsWindow : EditorWindow
{
private const string RuntimeAsmdefPath = "Assets/FlowScope/Runtime/FlowScope.Runtime.asmdef";
private const string AddressablesAsmdefPath = "Assets/FlowScope/Addressables/FlowScope.Addressables.asmdef";
private const string MainMenuScenePath = "Assets/FlowScope/Samples/MainMenuP0/Scenes/MainMenuP0.unity";
private const string MainMenuPanelPrefabPath = "Assets/FlowScope/Samples/MainMenuP0/Prefabs/MainMenuPanel.prefab";
private const string AddressablesPackageName = "com.unity.addressables";
private static readonly IReadOnlyList<AssetCheck> AssetChecks = new[]
{
new AssetCheck("Runtime asmdef", RuntimeAsmdefPath),
new AssetCheck("Addressables asmdef", AddressablesAsmdefPath),
new AssetCheck("MainMenuP0 scene", MainMenuScenePath),
new AssetCheck("MainMenuPanel prefab", MainMenuPanelPrefabPath),
};
private readonly List<DiagnosticResult> _assetResults = new List<DiagnosticResult>();
private ListRequest _packageListRequest;
private DiagnosticResult _addressablesPackageResult = DiagnosticResult.Pending(
"Addressables package",
"Package status has not been refreshed.");
private Vector2 _scrollPosition;
[MenuItem("Tools/FlowScope/Diagnostics")]
public static void Open()
{
FlowScopeDiagnosticsWindow window = GetWindow<FlowScopeDiagnosticsWindow>("FlowScope Diagnostics");
window.minSize = new Vector2(520f, 320f);
window.RefreshAll();
window.Show();
}
private void OnEnable()
{
RefreshAssetChecks();
RefreshPackageStatus();
}
private void OnDisable()
{
EditorApplication.update -= PollPackageListRequest;
}
private void OnGUI()
{
using (new EditorGUILayout.VerticalScope())
{
EditorGUILayout.LabelField("FlowScope Diagnostics", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("Read-only diagnostics. This window checks project state and does not create, move, delete, or repair user assets.", MessageType.Info);
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Refresh", GUILayout.Width(96f)))
{
RefreshAll();
}
GUILayout.Label(
_packageListRequest != null && !_packageListRequest.IsCompleted
? "Refreshing package status..."
: "Package status is complete or has not been requested.",
EditorStyles.miniLabel);
}
EditorGUILayout.Space();
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
DrawResult(_addressablesPackageResult);
foreach (DiagnosticResult result in _assetResults)
{
DrawResult(result);
}
EditorGUILayout.EndScrollView();
}
}
private void RefreshAll()
{
RefreshAssetChecks();
RefreshPackageStatus();
Repaint();
}
private void RefreshAssetChecks()
{
_assetResults.Clear();
foreach (AssetCheck check in AssetChecks)
{
bool exists = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(check.Path) != null;
_assetResults.Add(exists
? DiagnosticResult.Pass(check.Label, check.Path)
: DiagnosticResult.Fail(check.Label, check.Path));
}
}
private void RefreshPackageStatus()
{
EditorApplication.update -= PollPackageListRequest;
_addressablesPackageResult = DiagnosticResult.Pending(
"Addressables package",
"Querying com.unity.addressables through Unity Package Manager.");
_packageListRequest = Client.List(true);
EditorApplication.update += PollPackageListRequest;
}
private void PollPackageListRequest()
{
if (_packageListRequest == null || !_packageListRequest.IsCompleted)
{
return;
}
EditorApplication.update -= PollPackageListRequest;
if (_packageListRequest.Status == StatusCode.Success)
{
bool found = false;
foreach (UnityEditor.PackageManager.PackageInfo packageInfo in _packageListRequest.Result)
{
if (string.Equals(packageInfo.name, AddressablesPackageName, StringComparison.Ordinal))
{
found = true;
_addressablesPackageResult = DiagnosticResult.Pass(
"Addressables package",
packageInfo.name + " " + packageInfo.version);
break;
}
}
if (!found)
{
_addressablesPackageResult = DiagnosticResult.Fail(
"Addressables package",
"com.unity.addressables was not found in the current Package Manager list.");
}
}
else
{
string errorMessage = _packageListRequest.Error != null
? _packageListRequest.Error.message
: "Package Manager returned an unknown error.";
_addressablesPackageResult = DiagnosticResult.Warning("Addressables package", errorMessage);
}
_packageListRequest = null;
Repaint();
}
private static void DrawResult(DiagnosticResult result)
{
MessageType messageType = ToMessageType(result.Status);
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
{
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.Label(ToStatusText(result.Status), GUILayout.Width(72f));
EditorGUILayout.LabelField(result.Label, EditorStyles.boldLabel);
}
EditorGUILayout.HelpBox(result.Detail, messageType);
}
}
private static MessageType ToMessageType(DiagnosticStatus status)
{
switch (status)
{
case DiagnosticStatus.Pass:
return MessageType.Info;
case DiagnosticStatus.Fail:
return MessageType.Error;
case DiagnosticStatus.Warning:
return MessageType.Warning;
default:
return MessageType.None;
}
}
private static string ToStatusText(DiagnosticStatus status)
{
switch (status)
{
case DiagnosticStatus.Pass:
return "OK";
case DiagnosticStatus.Fail:
return "Missing";
case DiagnosticStatus.Warning:
return "Warning";
default:
return "Pending";
}
}
private readonly struct AssetCheck
{
public AssetCheck(string label, string path)
{
Label = label;
Path = path;
}
public string Label { get; }
public string Path { get; }
}
private readonly struct DiagnosticResult
{
private DiagnosticResult(DiagnosticStatus status, string label, string detail)
{
Status = status;
Label = label;
Detail = detail;
}
public DiagnosticStatus Status { get; }
public string Label { get; }
public string Detail { get; }
public static DiagnosticResult Pass(string label, string detail)
{
return new DiagnosticResult(DiagnosticStatus.Pass, label, detail);
}
public static DiagnosticResult Fail(string label, string detail)
{
return new DiagnosticResult(DiagnosticStatus.Fail, label, detail);
}
public static DiagnosticResult Warning(string label, string detail)
{
return new DiagnosticResult(DiagnosticStatus.Warning, label, detail);
}
public static DiagnosticResult Pending(string label, string detail)
{
return new DiagnosticResult(DiagnosticStatus.Pending, label, detail);
}
}
private enum DiagnosticStatus
{
Pending,
Pass,
Warning,
Fail,
}
}
}