fr.jeanf.eventsystem 0.1.126 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.attestation.p7m +0 -0
- package/Documentation~/images/.gitkeep +0 -0
- package/Documentation~/images/debugger-channels.png +0 -0
- package/Documentation~/images/debugger-eventlog.png +0 -0
- package/Editor/EventSystemDebuggerWindow.cs +562 -0
- package/Editor/EventSystemDebuggerWindow.cs.meta +2 -0
- package/Editor/jeanf.eventsystem.editor.asmdef +18 -0
- package/Editor/jeanf.eventsystem.editor.asmdef.meta +7 -0
- package/Editor.meta +8 -0
- package/README.md +122 -10
- package/Runtime/BaseClasses/CanonicalChannelResolver.cs +60 -0
- package/Runtime/BaseClasses/CanonicalChannelResolver.cs.meta +11 -0
- package/Runtime/Diagnostics/EventDiagnostics.cs +395 -0
- package/Runtime/Diagnostics/EventDiagnostics.cs.meta +2 -0
- package/Runtime/Diagnostics.meta +8 -0
- package/Runtime/PingSystem/PingableScriptableObject.cs +3 -3
- package/Runtime/ScriptableObjects/ActionRebindEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/DecimalBoolEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/DecimalDecimalEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/DecimalFloatEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/DecimalGameObjectEventChannelSO.cs +11 -4
- package/Runtime/ScriptableObjects/Advanced/DecimalIntEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/DecimalStringEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/InputActionIntEventChannelSO.cs +10 -4
- package/Runtime/ScriptableObjects/Advanced/IntBoolEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/IntEnumEventChannelSO.cs +10 -4
- package/Runtime/ScriptableObjects/Advanced/IntFloatEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/IntGameObjectEventChannelSO.cs +11 -4
- package/Runtime/ScriptableObjects/Advanced/IntIntEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/IntStringEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/StringBoolEventChannelSO.cs +10 -4
- package/Runtime/ScriptableObjects/Advanced/StringFloatEventChannelSO.cs +13 -6
- package/Runtime/ScriptableObjects/Advanced/StringStringtEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/Advanced/TimelineTriggerEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/BoolEventChannelSO.cs +13 -5
- package/Runtime/ScriptableObjects/BoolFloatEventChannelSO.cs +10 -4
- package/Runtime/ScriptableObjects/DecimalEventChannelSO.cs +13 -7
- package/Runtime/ScriptableObjects/FloatEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/GameObjectEventChannelSO.cs +10 -2
- package/Runtime/ScriptableObjects/GameObjectIntBoolEventChannelSO.cs +10 -7
- package/Runtime/ScriptableObjects/InputActionEventChannelSO.cs +10 -5
- package/Runtime/ScriptableObjects/IntEventChannelSO.cs +12 -5
- package/Runtime/ScriptableObjects/QuaternionEventChannelSO.cs +10 -7
- package/Runtime/ScriptableObjects/ScriptableObjectEventChannelSO.cs +19 -5
- package/Runtime/ScriptableObjects/StringEventChannelSO.cs +15 -4
- package/Runtime/ScriptableObjects/StringListEventChannelSO.cs +10 -5
- package/Runtime/ScriptableObjects/TeleportEventChannelSO.cs +12 -4
- package/Runtime/ScriptableObjects/TransformEventChannelSO.cs +12 -4
- package/Runtime/ScriptableObjects/Vector2EventChannelSO.cs +10 -7
- package/Runtime/ScriptableObjects/Vector3EventChannelSO.cs +10 -7
- package/Runtime/ScriptableObjects/VoidEventChannelSO.cs +10 -3
- package/Runtime/SenderInterfaces/Advanced/DecimalBoolEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/DecimalDecimalEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/DecimalFloatEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/DecimalGameObjectEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/DecimalIntEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/DecimalStringEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/IntBoolEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/IntEnumEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/IntFloatEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/IntGameObjectEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/IntIntEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/IntStringEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/StringBoolEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/StringFloatEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/Advanced/StringStringEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/BoolEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/DecimalEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/FloatEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/GameObjectEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/IEventPublisher.cs +19 -0
- package/Runtime/SenderInterfaces/IEventPublisher.cs.meta +2 -0
- package/Runtime/SenderInterfaces/IInputActionIntEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/IntEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/ScriptableObjectEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/StringEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/StringListEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/TimelineBoolEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/TransformEventSender.cs +3 -2
- package/Runtime/SenderInterfaces/VoidEventSender.cs +3 -2
- package/package.json +2 -2
package/.attestation.p7m
CHANGED
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Reflection;
|
|
4
|
+
using System.Runtime.CompilerServices;
|
|
5
|
+
using UnityEditor;
|
|
6
|
+
using UnityEngine;
|
|
7
|
+
using Object = UnityEngine.Object;
|
|
8
|
+
|
|
9
|
+
namespace jeanf.EventSystem.EditorTools
|
|
10
|
+
{
|
|
11
|
+
public class EventSystemDebuggerWindow : EditorWindow
|
|
12
|
+
{
|
|
13
|
+
public const string PrefAutoSender = "jeanf.evtdbg.autoSender";
|
|
14
|
+
public const string PrefAutoReceiver = "jeanf.evtdbg.autoReceiver";
|
|
15
|
+
|
|
16
|
+
enum Tab { Channels, EventLog }
|
|
17
|
+
|
|
18
|
+
Tab _tab = Tab.Channels;
|
|
19
|
+
Vector2 _channelScroll;
|
|
20
|
+
Vector2 _logScroll;
|
|
21
|
+
string _channelSearch = "";
|
|
22
|
+
string _logSearch = "";
|
|
23
|
+
bool _duplicatesOnly;
|
|
24
|
+
readonly HashSet<int> _expanded = new HashSet<int>();
|
|
25
|
+
|
|
26
|
+
EventDiagnostics.RaiseRecord[] _logBuffer = new EventDiagnostics.RaiseRecord[EventDiagnostics.BufferCapacity];
|
|
27
|
+
int _logCount;
|
|
28
|
+
|
|
29
|
+
readonly Dictionary<string, List<Component>> _senderScan = new Dictionary<string, List<Component>>();
|
|
30
|
+
double _nextScan;
|
|
31
|
+
|
|
32
|
+
const BindingFlags FieldFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
|
|
33
|
+
|
|
34
|
+
[MenuItem("Window/jeanf/Event System Debugger")]
|
|
35
|
+
static void Open()
|
|
36
|
+
{
|
|
37
|
+
var w = GetWindow<EventSystemDebuggerWindow>();
|
|
38
|
+
w.titleContent = new GUIContent("Event Debugger");
|
|
39
|
+
w.minSize = new Vector2(540, 320);
|
|
40
|
+
w.Show();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void OnEnable()
|
|
44
|
+
{
|
|
45
|
+
EditorApplication.update += OnEditorUpdate;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void OnDisable()
|
|
49
|
+
{
|
|
50
|
+
EditorApplication.update -= OnEditorUpdate;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
double _nextRepaint;
|
|
54
|
+
|
|
55
|
+
void OnEditorUpdate()
|
|
56
|
+
{
|
|
57
|
+
if (!EditorApplication.isPlaying) return;
|
|
58
|
+
if (EditorApplication.timeSinceStartup >= _nextScan)
|
|
59
|
+
{
|
|
60
|
+
_nextScan = EditorApplication.timeSinceStartup + 1.0;
|
|
61
|
+
RebuildSenderScan();
|
|
62
|
+
}
|
|
63
|
+
if (EditorApplication.timeSinceStartup < _nextRepaint) return;
|
|
64
|
+
_nextRepaint = EditorApplication.timeSinceStartup + 0.2;
|
|
65
|
+
Repaint();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void RebuildSenderScan()
|
|
69
|
+
{
|
|
70
|
+
_senderScan.Clear();
|
|
71
|
+
var comps = Object.FindObjectsOfType<MonoBehaviour>(true);
|
|
72
|
+
foreach (var comp in comps)
|
|
73
|
+
{
|
|
74
|
+
if (comp == null) continue;
|
|
75
|
+
foreach (var itf in comp.GetType().GetInterfaces())
|
|
76
|
+
{
|
|
77
|
+
if (itf.Namespace != "jeanf.EventSystem") continue;
|
|
78
|
+
if (!itf.Name.EndsWith("EventSender", StringComparison.Ordinal)) continue;
|
|
79
|
+
foreach (var p in itf.GetProperties())
|
|
80
|
+
{
|
|
81
|
+
if (!typeof(DescriptionBaseSO).IsAssignableFrom(p.PropertyType)) continue;
|
|
82
|
+
if (!(p.GetValue(comp) is DescriptionBaseSO ch)) continue;
|
|
83
|
+
string gk = EventDiagnostics.GroupKey(ch.Guid, RuntimeHelpers.GetHashCode(ch));
|
|
84
|
+
if (!_senderScan.TryGetValue(gk, out var list))
|
|
85
|
+
{
|
|
86
|
+
list = new List<Component>();
|
|
87
|
+
_senderScan[gk] = list;
|
|
88
|
+
}
|
|
89
|
+
if (!list.Contains(comp)) list.Add(comp);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
void OnGUI()
|
|
96
|
+
{
|
|
97
|
+
DrawToolbar();
|
|
98
|
+
if (_tab == Tab.Channels) DrawChannels();
|
|
99
|
+
else DrawEventLog();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void DrawToolbar()
|
|
103
|
+
{
|
|
104
|
+
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
|
|
105
|
+
{
|
|
106
|
+
if (GUILayout.Toggle(_tab == Tab.Channels, "Channels", EditorStyles.toolbarButton)) _tab = Tab.Channels;
|
|
107
|
+
if (GUILayout.Toggle(_tab == Tab.EventLog, "Event Log", EditorStyles.toolbarButton)) _tab = Tab.EventLog;
|
|
108
|
+
GUILayout.FlexibleSpace();
|
|
109
|
+
bool resolver = CanonicalChannelResolver.Resolve != null;
|
|
110
|
+
var c = GUI.color;
|
|
111
|
+
GUI.color = resolver ? new Color(0.5f, 1f, 0.5f) : new Color(1f, 0.6f, 0.4f);
|
|
112
|
+
GUILayout.Label(resolver ? "● resolver installed" : "○ no resolver", EditorStyles.miniLabel);
|
|
113
|
+
GUI.color = c;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!EditorApplication.isPlaying)
|
|
117
|
+
EditorGUILayout.HelpBox("Enter Play mode to capture live channels and events.", MessageType.Info);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void DrawChannels()
|
|
121
|
+
{
|
|
122
|
+
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
|
|
123
|
+
{
|
|
124
|
+
_channelSearch = GUILayout.TextField(_channelSearch, EditorStyles.toolbarSearchField, GUILayout.MinWidth(120));
|
|
125
|
+
_duplicatesOnly = GUILayout.Toggle(_duplicatesOnly, "Duplicates only", EditorStyles.toolbarButton, GUILayout.Width(110));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var groups = BuildGroups();
|
|
129
|
+
|
|
130
|
+
GUILayout.Label($"Live channels: {groups.Count}", EditorStyles.miniBoldLabel);
|
|
131
|
+
|
|
132
|
+
_channelScroll = EditorGUILayout.BeginScrollView(_channelScroll);
|
|
133
|
+
foreach (var g in groups)
|
|
134
|
+
{
|
|
135
|
+
if (!string.IsNullOrEmpty(_channelSearch) &&
|
|
136
|
+
g.displayName.IndexOf(_channelSearch, StringComparison.OrdinalIgnoreCase) < 0)
|
|
137
|
+
continue;
|
|
138
|
+
if (_duplicatesOnly && g.instances.Count <= 1) continue;
|
|
139
|
+
DrawGroup(g);
|
|
140
|
+
}
|
|
141
|
+
EditorGUILayout.EndScrollView();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
class Group
|
|
145
|
+
{
|
|
146
|
+
public string groupKey;
|
|
147
|
+
public string displayName;
|
|
148
|
+
public string typeName;
|
|
149
|
+
public List<(EventDiagnostics.ChannelRecord rec, ScriptableObject so)> instances =
|
|
150
|
+
new List<(EventDiagnostics.ChannelRecord, ScriptableObject)>();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
List<Group> BuildGroups()
|
|
154
|
+
{
|
|
155
|
+
var byKey = new Dictionary<string, Group>();
|
|
156
|
+
var records = EventDiagnostics.SnapshotChannels();
|
|
157
|
+
foreach (var rec in records)
|
|
158
|
+
{
|
|
159
|
+
ScriptableObject so = null;
|
|
160
|
+
rec.instance?.TryGetTarget(out so);
|
|
161
|
+
if (so == null)
|
|
162
|
+
{
|
|
163
|
+
EventDiagnostics.PruneChannel(rec.key);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
string gk = EventDiagnostics.GroupKey(rec.guid, rec.key);
|
|
168
|
+
if (!byKey.TryGetValue(gk, out var g))
|
|
169
|
+
{
|
|
170
|
+
g = new Group { groupKey = gk, displayName = so.name, typeName = rec.typeName };
|
|
171
|
+
byKey[gk] = g;
|
|
172
|
+
}
|
|
173
|
+
g.instances.Add((rec, so));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
var list = new List<Group>(byKey.Values);
|
|
177
|
+
list.Sort((a, b) => string.Compare(a.displayName, b.displayName, StringComparison.OrdinalIgnoreCase));
|
|
178
|
+
return list;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
void DrawGroup(Group g)
|
|
182
|
+
{
|
|
183
|
+
bool dup = g.instances.Count > 1;
|
|
184
|
+
int subTotal = 0;
|
|
185
|
+
foreach (var inst in g.instances) subTotal += CountSubscribers(inst.so);
|
|
186
|
+
|
|
187
|
+
int gkHash = g.groupKey.GetHashCode();
|
|
188
|
+
bool open = _expanded.Contains(gkHash);
|
|
189
|
+
|
|
190
|
+
using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox))
|
|
191
|
+
{
|
|
192
|
+
bool nowOpen = EditorGUILayout.Foldout(open, GUIContent.none, true, EditorStyles.foldout);
|
|
193
|
+
if (nowOpen != open)
|
|
194
|
+
{
|
|
195
|
+
if (nowOpen) _expanded.Add(gkHash); else _expanded.Remove(gkHash);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
GUILayout.Label(g.displayName, EditorStyles.boldLabel, GUILayout.Width(200));
|
|
199
|
+
GUILayout.Label(g.typeName, EditorStyles.miniLabel, GUILayout.Width(150));
|
|
200
|
+
GUILayout.Label($"inst {g.instances.Count}", EditorStyles.miniLabel, GUILayout.Width(54));
|
|
201
|
+
GUILayout.Label($"subs {subTotal}", EditorStyles.miniLabel, GUILayout.Width(54));
|
|
202
|
+
|
|
203
|
+
GUILayout.FlexibleSpace();
|
|
204
|
+
if (dup)
|
|
205
|
+
{
|
|
206
|
+
var c = GUI.color; GUI.color = new Color(1f, 0.55f, 0.4f);
|
|
207
|
+
GUILayout.Label("▲ DUPLICATE", EditorStyles.miniBoldLabel, GUILayout.Width(90));
|
|
208
|
+
GUI.color = c;
|
|
209
|
+
}
|
|
210
|
+
else if (subTotal == 0)
|
|
211
|
+
{
|
|
212
|
+
GUILayout.Label("◌ no listeners", EditorStyles.miniLabel, GUILayout.Width(90));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (GUILayout.Button("Select GOs", EditorStyles.miniButton, GUILayout.Width(80)))
|
|
216
|
+
SelectAllListeners(g);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (open) DrawGroupDetails(g);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
void DrawGroupDetails(Group g)
|
|
223
|
+
{
|
|
224
|
+
EditorGUI.indentLevel++;
|
|
225
|
+
ScriptableObject canonical = null;
|
|
226
|
+
try { canonical = CanonicalChannelResolver.GetCanonical((ScriptableObject)g.instances[0].so); }
|
|
227
|
+
catch { }
|
|
228
|
+
|
|
229
|
+
foreach (var inst in g.instances)
|
|
230
|
+
{
|
|
231
|
+
var so = inst.so;
|
|
232
|
+
var rec = inst.rec;
|
|
233
|
+
bool isCanonical = canonical != null && ReferenceEquals(canonical, so);
|
|
234
|
+
|
|
235
|
+
using (new EditorGUILayout.HorizontalScope())
|
|
236
|
+
{
|
|
237
|
+
GUILayout.Space(16);
|
|
238
|
+
GUILayout.Label(isCanonical ? "[CANONICAL]" : "[duplicate]",
|
|
239
|
+
isCanonical ? EditorStyles.miniBoldLabel : EditorStyles.miniLabel, GUILayout.Width(86));
|
|
240
|
+
GUILayout.Label($"id {so.GetInstanceID()}", EditorStyles.miniLabel, GUILayout.Width(96));
|
|
241
|
+
GUILayout.Label($"thread {rec.firstSeenThreadId}" + (rec.seenOffMainThread ? " ⚠" : ""),
|
|
242
|
+
EditorStyles.miniLabel, GUILayout.Width(90));
|
|
243
|
+
if (GUILayout.Button("Ping asset", EditorStyles.miniButton, GUILayout.Width(74)))
|
|
244
|
+
EditorGUIUtility.PingObject(so);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
var subs = GetSubscribers(so);
|
|
248
|
+
using (new EditorGUILayout.HorizontalScope())
|
|
249
|
+
{
|
|
250
|
+
GUILayout.Space(22);
|
|
251
|
+
RoleBadge("RECV", RecvColor);
|
|
252
|
+
GUILayout.Label($"receivers ({subs.Count})", EditorStyles.miniBoldLabel);
|
|
253
|
+
}
|
|
254
|
+
foreach (var s in subs)
|
|
255
|
+
{
|
|
256
|
+
using (new EditorGUILayout.HorizontalScope())
|
|
257
|
+
{
|
|
258
|
+
GUILayout.Space(40);
|
|
259
|
+
GUILayout.Label("↳ " + s.label, EditorStyles.miniLabel, GUILayout.Width(320));
|
|
260
|
+
GUILayout.FlexibleSpace();
|
|
261
|
+
using (new EditorGUI.DisabledScope(s.target == null))
|
|
262
|
+
{
|
|
263
|
+
if (GUILayout.Button("Select", EditorStyles.miniButton, GUILayout.Width(60)))
|
|
264
|
+
{
|
|
265
|
+
Selection.activeObject = s.SelectionTarget;
|
|
266
|
+
EditorGUIUtility.PingObject(s.SelectionTarget);
|
|
267
|
+
}
|
|
268
|
+
if (GUILayout.Button("Ping", EditorStyles.miniButton, GUILayout.Width(50)))
|
|
269
|
+
EditorGUIUtility.PingObject(s.SelectionTarget);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
var publishers = GetPublishers(g);
|
|
276
|
+
var stackSenders = EventDiagnostics.SnapshotStackSenders(g.groupKey);
|
|
277
|
+
int senderTotal = publishers.Count + stackSenders.Length;
|
|
278
|
+
using (new EditorGUILayout.HorizontalScope())
|
|
279
|
+
{
|
|
280
|
+
GUILayout.Space(16);
|
|
281
|
+
RoleBadge("SEND", SendColor);
|
|
282
|
+
GUILayout.Label($"senders ({senderTotal})", EditorStyles.miniBoldLabel);
|
|
283
|
+
if (senderTotal == 0)
|
|
284
|
+
GUILayout.Label("— none yet (enable “Track sender” to auto-detect by class, or this.Publish(…) for exact GameObject)", EditorStyles.miniLabel);
|
|
285
|
+
}
|
|
286
|
+
foreach (var ss in stackSenders)
|
|
287
|
+
{
|
|
288
|
+
using (new EditorGUILayout.HorizontalScope())
|
|
289
|
+
{
|
|
290
|
+
GUILayout.Space(40);
|
|
291
|
+
string m = string.IsNullOrEmpty(ss.method) ? "" : "." + ss.method + "()";
|
|
292
|
+
var prev = GUI.color;
|
|
293
|
+
GUI.color = new Color(prev.r, prev.g, prev.b, 0.75f);
|
|
294
|
+
GUILayout.Label($"⇧ {ss.typeName}{m} ×{ss.count} (by stack, no GameObject)", EditorStyles.miniLabel, GUILayout.Width(420));
|
|
295
|
+
GUI.color = prev;
|
|
296
|
+
GUILayout.FlexibleSpace();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
foreach (var p in publishers)
|
|
300
|
+
{
|
|
301
|
+
using (new EditorGUILayout.HorizontalScope())
|
|
302
|
+
{
|
|
303
|
+
GUILayout.Space(40);
|
|
304
|
+
string name = p.comp != null ? p.comp.GetType().Name + " ▸ \"" + p.comp.gameObject.name + "\"" : p.label;
|
|
305
|
+
GUILayout.Label("⇧ " + name, EditorStyles.miniLabel, GUILayout.Width(320));
|
|
306
|
+
GUILayout.FlexibleSpace();
|
|
307
|
+
using (new EditorGUI.DisabledScope(p.comp == null))
|
|
308
|
+
{
|
|
309
|
+
if (GUILayout.Button("Select", EditorStyles.miniButton, GUILayout.Width(60)))
|
|
310
|
+
{
|
|
311
|
+
Selection.activeObject = p.comp != null ? p.comp.gameObject : null;
|
|
312
|
+
if (p.comp != null) EditorGUIUtility.PingObject(p.comp.gameObject);
|
|
313
|
+
}
|
|
314
|
+
if (GUILayout.Button("Ping", EditorStyles.miniButton, GUILayout.Width(50)))
|
|
315
|
+
if (p.comp != null) EditorGUIUtility.PingObject(p.comp.gameObject);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
EditorGUI.indentLevel--;
|
|
321
|
+
GUILayout.Space(4);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
static readonly Color RecvColor = new Color(0.45f, 0.8f, 1f);
|
|
325
|
+
static readonly Color SendColor = new Color(1f, 0.72f, 0.4f);
|
|
326
|
+
|
|
327
|
+
static void RoleBadge(string text, Color color)
|
|
328
|
+
{
|
|
329
|
+
var prev = GUI.color;
|
|
330
|
+
GUI.color = color;
|
|
331
|
+
GUILayout.Label(text, EditorStyles.miniBoldLabel, GUILayout.Width(38));
|
|
332
|
+
GUI.color = prev;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
struct PubInfo
|
|
336
|
+
{
|
|
337
|
+
public string label;
|
|
338
|
+
public Component comp;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
List<PubInfo> GetPublishers(Group g)
|
|
342
|
+
{
|
|
343
|
+
var list = new List<PubInfo>();
|
|
344
|
+
var seen = new HashSet<int>();
|
|
345
|
+
|
|
346
|
+
foreach (var pr in EventDiagnostics.SnapshotPublishers(g.groupKey))
|
|
347
|
+
{
|
|
348
|
+
Component c = null;
|
|
349
|
+
pr.component?.TryGetTarget(out c);
|
|
350
|
+
if (c == null) continue;
|
|
351
|
+
if (!seen.Add(c.GetInstanceID())) continue;
|
|
352
|
+
list.Add(new PubInfo { comp = c, label = pr.typeName });
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (_senderScan.TryGetValue(g.groupKey, out var scanned))
|
|
356
|
+
{
|
|
357
|
+
foreach (var c in scanned)
|
|
358
|
+
{
|
|
359
|
+
if (c == null) continue;
|
|
360
|
+
if (!seen.Add(c.GetInstanceID())) continue;
|
|
361
|
+
list.Add(new PubInfo { comp = c, label = c.GetType().Name });
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return list;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
struct SubInfo
|
|
368
|
+
{
|
|
369
|
+
public string label;
|
|
370
|
+
public Object target;
|
|
371
|
+
public GameObject go;
|
|
372
|
+
public Object SelectionTarget => go != null ? go : target;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
int CountSubscribers(ScriptableObject so)
|
|
376
|
+
{
|
|
377
|
+
int n = 0;
|
|
378
|
+
ForEachSubscriber(so, (_, __) => n++);
|
|
379
|
+
return n;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
List<SubInfo> GetSubscribers(ScriptableObject so)
|
|
383
|
+
{
|
|
384
|
+
var list = new List<SubInfo>();
|
|
385
|
+
ForEachSubscriber(so, (target, method) =>
|
|
386
|
+
{
|
|
387
|
+
var go = (target as Component)?.gameObject;
|
|
388
|
+
string typeName = method?.DeclaringType?.Name ?? target?.GetType().Name ?? "static";
|
|
389
|
+
string goName = go != null ? " ▸ \"" + go.name + "\"" : "";
|
|
390
|
+
list.Add(new SubInfo
|
|
391
|
+
{
|
|
392
|
+
label = $"{typeName}.{method?.Name}(){goName}",
|
|
393
|
+
target = target as Object,
|
|
394
|
+
go = go,
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
return list;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
static void ForEachSubscriber(ScriptableObject so, Action<object, MethodInfo> action)
|
|
401
|
+
{
|
|
402
|
+
if (so == null) return;
|
|
403
|
+
var t = so.GetType();
|
|
404
|
+
while (t != null && t != typeof(ScriptableObject))
|
|
405
|
+
{
|
|
406
|
+
foreach (var f in t.GetFields(FieldFlags))
|
|
407
|
+
{
|
|
408
|
+
if (!typeof(Delegate).IsAssignableFrom(f.FieldType)) continue;
|
|
409
|
+
if (!(f.GetValue(so) is Delegate del)) continue;
|
|
410
|
+
foreach (var d in del.GetInvocationList())
|
|
411
|
+
action(d.Target, d.Method);
|
|
412
|
+
}
|
|
413
|
+
t = t.BaseType;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
void SelectAllListeners(Group g)
|
|
418
|
+
{
|
|
419
|
+
var objs = new List<Object>();
|
|
420
|
+
foreach (var inst in g.instances)
|
|
421
|
+
foreach (var s in GetSubscribers(inst.so))
|
|
422
|
+
if (s.SelectionTarget != null) objs.Add(s.SelectionTarget);
|
|
423
|
+
if (objs.Count > 0)
|
|
424
|
+
{
|
|
425
|
+
Selection.objects = objs.ToArray();
|
|
426
|
+
EditorGUIUtility.PingObject(objs[0]);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
void DrawEventLog()
|
|
431
|
+
{
|
|
432
|
+
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
|
|
433
|
+
{
|
|
434
|
+
GUILayout.Label("On play:", EditorStyles.miniLabel, GUILayout.Width(54));
|
|
435
|
+
DrawPrefToggle(PrefAutoSender, "Track sender", v =>
|
|
436
|
+
{
|
|
437
|
+
EventDiagnostics.CaptureSenderStack = v;
|
|
438
|
+
EventDiagnostics.TrackingEnabled = v || EventDiagnostics.CaptureReceivers;
|
|
439
|
+
});
|
|
440
|
+
DrawPrefToggle(PrefAutoReceiver, "Track receiver", v =>
|
|
441
|
+
{
|
|
442
|
+
EventDiagnostics.CaptureReceivers = v;
|
|
443
|
+
EventDiagnostics.TrackingEnabled = v || EventDiagnostics.CaptureSenderStack;
|
|
444
|
+
});
|
|
445
|
+
if (GUILayout.Button("Clear", EditorStyles.toolbarButton, GUILayout.Width(50)))
|
|
446
|
+
EventDiagnostics.Clear();
|
|
447
|
+
GUILayout.FlexibleSpace();
|
|
448
|
+
_logSearch = GUILayout.TextField(_logSearch, EditorStyles.toolbarSearchField, GUILayout.MinWidth(120));
|
|
449
|
+
GUILayout.Label($"{EventDiagnostics.RaiseCount}/{EventDiagnostics.BufferCapacity}", EditorStyles.miniLabel);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
_logCount = EventDiagnostics.SnapshotRaises(_logBuffer);
|
|
453
|
+
|
|
454
|
+
DrawCounts();
|
|
455
|
+
|
|
456
|
+
using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox))
|
|
457
|
+
{
|
|
458
|
+
GUILayout.Label("Seq", EditorStyles.miniBoldLabel, GUILayout.Width(54));
|
|
459
|
+
GUILayout.Label("Time", EditorStyles.miniBoldLabel, GUILayout.Width(64));
|
|
460
|
+
GUILayout.Label("Channel", EditorStyles.miniBoldLabel, GUILayout.Width(180));
|
|
461
|
+
GUILayout.Label("Payload", EditorStyles.miniBoldLabel, GUILayout.Width(110));
|
|
462
|
+
GUILayout.Label("Sender", EditorStyles.miniBoldLabel, GUILayout.Width(180));
|
|
463
|
+
GUILayout.Label("Receiver(s)", EditorStyles.miniBoldLabel);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
_logScroll = EditorGUILayout.BeginScrollView(_logScroll);
|
|
467
|
+
for (int i = _logCount - 1; i >= 0; i--)
|
|
468
|
+
{
|
|
469
|
+
var r = _logBuffer[i];
|
|
470
|
+
if (!string.IsNullOrEmpty(_logSearch) &&
|
|
471
|
+
(r.typeName?.IndexOf(_logSearch, StringComparison.OrdinalIgnoreCase) ?? -1) < 0 &&
|
|
472
|
+
(r.payload?.IndexOf(_logSearch, StringComparison.OrdinalIgnoreCase) ?? -1) < 0)
|
|
473
|
+
continue;
|
|
474
|
+
|
|
475
|
+
using (new EditorGUILayout.HorizontalScope())
|
|
476
|
+
{
|
|
477
|
+
GUILayout.Label("#" + r.seq, EditorStyles.miniLabel, GUILayout.Width(54));
|
|
478
|
+
GUILayout.Label(r.time.ToString("0.000"), EditorStyles.miniLabel, GUILayout.Width(64));
|
|
479
|
+
GUILayout.Label(r.typeName, EditorStyles.miniLabel, GUILayout.Width(180));
|
|
480
|
+
GUILayout.Label(r.payload, EditorStyles.miniLabel, GUILayout.Width(110));
|
|
481
|
+
string sender = r.senderObject != null
|
|
482
|
+
? r.senderType
|
|
483
|
+
: r.senderType != null ? r.senderType + "." + r.senderMethod + "()" : "—";
|
|
484
|
+
if (r.offMainThread) sender = "⚠ t" + r.threadId + " " + sender;
|
|
485
|
+
GUILayout.Label(sender, EditorStyles.miniLabel, GUILayout.Width(146));
|
|
486
|
+
using (new EditorGUI.DisabledScope(r.senderObject == null))
|
|
487
|
+
{
|
|
488
|
+
if (GUILayout.Button("Sel", EditorStyles.miniButton, GUILayout.Width(32)) && r.senderObject != null)
|
|
489
|
+
{
|
|
490
|
+
Selection.activeObject = r.senderObject;
|
|
491
|
+
EditorGUIUtility.PingObject(r.senderObject);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
GUILayout.Label(string.IsNullOrEmpty(r.receivers) ? "—" : r.receivers, EditorStyles.miniLabel);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
EditorGUILayout.EndScrollView();
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
static void DrawPrefToggle(string key, string label, Action<bool> applyLive)
|
|
501
|
+
{
|
|
502
|
+
bool cur = EditorPrefs.GetBool(key, false);
|
|
503
|
+
bool next = GUILayout.Toggle(cur, label, EditorStyles.toolbarButton, GUILayout.Width(100));
|
|
504
|
+
if (next != cur)
|
|
505
|
+
{
|
|
506
|
+
EditorPrefs.SetBool(key, next);
|
|
507
|
+
if (EditorApplication.isPlaying) applyLive?.Invoke(next);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
void DrawCounts()
|
|
512
|
+
{
|
|
513
|
+
if (_logCount == 0) return;
|
|
514
|
+
var counts = new Dictionary<string, int>();
|
|
515
|
+
int max = 1;
|
|
516
|
+
for (int i = 0; i < _logCount; i++)
|
|
517
|
+
{
|
|
518
|
+
var name = _logBuffer[i].typeName ?? "?";
|
|
519
|
+
counts.TryGetValue(name, out int n);
|
|
520
|
+
n++;
|
|
521
|
+
counts[name] = n;
|
|
522
|
+
if (n > max) max = n;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
|
|
526
|
+
{
|
|
527
|
+
foreach (var kv in counts)
|
|
528
|
+
{
|
|
529
|
+
using (new EditorGUILayout.HorizontalScope())
|
|
530
|
+
{
|
|
531
|
+
GUILayout.Label(kv.Key, EditorStyles.miniLabel, GUILayout.Width(180));
|
|
532
|
+
var rect = GUILayoutUtility.GetRect(120, 10);
|
|
533
|
+
EditorGUI.DrawRect(new Rect(rect.x, rect.y + 1, 120f * kv.Value / max, 8),
|
|
534
|
+
new Color(0.4f, 0.7f, 1f));
|
|
535
|
+
GUILayout.Label(kv.Value.ToString(), EditorStyles.miniLabel, GUILayout.Width(50));
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
[InitializeOnLoad]
|
|
543
|
+
static class EventDiagnosticsAutoStart
|
|
544
|
+
{
|
|
545
|
+
static EventDiagnosticsAutoStart()
|
|
546
|
+
{
|
|
547
|
+
EditorApplication.playModeStateChanged += OnPlayModeChanged;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
static void OnPlayModeChanged(PlayModeStateChange state)
|
|
551
|
+
{
|
|
552
|
+
if (state != PlayModeStateChange.EnteredPlayMode) return;
|
|
553
|
+
|
|
554
|
+
bool sender = EditorPrefs.GetBool(EventSystemDebuggerWindow.PrefAutoSender, false);
|
|
555
|
+
bool receiver = EditorPrefs.GetBool(EventSystemDebuggerWindow.PrefAutoReceiver, false);
|
|
556
|
+
|
|
557
|
+
EventDiagnostics.CaptureSenderStack = sender;
|
|
558
|
+
EventDiagnostics.CaptureReceivers = receiver;
|
|
559
|
+
EventDiagnostics.TrackingEnabled = sender || receiver;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jeanf.eventsystem.editor",
|
|
3
|
+
"rootNamespace": "",
|
|
4
|
+
"references": [
|
|
5
|
+
"jeanf.eventsystem"
|
|
6
|
+
],
|
|
7
|
+
"includePlatforms": [
|
|
8
|
+
"Editor"
|
|
9
|
+
],
|
|
10
|
+
"excludePlatforms": [],
|
|
11
|
+
"allowUnsafeCode": false,
|
|
12
|
+
"overrideReferences": false,
|
|
13
|
+
"precompiledReferences": [],
|
|
14
|
+
"autoReferenced": true,
|
|
15
|
+
"defineConstraints": [],
|
|
16
|
+
"versionDefines": [],
|
|
17
|
+
"noEngineReferences": false
|
|
18
|
+
}
|