77
88public 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