1+ using UnityEngine ;
2+ using UnityEditor ;
3+ using UnityEditor . SceneManagement ;
4+ using System . Collections . Generic ;
5+ using System . Linq ;
6+ using SOBaseEvents ;
7+
8+ public class EventSystemAuditor : EditorWindow
9+ {
10+ private Vector2 _scrollPos ;
11+ 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 > > ( ) ;
16+
17+ private struct UsageDetail
18+ {
19+ public string GameObjectName ;
20+ public string ComponentTypeName ;
21+ public Object Context ; // Para hacer ping al componente exacto
22+ }
23+
24+ [ MenuItem ( "Tools/SO Event System Auditor" ) ]
25+ public static void ShowWindow ( ) => GetWindow < EventSystemAuditor > ( "Event Auditor" ) ;
26+
27+ private void OnEnable ( ) => RefreshEventList ( ) ;
28+
29+ private void OnGUI ( )
30+ {
31+ RenderEventSelector ( ) ;
32+ EditorGUILayout . Space ( 10 ) ;
33+ RenderUsageResults ( ) ;
34+ }
35+
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 ( ) ;
40+
41+ _scrollPos = EditorGUILayout . BeginScrollView ( _scrollPos , GUILayout . Height ( 150 ) ) ;
42+ foreach ( var ev in _allProjectEvents )
43+ {
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+ }
51+ }
52+ GUI . color = Color . white ;
53+ EditorGUILayout . EndScrollView ( ) ;
54+ }
55+
56+ private void RenderUsageResults ( )
57+ {
58+ GUILayout . Label ( "2. Detalle de Referencias Encontradas" , EditorStyles . boldLabel ) ;
59+ if ( _selectedEvent == null ) return ;
60+
61+ if ( _usageResults . Count == 0 )
62+ {
63+ EditorGUILayout . HelpBox ( "No se han encontrado referencias directas en componentes." , MessageType . Info ) ;
64+ return ;
65+ }
66+
67+ foreach ( var entry in _usageResults )
68+ {
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 )
75+ {
76+ EditorGUILayout . BeginHorizontal ( ) ;
77+ GUILayout . Space ( 20 ) ;
78+ if ( GUILayout . Button ( $ "GO: { detail . GameObjectName } | Comp: { detail . ComponentTypeName } ", EditorStyles . label ) )
79+ {
80+ EditorGUIUtility . PingObject ( detail . Context ) ;
81+ }
82+ EditorGUILayout . EndHorizontal ( ) ;
83+ }
84+ EditorGUILayout . EndVertical ( ) ;
85+ EditorGUILayout . Space ( 2 ) ;
86+ }
87+ }
88+
89+ private void RefreshEventList ( )
90+ {
91+ _allProjectEvents . Clear ( ) ;
92+ string [ ] guids = AssetDatabase . FindAssets ( "t:ScriptableObject" ) ;
93+ foreach ( var guid in guids )
94+ {
95+ string path = AssetDatabase . GUIDToAssetPath ( guid ) ;
96+ var so = AssetDatabase . LoadAssetAtPath < ScriptableObject > ( path ) ;
97+ if ( so is ISOEventBase ) _allProjectEvents . Add ( so ) ;
98+ }
99+ }
100+
101+ private void PerformDeepScan ( ScriptableObject targetEvent )
102+ {
103+ _usageResults . Clear ( ) ;
104+ string targetPath = AssetDatabase . GetAssetPath ( targetEvent ) ;
105+ string [ ] potentialAssets = AssetDatabase . FindAssets ( "t:Prefab t:Scene" ) ;
106+
107+ foreach ( var guid in potentialAssets )
108+ {
109+ string path = AssetDatabase . GUIDToAssetPath ( guid ) ;
110+ string [ ] deps = AssetDatabase . GetDependencies ( path ) ;
111+ if ( ! deps . Contains ( targetPath ) ) continue ;
112+
113+ if ( path . EndsWith ( ".prefab" ) )
114+ {
115+ ScanPrefab ( path , targetEvent ) ;
116+ }
117+ else if ( path . EndsWith ( ".unity" ) )
118+ {
119+ ScanScene ( path , targetEvent ) ;
120+ }
121+ }
122+ }
123+
124+ private void ScanPrefab ( string path , ScriptableObject target )
125+ {
126+ GameObject root = AssetDatabase . LoadAssetAtPath < GameObject > ( path ) ;
127+ var components = root . GetComponentsInChildren < Component > ( true ) ;
128+ CheckComponents ( path , components , target ) ;
129+ }
130+
131+ private void ScanScene ( string path , ScriptableObject target )
132+ {
133+ // Nota: Para escenas no abiertas, hay que cargarlas en el editor de forma temporal y silenciosa
134+ SceneAsset sceneAsset = AssetDatabase . LoadAssetAtPath < SceneAsset > ( path ) ;
135+ var tempScene = EditorSceneManager . OpenScene ( path , OpenSceneMode . Additive ) ;
136+
137+ var allComponents = Resources . FindObjectsOfTypeAll < Component > ( )
138+ . Where ( c => c . gameObject . scene == tempScene ) ;
139+
140+ CheckComponents ( path , allComponents , target ) ;
141+
142+ EditorSceneManager . CloseScene ( tempScene , true ) ;
143+ }
144+
145+ private void CheckComponents ( string assetPath , IEnumerable < Component > components , ScriptableObject target )
146+ {
147+ foreach ( var comp in components )
148+ {
149+ 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
153+ SerializedObject so = new SerializedObject ( comp ) ;
154+ SerializedProperty prop = so . GetIterator ( ) ;
155+
156+ while ( prop . NextVisible ( true ) )
157+ {
158+ if ( prop . propertyType == SerializedPropertyType . ObjectReference && prop . objectReferenceValue == target )
159+ {
160+ if ( ! _usageResults . ContainsKey ( assetPath ) ) _usageResults [ assetPath ] = new List < UsageDetail > ( ) ;
161+
162+ _usageResults [ assetPath ] . Add ( new UsageDetail {
163+ GameObjectName = comp . gameObject . name ,
164+ ComponentTypeName = comp . GetType ( ) . Name ,
165+ Context = comp
166+ } ) ;
167+ break ;
168+ }
169+ }
170+ }
171+ }
172+ }
0 commit comments