├── .github └── FUNDING.yml ├── .gitignore ├── DevsDaddy.meta ├── DevsDaddy ├── Shared.meta └── Shared │ ├── EventFramework.meta │ └── EventFramework │ ├── Core.meta │ ├── Core │ ├── Extensions.meta │ ├── Extensions │ │ ├── CollectionExtensions.cs │ │ └── CollectionExtensions.cs.meta │ ├── Messenger.meta │ ├── Messenger │ │ ├── EventSubscriber.cs │ │ ├── EventSubscriber.cs.meta │ │ ├── IEventMessenger.cs │ │ ├── IEventMessenger.cs.meta │ │ ├── IEventMessengerPublish.cs │ │ ├── IEventMessengerPublish.cs.meta │ │ ├── IEventMessengerSubscribe.cs │ │ ├── IEventMessengerSubscribe.cs.meta │ │ ├── IEventMessengerUnsubscribe.cs │ │ └── IEventMessengerUnsubscribe.cs.meta │ ├── Objects.meta │ ├── Objects │ │ ├── MonoSingleton.cs │ │ ├── MonoSingleton.cs.meta │ │ ├── Singleton.cs │ │ └── Singleton.cs.meta │ ├── Payloads.meta │ ├── Payloads │ │ ├── IPayload.cs │ │ └── IPayload.cs.meta │ ├── Threading.meta │ └── Threading │ │ ├── DispatcherTask.cs │ │ ├── DispatcherTask.cs.meta │ │ ├── IThreadDispatcher.cs │ │ ├── IThreadDispatcher.cs.meta │ │ ├── MainThreadDispatcher.cs │ │ ├── MainThreadDispatcher.cs.meta │ │ ├── WeakRefDelegate.cs │ │ ├── WeakRefDelegate.cs.meta │ │ ├── WeakRefWrapper.cs │ │ └── WeakRefWrapper.cs.meta │ ├── EventFramework.asmdef │ ├── EventFramework.asmdef.meta │ ├── EventMessenger.cs │ ├── EventMessenger.cs.meta │ ├── Preview.png │ ├── Preview.png.meta │ ├── package.json │ └── package.json.meta ├── LICENSE └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | custom: https://boosty.to/devsdaddy 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # MemoryCaptures can get excessive in size. 14 | # They also could contain extremely sensitive data 15 | /[Mm]emoryCaptures/ 16 | 17 | # Recordings can get excessive in size 18 | /[Rr]ecordings/ 19 | 20 | # Uncomment this line if you wish to ignore the asset store tools plugin 21 | # /[Aa]ssets/AssetStoreTools* 22 | 23 | # Autogenerated Jetbrains Rider plugin 24 | /[Aa]ssets/Plugins/Editor/JetBrains* 25 | 26 | # Visual Studio cache directory 27 | .vs/ 28 | 29 | # Gradle cache directory 30 | .gradle/ 31 | 32 | # Autogenerated VS/MD/Consulo solution and project files 33 | ExportedObj/ 34 | .consulo/ 35 | *.csproj 36 | *.unityproj 37 | *.sln 38 | *.suo 39 | *.tmp 40 | *.user 41 | *.userprefs 42 | *.pidb 43 | *.booproj 44 | *.svd 45 | *.pdb 46 | *.mdb 47 | *.opendb 48 | *.VC.db 49 | 50 | # Unity3D generated meta files 51 | *.pidb.meta 52 | *.pdb.meta 53 | *.mdb.meta 54 | 55 | # Unity3D generated file on crash reports 56 | sysinfo.txt 57 | 58 | # Builds 59 | *.apk 60 | *.aab 61 | *.unitypackage 62 | *.app 63 | 64 | # Crashlytics generated file 65 | crashlytics-build.properties 66 | 67 | # Packed Addressables 68 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* 69 | 70 | # Temporary auto-generated Android Assets 71 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 72 | /[Aa]ssets/[Ss]treamingAssets/aa/* 73 | -------------------------------------------------------------------------------- /DevsDaddy.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6f43c744ec02df449ad432a3ec700e2 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /DevsDaddy/Shared.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bb5671adff99c27419f1d633a2f6f2ef 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 77c0d33981124b71b31b00801813a8da 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d12fd6a46d46479297ce2953ae2fd4d8 3 | timeCreated: 1709907914 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Extensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 00986101bb37441889fc367b31e30c54 3 | timeCreated: 1709907934 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Extensions/CollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DevsDaddy.Shared.EventFramework.Core.Extensions 5 | { 6 | public static class CollectionExtensions 7 | { 8 | public static object[] ToObjectArray(this T[] source) 9 | { 10 | if(source.IsNullOrEmpty()) 11 | { 12 | return null; 13 | } 14 | var copy = new object[source.Length]; 15 | Array.Copy(source, copy, source.Length); 16 | return copy; 17 | } 18 | 19 | public static bool IsNullOrEmpty(this ICollection source) 20 | { 21 | if(source == null) 22 | { 23 | return true; 24 | } 25 | if(source.Count < 1) 26 | { 27 | return true; 28 | } 29 | return false; 30 | } 31 | 32 | public static void ForEach(this IEnumerable collection, Action action) 33 | { 34 | foreach (var item in collection) 35 | { 36 | action(item); 37 | } 38 | } 39 | 40 | public static bool IsNullOrEmpty(this string source) 41 | { 42 | var isEmpty = string.IsNullOrEmpty(source); 43 | return isEmpty; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Extensions/CollectionExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d3fbd7a03f204ae9be879f9f91d1e8b7 3 | timeCreated: 1709907949 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a529d3773c3a4c079cb6deb5aec78c83 3 | timeCreated: 1709908056 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/EventSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using UnityEngine; 4 | 5 | namespace DevsDaddy.Shared.EventFramework.Core.Messenger 6 | { 7 | /// 8 | /// Event Subscriber Class 9 | /// 10 | internal class EventSubscriber : IDisposable 11 | { 12 | private WeakReference _callbackTarget; 13 | private MethodInfo _callbackMethod; 14 | 15 | private WeakReference _predicateTarget; 16 | private MethodInfo _predicateMethod; 17 | 18 | public bool IsAlive 19 | { 20 | get 21 | { 22 | if(_callbackMethod == null) 23 | { 24 | return false; 25 | } 26 | if(_callbackMethod.IsStatic) 27 | { 28 | return true; 29 | } 30 | if(_callbackTarget == null || 31 | !_callbackTarget.IsAlive || 32 | _callbackTarget.Target == null) 33 | { 34 | return false; 35 | } 36 | return true; 37 | } 38 | } 39 | 40 | public Type PayloadType 41 | { 42 | get; 43 | } 44 | 45 | public int Id 46 | { 47 | get; 48 | } 49 | 50 | public override int GetHashCode() 51 | { 52 | return Id; 53 | } 54 | 55 | public EventSubscriber(Type payloadType, Delegate callback, Delegate predicate = null) 56 | { 57 | // validate params 58 | if(payloadType == null) 59 | { 60 | throw new ArgumentNullException(nameof(payloadType)); 61 | } 62 | if(callback == null) 63 | { 64 | throw new ArgumentNullException(nameof(callback)); 65 | } 66 | 67 | // assign values to vars 68 | PayloadType = payloadType; 69 | Id = callback.GetHashCode(); 70 | _callbackMethod = callback.Method; 71 | 72 | // check if callback method is not a static method 73 | if(!_callbackMethod.IsStatic && 74 | callback.Target != null) 75 | { 76 | // init weak reference to callback owner 77 | _callbackTarget = new WeakReference(callback.Target); 78 | } 79 | 80 | // --- init predicate --- 81 | if(predicate == null) 82 | { 83 | return; 84 | } 85 | _predicateMethod = predicate.Method; 86 | 87 | if(!_predicateMethod.IsStatic && 88 | !Equals(predicate.Target, callback.Target)) 89 | { 90 | _predicateTarget = new WeakReference(predicate.Target); 91 | } 92 | } 93 | 94 | public void Invoke(T payload) 95 | { 96 | // validate callback method info 97 | if(_callbackMethod == null) 98 | { 99 | Debug.LogError($"{nameof(_callbackMethod)} is null."); 100 | return; 101 | } 102 | if(!_callbackMethod.IsStatic && 103 | (_callbackTarget == null || 104 | !_callbackTarget.IsAlive)) 105 | { 106 | Debug.LogWarning($"{nameof(_callbackMethod)} is not alive."); 107 | return; 108 | } 109 | 110 | // get reference to the predicate function owner 111 | if(_predicateMethod != null) 112 | { 113 | object predicateTarget = null; 114 | if(!_predicateMethod.IsStatic) 115 | { 116 | if(_predicateTarget != null && 117 | _predicateTarget.IsAlive) 118 | { 119 | predicateTarget = _predicateTarget.Target; 120 | } 121 | else if(_callbackTarget != null && 122 | _callbackTarget.IsAlive) 123 | { 124 | predicateTarget = _callbackTarget.Target; 125 | } 126 | } 127 | 128 | // check if predicate returned 'true' 129 | var isAccepted = (bool)_predicateMethod.Invoke(predicateTarget, new object[] {payload}); 130 | if(!isAccepted) 131 | { 132 | // TODO log ? 133 | return; 134 | } 135 | } 136 | 137 | // invoke callback method 138 | object callbackTarget = null; 139 | if(!_callbackMethod.IsStatic && 140 | _callbackTarget != null && _callbackTarget.IsAlive) 141 | { 142 | callbackTarget = _callbackTarget.Target; 143 | } 144 | _callbackMethod.Invoke(callbackTarget, new object[] {payload}); 145 | } 146 | 147 | public void Dispose() 148 | { 149 | _callbackMethod = null; 150 | if(_callbackTarget != null) 151 | { 152 | _callbackTarget.Target = null; 153 | _callbackTarget = null; 154 | } 155 | 156 | _predicateMethod = null; 157 | if(_predicateTarget != null) 158 | { 159 | _predicateTarget.Target = null; 160 | _predicateTarget = null; 161 | } 162 | } 163 | } 164 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/EventSubscriber.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 159809fba4d643b4b5a48bf76d03fee0 3 | timeCreated: 1709908344 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/IEventMessenger.cs: -------------------------------------------------------------------------------- 1 | namespace DevsDaddy.Shared.EventFramework.Core.Messenger 2 | { 3 | /// 4 | /// Event Messenger Interface 5 | /// 6 | public interface IEventMessenger : IEventMessengerPublish, IEventMessengerSubscribe, IEventMessengerUnsubscribe { } 7 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/IEventMessenger.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 839409adb47840e9815050e158c5ae2b 3 | timeCreated: 1709908063 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/IEventMessengerPublish.cs: -------------------------------------------------------------------------------- 1 | using DevsDaddy.Shared.EventFramework.Core.Payloads; 2 | 3 | namespace DevsDaddy.Shared.EventFramework.Core.Messenger 4 | { 5 | /// 6 | /// Event Messenger Publish Interface 7 | /// 8 | public interface IEventMessengerPublish 9 | { 10 | /// 11 | /// Publish Payload 12 | /// 13 | /// 14 | /// 15 | /// 16 | IEventMessengerPublish Publish(T payload) where T : IPayload; 17 | 18 | /// 19 | /// Get Current Payload State or Null 20 | /// 21 | /// 22 | /// 23 | T GetState() where T : class, IPayload; 24 | } 25 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/IEventMessengerPublish.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b08fc7fb9da9403faae63d3d185b3244 3 | timeCreated: 1709908097 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/IEventMessengerSubscribe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DevsDaddy.Shared.EventFramework.Core.Payloads; 3 | 4 | namespace DevsDaddy.Shared.EventFramework.Core.Messenger 5 | { 6 | /// 7 | /// Event Messenger Subscribe Interface 8 | /// 9 | public interface IEventMessengerSubscribe 10 | { 11 | /// 12 | /// Subscribe Listener to Payload 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | IEventMessengerSubscribe Subscribe(Action callback, Predicate predicate = null) where T : IPayload; 19 | } 20 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/IEventMessengerSubscribe.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 08a5957f355341e999b24f3a31d70ead 3 | timeCreated: 1709908173 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/IEventMessengerUnsubscribe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DevsDaddy.Shared.EventFramework.Core.Payloads; 3 | 4 | namespace DevsDaddy.Shared.EventFramework.Core.Messenger 5 | { 6 | /// 7 | /// Event Messenger Unsubscribe Interface 8 | /// 9 | public interface IEventMessengerUnsubscribe 10 | { 11 | /// 12 | /// Unsubscribe Listener from Payload 13 | /// 14 | /// 15 | /// 16 | /// 17 | IEventMessengerUnsubscribe Unsubscribe(Action callback) where T : IPayload; 18 | } 19 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Messenger/IEventMessengerUnsubscribe.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2cb648b65a7d403b852deae7c357ba17 3 | timeCreated: 1709908220 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Objects.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40e14a4be7b74fcaa144747f26cb6d61 3 | timeCreated: 1709915276 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Objects/MonoSingleton.cs: -------------------------------------------------------------------------------- 1 | using DevsDaddy.Shared.EventFramework.Core.Extensions; 2 | using UnityEngine; 3 | 4 | namespace DevsDaddy.Shared.EventFramework.Core.Objects 5 | { 6 | public class MonoSingleton : MonoBehaviour where TImplementation : MonoBehaviour, TInterface 7 | { 8 | private static TInterface _main; 9 | 10 | public static TInterface Main 11 | { 12 | get 13 | { 14 | var res = InvalidateInstance(); 15 | return res; 16 | } 17 | } 18 | 19 | private void Awake() 20 | { 21 | InvalidateInstance(); 22 | } 23 | 24 | private static TInterface InvalidateInstance() 25 | { 26 | if(!Equals(_main, default(TImplementation))) 27 | { 28 | return _main; 29 | } 30 | 31 | var typeInterface = typeof(TInterface); 32 | var objects = FindObjectsOfType(); 33 | if(!objects.IsNullOrEmpty()) 34 | { 35 | foreach (var obj in objects) 36 | { 37 | if(typeInterface.IsAssignableFrom(obj.GetType())) 38 | { 39 | _main = obj; 40 | } 41 | } 42 | } 43 | 44 | if (!Equals(_main, default(TImplementation))) 45 | { 46 | return _main; 47 | } 48 | 49 | var typeImplementation = typeof(TImplementation); 50 | var go = new GameObject($"[{typeImplementation.Name}]"); 51 | go.transform.SetParent(null); 52 | 53 | _main = go.AddComponent(); 54 | return _main; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Objects/MonoSingleton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e57d2676d9d346e9a3d7c2151fe05a9f 3 | timeCreated: 1709915290 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Objects/Singleton.cs: -------------------------------------------------------------------------------- 1 | namespace DevsDaddy.Shared.EventFramework.Core.Objects 2 | { 3 | public abstract class Singleton 4 | where TImplementation : TInterface, new() 5 | { 6 | public static TInterface Main { get; } = new TImplementation(); 7 | 8 | protected Singleton() 9 | { 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Objects/Singleton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a8062424bdd743b6aa1b3e73b62ce5c9 3 | timeCreated: 1709915383 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Payloads.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0b89c307c8b04b62b2fb657737d7f4ec 3 | timeCreated: 1709908134 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Payloads/IPayload.cs: -------------------------------------------------------------------------------- 1 | namespace DevsDaddy.Shared.EventFramework.Core.Payloads 2 | { 3 | /// 4 | /// Payload 5 | /// 6 | public interface IPayload { } 7 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Payloads/IPayload.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0afffdf99c7d44468a1a482cc5769a2e 3 | timeCreated: 1709908140 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fb7b7428eea74614825d8dadf35538e6 3 | timeCreated: 1709908759 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/DispatcherTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DevsDaddy.Shared.EventFramework.Core.Threading 4 | { 5 | public class DispatcherTask : IDisposable 6 | { 7 | public WeakRefDelegate Action 8 | { 9 | get; private set; 10 | } 11 | 12 | private object[] Payload 13 | { 14 | get; 15 | set; 16 | } 17 | 18 | public DispatcherTask(Delegate action, object[] payload) 19 | { 20 | Action = new WeakRefDelegate(action); 21 | Payload = payload; 22 | } 23 | 24 | public void Invoke() 25 | { 26 | if(Action == null || !Action.IsAlive) 27 | { 28 | return; 29 | } 30 | Action.Invoke(Payload); 31 | } 32 | 33 | public void Dispose() 34 | { 35 | if(Action != null) 36 | { 37 | Action.Dispose(); 38 | Action = null; 39 | } 40 | Payload = null; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/DispatcherTask.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a89d39c53f104fc2b275ccdfb9985f14 3 | timeCreated: 1709908762 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/IThreadDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DevsDaddy.Shared.EventFramework.Core.Threading 4 | { 5 | /// 6 | /// Thread Dispatcher Interface 7 | /// 8 | public interface IThreadDispatcher 9 | { 10 | int ThreadId { get; } 11 | void Dispatch(Delegate action, object[] payload); 12 | } 13 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/IThreadDispatcher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 359c553056b1489e9f2efecd9c470a18 3 | timeCreated: 1709908774 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/MainThreadDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Threading; 4 | using DevsDaddy.Shared.EventFramework.Core.Objects; 5 | using UnityEngine; 6 | 7 | namespace DevsDaddy.Shared.EventFramework.Core.Threading 8 | { 9 | public class MainThreadDispatcher : MonoSingleton 10 | , IThreadDispatcher 11 | { 12 | private readonly ConcurrentQueue _tasks = new ConcurrentQueue(); 13 | 14 | public int ThreadId 15 | { 16 | get; 17 | private set; 18 | } 19 | 20 | public int TasksCount => _tasks.Count; 21 | 22 | private void Awake() 23 | { 24 | ThreadId = Thread.CurrentThread.ManagedThreadId; 25 | } 26 | 27 | public void Dispatch(Delegate action, object[] payload) 28 | { 29 | _tasks.Enqueue(new DispatcherTask(action, payload)); 30 | } 31 | 32 | private void Update() 33 | { 34 | while(_tasks.Count > 0) 35 | { 36 | if (!_tasks.TryDequeue(out var task)) 37 | { 38 | continue; 39 | } 40 | Debug.Log($"(Queue.Count: {_tasks.Count}) Dispatching task {task.Action}"); 41 | 42 | task.Invoke(); 43 | task.Dispose(); 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/MainThreadDispatcher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a3729f2a81f14f098e44bbb17557d7b3 3 | timeCreated: 1709908959 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/WeakRefDelegate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace DevsDaddy.Shared.EventFramework.Core.Threading 5 | { 6 | public class WeakRefDelegate : WeakRefWrapper, IEquatable, IComparable 7 | { 8 | private int Id { get; } 9 | private MethodInfo Method { get; set; } 10 | 11 | public override int GetHashCode() 12 | { 13 | return Id; 14 | } 15 | 16 | public WeakRefDelegate(Delegate method) : base(method.Target) 17 | { 18 | Method = method.Method; 19 | Id = method.GetHashCode(); 20 | } 21 | 22 | public object Invoke(object[] args) 23 | { 24 | if (IsDisposed || !IsAlive) 25 | { 26 | return null; 27 | } 28 | 29 | var result = Method.Invoke(Target, args); 30 | return result; 31 | } 32 | 33 | public bool Contains(Delegate method) 34 | { 35 | if(method == null || !IsAlive) 36 | { 37 | return false; 38 | } 39 | 40 | var contains = Equals(Target, method.Target) && Equals(Method, method.Method); 41 | return contains; 42 | } 43 | 44 | protected override void Dispose(bool disposing) 45 | { 46 | base.Dispose(disposing); 47 | 48 | if (disposing) 49 | { 50 | Method = null; 51 | } 52 | } 53 | 54 | public bool Equals(Delegate other) 55 | { 56 | if(other == null) return false; 57 | var otherId = other.GetHashCode(); 58 | var equals = Id == otherId; 59 | return equals; 60 | } 61 | 62 | public int CompareTo(object obj) 63 | { 64 | if (!(obj is Delegate @delegate)) 65 | { 66 | return -1; 67 | } 68 | 69 | if (Equals(@delegate)) 70 | { 71 | return 0; 72 | } 73 | return -1; 74 | } 75 | 76 | public override string ToString() 77 | { 78 | return $"{GetType().Name}: {Id}, {Method}, {IsAlive}"; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/WeakRefDelegate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c419da5e8534fa2a812339defecd056 3 | timeCreated: 1709908829 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/WeakRefWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DevsDaddy.Shared.EventFramework.Core.Threading 4 | { 5 | public abstract class WeakRefWrapper : IDisposable 6 | { 7 | private WeakReference _ref; 8 | 9 | protected object Target 10 | { 11 | get 12 | { 13 | var target = IsAlive ? _ref.Target : null; 14 | return target; 15 | } 16 | } 17 | 18 | public bool IsAlive 19 | { 20 | get 21 | { 22 | var isAlive = _ref == null || (_ref.IsAlive && _ref.Target != null); 23 | return isAlive; 24 | } 25 | } 26 | 27 | protected WeakRefWrapper(object target) 28 | { 29 | _ref = new WeakReference(target, false); 30 | } 31 | 32 | protected bool IsDisposed; 33 | 34 | protected virtual void Dispose(bool disposing) 35 | { 36 | if (IsDisposed) return; 37 | if (disposing) 38 | { 39 | if(_ref != null) 40 | { 41 | _ref.Target = null; 42 | _ref = null; 43 | } 44 | } 45 | IsDisposed = true; 46 | } 47 | 48 | public void Dispose() 49 | { 50 | Dispose(true); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Core/Threading/WeakRefWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6316ba9f33ba40bd9657be195028246e 3 | timeCreated: 1709908838 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/EventFramework.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EventFramework" 3 | } 4 | -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/EventFramework.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9e94c900901bded428fa7bec1dab4d89 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/EventMessenger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using DevsDaddy.Shared.EventFramework.Core.Extensions; 5 | using DevsDaddy.Shared.EventFramework.Core.Messenger; 6 | using DevsDaddy.Shared.EventFramework.Core.Objects; 7 | using DevsDaddy.Shared.EventFramework.Core.Payloads; 8 | using DevsDaddy.Shared.EventFramework.Core.Threading; 9 | using UnityEngine; 10 | 11 | namespace DevsDaddy.Shared.EventFramework 12 | { 13 | /// 14 | /// Event Messenger 15 | /// 16 | public class EventMessenger : Singleton, IEventMessenger 17 | { 18 | // Subscribers Collection 19 | private readonly Dictionary> _subscribersSet = 20 | new Dictionary>(); 21 | 22 | // List of subscribers to optimize iteration during subscribers processing 23 | private readonly List _subscribers = new List(); 24 | private readonly Dictionary _payloadStates = new Dictionary(); 25 | 26 | // List of subscribers to optimize add (subscribe) operation 27 | private readonly List _add = new List(); 28 | private bool _isPublishing; 29 | 30 | /// 31 | /// Event Messenger Controller 32 | /// 33 | static EventMessenger() 34 | { 35 | Debug.Log($"Main Thread ID: {MainThreadDispatcher.Main.ThreadId}"); 36 | } 37 | 38 | /// 39 | /// Publish given payload to relevant subscribers 40 | /// 41 | /// Instance of payload to publish 42 | /// The type of payload to publish 43 | /// Instance of the Messenger 44 | public IEventMessengerPublish Publish(T payload) where T : IPayload 45 | { 46 | // if calling thread is same as main thread, call "PublishInternal" directly 47 | if(Thread.CurrentThread.ManagedThreadId == MainThreadDispatcher.Main.ThreadId) 48 | { 49 | PublishInternal(payload); 50 | return this; 51 | } 52 | 53 | // capture "PublishInternal" in local action var. 54 | Action act = PublishInternal; 55 | // add "act" into "MainThreadDispatcher" queue 56 | MainThreadDispatcher.Main.Dispatch(act, new object[] { payload }); 57 | return this; 58 | } 59 | 60 | /// 61 | /// Publish Payload 62 | /// 63 | /// 64 | /// Internal function that is used with "MainThreadDispatcher" 65 | /// 66 | /// The payload 67 | /// The type of the payload 68 | private void PublishInternal(T payload) where T : IPayload 69 | { 70 | try 71 | { 72 | // turn on the flag 73 | _isPublishing = true; 74 | 75 | var key = typeof(T); // capture the type of the payload in local var. 76 | 77 | if (!_payloadStates.ContainsKey(key)) 78 | _payloadStates.Add(key, payload); 79 | else 80 | _payloadStates[key] = payload; 81 | 82 | if (!_subscribersSet.ContainsKey(key)) 83 | { 84 | return; 85 | } 86 | 87 | // get subscriber's dic. for the payload type 88 | _subscribersSet.TryGetValue(key, out var callbacks); 89 | // check if "callbacks" dic. is null or empty 90 | if (callbacks.IsNullOrEmpty()) 91 | { 92 | // remove payload type key is "callbacks" dic is empty 93 | _subscribersSet.Remove(key); 94 | return; 95 | } 96 | 97 | // iterate thru dic and invoke callbacks 98 | foreach (var callback in callbacks.Values) 99 | { 100 | callback?.Invoke(payload); 101 | } 102 | } 103 | finally 104 | { 105 | // turn off the flag 106 | _isPublishing = false; 107 | // process pending tasks 108 | Process(); 109 | } 110 | } 111 | 112 | /// 113 | /// Subscribe the callback to specified payload type 114 | /// 115 | /// Callback delegate 116 | /// Callback's predicate 117 | /// The type of the payload 118 | /// Messenger instance 119 | public IEventMessengerSubscribe Subscribe(Action callback, Predicate predicate = null) where T : IPayload 120 | { 121 | // check if current thread ID == main thread ID 122 | if(Thread.CurrentThread.ManagedThreadId == MainThreadDispatcher.Main.ThreadId) 123 | { 124 | // execute subscribe method on main thread 125 | SubscribeInternal(callback, predicate); 126 | return this; 127 | } 128 | 129 | // capture delegate reference 130 | Action, Predicate> act = SubscribeInternal; 131 | // add delegate and payload into main thread dispatcher queue 132 | MainThreadDispatcher.Main.Dispatch(act, new object[] { callback, predicate }); 133 | return this; 134 | } 135 | 136 | /// 137 | /// Subscribe the callback to specified payload type 138 | /// 139 | /// 140 | /// Used internally by messenger to sync threads 141 | /// 142 | /// Callback delegate 143 | /// Predicate delegate (optional) 144 | /// The type of the payload 145 | private void SubscribeInternal(Action callback, Predicate predicate = null) 146 | { 147 | // capture the type of the payload 148 | var key = typeof(T); 149 | // init new subscriber instance 150 | var sub = new EventSubscriber(key, callback, predicate); 151 | 152 | // check if messenger is busy with publishing payloads 153 | if(_isPublishing) 154 | { 155 | // add subscriber into "Add" queue if messenger is busy with publishing 156 | _add.Add(sub); 157 | return; 158 | } 159 | // if messenger is not busy with publishing, add into subscribers list 160 | SubscribeInternal(sub); 161 | } 162 | 163 | /// 164 | /// Adds subscriber into subscribers list 165 | /// 166 | /// 167 | private void SubscribeInternal(EventSubscriber subscriber) 168 | { 169 | // check is subscriber is valid 170 | if (subscriber?.IsAlive != true) { 171 | Debug.LogError($"The {nameof(subscriber)} is null or not alive."); 172 | return; 173 | } 174 | 175 | // capture payload type into local var 'key' 176 | var key = subscriber.PayloadType; 177 | // capture subscribers dic into local var 'dic' 178 | Dictionary callbacks; 179 | if (_subscribersSet.ContainsKey(key)) 180 | { 181 | // fetch list of callbacks for this payload type 182 | _subscribersSet.TryGetValue(key, out callbacks); 183 | } 184 | else 185 | { 186 | // init list of callbacks/subscribers 187 | callbacks = new Dictionary(); 188 | _subscribersSet.Add(key, callbacks); 189 | } 190 | 191 | if (callbacks == null) 192 | { 193 | Debug.LogError("Callbacks container is null!"); 194 | return; 195 | } 196 | 197 | // check if subscriber is already registered 198 | if(callbacks.ContainsKey(subscriber.Id)) 199 | { 200 | return; 201 | } 202 | // register new subscriber 203 | callbacks.Add(subscriber.Id, subscriber); 204 | 205 | // add new list of callbacks/subscribers into flat list for fast access 206 | if (!_subscribers.Contains(subscriber)) 207 | { 208 | _subscribers.Add(subscriber); 209 | } 210 | } 211 | 212 | /// 213 | /// Unsubscribe given callback by payload type 214 | /// 215 | /// The callback to unsubscribe 216 | /// The type of the payload 217 | /// Instance of 218 | public IEventMessengerUnsubscribe Unsubscribe(Action callback) where T : IPayload 219 | { 220 | // check if method called on main thread 221 | if(Thread.CurrentThread.ManagedThreadId == MainThreadDispatcher.Main.ThreadId) 222 | { 223 | // call internal method 224 | UnsubscribeInternal(callback); 225 | return this; 226 | } 227 | 228 | // capture delegate in 'act' var 229 | Action> act = UnsubscribeInternal; 230 | // add 'act' delegate into main thread dispatcher queue 231 | MainThreadDispatcher.Main.Dispatch(act, new object[] { callback }); 232 | return this; 233 | } 234 | 235 | /// 236 | /// Unsubscribe given callback by payload type 237 | /// 238 | /// Internal method 239 | /// The callback delegate 240 | /// The type of the payload 241 | private void UnsubscribeInternal(Action callback) 242 | { 243 | // capture payload type into 'key' var 244 | var key = typeof(T); 245 | // capture subscribers dic into 'dic' var 246 | var dic = _subscribersSet; 247 | // check if payload is registered 248 | if (!dic.ContainsKey(key)) 249 | { 250 | return; 251 | } 252 | 253 | // get list of callbacks for the payload 254 | dic.TryGetValue(key, out var callbacks); 255 | // check if callbacks list is null or empty and if messenger is publishing payloads 256 | if(!_isPublishing && callbacks.IsNullOrEmpty()) 257 | { 258 | // remove payload from subscribers dic 259 | dic.Remove(key); 260 | return; 261 | } 262 | 263 | // get callback ID 264 | var id = callback.GetHashCode(); 265 | // check if callback is registered 266 | if(callbacks.ContainsKey(id)) 267 | { 268 | // get subscriber instance and dispose it 269 | var subscriber = callbacks[id]; 270 | subscriber.Dispose(); 271 | 272 | // check if messenger is busy with publishing 273 | if(!_isPublishing) 274 | { 275 | // remove the subscriber from the callbacks dic 276 | callbacks.Remove(id); 277 | // remove the subscriber from the subscribers dic 278 | if (_subscribers.Contains(subscriber)) 279 | { 280 | _subscribers.Remove(subscriber); 281 | } 282 | } 283 | } 284 | 285 | // check is messenger is busy with publishing or if callbacks are NOT empty 286 | if(_isPublishing || !callbacks.IsNullOrEmpty()) 287 | { 288 | return; 289 | } 290 | // remove callbacks from the _subscribersSet 291 | dic.Remove(key); 292 | } 293 | 294 | /// 295 | /// Get Current Payload State 296 | /// 297 | /// 298 | /// 299 | public T GetState() where T : class, IPayload { 300 | var key = typeof(T); 301 | if (!_payloadStates.ContainsKey(key)) { 302 | return null; 303 | } 304 | 305 | return (T)_payloadStates[key]; 306 | } 307 | 308 | /// 309 | /// Process collections. 310 | /// Cleanup "dead" subscribers and add from waiting list. 311 | /// 312 | private void Process() 313 | { 314 | // cleanup "dead" subscribers 315 | for(var i = 0; i < _subscribers.Count; i++) 316 | { 317 | var subscriber = _subscribers[i]; 318 | if(subscriber == null) 319 | { 320 | _subscribers.RemoveAt(i); 321 | i--; 322 | continue; 323 | } 324 | if(subscriber.IsAlive) 325 | { 326 | continue; 327 | } 328 | 329 | _subscribers.Remove(subscriber); 330 | i--; 331 | 332 | if(!_subscribersSet.ContainsKey(subscriber.PayloadType)) 333 | { 334 | continue; 335 | } 336 | 337 | var callbacks = _subscribersSet[subscriber.PayloadType]; 338 | callbacks.Remove(subscriber.Id); 339 | 340 | if(callbacks.Count > 0) 341 | { 342 | continue; 343 | } 344 | _subscribersSet.Remove(subscriber.PayloadType); 345 | } 346 | 347 | // add waiting subscribers 348 | foreach (var subscriber in _add) 349 | { 350 | SubscribeInternal(subscriber); 351 | } 352 | _add.Clear(); 353 | } 354 | } 355 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/EventMessenger.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2e366d8630ca41ceba75040078f2783f 3 | timeCreated: 1709842285 -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevsDaddy/UnityEventFramework/f373066ec11ee4f51a42d99c0e0999fc6b563109/DevsDaddy/Shared/EventFramework/Preview.png -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/Preview.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad25d73d75d3adc45869b4c8515d736e 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | flipGreenChannel: 0 24 | isReadable: 0 25 | streamingMipmaps: 0 26 | streamingMipmapsPriority: 0 27 | vTOnly: 0 28 | ignoreMipmapLimit: 0 29 | grayScaleToAlpha: 0 30 | generateCubemap: 6 31 | cubemapConvolution: 0 32 | seamlessCubemap: 0 33 | textureFormat: 1 34 | maxTextureSize: 2048 35 | textureSettings: 36 | serializedVersion: 2 37 | filterMode: 1 38 | aniso: 1 39 | mipBias: 0 40 | wrapU: 1 41 | wrapV: 1 42 | wrapW: 0 43 | nPOTScale: 0 44 | lightmap: 0 45 | compressionQuality: 50 46 | spriteMode: 1 47 | spriteExtrude: 1 48 | spriteMeshType: 1 49 | alignment: 0 50 | spritePivot: {x: 0.5, y: 0.5} 51 | spritePixelsToUnits: 100 52 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 53 | spriteGenerateFallbackPhysicsShape: 1 54 | alphaUsage: 1 55 | alphaIsTransparency: 1 56 | spriteTessellationDetail: -1 57 | textureType: 8 58 | textureShape: 1 59 | singleChannelComponent: 0 60 | flipbookRows: 1 61 | flipbookColumns: 1 62 | maxTextureSizeSet: 0 63 | compressionQualitySet: 0 64 | textureFormatSet: 0 65 | ignorePngGamma: 0 66 | applyGammaDecoding: 0 67 | swizzle: 50462976 68 | cookieLightType: 0 69 | platformSettings: 70 | - serializedVersion: 3 71 | buildTarget: DefaultTexturePlatform 72 | maxTextureSize: 2048 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | ignorePlatformSupport: 0 81 | androidETC2FallbackOverride: 0 82 | forceMaximumCompressionQuality_BC6H_BC7: 0 83 | - serializedVersion: 3 84 | buildTarget: Standalone 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | ignorePlatformSupport: 0 94 | androidETC2FallbackOverride: 0 95 | forceMaximumCompressionQuality_BC6H_BC7: 0 96 | spriteSheet: 97 | serializedVersion: 2 98 | sprites: [] 99 | outline: [] 100 | physicsShape: [] 101 | bones: [] 102 | spriteID: 5e97eb03825dee720800000000000000 103 | internalID: 0 104 | vertices: [] 105 | indices: 106 | edges: [] 107 | weights: [] 108 | secondaryTextures: [] 109 | nameFileIdTable: {} 110 | mipmapLimitGroupName: 111 | pSDRemoveMatte: 0 112 | userData: 113 | assetBundleName: 114 | assetBundleVariant: 115 | -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.devsdaddy.eventframework", 3 | "displayName": "Unity Event Framework", 4 | "version": "0.9.0", 5 | "unity": "2019.3", 6 | "description": "Unity Event Framework is a simple and elegant way to handle events between your objects in Unity. The framework uses the PubSub pattern with current Payload states for easy access to previously sent events.", 7 | "documentationUrl": "https://github.com/DevsDaddy/UnityEventFramework", 8 | "changelogUrl": "https://github.com/DevsDaddy/UnityEventFramework/releases", 9 | "licensesUrl": "https://github.com/DevsDaddy/UnityEventFramework/blob/main/LICENSE", 10 | "keywords": [ 11 | "events", 12 | "framework", 13 | "pubsub", 14 | "pattern", 15 | "reactive", 16 | "unity" 17 | ], 18 | "author": { 19 | "name": "DevsDaddy", 20 | "email": "blackfixltd@gmail.com", 21 | "url": "https://devsdaddy.hashnode.dev/" 22 | }, 23 | "category": "Unity" 24 | } -------------------------------------------------------------------------------- /DevsDaddy/Shared/EventFramework/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: de5fc124989440d795f2df5805be9a81 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Elijah Brown 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 | # Unity Events Framework 2 | Unity Event Framework
3 | **Unity Event Framework** is a simple and elegant way to handle events between your objects in Unity. 4 | The framework uses the PubSub pattern with current Payload states for easy access to previously sent events. 5 | 6 | Inspired by the work of SuperMaxim 7 | 8 | ## Why is that necessary? 9 | There are several advantages to this approach, ranging from reducing cohesion in your project by not directly referencing objects to resolving asynchronous events within the project. You can also retrieve the state of an event at any time if it has been previously sent. 10 | 11 | ## Get Started 12 | **Installation process:** 13 | - Install a package using Unity Package Manager (https://github.com/DevsDaddy/UnityEventFramework.git?path=/DevsDaddy/Shared/EventFramework/); 14 | - See usage examples below; 15 | 16 | **Unity Package Manager URL:** 17 | ``` 18 | https://github.com/DevsDaddy/UnityEventFramework.git?path=/DevsDaddy/Shared/EventFramework/ 19 | ``` 20 | 21 | ## Usage 22 | **Create Payload (Event Model) for your Events:** 23 | ```csharp 24 | public class TestPayload : IPayload 25 | { 26 | public string Message = ""; 27 | } 28 | ``` 29 | 30 | **To Subscribe for Payload (event) you can add listener via EventMessenger Class:** 31 | ```csharp 32 | EventMessenger.Main.Subscribe(payload => { 33 | Debug.Log(payload.Message); 34 | }); 35 | ``` 36 | 37 | **To Publish New Payload (Event) you can:*** 38 | ```csharp 39 | EventMessenger.Main.Publish(new TestPayload { 40 | Message = "Hello world!" 41 | }); 42 | ``` 43 | 44 | **Also you can get latest state for any early published payload (or null if not published yet):*** 45 | ```csharp 46 | TestPayload currentPayload = EventMessenger.Main.GetState(); 47 | Debug.Log(currentPayload.Message); 48 | ``` 49 | 50 | ## Examples 51 | See framework usage examples in other projects: 52 | * Game Shield - Unity Game Security and Anti-Cheat Toolkit; 53 | * Simple UI Framework for management of your UI; 54 | * OneUI Kit - Full-featured UI Kit for your applications and Games. Ready for MVC/MVP/MVVM; 55 | 56 | ## Coming Soon (TO-DO) 57 | **I plan to add the following functionality in the near future:** 58 | - Reactive Fields with Auto-Resolving via EventMessenger Class; 59 | 60 | ## Join Community 61 | - Discord Community 62 | 63 | ## Support Me 64 | **You can support the development and updating of libraries and assemblies by dropping a coin:** 65 | 66 | 67 | 68 | 69 |
Bitcoin (BTC)bc1qef2d34r4xkrm48zknjdjt7c0ea92ay9m2a7q55
Etherium (ETH)0x1112a2Ef850711DF4dE9c432376F255f416ef5d0
Boostyhttps://boosty.to/devsdaddy
70 | --------------------------------------------------------------------------------