├── .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 GetSubscribersInSentEvent(EventData.TranzmitDelegate TranzmitEvent) 346 | { 347 | List result = new List(); 348 | 349 | if (TranzmitEvent != null) 350 | { 351 | foreach (Delegate subscriber in TranzmitEvent.GetInvocationList()) 352 | { 353 | result.Add(subscriber.Target); 354 | } 355 | } 356 | 357 | return result; 358 | } 359 | 360 | // ----------------------------------------------------------------------------------------- 361 | 362 | /// 363 | /// Checks if the provided Event Name exists within the code. 364 | /// 365 | /// 366 | /// True if exists 367 | public bool EventNameExists(EventNames eventName) 368 | { 369 | if(Enum.IsDefined(typeof(EventNames), eventName)) 370 | { 371 | return true; 372 | } 373 | else 374 | { 375 | return false; 376 | } 377 | } 378 | 379 | // ----------------------------------------------------------------------------------------- 380 | 381 | /// 382 | /// Checks if the provided Event is being used in the Events Dictionary. 383 | /// 384 | /// 385 | /// True if the Event Name is found 386 | public bool CheckEventIsAllocated(EventNames eventName) 387 | { 388 | if (Events != null && Events.Count != 0) 389 | { 390 | if (Events.ContainsKey(eventName)) 391 | { 392 | return true; 393 | } 394 | else 395 | { 396 | return false; 397 | } 398 | } 399 | else 400 | { 401 | return false; 402 | } 403 | } 404 | 405 | // ----------------------------------------------------------------------------------------- 406 | 407 | /// 408 | /// A handy function that makes Subscribing (most common use) to an event easy, as all checking is handled here. Massively reduces code elsewhere. 409 | /// 410 | /// 411 | /// The Valid Event if it exists 412 | public bool CheckEventIsAvailable(EventNames eventName) 413 | { 414 | if (Events != null && Events.Count != 0) 415 | { 416 | if (CheckEventIsAllocated(eventName)) 417 | { 418 | return true; 419 | } 420 | else 421 | { 422 | return false; 423 | } 424 | } 425 | else 426 | { 427 | return false; 428 | } 429 | } 430 | 431 | // ----------------------------------------------------------------------------------------- 432 | 433 | /// 434 | /// Recommended way to use Tranzmit to send Events. Various checks are carried out from this point forward. 435 | /// 436 | /// The name of the event 437 | /// The object that is broadcasting this event. 438 | /// The data payload to send. 439 | public void BroadcastEvent(EventNames eventName, object source, object payload) 440 | { 441 | if (CheckEventIsAllocated(eventName)) 442 | { 443 | // BROADCAST! 444 | Events[eventName].Send(source, payload); 445 | } 446 | else 447 | { 448 | Debug.Log("No Instance of Tranzmit has been found!"); 449 | } 450 | } 451 | } 452 | } -------------------------------------------------------------------------------- /Debug V2/Code/CodeBlepGenericDragWindow.cs: -------------------------------------------------------------------------------- 1 | using Sirenix.OdinInspector; 2 | using UnityEngine; 3 | using UnityEngine.EventSystems; 4 | using UnityEngine.UI; 5 | 6 | namespace blep 7 | { 8 | public class CodeBlepGenericDragWindow : MonoBehaviour, IPointerDownHandler 9 | { 10 | //[BoxGroup("CONFIG")] public bool IsActive; 11 | [Required][BoxGroup("MISC REFS")] public RectTransform Root; 12 | [Required][BoxGroup("MISC REFS")] public Image DragImage; 13 | 14 | #pragma warning disable 0414 15 | private bool MouseHeldDown; 16 | 17 | private Vector2 DragOffset; 18 | private bool IsDragging; 19 | private Vector3 MousePosition; 20 | 21 | //--------------------------------------------------------------------------------------- 22 | 23 | private void Update() 24 | { 25 | if (Input.GetMouseButton(0)) 26 | { 27 | MouseHeldDown = true; 28 | } 29 | else 30 | { 31 | IsDragging = false; 32 | MouseHeldDown = false; 33 | } 34 | 35 | DragWindow(); 36 | } 37 | 38 | //--------------------------------------------------------------------------------------- 39 | 40 | private void DragWindow() 41 | { 42 | MousePosition = Input.mousePosition; 43 | 44 | if (IsDragging) 45 | { 46 | Root.gameObject.transform.position = (Vector2)MousePosition + DragOffset; 47 | } 48 | } 49 | 50 | //--------------------------------------------------------------------------------------- 51 | 52 | public void OnPointerDown(PointerEventData eventData) 53 | { 54 | if (DragImage.gameObject == eventData.pointerCurrentRaycast.gameObject) 55 | { 56 | IsDragging = true; 57 | DragOffset = Root.gameObject.transform.position - Input.mousePosition; 58 | } 59 | } 60 | 61 | //--------------------------------------------------------------------------------------- 62 | 63 | public void VirtualPointerDown(Vector3 mousePosition) 64 | { 65 | IsDragging = true; 66 | DragOffset = Root.gameObject.transform.position - mousePosition; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Debug V2/Code/CodeBlepGenericResizeWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Sirenix.OdinInspector; 5 | using UnityEngine; 6 | using UnityEngine.EventSystems; 7 | using UnityEngine.UI; 8 | 9 | namespace blep 10 | { 11 | public class CodeBlepGenericResizeWindow : MonoBehaviour, IPointerDownHandler 12 | { 13 | public ResizeModes ResizeMode; 14 | 15 | [Required][BoxGroup("MISC REFS")] public RectTransform Root; 16 | [Required][BoxGroup("MISC REFS")] public Image ResizeImage; 17 | 18 | public Vector2Int StartSize = new Vector2Int(500, 500); 19 | public Vector2Int MinSize = new Vector2Int(300, 300); 20 | 21 | #pragma warning disable 0414 22 | private bool MouseHeldDown; 23 | 24 | private bool IsResizing; 25 | private int ResizeMouseXDifference; 26 | private int ResizeMouseYDifference; 27 | private int ResizeDeltaXFinal; 28 | private int ResizeDeltaYFinal; 29 | private Vector3 ResizeMouseStart; 30 | private Vector2 ResizeRootDeltaSizeStart; 31 | private Vector3 MousePosition; 32 | 33 | public enum ResizeModes {None, X, Y, All} 34 | 35 | //--------------------------------------------------------------------------------------- 36 | 37 | private void Start() 38 | { 39 | Root.sizeDelta = StartSize; 40 | } 41 | 42 | //--------------------------------------------------------------------------------------- 43 | 44 | private void Update() 45 | { 46 | if (Input.GetMouseButton(0)) 47 | { 48 | MouseHeldDown = true; 49 | } 50 | else 51 | { 52 | IsResizing = false; 53 | MouseHeldDown = false; 54 | } 55 | 56 | ResizeWindow(); 57 | } 58 | 59 | //--------------------------------------------------------------------------------------- 60 | 61 | private void ResizeWindow() 62 | { 63 | MousePosition = Input.mousePosition; 64 | 65 | // RESIZING 66 | if (IsResizing && ResizeMode != ResizeModes.None) 67 | { 68 | // X 69 | if (ResizeMode == ResizeModes.X || ResizeMode == ResizeModes.All) 70 | { 71 | ResizeMouseXDifference = (int) ResizeMouseStart.x - (int) Input.mousePosition.x; 72 | ResizeDeltaXFinal = (int) ResizeRootDeltaSizeStart.x - ResizeMouseXDifference; 73 | ResizeDeltaXFinal = Mathf.Clamp(ResizeDeltaXFinal, MinSize.x, int.MaxValue); 74 | Root.sizeDelta = new Vector2(ResizeDeltaXFinal, Root.sizeDelta.y); 75 | } 76 | 77 | // Y 78 | if (ResizeMode == ResizeModes.Y || ResizeMode == ResizeModes.All) 79 | { 80 | ResizeMouseYDifference = (int) ResizeMouseStart.y - (int) Input.mousePosition.y; 81 | ResizeDeltaYFinal = (int) ResizeRootDeltaSizeStart.y + ResizeMouseYDifference; 82 | ResizeDeltaYFinal = Mathf.Clamp(ResizeDeltaYFinal, MinSize.y, int.MaxValue); 83 | Root.sizeDelta = new Vector2(Root.sizeDelta.x, ResizeDeltaYFinal); 84 | } 85 | } 86 | } 87 | 88 | //--------------------------------------------------------------------------------------- 89 | 90 | public void OnPointerDown(PointerEventData eventData) 91 | { 92 | if (ResizeImage.gameObject == eventData.pointerCurrentRaycast.gameObject) 93 | { 94 | IsResizing = true; 95 | ResizeMouseStart = MousePosition; 96 | ResizeRootDeltaSizeStart = Root.sizeDelta; 97 | } 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /Debug V2/Code/CodeBlepGridLayoutGroupWidthModifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Sirenix.OdinInspector; 5 | using UnityEngine; 6 | using UnityEngine.UI; 7 | 8 | namespace blep 9 | { 10 | public class CodeBlepGridLayoutGroupWidthModifier : MonoBehaviour 11 | { 12 | public int RowOrColumnCount = 5; 13 | 14 | public GridLayoutGroup GridLayout; 15 | public RectTransform GridContainer; 16 | 17 | [ReadOnly] public Vector2 GridContainerRectDimensions; 18 | 19 | private Vector2 PreviousGridContainerSize; 20 | 21 | // ----------------------------------------------------------------------------------------- 22 | 23 | private void Update() 24 | { 25 | ResizeGridCell(); 26 | } 27 | 28 | // ----------------------------------------------------------------------------------------- 29 | 30 | [Button] 31 | public void ResizeGridCell(bool force = false) 32 | { 33 | GridContainerRectDimensions = new Vector2(GridContainer.rect.width, GridContainer.rect.height); 34 | 35 | if (force || GridContainerRectDimensions != PreviousGridContainerSize) 36 | { 37 | PreviousGridContainerSize = GridContainerRectDimensions; 38 | GridLayout.cellSize = new Vector2((GridContainerRectDimensions.x / RowOrColumnCount) - GridLayout.spacing.x, GridLayout.cellSize.y); 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Debug V2/Code/TranzmitDebugV2.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using Sirenix.OdinInspector; 4 | using System; 5 | using UnityEngine.UIElements; 6 | using System.Linq; 7 | using System.Text.RegularExpressions; 8 | using Sirenix.Serialization; 9 | using Object = System.Object; 10 | 11 | namespace Blep.Tranzmit 12 | { 13 | public class TranzmitDebugV2 : SerializedMonoBehaviour 14 | { 15 | /// 16 | /// Used for testing and general debugging. 17 | /// This script is not designed for use when stress testing / checking for GC, and it is recommended to remove for correct results in Profiler. 18 | /// It is a verbose tool that may generate GC, although I have tried to make it as friendly to GC as I can in practical terms. 19 | /// 20 | public static TranzmitDebugV2 Instance; 21 | 22 | [BoxGroup("REFERENCES")] 23 | [Required] public Tranzmit Tranzmit; 24 | 25 | [BoxGroup("SEQUENTIAL LOG OPTIONS")] 26 | public bool SequentialLogEnabled = true; 27 | 28 | [BoxGroup("SEQUENTIAL LOG OPTIONS")] 29 | public bool SequentialLogErrorsOnly = false; 30 | 31 | [BoxGroup("SEQUENTIAL LOG OPTIONS")] 32 | public bool SequentialLogStorePayloads = true; 33 | 34 | [BoxGroup("SEQUENTIAL LOG OPTIONS")] 35 | public bool SequentialLogValuesOnlyPayloads = true; 36 | 37 | [BoxGroup("DEBUG LOG OPTIONS")] 38 | public bool DebugLogEnabled = true; 39 | 40 | [BoxGroup("DEBUG LOG OPTIONS")] 41 | public bool DebugLogStorePayloads = true; 42 | 43 | [BoxGroup("LOGS")][TableList] 44 | public List SequentialLog = new List(); 45 | 46 | [BoxGroup("LOGS")] 47 | public Dictionary DebugLog = new Dictionary(); 48 | 49 | [ShowOdinSerializedPropertiesInInspector][HideReferenceObjectPicker] 50 | public class SequentialLogData 51 | { 52 | [TableColumnWidth(300, Resizable = false)] 53 | public SequentialGeneralData General; 54 | 55 | [TableColumnWidth(300, Resizable = false)] 56 | [HideReferenceObjectPicker][HideDuplicateReferenceBox] 57 | public List Subscribers; 58 | 59 | [TextArea(9,30)] public string Payload; 60 | } 61 | 62 | [ShowOdinSerializedPropertiesInInspector][HideReferenceObjectPicker] 63 | public class SequentialGeneralData 64 | { 65 | [ProgressBar(0,0, ColorGetter = "StatusColor", DrawValueLabel = false)][HideLabel] 66 | public int Status; 67 | public int FrameNumber; 68 | public object Broadcaster; 69 | public Tranzmit.EventNames EventName; 70 | public Tranzmit.DeliveryStatuses DeliveryStatus; 71 | public GameObject UIElement; 72 | public List Errors = new List(); 73 | 74 | public Color StatusColor() 75 | { 76 | if (DeliveryStatus == Tranzmit.DeliveryStatuses.Failed) 77 | { 78 | return Color.red; 79 | } 80 | 81 | return new Color(0, .8f, 1f); 82 | } 83 | } 84 | 85 | [ShowOdinSerializedPropertiesInInspector][HideReferenceObjectPicker] 86 | public class LogData 87 | { 88 | [HideReferenceObjectPicker] 89 | public List Subscribers = new List(); 90 | public LogStats Success = new LogStats(); 91 | public LogStats MissingSource = new LogStats(); 92 | public LogStats MissingPayload = new LogStats(); 93 | public LogStats WrongDataType = new LogStats(); 94 | } 95 | 96 | [HideReferenceObjectPicker] 97 | public class LogStats 98 | { 99 | [Tooltip("The number of time that this type of Event Status has occured.")] 100 | public int Count; 101 | 102 | [Tooltip("Certain malformed events will not have a broadcaster object. We count them here.")] 103 | public int NullSources; 104 | 105 | [HideReferenceObjectPicker] 106 | [Tooltip("Payload that was sent by the Event. Malformed Events might result in a Null entry.")] 107 | public List Sources = new List(); 108 | 109 | [HideReferenceObjectPicker] 110 | [Tooltip("Payload that was sent by the Event. Malformed Events might result in a Null entry.")] 111 | [TextArea(5,100)] 112 | public List Payloads = new List(); 113 | } 114 | 115 | // ----------------------------------------------------------------------------------------- 116 | 117 | /// 118 | /// Used instead of Start as using [ExecuteAlways]. Called after recompiles etc 119 | /// 120 | void OnEnable() 121 | { 122 | Instance = this; 123 | SubscribeToTranzmit(); 124 | InitializeDebugLog(); 125 | } 126 | 127 | // ----------------------------------------------------------------------------------------- 128 | 129 | /// 130 | /// This is called by Unity when an Object is being destroyed. 131 | /// 132 | private void OnDestroy() 133 | { 134 | UnsubscribeFromTranzmit(); 135 | } 136 | 137 | // ----------------------------------------------------------------------------------------- 138 | 139 | /// 140 | /// You might have noticed that I am using in-built Events to subscribe to Tranzmit, rather than using Tranzmit to handle them. There are multiple reasons including: 141 | /// - If Tranzmit breaks, the debugger has a chance of also failing. The number of events are minimal and easy to handle, so no biggy. 142 | /// - Reduces clutter in Tranzmit Events for the end user, so only their Events will be present. 143 | /// 144 | [ButtonGroup] 145 | void SubscribeToTranzmit() 146 | { 147 | UnsubscribeFromTranzmit(); 148 | 149 | if (Tranzmit != null) 150 | { 151 | Tranzmit.EventAdded += EventAdded; 152 | Tranzmit.EventDeleted += EventDeleted; 153 | Tranzmit.EventSent += EventReceived; 154 | } 155 | else 156 | { 157 | Debug.Log("No Instance of Tranzmit has been found!\nTranzmit Graph will not be generated"); 158 | } 159 | } 160 | 161 | // ----------------------------------------------------------------------------------------- 162 | 163 | /// 164 | /// Unsubscribes from Tranzmits in-built events that are aimed for use by the debug tool, or any other tool the user might create. 165 | /// See above for further details on why this approach has been taken. 166 | /// 167 | [ButtonGroup] 168 | void UnsubscribeFromTranzmit() 169 | { 170 | if (Tranzmit != null) 171 | { 172 | Tranzmit.EventAdded -= EventAdded; 173 | Tranzmit.EventDeleted -= EventDeleted; 174 | Tranzmit.EventSent -= EventReceived; 175 | } 176 | else 177 | { 178 | Debug.Log("No Instance of Tranzmit has been found!\nTranzmit Graph will not be generated"); 179 | } 180 | } 181 | 182 | // ----------------------------------------------------------------------------------------- 183 | 184 | /// 185 | /// A built-in Tranzmit Event sent by Tranzmit when an Event has been added to the Tranzmit Events Dictionary. 186 | /// 187 | /// The name of the event that was added to Tranzmit.Events 188 | public void EventAdded(Tranzmit.EventNames eventName) 189 | { 190 | // Reserved 191 | } 192 | 193 | // ----------------------------------------------------------------------------------------- 194 | 195 | /// 196 | /// A built-in Tranzmit Event sent by Tranzmit when an Event has been removed from the Tranzmit Events Dictionary. 197 | /// When received, Tranzmit Debug will auto remove an debug data associated with the Event Name. 198 | /// 199 | /// The name of the event that was removed from Tranzmit.Events 200 | public void EventDeleted(Tranzmit.EventNames eventName) 201 | { 202 | // Reserved 203 | } 204 | 205 | // ----------------------------------------------------------------------------------------- 206 | 207 | /// 208 | /// The business end of Tranzmit Debug. When Tranzmit ATTEMPTS to send an event, it also broadcasts information about it. This is sent regardless of whether the requested Tranzmit Event was valid and sent. 209 | /// It creates and saves the associated data. Notice that we store the button information in here. This allows for more efficient updating of the Graphview. 210 | /// 211 | /// The object that requested for a Tranzmit event to be sent. Can be Null 212 | /// A basic 'Success' or 'Failed' output. 213 | /// A list of Enums that will show ALL issues (if any) with the Tranzmit Event Send request. 214 | /// The name of the Tranzmit Event. 215 | /// The data type specified by the user when they configured the Tranzmit Event. 216 | /// The type of data the user actually attached to the event. Can be Null. 217 | /// The Event/Delegate of the Tranzmit Event. 218 | public void EventReceived(object payload, object source, Tranzmit.DeliveryStatuses status, List errors, Tranzmit.EventNames eventName, Type requiredDataType, Type providedDataType, Tranzmit.EventData.TranzmitDelegate tranzmitDelegate) 219 | { 220 | var logData = DebugLog[eventName]; 221 | 222 | if (SequentialLogEnabled) 223 | { 224 | GenerateNewSequentialLog(eventName, payload, source, status, errors); 225 | } 226 | 227 | if (SequentialLogEnabled) 228 | { 229 | GenerateDebugLog(logData, payload, source, status, errors, eventName); 230 | } 231 | } 232 | 233 | // ----------------------------------------------------------------------------------------- 234 | 235 | [Button] 236 | public void InitializeDebugLog() 237 | { 238 | if (Tranzmit != null) 239 | { 240 | // SEQUENTIAL LOG 241 | if (SequentialLog == null) 242 | { 243 | SequentialLog = new List(); 244 | } 245 | else 246 | { 247 | SequentialLog.Clear(); 248 | } 249 | 250 | // DEBUG LOG 251 | if (DebugLog == null) 252 | { 253 | DebugLog = new Dictionary(); 254 | } 255 | else 256 | { 257 | DebugLog.Clear(); 258 | } 259 | 260 | foreach (KeyValuePair tranzmitEvent in Tranzmit.Events) 261 | { 262 | DebugLog.Add(tranzmitEvent.Key, new LogData(){ Subscribers = tranzmitEvent.Value.GetSubscribers()}); 263 | } 264 | } 265 | } 266 | 267 | // ----------------------------------------------------------------------------------------- 268 | 269 | public void GenerateNewSequentialLog(Tranzmit.EventNames eventName, object payload, object source, Tranzmit.DeliveryStatuses status, List errors) 270 | { 271 | if (SequentialLogErrorsOnly == true && status == Tranzmit.DeliveryStatuses.Success) 272 | { 273 | return; 274 | } 275 | 276 | var subscribers = Tranzmit.Events[eventName].GetSubscribers().Select(x => x.Target).ToList(); 277 | 278 | var payloadJSON = ""; 279 | 280 | if (SequentialLogStorePayloads) 281 | { 282 | payloadJSON = System.Text.Encoding.Default.GetString(SerializationUtility.SerializeValue(payload, DataFormat.JSON)); 283 | 284 | if (SequentialLogValuesOnlyPayloads) 285 | { 286 | payloadJSON = payloadJSON.Substring(payloadJSON.IndexOf(",") + 1); 287 | payloadJSON = payloadJSON.Substring(payloadJSON.IndexOf(",") + 1); 288 | payloadJSON = payloadJSON.Substring(payloadJSON.IndexOf(",") + 1); 289 | payloadJSON = payloadJSON.Replace(" ", ""); 290 | payloadJSON = payloadJSON.Replace("}", ""); 291 | } 292 | } 293 | 294 | var logStats = new SequentialGeneralData(); 295 | logStats.FrameNumber = Time.frameCount; 296 | logStats.Broadcaster = source; 297 | logStats.EventName = eventName; 298 | logStats.DeliveryStatus = status; 299 | logStats.Errors = errors; 300 | 301 | var logData = new SequentialLogData() {General = logStats, Subscribers = subscribers, Payload = payloadJSON}; 302 | 303 | SequentialLog.Add(logData); 304 | TranzmitDebugV2UI.Instance.AddNewEvent(logData); 305 | } 306 | 307 | // ----------------------------------------------------------------------------------------- 308 | 309 | public void GenerateDebugLog(LogData logData, object payload, object source, Tranzmit.DeliveryStatuses status, List errors, Tranzmit.EventNames eventName) 310 | { 311 | // Success 312 | if (status == Tranzmit.DeliveryStatuses.Success) 313 | { 314 | logData.Success.Count++; 315 | UpdateBroadcaster(source, logData.Success); 316 | 317 | if (DebugLogStorePayloads) 318 | { 319 | var result = SerializationUtility.SerializeValue(payload, DataFormat.JSON); 320 | logData.Success.Payloads.Add(System.Text.Encoding.Default.GetString(result)); 321 | } 322 | } 323 | 324 | // Failed: NOTE...Error Type "NoSubscribers" will not trigger Debug. 325 | if (status == Tranzmit.DeliveryStatuses.Failed) 326 | { 327 | foreach (var error in errors) 328 | { 329 | if (error == Tranzmit.Errors.MissingPayload) 330 | { 331 | logData.MissingPayload.Count++; 332 | UpdateBroadcaster(source, logData.MissingPayload); 333 | 334 | if (DebugLogStorePayloads) 335 | { 336 | var result = SerializationUtility.SerializeValue(payload, DataFormat.JSON); 337 | logData.MissingPayload.Payloads.Add(System.Text.Encoding.Default.GetString(result)); 338 | } 339 | } 340 | 341 | if (error == Tranzmit.Errors.MissingSource) 342 | { 343 | logData.MissingSource.Count++; 344 | UpdateBroadcaster(source, logData.MissingSource); 345 | 346 | if (DebugLogStorePayloads) 347 | { 348 | var result = SerializationUtility.SerializeValue(payload, DataFormat.JSON); 349 | logData.MissingSource.Payloads.Add(System.Text.Encoding.Default.GetString(result)); 350 | } 351 | } 352 | 353 | if (error == Tranzmit.Errors.WrongDataType) 354 | { 355 | logData.WrongDataType.Count++; 356 | UpdateBroadcaster(source, logData.WrongDataType); 357 | 358 | if (DebugLogStorePayloads) 359 | { 360 | var result = SerializationUtility.SerializeValue(payload, DataFormat.JSON); 361 | logData.WrongDataType.Payloads.Add(System.Text.Encoding.Default.GetString(result)); 362 | } 363 | } 364 | } 365 | } 366 | } 367 | 368 | // ----------------------------------------------------------------------------------------- 369 | 370 | public void UpdateBroadcaster(object source, LogStats logStats) 371 | { 372 | if (source != null) 373 | { 374 | var broadcaster = logStats.Sources.Find(x => x == source); 375 | 376 | if (broadcaster == null) 377 | { 378 | logStats.Sources.Add(source); 379 | } 380 | } 381 | else 382 | { 383 | logStats.NullSources++; 384 | } 385 | } 386 | 387 | // ----------------------------------------------------------------------------------------- 388 | 389 | public int GetErrorsCount() 390 | { 391 | int count = 0; 392 | 393 | foreach(KeyValuePair entry in DebugLog) 394 | { 395 | count += entry.Value.MissingPayload.Count; 396 | count += entry.Value.MissingSource.Count; 397 | count += entry.Value.WrongDataType.Count; 398 | } 399 | 400 | return count; 401 | } 402 | } 403 | } -------------------------------------------------------------------------------- /Debug V2/Code/TranzmitDebugV2UI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using Blep.Tranzmit; 7 | using Blep.Tranzmit.Demo; 8 | using Sirenix.OdinInspector; 9 | using TMPro; 10 | using UnityEngine; 11 | using UnityEngine.Serialization; 12 | using UnityEngine.UI; 13 | 14 | public class TranzmitDebugV2UI : SerializedMonoBehaviour 15 | { 16 | public static TranzmitDebugV2UI Instance; 17 | 18 | [BoxGroup("CONFIG")] public bool IsEnabled = true; 19 | [BoxGroup("CONFIG")] public bool NewAtTop = true; 20 | [BoxGroup("CONFIG")] public bool FilterEnabled; 21 | 22 | [BoxGroup("FILTER")][HideLabel] public FilterData Filter; 23 | 24 | [BoxGroup("REQUIRED")][Required] public Tranzmit Tranzmit; 25 | [BoxGroup("REQUIRED")][Required] public TranzmitDebugV2 TranzmitDebugV2; 26 | [BoxGroup("REQUIRED")][Required] public GameObject DebugItemPrefab; 27 | [BoxGroup("REQUIRED")][Required] public RectTransform DebugScroll; 28 | [BoxGroup("REQUIRED")][Required] public RectTransform DebugScrollContent; 29 | [BoxGroup("REQUIRED")][Required] public RectTransform SelectorModal; 30 | [BoxGroup("REQUIRED")][Required] public RectTransform SelectorScrollContent; 31 | [BoxGroup("REQUIRED")][Required] public GameObject SelectorButtonPrefab; 32 | [BoxGroup("REQUIRED")][Required] public TMP_Text EventCountText; 33 | [BoxGroup("REQUIRED")][Required] public TMP_Text ErrorsCountText; 34 | [BoxGroup("REQUIRED")][Required] public TMP_Text FilterInfo; 35 | 36 | [BoxGroup("BUTTONS")][Required] public Button CollapseButton; 37 | [BoxGroup("BUTTONS")][Required] public Button ClearButton; 38 | [BoxGroup("BUTTONS")][Required] public Button ResetFilter; 39 | [BoxGroup("BUTTONS")][Required] public Button ModalCloseButton; 40 | 41 | [BoxGroup("TOGGLES")][Required] public Toggle EnabledToggle; 42 | [BoxGroup("TOGGLES")][Required] public Toggle ErrorsOnlyToggle; 43 | [BoxGroup("TOGGLES")][Required] public Toggle StorePayloadsToggle; 44 | [BoxGroup("TOGGLES")][Required] public Toggle PayloadValuesOnly; 45 | 46 | [BoxGroup("DATA")][ReadOnly] public bool FilterChanged; 47 | [BoxGroup("DATA")][ReadOnly] public List DebugLUT = new List(); 48 | [BoxGroup("DATA")][ReadOnly] public List FilteredList = new List(); 49 | 50 | 51 | // private FilterData PreviousFilter; 52 | 53 | [Serializable] 54 | public class DebugLUTData 55 | { 56 | public TranzmitDebugV2.SequentialLogData Log; 57 | public TranzmitDebugV2UIItemLocal TranzmitDebugV2UIItemLocal; 58 | } 59 | 60 | [ShowOdinSerializedPropertiesInInspector] 61 | [HideReferenceObjectPicker] 62 | public class FilterData 63 | { 64 | public int FrameNumber; 65 | public Tranzmit.EventNames EventName; 66 | public Tranzmit.DeliveryStatuses DeliveryStatus; 67 | public Tranzmit.Errors Error; 68 | public object Broadcaster; 69 | public object Subscriber; 70 | 71 | public void Reset() 72 | { 73 | FrameNumber = 0; 74 | EventName = Tranzmit.EventNames.None; 75 | DeliveryStatus = Tranzmit.DeliveryStatuses.None; 76 | Error = Tranzmit.Errors.None; 77 | Broadcaster = null; 78 | Subscriber = null; 79 | } 80 | 81 | public string GenerateFilterInfo() 82 | { 83 | var result = ""; 84 | 85 | if (FrameNumber != 0) 86 | { 87 | result += $"[ Frame Number: {FrameNumber} ] "; 88 | } 89 | 90 | if (Broadcaster != null) 91 | { 92 | result += $"[ Broadcaster: {Broadcaster.ToString()} ] "; 93 | } 94 | 95 | if (Subscriber != null) 96 | { 97 | result += $"[ Subscriber: {Subscriber.ToString()} ] "; 98 | } 99 | 100 | if (EventName != Tranzmit.EventNames.None) 101 | { 102 | result += $"[ Event Name: {EventName.ToString()} ] "; 103 | } 104 | 105 | if (DeliveryStatus != Tranzmit.DeliveryStatuses.None) 106 | { 107 | result += $"[ Delivery Status: {DeliveryStatus.ToString()} ] "; 108 | } 109 | 110 | if (Error != Tranzmit.Errors.None) 111 | { 112 | result += $"[ Error: {Error.ToString()} ] "; 113 | } 114 | 115 | return result; 116 | } 117 | } 118 | 119 | // ----------------------------------------------------------------------------------------- 120 | 121 | private void Awake() 122 | { 123 | Instance = this; 124 | 125 | SelectorModal.gameObject.SetActive(false); 126 | 127 | CollapseButton.onClick.AddListener(Collapse); 128 | ClearButton.onClick.AddListener(ClearLogDataClicked); 129 | ResetFilter.onClick.AddListener(ResetFilterClicked); 130 | ModalCloseButton.onClick.AddListener(ModalClose); 131 | 132 | EnabledToggle.onValueChanged.AddListener(EnableToggleChanged); 133 | ErrorsOnlyToggle.onValueChanged.AddListener(ErrorsOnlyToggleChanged); 134 | StorePayloadsToggle.onValueChanged.AddListener(StorePayloadsToggleChanged); 135 | PayloadValuesOnly.onValueChanged.AddListener(PayloadValuesOnlyChanged); 136 | } 137 | 138 | // ----------------------------------------------------------------------------------------- 139 | 140 | private void Start() 141 | { 142 | EnabledToggle.isOn = TranzmitDebugV2.Instance.enabled; 143 | ErrorsOnlyToggle.isOn = TranzmitDebugV2.Instance.SequentialLogErrorsOnly; 144 | StorePayloadsToggle.isOn = TranzmitDebugV2.Instance.SequentialLogStorePayloads; 145 | PayloadValuesOnly.isOn = TranzmitDebugV2.Instance.SequentialLogValuesOnlyPayloads; 146 | } 147 | 148 | // ----------------------------------------------------------------------------------------- 149 | 150 | public void OnDestroy() 151 | { 152 | CollapseButton.onClick.RemoveListener(Collapse); 153 | ClearButton.onClick.RemoveListener(ClearLogDataClicked); 154 | ResetFilter.onClick.RemoveListener(ResetFilterClicked); 155 | ModalCloseButton.onClick.RemoveListener(ModalClose); 156 | 157 | EnabledToggle.onValueChanged.RemoveListener(EnableToggleChanged); 158 | ErrorsOnlyToggle.onValueChanged.RemoveListener(ErrorsOnlyToggleChanged); 159 | StorePayloadsToggle.onValueChanged.RemoveListener(StorePayloadsToggleChanged); 160 | PayloadValuesOnly.onValueChanged.RemoveListener(PayloadValuesOnlyChanged); 161 | } 162 | 163 | // ----------------------------------------------------------------------------------------- 164 | 165 | private void Update() 166 | { 167 | if (FilterChanged) 168 | { 169 | FilterChanged = false; 170 | FilterRefresh(); 171 | } 172 | } 173 | 174 | // ----------------------------------------------------------------------------------------- 175 | 176 | public void AddNewEvent(TranzmitDebugV2.SequentialLogData log) 177 | { 178 | log.General.UIElement = Instantiate(DebugItemPrefab); 179 | log.General.UIElement.transform.SetParent(DebugScrollContent); 180 | 181 | if (NewAtTop) 182 | { 183 | log.General.UIElement.transform.SetAsFirstSibling(); 184 | } 185 | 186 | log.General.UIElement.name = $"{log.General.FrameNumber}-{log.General.EventName}-{log.General.DeliveryStatus}"; 187 | 188 | var local = log.General.UIElement.GetComponent(); 189 | local.Log = log; 190 | 191 | // Status 192 | ColorBlock cb = local.Status.colors; 193 | cb.normalColor = log.General.StatusColor(); 194 | local.Status.colors = cb; 195 | 196 | // Frame Number 197 | local.FrameNumberText.text = log.General.FrameNumber.ToString(); 198 | 199 | // Event Name 200 | local.EventNameText.text = log.General.EventName.ToString(); 201 | 202 | // Broadcaster 203 | if (log.General.Broadcaster != null) 204 | { 205 | local.BroadcastorText.text = log.General.Broadcaster.ToString(); 206 | } 207 | else 208 | { 209 | ColorBlock broadcasterButtonColors = local.Status.colors; 210 | broadcasterButtonColors.normalColor = new Color(0.1226415f, 0.007520473f, 0.007520473f, 1f); 211 | local.Broadcastor.colors = broadcasterButtonColors; 212 | local.BroadcastorText.text = "Broadcaster Missing"; 213 | } 214 | 215 | // Subscribers 216 | if (log.Subscribers.Count > 0) 217 | { 218 | local.SubscribersText.text = $"Subscribers ({log.Subscribers.Count})"; 219 | } 220 | else 221 | { 222 | local.Errors.interactable = false; 223 | local.SubscribersText.text = $"No Subscribers"; 224 | } 225 | 226 | // Errors 227 | if (log.General.Errors.Count > 0) 228 | { 229 | ColorBlock errorsButtonColorBlock = local.Errors.colors; 230 | errorsButtonColorBlock.normalColor = new Color(0.1226415f, 0.007520473f, 0.007520473f, 1f); 231 | local.Errors.colors = errorsButtonColorBlock; 232 | local.ErrorsText.text = $"Errors ({log.General.Errors.Count})"; 233 | } 234 | else 235 | { 236 | local.Errors.interactable = false; 237 | local.ErrorsText.text = $"No Errors"; 238 | } 239 | 240 | // Payload 241 | if (TranzmitDebugV2.SequentialLogStorePayloads) 242 | { 243 | local.Payload.text = log.Payload.Replace("\n", "").Replace("\r", " || "); 244 | } 245 | else 246 | { 247 | local.Payload.text = ""; 248 | } 249 | 250 | DebugLUT.Add(new DebugLUTData(){TranzmitDebugV2UIItemLocal = local, Log = log}); 251 | 252 | FilterRefresh(); 253 | } 254 | 255 | // ----------------------------------------------------------------------------------------- 256 | 257 | [Button] 258 | public void FilterRefresh() 259 | { 260 | // Initial List 261 | FilteredList = DebugLUT; 262 | 263 | // Set all to inactive 264 | foreach (var show in FilteredList) 265 | { 266 | show.Log.General.UIElement.SetActive(false); 267 | } 268 | 269 | // Delivery Status 270 | if (Filter.DeliveryStatus != Tranzmit.DeliveryStatuses.None) 271 | { 272 | FilteredList = FilteredList.Where(x => x.Log.General.DeliveryStatus == Filter.DeliveryStatus).ToList(); 273 | } 274 | 275 | // Frame Number 276 | if (Filter.FrameNumber != 0) 277 | { 278 | FilteredList = FilteredList.Where(x => x.Log.General.FrameNumber == Filter.FrameNumber).ToList(); 279 | } 280 | 281 | // Broadcaster 282 | if (Filter.Broadcaster != null) 283 | { 284 | FilteredList = FilteredList.Where(x => x.Log.General.Broadcaster == Filter.Broadcaster).ToList(); 285 | } 286 | 287 | // Subscriber 288 | if (Filter.Subscriber != null) 289 | { 290 | FilteredList = FilteredList.Where(x => x.Log.Subscribers.Contains(Filter.Subscriber)).ToList(); 291 | } 292 | 293 | // Error 294 | if (Filter.Error != Tranzmit.Errors.None) 295 | { 296 | FilteredList = FilteredList.Where(x => x.Log.General.Errors.Contains(Filter.Error)).ToList(); 297 | } 298 | 299 | // Event Name 300 | if (Filter.EventName != Tranzmit.EventNames.None) 301 | { 302 | FilteredList = FilteredList.Where(x => x.Log.General.EventName == Filter.EventName).ToList(); 303 | } 304 | 305 | // Apply 306 | foreach (var show in FilteredList) 307 | { 308 | show.Log.General.UIElement.SetActive(true); 309 | } 310 | 311 | // Text Update 312 | TextFieldsUpdate(); 313 | } 314 | 315 | // ----------------------------------------------------------------------------------------- 316 | 317 | public void ShowSubscribers(List objects) 318 | { 319 | foreach (Transform child in SelectorScrollContent.transform) 320 | { 321 | Destroy(child.gameObject); 322 | } 323 | 324 | if (objects.Count > 0) 325 | { 326 | foreach (var o in objects) 327 | { 328 | var button = Instantiate(SelectorButtonPrefab); 329 | button.transform.SetParent(SelectorScrollContent); 330 | button.transform.name = o.ToString(); 331 | 332 | var local = button.GetComponent(); 333 | local.Buttontext.text = o.ToString(); 334 | local.ButtonType = TranzmitDebugV2UISelectorButtonLocal.ButtonTypes.Subscriber; 335 | local.Subscriber = o; 336 | 337 | if (o == Filter.Subscriber) 338 | { 339 | ColorBlock broadcasterButtonColors = local.Button.colors; 340 | broadcasterButtonColors.normalColor = Color.yellow; 341 | local.Buttontext.color = Color.black; 342 | local.Button.colors = broadcasterButtonColors; 343 | } 344 | } 345 | } 346 | 347 | SelectorModal.gameObject.SetActive(true); 348 | } 349 | 350 | // ----------------------------------------------------------------------------------------- 351 | 352 | public void CloseSelectionModal() 353 | { 354 | SelectorModal.gameObject.SetActive(false); 355 | } 356 | 357 | // ----------------------------------------------------------------------------------------- 358 | 359 | public void ShowErrors(List errors) 360 | { 361 | foreach (Transform child in SelectorScrollContent.transform) 362 | { 363 | Destroy(child.gameObject); 364 | } 365 | 366 | if (errors.Count > 0) 367 | { 368 | foreach (var error in errors) 369 | { 370 | var button = Instantiate(SelectorButtonPrefab); 371 | button.transform.SetParent(SelectorScrollContent); 372 | button.transform.name = error.ToString(); 373 | 374 | var local = button.GetComponent(); 375 | local.Buttontext.text = error.ToString(); 376 | local.ButtonType = TranzmitDebugV2UISelectorButtonLocal.ButtonTypes.Error; 377 | local.Error = error; 378 | 379 | if (error == Filter.Error) 380 | { 381 | ColorBlock errorButtonColors = local.Button.colors; 382 | errorButtonColors.normalColor = Color.yellow; 383 | local.Buttontext.color = Color.black; 384 | local.Button.colors = errorButtonColors; 385 | } 386 | } 387 | } 388 | 389 | SelectorModal.gameObject.SetActive(true); 390 | } 391 | 392 | // ----------------------------------------------------------------------------------------- 393 | 394 | public void ClearLogDataClicked() 395 | { 396 | foreach (Transform child in DebugScrollContent.transform) 397 | { 398 | Destroy(child.gameObject); 399 | } 400 | 401 | DebugLUT.Clear(); 402 | TranzmitDebugV2.Instance.InitializeDebugLog(); 403 | TextFieldsUpdate(); 404 | } 405 | 406 | // ----------------------------------------------------------------------------------------- 407 | 408 | public void ModalClose() 409 | { 410 | CloseSelectionModal(); 411 | } 412 | 413 | // ----------------------------------------------------------------------------------------- 414 | 415 | public void ResetFilterClicked() 416 | { 417 | Filter = new FilterData(); 418 | FilterRefresh(); 419 | } 420 | 421 | // ----------------------------------------------------------------------------------------- 422 | 423 | public void Collapse() 424 | { 425 | DebugScrollContent.gameObject.SetActive(!DebugScrollContent.gameObject.activeSelf); 426 | } 427 | 428 | // ----------------------------------------------------------------------------------------- 429 | 430 | [Button] 431 | public void TextFieldsUpdate() 432 | { 433 | StartCoroutine(Go()); 434 | 435 | IEnumerator Go() 436 | { 437 | // Allow for UI to refresh! 438 | yield return null; 439 | FilterInfo.text = Filter.GenerateFilterInfo(); 440 | EventCountText.text = $"[{ChildCountActive(DebugScrollContent)} / {DebugScrollContent.childCount}]"; 441 | ErrorsCountText.text = $"[{TranzmitDebugV2.Instance.GetErrorsCount()}]"; 442 | } 443 | } 444 | 445 | // ----------------------------------------------------------------------------------------- 446 | 447 | public static int ChildCountActive( Transform target ) 448 | { 449 | int result = 0; 450 | 451 | foreach(Transform t in target) 452 | { 453 | if (t.gameObject.activeSelf) 454 | { 455 | result++; 456 | } 457 | } 458 | 459 | return result; 460 | } 461 | 462 | // ----------------------------------------------------------------------------------------- 463 | 464 | public void EnableToggleChanged(bool status) 465 | { 466 | TranzmitDebugV2.Instance.SequentialLogEnabled = status; 467 | } 468 | 469 | // ----------------------------------------------------------------------------------------- 470 | 471 | public void ErrorsOnlyToggleChanged(bool status) 472 | { 473 | TranzmitDebugV2.Instance.SequentialLogErrorsOnly = status; 474 | } 475 | 476 | // ----------------------------------------------------------------------------------------- 477 | 478 | public void StorePayloadsToggleChanged(bool status) 479 | { 480 | TranzmitDebugV2.Instance.SequentialLogStorePayloads = status; 481 | } 482 | 483 | // ----------------------------------------------------------------------------------------- 484 | 485 | public void PayloadValuesOnlyChanged(bool status) 486 | { 487 | TranzmitDebugV2.Instance.SequentialLogValuesOnlyPayloads = status; 488 | } 489 | } -------------------------------------------------------------------------------- /Debug V2/Code/TranzmitDebugV2UIItemLocal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Blep.Tranzmit; 5 | using Sirenix.OdinInspector; 6 | using TMPro; 7 | using UnityEngine; 8 | using UnityEngine.UIElements; 9 | using UnityEngine.UI; 10 | 11 | public class TranzmitDebugV2UIItemLocal : MonoBehaviour 12 | { 13 | [Required] public UnityEngine.UI.Button Status; 14 | 15 | [Required] public UnityEngine.UI.Button FrameNumber; 16 | [Required] public TMP_Text FrameNumberText; 17 | 18 | [Required] public UnityEngine.UI.Button Broadcastor; 19 | [Required] public TMP_Text BroadcastorText; 20 | 21 | [Required] public UnityEngine.UI.Button Subscribers; 22 | [Required] public TMP_Text SubscribersText; 23 | 24 | [Required] public UnityEngine.UI.Button Errors; 25 | [Required] public TMP_Text ErrorsText; 26 | 27 | [Required] public UnityEngine.UI.Button EventName; 28 | [Required] public TMP_Text EventNameText; 29 | 30 | [Required] public TMP_Text Payload; 31 | 32 | [ReadOnly] public TranzmitDebugV2.SequentialLogData Log; 33 | 34 | // --------------------------------------------------------------------------- 35 | 36 | public void Start() 37 | { 38 | Status.onClick.AddListener(StatusButtonClicked); 39 | FrameNumber.onClick.AddListener(FrameButtonClicked); 40 | EventName.onClick.AddListener(EventNameButtonClicked); 41 | Broadcastor.onClick.AddListener(BroadcastorButtonClicked); 42 | Subscribers.onClick.AddListener(SubscribersButtonClicked); 43 | Errors.onClick.AddListener(ErrorsButtonClicked); 44 | } 45 | 46 | // --------------------------------------------------------------------------- 47 | 48 | public void OnDestroy() 49 | { 50 | Status.onClick.RemoveListener(StatusButtonClicked); 51 | FrameNumber.onClick.RemoveListener(FrameButtonClicked); 52 | EventName.onClick.RemoveListener(EventNameButtonClicked); 53 | Broadcastor.onClick.RemoveListener(BroadcastorButtonClicked); 54 | Subscribers.onClick.RemoveListener(SubscribersButtonClicked); 55 | Errors.onClick.RemoveListener(ErrorsButtonClicked); 56 | } 57 | 58 | // --------------------------------------------------------------------------- 59 | 60 | public void StatusButtonClicked() 61 | { 62 | if (TranzmitDebugV2UI.Instance.Filter.DeliveryStatus != Log.General.DeliveryStatus) 63 | { 64 | TranzmitDebugV2UI.Instance.Filter.DeliveryStatus = Log.General.DeliveryStatus; 65 | } 66 | else 67 | { 68 | TranzmitDebugV2UI.Instance.Filter.DeliveryStatus = Tranzmit.DeliveryStatuses.None; 69 | } 70 | 71 | TranzmitDebugV2UI.Instance.FilterChanged = true; 72 | } 73 | 74 | // --------------------------------------------------------------------------- 75 | 76 | public void FrameButtonClicked() 77 | { 78 | if (TranzmitDebugV2UI.Instance.Filter.FrameNumber != Log.General.FrameNumber) 79 | { 80 | TranzmitDebugV2UI.Instance.Filter.FrameNumber = Log.General.FrameNumber; 81 | } 82 | else 83 | { 84 | TranzmitDebugV2UI.Instance.Filter.FrameNumber = 0; 85 | } 86 | 87 | TranzmitDebugV2UI.Instance.FilterChanged = true; 88 | } 89 | 90 | // --------------------------------------------------------------------------- 91 | 92 | public void BroadcastorButtonClicked() 93 | { 94 | if (TranzmitDebugV2UI.Instance.Filter.Broadcaster != Log.General.Broadcaster) 95 | { 96 | TranzmitDebugV2UI.Instance.Filter.Broadcaster = Log.General.Broadcaster; 97 | } 98 | else 99 | { 100 | TranzmitDebugV2UI.Instance.Filter.Broadcaster = null; 101 | } 102 | 103 | TranzmitDebugV2UI.Instance.FilterChanged = true; 104 | } 105 | 106 | // --------------------------------------------------------------------------- 107 | 108 | public void SubscribersButtonClicked() 109 | { 110 | if (Log.Subscribers.Count > 0) 111 | { 112 | TranzmitDebugV2UI.Instance.ShowSubscribers(Log.Subscribers); 113 | } 114 | } 115 | 116 | // --------------------------------------------------------------------------- 117 | 118 | public void ErrorsButtonClicked() 119 | { 120 | if (Log.General.Errors.Count > 0) 121 | { 122 | TranzmitDebugV2UI.Instance.ShowErrors(Log.General.Errors); 123 | } 124 | } 125 | 126 | // --------------------------------------------------------------------------- 127 | 128 | public void EventNameButtonClicked() 129 | { 130 | if (TranzmitDebugV2UI.Instance.Filter.EventName != Log.General.EventName) 131 | { 132 | TranzmitDebugV2UI.Instance.Filter.EventName = Log.General.EventName; 133 | } 134 | else 135 | { 136 | TranzmitDebugV2UI.Instance.Filter.EventName = Tranzmit.EventNames.None; 137 | } 138 | 139 | TranzmitDebugV2UI.Instance.FilterChanged = true; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Debug V2/Code/TranzmitDebugV2UISelectorButtonLocal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Blep.Tranzmit; 5 | using Sirenix.OdinInspector; 6 | using TMPro; 7 | using UnityEngine; 8 | using UnityEngine.UI; 9 | 10 | public class TranzmitDebugV2UISelectorButtonLocal : SerializedMonoBehaviour 11 | { 12 | [Required] public Button Button; 13 | [Required] public TMP_Text Buttontext; 14 | public ButtonTypes ButtonType; 15 | public object Subscriber; 16 | public Tranzmit.Errors Error; 17 | 18 | // ----------------------------------------------------------------------------------------- 19 | 20 | public enum ButtonTypes { None, Subscriber, Error } 21 | 22 | // ----------------------------------------------------------------------------------------- 23 | 24 | public void Awake() 25 | { 26 | Button.onClick.AddListener(ButtonClicked); 27 | } 28 | 29 | // ----------------------------------------------------------------------------------------- 30 | 31 | public void OnDestroy() 32 | { 33 | Button.onClick.RemoveListener(ButtonClicked); 34 | } 35 | 36 | // ----------------------------------------------------------------------------------------- 37 | 38 | public void ButtonClicked() 39 | { 40 | if (ButtonType == ButtonTypes.Subscriber) 41 | { 42 | if (TranzmitDebugV2UI.Instance.Filter.Subscriber != Subscriber) 43 | { 44 | TranzmitDebugV2UI.Instance.Filter.Subscriber = Subscriber; 45 | } 46 | else 47 | { 48 | TranzmitDebugV2UI.Instance.Filter.Subscriber = null; 49 | } 50 | 51 | TranzmitDebugV2UI.Instance.CloseSelectionModal(); 52 | TranzmitDebugV2UI.Instance.FilterChanged = true; 53 | } 54 | 55 | if (ButtonType == ButtonTypes.Error) 56 | { 57 | if (TranzmitDebugV2UI.Instance.Filter.Error != Error) 58 | { 59 | TranzmitDebugV2UI.Instance.Filter.Error = Error; 60 | } 61 | else 62 | { 63 | TranzmitDebugV2UI.Instance.Filter.Error = Tranzmit.Errors.None; 64 | } 65 | 66 | TranzmitDebugV2UI.Instance.CloseSelectionModal(); 67 | TranzmitDebugV2UI.Instance.FilterChanged = true; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Debug V2/Prefabs/Selector Button.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &713957018937344053 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 713957018937344052} 12 | - component: {fileID: 713957018937344049} 13 | - component: {fileID: 713957018937344054} 14 | - component: {fileID: 713957018937344055} 15 | - component: {fileID: 6066834020172654781} 16 | m_Layer: 5 17 | m_Name: Selector Button 18 | m_TagString: Untagged 19 | m_Icon: {fileID: 0} 20 | m_NavMeshLayer: 0 21 | m_StaticEditorFlags: 0 22 | m_IsActive: 1 23 | --- !u!224 &713957018937344052 24 | RectTransform: 25 | m_ObjectHideFlags: 0 26 | m_CorrespondingSourceObject: {fileID: 0} 27 | m_PrefabInstance: {fileID: 0} 28 | m_PrefabAsset: {fileID: 0} 29 | m_GameObject: {fileID: 713957018937344053} 30 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 31 | m_LocalPosition: {x: 0, y: 0, z: 0} 32 | m_LocalScale: {x: 1, y: 1, z: 1} 33 | m_ConstrainProportionsScale: 0 34 | m_Children: 35 | - {fileID: 713957019088986686} 36 | m_Father: {fileID: 0} 37 | m_RootOrder: -1 38 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 39 | m_AnchorMin: {x: 0, y: 0} 40 | m_AnchorMax: {x: 0, y: 0} 41 | m_AnchoredPosition: {x: 0, y: 0} 42 | m_SizeDelta: {x: 0, y: 0} 43 | m_Pivot: {x: 0.5, y: 0.5} 44 | --- !u!222 &713957018937344049 45 | CanvasRenderer: 46 | m_ObjectHideFlags: 0 47 | m_CorrespondingSourceObject: {fileID: 0} 48 | m_PrefabInstance: {fileID: 0} 49 | m_PrefabAsset: {fileID: 0} 50 | m_GameObject: {fileID: 713957018937344053} 51 | m_CullTransparentMesh: 1 52 | --- !u!114 &713957018937344054 53 | MonoBehaviour: 54 | m_ObjectHideFlags: 0 55 | m_CorrespondingSourceObject: {fileID: 0} 56 | m_PrefabInstance: {fileID: 0} 57 | m_PrefabAsset: {fileID: 0} 58 | m_GameObject: {fileID: 713957018937344053} 59 | m_Enabled: 1 60 | m_EditorHideFlags: 0 61 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 62 | m_Name: 63 | m_EditorClassIdentifier: 64 | m_Material: {fileID: 0} 65 | m_Color: {r: 1, g: 1, b: 1, a: 1} 66 | m_RaycastTarget: 1 67 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 68 | m_Maskable: 1 69 | m_OnCullStateChanged: 70 | m_PersistentCalls: 71 | m_Calls: [] 72 | m_Sprite: {fileID: 0} 73 | m_Type: 1 74 | m_PreserveAspect: 0 75 | m_FillCenter: 1 76 | m_FillMethod: 4 77 | m_FillAmount: 1 78 | m_FillClockwise: 1 79 | m_FillOrigin: 0 80 | m_UseSpriteMesh: 0 81 | m_PixelsPerUnitMultiplier: 1 82 | --- !u!114 &713957018937344055 83 | MonoBehaviour: 84 | m_ObjectHideFlags: 0 85 | m_CorrespondingSourceObject: {fileID: 0} 86 | m_PrefabInstance: {fileID: 0} 87 | m_PrefabAsset: {fileID: 0} 88 | m_GameObject: {fileID: 713957018937344053} 89 | m_Enabled: 1 90 | m_EditorHideFlags: 0 91 | m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} 92 | m_Name: 93 | m_EditorClassIdentifier: 94 | m_Navigation: 95 | m_Mode: 0 96 | m_WrapAround: 0 97 | m_SelectOnUp: {fileID: 0} 98 | m_SelectOnDown: {fileID: 0} 99 | m_SelectOnLeft: {fileID: 0} 100 | m_SelectOnRight: {fileID: 0} 101 | m_Transition: 1 102 | m_Colors: 103 | m_NormalColor: {r: 0.24528301, g: 0.24528301, b: 0.24528301, a: 1} 104 | m_HighlightedColor: {r: 0.6409545, g: 0.7264151, b: 0, a: 1} 105 | m_PressedColor: {r: 0.6409545, g: 0.7264151, b: 0, a: 1} 106 | m_SelectedColor: {r: 0.1137255, g: 0.1137255, b: 0.1137255, a: 1} 107 | m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} 108 | m_ColorMultiplier: 1 109 | m_FadeDuration: 0.1 110 | m_SpriteState: 111 | m_HighlightedSprite: {fileID: 0} 112 | m_PressedSprite: {fileID: 0} 113 | m_SelectedSprite: {fileID: 0} 114 | m_DisabledSprite: {fileID: 0} 115 | m_AnimationTriggers: 116 | m_NormalTrigger: Normal 117 | m_HighlightedTrigger: Highlighted 118 | m_PressedTrigger: Pressed 119 | m_SelectedTrigger: Selected 120 | m_DisabledTrigger: Disabled 121 | m_Interactable: 1 122 | m_TargetGraphic: {fileID: 713957018937344054} 123 | m_OnClick: 124 | m_PersistentCalls: 125 | m_Calls: [] 126 | --- !u!114 &6066834020172654781 127 | MonoBehaviour: 128 | m_ObjectHideFlags: 0 129 | m_CorrespondingSourceObject: {fileID: 0} 130 | m_PrefabInstance: {fileID: 0} 131 | m_PrefabAsset: {fileID: 0} 132 | m_GameObject: {fileID: 713957018937344053} 133 | m_Enabled: 1 134 | m_EditorHideFlags: 0 135 | m_Script: {fileID: 11500000, guid: 90831ba2bd0ba464ba840a59d1c8fcbf, type: 3} 136 | m_Name: 137 | m_EditorClassIdentifier: 138 | serializationData: 139 | SerializedFormat: 2 140 | SerializedBytes: 141 | ReferencedUnityObjects: [] 142 | SerializedBytesString: 143 | Prefab: {fileID: 0} 144 | PrefabModificationsReferencedUnityObjects: [] 145 | PrefabModifications: [] 146 | SerializationNodes: 147 | - Name: Subscriber 148 | Entry: 6 149 | Data: 150 | Button: {fileID: 713957018937344055} 151 | Buttontext: {fileID: 713957019088986681} 152 | ButtonType: 0 153 | Error: 0 154 | --- !u!1 &713957019088986687 155 | GameObject: 156 | m_ObjectHideFlags: 0 157 | m_CorrespondingSourceObject: {fileID: 0} 158 | m_PrefabInstance: {fileID: 0} 159 | m_PrefabAsset: {fileID: 0} 160 | serializedVersion: 6 161 | m_Component: 162 | - component: {fileID: 713957019088986686} 163 | - component: {fileID: 713957019088986680} 164 | - component: {fileID: 713957019088986681} 165 | m_Layer: 5 166 | m_Name: Title 167 | m_TagString: Untagged 168 | m_Icon: {fileID: 0} 169 | m_NavMeshLayer: 0 170 | m_StaticEditorFlags: 0 171 | m_IsActive: 1 172 | --- !u!224 &713957019088986686 173 | RectTransform: 174 | m_ObjectHideFlags: 0 175 | m_CorrespondingSourceObject: {fileID: 0} 176 | m_PrefabInstance: {fileID: 0} 177 | m_PrefabAsset: {fileID: 0} 178 | m_GameObject: {fileID: 713957019088986687} 179 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 180 | m_LocalPosition: {x: 0, y: 0, z: 0} 181 | m_LocalScale: {x: 1, y: 1, z: 1} 182 | m_ConstrainProportionsScale: 0 183 | m_Children: [] 184 | m_Father: {fileID: 713957018937344052} 185 | m_RootOrder: -1 186 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 187 | m_AnchorMin: {x: 0, y: 0} 188 | m_AnchorMax: {x: 1, y: 1} 189 | m_AnchoredPosition: {x: 0, y: 0} 190 | m_SizeDelta: {x: 0, y: 0} 191 | m_Pivot: {x: 0.5, y: 0.5} 192 | --- !u!222 &713957019088986680 193 | CanvasRenderer: 194 | m_ObjectHideFlags: 0 195 | m_CorrespondingSourceObject: {fileID: 0} 196 | m_PrefabInstance: {fileID: 0} 197 | m_PrefabAsset: {fileID: 0} 198 | m_GameObject: {fileID: 713957019088986687} 199 | m_CullTransparentMesh: 1 200 | --- !u!114 &713957019088986681 201 | MonoBehaviour: 202 | m_ObjectHideFlags: 0 203 | m_CorrespondingSourceObject: {fileID: 0} 204 | m_PrefabInstance: {fileID: 0} 205 | m_PrefabAsset: {fileID: 0} 206 | m_GameObject: {fileID: 713957019088986687} 207 | m_Enabled: 1 208 | m_EditorHideFlags: 0 209 | m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} 210 | m_Name: 211 | m_EditorClassIdentifier: 212 | m_Material: {fileID: 0} 213 | m_Color: {r: 1, g: 1, b: 1, a: 1} 214 | m_RaycastTarget: 1 215 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 216 | m_Maskable: 1 217 | m_OnCullStateChanged: 218 | m_PersistentCalls: 219 | m_Calls: [] 220 | m_text: Errors (3) 221 | m_isRightToLeft: 0 222 | m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} 223 | m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} 224 | m_fontSharedMaterials: [] 225 | m_fontMaterial: {fileID: 0} 226 | m_fontMaterials: [] 227 | m_fontColor32: 228 | serializedVersion: 2 229 | rgba: 4294967295 230 | m_fontColor: {r: 1, g: 1, b: 1, a: 1} 231 | m_enableVertexGradient: 0 232 | m_colorMode: 3 233 | m_fontColorGradient: 234 | topLeft: {r: 1, g: 1, b: 1, a: 1} 235 | topRight: {r: 1, g: 1, b: 1, a: 1} 236 | bottomLeft: {r: 1, g: 1, b: 1, a: 1} 237 | bottomRight: {r: 1, g: 1, b: 1, a: 1} 238 | m_fontColorGradientPreset: {fileID: 0} 239 | m_spriteAsset: {fileID: 0} 240 | m_tintAllSprites: 0 241 | m_StyleSheet: {fileID: 0} 242 | m_TextStyleHashCode: -1183493901 243 | m_overrideHtmlColors: 0 244 | m_faceColor: 245 | serializedVersion: 2 246 | rgba: 4294967295 247 | m_fontSize: 12 248 | m_fontSizeBase: 12 249 | m_fontWeight: 400 250 | m_enableAutoSizing: 0 251 | m_fontSizeMin: 18 252 | m_fontSizeMax: 72 253 | m_fontStyle: 0 254 | m_HorizontalAlignment: 2 255 | m_VerticalAlignment: 512 256 | m_textAlignment: 65535 257 | m_characterSpacing: 0 258 | m_wordSpacing: 0 259 | m_lineSpacing: 0 260 | m_lineSpacingMax: 0 261 | m_paragraphSpacing: 0 262 | m_charWidthMaxAdj: 0 263 | m_enableWordWrapping: 1 264 | m_wordWrappingRatios: 0.4 265 | m_overflowMode: 1 266 | m_linkedTextComponent: {fileID: 0} 267 | parentLinkedComponent: {fileID: 0} 268 | m_enableKerning: 1 269 | m_enableExtraPadding: 0 270 | checkPaddingRequired: 0 271 | m_isRichText: 1 272 | m_parseCtrlCharacters: 1 273 | m_isOrthographic: 1 274 | m_isCullingEnabled: 0 275 | m_horizontalMapping: 0 276 | m_verticalMapping: 0 277 | m_uvLineOffset: 0 278 | m_geometrySortingOrder: 0 279 | m_IsTextObjectScaleStatic: 0 280 | m_VertexBufferAutoSizeReduction: 0 281 | m_useMaxVisibleDescender: 1 282 | m_pageToDisplay: 1 283 | m_margin: {x: 0, y: 0, z: 0, w: 0} 284 | m_isUsingLegacyAnimationComponent: 0 285 | m_isVolumetricText: 0 286 | m_hasFontAssetChanged: 0 287 | m_baseMaterial: {fileID: 0} 288 | m_maskOffset: {x: 0, y: 0, z: 0, w: 0} 289 | -------------------------------------------------------------------------------- /Debug V2/Textures/Close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-blep/Tranzmit/136233d34e741699f7309223d27b9bdfacf2ce77/Debug V2/Textures/Close.png -------------------------------------------------------------------------------- /Debug V2/Textures/Resize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-blep/Tranzmit/136233d34e741699f7309223d27b9bdfacf2ce77/Debug V2/Textures/Resize.png -------------------------------------------------------------------------------- /Debug/EventsSentUI.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using TMPro; 5 | 6 | namespace Blep.Tranzmit.Demo 7 | { 8 | public class EventsSentUI : MonoBehaviour 9 | { 10 | public TMP_Text TotalUI; 11 | public int Total = 0; 12 | 13 | // ----------------------------------------------------------------------------------------- 14 | 15 | void Update() 16 | { 17 | TotalUI.text = Total.ToString(); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Debug/Graph/Editor/Blackboard_Properties.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System; 5 | 6 | namespace Blep.Tranzmit 7 | { 8 | [Serializable] 9 | public class ColorProperty 10 | { 11 | public string PropertyName = "Color"; 12 | public Color PropertyValue = new Color(); 13 | } 14 | 15 | [Serializable] 16 | public class FloatProperty 17 | { 18 | public string PropertyName = "Float"; 19 | public float PropertyValue = 0; 20 | } 21 | 22 | [Serializable] 23 | public class Vector2Property 24 | { 25 | public string PropertyName = "Vector2"; 26 | public Vector2 PropertyValue = new Vector2(); 27 | } 28 | } -------------------------------------------------------------------------------- /Debug/Graph/Editor/Resources/Tranzmit_Graph.uss: -------------------------------------------------------------------------------- 1 | GridBackground { 2 | --grid-background-color: #282828; 3 | --line-color: rgba(193,196,192,0.1); 4 | --thick-line-color: rgba(193,196,192,0.1); 5 | --spacing: 10; 6 | } -------------------------------------------------------------------------------- /Debug/Graph/Editor/Tranzmit_Graph.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEditor.Experimental.GraphView; 3 | using UnityEditor.UIElements; 4 | using UnityEngine; 5 | using UnityEngine.UIElements; 6 | 7 | namespace Blep.Tranzmit 8 | { 9 | public class Tranzmit_Graph : EditorWindow 10 | { 11 | /// 12 | /// Hurrah for the video below. Pretty much the only concise resource at this time. 13 | /// I wanted to share/give credit so that others can start using this rather good UI! 14 | /// https://www.youtube.com/watch?v=7KHGH0fPL84 15 | /// 16 | 17 | // The reference to the graph that we will create 18 | public static Tranzmit_Graph_View _TranzmitGraphView; 19 | 20 | // 'Duration' and 'Done' are used to delay the update of the graph to allow the rest of Unity and Tranzmit to do their thing. 21 | private float Duration; 22 | private bool Done = false; 23 | 24 | // Menu Item to open the graph 25 | [MenuItem("Tranzmit/Tranzmit Graph")] 26 | public static void OpenTranzmitGraphWindow() 27 | { 28 | var window = GetWindow(); 29 | window.titleContent = new GUIContent("Tranzmit Graph"); 30 | } 31 | 32 | // ----------------------------------------------------------------------------------------- 33 | 34 | private void OnEnable() 35 | { 36 | Done = false; 37 | Subscribe(); 38 | 39 | EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; 40 | EditorApplication.playModeStateChanged += OnPlayModeStateChanged; 41 | } 42 | 43 | // ----------------------------------------------------------------------------------------- 44 | 45 | private void OnDisable() 46 | { 47 | //Remove from editor window 48 | rootVisualElement.Remove(_TranzmitGraphView); 49 | 50 | Unsubscribe(); 51 | 52 | EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; 53 | } 54 | 55 | // ----------------------------------------------------------------------------------------- 56 | 57 | private void OnPlayModeStateChanged(PlayModeStateChange state) 58 | { 59 | // Re-establish Graph View to work in Edit Mode 60 | if (state == PlayModeStateChange.EnteredEditMode) 61 | { 62 | _TranzmitGraphView.Generate(); 63 | Subscribe(); 64 | } 65 | } 66 | 67 | // ----------------------------------------------------------------------------------------- 68 | 69 | protected virtual void OnEditorUpdate() 70 | { 71 | // We delay the graph creation to allow ALL Subscribers to register. Ugly but effective. 72 | if (Duration > 0.01f && Done == false) 73 | { 74 | Done = true; 75 | 76 | ConstructGraphView(); 77 | GenerateBlackBoard(); 78 | GenerateToolbar(); 79 | } 80 | } 81 | 82 | // ----------------------------------------------------------------------------------------- 83 | 84 | /// 85 | /// Builds the Graph 86 | /// 87 | private void ConstructGraphView() 88 | { 89 | _TranzmitGraphView = new Tranzmit_Graph_View 90 | { 91 | // ASssign the name of the graph 92 | name = "Tranzmit Graph" 93 | }; 94 | 95 | GenerateMiniMap(); 96 | 97 | // Stretch the graphview fully over editor window 98 | _TranzmitGraphView.StretchToParentSize(); 99 | 100 | //Add to the editor window 101 | rootVisualElement.Add(_TranzmitGraphView); 102 | 103 | Subscribe(); 104 | } 105 | 106 | // ----------------------------------------------------------------------------------------- 107 | 108 | /// 109 | /// Subscribe to the in-built Tranzmit Events 110 | /// 111 | public void Subscribe() 112 | { 113 | // Play it safe! 114 | Unsubscribe(); 115 | 116 | if (_TranzmitGraphView != null && _TranzmitGraphView.Tranzmit != null) 117 | { 118 | _TranzmitGraphView.Tranzmit.EventAdded += _TranzmitGraphView.EventAdded; 119 | _TranzmitGraphView.Tranzmit.EventDeleted += _TranzmitGraphView.EventDeleted; 120 | _TranzmitGraphView.Tranzmit.TranzmitDebugReset += _TranzmitGraphView.EventTranzmitDebugReset; 121 | _TranzmitGraphView.Tranzmit.TranzmitDebugLogUpdated += _TranzmitGraphView.TranzmitDebugLogUpdated; 122 | } 123 | 124 | #if UNITY_EDITOR 125 | Duration = Time.realtimeSinceStartup; 126 | EditorApplication.update += OnEditorUpdate; 127 | #endif 128 | } 129 | 130 | // ----------------------------------------------------------------------------------------- 131 | 132 | /// 133 | /// Unsubscribe to the in-built Tranzmit Events 134 | /// 135 | public void Unsubscribe() 136 | { 137 | // Unsubcribe from event 138 | if (_TranzmitGraphView != null && _TranzmitGraphView.Tranzmit != null) 139 | { 140 | _TranzmitGraphView.Tranzmit.EventAdded -= _TranzmitGraphView.EventAdded; 141 | _TranzmitGraphView.Tranzmit.EventDeleted -= _TranzmitGraphView.EventDeleted; 142 | _TranzmitGraphView.Tranzmit.TranzmitDebugReset -= _TranzmitGraphView.EventTranzmitDebugReset; 143 | _TranzmitGraphView.Tranzmit.TranzmitDebugLogUpdated -= _TranzmitGraphView.TranzmitDebugLogUpdated; 144 | } 145 | 146 | #if UNITY_EDITOR 147 | EditorApplication.update -= OnEditorUpdate; 148 | #endif 149 | } 150 | 151 | // ----------------------------------------------------------------------------------------- 152 | 153 | /// 154 | /// used to create the floating 'in Gapgh' minimap for easy naviagtion when there are lots of nodes. 155 | /// 156 | private void GenerateMiniMap() 157 | { 158 | var miniMap = new MiniMap { anchored = false }; 159 | var cords = _TranzmitGraphView.contentViewContainer.WorldToLocal(new Vector2(this.maxSize.x -10, 32)); 160 | miniMap.SetPosition(new Rect(cords.x, cords.y, 200, 140)); 161 | _TranzmitGraphView.Add(miniMap); 162 | } 163 | 164 | // ----------------------------------------------------------------------------------------- 165 | 166 | /// 167 | /// Generate the toolbar found at the top of the graph. 168 | /// 169 | private void GenerateToolbar() 170 | { 171 | var toolbar = new Toolbar(); 172 | 173 | var buildButton = new Button(clickEvent: () => { _TranzmitGraphView.Generate(); Subscribe(); }); 174 | buildButton.text = "BUILD / REFRESH"; 175 | toolbar.Add(buildButton); 176 | 177 | var verticalButton = new Button(clickEvent: () => { 178 | _TranzmitGraphView.Arrange_Subscriber_Results(Tranzmit_Graph_View.ArrangementTypes.Vertical); 179 | _TranzmitGraphView.Arrange_Broadcaster_Results(Tranzmit_Graph_View.ArrangementTypes.Vertical); 180 | }); 181 | verticalButton.text = "Vertical"; 182 | toolbar.Add(verticalButton); 183 | 184 | var gridButton = new Button(clickEvent: () => { 185 | _TranzmitGraphView.Arrange_Subscriber_Results(Tranzmit_Graph_View.ArrangementTypes.Grid); 186 | _TranzmitGraphView.Arrange_Broadcaster_Results(Tranzmit_Graph_View.ArrangementTypes.Grid); 187 | }); 188 | gridButton.text = "Grid"; 189 | toolbar.Add(gridButton); 190 | 191 | // Adds toolbar to the graph 192 | rootVisualElement.Add(toolbar); 193 | } 194 | 195 | // ----------------------------------------------------------------------------------------- 196 | 197 | /// 198 | /// Generate the BlackBoard that will hold Various Settings for this Graph 199 | /// 200 | private void GenerateBlackBoard() 201 | { 202 | var blackBoard = new Blackboard(_TranzmitGraphView); 203 | blackBoard.Add(new BlackboardSection { title = "Graph Settings" }); 204 | blackBoard.SetPosition(new Rect(10, 30, 300, 300)); 205 | 206 | _TranzmitGraphView.Add(blackBoard); 207 | 208 | _TranzmitGraphView.Blackboard = blackBoard; 209 | 210 | Generate_Subscriber_Grid_Spacing_Field(); 211 | Generate_Broadcaster_Grid_Spacing_Field(); 212 | Generate_Subscriber_Vertical_Spacing_Field(); 213 | Generate_Broadcaster_Vertical_Spacing_Field(); 214 | Generate_BlackBoard_Success_Color_Field(); 215 | Generate_BlackBoard_Error_Color_Field(); 216 | } 217 | 218 | // ----------------------------------------------------------------------------------------- 219 | 220 | public void Generate_Subscriber_Vertical_Spacing_Field() 221 | { 222 | var floatProp = new FloatProperty(); 223 | floatProp.PropertyName = _TranzmitGraphView.VerticalYSpacing_Subscriber.PropertyName; 224 | floatProp.PropertyValue = _TranzmitGraphView.VerticalYSpacing_Subscriber.PropertyValue; 225 | 226 | var visualElement = new VisualElement(); 227 | var blackboardField = new BlackboardField { text = floatProp.PropertyName, typeText = "" }; 228 | visualElement.Add(blackboardField); 229 | 230 | var field = new FloatField("Value:"); 231 | field.value = floatProp.PropertyValue; 232 | 233 | field.RegisterValueChangedCallback(ChangeEvent => 234 | { 235 | _TranzmitGraphView.VerticalYSpacing_Subscriber.PropertyValue = field.value; 236 | 237 | if (_TranzmitGraphView.CurrentArrangementType == Tranzmit_Graph_View.ArrangementTypes.Vertical) 238 | { 239 | _TranzmitGraphView.Arrange_Subscriber_Results(Tranzmit_Graph_View.ArrangementTypes.Vertical); 240 | } 241 | }); 242 | 243 | var blackBoardValueRow = new BlackboardRow(blackboardField, field); 244 | visualElement.Add(blackBoardValueRow); 245 | 246 | _TranzmitGraphView.Blackboard.Add(visualElement); 247 | } 248 | 249 | // ----------------------------------------------------------------------------------------- 250 | 251 | public void Generate_Broadcaster_Vertical_Spacing_Field() 252 | { 253 | var floatProp = new FloatProperty(); 254 | floatProp.PropertyName = _TranzmitGraphView.VerticalYSpacing_Broadcaster.PropertyName; 255 | floatProp.PropertyValue = _TranzmitGraphView.VerticalYSpacing_Broadcaster.PropertyValue; 256 | 257 | var visualElement = new VisualElement(); 258 | var blackboardField = new BlackboardField { text = floatProp.PropertyName, typeText = "" }; 259 | visualElement.Add(blackboardField); 260 | 261 | var field = new FloatField("Value:"); 262 | field.value = floatProp.PropertyValue; 263 | 264 | field.RegisterValueChangedCallback(ChangeEvent => 265 | { 266 | _TranzmitGraphView.VerticalYSpacing_Broadcaster.PropertyValue = field.value; 267 | 268 | if (_TranzmitGraphView.CurrentArrangementType == Tranzmit_Graph_View.ArrangementTypes.Vertical) 269 | { 270 | _TranzmitGraphView.Arrange_Broadcaster_Results(Tranzmit_Graph_View.ArrangementTypes.Vertical); 271 | } 272 | }); 273 | 274 | var blackBoardValueRow = new BlackboardRow(blackboardField, field); 275 | visualElement.Add(blackBoardValueRow); 276 | 277 | _TranzmitGraphView.Blackboard.Add(visualElement); 278 | } 279 | 280 | // ----------------------------------------------------------------------------------------- 281 | 282 | public void Generate_Broadcaster_Grid_Spacing_Field() 283 | { 284 | var v2 = new Vector2Property(); 285 | v2.PropertyName = _TranzmitGraphView.GridLayoutSpacing_Broadcaster.PropertyName; 286 | v2.PropertyValue = _TranzmitGraphView.GridLayoutSpacing_Broadcaster.PropertyValue; 287 | 288 | var visualElement = new VisualElement(); 289 | var blackboardField = new BlackboardField { text = v2.PropertyName, typeText = "" }; 290 | visualElement.Add(blackboardField); 291 | 292 | var field = new Vector2Field("Value:"); 293 | field.value = v2.PropertyValue; 294 | 295 | field.RegisterValueChangedCallback(ChangeEvent => 296 | { 297 | _TranzmitGraphView.GridLayoutSpacing_Broadcaster.PropertyValue = field.value; 298 | 299 | if (_TranzmitGraphView.CurrentArrangementType == Tranzmit_Graph_View.ArrangementTypes.Grid) 300 | { 301 | _TranzmitGraphView.Arrange_Broadcaster_Results(Tranzmit_Graph_View.ArrangementTypes.Grid); 302 | } 303 | }); 304 | 305 | var blackBoardValueRow = new BlackboardRow(blackboardField, field); 306 | visualElement.Add(blackBoardValueRow); 307 | 308 | _TranzmitGraphView.Blackboard.Add(visualElement); 309 | } 310 | 311 | // ----------------------------------------------------------------------------------------- 312 | 313 | public void Generate_Subscriber_Grid_Spacing_Field() 314 | { 315 | var v2 = new Vector2Property(); 316 | v2.PropertyName = _TranzmitGraphView.GridLayoutSpacing_Subscriber.PropertyName; 317 | v2.PropertyValue = _TranzmitGraphView.GridLayoutSpacing_Subscriber.PropertyValue; 318 | 319 | var visualElement = new VisualElement(); 320 | var blackboardField = new BlackboardField { text = v2.PropertyName, typeText = "" }; 321 | visualElement.Add(blackboardField); 322 | 323 | var field = new Vector2Field("Value:"); 324 | field.value = v2.PropertyValue; 325 | 326 | field.RegisterValueChangedCallback(ChangeEvent => 327 | { 328 | _TranzmitGraphView.GridLayoutSpacing_Subscriber.PropertyValue = field.value; 329 | 330 | if (_TranzmitGraphView.CurrentArrangementType == Tranzmit_Graph_View.ArrangementTypes.Grid) 331 | { 332 | _TranzmitGraphView.Arrange_Subscriber_Results(Tranzmit_Graph_View.ArrangementTypes.Grid); 333 | } 334 | }); 335 | 336 | var blackBoardValueRow = new BlackboardRow(blackboardField, field); 337 | visualElement.Add(blackBoardValueRow); 338 | 339 | _TranzmitGraphView.Blackboard.Add(visualElement); 340 | } 341 | 342 | // ----------------------------------------------------------------------------------------- 343 | 344 | public void Generate_BlackBoard_Success_Color_Field() 345 | { 346 | var color = new ColorProperty(); 347 | color.PropertyName = _TranzmitGraphView.SuccessColor.PropertyName; 348 | color.PropertyValue = _TranzmitGraphView.SuccessColor.PropertyValue; 349 | 350 | var visualElement = new VisualElement(); 351 | var blackboardField = new BlackboardField { text = color.PropertyName, typeText = "" }; 352 | visualElement.Add(blackboardField); 353 | 354 | var field = new ColorField("Value:"); 355 | field.value = color.PropertyValue; 356 | 357 | field.RegisterValueChangedCallback(ChangeEvent => 358 | { 359 | _TranzmitGraphView.SuccessColor.PropertyValue = field.value; 360 | _TranzmitGraphView.UpdateSuccessColorsOnGraphElements(); 361 | }); 362 | 363 | var blackBoardValueRow = new BlackboardRow(blackboardField, field); 364 | visualElement.Add(blackBoardValueRow); 365 | 366 | _TranzmitGraphView.Blackboard.Add(visualElement); 367 | } 368 | 369 | // ----------------------------------------------------------------------------------------- 370 | 371 | public void Generate_BlackBoard_Error_Color_Field() 372 | { 373 | var color = new ColorProperty(); 374 | color.PropertyName = _TranzmitGraphView.ErrorColor.PropertyName; 375 | color.PropertyValue = _TranzmitGraphView.ErrorColor.PropertyValue; 376 | 377 | var visualElement = new VisualElement(); 378 | var blackboardField = new BlackboardField { text = color.PropertyName, typeText = "" }; 379 | visualElement.Add(blackboardField); 380 | 381 | var field = new ColorField("Value:"); 382 | field.value = color.PropertyValue; 383 | 384 | field.RegisterValueChangedCallback(ChangeEvent => 385 | { 386 | _TranzmitGraphView.ErrorColor.PropertyValue = field.value; 387 | _TranzmitGraphView.UpdateErrorColorsOnGraphElements(); 388 | }); 389 | 390 | var blackBoardValueRow = new BlackboardRow(blackboardField, field); 391 | visualElement.Add(blackBoardValueRow); 392 | 393 | _TranzmitGraphView.Blackboard.Add(visualElement); 394 | } 395 | } 396 | } -------------------------------------------------------------------------------- /Debug/Graph/Editor/Tranzmit_Graph_View.cs: -------------------------------------------------------------------------------- 1 | using Blep.Tranzmit; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using UnityEditor; 6 | using UnityEditor.Experimental.GraphView; 7 | using UnityEngine; 8 | using UnityEngine.UIElements; 9 | using UnityEditor.UIElements; 10 | 11 | public class Tranzmit_Graph_View : GraphView 12 | { 13 | /// 14 | /// HIGHLY EXPERIMENTAL!.... Unity are also classing this as experimental. 15 | /// I wanted to learn and thought Tranmit would be useful in this environment. 16 | /// 17 | 18 | public Tranzmit Tranzmit; 19 | public TranzmitDebug TranzmitDebug; 20 | public Blackboard Blackboard; 21 | 22 | private Rect TranzmitCorePosition = new Rect(600, 200, 600, 600); 23 | private Rect TranzmitSubscriberBasePosition = new Rect(1000, 200, 500, 500); 24 | private Rect TranzmitBroadcastBasePosition = new Rect(200, 200, 500, 500); 25 | 26 | public ColorProperty SilentColor = new ColorProperty() { PropertyName = "Silent Color", PropertyValue = Color.gray}; 27 | public ColorProperty SuccessColor = new ColorProperty() { PropertyName = "Success Color", PropertyValue = new Color(0.27f, 0.64f, 1.00f)}; 28 | public ColorProperty ErrorColor = new ColorProperty() { PropertyName = "Error Color", PropertyValue = new Color(.8f, .2f, 0f) }; 29 | 30 | public Vector2Property GridLayoutSpacing_Subscriber = new Vector2Property() { PropertyName = "Subscriber Grid Spacing", PropertyValue = new Vector2(400, 180) }; 31 | public Vector2Property GridLayoutSpacing_Broadcaster = new Vector2Property() { PropertyName = "Broadcaster Grid Spacing", PropertyValue = new Vector2(400, 180) }; 32 | 33 | public FloatProperty VerticalYSpacing_Subscriber = new FloatProperty() { PropertyName = "Subscriber Vertical Y Spacing", PropertyValue = 90 }; 34 | public FloatProperty VerticalYSpacing_Broadcaster = new FloatProperty() { PropertyName = "Broadcaster Vertical Y Spacing", PropertyValue = 90 }; 35 | 36 | private float SubscriberPortsSpacing = 24; 37 | private float BroadcasterSpacing = 24; 38 | 39 | private List SubscriberNodes = new List(); 40 | 41 | private Dictionary BroadcasterNodes = new Dictionary(); 42 | 43 | public ArrangementTypes CurrentArrangementType = ArrangementTypes.Grid; 44 | 45 | public class SubscriberNodeData 46 | { 47 | public object Subscriber; 48 | public Tranzmit_Node Node; 49 | public List PortEdgeEvent = new List(); 50 | } 51 | 52 | public class BroadcasterNodeData 53 | { 54 | public Tranzmit_Node TranzmitNodeEventNode; 55 | public Port Port; 56 | public Port TranzmitPort; 57 | public Edge Edge; 58 | public int TotalButtons; 59 | } 60 | 61 | public class PortEdgeEventData 62 | { 63 | public Tranzmit.EventNames EventName; 64 | public Port SubscriberPort; 65 | public Port TranzmitPort; 66 | public Edge Edge; 67 | } 68 | 69 | public enum ArrangementTypes 70 | { 71 | Vertical = 0, 72 | Inline = 1, 73 | Grid = 2 74 | } 75 | 76 | // ----------------------------------------------------------------------------------------- 77 | 78 | /// 79 | /// UNITY - Creates the graph instance and relevant settings. 80 | /// 81 | public Tranzmit_Graph_View() 82 | { 83 | // Load style sheet 84 | styleSheets.Add(Resources.Load("Tranzmit_Graph")); 85 | 86 | // Enable common graph interactions 87 | this.AddManipulator(new ContentDragger()); 88 | this.AddManipulator(new SelectionDragger()); 89 | this.AddManipulator(new RectangleSelector()); 90 | 91 | // Setup Zoom 92 | SetupZoom(ContentZoomer.DefaultMinScale, ContentZoomer.DefaultMaxScale); 93 | 94 | // Setup Grid 95 | var grid = new GridBackground(); 96 | Insert(0, grid); 97 | grid.StretchToParentSize(); 98 | 99 | Generate(); 100 | } 101 | 102 | // ----------------------------------------------------------------------------------------- 103 | 104 | /// 105 | /// Manual way of forcing a refresh of Tranzmit Graph. Used on startup. 106 | /// 107 | public void SyncGraphWithTranzmitDebug() 108 | { 109 | foreach (KeyValuePair> entry in TranzmitDebug.Success) 110 | { 111 | foreach (TranzmitDebug.LogEntry log in entry.Value) 112 | { 113 | UpdateButtonsOnSubscriberNodes(log); 114 | UpdateButtonsAndPortsOnBroadcasterNodes(log, true); 115 | } 116 | } 117 | 118 | foreach (KeyValuePair> entry in TranzmitDebug.Failed) 119 | { 120 | foreach (TranzmitDebug.LogEntry log in entry.Value) 121 | { 122 | UpdateButtonsAndPortsOnBroadcasterNodes(log, true); 123 | } 124 | } 125 | } 126 | 127 | // ----------------------------------------------------------------------------------------- 128 | 129 | // This section deals with events recieved from Tranzmit. 130 | 131 | public void EventAdded(Tranzmit.EventNames eventName) 132 | { 133 | Generate(); 134 | } 135 | 136 | public void EventDeleted(Tranzmit.EventNames eventName) 137 | { 138 | Generate(); 139 | } 140 | 141 | public void EventTranzmitDebugReset() 142 | { 143 | Generate(); 144 | } 145 | 146 | public void TranzmitDebugLogUpdated(TranzmitDebug.LogEntry logEntry) 147 | { 148 | UpdateButtonsOnSubscriberNodes(logEntry); 149 | UpdateButtonsAndPortsOnBroadcasterNodes(logEntry, false); 150 | } 151 | 152 | // ----------------------------------------------------------------------------------------- 153 | 154 | /// 155 | /// This handles the whole process of generating the graph 156 | /// 157 | public void Generate() 158 | { 159 | RemoveAllGraphElements(); 160 | 161 | TranzmitDebug = GameObject.FindObjectOfType(); 162 | Tranzmit = GameObject.FindObjectOfType(); 163 | 164 | if (Tranzmit != null) 165 | { 166 | if (TranzmitDebug != null) 167 | { 168 | GenerateTranzmitNodes(); 169 | 170 | SyncGraphWithTranzmitDebug(); 171 | 172 | Arrange_Subscriber_Results(CurrentArrangementType); 173 | 174 | Arrange_Broadcaster_Results(CurrentArrangementType); 175 | } 176 | else 177 | { 178 | // Debug.Log("No Instance of TranzmitDebug has been found!\nTranzmit Graph will not be generated"); 179 | } 180 | } 181 | else 182 | { 183 | // Debug.Log("No Instance of Tranzmit has been found!\nTranzmit Graph will not be generated"); 184 | } 185 | } 186 | 187 | // ----------------------------------------------------------------------------------------- 188 | 189 | /// 190 | /// Removes all graph elements. Due to the poor documentation, I am not aware of a better way to do this. I can't help feeling there is a better way! 191 | /// 192 | private void RemoveAllGraphElements() 193 | { 194 | ports.ForEach((port) => 195 | { 196 | port.Clear(); 197 | }); 198 | 199 | nodes.ForEach((node) => 200 | { 201 | node.Clear(); 202 | }); 203 | 204 | edges.ForEach((edge) => 205 | { 206 | edge.Clear(); 207 | }); 208 | } 209 | 210 | // ----------------------------------------------------------------------------------------- 211 | 212 | // TRANZMIT NODE OUT Port Generation 213 | private Port Port_Generate_TRANZMIT_Out(Tranzmit_Node node, Direction portDirection, Port.Capacity capacity = Port.Capacity.Multi) 214 | { 215 | return node.InstantiatePort(Orientation.Horizontal, portDirection, capacity, typeof(int)); 216 | } 217 | 218 | // ----------------------------------------------------------------------------------------- 219 | 220 | // TRANZMIT NODE OUT Port Generation 221 | private Port Port_Generate_TRANZMIT_In(Tranzmit_Node node, Direction portDirection, Port.Capacity capacity = Port.Capacity.Single) 222 | { 223 | return node.InstantiatePort(Orientation.Horizontal, portDirection, capacity, typeof(int)); 224 | } 225 | 226 | // ----------------------------------------------------------------------------------------- 227 | 228 | // SUBSCRIBER NODE Port Generation 229 | private Port Port_Generate_SUBSCRIBER(Tranzmit_Node node, Direction portDirection, Port.Capacity capacity = Port.Capacity.Single) 230 | { 231 | return node.InstantiatePort(Orientation.Horizontal, portDirection, capacity, typeof(int)); 232 | } 233 | 234 | // ----------------------------------------------------------------------------------------- 235 | 236 | // EVENT TYPE NODE Port Generation 237 | private Port Port_Generate_EVENT_TYPE(Tranzmit_Node node, Direction portDirection, Port.Capacity capacity = Port.Capacity.Single) 238 | { 239 | return node.InstantiatePort(Orientation.Horizontal, portDirection, capacity, typeof(int)); 240 | } 241 | 242 | // ----------------------------------------------------------------------------------------- 243 | 244 | /// 245 | /// Launcher for generating all required nodes for the graph to work 246 | /// 247 | private void GenerateTranzmitNodes() 248 | { 249 | SubscriberNodes.Clear(); 250 | BroadcasterNodes.Clear(); 251 | 252 | // TRANZMIT ------------------------------- 253 | var tranzmitNode = GenerateTranzmitNode("TRANZMIT"); 254 | 255 | // OTHER NODES / PORTS 256 | foreach (KeyValuePair tranzmitEvent in Tranzmit.Events) 257 | { 258 | // Tranzmit Event Type Port 259 | var outPort = Port_Add_Tranzmit_OUT(tranzmitNode, tranzmitEvent.Key); 260 | var inPort = Port_Add_Tranzmit_IN(tranzmitNode, tranzmitEvent.Key); 261 | 262 | // Create and connect Subscriber Nodes for this Port / Tranzmit Event Type 263 | Generate_Nodes_Subscriber(tranzmitNode, outPort, tranzmitEvent.Value); 264 | 265 | // TRANZMIT EVENT TYPE NODES------------------- 266 | Generate_Broadcaster_Node(inPort, tranzmitEvent.Value); 267 | } 268 | } 269 | 270 | // ----------------------------------------------------------------------------------------- 271 | 272 | /// 273 | /// Generates a new Tranzmit Node 274 | /// 275 | /// The displayed name of the node. 276 | /// The generated Node 277 | private Tranzmit_Node GenerateTranzmitNode(string nodeName) 278 | { 279 | var node = new Tranzmit_Node 280 | { 281 | title = nodeName, 282 | Dialogue = nodeName, 283 | GUID = Guid.NewGuid().ToString() 284 | }; 285 | 286 | var button = new Button(clickEvent: () => { SelectObject(Tranzmit); }); 287 | button.text = "Find Tranzmit"; 288 | node.mainContainer.Add(button); 289 | 290 | var button2 = new Button(clickEvent: () => { SelectObject(TranzmitDebug); }); 291 | button2.text = "Find Tranzmit Debug"; 292 | node.mainContainer.Add(button2); 293 | 294 | node.SetPosition(TranzmitCorePosition); 295 | 296 | AddElement(node); 297 | 298 | return node; 299 | } 300 | 301 | // ----------------------------------------------------------------------------------------- 302 | 303 | /// 304 | /// Generates a new Subscriber Node 305 | /// 306 | /// The displayed name of the node. 307 | /// The generated Node 308 | private Tranzmit_Node GenerateTranzmitSubscriberNode(string nodeName) 309 | { 310 | var node = new Tranzmit_Node 311 | { 312 | title = nodeName, 313 | Dialogue = nodeName, 314 | GUID = Guid.NewGuid().ToString() 315 | }; 316 | 317 | node.SetPosition(TranzmitSubscriberBasePosition); 318 | 319 | AddElement(node); 320 | 321 | return node; 322 | } 323 | 324 | // ----------------------------------------------------------------------------------------- 325 | 326 | /// 327 | /// Generates a new Broadcaster Node 328 | /// 329 | /// The displayed name of the node. 330 | /// The generated Node 331 | private Tranzmit_Node GenerateTranzmitBoroadcasterNode(string nodeName) 332 | { 333 | var node = new Tranzmit_Node 334 | { 335 | title = nodeName, 336 | Dialogue = nodeName, 337 | GUID = Guid.NewGuid().ToString() 338 | }; 339 | 340 | node.SetPosition(TranzmitBroadcastBasePosition); 341 | 342 | AddElement(node); 343 | 344 | return node; 345 | } 346 | 347 | // ----------------------------------------------------------------------------------------- 348 | 349 | // Adds an Event Type Out port on the Core Node 350 | /// 351 | /// Adds an In port on the Tranzmit Node 352 | /// 353 | /// The Tranzmit Node 354 | /// The associated event 355 | /// The Generated Port 356 | private Port Port_Add_Tranzmit_OUT(Tranzmit_Node node, Tranzmit.EventNames eventName) 357 | { 358 | // OUT 359 | var outPort = Port_Generate_TRANZMIT_Out(node, Direction.Output); 360 | outPort.portName = eventName.ToString(); ; 361 | outPort.portColor = SilentColor.PropertyValue; 362 | node.outputContainer.Add(outPort); 363 | 364 | return outPort; 365 | } 366 | 367 | // ----------------------------------------------------------------------------------------- 368 | 369 | /// 370 | /// Adds an Out port on the Tranzmit Node 371 | /// 372 | /// The Tranzmit Node 373 | /// The associated event 374 | /// The Generated Port 375 | private Port Port_Add_Tranzmit_IN(Tranzmit_Node node, Tranzmit.EventNames eventName) 376 | { 377 | // IN 378 | var inPort = Port_Generate_TRANZMIT_In(node, Direction.Input); 379 | inPort.portName = eventName.ToString(); ; 380 | inPort.portColor = SilentColor.PropertyValue; 381 | node.inputContainer.Add(inPort); 382 | 383 | return inPort; 384 | } 385 | 386 | // ----------------------------------------------------------------------------------------- 387 | 388 | /// 389 | /// Adds an Event Type Out port on the Core Node 390 | /// 391 | /// The Node to which the Port will be attached to 392 | /// The Generated Port 393 | private Port Port_Add_Event_Type_Node(Tranzmit_Node node) 394 | { 395 | var port = Port_Generate_EVENT_TYPE(node, Direction.Output); 396 | port.portName = ""; 397 | port.portColor = SilentColor.PropertyValue; 398 | node.inputContainer.Add(port); 399 | 400 | return port; 401 | } 402 | 403 | // ----------------------------------------------------------------------------------------- 404 | 405 | /// 406 | /// Generates ALL Subscriber Nodes 407 | /// 408 | /// The Tanzmit Node to connect to 409 | /// The Tanzmit Port to connect to 410 | /// The associated event 411 | private void Generate_Nodes_Subscriber(Tranzmit_Node tranzmitNode, Port coreNodePort, Tranzmit.EventData tranzmitEvent) 412 | { 413 | if (tranzmitEvent != null) 414 | { 415 | // Iterate Subscribers in the Event 416 | foreach (Delegate subscriber in tranzmitEvent.GetSubscribers()) 417 | { 418 | bool found = false; 419 | 420 | // Iterate through our list of generated Subscriber Nodes 421 | foreach (SubscriberNodeData subNode in SubscriberNodes) 422 | { 423 | // Check if the subscription objects are the same 424 | if (subscriber.Target == subNode.Subscriber) 425 | { 426 | found = true; 427 | 428 | // We just add a port onto the existing graph node 429 | var SubscriberPort = GenerateTranzmitSubscriberInputPorts(subNode.Node, tranzmitEvent); 430 | var edge = SubscriberPort.ConnectTo(coreNodePort); 431 | SubscriberPort.edgeConnector.target.Add(edge); 432 | 433 | subNode.PortEdgeEvent.Add(new PortEdgeEventData() { SubscriberPort = SubscriberPort, TranzmitPort = coreNodePort, Edge = edge, EventName = tranzmitEvent.Info.EventName }); 434 | } 435 | } 436 | 437 | // No graph node exists for the Subscription object so we create it and add / connect the edge. 438 | if (found == false) 439 | { 440 | var subscriberNode = GenerateTranzmitSubscriberNode(subscriber.Target.ToString()); 441 | 442 | SubscriberNodeData newSubscriberNode = new SubscriberNodeData(); 443 | newSubscriberNode.Node = subscriberNode; 444 | newSubscriberNode.Subscriber = subscriber.Target; 445 | 446 | var button = new Button(clickEvent: () => { SelectObject(subscriber.Target); }); 447 | button.text = "Find"; 448 | newSubscriberNode.Node.mainContainer.Add(button); 449 | 450 | 451 | // Connect Ports 452 | var SubscriberPort = GenerateTranzmitSubscriberInputPorts(subscriberNode, tranzmitEvent); 453 | 454 | // Build Edge 455 | var edge = SubscriberPort.ConnectTo(coreNodePort); 456 | SubscriberPort.edgeConnector.target.Add(edge); 457 | 458 | // Add connected port to new entry 459 | newSubscriberNode.PortEdgeEvent.Add(new PortEdgeEventData() { SubscriberPort = SubscriberPort, TranzmitPort = coreNodePort, Edge = edge, EventName = tranzmitEvent.Info.EventName }); 460 | 461 | // Add Entry 462 | SubscriberNodes.Add(newSubscriberNode); 463 | } 464 | } 465 | 466 | // Update the node when we are done with it 467 | tranzmitNode.RefreshExpandedState(); 468 | tranzmitNode.RefreshPorts(); 469 | } 470 | else 471 | { 472 | Debug.Log("No subscribers were found!"); 473 | } 474 | } 475 | 476 | // ----------------------------------------------------------------------------------------- 477 | 478 | /// 479 | /// Generate the all parts of the Broadcaster Node including ports etc, connects it the Tranzmit Node, and adds it to the BroadcasterNodes Dictionary for easy reference later on. 480 | /// 481 | /// The port on the Tranzmit Node to which this new Broadcaster node will be connected to. 482 | /// The associated event 483 | private void Generate_Broadcaster_Node(Port tranzmitPort, Tranzmit.EventData tranzmitEvent) 484 | { 485 | var node = GenerateTranzmitBoroadcasterNode(tranzmitEvent.Info.EventName.ToString()); 486 | 487 | var port = Port_Add_Event_Type_Node(node); 488 | var edge = port.ConnectTo(tranzmitPort); 489 | port.edgeConnector.target.Add(edge); 490 | 491 | var newEventTypeNodeData = new BroadcasterNodeData(); 492 | newEventTypeNodeData.TranzmitNodeEventNode = node; 493 | newEventTypeNodeData.Port = port; 494 | newEventTypeNodeData.TranzmitPort = tranzmitPort; 495 | newEventTypeNodeData.Edge = edge; 496 | 497 | BroadcasterNodes.Add(tranzmitEvent.Info.EventName, newEventTypeNodeData); 498 | 499 | node.RefreshExpandedState(); 500 | node.RefreshPorts(); 501 | } 502 | 503 | // ----------------------------------------------------------------------------------------- 504 | 505 | /// 506 | /// Creates the ports on the Subscriber Nodes. 507 | /// 508 | /// The Node to which we want to attach this port to. 509 | /// The Event that will be associated with this port. 510 | /// The created port 511 | private Port GenerateTranzmitSubscriberInputPorts(Tranzmit_Node subscriberNode, Tranzmit.EventData tranzmitEvent) 512 | { 513 | var inputPort = Port_Generate_SUBSCRIBER(subscriberNode, Direction.Input, Port.Capacity.Single); 514 | inputPort.portName = tranzmitEvent.Info.EventName.ToString(); 515 | inputPort.portColor = SilentColor.PropertyValue; 516 | subscriberNode.inputContainer.Add(inputPort); 517 | subscriberNode.RefreshExpandedState(); 518 | subscriberNode.RefreshPorts(); 519 | 520 | return inputPort; 521 | } 522 | 523 | // ----------------------------------------------------------------------------------------- 524 | 525 | /// 526 | /// Used to enable Edge Connections this is a Unity in-built callback. Without this you cannot manually connect ports. 527 | /// NOTICE: This is not actually needed as we do not manually attached ports, but seeing as this was a learning project, I am leaving it in for reference and for anyone who wishes to extend this. 528 | /// 529 | /// 530 | public override List GetCompatiblePorts(Port StartPort, NodeAdapter nodeAdapter) 531 | { 532 | var compatiblePorts = new List(); 533 | 534 | ports.ForEach((port) => 535 | { 536 | // make sure edge is not trying to connect with it's own port OR the node it is attached too. 537 | if (StartPort != port && StartPort.node != port.node) 538 | { 539 | compatiblePorts.Add(port); 540 | } 541 | }); 542 | 543 | return compatiblePorts; 544 | } 545 | 546 | // ----------------------------------------------------------------------------------------- 547 | 548 | /// 549 | /// Updates the RELEAVNT buttons in Subscriber nodes, when a SUCCESSFUL Event has occured. 550 | /// 551 | /// Checks if Event Broadcast was succefull or not. 552 | /// The associated event 553 | public void UpdateButtonsOnSubscriberNodes(TranzmitDebug.LogEntry logEntry) 554 | { 555 | // They only react to Success Logs - Which only have index[0] in LogEntries List. 556 | if (logEntry.Status == Tranzmit.DeliveryStatuses.Success) 557 | { 558 | foreach (SubscriberNodeData subNode in SubscriberNodes) 559 | { 560 | foreach (PortEdgeEventData portNodeEvent in subNode.PortEdgeEvent) 561 | { 562 | if (portNodeEvent.EventName == logEntry.TranzmitEvent) 563 | { 564 | portNodeEvent.TranzmitPort.portColor = SuccessColor.PropertyValue; 565 | portNodeEvent.TranzmitPort.visualClass = ""; // HACK: Force Refresh. Vary the input to trigger otherwise only works once. 566 | 567 | portNodeEvent.SubscriberPort.portName = $"{logEntry.TranzmitEvent.ToString()} [{TranzmitDebug.Success[logEntry.TranzmitEvent][0].Subscribers[subNode.Subscriber].EventCount}]"; // Always index 0! 568 | portNodeEvent.SubscriberPort.portColor = SuccessColor.PropertyValue; 569 | portNodeEvent.SubscriberPort.visualClass = ""; // HACK: Force Refresh. Vary the input to trigger otherwise only works once. 570 | 571 | portNodeEvent.Edge.UpdateEdgeControl(); 572 | } 573 | } 574 | } 575 | } 576 | } 577 | 578 | // ----------------------------------------------------------------------------------------- 579 | 580 | /// 581 | /// Updates the RELEVANT buttons and Ports assicoated with the Event that occured. 582 | /// 583 | /// The log entry that was added or modified. 584 | /// Use full refresh all buttons when no event has occured. 585 | public void UpdateButtonsAndPortsOnBroadcasterNodes(TranzmitDebug.LogEntry logEntry, bool forceRefresh) 586 | { 587 | if (BroadcasterNodes.ContainsKey(logEntry.TranzmitEvent)) 588 | { 589 | // BUTTONS 590 | foreach (KeyValuePair buttonData in logEntry.Broadcasters) 591 | { 592 | // IF Button does not exist, create it. 593 | if (buttonData.Value.GraphButton == null || forceRefresh == true) 594 | { 595 | buttonData.Value.GraphButton = new Button(clickEvent: () => { SelectObject(buttonData.Key); }); 596 | 597 | if (logEntry.Errors.Contains(Tranzmit.Errors.MissingSource)) 598 | { 599 | buttonData.Value.GraphButton.text = $"Source Missing! [{buttonData.Value.EventCount}]"; 600 | } 601 | else 602 | { 603 | buttonData.Value.GraphButton.text = $"{buttonData.Key.ToString()} [{buttonData.Value.EventCount}]"; 604 | } 605 | 606 | if (logEntry.Status == Tranzmit.DeliveryStatuses.Failed) 607 | { 608 | buttonData.Value.GraphButton.style.backgroundColor = ErrorColor.PropertyValue; 609 | } 610 | 611 | BroadcasterNodes[logEntry.TranzmitEvent].TranzmitNodeEventNode.mainContainer.Add(buttonData.Value.GraphButton); 612 | } 613 | else // Button Exists 614 | { 615 | if (logEntry.Errors.Contains(Tranzmit.Errors.MissingSource)) 616 | { 617 | buttonData.Value.GraphButton.text = $"Source Missing! [{buttonData.Value.EventCount}]"; 618 | } 619 | else 620 | { 621 | buttonData.Value.GraphButton.text = $"{buttonData.Key.ToString()} [{buttonData.Value.EventCount}]"; 622 | } 623 | } 624 | 625 | BroadcasterNodes[logEntry.TranzmitEvent].TotalButtons = BroadcasterNodes[logEntry.TranzmitEvent].TranzmitNodeEventNode.mainContainer.childCount; 626 | } 627 | 628 | // PORTS 629 | if (logEntry.Status == Tranzmit.DeliveryStatuses.Success) 630 | { 631 | if (BroadcasterNodes[logEntry.TranzmitEvent].Port.portColor != ErrorColor.PropertyValue) 632 | { 633 | BroadcasterNodes[logEntry.TranzmitEvent].TranzmitPort.portColor = SuccessColor.PropertyValue; 634 | BroadcasterNodes[logEntry.TranzmitEvent].TranzmitPort.visualClass = ""; // HACK: Force Refresh. 635 | 636 | BroadcasterNodes[logEntry.TranzmitEvent].Port.portColor = SuccessColor.PropertyValue; 637 | BroadcasterNodes[logEntry.TranzmitEvent].Port.visualClass = ""; // HACK: Force Refresh. 638 | } 639 | } 640 | else 641 | { 642 | if (BroadcasterNodes[logEntry.TranzmitEvent].Port.portColor != ErrorColor.PropertyValue) 643 | { 644 | BroadcasterNodes[logEntry.TranzmitEvent].TranzmitPort.portColor = ErrorColor.PropertyValue; 645 | BroadcasterNodes[logEntry.TranzmitEvent].TranzmitPort.visualClass = "1"; // HACK: Force Refresh. 646 | 647 | BroadcasterNodes[logEntry.TranzmitEvent].Port.portColor = ErrorColor.PropertyValue; 648 | BroadcasterNodes[logEntry.TranzmitEvent].Port.visualClass = "1"; // HACK: Force Refresh. 649 | } 650 | } 651 | 652 | 653 | Arrange_Broadcaster_Results(CurrentArrangementType); 654 | } 655 | } 656 | 657 | // ----------------------------------------------------------------------------------------- 658 | 659 | /// 660 | /// Handles the actual layout of Subscriber nodes in the Graph View 661 | /// 662 | public void Arrange_Subscriber_Results(ArrangementTypes arrangementType) 663 | { 664 | CurrentArrangementType = ArrangementTypes.Vertical; 665 | 666 | if (arrangementType == ArrangementTypes.Vertical) 667 | { 668 | // Node index ;) 669 | var count = 0; 670 | 671 | Vector2 position = new Vector2(); 672 | 673 | for (int col = 0; col < SubscriberNodes.Count(); col++) 674 | { 675 | if (count > 0) 676 | { 677 | position += new Vector2( 678 | 0, 679 | VerticalYSpacing_Subscriber.PropertyValue + (SubscriberPortsSpacing * SubscriberNodes[count - 1].PortEdgeEvent.Count()) 680 | ); 681 | } 682 | else 683 | { 684 | position = new Vector2( 685 | TranzmitSubscriberBasePosition.x, 686 | TranzmitSubscriberBasePosition.y 687 | ); 688 | } 689 | 690 | SubscriberNodes[count].Node.SetPosition(new Rect(position, Vector2.zero)); 691 | count++; 692 | if (count == SubscriberNodes.Count()) 693 | { 694 | return; 695 | } 696 | } 697 | } 698 | 699 | if (arrangementType == ArrangementTypes.Grid) 700 | { 701 | CurrentArrangementType = ArrangementTypes.Grid; 702 | 703 | float portSpacing = GetMostSubscribersInASingleSubscriberNode() * SubscriberPortsSpacing; 704 | 705 | int columns = (int)Math.Sqrt(SubscriberNodes.Count()); 706 | int rows = (int)Math.Ceiling(SubscriberNodes.Count() / (float)columns); 707 | 708 | // Node index ;) 709 | var count = 0; 710 | 711 | for (int col = 0; col < columns; col++) 712 | { 713 | for (int row = 0; row < rows; row++) 714 | { 715 | Vector2 position = new Vector2( 716 | TranzmitSubscriberBasePosition.x + (row * GridLayoutSpacing_Subscriber.PropertyValue.x), 717 | TranzmitSubscriberBasePosition.y + (col * GridLayoutSpacing_Subscriber.PropertyValue.y) + (col * portSpacing)); 718 | 719 | SubscriberNodes[count].Node.SetPosition(new Rect(position, Vector2.zero)); 720 | 721 | count++; 722 | 723 | if(count == SubscriberNodes.Count()) 724 | { 725 | return; 726 | } 727 | } 728 | } 729 | } 730 | } 731 | 732 | // ----------------------------------------------------------------------------------------- 733 | 734 | /// 735 | /// Handles the actual layout of Broadcaster nodes in the Graph View 736 | /// 737 | /// 738 | public void Arrange_Broadcaster_Results(ArrangementTypes arrangementType) 739 | { 740 | CurrentArrangementType = ArrangementTypes.Vertical; 741 | 742 | if (arrangementType == ArrangementTypes.Vertical) 743 | { 744 | var count = 0; 745 | 746 | Vector2 position = new Vector2(); 747 | 748 | List eventTypeNodesList = BroadcasterNodes.Values.ToList(); 749 | 750 | for (int col = 0; col < eventTypeNodesList.Count(); col++) 751 | { 752 | if (count > 0) 753 | { 754 | position += new Vector2( 755 | 0, 756 | VerticalYSpacing_Broadcaster.PropertyValue + (BroadcasterSpacing * eventTypeNodesList[count - 1].TotalButtons) 757 | ); 758 | } 759 | else 760 | { 761 | position = new Vector2( 762 | TranzmitBroadcastBasePosition.x, 763 | TranzmitBroadcastBasePosition.y 764 | ); 765 | } 766 | 767 | eventTypeNodesList[count].TranzmitNodeEventNode.SetPosition(new Rect(position, Vector2.zero)); 768 | count++; 769 | if (count == eventTypeNodesList.Count()) 770 | { 771 | return; 772 | } 773 | } 774 | } 775 | 776 | if (arrangementType == ArrangementTypes.Grid) 777 | { 778 | CurrentArrangementType = ArrangementTypes.Grid; 779 | 780 | float broadcasterSpacing = GetMostBroadcastersInASingleEventtypeNode() * BroadcasterSpacing; 781 | 782 | int columns = (int)Math.Sqrt(BroadcasterNodes.Count()); 783 | int rows = (int)Math.Ceiling(BroadcasterNodes.Count() / (float)columns); 784 | 785 | // Node index ;) 786 | var count = 0; 787 | 788 | List eventTypeNodesList = BroadcasterNodes.Values.ToList(); 789 | 790 | for (int col = 0; col < columns; col++) 791 | { 792 | for (int row = 0; row < rows; row++) 793 | { 794 | Vector2 position = new Vector2( 795 | TranzmitBroadcastBasePosition.x - (row * GridLayoutSpacing_Broadcaster.PropertyValue.x), 796 | TranzmitBroadcastBasePosition.y + (col * GridLayoutSpacing_Broadcaster.PropertyValue.y) + (col * broadcasterSpacing)); 797 | 798 | eventTypeNodesList[count].TranzmitNodeEventNode.SetPosition(new Rect(position, Vector2.zero)); 799 | 800 | count++; 801 | 802 | if (count == BroadcasterNodes.Count()) 803 | { 804 | return; 805 | } 806 | } 807 | } 808 | } 809 | } 810 | 811 | // ----------------------------------------------------------------------------------------- 812 | 813 | /// 814 | /// Finds the most Ports in a single instance of a Subscriber Node 815 | /// 816 | /// Number of Ports in the node with most ports 817 | private int GetMostSubscribersInASingleSubscriberNode() 818 | { 819 | int max = 0; 820 | 821 | foreach (SubscriberNodeData node in SubscriberNodes) 822 | { 823 | if (node.PortEdgeEvent.Count > max) 824 | { 825 | max = node.PortEdgeEvent.Count; 826 | } 827 | } 828 | 829 | return max; 830 | } 831 | 832 | // ----------------------------------------------------------------------------------------- 833 | 834 | /// 835 | /// Finds the most Broadcasters in a single instance of an Event Type Node 836 | /// 837 | /// Number of Ports in the node with most ports 838 | private int GetMostBroadcastersInASingleEventtypeNode() 839 | { 840 | int max = 0; 841 | 842 | foreach (KeyValuePair node in BroadcasterNodes) 843 | { 844 | if (node.Value.TotalButtons > max) 845 | { 846 | max = node.Value.TotalButtons; 847 | } 848 | } 849 | 850 | return max; 851 | } 852 | 853 | // ----------------------------------------------------------------------------------------- 854 | 855 | /// 856 | /// Focus on specified Object in the Hierarchy 857 | /// 858 | /// The target object which we are looking for 859 | private void SelectObject(object target) 860 | { 861 | Selection.activeObject = target as UnityEngine.Object; 862 | } 863 | 864 | // ----------------------------------------------------------------------------------------- 865 | 866 | public void UpdateErrorColorsOnGraphElements() 867 | { 868 | foreach (KeyValuePair> entry in TranzmitDebug.Failed) 869 | { 870 | foreach (TranzmitDebug.LogEntry log in entry.Value) 871 | { 872 | // BROADCASTERS 873 | foreach (KeyValuePair buttonData in log.Broadcasters) 874 | { 875 | buttonData.Value.GraphButton.style.backgroundColor = ErrorColor.PropertyValue; 876 | 877 | BroadcasterNodes[log.TranzmitEvent].TranzmitPort.portColor = ErrorColor.PropertyValue; 878 | BroadcasterNodes[log.TranzmitEvent].TranzmitPort.style.color = ErrorColor.PropertyValue; 879 | BroadcasterNodes[log.TranzmitEvent].TranzmitPort.visualClass = "2"; // HACK: Force Refresh. 880 | 881 | BroadcasterNodes[log.TranzmitEvent].Port.portColor = ErrorColor.PropertyValue; 882 | BroadcasterNodes[log.TranzmitEvent].Port.style.color = ErrorColor.PropertyValue; 883 | BroadcasterNodes[log.TranzmitEvent].Port.visualClass = "2"; // HACK: Force Refresh. 884 | 885 | BroadcasterNodes[log.TranzmitEvent].Edge.style.color = ErrorColor.PropertyValue; 886 | } 887 | } 888 | } 889 | } 890 | 891 | // ----------------------------------------------------------------------------------------- 892 | 893 | public void UpdateSuccessColorsOnGraphElements() 894 | { 895 | foreach (KeyValuePair> entry in TranzmitDebug.Success) 896 | { 897 | foreach (TranzmitDebug.LogEntry log in entry.Value) 898 | { 899 | // BROADCASTERS 900 | foreach (KeyValuePair buttonData in log.Broadcasters) 901 | { 902 | buttonData.Value.GraphButton.style.backgroundColor = SuccessColor.PropertyValue; 903 | 904 | BroadcasterNodes[log.TranzmitEvent].TranzmitPort.portColor = SuccessColor.PropertyValue; 905 | BroadcasterNodes[log.TranzmitEvent].TranzmitPort.style.color = SuccessColor.PropertyValue; 906 | BroadcasterNodes[log.TranzmitEvent].TranzmitPort.visualClass = "2"; // HACK: Force Refresh. 907 | 908 | BroadcasterNodes[log.TranzmitEvent].Port.portColor = SuccessColor.PropertyValue; 909 | BroadcasterNodes[log.TranzmitEvent].Port.style.color = SuccessColor.PropertyValue; 910 | BroadcasterNodes[log.TranzmitEvent].Port.visualClass = "2"; // HACK: Force Refresh. 911 | 912 | BroadcasterNodes[log.TranzmitEvent].Edge.style.color = SuccessColor.PropertyValue; 913 | } 914 | } 915 | } 916 | 917 | foreach (SubscriberNodeData subNode in SubscriberNodes) 918 | { 919 | foreach (PortEdgeEventData portNodeEvent in subNode.PortEdgeEvent) 920 | { 921 | // If it has been changed in color previously then we can safely update it as they change color only on the first successful event. 922 | if (portNodeEvent.SubscriberPort.portColor != SilentColor.PropertyValue) 923 | { 924 | portNodeEvent.TranzmitPort.portColor = SuccessColor.PropertyValue; 925 | portNodeEvent.TranzmitPort.style.color = SuccessColor.PropertyValue; 926 | portNodeEvent.TranzmitPort.visualClass = ""; // HACK: Force Refresh. Vary the input to trigger otherwise only works once. 927 | 928 | portNodeEvent.SubscriberPort.style.color = SuccessColor.PropertyValue; 929 | portNodeEvent.SubscriberPort.portColor = SuccessColor.PropertyValue; 930 | portNodeEvent.SubscriberPort.visualClass = ""; // HACK: Force Refresh. Vary the input to trigger otherwise only works once. 931 | 932 | portNodeEvent.Edge.style.color = SuccessColor.PropertyValue; 933 | } 934 | } 935 | } 936 | } 937 | } 938 | -------------------------------------------------------------------------------- /Debug/Graph/Editor/Tranzmit_Node.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor.Experimental.GraphView; 2 | 3 | namespace Blep.Tranzmit 4 | { 5 | public class Tranzmit_Node : Node 6 | { 7 | // Current unused. Considering use in future versions of the the graph. 8 | public string GUID; 9 | public string Dialogue; 10 | public bool EntryPoint = false; 11 | } 12 | } -------------------------------------------------------------------------------- /Debug/TranzmitDebug.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using Sirenix.OdinInspector; 4 | using System; 5 | using UnityEngine.UIElements; 6 | using System.Linq; 7 | 8 | namespace Blep.Tranzmit 9 | { 10 | /// 11 | /// Used for testing and general debugging. 12 | /// This script is not designed for use when stress testing / checking for GC, and it is recommended to remove for correct results in Profiler. 13 | /// It is a verbose tool that may generate GC, although I have tried to make it as friendly to GC as I can in practical terms. 14 | /// 15 | /// Event grouping order is: [SUCCESS or FAILED][EVENT NAME][ERROR LIST][BROADCASTERS && SUBSCRIBERS] 16 | /// 17 | /// 18 | 19 | [ExecuteAlways] 20 | public class TranzmitDebug : SerializedMonoBehaviour 21 | { 22 | [Required] 23 | public Tranzmit Tranzmit; 24 | 25 | [FoldoutGroup("Events")] 26 | [ReadOnly] 27 | public Dictionary> Success = new Dictionary>(); 28 | 29 | [FoldoutGroup("Events")] 30 | [ReadOnly] 31 | public Dictionary> Failed = new Dictionary>(); 32 | public enum DebugTypes { Info, Warning, Error } 33 | 34 | [ShowOdinSerializedPropertiesInInspector] 35 | public class LogEntry 36 | { 37 | public Tranzmit.EventNames TranzmitEvent; 38 | public Tranzmit.DeliveryStatuses Status; 39 | 40 | // This errors list is key to organising and grouping stored events 41 | [ListDrawerSettings(Expanded = true)] 42 | public List Errors; 43 | 44 | public Type RequiredDataType; 45 | public List ProvidedDataTypes = new List(); 46 | public Dictionary Broadcasters = new Dictionary(); 47 | public Dictionary Subscribers = new Dictionary(); 48 | } 49 | 50 | [Serializable] 51 | public class ButtonData 52 | { 53 | public int EventCount = 0; 54 | 55 | //[HideInInspector] 56 | public Button GraphButton; 57 | } 58 | 59 | // Used for graceful allocation in Failed Log. Otherwise a new button etc will be generated for each Event without a source. 60 | // Pointless creating new ones as we don't know the source! ;) 61 | [HideInInspector] 62 | public object NullSourceObject = new object(); 63 | 64 | // ----------------------------------------------------------------------------------------- 65 | 66 | 67 | /// 68 | /// Used instead of Start as using [ExecuteAlways]. Called after recompiles etc 69 | /// 70 | void OnEnable() 71 | { 72 | SubscribeToTranzmit(); 73 | } 74 | 75 | // ----------------------------------------------------------------------------------------- 76 | 77 | /// 78 | /// This is called by Unity when an Object is being destroyed. 79 | /// 80 | private void OnDestroy() 81 | { 82 | UnsubscribeFromTranzmit(); 83 | } 84 | 85 | // ----------------------------------------------------------------------------------------- 86 | 87 | /// 88 | /// You might have noticed that I am using in-built Events to subscribe to Tranzmit, rather than using Tranzmit to handle them. There are multiple reasons including: 89 | /// - If Tranzmit breaks, the debugger has a chance of also failing. The number of events are minimal and easy to handle, so no biggy. 90 | /// - Reduces clutter in Tranzmit Events for the end user, so only their Events will be present. 91 | /// 92 | [ButtonGroup] 93 | void SubscribeToTranzmit() 94 | { 95 | UnsubscribeFromTranzmit(); 96 | 97 | if (Tranzmit != null) 98 | { 99 | Tranzmit.EventAdded += EventAdded; 100 | Tranzmit.EventDeleted += EventDeleted; 101 | Tranzmit.EventSent += EventSent; 102 | } 103 | else 104 | { 105 | Debug.Log("No Instance of Tranzmit has been found!\nTranzmit Graph will not be generated"); 106 | } 107 | } 108 | 109 | // ----------------------------------------------------------------------------------------- 110 | 111 | /// 112 | /// Unsubscribes from Tranzmits in-built events that are aimed for use by the debug tool, or any other tool the user might create. 113 | /// See above for further details on why this approach has been taken. 114 | /// 115 | void UnsubscribeFromTranzmit() 116 | { 117 | if (Tranzmit != null) 118 | { 119 | Tranzmit.EventAdded -= EventAdded; 120 | Tranzmit.EventDeleted -= EventDeleted; 121 | Tranzmit.EventSent -= EventSent; 122 | } 123 | else 124 | { 125 | Debug.Log("No Instance of Tranzmit has been found!\nTranzmit Graph will not be generated"); 126 | } 127 | } 128 | 129 | // ----------------------------------------------------------------------------------------- 130 | 131 | /// 132 | /// Clears all collected debug data 133 | /// 134 | [ButtonGroup] 135 | public void Reset() 136 | { 137 | Success = new Dictionary> (); 138 | Failed = new Dictionary> (); 139 | 140 | if (Tranzmit != null) 141 | { 142 | Tranzmit.Broadcast_Tranzmit_Debug_Reset(); 143 | } 144 | } 145 | 146 | // ----------------------------------------------------------------------------------------- 147 | 148 | /// 149 | /// A built-in Tranzmit Event sent by Tranzmit when an Event has been added to the Tranzmit Events Dictionary. 150 | /// 151 | /// The name of the event that was added to Tranzmit.Events 152 | public void EventAdded(Tranzmit.EventNames eventName) 153 | { 154 | // Currently Unused. 155 | } 156 | 157 | // ----------------------------------------------------------------------------------------- 158 | 159 | /// 160 | /// A built-in Tranzmit Event sent by Tranzmit when an Event has been removed from the Tranzmit Events Dictionary. 161 | /// When received, Tranzmit Debug will auto remove an debug data associated with the Event Name. 162 | /// 163 | /// The name of the event that was removed from Tranzmit.Events 164 | public void EventDeleted(Tranzmit.EventNames eventName) 165 | { 166 | Remove_Debug_Data_For_Deleted_Event_Type_ENUM(); 167 | Remove_Debug_Data_For_Deleted_Event_Type_In_TRANZMIT(); 168 | } 169 | 170 | // ----------------------------------------------------------------------------------------- 171 | 172 | /// 173 | /// The business end of Tranzmit Debug. When Tranzmit ATTEMPTS to send an event, it also broadcasts information about it. This is sent regardless of whether the requested Tranzmit Event was valid and sent. 174 | /// It creates and saves the associated data. Notice that we store the button information in here. This allows for more efficient updating of the Graphview. 175 | /// 176 | /// The object that requested for a Tranzmit event to be sent. Can be Null 177 | /// A basic 'Success' or 'Failed' output. 178 | /// A list of Enums that will show ALL issues (if any) with the Tranzmit Event Send request. 179 | /// The name of the Tranzmit Event. 180 | /// The data type specified by the user when they configured the Tranzmit Event. 181 | /// The type of data the user actually attached to the event. Can be Null. 182 | /// The Event/Delegate of the Tranzmit Event. 183 | public void EventSent(object payload, object source, Tranzmit.DeliveryStatuses status, List errors, Tranzmit.EventNames eventName, Type requiredDataType, Type providedDataType, Tranzmit.EventData.TranzmitDelegate tranzmitDelegate) 184 | { 185 | // This will be assigned to later on, and allows for cleaner code and less if statements etc 186 | Dictionary> saveLocation = null; 187 | 188 | // Allocate the Dictionary to use 189 | if (status == Tranzmit.DeliveryStatuses.Success) 190 | { 191 | saveLocation = Success; 192 | } 193 | else 194 | { 195 | saveLocation = Failed; 196 | } 197 | 198 | // Deal with potential NULL source 199 | if (source == null) 200 | { 201 | // We have to give it something! 202 | source = NullSourceObject; 203 | } 204 | 205 | LogEntry newLogEntry = new LogEntry(); 206 | 207 | // CREATE NEW EVENT LOGS FIRST - WILL APPLY TOTAL TO SUBSCRIBERS AND BROADCASTERS AFTER (BELOW) 208 | // NEW ENTRY INTO LIST - AS EVENT NAME NOT FOUND 209 | if (!saveLocation.ContainsKey(eventName)) 210 | { 211 | newLogEntry = GenerateLogEntry(source, status, errors, eventName, requiredDataType, providedDataType, tranzmitDelegate); 212 | saveLocation.Add(eventName, new List() { newLogEntry }); 213 | 214 | Tranzmit.Broadcast_Tranzmit_Log_Update(newLogEntry); 215 | } 216 | else // EXISTING EVENT - We now Compare the ERRORS list - If no match found create a new entry based on ERRRORS 217 | { 218 | // Null if not match found 219 | var foundLog = ReturnFirstLogEntryWithMatchingErrorsList(saveLocation[eventName], errors); 220 | 221 | // NEW ERRORS LIST 222 | if (foundLog == null) 223 | { 224 | newLogEntry = GenerateLogEntry(source, status, errors, eventName, requiredDataType, providedDataType, tranzmitDelegate); 225 | saveLocation[eventName].Add(newLogEntry); 226 | Tranzmit.Broadcast_Tranzmit_Log_Update(newLogEntry); 227 | } 228 | } 229 | 230 | // SUBSCRIBERS - We update subscribers in case new ones have been added through code at some point. 231 | //...and also add to the count if they already exist 232 | var currentSubscribers = Tranzmit.GetSubscribersInSentEvent(tranzmitDelegate); 233 | 234 | // SUBSCRIBERS 235 | if (saveLocation.ContainsKey(eventName)) 236 | { 237 | var foundLog = ReturnFirstLogEntryWithMatchingErrorsList(saveLocation[eventName], errors); 238 | 239 | if (foundLog != null) 240 | { 241 | foreach (object o in currentSubscribers) 242 | { 243 | if (foundLog.Subscribers.ContainsKey(o)) 244 | { 245 | foundLog.Subscribers[o].EventCount++; 246 | } 247 | else 248 | { 249 | foundLog.Subscribers.Add(o, new ButtonData() { EventCount = 0}); 250 | } 251 | } 252 | 253 | Tranzmit.Broadcast_Tranzmit_Log_Update(foundLog); 254 | } 255 | } 256 | 257 | // BROADCASTERS 258 | if (saveLocation.ContainsKey(eventName)) 259 | { 260 | var foundLog = ReturnFirstLogEntryWithMatchingErrorsList(saveLocation[eventName], errors); 261 | 262 | if (foundLog != null) 263 | { 264 | if (foundLog.Broadcasters.ContainsKey(source)) 265 | { 266 | foundLog.Broadcasters[source].EventCount++; 267 | } 268 | else 269 | { 270 | foundLog.Broadcasters.Add(source, new ButtonData() { EventCount = 1}); 271 | } 272 | 273 | Tranzmit.Broadcast_Tranzmit_Log_Update(foundLog); 274 | } 275 | } 276 | } 277 | 278 | // ----------------------------------------------------------------------------------------- 279 | 280 | /// 281 | /// Seperate function to deal with the actual creation of the Debug Log entry. 282 | /// 283 | /// The new generated log entry. 284 | public LogEntry GenerateLogEntry(object source, Tranzmit.DeliveryStatuses status, List errors, Tranzmit.EventNames eventName, Type requiredDataType, Type providedDataType, Tranzmit.EventData.TranzmitDelegate tranzmitDelegate) 285 | { 286 | var entry = new LogEntry(); 287 | entry.Status = status; 288 | entry.Errors = errors; 289 | entry.TranzmitEvent = eventName; 290 | entry.RequiredDataType = requiredDataType; 291 | entry.ProvidedDataTypes.Add(providedDataType); 292 | entry.Broadcasters.Add(source, new ButtonData() { EventCount = 0 }); 293 | 294 | var subscribers = Tranzmit.GetSubscribersInSentEvent(tranzmitDelegate); 295 | 296 | foreach (object subscriber in subscribers) 297 | { 298 | entry.Subscribers.Add(subscriber, new ButtonData()); 299 | } 300 | 301 | return entry; 302 | } 303 | 304 | // ----------------------------------------------------------------------------------------- 305 | 306 | /// 307 | /// Handy function to find a matching error list 308 | /// 309 | /// Either the log entry with matching error list OR NUll 310 | public LogEntry ReturnFirstLogEntryWithMatchingErrorsList(List logs, List errors) 311 | { 312 | var found = new List(); 313 | 314 | foreach (LogEntry log in logs) 315 | { 316 | if (log != null) 317 | { 318 | var areEquivalent = (log.Errors.Count == errors.Count) && !log.Errors.Except(errors).Any(); 319 | 320 | if (areEquivalent == true) 321 | { 322 | found.Add(log); 323 | } 324 | } 325 | } 326 | 327 | if(found.Count > 1) 328 | { 329 | Debug.LogError($"DEFENSIVE WARNING: More than 1 match when searching for matching Errors List were found! This should not have happened. Returning first entry in list!"); 330 | } 331 | 332 | if(found.Count > 0) 333 | { 334 | return found[0]; 335 | } 336 | else 337 | { 338 | return null; 339 | } 340 | } 341 | 342 | // ----------------------------------------------------------------------------------------- 343 | 344 | /// 345 | /// Used for when an Event has been removed from the EventNames Enums, and is called by a subscriber to Tranzmit built-in event system. 346 | /// 347 | public void Remove_Debug_Data_For_Deleted_Event_Type_ENUM() 348 | { 349 | // SUCCESS DATA 350 | var deleteSentItems = new List(); 351 | 352 | foreach (Tranzmit.EventNames eventName in Success.Keys) 353 | { 354 | if (Tranzmit.EventNameExists(eventName)) 355 | { 356 | deleteSentItems.Add(eventName); 357 | } 358 | } 359 | 360 | foreach (Tranzmit.EventNames deleteKey in deleteSentItems) 361 | { 362 | Success.Remove(deleteKey); 363 | } 364 | } 365 | 366 | // ----------------------------------------------------------------------------------------- 367 | 368 | /// 369 | /// Used for when an Event has been removed from the Tranzmit Events Dictionary, and is called by a subscriber to Tranzmit built-in event system. 370 | /// 371 | public void Remove_Debug_Data_For_Deleted_Event_Type_In_TRANZMIT() 372 | { 373 | // SENT DATA 374 | var deleteSentItems = new List(); 375 | foreach (Tranzmit.EventNames eventName in Success.Keys) 376 | { 377 | // If Event Type does not exist 378 | if (Tranzmit.CheckEventIsAllocated(eventName)) 379 | { 380 | deleteSentItems.Add(eventName); 381 | } 382 | } 383 | 384 | foreach (Tranzmit.EventNames deleteKey in deleteSentItems) 385 | { 386 | Success.Remove(deleteKey); 387 | } 388 | } 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /Example Code/Broadcaster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using UnityEngine; 4 | using Sirenix.OdinInspector; 5 | using Blep.Tranzmit; 6 | using System.Collections.Generic; 7 | 8 | 9 | /// 10 | /// Example script that shows how you can broadcast an Event: 11 | /// 12 | 13 | namespace Blep.Tranzmit.Demo 14 | { 15 | public class Broadcaster : MonoBehaviour 16 | { 17 | [FoldoutGroup("Settings")] 18 | [Required] 19 | public Tranzmit Tranzmit; 20 | 21 | [FoldoutGroup("Settings")] 22 | [Tooltip("Only works at Runtime. When true will cause a constant stream of Tranzmit Events to be sent.")] 23 | public bool StressTest = false; 24 | 25 | [FoldoutGroup("Settings")] 26 | [Tooltip("Multiplies the amount of broadcasts sent.")] 27 | [Range(1, 100)] 28 | public int StressMultiplier = 10; 29 | 30 | [FoldoutGroup("Settings")] 31 | [Tooltip("Delay between broadcasts.")] 32 | [Range(0.01f, 10)] 33 | public float SendDelay = 1; 34 | 35 | [FoldoutGroup("Settings")] 36 | public PlayerStatsData PlayerStatsTestData; 37 | 38 | private DummyClassData DummyClass; 39 | 40 | [Serializable] 41 | public struct PlayerStatsData 42 | { 43 | public string Name; 44 | public float Health; 45 | } 46 | 47 | public class DummyClassData 48 | { 49 | public string Sometext = "Some Text for Dummy class"; 50 | } 51 | 52 | // ----------------------------------------------------------------------------------------- 53 | 54 | private void Start() 55 | { 56 | StartCoroutine(Main()); 57 | 58 | if (StressTest) 59 | { 60 | for (int i = 0; i < StressMultiplier; i++) 61 | { 62 | // The SendPlayerStats example is using an already created instance of SendPlayerStats. This is to reduce Garbage collection when load testing as it could potentially distort the results. 63 | SendPlayerStats(Tranzmit.EventNames.PlayerStats); 64 | SendDamage(Tranzmit.EventNames.Damage); 65 | SendSecretFound(Tranzmit.EventNames.SecretFound); 66 | } 67 | } 68 | } 69 | 70 | // ----------------------------------------------------------------------------------------- 71 | 72 | IEnumerator Main() 73 | { 74 | while (true) 75 | { 76 | if (StressTest) 77 | { 78 | yield return new WaitForSeconds(SendDelay); 79 | 80 | for (int i = 0; i < StressMultiplier; i++) 81 | { 82 | // The SendPlayerStats example is using an alrerady created instance of SendPlayerStats. This is to reduce Garbage collection when load testing as it could potentially distort the results. 83 | SendPlayerStats(Tranzmit.EventNames.PlayerStats); 84 | SendDamage(Tranzmit.EventNames.Damage); 85 | SendSecretFound(Tranzmit.EventNames.SecretFound); 86 | } 87 | } 88 | 89 | yield return null; 90 | } 91 | } 92 | 93 | // ----------------------------------------------------------------------------------------- 94 | 95 | [Button("Send Player Stats"), GUIColor(0.5f, 0.5f, 1)] 96 | [PropertySpace(20, 10)] 97 | public void SendPlayerStats(Tranzmit.EventNames eventName = Tranzmit.EventNames.PlayerStats) 98 | { 99 | if (Tranzmit != null) 100 | { 101 | PlayerStatsTestData.Health = UnityEngine.Random.Range(0, 100); 102 | PlayerStatsTestData.Name = GenerateName(UnityEngine.Random.Range(5, 20)); 103 | 104 | // BROADCAST! 105 | Tranzmit.BroadcastEvent(eventName, this, PlayerStatsTestData); 106 | } 107 | else 108 | { 109 | Debug.Log("No Instance of Tranzmit has been found!"); 110 | } 111 | } 112 | 113 | // ----------------------------------------------------------------------------------------- 114 | 115 | [Button("Send Damage"), GUIColor(0.5f, 0.5f, 1)] 116 | [PropertySpace(10, 10)] 117 | public void SendDamage(Tranzmit.EventNames eventName = Tranzmit.EventNames.Damage) 118 | { 119 | if (Tranzmit != null) 120 | { 121 | // BROADCAST! 122 | Tranzmit.BroadcastEvent(eventName, this, UnityEngine.Random.Range(0, 100)); 123 | } 124 | else 125 | { 126 | Debug.Log("No Instance of Tranzmit has been found!"); 127 | } 128 | } 129 | 130 | // ----------------------------------------------------------------------------------------- 131 | 132 | [Button("Send Secret Found"), GUIColor(0.5f, 0.5f, 1)] 133 | [PropertySpace(10, 10)] 134 | public void SendSecretFound(Tranzmit.EventNames eventName = Tranzmit.EventNames.SecretFound) 135 | { 136 | if (Tranzmit != null) 137 | { 138 | // BROADCAST! 139 | Tranzmit.BroadcastEvent(eventName, this, RandomBoolean()); 140 | } 141 | else 142 | { 143 | Debug.Log("No Instance of Tranzmit has been found!"); 144 | } 145 | } 146 | 147 | // ----------------------------------------------------------------------------------------- 148 | 149 | [Button("Generate No Source Errors"), GUIColor(0.5f, 0.5f, 1)] 150 | public void Test1() 151 | { 152 | foreach (KeyValuePair tranzmitEvent in Tranzmit.Events) 153 | { 154 | if (tranzmitEvent.Value.Info.EventName == Tranzmit.EventNames.Damage) 155 | { 156 | // BROADCAST! 157 | tranzmitEvent.Value.Send(null, UnityEngine.Random.Range(0, 100)); 158 | } 159 | 160 | if (tranzmitEvent.Value.Info.EventName == Tranzmit.EventNames.SecretFound) 161 | { 162 | // BROADCAST! 163 | tranzmitEvent.Value.Send(null, true); 164 | } 165 | 166 | if (tranzmitEvent.Value.Info.EventName == Tranzmit.EventNames.PlayerStats) 167 | { 168 | // BROADCAST! 169 | tranzmitEvent.Value.Send(null, new PlayerStatsData(){ Name = GenerateName(UnityEngine.Random.Range(5, 20)), Health = UnityEngine.Random.Range(0, 100)}); 170 | } 171 | } 172 | } 173 | 174 | // ----------------------------------------------------------------------------------------- 175 | 176 | [Button("Generate No Payload Errors"), GUIColor(0.5f, 0.5f, 1)] 177 | public void Test2() 178 | { 179 | foreach (KeyValuePair tranzmitEvent in Tranzmit.Events) 180 | { 181 | // BROADCAST! 182 | tranzmitEvent.Value.Send(this, null); 183 | } 184 | } 185 | 186 | // ----------------------------------------------------------------------------------------- 187 | 188 | [Button("Generate Wrong Data Type Errors"), GUIColor(0.5f, 0.5f, 1)] 189 | public void Test3() 190 | { 191 | foreach (KeyValuePair tranzmitEvent in Tranzmit.Events) 192 | { 193 | // BROADCAST! 194 | tranzmitEvent.Value.Send(this, new DummyClassData(){ Sometext = "Some text!"}); 195 | } 196 | } 197 | 198 | // ----------------------------------------------------------------------------------------- 199 | 200 | [Button("Generate Multiple Errors"), GUIColor(0.5f, 0.5f, 1)] 201 | public void Test4() 202 | { 203 | foreach (KeyValuePair tranzmitEvent in Tranzmit.Events) 204 | { 205 | // BROADCAST! 206 | tranzmitEvent.Value.Send(null, null); 207 | } 208 | } 209 | 210 | // ----------------------------------------------------------------------------------------- 211 | 212 | public bool RandomBoolean () 213 | { 214 | if (UnityEngine.Random.value >= 0.5) 215 | { 216 | return true; 217 | } 218 | return false; 219 | } 220 | 221 | // ----------------------------------------------------------------------------------------- 222 | 223 | public string GenerateName(int len) 224 | { 225 | System.Random r = new System.Random(); 226 | string[] consonants = { "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "l", "n", "p", "q", "r", "s", "sh", "zh", "t", "v", "w", "x" }; 227 | string[] vowels = { "a", "e", "i", "o", "u", "ae", "y" }; 228 | string Name = ""; 229 | Name += consonants[r.Next(consonants.Length)].ToUpper(); 230 | Name += vowels[r.Next(vowels.Length)]; 231 | int b = 2; //b tells how many times a new letter has been added. It's 2 right now because the first two letters are already in the name. 232 | while (b < len) 233 | { 234 | Name += consonants[r.Next(consonants.Length)]; 235 | b++; 236 | Name += vowels[r.Next(vowels.Length)]; 237 | b++; 238 | } 239 | 240 | return Name; 241 | } 242 | } 243 | } -------------------------------------------------------------------------------- /Example Code/Subscriber.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using Sirenix.OdinInspector; 3 | using Blep.Tranzmit; 4 | 5 | /// 6 | /// 7 | /// - This is an example script, showing how to subscribe to an event in Tranzmit. For example: 8 | /// 9 | /// - Don't forget to Unsubsribe from events when destroying an object! Otherwise you will suffer from memory leaks. This is standard coding practice, and not a limitation of this code. 10 | /// 11 | /// 12 | 13 | namespace Blep.Tranzmit.Demo 14 | { 15 | // Make useable in the editor 16 | [ExecuteAlways] 17 | public class Subscriber : MonoBehaviour 18 | { 19 | [Required] 20 | public Tranzmit Tranzmit; 21 | 22 | [Tooltip("Used by the demo scene UI")] 23 | public EventsSentUI EventsSentUI; 24 | 25 | [Tooltip("Suppress output to the Output field")] 26 | public bool Silent = false; 27 | 28 | [Tooltip("How many times we subscribe to all 3 events setup in the test scene")] 29 | public int SubscribeIterations = 1; 30 | 31 | [TextArea(3, 30)] 32 | public string Output; 33 | 34 | // ----------------------------------------------------------------------------------------- 35 | 36 | /// 37 | /// Used instead of Start as using [ExecuteAlways]. Called after recompiles etc 38 | /// 39 | void OnEnable() 40 | { 41 | Subscribe(); 42 | Output = ""; 43 | } 44 | 45 | // ----------------------------------------------------------------------------------------- 46 | 47 | /// 48 | /// This is called by Unity when an Object is being destroyed. 49 | /// 50 | private void OnDestroy() 51 | { 52 | // Unsubscribe fromt the events. This is important to prevent memory leakage. 53 | Unsubscribe(); 54 | } 55 | 56 | // ----------------------------------------------------------------------------------------- 57 | 58 | /// 59 | /// Demonstrates on how to Subscribe to a Tranzmit Event. 60 | /// 61 | [ButtonGroup] 62 | public void Subscribe() 63 | { 64 | // Yep! Playing it safe, and try to keep things tidy. 65 | Unsubscribe(); 66 | 67 | if (Tranzmit != null) 68 | { 69 | // Yes, you can subscribe in the same way, multiple times! 70 | for (int i = 0; i < SubscribeIterations; i++) 71 | { 72 | // Rather than blindly trying to access the Tranzmit Event, I have created a helper to check to see if it will be valid. 73 | // I recommend using this approach. 74 | if (Tranzmit.CheckEventIsAvailable(Tranzmit.EventNames.PlayerStats)) 75 | { 76 | Tranzmit.Events[Tranzmit.EventNames.PlayerStats].TranzmitEvent += PlayerStatsAction; 77 | } 78 | 79 | if (Tranzmit.CheckEventIsAvailable(Tranzmit.EventNames.Damage)) 80 | { 81 | Tranzmit.Events[Tranzmit.EventNames.Damage].TranzmitEvent += DamageAction; 82 | } 83 | 84 | if (Tranzmit.CheckEventIsAvailable(Tranzmit.EventNames.SecretFound)) 85 | { 86 | Tranzmit.Events[Tranzmit.EventNames.SecretFound].TranzmitEvent += SecretFoundAction; 87 | } 88 | } 89 | } 90 | else 91 | { 92 | Debug.LogWarning("No Instance of Tranzmit has been found!"); 93 | } 94 | } 95 | 96 | // ----------------------------------------------------------------------------------------- 97 | 98 | /// 99 | /// Demonstrates on how to Unsubscribe from a Tranzmit Event. 100 | /// 101 | [ButtonGroup] 102 | void Unsubscribe() 103 | { 104 | if (Tranzmit != null) 105 | { 106 | for (int i = 0; i < SubscribeIterations; i++) 107 | { 108 | // Rather than blindly trying to access the Tranzmit Event, I have created a helper to check to see if it will be valid. 109 | // I recommend using this approach. 110 | if (Tranzmit.CheckEventIsAvailable(Tranzmit.EventNames.PlayerStats)) 111 | { 112 | Tranzmit.Events[Tranzmit.EventNames.PlayerStats].TranzmitEvent -= PlayerStatsAction; 113 | } 114 | 115 | if (Tranzmit.CheckEventIsAvailable(Tranzmit.EventNames.Damage)) 116 | { 117 | Tranzmit.Events[Tranzmit.EventNames.Damage].TranzmitEvent -= DamageAction; 118 | } 119 | 120 | if (Tranzmit.CheckEventIsAvailable(Tranzmit.EventNames.SecretFound)) 121 | { 122 | Tranzmit.Events[Tranzmit.EventNames.SecretFound].TranzmitEvent -= SecretFoundAction; 123 | } 124 | } 125 | } 126 | } 127 | 128 | // ----------------------------------------------------------------------------------------- 129 | 130 | [ButtonGroup] 131 | private void Reset() 132 | { 133 | Output = ""; 134 | } 135 | 136 | // ----------------------------------------------------------------------------------------- 137 | 138 | /// 139 | /// Test function for when the specified Tranzmit Event has occured. 140 | /// 141 | /// The Object that is using Tranzmit to send an Event. 142 | /// The data being passed through Tranzmit to the subscribers of the event. 143 | void PlayerStatsAction(object source, object payload) 144 | { 145 | if (EventsSentUI != null) 146 | { 147 | EventsSentUI.Total++; 148 | } 149 | 150 | var data = (Broadcaster.PlayerStatsData)payload; 151 | 152 | if (Silent == false) 153 | Output += "\n\n" + this.GetType().Name + "\n" + data.Name + " | " + data.Health; 154 | } 155 | 156 | // ----------------------------------------------------------------------------------------- 157 | 158 | /// 159 | /// Test function for when the specified Tranzmit Event has occured. 160 | /// 161 | /// The Object that is using Tranzmit to send an Event. 162 | /// The data being passed through Tranzmit to the subscribers of the event. 163 | void DamageAction(object source, object payload) 164 | { 165 | if (EventsSentUI != null) 166 | { 167 | EventsSentUI.Total++; 168 | } 169 | 170 | var data = (int)payload; 171 | 172 | if (Silent == false) 173 | Output += "\n\n" + GetType().Name + "\n" + data; 174 | } 175 | 176 | // ----------------------------------------------------------------------------------------- 177 | 178 | /// 179 | /// Test function for when the specified Tranzmit Event has occured. 180 | /// 181 | /// The Object that is using Tranzmit to send an Event. 182 | /// The data being passed through Tranzmit to the subscribers of the event. 183 | void SecretFoundAction(object source, object payload) 184 | { 185 | if (EventsSentUI != null) 186 | { 187 | EventsSentUI.Total++; 188 | } 189 | 190 | var data = (bool)payload; 191 | 192 | if (Silent == false) 193 | Output += "\n\n" + this.GetType().Name + " | " + data; 194 | } 195 | } 196 | } -------------------------------------------------------------------------------- /Images/tranzmit-debug-v2-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-blep/Tranzmit/136233d34e741699f7309223d27b9bdfacf2ce77/Images/tranzmit-debug-v2-ui.png -------------------------------------------------------------------------------- /Images/trazmit-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-blep/Tranzmit/136233d34e741699f7309223d27b9bdfacf2ce77/Images/trazmit-graph.png -------------------------------------------------------------------------------- /Images/trazmit-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-blep/Tranzmit/136233d34e741699f7309223d27b9bdfacf2ce77/Images/trazmit-main.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Pixel Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tranzmit 2 | Unity 3D Event system that uses the new Experimental Unity GraphView (https://docs.unity3d.com/ScriptReference/Experimental.GraphView.GraphView.html), allowing visualization of the flow of event data. 3 | 4 | REQUIRED COMPONENT - Will Not Compile without Odin Inspector!: 5 | https://odininspector.com/ 6 | 7 | NOTE - Graph will not be operational until an Event has been added. 8 | 9 | ### Releases 10 | * V1 - Tranzmit Core, and Debug V1 that works with Unity Graphview API based debug visualization 11 | * V2 - Minor Tweaks to Tranzmit Core, new Debug V2 (V1 is still included) with a Unity UI based debug visualization to go with it. 12 | 13 | ### Details 14 | I love Event Driven Architectures (EDA). It makes for nice, decoupled code. But I am not a fan of how ambiguous the relationships between scripts can be. Enter Tranzmit, a fully functional, object based (send anything!) event system... with a twist! 15 | 16 | ### Main Features: 17 | * Multi level error checking / handling 18 | * Multiple real time logging and visual feedback tools 19 | * Various code examples 20 | * Send any object 21 | * Minimal coding required 22 | * Clean Interface power by Odin Inspector 23 | * Multi platform 24 | * Zero Garbage Collection when ran as compiled EXE (as far as my tests show!) 25 | 26 | I have also developed various event logging tools, for the monitoring and debugging of Events. Those tools are further extended by visualization tools. 27 | 28 | V1 Debug is leveraging the Unity GraphView API, along with the power of Odin Inspector, you can also see in real time which scripts are sending events, and which scripts are listening, receiving ...and failing! Clicking on graph elements takes you to the scripts, acting as a navigation system for your code! 29 | 30 | V2 Debug uses the Unity UI API for compiled runtime visualization and feedback. It has filtering options and controls for the Debug V2 tool. 31 | 32 | Why the dependency on Odin Inspector? In short, this project was coded for myself, and the last thing I want to be doing is hand coding custom Unity interfaces, when I can do it in a fraction of the time (and better!) with Odin Inspector. If you do any kind of coding in Unity on a regular basis, you should seriously consider using Odin Inspector. It's the first thing I setup in any new project. 33 | 34 | That said, if there is enough interest in Tranzmit without Odin Inspector, I would consider developing the custom interfaces required. 35 | 36 | I hope this proves useful to someone, and if you have any comments or improvements regarding this code, please do so! :) 37 | 38 | Additional info will be made available at https://blep.io 39 | 40 | Overview video on YouTube: https://youtu.be/BfAUmtgjHac 41 | 42 | Odin Inspector Community Tools: https://odininspector.com/community-tools/58C/tranzmit-an-event-system-with-visual-feedback-and-multi-level-error-checking 43 | 44 | ![Image of Trazmit Components](Images/trazmit-main.png) 45 | ![Image of Trazmit GraphView](Images/trazmit-graph.png) 46 | ![Image of Trazmit Debug V2 UI](Images/tranzmit-debug-v2-ui.png) 47 | -------------------------------------------------------------------------------- /Tranzmit with Debug V1 and V2 Demo Scenes.unitypackage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-blep/Tranzmit/136233d34e741699f7309223d27b9bdfacf2ce77/Tranzmit with Debug V1 and V2 Demo Scenes.unitypackage --------------------------------------------------------------------------------