├── .gitattributes
├── Core
├── EventNames.cs
├── InternalEvents.cs
└── Tranzmit.cs
├── Debug V2
├── Code
│ ├── CodeBlepGenericDragWindow.cs
│ ├── CodeBlepGenericResizeWindow.cs
│ ├── CodeBlepGridLayoutGroupWidthModifier.cs
│ ├── TranzmitDebugV2.cs
│ ├── TranzmitDebugV2UI.cs
│ ├── TranzmitDebugV2UIItemLocal.cs
│ └── TranzmitDebugV2UISelectorButtonLocal.cs
├── Prefabs
│ ├── Debug Item.prefab
│ └── Selector Button.prefab
└── Textures
│ ├── Close.png
│ └── Resize.png
├── Debug
├── EventsSentUI.cs
├── Graph
│ └── Editor
│ │ ├── Blackboard_Properties.cs
│ │ ├── Resources
│ │ └── Tranzmit_Graph.uss
│ │ ├── Tranzmit_Graph.cs
│ │ ├── Tranzmit_Graph_View.cs
│ │ └── Tranzmit_Node.cs
└── TranzmitDebug.cs
├── Example Code
├── Broadcaster.cs
└── Subscriber.cs
├── Images
├── tranzmit-debug-v2-ui.png
├── trazmit-graph.png
└── trazmit-main.png
├── LICENSE
├── README.md
└── Tranzmit with Debug V1 and V2 Demo Scenes.unitypackage
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/Core/EventNames.cs:
--------------------------------------------------------------------------------
1 | namespace Blep.Tranzmit
2 | {
3 | public partial class Tranzmit
4 | {
5 | ///
6 | /// To create a new Event Name, add it to the enum below.
7 | /// Use the intergers to preserve other fields when you modify these enums! 0 to 10 are reserved for Tranzmit.
8 | /// Also if you accidentaly delete the wrong enum, adding it back in with the same int (Tranzmit Event will show the value!) will restore it back to normal in Trazmit Event.
9 | /// Also allows for renaming!
10 | /// Check your Intergers! Duplicates will cause issues!
11 | ///
12 | /// ///
13 | /// CONSIDERING CHECKS LIKE THIS:
14 | /// num Status
15 | /// {
16 | /// OK = 0,
17 | /// Warning = 64,
18 | /// Error = 256
19 | /// }
20 | ///
21 | /// static void Main(string[] args)
22 | /// {
23 | /// bool exists;
24 | ///
25 | /// // Testing for Integer Values
26 | /// exists = Enum.IsDefined(typeof(Status), 0); // exists = true
27 | /// exists = Enum.IsDefined(typeof(Status), 1); // exists = false
28 | ///
29 | /// // Testing for Constant Names
30 | /// exists = Enum.IsDefined(typeof(Status), "OK"); // exists = true
31 | /// exists = Enum.IsDefined(typeof(Status), "NotOK"); // exists = false
32 | /// }
33 | ///
34 | ///
35 | ///
36 |
37 | // ALSO CONSIDERING TURNING THIS INTO A LIST WITH HELPER FUNCTION
38 |
39 | public enum EventNames
40 | {
41 | None = 0,
42 | PlayerStats = 1,
43 | Damage = 2,
44 | SecretFound = 3
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/Core/InternalEvents.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Blep.Tranzmit
5 | {
6 | ///
7 | /// We could use Tranzmit for these events. However, if Tranzmit breaks for some reason, it might break the whole debug process.
8 | ///
9 |
10 | public partial class Tranzmit
11 | {
12 | public delegate void EventCreatedDelegate(EventNames eventName);
13 | public event EventCreatedDelegate EventAdded;
14 |
15 | ///
16 | /// Called when a new Event has been edded to Tranzmit Events.
17 | ///
18 | /// The name of the new event added.
19 | public void Broadcast_Event_Added(EventNames eventName)
20 | {
21 | // Subscribers?
22 | if (EventAdded != null)
23 | {
24 | EventAdded(eventName);
25 | }
26 | }
27 |
28 | // -----------------------------------------------------------------------------------------
29 |
30 | public delegate void EventDeletedDelegate(EventNames eventName);
31 | public event EventDeletedDelegate EventDeleted;
32 |
33 | ///
34 | /// Called when a new Event has been deleted from Tranzmit Events.
35 | ///
36 | /// The name of the new event deleted.
37 | public void Broadcast_Event_Deleted(EventNames eventName)
38 | {
39 | // Subscribers?
40 | if (EventDeleted != null)
41 | {
42 | EventDeleted(eventName);
43 | }
44 | }
45 |
46 | // -----------------------------------------------------------------------------------------
47 |
48 | public delegate void EventSentDelegate(object payload, object source, DeliveryStatuses status, List errorTypes, EventNames eventName, Type requiredDataType, Type providedDataType, EventData.TranzmitDelegate tranzmitDelegate);
49 | public event EventSentDelegate EventSent;
50 |
51 | ///
52 | /// Called when an Event has been sent by an Object via Tranzmit. The information here will provide an insight into whether the send was successful or not.
53 | ///
54 | /// The name of the Event sent.
55 | public void Broadcast_Event_Sent(object payload, object source, DeliveryStatuses status, List errors, EventNames eventName, Type requiredDataType, Type providedDataType, EventData.TranzmitDelegate tranzmitDelegate)
56 | {
57 | // Subscribers?
58 | if (tranzmitDelegate != null && EventSent != null)
59 | {
60 | EventSent(payload, source, status, errors, eventName, requiredDataType, providedDataType, tranzmitDelegate);
61 | }
62 | }
63 |
64 | // -----------------------------------------------------------------------------------------
65 |
66 | public delegate void TranzmitDebugResetDelegate();
67 | public event TranzmitDebugResetDelegate TranzmitDebugReset;
68 |
69 | ///
70 | /// This event is triggered when Tranzmit Debug clears it's debug data, and allows other modules to react accordingly. For example Tranzmit Graph uses this to refresh displayed data.
71 | ///
72 | public void Broadcast_Tranzmit_Debug_Reset()
73 | {
74 | // Subscribers?
75 | if (TranzmitDebugReset != null)
76 | {
77 | TranzmitDebugReset();
78 | }
79 | }
80 |
81 | // -----------------------------------------------------------------------------------------
82 |
83 | public delegate void TranzmitDebugLogUpdateDelegate(TranzmitDebug.LogEntry updatedLog);
84 | public event TranzmitDebugLogUpdateDelegate TranzmitDebugLogUpdated;
85 |
86 | ///
87 | /// Used to notify when a Debug Log has been updated, and makes for efficient direct updating of information, rather than trying to locate an changes in debug data. Used by Tranzmit Graph.
88 | ///
89 | /// The debug log that has been updated
90 | public void Broadcast_Tranzmit_Log_Update(TranzmitDebug.LogEntry updatedLog)
91 | {
92 | // Subscribers?
93 | if (TranzmitDebugLogUpdated != null)
94 | {
95 | TranzmitDebugLogUpdated(updatedLog);
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/Core/Tranzmit.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 | using System.Linq;
6 | using System.Collections;
7 |
8 | ///
9 | /// - WORKS IN EDITOR and RUNTIME
10 | ///
11 | /// Features:
12 | /// - Error checking and handling at all stages.
13 | /// - Virtually Zero GC.
14 | /// - Debug Module to allow tracing of Tranzmit Events that are not formed correctly.
15 | /// - Unity Graphview Editor Window to visualize the Events in Realtime.
16 | /// - Typesafe implementation of Tranzmit Event names.
17 | /// - Passes any Type of Object
18 | ///
19 | /// - When working within the editor be aware that all sorts of Unity serialzation and compile events can break the Subscriptions! There is only so much that I can do to defend against this ;)
20 | ///
21 | ///
22 |
23 | namespace Blep.Tranzmit
24 | {
25 | ///
26 | /// This is the main component of Tranzmit. It will operate independant of the Debug Module and Graphview Ediotr window.
27 | ///
28 | [ExecuteAlways]
29 | public partial class Tranzmit : SerializedMonoBehaviour
30 | {
31 | ///
32 | /// Used by the Tranzmit event we are trying to send.
33 | ///
34 | public enum DeliveryStatuses
35 | {
36 | None,
37 | Success,
38 | Failed
39 | }
40 |
41 | ///
42 | /// The types of errors being handled / caught by Tranzmit. If any of these errors occur, the Tranzmit event will not be sent.
43 | ///
44 | public enum Errors
45 | {
46 | None,
47 | MissingSource,
48 | NoSubscribers,
49 | MissingPayload,
50 | WrongDataType
51 | }
52 |
53 | ///
54 | /// Handles the process of adding a new Event
55 | ///
56 | [BoxGroup]
57 | [HideReferenceObjectPicker]
58 | [HideLabel]
59 | public AddNewEventToEventsData AddEvent = new AddNewEventToEventsData();
60 |
61 | ///
62 | /// This is where all user created Tranzmit Events are stored.
63 | ///
64 | [Tooltip("The Created Events. Subscribers respond to events in this Dictionary.")]
65 | [DictionaryDrawerSettings(IsReadOnly = true)]
66 | [Title("EVENTS", "The core of Tranzmit! All your events are here. To create a new Event Type, edit the EventNames.cs script.")]
67 | [PropertySpace(SpaceBefore = 20, SpaceAfter = 20)]
68 | public Dictionary Events = new Dictionary();
69 |
70 |
71 | // Most Data you require is in here.
72 | [Serializable]
73 | [HideReferenceObjectPicker]
74 | public class EventData
75 | {
76 | // 1 - Define the Delegate
77 | public delegate void TranzmitDelegate(object source, object payload);
78 |
79 | [ReadOnly]
80 | public InfoData Info = new InfoData();
81 |
82 | public class InfoData
83 | {
84 | // Handy reference to the Tranzmit Instance that this Event resides in.
85 | public Tranzmit Tranzmit;
86 |
87 | [Required]
88 | public EventNames EventName;
89 |
90 | [Required]
91 | public Type DataType;
92 | }
93 |
94 | // 2 - Define The Event based on the delegate
95 | public event TranzmitDelegate TranzmitEvent;
96 |
97 |
98 | ///
99 | /// Send the Event. Handles all error checking before we try to send the Event.
100 | ///
101 | /// The object that is sending a Tranzmit Event
102 | /// The object that contains the data being sent with the Tranzmit event
103 | // 3 - Send The Event
104 | public void Send(object source, object payload)
105 | {
106 | List Errors = new List();
107 | Type dataType = null;
108 |
109 | if (source == null)
110 | Errors.Add(Tranzmit.Errors.MissingSource);
111 |
112 | if (TranzmitEvent == null)
113 | Errors.Add(Tranzmit.Errors.NoSubscribers);
114 |
115 | if (payload == null)
116 | {
117 | Errors.Add(Tranzmit.Errors.MissingPayload);
118 | }
119 | else
120 | {
121 | dataType = payload.GetType();
122 | if (dataType != Info.DataType)
123 | Errors.Add(Tranzmit.Errors.WrongDataType);
124 | }
125 |
126 | DeliveryStatuses delieveryStatus;
127 |
128 | if (Errors.Count == 0)
129 | {
130 | delieveryStatus = DeliveryStatuses.Success;
131 | }
132 | else
133 | {
134 | delieveryStatus = DeliveryStatuses.Failed;
135 | }
136 |
137 | if (delieveryStatus == DeliveryStatuses.Success)
138 | {
139 | TranzmitEvent.Invoke(source, payload);
140 | }
141 |
142 | Info.Tranzmit.Broadcast_Event_Sent(payload, source, delieveryStatus, Errors, Info.EventName, Info.DataType, dataType, TranzmitEvent);
143 | }
144 |
145 | ///
146 | /// Changes the Data Type of the specified Event
147 | ///
148 | ///
149 | [Button]
150 | public void ChangeDataType(Type type)
151 | {
152 | if (type != null)
153 | {
154 | Info.DataType = type;
155 | }
156 | }
157 |
158 | ///
159 | /// Removes all subscribers from the specified Event
160 | ///
161 | [ButtonGroup, GUIColor(1f, 0.5f, 0.0f)]
162 | public void RemoveAllSubscribers()
163 | {
164 | TranzmitEvent = null;
165 | }
166 |
167 | ///
168 | /// Deletes the specified Event
169 | ///
170 | [ButtonGroup, GUIColor(0.8f, 0.1f, 0.1f)]
171 | public void DeleteEvent()
172 | {
173 | IEnumerator Delete(EventNames EventName)
174 | {
175 | // If we don't wait, deleting Causes an error in Odin when deleting anything other than last entry in dictionary.
176 | yield return null;
177 |
178 | Info.Tranzmit.Events.Remove(EventName);
179 | Info.Tranzmit.Broadcast_Event_Deleted(EventName);
180 |
181 | // ERRORS: InvalidOperationException: Sequence contains no elements
182 | // When removing EVENT after ENUM EVENT TYPE HAS BEEN DELETED!
183 |
184 | var newList = Info.Tranzmit.AddEvent.GenerateListOfUnusedEventNames();
185 |
186 | if (newList.Count > 0)
187 | {
188 | Info.Tranzmit.AddEvent.EventName = Info.Tranzmit.AddEvent.GenerateListOfUnusedEventNames().First();
189 | }
190 | }
191 |
192 | Info.Tranzmit.StartCoroutine(Delete(Info.EventName));
193 | }
194 |
195 | ///
196 | /// Fetches the Subscribers (Deleagtes) 'attached' to the Specified Event. This is the only way I can find to get delgates directly from this class.
197 | ///
198 | /// Event Delegates
199 | public List GetSubscribers()
200 | {
201 |
202 | if (TranzmitEvent != null)
203 | {
204 | return TranzmitEvent.GetInvocationList().ToList();
205 | }
206 |
207 | return new List();
208 | }
209 |
210 | ///
211 | /// Experimental. Work in progress. Not Complete. Exploring removal of Invocation (subscriber) that have a NULL target.
212 | /// Would consider using as first step in Send();
213 | ///
214 | public void RemoveInvocationWithoutTarget()
215 | {
216 | if (TranzmitEvent != null)
217 | {
218 | var subscribers = TranzmitEvent.GetInvocationList();
219 |
220 | if (subscribers != null)
221 | {
222 | foreach (var invocation in TranzmitEvent.GetInvocationList())
223 | {
224 | if (invocation.Target == null)
225 | {
226 | // How to remove a Subscriber from Delegate with no Target? Is it possible?
227 | // TranzmitEvent -= delegate(object source, object payload) { };
228 | }
229 | }
230 | }
231 | }
232 | }
233 | }
234 |
235 | // -----------------------------------------------------------------------------------------
236 |
237 | public class AddNewEventToEventsData
238 | {
239 | // Used for reference to parent class instance.
240 | private Tranzmit _Tranzmit;
241 | public AddNewEventToEventsData(Tranzmit _Tranzmit = null)
242 | {
243 | this._Tranzmit = _Tranzmit;
244 | }
245 |
246 |
247 | [ValueDropdown(nameof(GenerateListOfUnusedEventNames), SortDropdownItems = true, DrawDropdownForListElements = true)]
248 | public EventNames EventName;
249 | public Type DataType = null;
250 |
251 |
252 | ///
253 | /// Adds an Event to the Events Dictionary
254 | ///
255 | [ButtonGroup]
256 | [Button("Add Event", ButtonStyle.Box, Expanded = true), GUIColor(0f, 1f, 0f)]
257 | public void Add()
258 | {
259 | if (!_Tranzmit.CheckEventIsAllocated(EventName))
260 | {
261 | if (DataType != null)
262 | {
263 | var newEventData = new EventData();
264 |
265 | newEventData.Info = new EventData.InfoData();
266 | newEventData.Info.Tranzmit = _Tranzmit;
267 | newEventData.Info.EventName = EventName;
268 | newEventData.Info.DataType = DataType;
269 |
270 | _Tranzmit.Events.Add(EventName, newEventData);
271 |
272 | _Tranzmit.Broadcast_Event_Added(EventName);
273 |
274 | if (GenerateListOfUnusedEventNames().Count() != 0)
275 | {
276 | EventName = GenerateListOfUnusedEventNames().First();
277 | }
278 |
279 | }
280 | else
281 | {
282 | Debug.LogError(TranzmitDebug.DebugTypes.Error + " - No Data Type has been specified when trying to create the Event. Aborted.");
283 | }
284 | }
285 | else
286 | {
287 | Debug.LogError(TranzmitDebug.DebugTypes.Error + " - An entry to the Event Type of " + EventName + "Already exists! Aborted.");
288 | }
289 | }
290 |
291 |
292 | ///
293 | /// Used by ODIN - [ValueDropdown(nameof(GetAvailableList)] - For generating a list of Unused Event Types
294 | ///
295 | /// The list used for ODIN Event Names drop down
296 | public List GenerateListOfUnusedEventNames()
297 | {
298 | List result = new List();
299 |
300 | if (_Tranzmit != null && _Tranzmit.Events != null && _Tranzmit.Events.Count > 0)
301 | {
302 | foreach (EventNames val in Enum.GetValues(typeof(EventNames)))
303 | {
304 | if (_Tranzmit.CheckEventIsAllocated(val) == false)
305 | {
306 | result.Add(val);
307 | }
308 | }
309 | }
310 | else
311 | {
312 | foreach (EventNames val in Enum.GetValues(typeof(EventNames)))
313 | {
314 | result.Add(val);
315 | }
316 | }
317 |
318 | return result;
319 | }
320 | }
321 |
322 | // -----------------------------------------------------------------------------------------
323 |
324 | ///
325 | /// This script is using [ExecuteAlways] as such OnEnable is called after recompiles etc. This allow for use with UNity Editor as well as Runtime Compile.
326 | ///
327 | private void OnEnable()
328 | {
329 | // Added here so that we can pass in the reference to Tranzmit (this)
330 | AddEvent = new AddNewEventToEventsData(this);
331 |
332 | if (AddEvent.GenerateListOfUnusedEventNames().Count() != 0)
333 | {
334 | AddEvent.EventName = AddEvent.GenerateListOfUnusedEventNames().First();
335 | }
336 | }
337 |
338 | // -----------------------------------------------------------------------------------------
339 |
340 | ///
341 | /// Fetches a list of Subscriber Objects in the Event that was sent
342 | ///
343 | /// The event which we are querying for Subscribers
344 | /// List of Subscriber Objects
345 | public List