147 lines
6.2 KiB
C#
147 lines
6.2 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text.RegularExpressions;
|
|
using UnityEditor;
|
|
|
|
namespace RunlevelSystems.DevPlus1.EditorTools
|
|
{
|
|
public static class RLScriptAnalyzer
|
|
{
|
|
private static readonly string[] LifecycleMethods =
|
|
{
|
|
"Awake", "OnEnable", "Start", "Update", "FixedUpdate", "LateUpdate",
|
|
"OnDisable", "OnDestroy", "OnTriggerEnter", "OnTriggerExit",
|
|
"OnCollisionEnter", "OnCollisionExit"
|
|
};
|
|
|
|
private static readonly string[] UnityApiMarkers =
|
|
{
|
|
"SceneManager", "Instantiate", "Destroy", "GetComponent",
|
|
"FindObjectOfType", "FindFirstObjectByType", "Resources.Load",
|
|
"Addressables", "Input", "UnityEvent"
|
|
};
|
|
|
|
public static List<RLScriptInfo> AnalyzeScripts()
|
|
{
|
|
List<RLScriptInfo> results = new List<RLScriptInfo>();
|
|
string[] guids = AssetDatabase.FindAssets("t:MonoScript");
|
|
|
|
foreach (string guid in guids)
|
|
{
|
|
string path = AssetDatabase.GUIDToAssetPath(guid);
|
|
if (path.StartsWith("Assets/RL_DevPlus1/Editor/"))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
MonoScript monoScript = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
|
|
if (monoScript == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string text = File.Exists(path) ? File.ReadAllText(path) : string.Empty;
|
|
System.Type scriptClass = monoScript.GetClass();
|
|
RLScriptInfo info = new RLScriptInfo();
|
|
info.scriptPath = path;
|
|
info.className = scriptClass != null ? scriptClass.Name : GuessClassName(text);
|
|
info.baseClass = scriptClass != null && scriptClass.BaseType != null ? scriptClass.BaseType.Name : GuessBaseClass(text);
|
|
info.isMonoBehaviour = scriptClass != null && typeof(UnityEngine.MonoBehaviour).IsAssignableFrom(scriptClass);
|
|
info.isScriptableObject = scriptClass != null && typeof(UnityEngine.ScriptableObject).IsAssignableFrom(scriptClass);
|
|
info.lifecycleMethods.AddRange(FindLifecycleMethods(text));
|
|
info.publicMethods.AddRange(FindPublicMethods(text));
|
|
info.serializedFields.AddRange(FindSerializedFields(text));
|
|
info.publicFields.AddRange(FindPublicFields(text));
|
|
info.unityApiUsage.AddRange(FindUnityApiUsage(text));
|
|
info.possibleRole = GuessRole(path, info);
|
|
results.Add(info);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
private static string GuessClassName(string text)
|
|
{
|
|
Match match = Regex.Match(text, @"class\s+([A-Za-z_][A-Za-z0-9_]*)");
|
|
return match.Success ? match.Groups[1].Value : "not detected";
|
|
}
|
|
|
|
private static string GuessBaseClass(string text)
|
|
{
|
|
Match match = Regex.Match(text, @"class\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*([A-Za-z_][A-Za-z0-9_]*)");
|
|
return match.Success ? match.Groups[1].Value : "not detected";
|
|
}
|
|
|
|
private static List<string> FindLifecycleMethods(string text)
|
|
{
|
|
List<string> results = new List<string>();
|
|
foreach (string method in LifecycleMethods)
|
|
{
|
|
if (Regex.IsMatch(text, @"\b" + method + @"\s*\("))
|
|
{
|
|
results.Add(method);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static List<string> FindPublicMethods(string text)
|
|
{
|
|
return UniqueMatches(text, @"public\s+[A-Za-z_][A-Za-z0-9_<>,\[\]\?]*\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(");
|
|
}
|
|
|
|
private static List<string> FindSerializedFields(string text)
|
|
{
|
|
return UniqueMatches(text, @"\[SerializeField\]\s*(private|protected|public)?\s*[A-Za-z_][A-Za-z0-9_<>,\[\]]*\s+([A-Za-z_][A-Za-z0-9_]*)", 2);
|
|
}
|
|
|
|
private static List<string> FindPublicFields(string text)
|
|
{
|
|
return UniqueMatches(text, @"public\s+[A-Za-z_][A-Za-z0-9_<>,\[\]]*\s+([A-Za-z_][A-Za-z0-9_]*)\s*(=|;)");
|
|
}
|
|
|
|
private static List<string> FindUnityApiUsage(string text)
|
|
{
|
|
List<string> results = new List<string>();
|
|
foreach (string marker in UnityApiMarkers)
|
|
{
|
|
if (text.Contains(marker))
|
|
{
|
|
results.Add(marker);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static List<string> UniqueMatches(string text, string pattern, int group = 1)
|
|
{
|
|
List<string> results = new List<string>();
|
|
foreach (Match match in Regex.Matches(text, pattern))
|
|
{
|
|
string value = match.Groups[group].Value;
|
|
if (!string.IsNullOrEmpty(value) && !results.Contains(value))
|
|
{
|
|
results.Add(value);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static string GuessRole(string path, RLScriptInfo info)
|
|
{
|
|
string value = (path + " " + info.className).ToLowerInvariant();
|
|
if (value.Contains("player")) return "Possible player controller";
|
|
if (value.Contains("enemy") || value.Contains("ai")) return "Possible enemy AI";
|
|
if (value.Contains("ui") || value.Contains("menu") || value.Contains("hud")) return "Possible UI controller";
|
|
if (value.Contains("game") && value.Contains("manager")) return "Possible game manager";
|
|
if (value.Contains("spawner") || value.Contains("spawn")) return "Possible spawner";
|
|
if (value.Contains("inventory")) return "Possible inventory system";
|
|
if (value.Contains("health") || value.Contains("damage")) return "Possible health/damage system";
|
|
if (value.Contains("camera")) return "Possible camera controller";
|
|
if (value.Contains("audio") || value.Contains("music")) return "Possible audio manager";
|
|
if (value.Contains("scene")) return "Possible scene loader";
|
|
if (info.isScriptableObject) return "Possible data/config asset";
|
|
return "Possible utility or gameplay script";
|
|
}
|
|
}
|
|
}
|