Files
zeling_v2/Assets/_Game/Scripts/Editor/Tools/ScriptExecutionOrderTools.cs
Joywayer 82ce9ff09a refactor(editor): reorganize Editor directory and unify menu hierarchy
File directory changes (mirror Scripts/ module structure):
- AbilityTypeDrawer.cs         → Equipment/
- CharacterWizardWindow.cs     → Character/
- FormEditorWindow.cs          → Player/
- GMToolWindow.cs              → Tools/
- SOManagerWindow.cs           → Tools/
- Map/MapRoomDataEditor.cs     → World/Map/
- Navigation/ (root)           → Enemies/Navigation/
- Achievements/                → Progression/

Menu hierarchy changes (BaseGames/ top-level):
- Data/: +Character Wizard (from Tools/), +Boss Skill Sequence (from Tools/)
- Addressables/: +Addressable Batch Tool, +Asset Reference Graph, +Validate Address Keys (from Tools/Verification/)
- Scene/Setup/: +Boot Flow Wizard, +Scaffold *, +Auto-Open Persistent (from Tools/)
- Scene/: +Camera Area Setup (from Camera/), +Bake All NavSurfaces (from Tools/)
- Events/: +Event Bus Monitor, +Event Chain Viewer, +Create/Reimport Event Channels (from Tools/)
- Tools/Validation/: +Validate All SOs, +Apply/Validate Script Order (from Tools/ flat)
- Tools/Maintenance/: +Missing Scripts/*, +Physics2D Layer Matrix/* (from Tools/ flat)

Result: BaseGames/Tools/ reduced from 16 flat items to 4 items + 2 submenus

Docs: update AssetFolderSpec §12 editor tool table with new menu paths

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-20 11:52:17 +08:00

160 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace BaseGames.Editor
{
/// <summary>
/// 一键应用/校验项目推荐的 Script Execution Order。
/// </summary>
public static class ScriptExecutionOrderTools
{
private readonly struct OrderRule
{
public readonly string ClassName;
public readonly int Order;
public OrderRule(string className, int order)
{
ClassName = className;
Order = order;
}
}
private static readonly OrderRule[] Rules =
{
new OrderRule("GameServiceRegistrar", -2000),
new OrderRule("GameManager", -1000),
new OrderRule("SceneService", -900),
new OrderRule("GameSaveManager", -900),
new OrderRule("AudioManager", -500),
new OrderRule("PlayerController", -100),
};
[MenuItem("BaseGames/Tools/Validation/Apply Script Execution Order Preset")]
public static void ApplyPreset()
{
int updated = 0;
int skipped = 0;
var issues = new List<string>();
foreach (var rule in Rules)
{
if (!TryFindMonoScript(rule.ClassName, out MonoScript script, out string issue))
{
skipped++;
issues.Add(issue);
continue;
}
int current = MonoImporter.GetExecutionOrder(script);
if (current == rule.Order)
continue;
MonoImporter.SetExecutionOrder(script, rule.Order);
updated++;
}
AssetDatabase.SaveAssets();
if (issues.Count > 0)
{
Debug.LogWarning(
"[ScriptExecutionOrderTools] 已应用执行顺序预设(部分脚本未处理)。\n" +
$"更新: {updated}, 跳过: {skipped}\n- {string.Join("\n- ", issues)}");
return;
}
Debug.Log($"[ScriptExecutionOrderTools] 执行顺序预设应用完成。更新数量: {updated}。");
}
[MenuItem("BaseGames/Tools/Validation/Validate Script Execution Order Preset")]
public static void ValidatePreset()
{
var mismatches = new List<string>();
var issues = new List<string>();
foreach (var rule in Rules)
{
if (!TryFindMonoScript(rule.ClassName, out MonoScript script, out string issue))
{
issues.Add(issue);
continue;
}
int current = MonoImporter.GetExecutionOrder(script);
if (current != rule.Order)
mismatches.Add($"{rule.ClassName}: 当前 {current}, 期望 {rule.Order}");
}
if (mismatches.Count == 0 && issues.Count == 0)
{
Debug.Log("[ScriptExecutionOrderTools] 执行顺序校验通过,所有脚本均符合预设。");
return;
}
string message = "[ScriptExecutionOrderTools] 执行顺序校验发现问题。";
if (mismatches.Count > 0)
message += "\n顺序不一致:\n- " + string.Join("\n- ", mismatches);
if (issues.Count > 0)
message += "\n脚本解析问题:\n- " + string.Join("\n- ", issues);
Debug.LogWarning(message);
}
/// <summary>
/// 根据 <paramref name="className"/> 查找 MonoScript。
/// <para>当 className 包含 '.'(全限定名)时,用 <c>type.FullName</c> 精确匹配;
/// 否则用 <c>type.Name</c> 匹配(向后兼容简单类名)。</para>
/// </summary>
private static bool TryFindMonoScript(string className, out MonoScript script, out string issue)
{
script = null;
issue = null;
// 全限定名时FindAssets 只取最后一段(简单类名)作为搜索词
bool useFullName = className.Contains('.');
string searchName = useFullName
? className.Substring(className.LastIndexOf('.') + 1)
: className;
string[] guids = AssetDatabase.FindAssets($"{searchName} t:MonoScript");
var matches = new List<MonoScript>();
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
var candidate = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
if (candidate == null)
continue;
Type type = candidate.GetClass();
if (type == null) continue;
bool nameMatch = useFullName
? type.FullName == className
: type.Name == className;
if (nameMatch)
matches.Add(candidate);
}
if (matches.Count == 0)
{
issue = $"未找到脚本: {className}";
return false;
}
if (matches.Count > 1)
{
issue = $"存在多个同名脚本: {className}(请消歧后重试)";
return false;
}
script = matches[0];
return true;
}
}
}