@@ -9,136 +9,161 @@ public class EventSystemAuditor : EditorWindow
99{
1010 private Vector2 _scrollPos ;
1111 private List < ScriptableObject > _allProjectEvents = new List < ScriptableObject > ( ) ;
12- private ScriptableObject _selectedEvent ;
13-
14- // Diccionario para guardar: Ruta del Asset -> Lista de detalles (GameObject + Componente)
15- private Dictionary < string , List < UsageDetail > > _usageResults = new Dictionary < string , List < UsageDetail > > ( ) ;
12+ private Dictionary < ScriptableObject , bool > _expansionStates = new Dictionary < ScriptableObject , bool > ( ) ;
13+ private Dictionary < ScriptableObject , Dictionary < string , List < UsageDetail > > > _masterResults = new Dictionary < ScriptableObject , Dictionary < string , List < UsageDetail > > > ( ) ;
1614
1715 private struct UsageDetail
1816 {
1917 public string GameObjectName ;
2018 public string ComponentTypeName ;
21- public Object Context ; // Para hacer ping al componente exacto
19+ public Object Context ;
2220 }
23-
24- [ MenuItem ( "EspidiGames/SO Events /SO Event System Auditor" ) ]
21+
22+ [ MenuItem ( "Tools /SO Event System Auditor" ) ]
2523 public static void ShowWindow ( ) => GetWindow < EventSystemAuditor > ( "Event Auditor" ) ;
2624
27- private void OnEnable ( ) => RefreshEventList ( ) ;
25+ private void OnEnable ( ) => RefreshAndScanAll ( ) ;
2826
2927 private void OnGUI ( )
3028 {
31- RenderEventSelector ( ) ;
32- EditorGUILayout . Space ( 10 ) ;
33- RenderUsageResults ( ) ;
34- }
29+ // --- TOOLBAR SUPERIOR ---
30+ EditorGUILayout . BeginHorizontal ( EditorStyles . toolbar ) ;
31+ if ( GUILayout . Button ( "Refrescar y Escanear Proyecto" , EditorStyles . toolbarButton ) ) RefreshAndScanAll ( ) ;
32+ GUILayout . FlexibleSpace ( ) ;
33+
34+ if ( GUILayout . Button ( "Expandir Todo" , EditorStyles . toolbarButton ) ) SetAllExpansion ( true ) ;
35+ if ( GUILayout . Button ( "Colapsar Todo" , EditorStyles . toolbarButton ) ) SetAllExpansion ( false ) ;
36+ EditorGUILayout . EndHorizontal ( ) ;
3537
36- private void RenderEventSelector ( )
37- {
38- GUILayout . Label ( "1. Selección de Evento (ISOEventBase)" , EditorStyles . boldLabel ) ;
39- if ( GUILayout . Button ( "Refrescar Lista de Proyecto" ) ) RefreshEventList ( ) ;
38+ _scrollPos = EditorGUILayout . BeginScrollView ( _scrollPos ) ;
39+
40+ if ( _allProjectEvents . Count == 0 )
41+ {
42+ EditorGUILayout . HelpBox ( "No se encontraron eventos que implementen ISOEventBase." , MessageType . Info ) ;
43+ }
4044
41- _scrollPos = EditorGUILayout . BeginScrollView ( _scrollPos , GUILayout . Height ( 150 ) ) ;
4245 foreach ( var ev in _allProjectEvents )
4346 {
44- bool isSelected = ( _selectedEvent == ev ) ;
45- GUI . color = isSelected ? Color . cyan : Color . white ;
46- if ( GUILayout . Button ( $ "{ ev . name } ({ ev . GetType ( ) . Name } )", EditorStyles . miniButton ) )
47- {
48- _selectedEvent = ev ;
49- PerformDeepScan ( ev ) ;
50- }
47+ RenderEventGroup ( ev ) ;
5148 }
52- GUI . color = Color . white ;
49+
5350 EditorGUILayout . EndScrollView ( ) ;
5451 }
5552
56- private void RenderUsageResults ( )
53+ private void RenderEventGroup ( ScriptableObject ev )
5754 {
58- GUILayout . Label ( "2. Detalle de Referencias Encontradas" , EditorStyles . boldLabel ) ;
59- if ( _selectedEvent == null ) return ;
55+ if ( ! _expansionStates . ContainsKey ( ev ) ) _expansionStates [ ev ] = true ;
56+ bool expanded = _expansionStates [ ev ] ;
6057
61- if ( _usageResults . Count == 0 )
58+ // Definimos un estilo que cambie visualmente si está expandido
59+ GUIStyle headerStyle = new GUIStyle ( EditorStyles . miniButtonMid ) ;
60+ headerStyle . alignment = TextAnchor . MiddleLeft ;
61+ headerStyle . fontStyle = FontStyle . Bold ;
62+ headerStyle . fontSize = 11 ;
63+ headerStyle . fixedHeight = 25 ;
64+
65+ // Feedback visual: Si está expandido, resaltamos el botón
66+ if ( expanded ) GUI . backgroundColor = new Color ( 0.8f , 0.9f , 1f ) ;
67+
68+ EditorGUILayout . BeginVertical ( EditorStyles . helpBox ) ;
69+
70+ // El icono de flecha (foldout) ayuda a entender que es colapsable
71+ string arrow = expanded ? "▼" : "▶" ;
72+ if ( GUILayout . Button ( $ " { arrow } { ev . name . ToUpper ( ) } [{ ev . GetType ( ) . Name } ]", headerStyle ) )
6273 {
63- EditorGUILayout . HelpBox ( "No se han encontrado referencias directas en componentes." , MessageType . Info ) ;
64- return ;
74+ _expansionStates [ ev ] = ! expanded ;
6575 }
76+ GUI . backgroundColor = Color . white ;
6677
67- foreach ( var entry in _usageResults )
78+ if ( expanded )
6879 {
69- EditorGUILayout . BeginVertical ( "helpbox" ) ;
70-
71- // Título: Nombre del Prefab o Escena
72- GUILayout . Label ( System . IO . Path . GetFileName ( entry . Key ) , EditorStyles . whiteLargeLabel ) ;
73-
74- foreach ( var detail in entry . Value )
80+ EditorGUILayout . Space ( 2 ) ;
81+ if ( _masterResults . ContainsKey ( ev ) && _masterResults [ ev ] . Count > 0 )
7582 {
76- EditorGUILayout . BeginHorizontal ( ) ;
77- GUILayout . Space ( 20 ) ;
78- if ( GUILayout . Button ( $ "GO: { detail . GameObjectName } | Comp: { detail . ComponentTypeName } ", EditorStyles . label ) )
83+ foreach ( var assetEntry in _masterResults [ ev ] )
7984 {
80- EditorGUIUtility . PingObject ( detail . Context ) ;
85+ // Contenedor para cada Prefab/Escena
86+ EditorGUILayout . BeginVertical ( EditorStyles . textArea ) ;
87+ GUILayout . Label ( $ "📂 { System . IO . Path . GetFileName ( assetEntry . Key ) } ", EditorStyles . boldLabel ) ;
88+
89+ foreach ( var detail in assetEntry . Value )
90+ {
91+ EditorGUILayout . BeginHorizontal ( ) ;
92+ GUILayout . Space ( 15 ) ;
93+ // El botón de cada componente para hacer ping
94+ if ( GUILayout . Button ( $ " # GO: { detail . GameObjectName } ({ detail . ComponentTypeName } )", EditorStyles . label ) )
95+ {
96+ EditorGUIUtility . PingObject ( detail . Context ) ;
97+ }
98+ EditorGUILayout . EndHorizontal ( ) ;
99+ }
100+ EditorGUILayout . EndVertical ( ) ;
101+ EditorGUILayout . Space ( 1 ) ;
81102 }
82- EditorGUILayout . EndHorizontal ( ) ;
83103 }
84- EditorGUILayout . EndVertical ( ) ;
85- EditorGUILayout . Space ( 2 ) ;
104+ else
105+ {
106+ EditorGUILayout . LabelField ( " No se detectaron usos en el proyecto." , EditorStyles . centeredGreyMiniLabel ) ;
107+ }
86108 }
109+
110+ EditorGUILayout . EndVertical ( ) ;
111+ EditorGUILayout . Space ( 2 ) ;
87112 }
88113
89- private void RefreshEventList ( )
114+ private void SetAllExpansion ( bool state )
115+ {
116+ var keys = _expansionStates . Keys . ToList ( ) ;
117+ foreach ( var key in keys ) _expansionStates [ key ] = state ;
118+ }
119+
120+ // --- LÓGICA DE ESCANEO (Sin cambios significativos para mantener la funcionalidad) ---
121+ private void RefreshAndScanAll ( )
90122 {
91123 _allProjectEvents . Clear ( ) ;
124+ _masterResults . Clear ( ) ;
125+
92126 string [ ] guids = AssetDatabase . FindAssets ( "t:ScriptableObject" ) ;
93127 foreach ( var guid in guids )
94128 {
95129 string path = AssetDatabase . GUIDToAssetPath ( guid ) ;
96130 var so = AssetDatabase . LoadAssetAtPath < ScriptableObject > ( path ) ;
97- if ( so is ISOEventBase ) _allProjectEvents . Add ( so ) ;
131+ if ( so is ISOEventBase ) //
132+ {
133+ _allProjectEvents . Add ( so ) ;
134+ _masterResults [ so ] = new Dictionary < string , List < UsageDetail > > ( ) ;
135+ if ( ! _expansionStates . ContainsKey ( so ) ) _expansionStates [ so ] = true ; // Expandido por defecto
136+ }
98137 }
99- }
100138
101- private void PerformDeepScan ( ScriptableObject targetEvent )
102- {
103- _usageResults . Clear ( ) ;
104- string targetPath = AssetDatabase . GetAssetPath ( targetEvent ) ;
105139 string [ ] potentialAssets = AssetDatabase . FindAssets ( "t:Prefab t:Scene" ) ;
106-
107140 foreach ( var guid in potentialAssets )
108141 {
109- string path = AssetDatabase . GUIDToAssetPath ( guid ) ;
110- string [ ] deps = AssetDatabase . GetDependencies ( path ) ;
111- if ( ! deps . Contains ( targetPath ) ) continue ;
142+ string assetPath = AssetDatabase . GUIDToAssetPath ( guid ) ;
143+ string [ ] deps = AssetDatabase . GetDependencies ( assetPath ) ;
112144
113- if ( path . EndsWith ( ".prefab" ) )
114- {
115- ScanPrefab ( path , targetEvent ) ;
116- }
117- else if ( path . EndsWith ( ".unity" ) )
145+ foreach ( var ev in _allProjectEvents )
118146 {
119- ScanScene ( path , targetEvent ) ;
147+ if ( deps . Contains ( AssetDatabase . GetAssetPath ( ev ) ) )
148+ {
149+ if ( assetPath . EndsWith ( ".prefab" ) ) ScanPrefab ( assetPath , ev ) ;
150+ else if ( assetPath . EndsWith ( ".unity" ) ) ScanScene ( assetPath , ev ) ;
151+ }
120152 }
121153 }
122154 }
123155
124156 private void ScanPrefab ( string path , ScriptableObject target )
125157 {
126158 GameObject root = AssetDatabase . LoadAssetAtPath < GameObject > ( path ) ;
127- var components = root . GetComponentsInChildren < Component > ( true ) ;
128- CheckComponents ( path , components , target ) ;
159+ CheckComponents ( path , root . GetComponentsInChildren < Component > ( true ) , target ) ;
129160 }
130161
131162 private void ScanScene ( string path , ScriptableObject target )
132163 {
133- // Nota: Para escenas no abiertas, hay que cargarlas en el editor de forma temporal y silenciosa
134- SceneAsset sceneAsset = AssetDatabase . LoadAssetAtPath < SceneAsset > ( path ) ;
135164 var tempScene = EditorSceneManager . OpenScene ( path , OpenSceneMode . Additive ) ;
136-
137- var allComponents = Resources . FindObjectsOfTypeAll < Component > ( )
138- . Where ( c => c . gameObject . scene == tempScene ) ;
139-
165+ var allComponents = Resources . FindObjectsOfTypeAll < Component > ( ) . Where ( c => c . gameObject . scene == tempScene ) ;
140166 CheckComponents ( path , allComponents , target ) ;
141-
142167 EditorSceneManager . CloseScene ( tempScene , true ) ;
143168 }
144169
@@ -147,24 +172,22 @@ private void CheckComponents(string assetPath, IEnumerable<Component> components
147172 foreach ( var comp in components )
148173 {
149174 if ( comp == null ) continue ;
150-
151- // Usamos SerializedObject para iterar por todas las propiedades del componente
152- // Esto detecta el evento incluso si está en un script personalizado que no sea un EventListener
153175 SerializedObject so = new SerializedObject ( comp ) ;
154176 SerializedProperty prop = so . GetIterator ( ) ;
155177
156178 while ( prop . NextVisible ( true ) )
157179 {
158180 if ( prop . propertyType == SerializedPropertyType . ObjectReference && prop . objectReferenceValue == target )
159181 {
160- if ( ! _usageResults . ContainsKey ( assetPath ) ) _usageResults [ assetPath ] = new List < UsageDetail > ( ) ;
182+ if ( ! _masterResults [ target ] . ContainsKey ( assetPath ) )
183+ _masterResults [ target ] [ assetPath ] = new List < UsageDetail > ( ) ;
161184
162- _usageResults [ assetPath ] . Add ( new UsageDetail {
185+ _masterResults [ target ] [ assetPath ] . Add ( new UsageDetail {
163186 GameObjectName = comp . gameObject . name ,
164187 ComponentTypeName = comp . GetType ( ) . Name ,
165188 Context = comp
166189 } ) ;
167- break ;
190+ break ;
168191 }
169192 }
170193 }
0 commit comments