using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace BaseGames.Editor
{
///
/// 一键应用/校验项目推荐的 Script Execution Order。
///
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();
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();
var issues = new List();
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);
}
///
/// 根据 查找 MonoScript。
/// 当 className 包含 '.'(全限定名)时,用 type.FullName 精确匹配;
/// 否则用 type.Name 匹配(向后兼容简单类名)。
///
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();
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
var candidate = AssetDatabase.LoadAssetAtPath(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;
}
}
}