Skip to content

Commit 0a3bc4f

Browse files
committed
SO Events Auditor tool code review
1 parent a3b8093 commit 0a3bc4f

1 file changed

Lines changed: 158 additions & 76 deletions

File tree

Editor/MappingTool/EventSystemAuditor.cs

Lines changed: 158 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77

88
public class EventSystemAuditor : EditorWindow
99
{
10+
private const string PrefabExtension = ".prefab";
11+
private const string SceneExtension = ".unity";
12+
1013
private Vector2 _scrollPos;
1114
private List<ScriptableObject> _allProjectEvents = new List<ScriptableObject>();
12-
13-
// State management for UI expansion
14-
private Dictionary<ScriptableObject, bool> _expansionStates = new Dictionary<ScriptableObject, bool>();
15-
16-
// Master data: Event -> Asset Path -> List of specific usages
15+
private Dictionary<ScriptableObject, bool> _expandedStates = new Dictionary<ScriptableObject, bool>();
1716
private Dictionary<ScriptableObject, Dictionary<string, List<UsageDetail>>> _masterResults =
1817
new Dictionary<ScriptableObject, Dictionary<string, List<UsageDetail>>>();
18+
private GUIStyle _headerStyle;
1919

2020
private struct UsageDetail
2121
{
@@ -24,85 +24,105 @@ private struct UsageDetail
2424
public Object Context; // Reference to ping the specific component
2525
}
2626

27-
[MenuItem("Tools/SO Event System Auditor")]
28-
public static void ShowWindow() => GetWindow<EventSystemAuditor>("Event Auditor");
27+
[MenuItem("EspidiGames/SO Events/SO Event System Auditor")]
28+
public static void ShowWindow()
29+
{
30+
GetWindow<EventSystemAuditor>("Event Auditor");
31+
}
2932

30-
private void OnEnable() => RefreshAndScanAll();
33+
private void OnEnable()
34+
{
35+
GetWindow<EventSystemAuditor>("Event Auditor");
36+
RefreshAndScanAll();
37+
}
3138

3239
private void OnGUI()
3340
{
34-
// --- TOP TOOLBAR ---
41+
RenderTopToolBar();
42+
RenderResultsSection();
43+
}
44+
45+
private void RenderTopToolBar()
46+
{
3547
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
36-
if (GUILayout.Button("Refresh & Scan Project", EditorStyles.toolbarButton)) RefreshAndScanAll();
48+
49+
if (GUILayout.Button("Refresh & Scan Project", EditorStyles.toolbarButton))
50+
{
51+
RefreshAndScanAll();
52+
}
53+
3754
GUILayout.FlexibleSpace();
55+
56+
if (GUILayout.Button("Expand All", EditorStyles.toolbarButton))
57+
{
58+
SetEventUsagesExpandedState(true);
59+
}
60+
61+
if (GUILayout.Button("Collapse All", EditorStyles.toolbarButton))
62+
{
63+
SetEventUsagesExpandedState(false);
64+
}
3865

39-
if (GUILayout.Button("Expand All", EditorStyles.toolbarButton)) SetAllExpansion(true);
40-
if (GUILayout.Button("Collapse All", EditorStyles.toolbarButton)) SetAllExpansion(false);
4166
EditorGUILayout.EndHorizontal();
67+
}
4268

69+
private void RenderResultsSection()
70+
{
4371
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos);
4472

4573
if (_allProjectEvents.Count == 0)
4674
{
47-
EditorGUILayout.HelpBox("No ScriptableObjects implementing ISOEventBase were found in the project.", MessageType.Info);
75+
EditorGUILayout.HelpBox("No ScriptableObjects implementing ISOEventBase were found in the project.",
76+
MessageType.Info);
4877
}
4978

50-
foreach (var ev in _allProjectEvents)
79+
foreach (var soEvent in _allProjectEvents)
5180
{
52-
RenderEventGroup(ev);
81+
RenderSOEventsUsages(soEvent);
5382
}
5483

5584
EditorGUILayout.EndScrollView();
5685
}
57-
58-
private void RenderEventGroup(ScriptableObject ev)
86+
87+
private void RenderSOEventsUsages(ScriptableObject soEvent)
5988
{
6089
// Default to expanded if state not found
61-
if (!_expansionStates.ContainsKey(ev)) _expansionStates[ev] = true;
62-
bool expanded = _expansionStates[ev];
63-
64-
// Custom Header Style
65-
GUIStyle headerStyle = new GUIStyle(EditorStyles.miniButtonMid);
66-
headerStyle.alignment = TextAnchor.MiddleLeft;
67-
headerStyle.fontStyle = FontStyle.Bold;
68-
headerStyle.fontSize = 11;
69-
headerStyle.fixedHeight = 25;
90+
if (!_expandedStates.ContainsKey(soEvent))
91+
{
92+
_expandedStates[soEvent] = true;
93+
}
94+
95+
var expanded = _expandedStates[soEvent];
96+
_headerStyle ??= CreateHeaderStyle();
7097

7198
// Visual Feedback: Highlight background if expanded
72-
if (expanded) GUI.backgroundColor = new Color(0.8f, 0.9f, 1f);
99+
if (expanded)
100+
{
101+
GUI.backgroundColor = new Color(0.8f, 0.9f, 1f);
102+
}
73103

74104
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
75105

76-
// Toggle Button
77-
string arrow = expanded ? "▼" : "▶";
78-
if (GUILayout.Button($" {arrow} {ev.name.ToUpper()} [{ev.GetType().Name}]", headerStyle))
79-
{
80-
_expansionStates[ev] = !expanded;
81-
}
106+
RenderScriptableObjectEventEntryHeaderToggle(soEvent, expanded);
82107
GUI.backgroundColor = Color.white;
83108

84109
if (expanded)
85110
{
86111
EditorGUILayout.Space(2);
87-
if (_masterResults.ContainsKey(ev) && _masterResults[ev].Count > 0)
112+
if (_masterResults.ContainsKey(soEvent) && _masterResults[soEvent].Count > 0)
88113
{
89-
foreach (var assetEntry in _masterResults[ev])
114+
foreach (var assetEntry in _masterResults[soEvent])
90115
{
91116
// Group by Asset (Prefab/Scene)
92117
EditorGUILayout.BeginVertical(EditorStyles.textArea);
118+
93119
GUILayout.Label($"📂 {System.IO.Path.GetFileName(assetEntry.Key)}", EditorStyles.boldLabel);
94120

95121
foreach (var detail in assetEntry.Value)
96122
{
97-
EditorGUILayout.BeginHorizontal();
98-
GUILayout.Space(15);
99-
// Deep link to component
100-
if (GUILayout.Button($" # GO: {detail.GameObjectName} ({detail.ComponentTypeName})", EditorStyles.label))
101-
{
102-
EditorGUIUtility.PingObject(detail.Context);
103-
}
104-
EditorGUILayout.EndHorizontal();
123+
RenderSOEventUsage(detail);
105124
}
125+
106126
EditorGUILayout.EndVertical();
107127
EditorGUILayout.Space(1);
108128
}
@@ -117,55 +137,110 @@ private void RenderEventGroup(ScriptableObject ev)
117137
EditorGUILayout.Space(2);
118138
}
119139

120-
private void SetAllExpansion(bool state)
140+
private static GUIStyle CreateHeaderStyle()
121141
{
122-
var keys = _expansionStates.Keys.ToList();
123-
foreach (var key in keys) _expansionStates[key] = state;
142+
var headerStyle = new GUIStyle(EditorStyles.miniButtonMid);
143+
headerStyle.alignment = TextAnchor.MiddleLeft;
144+
headerStyle.fontStyle = FontStyle.Bold;
145+
headerStyle.fontSize = 11;
146+
headerStyle.fixedHeight = 25;
147+
148+
return headerStyle;
149+
}
150+
151+
private void RenderScriptableObjectEventEntryHeaderToggle(ScriptableObject soEvent, bool expanded)
152+
{
153+
var arrow = expanded ? "▼" : "▶";
154+
if (GUILayout.Button($" {arrow} {soEvent.name.ToUpper()} [{soEvent.GetType().Name}]", _headerStyle))
155+
{
156+
_expandedStates[soEvent] = !expanded;
157+
}
158+
}
159+
160+
private static void RenderSOEventUsage(UsageDetail detail)
161+
{
162+
EditorGUILayout.BeginHorizontal();
163+
GUILayout.Space(15);
164+
// Deep link to component
165+
if (GUILayout.Button($" # GO: {detail.GameObjectName} ({detail.ComponentTypeName})", EditorStyles.label))
166+
{
167+
EditorGUIUtility.PingObject(detail.Context);
168+
}
169+
EditorGUILayout.EndHorizontal();
124170
}
125171

126-
// --- SCAN LOGIC ---
172+
private void SetEventUsagesExpandedState(bool expand)
173+
{
174+
var keys = _expandedStates.Keys.ToList();
175+
176+
foreach (var key in keys)
177+
{
178+
_expandedStates[key] = expand;
179+
}
180+
}
127181

182+
#region === Asset scanning logic ===
183+
128184
private void RefreshAndScanAll()
129185
{
130186
_allProjectEvents.Clear();
131187
_masterResults.Clear();
188+
189+
FindAllScriptableObjectEventAssets();
190+
ScanDependencies();
191+
}
192+
193+
private void FindAllScriptableObjectEventAssets()
194+
{
195+
var guids = AssetDatabase.FindAssets("t:ScriptableObject");
132196

133-
// 1. Find all relevant SOs in project
134-
string[] guids = AssetDatabase.FindAssets("t:ScriptableObject");
135197
foreach (var guid in guids)
136198
{
137-
string path = AssetDatabase.GUIDToAssetPath(guid);
138-
var so = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
139-
if (so is ISOEventBase)
199+
var path = AssetDatabase.GUIDToAssetPath(guid);
200+
var scriptableObjectAsset = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
201+
202+
if (scriptableObjectAsset is ISOEventBase)
140203
{
141-
_allProjectEvents.Add(so);
142-
_masterResults[so] = new Dictionary<string, List<UsageDetail>>();
143-
if (!_expansionStates.ContainsKey(so)) _expansionStates[so] = true;
204+
_allProjectEvents.Add(scriptableObjectAsset);
205+
_masterResults[scriptableObjectAsset] = new Dictionary<string, List<UsageDetail>>();
206+
if (!_expandedStates.ContainsKey(scriptableObjectAsset))
207+
{
208+
_expandedStates[scriptableObjectAsset] = true;
209+
}
144210
}
145211
}
212+
}
146213

147-
// 2. Perform deep dependency scan
148-
string[] potentialAssets = AssetDatabase.FindAssets("t:Prefab t:Scene");
214+
private void ScanDependencies()
215+
{
216+
var potentialAssets = AssetDatabase.FindAssets("t:Prefab t:Scene");
149217
foreach (var guid in potentialAssets)
150218
{
151-
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
152-
string[] deps = AssetDatabase.GetDependencies(assetPath);
219+
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
220+
var dependencies = AssetDatabase.GetDependencies(assetPath);
153221

154-
foreach (var ev in _allProjectEvents)
222+
foreach (var soEvent in _allProjectEvents)
155223
{
156-
if (deps.Contains(AssetDatabase.GetAssetPath(ev)))
224+
if (dependencies.Contains(AssetDatabase.GetAssetPath(soEvent)))
157225
{
158-
if (assetPath.EndsWith(".prefab")) ScanPrefab(assetPath, ev);
159-
else if (assetPath.EndsWith(".unity")) ScanScene(assetPath, ev);
226+
if (assetPath.EndsWith(PrefabExtension))
227+
{
228+
ScanPrefab(assetPath, soEvent);
229+
}
230+
else if (assetPath.EndsWith(SceneExtension))
231+
{
232+
ScanScene(assetPath, soEvent);
233+
}
160234
}
161235
}
162236
}
163237
}
164-
238+
165239
private void ScanPrefab(string path, ScriptableObject target)
166240
{
167-
GameObject root = AssetDatabase.LoadAssetAtPath<GameObject>(path);
168-
CheckComponents(path, root.GetComponentsInChildren<Component>(true), target);
241+
var root = AssetDatabase.LoadAssetAtPath<GameObject>(path);
242+
var allComponents = root.GetComponentsInChildren<Component>(true);
243+
CheckComponents(path, allComponents, target);
169244
}
170245

171246
private void ScanScene(string path, ScriptableObject target)
@@ -179,29 +254,36 @@ private void ScanScene(string path, ScriptableObject target)
179254

180255
private void CheckComponents(string assetPath, IEnumerable<Component> components, ScriptableObject target)
181256
{
182-
foreach (var comp in components)
257+
foreach (var component in components)
183258
{
184-
if (comp == null) continue;
259+
if (component == null)
260+
{
261+
continue;
262+
}
185263

186264
// Iterate through all serialized properties to find the SO reference
187-
SerializedObject so = new SerializedObject(comp);
188-
SerializedProperty prop = so.GetIterator();
265+
var serializedObject = new SerializedObject(component);
266+
var property = serializedObject.GetIterator();
189267

190-
while (prop.NextVisible(true))
268+
while (property.NextVisible(true))
191269
{
192-
if (prop.propertyType == SerializedPropertyType.ObjectReference && prop.objectReferenceValue == target)
270+
if (property.propertyType == SerializedPropertyType.ObjectReference && property.objectReferenceValue == target)
193271
{
194-
if (!_masterResults[target].ContainsKey(assetPath))
272+
if (!_masterResults[target].ContainsKey(assetPath))
273+
{
195274
_masterResults[target][assetPath] = new List<UsageDetail>();
275+
}
196276

197277
_masterResults[target][assetPath].Add(new UsageDetail {
198-
GameObjectName = comp.gameObject.name,
199-
ComponentTypeName = comp.GetType().Name,
200-
Context = comp
278+
GameObjectName = component.gameObject.name,
279+
ComponentTypeName = component.GetType().Name,
280+
Context = component
201281
});
202282
break;
203283
}
204284
}
205285
}
206286
}
287+
288+
#endregion
207289
}

0 commit comments

Comments
 (0)