├── .gitignore
├── Assets
├── Plugins.meta
├── Plugins
│ └── Editor.meta
├── UnityEvents.meta
└── UnityEvents
│ ├── Examples.meta
│ ├── Examples
│ ├── Advance.meta
│ ├── Advance
│ │ ├── ExampleCustomEventSystem.cs
│ │ ├── ExampleCustomEventSystem.cs.meta
│ │ ├── ExampleCustomTickEventSystem.cs
│ │ ├── ExampleCustomTickEventSystem.cs.meta
│ │ ├── ExampleEntityTargetReservations.cs
│ │ ├── ExampleEntityTargetReservations.cs.meta
│ │ ├── ExampleHandlers.cs
│ │ └── ExampleHandlers.cs.meta
│ ├── Simple.meta
│ ├── Simple
│ │ ├── ExampleSimple.cs
│ │ ├── ExampleSimple.cs.meta
│ │ ├── ExampleSimpleJob.cs
│ │ └── ExampleSimpleJob.cs.meta
│ ├── UnityEvents.Example.asmdef
│ └── UnityEvents.Example.asmdef.meta
│ ├── Scripts.meta
│ ├── Scripts
│ ├── EventHandlerJob.cs
│ ├── EventHandlerJob.cs.meta
│ ├── EventHandlerStandard.cs
│ ├── EventHandlerStandard.cs.meta
│ ├── EventManager.cs
│ ├── EventManager.cs.meta
│ ├── EventTarget.cs
│ ├── EventTarget.cs.meta
│ ├── GameObjectEventSystem.cs
│ ├── GameObjectEventSystem.cs.meta
│ ├── GlobalEventSystem.cs
│ ├── GlobalEventSystem.cs.meta
│ ├── Internal.meta
│ ├── Internal
│ │ ├── UnityEventsExceptions.cs
│ │ ├── UnityEventsExceptions.cs.meta
│ │ ├── UnityEventsInterfaces.cs
│ │ ├── UnityEventsInterfaces.cs.meta
│ │ ├── UnityEventsMisc.cs
│ │ └── UnityEventsMisc.cs.meta
│ ├── TickEventSystem.cs
│ ├── TickEventSystem.cs.meta
│ ├── UnityEventSystem.cs
│ ├── UnityEventSystem.cs.meta
│ ├── UnityEvents.asmdef
│ └── UnityEvents.asmdef.meta
│ ├── Tests.meta
│ └── Tests
│ ├── TestEventManager.cs
│ ├── TestEventManager.cs.meta
│ ├── TestEventTarget.cs
│ ├── TestEventTarget.cs.meta
│ ├── TestGameObjectEventSystemJob.cs
│ ├── TestGameObjectEventSystemJob.cs.meta
│ ├── TestGameObjectEventSystemStandard.cs
│ ├── TestGameObjectEventSystemStandard.cs.meta
│ ├── TestGameObjectUIEventSystemJob.cs
│ ├── TestGameObjectUIEventSystemJob.cs.meta
│ ├── TestGameObjectUIEventSystemStandard.cs
│ ├── TestGameObjectUIEventSystemStandard.cs.meta
│ ├── TestGlobalEventSystemJob.cs
│ ├── TestGlobalEventSystemJob.cs.meta
│ ├── TestGlobalEventSystemStandard.cs
│ ├── TestGlobalEventSystemStandard.cs.meta
│ ├── TestGlobalUIEventSystemJob.cs
│ ├── TestGlobalUIEventSystemJob.cs.meta
│ ├── TestGlobalUIEventSystemStandard.cs
│ ├── TestGlobalUIEventSystemStandard.cs.meta
│ ├── TestUnityEventJobSystem.cs
│ ├── TestUnityEventJobSystem.cs.meta
│ ├── TestUnityEventStandardSystem.cs
│ ├── TestUnityEventStandardSystem.cs.meta
│ ├── TestUnityEventsMisc.cs
│ ├── TestUnityEventsMisc.cs.meta
│ ├── UnityEvents.Test.asmdef
│ └── UnityEvents.Test.asmdef.meta
├── LICENSE
├── Packages
└── manifest.json
├── ProjectSettings
├── AudioManager.asset
├── ClusterInputManager.asset
├── DynamicsManager.asset
├── EditorBuildSettings.asset
├── EditorSettings.asset
├── GraphicsSettings.asset
├── InputManager.asset
├── NavMeshAreas.asset
├── NetworkManager.asset
├── Physics2DSettings.asset
├── PresetManager.asset
├── ProjectSettings.asset
├── ProjectVersion.txt
├── QualitySettings.asset
├── TagManager.asset
├── TimeManager.asset
├── UnityConnectSettings.asset
└── VFXManager.asset
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # =============== #
2 | # Unity generated #
3 | # =============== #
4 | [Tt]emp/
5 | [Oo]bj/
6 | [Bb]uild/
7 | [Ll]ibrary/
8 | sysinfo.txt
9 | .app
10 |
11 | # ===================================== #
12 | # Visual Studio / MonoDevelop generated #
13 | # ===================================== #
14 | [Ee]xported[Oo]bj/
15 | *.userprefs
16 | *.csproj
17 | *.csproj.meta
18 | *.pidb
19 | *.suo
20 | *.sln*
21 | *.user
22 | *.unityproj
23 | *.booproj
24 | .vscode/
25 | VSCode*
26 | VSCode/
27 | .vs/
28 |
29 | # ============ #
30 | # OS generated #
31 | # ============ #
32 | .DS_Store*
33 | ._*
34 | .Spotlight-V100
35 | .Trashes
36 | *Icon?
37 | *Icon?.meta
38 | ehthumbs.db
39 | [Tt]humbs.db
40 |
41 | # ========== #
42 | # Plugins #
43 | # ========== #
44 | UnityVS/
45 | *UnityVS.meta
46 | BIU/
47 | BIU.meta
48 | AutoSaver/
49 | AutoSaver.meta
50 | GeneratedOdinEditors.dll*
51 | Assets/External/Sirenix/Assemblies/Editor/
52 | Assets/External/Sirenix/Assemblies/Editor.meta
53 |
54 | # ======= #
55 | # FMOD #
56 | # ======= #
57 | /Assets/FMODStudioCache.asset
58 | /Assets/FMODStudioCache.asset.meta
59 | fmod.log
60 | fmod_editor.log
61 | !Assets/FMOD/StreamingAssets/fmod_audio/Build
62 |
63 | # ======= #
64 | # Other #
65 | # ======= #
66 | out/
67 | logs/
68 | build-process/
69 | sdks/steamworks_sdk_142/tools/ContentBuilder/content/
70 | sdks/build_loader/
71 |
72 | .*
73 | !/.gitignore
74 | !/Assets/PlayFabEditorExtensions/Editor/Resources/.CloudScript.js
75 | Assets/Plugins/Editor/JetBrains/
76 | Assets/Plugins/Editor/JetBrains.meta
77 |
--------------------------------------------------------------------------------
/Assets/Plugins.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ec540725aa24fff43b68bf5d4c17b0d1
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/Plugins/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 82fd2ede500ba7c49be58b4680b82750
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/UnityEvents.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d982b2eb55bf6a344b31e48da429d742
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d7b7b88763a933443aa8dfb2b3c031bf
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3f451b97248702849bb0dd9f13c11730
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance/ExampleCustomEventSystem.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UnityEvents.Example
4 | {
5 | ///
6 | /// Example of using an event system that isn't controlled by any of the update ticks. Events will only be processed
7 | /// when told to be processed.
8 | ///
9 | /// IF YOU ARE OK WITH EVENTS BEING PROCESSED IN FIXED UPDATE, UPDATE, OR LATE UPDATE then use TickEventSystem
10 | /// (example in ExampleCustomTickEventSystem.cs) as it will allow better subscription/event batching and will be more
11 | /// performant. ONLY IF you literally want to control when a system has it's events processed is when you would use
12 | /// the example in this file.
13 | ///
14 | public class ExampleCustomEventSystem
15 | {
16 | // This system will allow subscribers and events to be queued. Events have to be told when to process isntead
17 | // of happening automatically in a tick. The example will only show regular events but this can handle both.
18 | // See ExampleSimpleJob.cs for a job example.
19 | private UnityEventSystem _system = new UnityEventSystem();
20 |
21 | // I have to be an unmanaged type! Need references? Use an id and have a lookup database system.
22 | private struct EvExampleEvent
23 | {
24 | public int exampleValue;
25 |
26 | public EvExampleEvent(int exampleValue)
27 | {
28 | this.exampleValue = exampleValue;
29 | }
30 | }
31 |
32 | public void UseCustomSystem()
33 | {
34 | // Event systems are associated with an EventTarget, this is how an event system can know who to send
35 | // an event to but keep all events together for performance.
36 | //
37 | // For example the global sim event system is its own EventTarget. As is the Global UI system and each
38 | // GameObject is converted to an EventTarget.
39 | //
40 | // It is better to use a single UnityEventSystem with multiple entities than an UnityEventSystem for each
41 | // target. For example if there are multiple 'global' systems that all get processed at the same time then
42 | // it is more performant to have a single UnityEventSystem and an EventTarget for each 'global system' that
43 | // talk to the same UnityEventSystem.
44 | //
45 | // GlobalEventSystem, GameObject systems, and TickEventSystem all use EventManager which uses one UnityEventSystem
46 | // for each update tick.
47 | EventTarget target1 = EventTarget.CreateTarget();
48 | EventTarget target2 = EventTarget.CreateTarget();
49 |
50 | // Can subscribe a listener to both entities
51 | _system.Subscribe(target1, OnExampleEvent);
52 | _system.Subscribe(target2, OnExampleEventDoublePrint);
53 |
54 | // We queue up events, avoided the 'send' verb here since we have to manually process the events.
55 | _system.QueueEvent(target1, new EvExampleEvent(1));
56 |
57 | // Now we process the queued events. Since we only sent an event to the entity1 system, the listener to entity2
58 | // will NOT invoke.
59 | _system.ProcessEvents();
60 |
61 | // Each listener needs to unsubscribe from the appropriate event entity
62 | _system.Unsubscribe(target1, OnExampleEvent);
63 | _system.Unsubscribe(target2, OnExampleEventDoublePrint);
64 |
65 | // To have a global system that you control just store an EventEntity and use that.
66 | }
67 |
68 | private void OnExampleEvent(EvExampleEvent ev)
69 | {
70 | Debug.Log("Event received! Value: " + ev.exampleValue);
71 | }
72 |
73 | private void OnExampleEventDoublePrint(EvExampleEvent ev)
74 | {
75 | Debug.Log("Event received! Value: " + ev.exampleValue);
76 | Debug.Log("Event received! Value: " + ev.exampleValue);
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance/ExampleCustomEventSystem.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1cfdaae08c2e5c845b40fdcc6fa1ed3a
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance/ExampleCustomTickEventSystem.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UnityEvents.Example
4 | {
5 | ///
6 | /// Example of using a custom event system that send events on an update tick. This could be used to create custom
7 | /// local event system and custom global event system. GlobalEventSystem is a static class that holds a tick
8 | /// based event system for simulation and ui and passes subscriptions/events through it.
9 | ///
10 | public class ExampleCustomTickEventSystem
11 | {
12 | // This system will process events in the Update tick. The example will only show regular events but this can
13 | // handle both. See ExampleSimpleJob.cs for a job example.
14 | private TickEventSystem _system = new TickEventSystem(EventUpdateTick.Update);
15 |
16 | // I have to be an unmanaged type! Need references? Use an id and have a lookup database system.
17 | private struct EvExampleEvent
18 | {
19 | public int exampleValue;
20 |
21 | public EvExampleEvent(int exampleValue)
22 | {
23 | this.exampleValue = exampleValue;
24 | }
25 | }
26 |
27 | public void UseCustomSystem()
28 | {
29 | // Subscribe to the custom event system
30 | _system.Subscribe(OnExampleEvent);
31 |
32 | // Can send an event to it. This will be processed in the Update loop.
33 | _system.SendEvent(new EvExampleEvent(10));
34 |
35 | // And unsubscribe from it
36 | _system.Unsubscribe(OnExampleEvent);
37 | }
38 |
39 | private void OnExampleEvent(EvExampleEvent ev)
40 | {
41 | Debug.Log("Event received! Value: " + ev.exampleValue);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance/ExampleCustomTickEventSystem.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ee112101c292c8242800ff1209fd6d08
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance/ExampleEntityTargetReservations.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | namespace UnityEvents.Example
6 | {
7 | public class ExampleEntityTargetReservations
8 | {
9 | public void ReserveEntityTargets()
10 | {
11 | // See ExampleCustomEventSystem for a description of what EventTarget are and how they could be
12 | // used. Also see EventTarget.cs
13 |
14 | // Reservations allow us to reserve a block of event targets for us to use however way we see fit. Will
15 | // prevent EventTarget from giving out targets within that reservation on EventTarget creation or other'
16 | // reservations.
17 | EventTargetReservation reservation = EventTarget.ReserveTargets(100);
18 |
19 | // Grabs an EventTarget by index
20 | EventTarget target0 = reservation.GetEntityTarget(0);
21 | EventTarget target50 = reservation.GetEntityTarget(50);
22 |
23 | // Throws an error if outside the reservation (if checks are enabled)
24 | EventTarget target200 = reservation.GetEntityTarget(200);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance/ExampleEntityTargetReservations.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: eff85f34ce9a5fd4088b1e17e2e041b9
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance/ExampleHandlers.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEvents.Internal;
3 |
4 | namespace UnityEvents.Example
5 | {
6 | ///
7 | /// Example of using event handlers directly. Similar to UnityEventSystem but only works for a specific event.
8 | /// Can be used to only allow a single event.
9 | ///
10 | public class ExampleHandlers
11 | {
12 | private EventHandlerStandard _standardHandler = new EventHandlerStandard();
13 | private EventHandlerJob _jobHandler = new EventHandlerJob();
14 |
15 | // I have to be an unmanaged type! Need references? Use an id and have a lookup database system.
16 | private struct EvExampleEvent
17 | {
18 | public int exampleValue;
19 |
20 | public EvExampleEvent(int exampleValue)
21 | {
22 | this.exampleValue = exampleValue;
23 | }
24 | }
25 |
26 | private struct ExampleJob : IJobForEvent
27 | {
28 | // This result is stored across jobs, wipe it out at the beginning of each job if this isn't wanted!
29 | public int result;
30 |
31 | public void ExecuteEvent(EvExampleEvent ev)
32 | {
33 | result += ev.exampleValue;
34 | }
35 | }
36 |
37 | public void StandardHandlerExample()
38 | {
39 | // Handlers ultimately are what store the subscriptions and process events. Ideally they shouldn't need
40 | // to be used directly and TickEventSystem and UnityEventSystem would be sufficient in most cases.
41 |
42 | // See ExampleControlledEventSystem.cs for a description on EventEntities.
43 | EventTarget target = EventTarget.CreateTarget();
44 |
45 | // Subscribe, Unsubscribe, and Events will seem familiar but can ONLY use EvExampleEvent. Doesn't work for
46 | // all events.
47 | _standardHandler.Subscribe(target, OnExampleEvent);
48 |
49 | // Handlers have to be told to process events so we queue an event and process it later.
50 | _standardHandler.QueueEvent(target, new EvExampleEvent(7777));
51 | _standardHandler.ProcessEvents();
52 |
53 | _standardHandler.Unsubscribe(target, OnExampleEvent);
54 |
55 | // There's a job handler as well, they are separate and won't fire on the same events
56 | _jobHandler.Subscribe(target, new ExampleJob(), OnJobFinished);
57 | _jobHandler.QueueEvent(target, new EvExampleEvent(111));
58 | _jobHandler.ProcessEvents();
59 | _jobHandler.Unsubscribe(target, OnJobFinished);
60 |
61 | }
62 |
63 | private void OnExampleEvent(EvExampleEvent ev)
64 | {
65 | Debug.Log("Event received! Value: " + ev.exampleValue);
66 | }
67 |
68 | private void OnJobFinished(ExampleJob ev)
69 | {
70 | Debug.Log("Job finished! Value: " + ev.result);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Advance/ExampleHandlers.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d1c5fd7ff58a51947b92284c95ba58cc
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Simple.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5810ca7e6d141a049bb4d349ccc3b759
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Simple/ExampleSimple.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEvents.Internal;
3 |
4 | namespace UnityEvents.Example
5 | {
6 | ///
7 | /// Simple example of using the global and GameObject event systems
8 | ///
9 | public class ExampleSimple : MonoBehaviour
10 | {
11 | // I have to be an unmanaged type! Need references? Use an id and have a lookup database system.
12 | private struct EvExampleEvent
13 | {
14 | public int exampleValue;
15 |
16 | public EvExampleEvent(int exampleValue)
17 | {
18 | this.exampleValue = exampleValue;
19 | }
20 | }
21 |
22 | private void OnEnable()
23 | {
24 | // Subscribes to the global event system, handles events in FixedUpdate
25 | GlobalEventSystem.Subscribe(OnExampleEvent);
26 |
27 | // Subscribes to THIS GameObject's event system! Also Fixed Update
28 | gameObject.Subscribe(OnExampleEvent);
29 |
30 | // Is the game paused but still need events for UI? There's a global UI system. Handles events in
31 | // LateUpdate
32 | GlobalEventSystem.SubscribeUI(OnExampleEvent);
33 |
34 | // There's also local event system for each GameObject that run in LateUpdate.
35 | gameObject.SubscribeUI(OnExampleEvent);
36 | }
37 |
38 | private void OnDisable()
39 | {
40 | // Should always unsubscribe
41 |
42 | // Unsubscribe from the global system
43 | GlobalEventSystem.Unsubscribe(OnExampleEvent);
44 | gameObject.Unsubscribe(OnExampleEvent);
45 |
46 | GlobalEventSystem.UnsubscribeUI(OnExampleEvent);
47 | gameObject.UnsubscribeUI(OnExampleEvent);
48 | }
49 |
50 | public void SendEvents()
51 | {
52 | // Send an event to the global event system, will be processed in the next FixedUpdate
53 | GlobalEventSystem.SendEvent(new EvExampleEvent(10));
54 |
55 | // Send an event to a specific GameObject, only listeners subscribed to that gameobject will get
56 | // this event. Also will be processed in the next FixedUpdate
57 | gameObject.SendEvent(new EvExampleEvent(99));
58 |
59 | // Can send events to the global UI event system. These will be processed in LateUpdate which allows the
60 | // game to paused.
61 | GlobalEventSystem.SendEventUI(new EvExampleEvent(-1));
62 |
63 | // Similarly can send to a specific GameObject to be processed in LateUpdate
64 | gameObject.SendEventUI(new EvExampleEvent(999999));
65 | }
66 |
67 | private void OnExampleEvent(EvExampleEvent ev)
68 | {
69 | Debug.Log("Event received! Value: " + ev.exampleValue);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Simple/ExampleSimple.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 02f30ee5572dba9409e6c62a404fb9df
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Simple/ExampleSimpleJob.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEvents.Internal;
3 |
4 | namespace UnityEvents.Example
5 | {
6 | ///
7 | /// Simple example of using jobs with the event system
8 | ///
9 | public class ExampleSimpleJob : MonoBehaviour
10 | {
11 | // I have to be an unmanaged type! Need references? Use an id and have a lookup database system.
12 | private struct EvExampleEvent
13 | {
14 | public int exampleValue;
15 |
16 | public EvExampleEvent(int exampleValue)
17 | {
18 | this.exampleValue = exampleValue;
19 | }
20 | }
21 |
22 | private struct ExampleJob : IJobForEvent
23 | {
24 | // This result is stored across jobs, wipe it out at the beginning of each job if this isn't wanted!
25 | public int result;
26 |
27 | public void ExecuteEvent(EvExampleEvent ev)
28 | {
29 | result += ev.exampleValue;
30 | }
31 | }
32 |
33 | private void OnEnable()
34 | {
35 | // Jobs work with the global simulation and global UI event systems as well as the GameObject system. This
36 | // will just show examples with the global simulation system.
37 | //
38 | // When an event is fired jobs will processed in parallel using the burst compiler. Can make otherwise
39 | // long tasks very short. Afterwards the callback functions are invoked so the listener can use the results
40 | // of the job.
41 | GlobalEventSystem.SubscribeWithJob(new ExampleJob(), OnJobFinished);
42 | }
43 |
44 | private void OnDisable()
45 | {
46 | GlobalEventSystem.UnsubscribeWithJob(OnJobFinished);
47 | }
48 |
49 | public void SendEvents()
50 | {
51 | // Job listeners trigger on events like anything else. You can have job listeners and regular listeners to
52 | // a single event.
53 | GlobalEventSystem.SendEvent(new EvExampleEvent(10));
54 | }
55 |
56 | private void OnJobFinished(ExampleJob ev)
57 | {
58 | Debug.Log("Job finished! Value: " + ev.result);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/Simple/ExampleSimpleJob.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 49b20d95465d66c49a3748a972bf6d31
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/UnityEvents.Example.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "UnityEvents.Example",
3 | "references": [
4 | "UnityEvents"
5 | ],
6 | "optionalUnityReferences": [],
7 | "includePlatforms": [
8 | "Editor"
9 | ],
10 | "excludePlatforms": [],
11 | "allowUnsafeCode": false,
12 | "overrideReferences": false,
13 | "precompiledReferences": [],
14 | "autoReferenced": true,
15 | "defineConstraints": []
16 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Examples/UnityEvents.Example.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 197aa132777a36a4bbe5bcf49d007183
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 264256832277bb04fbe0e953b6fe70d6
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/EventHandlerJob.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Unity.Burst;
4 | using Unity.Collections;
5 | using Unity.Collections.LowLevel.Unsafe;
6 | using Unity.Jobs;
7 | using UnityEngine;
8 | using UnityEvents.Internal;
9 |
10 | namespace UnityEvents
11 | {
12 | ///
13 | /// Event system that processes jobs for events.
14 | ///
15 | /// The job the system is responsible for.
16 | /// The event the system is responsible for.
17 | public class EventHandlerJob :
18 | IJobEventSystem,
19 | IDisposable
20 | where T_Job : struct, IJobForEvent
21 | where T_Event : struct
22 | {
23 | private NativeList> _queuedEvents;
24 | private NativeList _subscribers;
25 |
26 | private List> _subscriberCallbacks;
27 | private Dictionary, int> _entityCallbackToIndex;
28 |
29 | private Dictionary, int> _cachedCurEvents;
30 |
31 | private bool _disposed;
32 | private readonly int _batchCount;
33 |
34 | private const int DEFAULT_EVENTS_TO_PROCESS_CAPACITY = 10;
35 | private const int DEFAULT_SUBSCRIBER_CAPACITY = 100;
36 | private const int DEFAULT_PARALLEL_BATCH_COUNT = 32;
37 |
38 | private struct UnityEventJob
39 | {
40 | public readonly T_Event ev;
41 | public readonly int subscriberIndex;
42 |
43 | public UnityEventJob(T_Event ev, int subscriberIndex)
44 | {
45 | this.ev = ev;
46 | this.subscriberIndex = subscriberIndex;
47 | }
48 | }
49 |
50 | private struct Subscription
51 | {
52 | public EventTarget target;
53 | public T_Job job;
54 |
55 | public Subscription(EventTarget target, T_Job job)
56 | {
57 | this.target = target;
58 | this.job = job;
59 | }
60 | }
61 |
62 | public EventHandlerJob() : this(
63 | DEFAULT_SUBSCRIBER_CAPACITY,
64 | DEFAULT_EVENTS_TO_PROCESS_CAPACITY,
65 | DEFAULT_PARALLEL_BATCH_COUNT)
66 | {
67 | }
68 |
69 | ///
70 | /// Create a system with some custom settings.
71 | ///
72 | /// The starting capacity of subscriber containers.
73 | /// The starting capacity of queued events containers.
74 | /// The batch count allowed per thread for parallel processing.
75 | public EventHandlerJob(
76 | int subscriberStartingCapacity,
77 | int queuedEventsStartingCapacity,
78 | int parallelBatchCount)
79 | {
80 | #if !DISABLE_EVENT_SAFETY_CHKS
81 | if (!UnsafeUtility.IsBlittable())
82 | {
83 | throw new JobTypeNotBlittableException(typeof(T_Job));
84 | }
85 |
86 | if (!UnsafeUtility.IsBlittable())
87 | {
88 | throw new EventTypeNotBlittableException(typeof(T_Event));
89 | }
90 | #endif
91 | _batchCount = parallelBatchCount;
92 |
93 | _subscribers = new NativeList(subscriberStartingCapacity, Allocator.Persistent);
94 | _subscriberCallbacks = new List>(subscriberStartingCapacity);
95 | _entityCallbackToIndex = new Dictionary, int>(subscriberStartingCapacity);
96 |
97 | _queuedEvents = new NativeList>(queuedEventsStartingCapacity, Allocator.Persistent);
98 |
99 | #if !DISABLE_EVENT_SAFETY_CHKS
100 | _cachedCurEvents = new Dictionary, int>(subscriberStartingCapacity);
101 | #endif
102 | }
103 |
104 | ///
105 | /// Disposes of some internally held state.
106 | ///
107 | public void Dispose()
108 | {
109 | #if !DISABLE_EVENT_SAFETY_CHKS
110 | if (_disposed)
111 | {
112 | _disposed = true;
113 | return;
114 | }
115 | #endif
116 | _queuedEvents.Dispose();
117 | _subscribers.Dispose();
118 | }
119 |
120 | ///
121 | /// Subscribe a job to the system.
122 | ///
123 | /// The entity to subscribe to.
124 | /// The job, and initial job state, to process when an event fires.
125 | /// The callback to invoke when a job finishes.
126 | public void Subscribe(EventTarget target, T_Job job, Action onComplete)
127 | {
128 | #if !DISABLE_EVENT_SAFETY_CHKS
129 | if (_entityCallbackToIndex.ContainsKey(new EntityCallbackId(target, onComplete)))
130 | {
131 | throw new MultipleSubscriptionsException(onComplete);
132 | }
133 | #endif
134 |
135 | _entityCallbackToIndex.Add(new EntityCallbackId(target, onComplete), _subscribers.Length);
136 | _subscribers.Add(new Subscription(target, job));
137 | _subscriberCallbacks.Add(onComplete);
138 | }
139 |
140 | ///
141 | /// Unsubscribe a job from the system.
142 | ///
143 | /// The entity to unsubscribe from.
144 | /// The callback that was invoked when a job finished.
145 | public void Unsubscribe(EventTarget target, Action onComplete)
146 | {
147 | EntityCallbackId callbackId = new EntityCallbackId(target, onComplete);
148 |
149 | if (_entityCallbackToIndex.TryGetValue(callbackId, out int index))
150 | {
151 | _entityCallbackToIndex.Remove(callbackId);
152 |
153 | _subscribers.RemoveAtSwapBack(index);
154 |
155 | _subscriberCallbacks[index] = _subscriberCallbacks[_subscriberCallbacks.Count - 1];
156 | _subscriberCallbacks.RemoveAt(_subscriberCallbacks.Count - 1);
157 |
158 | if (index != _subscribers.Length)
159 | {
160 | EntityCallbackId otherCallbackId = new EntityCallbackId(
161 | _subscribers[index].target,
162 | _subscriberCallbacks[index]);
163 |
164 | _entityCallbackToIndex[otherCallbackId] = index;
165 | }
166 | }
167 | }
168 |
169 | ///
170 | /// Queue an event to be processed later.
171 | ///
172 | /// The entity the event is for.
173 | /// The event to queue.
174 | public void QueueEvent(EventTarget target, T_Event ev)
175 | {
176 | QueuedEvent newEv = new QueuedEvent(target, ev);
177 |
178 | #if !DISABLE_EVENT_SAFETY_CHKS
179 | if (_cachedCurEvents.TryGetValue(newEv, out int index))
180 | {
181 | // If avoiding this warning is too annoying then make this the default behaviour and have this be a message sent
182 | // when in verbose mode or something
183 | Debug.LogWarning(
184 | $"To prevent parallel corruption, event {ev.GetType().Name} cannot be sent to the same entity multiple times between processing. This event will replace the previous one!");
185 |
186 | _queuedEvents[index] = newEv;
187 | }
188 | else
189 | {
190 | _cachedCurEvents[newEv] = _queuedEvents.Length;
191 | _queuedEvents.Add(newEv);
192 | }
193 | #else
194 | _queuedEvents.Add(newEv);
195 | #endif
196 | }
197 |
198 | ///
199 | /// Process all queued events.
200 | ///
201 | public void ProcessEvents()
202 | {
203 | // Early bail to avoid setting up job stuff unnecessarily
204 | if (_queuedEvents.Length == 0)
205 | {
206 | return;
207 | }
208 |
209 | NativeQueue eventsToProcessQueue = new NativeQueue(Allocator.TempJob);
210 |
211 | BuildEventQueueJob job = new BuildEventQueueJob();
212 | job.queuedEvents = _queuedEvents;
213 | job.subscribers = _subscribers;
214 | job.eventsToProcess = eventsToProcessQueue.ToConcurrent();
215 |
216 | job.Schedule(_queuedEvents.Length, 32).Complete();
217 |
218 | int eventCount = eventsToProcessQueue.Count;
219 |
220 | NativeArray eventsToProcess = new NativeArray(eventCount, Allocator.TempJob);
221 |
222 | EventQueueToEventArrayJob setJob = new EventQueueToEventArrayJob();
223 | setJob.eventsInQueue = eventsToProcessQueue;
224 | setJob.events = eventsToProcess;
225 |
226 | JobHandle setArrayHandle = setJob.Schedule();
227 |
228 | NativeArray jobsArray = new NativeArray(eventCount, Allocator.TempJob);
229 |
230 | CreateJobsArrayJob createJobArrayJob = new CreateJobsArrayJob();
231 | createJobArrayJob.events = eventsToProcess;
232 | createJobArrayJob.subscribers = _subscribers;
233 | createJobArrayJob.jobs = jobsArray;
234 |
235 | JobHandle createJobArrayHandle = createJobArrayJob.Schedule(
236 | eventCount,
237 | _batchCount,
238 | setArrayHandle);
239 |
240 | ExecuteEventJobsJob executeJob = new ExecuteEventJobsJob();
241 | executeJob.jobsResult = jobsArray;
242 | executeJob.evs = eventsToProcess;
243 |
244 | JobHandle executeHandle = executeJob.Schedule(
245 | eventCount,
246 | _batchCount,
247 | createJobArrayHandle);
248 |
249 | WriteBackToSubscribersJob writeBackJob = new WriteBackToSubscribersJob();
250 | writeBackJob.subscribers = _subscribers;
251 | writeBackJob.evs = eventsToProcess;
252 | writeBackJob.jobsResult = jobsArray;
253 |
254 | JobHandle writeBackHandle = writeBackJob.Schedule(
255 | eventCount,
256 | _batchCount,
257 | executeHandle);
258 |
259 | writeBackHandle.Complete();
260 |
261 | int count = eventsToProcess.Length;
262 |
263 | for (int i = 0; i < count; i++)
264 | {
265 | UnityEventJob ev = eventsToProcess[i];
266 | Subscription sub = _subscribers[ev.subscriberIndex];
267 |
268 | try
269 | {
270 | _subscriberCallbacks[ev.subscriberIndex](sub.job);
271 | }
272 | catch (Exception e)
273 | {
274 | Debug.LogException(e);
275 | }
276 | }
277 |
278 | eventsToProcessQueue.Dispose();
279 | eventsToProcess.Dispose();
280 | jobsArray.Dispose();
281 |
282 | _queuedEvents.Clear();
283 |
284 | #if !DISABLE_EVENT_SAFETY_CHKS
285 | _cachedCurEvents.Clear();
286 | #endif
287 | }
288 |
289 | ///
290 | /// Reset the system. Removes all listeners and queued events.
291 | ///
292 | public void Reset()
293 | {
294 | _queuedEvents.Clear();
295 | _subscribers.Clear();
296 | _subscriberCallbacks.Clear();
297 | _entityCallbackToIndex.Clear();
298 |
299 | #if !DISABLE_EVENT_SAFETY_CHKS
300 | _cachedCurEvents.Clear();
301 | #endif
302 | }
303 |
304 | ///
305 | /// Debug log an error for each subscriber that is still listening.
306 | ///
307 | public void VerifyNoSubscribers()
308 | {
309 | if (_subscribers.Length > 0)
310 | {
311 | // Just throw the first one, it'll get resolved
312 | throw new SubscriberStillListeningException(_subscriberCallbacks);
313 | }
314 | }
315 |
316 | [BurstCompile]
317 | private struct BuildEventQueueJob : IJobParallelFor
318 | {
319 | [ReadOnly]
320 | public NativeList> queuedEvents;
321 |
322 | [ReadOnly]
323 | public NativeList subscribers;
324 |
325 | public NativeQueue.Concurrent eventsToProcess;
326 |
327 | public void Execute(int index)
328 | {
329 | int count = subscribers.Length;
330 | QueuedEvent ev = queuedEvents[index];
331 |
332 | for (int i = 0; i < count; i++)
333 | {
334 | if (subscribers[i].target.Equals(ev.target))
335 | {
336 | eventsToProcess.Enqueue(new UnityEventJob(ev.ev, i));
337 | }
338 | }
339 | }
340 | }
341 |
342 | [BurstCompile]
343 | private struct EventQueueToEventArrayJob : IJob
344 | {
345 | public NativeQueue eventsInQueue;
346 |
347 | [WriteOnly]
348 | public NativeArray events;
349 |
350 | public void Execute()
351 | {
352 | int count = eventsInQueue.Count;
353 |
354 | for (int i = 0; i < count; i++)
355 | {
356 | events[i] = eventsInQueue.Dequeue();
357 | }
358 | }
359 | }
360 |
361 | [BurstCompile]
362 | private struct CreateJobsArrayJob : IJobParallelFor
363 | {
364 | [ReadOnly]
365 | public NativeArray events;
366 |
367 | [ReadOnly]
368 | public NativeList subscribers;
369 |
370 | [WriteOnly]
371 | public NativeArray jobs;
372 |
373 | public void Execute(int index)
374 | {
375 | jobs[index] = subscribers[events[index].subscriberIndex].job;
376 | }
377 | }
378 |
379 | [BurstCompile]
380 | private struct ExecuteEventJobsJob : IJobParallelFor
381 | {
382 | [ReadOnly]
383 | public NativeArray evs;
384 |
385 | public NativeArray jobsResult;
386 |
387 | public void Execute(int index)
388 | {
389 | T_Job job = jobsResult[index];
390 | job.ExecuteEvent(evs[index].ev);
391 | jobsResult[index] = job;
392 | }
393 | }
394 |
395 | [BurstCompile]
396 | private struct WriteBackToSubscribersJob : IJobParallelFor
397 | {
398 | [WriteOnly]
399 | [NativeDisableContainerSafetyRestriction]
400 | public NativeList subscribers;
401 |
402 | [ReadOnly]
403 | public NativeArray evs;
404 |
405 | [ReadOnly]
406 | public NativeArray jobsResult;
407 |
408 | public void Execute(int index)
409 | {
410 | Subscription sub = subscribers[evs[index].subscriberIndex];
411 | sub.job = jobsResult[index];
412 | subscribers[evs[index].subscriberIndex] = sub;
413 | }
414 | }
415 | }
416 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/EventHandlerJob.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9d83953d5e9722343991a56abfc56e02
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/EventHandlerStandard.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Unity.Burst;
4 | using Unity.Collections;
5 | using Unity.Collections.LowLevel.Unsafe;
6 | using Unity.Jobs;
7 | using UnityEngine;
8 | using UnityEvents.Internal;
9 |
10 | namespace UnityEvents
11 | {
12 | ///
13 | /// Event system that processes regular events.
14 | ///
15 | /// The event the system is responsible for.
16 | public class EventHandlerStandard : IEventSystem, IDisposable where T_Event : struct
17 | {
18 | private NativeList> _queuedEvents;
19 | private NativeList _subscribers;
20 |
21 | private List> _subscriberCallbacks;
22 | private Dictionary, int> _entityCallbackToIndex;
23 |
24 | private bool _disposed;
25 |
26 | private readonly int _batchCount;
27 |
28 | private const int DEFAULT_EVENTS_TO_PROCESS_CAPACITY = 10;
29 | private const int DEFAULT_SUBSCRIBER_CAPACITY = 100;
30 | private const int DEFAULT_PARALLEL_BATCH_COUNT = 32;
31 |
32 | public EventHandlerStandard() : this(
33 | DEFAULT_SUBSCRIBER_CAPACITY,
34 | DEFAULT_EVENTS_TO_PROCESS_CAPACITY,
35 | DEFAULT_PARALLEL_BATCH_COUNT)
36 | {
37 | }
38 |
39 | ///
40 | /// Create a system with some custom settings.
41 | ///
42 | /// The starting capacity of subscriber containers.
43 | /// The starting capacity of queued events containers.
44 | /// The batch count allowed per thread for parallel processing.
45 | public EventHandlerStandard(
46 | int subscriberStartingCapacity,
47 | int queuedEventsStartingCapacity,
48 | int parallelBatchCount)
49 | {
50 | #if !DISABLE_EVENT_SAFETY_CHKS
51 | if (!UnsafeUtility.IsBlittable())
52 | {
53 | throw new EventTypeNotBlittableException(typeof(T_Event));
54 | }
55 | #endif
56 | _batchCount = parallelBatchCount;
57 |
58 | _subscribers = new NativeList(subscriberStartingCapacity, Allocator.Persistent);
59 | _subscriberCallbacks = new List>(subscriberStartingCapacity);
60 | _entityCallbackToIndex = new Dictionary, int>(subscriberStartingCapacity);
61 |
62 | _queuedEvents = new NativeList>(queuedEventsStartingCapacity, Allocator.Persistent);
63 | }
64 |
65 | ///
66 | /// Disposes of some internally held state.
67 | ///
68 | public void Dispose()
69 | {
70 | #if !DISABLE_EVENT_SAFETY_CHKS
71 | if (_disposed)
72 | {
73 | _disposed = true;
74 | return;
75 | }
76 | #endif
77 | _queuedEvents.Dispose();
78 | _subscribers.Dispose();
79 | }
80 |
81 | ///
82 | /// Subscribe a listener to the system.
83 | ///
84 | /// The target to subscribe to.
85 | /// The callback that is invoked when an event fires.
86 | public void Subscribe(EventTarget target, Action callback)
87 | {
88 | #if !DISABLE_EVENT_SAFETY_CHKS
89 | if (_entityCallbackToIndex.ContainsKey(new EntityCallbackId(target, callback)))
90 | {
91 | throw new MultipleSubscriptionsException(callback);
92 | }
93 | #endif
94 |
95 | _entityCallbackToIndex.Add(new EntityCallbackId(target, callback), _subscribers.Length);
96 | _subscribers.Add(target);
97 | _subscriberCallbacks.Add(callback);
98 | }
99 |
100 | ///
101 | /// Unsubscribe a listener from the system.
102 | ///
103 | /// The target to unsubscribe from.
104 | /// The callback that was invoked during events.
105 | public void Unsubscribe(EventTarget target, Action callback)
106 | {
107 | EntityCallbackId callbackId = new EntityCallbackId(target, callback);
108 |
109 | if (_entityCallbackToIndex.TryGetValue(callbackId, out int index))
110 | {
111 | _entityCallbackToIndex.Remove(callbackId);
112 |
113 | _subscribers.RemoveAtSwapBack(index);
114 |
115 | _subscriberCallbacks[index] = _subscriberCallbacks[_subscriberCallbacks.Count - 1];
116 | _subscriberCallbacks.RemoveAt(_subscriberCallbacks.Count - 1);
117 |
118 | if (index != _subscribers.Length)
119 | {
120 | EntityCallbackId otherCallbackId = new EntityCallbackId(
121 | _subscribers[index],
122 | _subscriberCallbacks[index]);
123 |
124 | _entityCallbackToIndex[otherCallbackId] = index;
125 | }
126 | }
127 | }
128 |
129 | ///
130 | /// Queue an event to be processed later.
131 | ///
132 | /// The target the event is for.
133 | /// The event to queue.
134 | public void QueueEvent(EventTarget target, T_Event ev)
135 | {
136 | _queuedEvents.Add(new QueuedEvent(target, ev));
137 | }
138 |
139 | ///
140 | /// Process all queued events.
141 | ///
142 | public void ProcessEvents()
143 | {
144 | // Early bail to avoid setting up job stuff unnecessarily
145 | if (_queuedEvents.Length == 0)
146 | {
147 | return;
148 | }
149 |
150 | NativeQueue> eventsToProcessQueue =
151 | new NativeQueue>(Allocator.TempJob);
152 |
153 | BuildEventQueueJob job = new BuildEventQueueJob();
154 | job.queuedEvents = _queuedEvents;
155 | job.subscribers = _subscribers;
156 | job.eventsToProcess = eventsToProcessQueue.ToConcurrent();
157 |
158 | job.Schedule(_queuedEvents.Length, _batchCount).Complete();
159 |
160 | while (eventsToProcessQueue.TryDequeue(out UnityEvent ev))
161 | {
162 | try
163 | {
164 | _subscriberCallbacks[ev.subscriberIndex](ev.ev);
165 | }
166 | catch (Exception e)
167 | {
168 | Debug.LogException(e);
169 | }
170 | }
171 |
172 | eventsToProcessQueue.Dispose();
173 | _queuedEvents.Clear();
174 | }
175 |
176 | ///
177 | /// Reset the system. Removes all listeners and queued events.
178 | ///
179 | public void Reset()
180 | {
181 | _queuedEvents.Clear();
182 | _subscribers.Clear();
183 | _subscriberCallbacks.Clear();
184 | _entityCallbackToIndex.Clear();
185 | }
186 |
187 | ///
188 | /// Debug log an error for each subscriber that is still listening.
189 | ///
190 | public void VerifyNoSubscribers()
191 | {
192 | if (_subscribers.Length > 0)
193 | {
194 | // Just throw the first one, it'll get resolved
195 | throw new SubscriberStillListeningException(_subscriberCallbacks);
196 | }
197 | }
198 |
199 | [BurstCompile]
200 | private struct BuildEventQueueJob : IJobParallelFor
201 | {
202 | [ReadOnly]
203 | public NativeList> queuedEvents;
204 |
205 | [ReadOnly]
206 | public NativeList subscribers;
207 |
208 | public NativeQueue>.Concurrent eventsToProcess;
209 |
210 | public void Execute(int index)
211 | {
212 | int count = subscribers.Length;
213 | QueuedEvent ev = queuedEvents[index];
214 |
215 | for (int i = 0; i < count; i++)
216 | {
217 | if (subscribers[i].Equals(ev.target))
218 | {
219 | eventsToProcess.Enqueue(new UnityEvent(ev.ev, i));
220 | }
221 | }
222 | }
223 | }
224 | }
225 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/EventHandlerStandard.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fe7b7073d17471f42961d9758b17a1ca
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/EventManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using UnityEvents.Internal;
4 |
5 | namespace UnityEvents
6 | {
7 | ///
8 | /// EventManager manages systems with the various Unity lifetime ticks. Allows systems that run in FixedUpdate,
9 | /// Update, and LateUpdate.
10 | ///
11 | public class EventManager : MonoBehaviour
12 | {
13 | private static UnityEventSystem _fixedUpdateSystem = new UnityEventSystem();
14 | private static UnityEventSystem _updateSystem = new UnityEventSystem();
15 | private static UnityEventSystem _lateUpdateSystem = new UnityEventSystem();
16 |
17 | ///
18 | /// Subscribe a listener to an event in the specific update tick.
19 | ///
20 | /// The target to subscribe to.
21 | /// The event callback
22 | /// The update type to subscribe to.
23 | /// The event
24 | public static void Subscribe(EventTarget target, Action eventCallback, EventUpdateTick tick)
25 | where T_Event : struct
26 | {
27 | if (tick == EventUpdateTick.FixedUpdate)
28 | {
29 | _fixedUpdateSystem.Subscribe(target, eventCallback);
30 | }
31 | else if (tick == EventUpdateTick.Update)
32 | {
33 | _updateSystem.Subscribe(target, eventCallback);
34 | }
35 | else // Late Update
36 | {
37 | _lateUpdateSystem.Subscribe(target, eventCallback);
38 | }
39 | }
40 |
41 | ///
42 | /// Subscribe a job that processes during an event in the specific update tick.
43 | ///
44 | /// The target to subscribe to.
45 | /// The job, and starting data, to run when the event fires.
46 | /// The callback that is invoked when the job has finished.
47 | /// The update type to subscribe to.
48 | /// The event type.
49 | /// The job type.
50 | public static void SubscribeWithJob(
51 | EventTarget target,
52 | T_Job job,
53 | Action onComplete,
54 | EventUpdateTick tick)
55 | where T_Job : struct, IJobForEvent
56 | where T_Event : struct
57 | {
58 | if (tick == EventUpdateTick.FixedUpdate)
59 | {
60 | _fixedUpdateSystem.SubscribeWithJob(target, job, onComplete);
61 | }
62 | else if (tick == EventUpdateTick.Update)
63 | {
64 | _updateSystem.SubscribeWithJob(target, job, onComplete);
65 | }
66 | else // Late Update
67 | {
68 | _lateUpdateSystem.SubscribeWithJob(target, job, onComplete);
69 | }
70 | }
71 |
72 | ///
73 | /// Unsubscribe a listener from an event in the specific update tick.
74 | ///
75 | /// The target to unsubscribe from.
76 | /// The event callback
77 | /// The update type to unsubscribe to.
78 | /// The event
79 | public static void Unsubscribe(EventTarget target, Action eventCallback, EventUpdateTick tick)
80 | where T_Event : struct
81 | {
82 | if (tick == EventUpdateTick.FixedUpdate)
83 | {
84 | _fixedUpdateSystem.Unsubscribe(target, eventCallback);
85 | }
86 | else if (tick == EventUpdateTick.Update)
87 | {
88 | _updateSystem.Unsubscribe(target, eventCallback);
89 | }
90 | else // Late Update
91 | {
92 | _lateUpdateSystem.Unsubscribe(target, eventCallback);
93 | }
94 | }
95 |
96 | ///
97 | /// Unsubscribe a job that processed during from an event in the specific update tick.
98 | ///
99 | /// The target to unsubscribe from.
100 | /// The callback that is invoked when the job has finished.
101 | /// The update type to unsubscribe to.
102 | /// The job type.
103 | /// The event type.
104 | public static void UnsubscribeWithJob(EventTarget target, Action onComplete,
105 | EventUpdateTick tick)
106 | where T_Job : struct, IJobForEvent
107 | where T_Event : struct
108 | {
109 | if (tick == EventUpdateTick.FixedUpdate)
110 | {
111 | _fixedUpdateSystem.UnsubscribeWithJob(target, onComplete);
112 | }
113 | else if (tick == EventUpdateTick.Update)
114 | {
115 | _updateSystem.UnsubscribeWithJob(target, onComplete);
116 | }
117 | else // Late Update
118 | {
119 | _lateUpdateSystem.UnsubscribeWithJob(target, onComplete);
120 | }
121 | }
122 |
123 | ///
124 | /// Send an event to be processed in a specific update tick.
125 | ///
126 | /// The target to send the event to.
127 | /// The event to send
128 | /// The update tick to send to.
129 | /// The event type.
130 | public static void SendEvent(EventTarget target, T_Event ev, EventUpdateTick tick)
131 | where T_Event : struct
132 | {
133 | if (tick == EventUpdateTick.FixedUpdate)
134 | {
135 | _fixedUpdateSystem.QueueEvent(target, ev);
136 | }
137 | else if (tick == EventUpdateTick.Update)
138 | {
139 | _updateSystem.QueueEvent(target, ev);
140 | }
141 | else // Late Update
142 | {
143 | _lateUpdateSystem.QueueEvent(target, ev);
144 | }
145 | }
146 |
147 | ///
148 | /// Flushes all currently queued events NOW
149 | ///
150 | public static void FlushAll()
151 | {
152 | _fixedUpdateSystem.ProcessEvents();
153 | _updateSystem.ProcessEvents();
154 | _lateUpdateSystem.ProcessEvents();
155 | }
156 |
157 | ///
158 | /// Reset all the event systems with all update types.
159 | ///
160 | public static void ResetAll()
161 | {
162 | _fixedUpdateSystem.Reset();
163 | _updateSystem.Reset();
164 | _lateUpdateSystem.Reset();
165 | }
166 |
167 | ///
168 | /// Debug function to verify there are no lingering listeners. Throws an exception if there's a listener.
169 | ///
170 | public static void VerifyNoSubscribersAll()
171 | {
172 | _fixedUpdateSystem.VerifyNoSubscribers();
173 | _updateSystem.VerifyNoSubscribers();
174 | _lateUpdateSystem.VerifyNoSubscribers();
175 | }
176 |
177 | ///
178 | /// Debug function to verify there are no lingering listeners. Logs each offending system instead of throwing an
179 | /// exception.
180 | ///
181 | public static void VerifyNoSubscribersAllLog()
182 | {
183 | _fixedUpdateSystem.VerifyNoSubscribersLog();
184 | _updateSystem.VerifyNoSubscribersLog();
185 | _lateUpdateSystem.VerifyNoSubscribersLog();
186 | }
187 |
188 | private void FixedUpdate()
189 | {
190 | _fixedUpdateSystem.ProcessEvents();
191 | }
192 |
193 | private void Update()
194 | {
195 | _updateSystem.ProcessEvents();
196 | }
197 |
198 | private void LateUpdate()
199 | {
200 | _lateUpdateSystem.ProcessEvents();
201 | }
202 |
203 | private void OnDestroy()
204 | {
205 | ResetAll();
206 |
207 | _fixedUpdateSystem.Dispose();
208 | _updateSystem.Dispose();
209 | _lateUpdateSystem.Dispose();
210 | }
211 |
212 | [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
213 | private static void Initialize()
214 | {
215 | GameObject em = new GameObject("[EVENT MANAGER DO]", typeof(EventManager));
216 | DontDestroyOnLoad(em);
217 | }
218 | }
219 |
220 | public enum EventUpdateTick
221 | {
222 | FixedUpdate,
223 | Update,
224 | LateUpdate
225 | }
226 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/EventManager.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 090143b0b25343443ac673308f3acce2
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/EventTarget.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEvents.Internal;
3 | using Object = UnityEngine.Object;
4 |
5 | namespace UnityEvents
6 | {
7 | ///
8 | /// Used to represent the target of events. This is something that be subscribed to, unsubscribed from, and have
9 | /// events sent to. For example, the global event system uses an event target to maintain this. The GameObject event
10 | /// system has an event target for each GameObject.
11 | ///
12 | public struct EventTarget: IEquatable
13 | {
14 | public readonly ulong id;
15 |
16 | public static readonly EventTarget NULL_TARGET = new EventTarget(NULL_ID);
17 |
18 | // We reserve the first uint.MaxValue values for GameObjects
19 | private static ulong _ids = (ulong)uint.MaxValue + 1;
20 | private const ulong NULL_ID = ulong.MaxValue;
21 |
22 | ///
23 | /// Creates a target with a specific ID. This CAN clash with a previously created target of an id.
24 | /// Creating new target of the same id intentionally is fine and will work interchangeably.
25 | ///
26 | /// Id to bind the target to.
27 | public EventTarget(ulong id)
28 | {
29 | this.id = id;
30 | }
31 |
32 | ///
33 | /// Creates a target with a specific ID. This CAN clash with a previously created target of an id.
34 | /// Creating new target of the same id intentionally is fine and will work interchangeably.
35 | ///
36 | /// Id to bind the target to.
37 | public EventTarget(int id) : this(unchecked((uint)id))
38 | {
39 |
40 | }
41 |
42 | ///
43 | /// Creates a new unique event target.
44 | ///
45 | /// The new target.
46 | public static EventTarget CreateTarget()
47 | {
48 | return new EventTarget(_ids++);
49 | }
50 |
51 | ///
52 | /// Creates an event target associated with the supplied Unity Object.
53 | ///
54 | /// The object to associate the target with.
55 | /// The new target.
56 | public static EventTarget CreateTarget(Object obj)
57 | {
58 | if (obj == null)
59 | {
60 | return NULL_TARGET;
61 | }
62 |
63 | return new EventTarget(obj.GetInstanceID());
64 | }
65 |
66 | ///
67 | /// Reserves a reservation of targets to be leveraged by the caller. For custom management for some number of targets.
68 | ///
69 | /// The number of targets to reserve.
70 | /// The starting id of the reservation, this should be
71 | public static EventTargetReservation ReserveTargets(ulong count)
72 | {
73 | ulong start = _ids;
74 | #if !DISABLE_EVENT_SAFETY_CHKS
75 | checked
76 | {
77 | _ids += count;
78 | }
79 | #else
80 | _ids += count;
81 | #endif
82 |
83 | return new EventTargetReservation(start, count);
84 | }
85 |
86 | public bool Equals(EventTarget other)
87 | {
88 | return id == other.id;
89 | }
90 |
91 | public override bool Equals(object obj)
92 | {
93 | if (ReferenceEquals(null, obj)) return false;
94 | return obj is EventTarget other && Equals(other);
95 | }
96 |
97 | public override int GetHashCode()
98 | {
99 | return id.GetHashCode();
100 | }
101 | }
102 |
103 | ///
104 | /// Is a reservation of a block of event targets.
105 | ///
106 | public struct EventTargetReservation : IEquatable
107 | {
108 | private readonly ulong _reservationStart;
109 | private readonly ulong _reservationCount;
110 |
111 | // Generated by JetBrains
112 | private const int HASHCODE_MULTIPLIER = 397;
113 |
114 | public EventTargetReservation(ulong reservationStart, ulong reservationCount)
115 | {
116 | _reservationStart = reservationStart;
117 | _reservationCount = reservationCount;
118 | }
119 |
120 | ///
121 | /// Get an event target from the reservation.
122 | ///
123 | /// The index of the event target.
124 | /// The event Target.
125 | /// Throws if an invalid index.
126 | public EventTarget GetEntityTarget(int index)
127 | {
128 | #if !DISABLE_EVENT_SAFETY_CHKS
129 | if (index < 0 || (ulong)index >= _reservationCount)
130 | {
131 | throw new IndexOutOfReservedTargetsException();
132 | }
133 | #endif
134 |
135 | return new EventTarget(_reservationStart + (ulong)index);
136 | }
137 |
138 | ///
139 | /// Get an event target from the reservation.
140 | ///
141 | /// The index of the event target.
142 | /// The event Target.
143 | /// Throws if an invalid index.
144 | public EventTarget GetEntityTarget(ulong index)
145 | {
146 | #if !DISABLE_EVENT_SAFETY_CHKS
147 | if (index >= _reservationCount)
148 | {
149 | throw new IndexOutOfReservedTargetsException();
150 | }
151 | #endif
152 |
153 | return new EventTarget(_reservationStart + index);
154 | }
155 |
156 | public bool Equals(EventTargetReservation other)
157 | {
158 | return _reservationStart == other._reservationStart && _reservationCount == other._reservationCount;
159 | }
160 |
161 | public override bool Equals(object obj)
162 | {
163 | if (ReferenceEquals(null, obj)) return false;
164 | return obj is EventTargetReservation other && Equals(other);
165 | }
166 |
167 | public override int GetHashCode()
168 | {
169 | unchecked
170 | {
171 | return (_reservationStart.GetHashCode() * HASHCODE_MULTIPLIER) ^ _reservationCount.GetHashCode();
172 | }
173 | }
174 | }
175 | }
176 |
177 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/EventTarget.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6730ad9c87e27254e8fe54ffec402ad0
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/GameObjectEventSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using UnityEvents.Internal;
4 |
5 | namespace UnityEvents
6 | {
7 | public static class GameObjectEventSystem
8 | {
9 | public static void Subscribe(this GameObject gObj, Action callback) where T_Event : struct
10 | {
11 | EventManager.Subscribe(EventTarget.CreateTarget(gObj), callback, EventUpdateTick.FixedUpdate);
12 | }
13 |
14 | public static void SubscribeWithJob(this GameObject gObj, T_Job job, Action onComplete)
15 | where T_Job : struct, IJobForEvent
16 | where T_Event : struct
17 | {
18 | EventManager.SubscribeWithJob(
19 | EventTarget.CreateTarget(gObj),
20 | job,
21 | onComplete,
22 | EventUpdateTick.FixedUpdate);
23 | }
24 |
25 | public static void Unsubscribe(this GameObject gObj, Action callback)
26 | where T_Event : struct
27 | {
28 | EventManager.Unsubscribe(EventTarget.CreateTarget(gObj), callback, EventUpdateTick.FixedUpdate);
29 | }
30 |
31 | public static void UnsubscribeWithJob(this GameObject gObj, Action onComplete)
32 | where T_Job : struct, IJobForEvent
33 | where T_Event : struct
34 | {
35 | EventManager.UnsubscribeWithJob(
36 | EventTarget.CreateTarget(gObj),
37 | onComplete,
38 | EventUpdateTick.FixedUpdate);
39 | }
40 |
41 | public static void SendEvent(this GameObject gObj, T_Event ev) where T_Event : struct
42 | {
43 | EventManager.SendEvent(EventTarget.CreateTarget(gObj), ev, EventUpdateTick.FixedUpdate);
44 | }
45 |
46 | public static void SubscribeUI(this GameObject gObj, Action callback)
47 | where T_Event : struct
48 | {
49 | EventManager.Subscribe(EventTarget.CreateTarget(gObj), callback, EventUpdateTick.LateUpdate);
50 | }
51 |
52 | public static void SubscribeUIWithJob(this GameObject gObj, T_Job job, Action onComplete)
53 | where T_Job : struct, IJobForEvent
54 | where T_Event : struct
55 | {
56 | EventManager.SubscribeWithJob(
57 | EventTarget.CreateTarget(gObj),
58 | job,
59 | onComplete,
60 | EventUpdateTick.LateUpdate);
61 | }
62 |
63 | public static void UnsubscribeUI(this GameObject gObj, Action callback)
64 | where T_Event : struct
65 | {
66 | EventManager.Unsubscribe(
67 | EventTarget.CreateTarget(gObj),
68 | callback,
69 | EventUpdateTick.LateUpdate);
70 | }
71 |
72 | public static void UnsubscribeUIWithJob(this GameObject gObj, Action onComplete)
73 | where T_Job : struct, IJobForEvent
74 | where T_Event : struct
75 | {
76 | EventManager.UnsubscribeWithJob(
77 | EventTarget.CreateTarget(gObj),
78 | onComplete,
79 | EventUpdateTick.LateUpdate);
80 | }
81 |
82 | public static void SendEventUI(this GameObject gObj, T_Event ev) where T_Event : struct
83 | {
84 | EventManager.SendEvent(EventTarget.CreateTarget(gObj), ev, EventUpdateTick.LateUpdate);
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/GameObjectEventSystem.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ede1248eea3935f459f28473d6e164a4
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/GlobalEventSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEvents.Internal;
3 |
4 | namespace UnityEvents
5 | {
6 | ///
7 | /// A system that handles global events for Fixed Update. Intended for gameplay events.
8 | ///
9 | public static class GlobalEventSystem
10 | {
11 | private static TickEventSystem _simSystem = new TickEventSystem(EventUpdateTick.FixedUpdate);
12 | private static TickEventSystem _uiSystem = new TickEventSystem(EventUpdateTick.LateUpdate);
13 |
14 | ///
15 | /// Subscribe a listener to the global event system.
16 | ///
17 | /// The callback that's invoked when an event occurs.
18 | /// The event type.
19 | public static void Subscribe(Action callback) where T_Event : struct
20 | {
21 | _simSystem.Subscribe(callback);
22 | }
23 |
24 | ///
25 | /// Subscribe a job to the global event system.
26 | ///
27 | /// The job that is processed when an event occurs.
28 | /// The callback that's invoked when the job is done.
29 | /// The job type.
30 | /// The event type.
31 | public static void SubscribeWithJob(T_Job job, Action onComplete)
32 | where T_Job : struct, IJobForEvent
33 | where T_Event : struct
34 | {
35 | _simSystem.SubscribeWithJob(job, onComplete);
36 | }
37 |
38 | ///
39 | /// Unsubscribe a listener from the global event system.
40 | ///
41 | /// The callback to unsubscribe.
42 | /// The event type.
43 | public static void Unsubscribe(Action callback) where T_Event : struct
44 | {
45 | _simSystem.Unsubscribe(callback);
46 | }
47 |
48 | ///
49 | /// Unsubscribe a job from the global event system.
50 | ///
51 | /// The on complete callback to unsubscribe
52 | /// The job type to unsubscribe.
53 | /// The event type.
54 | public static void UnsubscribeWithJob(Action onComplete)
55 | where T_Job : struct, IJobForEvent
56 | where T_Event : struct
57 | {
58 | _simSystem.UnsubscribeWithJob(onComplete);
59 | }
60 |
61 | ///
62 | /// Send an event to the global event system.
63 | ///
64 | /// The event to send.
65 | /// The event type.
66 | public static void SendEvent(T_Event ev) where T_Event : struct
67 | {
68 | _simSystem.SendEvent(ev);
69 | }
70 |
71 | ///
72 | /// Subscribe a listener to the global UI event system.
73 | ///
74 | /// The callback that's invoked when an event occurs.
75 | /// The event type.
76 | public static void SubscribeUI(Action callback) where T_Event : struct
77 | {
78 | _uiSystem.Subscribe(callback);
79 | }
80 |
81 | ///
82 | /// Subscribe a job to the global UI event system.
83 | ///
84 | /// The job that is processed when an event occurs.
85 | /// The callback that's invoked when the job is done.
86 | /// The job type.
87 | /// The event type.
88 | public static void SubscribeUIWithJob(T_Job job, Action onComplete)
89 | where T_Job : struct, IJobForEvent
90 | where T_Event : struct
91 | {
92 | _uiSystem.SubscribeWithJob(job, onComplete);
93 | }
94 |
95 | ///
96 | /// Unsubscribe a listener from the global UI event system.
97 | ///
98 | /// The callback to unsubscribe.
99 | /// The event type.
100 | public static void UnsubscribeUI(Action callback) where T_Event : struct
101 | {
102 | _uiSystem.Unsubscribe(callback);
103 | }
104 |
105 | ///
106 | /// Unsubscribe a job from the global UI event system.
107 | ///
108 | /// The on complete callback to unsubscribe
109 | /// The job type to unsubscribe.
110 | /// The event type.
111 | public static void UnsubscribeUIWithJob(Action onComplete)
112 | where T_Job : struct, IJobForEvent
113 | where T_Event : struct
114 | {
115 | _uiSystem.UnsubscribeWithJob(onComplete);
116 | }
117 |
118 | ///
119 | /// Send an event to the global UI event system.
120 | ///
121 | /// The event to send.
122 | /// The event type.
123 | public static void SendEventUI(T_Event ev) where T_Event : struct
124 | {
125 | _uiSystem.SendEvent(ev);
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/GlobalEventSystem.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 07a6801a4bfbcf74998a7834297b4af2
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/Internal.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 51feeee6e92af4b4caf4c2d1d2435a33
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/Internal/UnityEventsExceptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace UnityEvents.Internal
5 | {
6 | public class MultipleSubscriptionsException : Exception
7 | {
8 | public MultipleSubscriptionsException(Action callback)
9 | : base($"Not allowed to subscribe the same callback to the same entity! Target: {callback.Target.GetType().Name} Event: {typeof(T).Name}")
10 | {
11 |
12 | }
13 | }
14 |
15 | public class SubscriberStillListeningException : Exception
16 | where T_Event : struct
17 | {
18 | public SubscriberStillListeningException(List> listeners)
19 | : base(GenerateMessage(listeners))
20 | {
21 | }
22 |
23 | private static string GenerateMessage(List> listeners)
24 | {
25 | string msg = $"The following subscribers are still listening to the {typeof(T_Event).Name} system!";
26 |
27 | foreach (Action listener in listeners)
28 | {
29 | if (listener == null)
30 | {
31 | msg += "\n";
32 | }
33 | else
34 | {
35 | msg += $"\n{listener.Method.Name}";
36 | }
37 | }
38 |
39 | return msg;
40 | }
41 | }
42 |
43 | public class IndexOutOfReservedTargetsException : Exception
44 | {
45 |
46 | }
47 |
48 | public class EventTypeNotBlittableException : Exception
49 | {
50 | public EventTypeNotBlittableException(Type type)
51 | : base($"Event type {type.Name} must be blittable!")
52 | {}
53 | }
54 |
55 | public class JobTypeNotBlittableException : Exception
56 | {
57 | public JobTypeNotBlittableException(Type type)
58 | : base($"Job type {type.Name} must be blittable!")
59 | {}
60 | }
61 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/Internal/UnityEventsExceptions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 382c09bd05d845940a497099bc7f460b
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/Internal/UnityEventsInterfaces.cs:
--------------------------------------------------------------------------------
1 | namespace UnityEvents.Internal
2 | {
3 | public interface IEventSystem
4 | {
5 | void Reset();
6 | void ProcessEvents();
7 | void VerifyNoSubscribers();
8 | }
9 |
10 | public interface IJobEventSystem : IEventSystem where T: struct
11 | {
12 | void QueueEvent(EventTarget target, T ev);
13 | }
14 |
15 | public interface IJobForEvent where T : struct
16 | {
17 | void ExecuteEvent(T ev);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/Internal/UnityEventsInterfaces.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e334ac3284c6305449960f9272914393
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/Internal/UnityEventsMisc.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UnityEvents.Internal
4 | {
5 | public struct QueuedEvent where T_Event : struct
6 | {
7 | public EventTarget target;
8 | public T_Event ev;
9 |
10 | public QueuedEvent(EventTarget target, T_Event ev)
11 | {
12 | this.target = target;
13 | this.ev = ev;
14 | }
15 | }
16 |
17 | public struct UnityEvent where T_Event : struct
18 | {
19 | public readonly T_Event ev;
20 | public readonly int subscriberIndex;
21 |
22 | public UnityEvent(T_Event ev, int subscriberIndex)
23 | {
24 | this.ev = ev;
25 | this.subscriberIndex = subscriberIndex;
26 | }
27 | }
28 |
29 | public struct EntityCallbackId : IEquatable>
30 | {
31 | public EventTarget target;
32 | public Action callback;
33 |
34 | // Generated by Jetbrains
35 | private const int HASHCODE_MULTIPLIER = 397;
36 |
37 | public EntityCallbackId(EventTarget target, Action callback)
38 | {
39 | this.target = target;
40 | this.callback = callback;
41 | }
42 |
43 | public bool Equals(EntityCallbackId other)
44 | {
45 | return target.Equals(other.target) && Equals(callback, other.callback);
46 | }
47 |
48 | public override bool Equals(object obj)
49 | {
50 | if (ReferenceEquals(null, obj)) return false;
51 | return obj is EntityCallbackId other && Equals(other);
52 | }
53 |
54 | public override int GetHashCode()
55 | {
56 | unchecked
57 | {
58 | return (target.GetHashCode() * HASHCODE_MULTIPLIER) ^ (callback != null ? callback.GetHashCode() : 0);
59 | }
60 | }
61 | }}
62 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/Internal/UnityEventsMisc.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b7a0c1e34b6672441bce3c23bee72cd8
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/TickEventSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEvents.Internal;
3 |
4 | namespace UnityEvents
5 | {
6 | ///
7 | /// Event System that runs in a given update tick (FixedUpdate, Update, or LateUpdate). Can be used to create
8 | /// custom event systems.
9 | ///
10 | public class TickEventSystem
11 | {
12 | private EventUpdateTick _tick;
13 | private EventTarget _target;
14 |
15 | ///
16 | /// Create an tick based event system.
17 | ///
18 | /// Which tick to run in.
19 | public TickEventSystem(EventUpdateTick updateTick)
20 | {
21 | _tick = updateTick;
22 | _target = EventTarget.CreateTarget();
23 | }
24 |
25 | ///
26 | /// Subscribe a listener to the tick based event system.
27 | ///
28 | /// The callback that's invoked when an event occurs.
29 | /// The event type.
30 | public void Subscribe(Action callback) where T_Event : struct
31 | {
32 | EventManager.Subscribe(_target, callback, _tick);
33 | }
34 |
35 | ///
36 | /// Subscribe a job to the tick based event system.
37 | ///
38 | /// The job that is processed when an event occurs.
39 | /// The callback that's invoked when the job is done.
40 | /// The job type.
41 | /// The event type.
42 | public void SubscribeWithJob(T_Job job, Action onComplete)
43 | where T_Job : struct, IJobForEvent
44 | where T_Event : struct
45 | {
46 | EventManager.SubscribeWithJob(_target, job, onComplete, _tick);
47 | }
48 |
49 | ///
50 | /// Unsubscribe a listener from the tick based event system.
51 | ///
52 | /// The callback to unsubscribe.
53 | /// The event type.
54 | public void Unsubscribe(Action callback) where T_Event : struct
55 | {
56 | EventManager.Unsubscribe(_target, callback, _tick);
57 | }
58 |
59 | ///
60 | /// Unsubscribe a job from the tick based event system.
61 | ///
62 | /// The on complete callback to unsubscribe
63 | /// The job type to unsubscribe.
64 | /// The event type.
65 | public void UnsubscribeWithJob(Action onComplete)
66 | where T_Job : struct, IJobForEvent
67 | where T_Event : struct
68 | {
69 | EventManager.UnsubscribeWithJob(_target, onComplete, _tick);
70 | }
71 |
72 | ///
73 | /// Send an event to the tick based event system.
74 | ///
75 | /// The event to send.
76 | /// The event type.
77 | public void SendEvent(T_Event ev) where T_Event : struct
78 | {
79 | EventManager.SendEvent(_target, ev, _tick);
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/TickEventSystem.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7f298f4b52c61874f9fb546cecd27a4d
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/UnityEventSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using UnityEvents.Internal;
5 |
6 | namespace UnityEvents
7 | {
8 | ///
9 | /// The event system that handles subscribers for all events, can queue all events, and will process the events
10 | /// when told to.
11 | ///
12 | public class UnityEventSystem : IDisposable
13 | {
14 | private List _systems = new List();
15 | private Dictionary _systemsCache = new Dictionary();
16 | private Dictionary _jobSystemsCache = new Dictionary();
17 |
18 | private Dictionary> _eventToJobSystems =
19 | new Dictionary>();
20 |
21 | // Cache, hit the same event multiple for better results
22 | private Type _cachedSystemEventType;
23 | private IEventSystem _cacheSystem;
24 |
25 | private Type _cachedJobSystemsType;
26 | private List _cachedJobSystems;
27 |
28 | private Type _cachedJobSystemType;
29 | private IEventSystem _cachedJobSystem;
30 |
31 | ///
32 | /// Subscribe a listener to an event.
33 | ///
34 | /// The target to subscribe to.
35 | /// The event callback
36 | /// The event
37 | public void Subscribe(EventTarget target, Action eventCallback) where T_Event : struct
38 | {
39 | EventHandlerStandard system = GetSystem();
40 | system.Subscribe(target, eventCallback);
41 | }
42 |
43 | ///
44 | /// Subscribe a job that processes during an event.
45 | ///
46 | /// The target to subscribe to.
47 | /// The job, and starting data, to run when the event fires.
48 | /// The callback that is invoked when the job has finished.
49 | /// The event type.
50 | /// The job type.
51 | public void SubscribeWithJob(EventTarget target, T_Job job, Action onComplete)
52 | where T_Job : struct, IJobForEvent
53 | where T_Event : struct
54 | {
55 | EventHandlerJob handler = GetJobSystem();
56 | handler.Subscribe(target, job, onComplete);
57 | }
58 |
59 | ///
60 | /// Unsubscribe a listener from an event.
61 | ///
62 | /// The target to unsubscribe from.
63 | /// The event callback
64 | /// The event
65 | public void Unsubscribe(EventTarget target, Action eventCallback) where T_Event : struct
66 | {
67 | EventHandlerStandard system = GetSystem();
68 | system.Unsubscribe(target, eventCallback);
69 | }
70 |
71 | ///
72 | /// Unsubscribe a job that processed during from an event.
73 | ///
74 | /// The target to unsubscribe from.
75 | /// The callback that is invoked when the job has finished.
76 | /// The job type.
77 | /// The event type.
78 | public void UnsubscribeWithJob(EventTarget target, Action onComplete)
79 | where T_Job : struct, IJobForEvent
80 | where T_Event : struct
81 | {
82 | EventHandlerJob handler = GetJobSystem();
83 | handler.Unsubscribe(target, onComplete);
84 | }
85 |
86 | ///
87 | /// Queue an event.
88 | ///
89 | /// The target to queue an event with.
90 | /// The event to queue.
91 | /// The event type.
92 | public void QueueEvent(EventTarget target, T_Event ev) where T_Event : struct
93 | {
94 | EventHandlerStandard system = GetSystem();
95 | system.QueueEvent(target, ev);
96 |
97 | List list = GetJobSystemsForEvent();
98 |
99 | int count = list.Count;
100 |
101 | for (int i = 0; i < count; i++)
102 | {
103 | IJobEventSystem typedSystem = (IJobEventSystem) list[i];
104 | typedSystem.QueueEvent(target, ev);
105 | }
106 | }
107 |
108 | ///
109 | /// Process all queued events.
110 | ///
111 | public void ProcessEvents()
112 | {
113 | int count = _systems.Count;
114 |
115 | for (int i = 0; i < count; i++)
116 | {
117 | _systems[i].ProcessEvents();
118 | }
119 | }
120 |
121 | ///
122 | /// Reset all systems in the collection.
123 | ///
124 | public void Reset()
125 | {
126 | int count = _systems.Count;
127 |
128 | for (int i = 0; i < count; i++)
129 | {
130 | _systems[i].Reset();
131 | }
132 | }
133 |
134 | ///
135 | /// Verify there are no subscribers in the systems.
136 | ///
137 | public void VerifyNoSubscribers()
138 | {
139 | int count = _systems.Count;
140 |
141 | for (int i = 0; i < count; i++)
142 | {
143 | _systems[i].VerifyNoSubscribers();
144 | }
145 | }
146 |
147 | ///
148 | /// Verify there are no subscribers. Logs instead of throwing an exception.
149 | ///
150 | public void VerifyNoSubscribersLog()
151 | {
152 | int count = _systems.Count;
153 |
154 | for (int i = 0; i < count; i++)
155 | {
156 | try
157 | {
158 | _systems[i].VerifyNoSubscribers();
159 | }
160 | catch (Exception e)
161 | {
162 | Debug.LogException(e);
163 | throw;
164 | }
165 | }
166 | }
167 |
168 | ///
169 | /// Disposes any resources held by the systems.
170 | ///
171 | public void Dispose()
172 | {
173 | int count = _systems.Count;
174 |
175 | for (int i = 0; i < count; i++)
176 | {
177 | if (_systems[i] is IDisposable disposable)
178 | {
179 | disposable.Dispose();
180 | }
181 | }
182 | }
183 |
184 | private EventHandlerStandard GetSystem() where T_Event : struct
185 | {
186 | Type evType = typeof(T_Event);
187 |
188 | if (evType == _cachedSystemEventType)
189 | {
190 | return (EventHandlerStandard) _cacheSystem;
191 | }
192 |
193 | IEventSystem system;
194 |
195 | if (!_systemsCache.TryGetValue(evType, out system))
196 | {
197 | system = new EventHandlerStandard();
198 | _systems.Add(system);
199 | _systemsCache[evType] = system;
200 | }
201 |
202 | _cachedSystemEventType = evType;
203 | _cacheSystem = system;
204 |
205 | return (EventHandlerStandard) system;
206 | }
207 |
208 | private EventHandlerJob GetJobSystem()
209 | where T_Job : struct, IJobForEvent
210 | where T_Event : struct
211 | {
212 | Type jobType = typeof(T_Job);
213 |
214 | if (jobType == _cachedJobSystemType)
215 | {
216 | return (EventHandlerJob) _cachedJobSystem;
217 | }
218 |
219 | IEventSystem system;
220 |
221 | if (!_jobSystemsCache.TryGetValue(typeof(T_Job), out system))
222 | {
223 | system = new EventHandlerJob();
224 | _systems.Add(system);
225 | _jobSystemsCache[typeof(T_Job)] = system;
226 | }
227 |
228 | _cachedJobSystemType = jobType;
229 | _cachedJobSystem = system;
230 |
231 | return (EventHandlerJob) system;
232 | }
233 |
234 | private List GetJobSystemsForEvent() where T_Event : struct
235 | {
236 | Type evType = typeof(T_Event);
237 |
238 | if (evType == _cachedJobSystemsType)
239 | {
240 | return _cachedJobSystems;
241 | }
242 |
243 | List list;
244 |
245 | if (!_eventToJobSystems.TryGetValue(evType, out list))
246 | {
247 | list = new List();
248 | _eventToJobSystems[evType] = list;
249 | }
250 |
251 | _cachedJobSystemsType = evType;
252 | _cachedJobSystems = list;
253 |
254 | return list;
255 | }
256 | }
257 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/UnityEventSystem.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 577ef3321fe573846a63f8f8ffe12425
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/UnityEvents.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "UnityEvents",
3 | "references": [
4 | "Unity.Jobs",
5 | "Unity.Burst",
6 | "Unity.Mathematics",
7 | "Unity.Collections"
8 | ],
9 | "optionalUnityReferences": [],
10 | "includePlatforms": [],
11 | "excludePlatforms": [],
12 | "allowUnsafeCode": false,
13 | "overrideReferences": false,
14 | "precompiledReferences": [],
15 | "autoReferenced": true,
16 | "defineConstraints": []
17 | }
--------------------------------------------------------------------------------
/Assets/UnityEvents/Scripts/UnityEvents.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f8c4ed1600e01de42a3fac384d8ac7c9
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Tests.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 35c3e8bfb7053e2408e7a5f21bd49d17
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/UnityEvents/Tests/TestEventManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using NUnit.Framework;
4 | using UnityEngine;
5 | using UnityEngine.TestTools;
6 |
7 | namespace UnityEvents.Test
8 | {
9 |
10 | public class TestEventManager
11 | {
12 | [TearDown]
13 | public void TearDown()
14 | {
15 | EventManager.ResetAll();
16 | }
17 |
18 | [UnityTest]
19 | public IEnumerator TestSimpleValue()
20 | {
21 | EventTarget target = EventTarget.CreateTarget();
22 |
23 | int value = 0;
24 | Action callback = x => { value += x.value; };
25 |
26 | EventManager.Subscribe(target, callback, EventUpdateTick.Update);
27 |
28 | EventManager.SendEvent(target, new EvSimpleEvent(10), EventUpdateTick.Update);
29 | Assert.IsTrue(value == 0);
30 |
31 | yield return null;
32 |
33 | Assert.IsTrue(value == 10);
34 | }
35 |
36 | [UnityTest]
37 | public IEnumerator TestSimpleValueJob()
38 | {
39 | EventTarget target = EventTarget.CreateTarget();
40 |
41 | Action callback = x => { Assert.IsTrue(x.result == 10); };
42 |
43 | EventManager.SubscribeWithJob(target, new TestJob(), callback, EventUpdateTick.Update);
44 | EventManager.SendEvent(target, new EvSimpleEvent(10), EventUpdateTick.Update);
45 |
46 | yield return null;
47 | }
48 |
49 | [UnityTest]
50 | public IEnumerator TestUpdateEvents()
51 | {
52 | EventTarget target = EventTarget.CreateTarget();
53 |
54 | Action updateCallback = x =>
55 | {
56 | string stacktrace = Environment.StackTrace;
57 | Assert.IsTrue(stacktrace.Contains("EventManager.Update ()"));
58 | };
59 |
60 | Action fixedUpdateCallback = x =>
61 | {
62 | string stacktrace = Environment.StackTrace;
63 | Assert.IsTrue(stacktrace.Contains("EventManager.FixedUpdate ()"));
64 | };
65 |
66 | Action lateUpdateCallback = x =>
67 | {
68 | string stacktrace = Environment.StackTrace;
69 | Assert.IsTrue(stacktrace.Contains("EventManager.LateUpdate ()"));
70 | };
71 |
72 | EventManager.Subscribe(target, updateCallback, EventUpdateTick.Update);
73 | EventManager.Subscribe(target, fixedUpdateCallback, EventUpdateTick.FixedUpdate);
74 | EventManager.Subscribe(target, lateUpdateCallback, EventUpdateTick.LateUpdate);
75 |
76 | EventManager.SendEvent(target, new EvSimpleEvent(), EventUpdateTick.Update);
77 | EventManager.SendEvent(target, new EvSimpleEvent(), EventUpdateTick.FixedUpdate);
78 | EventManager.SendEvent(target, new EvSimpleEvent(), EventUpdateTick.LateUpdate);
79 |
80 | yield return new WaitForFixedUpdate();
81 | yield return null;
82 | }
83 |
84 | [UnityTest]
85 | public IEnumerator TestUpdateMismatchEvent()
86 | {
87 | EventTarget target = EventTarget.CreateTarget();
88 |
89 | int value = 0;
90 | Action