# Table of Contents - [Introduction | Simple Event System](#introduction-simple-event-system) - [Subscribe to multiple Tags | Simple Event System](#subscribe-to-multiple-tags-simple-event-system) - [Payloads | Simple Event System](#payloads-simple-event-system) - [Networking | Simple Event System](#networking-simple-event-system) - [Unsubscribing | Simple Event System](#unsubscribing-simple-event-system) - [Unknown](#unknown) - [Payloads | Simple Event System](#payloads-simple-event-system) - [Unknown](#unknown) - [Unknown](#unknown) - [Switch on Payload Type | Ultimate Event System](#switch-on-payload-type-ultimate-event-system) - [Unknown](#unknown) - [Receiving & Subscribing | Ultimate Event System](#receiving-subscribing-ultimate-event-system) - [Working with Payloads | Ultimate Event System](#working-with-payloads-ultimate-event-system) - [Sending Events | Ultimate Event System](#sending-events-ultimate-event-system) - [Unknown](#unknown) - [Installation | Simple Event System](#installation-simple-event-system) - [Tag Hierarchy & Filtering | Ultimate Event System](#tag-hierarchy-filtering-ultimate-event-system) - [Unknown](#unknown) - [Unsubscribing & Lifecycle | Ultimate Event System](#unsubscribing-lifecycle-ultimate-event-system) - [Debugging & Tools | Ultimate Event System](#debugging-tools-ultimate-event-system) - [Best Practices | Ultimate Event System](#best-practices-ultimate-event-system) - [Installation & Setup | Ultimate Event System](#installation-setup-ultimate-event-system) - [Introduction | Ultimate Event System](#introduction-ultimate-event-system) - [quickstart | Ultimate Event System](#quickstart-ultimate-event-system) - [advanced | Ultimate Event System](#advanced-ultimate-event-system) - [C++ Developer Guide | Ultimate Event System](#c-developer-guide-ultimate-event-system) - [Receive Event | Simple Event System](#receive-event-simple-event-system) - [Send Event | Simple Event System](#send-event-simple-event-system) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Send Event | Simple Event System](#send-event-simple-event-system) - [Unknown](#unknown) - [Unknown](#unknown) --- # Introduction | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/introduction.md) . **Simple Event System (SES)** is a powerful and lightweight tool for Unreal Engine 5 that allows you to build game architecture without "spaghetti code." It is a **Global Event Bus** written 100% in Blueprints, designed for maximum modularity and ease of use. > **TL;DR:** SES allows Actor A to broadcast "Event X happened" along with data, without knowing who (Actor B, C, or D) is listening. #### Why use Simple Event System?[](https://asperazera.gitbook.io/simple-event-system#why-use-simple-event-system) * **100% Blueprints:** Content-only plugin, making it easy to customize and migrate to new engine versions. * **Complete Decoupling:** Removes the need for Hard References and "Cast To" nodes. * **Optimization:** Uses lightweight Instanced Structs instead of Objects to transfer data. * **Gameplay Tags:** Uses hierarchical tags (e.g., Game.State.Win) for organized event filtering. * **Replication Ready:** Built-in support for Multicast (Server-to-Clients) communication. * **Global Access:** Send and receive events from any Actor, Widget, or Component. * * * ### Technical Requirements[](https://asperazera.gitbook.io/simple-event-system#technical-requirements) Requirement Details **Engine Version** Unreal Engine 5.3+ **Plugins** **(for UE** **5.3** **and** **5.4****)** Struct Utils (Enabled by default in UE5) **Note:** This plugin requires UE 5.3 or higher due to reliance on modern Instanced Struct features that were unstable in previous engine versions. **Dependency Requirement** For **Unreal Engine 5.3 and 5.4**, please ensure the **Struct Utils** plugin is enabled in your project. Starting from **UE 5.5**, this logic became part of the Core Engine, so you **do not** need to enable any extra plugins. [NextInstallation](https://asperazera.gitbook.io/simple-event-system/installation) Last updated 7 months ago --- # Subscribe to multiple Tags | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags.md) . Sometimes a single Actor or Widget needs to react to different types of events. Instead of creating multiple `Bind Event` nodes, you can handle everything inside a single Listener logic. There are **three common ways** to handle multiple tags, depending on your needs. * * * ### 1\. Distinct Events (The Switch Node)[](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags#id-1.-distinct-events-the-switch-node) **Best for:** When you have a few specific, unrelated events that require different logic. This is the standard approach. The `Switch on Gameplay Tag` node allows you to add as many output pins as you need. In the **Details panel** of the node add the tags you want to listen to. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FsDhiXpYzcfK7rxLtiNiw%252Fimage.png%3Falt%3Dmedia%26token%3D51a4be28-8564-4dca-a8ab-2a22dbd8f227&width=768&dpr=3&quality=100&sign=3e575bf2&sv=2) > **Note:** The Switch node typically performs an **Exact Match**. If you listen for `Game.Start`, it will not trigger for `Game.Start.Round1`. * * * ### 2\. Hierarchical Groups (Parent Tags)[](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags#id-2.-hierarchical-groups-parent-tags) **Best for:** When you want to react to a _category_ of events. Gameplay Tags are hierarchical (`Parent.Child.SubChild`). If you want one piece of logic to run for **all** sub-tags under a specific parent, use the **Matches Tag** node instead of a Switch. #### Example Scenario[](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags#example-scenario) You have events: * `Round.Started` * `Round.Finished` * `Round.Paused` You want your Actor to react to **any** Round related events. #### Implementation[](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags#implementation) 1. Take the incoming **Event Tag**. 2. Search for the **Matches Tag** node. 3. In the **Tag to Match** field, select the parent tag: `Round`. 4. Connect the boolean result to a **Branch** node. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FXrqjwSc3iQNnpJD8Rflj%252Fimage.png%3Falt%3Dmedia%26token%3D182ca024-d15a-478c-bba6-1bd687467481&width=768&dpr=3&quality=100&sign=ee61a840&sv=2) **Result:** The Branch will be _True_ for `Round.Started` or any other sub-tag, because they "match" the parent category. * * * ### 3\. Custom Lists (Matches Any Tags)[](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags#id-3.-custom-lists-matches-any-tags) **Best for:** When you want to trigger the _same_ logic for a specific list of tags that are NOT hierarchically related. Sometimes you need to group unrelated events together (e.g., show a notification for both "Quest Complete" and "Level Up"). #### Implementation[](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags#implementation-1) 1. Create a `Make Literal Gameplay Tag Container` node. 2. Add the specific tags you want to check (e.g., `Quest.Complete` and `Player.LevelUp`). 3. Take the incoming **Event Tag** and search for the `Matches Any Tags` node. 4. Connect your Container to the **Other Container** pin. 5. Connect the result to a `Branch`. **Tip:** Instead of `Make Literal Gameplay Tag Container` you can create separate **variable** of **Gameplay Tag Container** type. With it you can add and remove Tags in this variable to react on events dynamically! ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FRWEBFFHiy1u5X4eQad7s%252Fimage.png%3Falt%3Dmedia%26token%3Db6889914-adad-412d-b669-090f5dd17857&width=768&dpr=3&quality=100&sign=fdf561e1&sv=2) **Result:** The Branch will be _True_ if the incoming event matches _any one_ of the tags in your list. * * * ### πŸ’‘ Summary: Which one to choose?[](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags#summary-which-one-to-choose) Method Node Used Use Case **Specific Logic** `Switch on Gameplay Tag` I need to do **different things** for different events (A -> Jump, B -> Run). **Category Logic** `Matches Tag` I need to do **one thing** for a whole group of events (Any Damage -> Subtract HP). **Group Logic** `Matches Any Tags` I need to do **one thing** for a specific list of unrelated events. [PreviousPayloads](https://asperazera.gitbook.io/simple-event-system/advanced/payloads) [NextUnsubscribing](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing) Last updated 7 months ago --- # Payloads | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/advanced/payloads.md) . To pass data (like Points, Names, or Quest IDs) without Hard References, SES uses **Instanced Structs**. #### Step 1: Create a Structure[](https://asperazera.gitbook.io/simple-event-system/advanced/payloads#step-1-create-a-structure) Create a standard **Blueprint Structure** in your Content Browser (e.g., **S\_ChatMessage\_Payload** with a **String** variable). ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252F4uys1a59RDfHDwQFQOb3%252Fimage.png%3Falt%3Dmedia%26token%3Dcc7a0ac4-0d87-4981-992b-43566be47bf4&width=768&dpr=3&quality=100&sign=caa6789b&sv=2) **Tip:** There is \`S\_Generic\_Payload\` struct that comes with an asset pack. It has some basic data type variables and can be used in common scenarios if you need. * * * #### Step 2: Sending Payload[](https://asperazera.gitbook.io/simple-event-system/advanced/payloads#step-2-sending-payload) When sending an event, you need to "wrap" your structure into the generic Payload container. 1. On the `Send Event` node, locate the **Payload** pin. 2. Drag off it and search for `Make Instanced Struct`. 3. Create `Make S_ChatMessage_Payload` node an connect it to the **Value** pin of `Make Instanced Struct` node. 4. Fill in your data. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FPO0kIB22Fm9JEOIw77WJ%252Fimage.png%3Falt%3Dmedia%26token%3Df4c93679-80d4-47b8-847f-0829fcc1780f&width=768&dpr=3&quality=100&sign=e3443b2e&sv=2) * * * #### Step 3: Receiving Payload[](https://asperazera.gitbook.io/simple-event-system/advanced/payloads#step-3-receiving-payload) When you receive an event, the data comes as a generic package. You need to open it. 1. From the **Payload** pin on your Event node, drag off and search for `Get Instanced Struct Value`. 2. Drag off from the Value pin and place `break S_ChatMessage_Payload` node. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FsKOmHib8VE2FsW4oWwcg%252Fimage.png%3Falt%3Dmedia%26token%3Da6728205-7bd9-4b31-a1b5-c4ed2ca783e3&width=768&dpr=3&quality=100&sign=84e2e97f&sv=2) [PreviousReceive Event](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event) [NextSubscribe to multiple Tags](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags) Last updated 7 months ago --- # Networking | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/advanced/networking.md) . Simple Event System follows a strict **Server Authoritative** architecture. The core logic resides in the `GameState`, but **only the Server** has the right to trigger events to ensure security and data consistency. * * * ### πŸ“‘ Sending Events: Two Modes[](https://asperazera.gitbook.io/simple-event-system/advanced/networking#sending-events-two-modes) There are two separate nodes. **Both nodes have a built-in Authority check.** If a Client attempts to call them, the execution is ignored. #### 1\. Send Game Event (Server Local)[](https://asperazera.gitbook.io/simple-event-system/advanced/networking#id-1.-send-game-event-server-local) **Use for:** Game Logic, AI decisions, Quest updates, Score calculations. * **Behavior:** Checks for Authority. If executed by the Server, it triggers the Event Dispatcher **locally on the Server only**. * **Result:** Only Server-side actors (GameMode, AI Controllers, Server-side logic) will receive this event. Clients will remain unaware. **Best Practice:** Use this when you need to update game state (like `Round -= 3`). Let standard variable replication (`RepNotify`) handle the synchronization to clients. #### 2\. Send Game Event Replicated (Multicast)[](https://asperazera.gitbook.io/simple-event-system/advanced/networking#id-2.-send-game-event-replicated-multicast) **Use for:** **UI Notifications** and maybe VFX or SFX in some scenarios. * **Behavior:** Checks for Authority. If executed by the Server, it triggers a **NetMulticast RPC**. * **Result:** The event is broadcast to **ALL connected Clients** (and the Server itself) simultaneously. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FtC8lh66dQykcKxNZhQ5X%252Fimage.png%3Falt%3Dmedia%26token%3Ded4f54eb-6706-463a-9217-5b6ef1dec776&width=768&dpr=3&quality=100&sign=d5974eda&sv=2) **Note:** Use this for "Transient" eventsβ€”things that happen in a moment and don't need to be saved (like an explosion sound). * * * ### πŸ›‘οΈ Security & Client Interaction[](https://asperazera.gitbook.io/simple-event-system/advanced/networking#security-and-client-interaction) To prevent cheating, **Clients cannot use these nodes directly.** If a Client (Remote machine) calls `Send Game Event` or `Send Game Event Replicated`, the system will simply **do nothing**. This prevents hackers from injecting fake events (e.g., "Add 1000 Gold"). #### How to trigger an event from a Client?[](https://asperazera.gitbook.io/simple-event-system/advanced/networking#how-to-trigger-an-event-from-a-client) If a player performs an action (e.g., presses a button), you must route the logic through the Server: 1. **Client:** Calls a standard **Run On Server** event (RPC) inside their Character or PlayerController (e.g., `Server_Interact`). 2. **Server:** Validates the action (Is the player close enough? Do they have the key?). 3. **Server:** Calls `**Send Game Event**` (for logic) or `**Send Game Event Replicated**` (for effects). [PreviousUnsubscribing](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing) Last updated 7 months ago --- # Unsubscribing | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing.md) . Since Simple Event System uses a global **Event Dispatcher**, "unsubscribing" can mean two things: either ignoring the event logically or completely severing the connection. Here are the three ways to handle stopping events. * * * ### 1\. Automatic Cleanup (Destroy Actor)[](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing#id-1.-automatic-cleanup-destroy-actor) **Best for:** Dead enemies, destroyed items, or level transitions. You generally **do not need** to manually unsubscribe actors that are being destroyed. Unreal Engine's Event Dispatcher system uses "weak references". When you call `Destroy Actor`, the engine automatically removes that actor from all dispatchers it was listening to. **Info:** You don't need to write any cleanup logic in the `EndPlay` event. It works out of the box. * * * ### 2\. Logical "Pause" (Enum/Boolean Filter)[](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing#id-2.-logical-pause-enum-boolean-filter) **Best for:** Temporarily ignoring events (e.g., player is stunned) or stopping reaction to one specific tag while keeping others active. Since you bind to the _Global Dispatcher_, you cannot "unbind" from just one specific tag (like `Game.Green`) while keeping `Game.Red`. Instead, use a **Enum** or **Boolean Variable** to gate the logic. #### Implementation[](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing#implementation) 1. Create a Boolean variable in your Actor (e.g., `bIsListening` or `bCanReceiveDamage`). 2. In your Event Graph, right after the **OnEventReceived** node (and before your Tag Switch), add a **Branch**. 3. Connect your boolean to the Branch. * **True:** Continue to the `Switch on Gameplay Tag` node. * **False:** Do nothing. This effectively "mutes" the events without breaking the connection. * * * ### 3\. Dynamic Filtering (Tag Container)[](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing#id-3.-dynamic-filtering-tag-container) **Best for:** Advanced actors that need to "subscribe" or "unsubscribe" from **specific** events on the fly during gameplay (e.g., unlocking a specific quest stage or enabling a feature). Instead of using multiple Boolean variables or unbinding the whole system, you can maintain a local **"Whitelist"** of tags that the actor is currently listening to. #### Implementation[](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing#implementation-1) 1. Create a variable in your Actor (e.g., named `BindedEvents`). 2. Set its type to **Gameplay Tag Container**. 3. In your Event Graph, immediately after receiving the event, check the incoming **Event Tag**. 4. Use the node **Matches Any Tags** (Container). 5. Connect your `BindedEvents` variable to the **Other Container** pin. 6. Connect the result to a **Branch**. If the incoming tag exists in your container, the Branch opens, and logic executes. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252Fax5uLyPzfL82pT73UOdS%252Fimage.png%3Falt%3Dmedia%26token%3D0c268688-38b2-418c-a2a4-00dab0bd7e4c&width=768&dpr=3&quality=100&sign=707b1225&sv=2) #### How to Control (Subscribe/Unsubscribe)[](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing#how-to-control-subscribe-unsubscribe) You can now modify this list at runtime using standard container nodes: * **To Subscribe:** Use the **Add Gameplay Tag** node on your `BindedEvents` variable (e.g., add `Game.Zone.Enter` when a player spawns). * **To Unsubscribe:** Use the **Remove Gameplay Tag** node (e.g., remove `Game.Zone.Enter` when the player leaves the area). ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FShm8bX5j1gMnZ8uhMrqw%252Fimage.png%3Falt%3Dmedia%26token%3D9bb8803a-8fcf-4e95-8996-0f45ae78efa3&width=768&dpr=3&quality=100&sign=bd14b2a6&sv=2) **Tip:** This effectively allows you to toggle individual event listeners on/off dynamically without breaking the connection to the global dispatcher. ### 4\. Manual Unbind (Hard Stop)[](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing#id-4.-manual-unbind-hard-stop) **Best for:** Optimization, or when an actor changes state completely and should never listen to the Event System again (but remains alive in the world). If you want to completely stop receiving _any_ global events on a specific actor: 1. Get the reference to the **Simple Event System Component** (using `Get Simple Event System`). 2. Drag off the component pin and search for **Unbind All Events from On Global Event**. 3. Call this node when you want to stop listening. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FNo8vQcvEswPWWh5MF7ga%252Fimage.png%3Falt%3Dmedia%26token%3D5bf69ddb-7a28-4ebf-9d26-5f54eed47141&width=768&dpr=3&quality=100&sign=eef38d46&sv=2) **Warning:** This will stop **ALL** tags for this actor. If you have multiple logic chains listening to the system in the same blueprint, they will all stop working. * * * ### πŸ“ Summary[](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing#summary) Method When to use? **Auto Cleanup** When the actor is destroyed. (Happens automatically). **Boolean Filter** Simple On/Off switch for the entire actor. **Dynamic Filter** **Granular control.** Add or remove specific tags from a "whitelist" at runtime. **Unbind All** When the actor is still alive but should completely disconnect from the system. [PreviousSubscribe to multiple Tags](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags) [NextNetworking](https://asperazera.gitbook.io/simple-event-system/advanced/networking) Last updated 7 months ago --- # Unknown \# Simple Event System ## Docs - \[Introduction\](https://asperazera.gitbook.io/simple-event-system/introduction.md) - \[Installation\](https://asperazera.gitbook.io/simple-event-system/installation.md) - \[Send Event\](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event.md) - \[Receive Event\](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event.md) - \[Payloads\](https://asperazera.gitbook.io/simple-event-system/advanced/payloads.md) - \[Subscribe to multiple Tags\](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags.md) - \[Unsubscribing\](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing.md) - \[Networking\](https://asperazera.gitbook.io/simple-event-system/advanced/networking.md) --- # Payloads | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/advanced/payloads.md) . To pass data (like Points, Names, or Quest IDs) without Hard References, SES uses **Instanced Structs**. #### Step 1: Create a Structure[](https://asperazera.gitbook.io/simple-event-system/advanced#step-1-create-a-structure) Create a standard **Blueprint Structure** in your Content Browser (e.g., **S\_ChatMessage\_Payload** with a **String** variable). ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252F4uys1a59RDfHDwQFQOb3%252Fimage.png%3Falt%3Dmedia%26token%3Dcc7a0ac4-0d87-4981-992b-43566be47bf4&width=768&dpr=3&quality=100&sign=caa6789b&sv=2) **Tip:** There is \`S\_Generic\_Payload\` struct that comes with an asset pack. It has some basic data type variables and can be used in common scenarios if you need. * * * #### Step 2: Sending Payload[](https://asperazera.gitbook.io/simple-event-system/advanced#step-2-sending-payload) When sending an event, you need to "wrap" your structure into the generic Payload container. 1. On the `Send Event` node, locate the **Payload** pin. 2. Drag off it and search for `Make Instanced Struct`. 3. Create `Make S_ChatMessage_Payload` node an connect it to the **Value** pin of `Make Instanced Struct` node. 4. Fill in your data. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FPO0kIB22Fm9JEOIw77WJ%252Fimage.png%3Falt%3Dmedia%26token%3Df4c93679-80d4-47b8-847f-0829fcc1780f&width=768&dpr=3&quality=100&sign=e3443b2e&sv=2) * * * #### Step 3: Receiving Payload[](https://asperazera.gitbook.io/simple-event-system/advanced#step-3-receiving-payload) When you receive an event, the data comes as a generic package. You need to open it. 1. From the **Payload** pin on your Event node, drag off and search for `Get Instanced Struct Value`. 2. Drag off from the Value pin and place `break S_ChatMessage_Payload` node. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FsKOmHib8VE2FsW4oWwcg%252Fimage.png%3Falt%3Dmedia%26token%3Da6728205-7bd9-4b31-a1b5-c4ed2ca783e3&width=768&dpr=3&quality=100&sign=84e2e97f&sv=2) [PreviousReceive Event](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event) [NextSubscribe to multiple Tags](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags) Last updated 7 months ago --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/simple-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/simple-event-system/advanced/unsubscribing.md). # Unsubscribing Since Simple Event System uses a global \*\*Event Dispatcher\*\*, "unsubscribing" can mean two things: either ignoring the event logically or completely severing the connection. Here are the three ways to handle stopping events. \*\*\* ### 1. Automatic Cleanup (Destroy Actor) \*\*Best for:\*\* Dead enemies, destroyed items, or level transitions. You generally \*\*do not need\*\* to manually unsubscribe actors that are being destroyed. Unreal Engine's Event Dispatcher system uses "weak references". When you call \`Destroy Actor\`, the engine automatically removes that actor from all dispatchers it was listening to. {% hint style="info" %} \*\*Info:\*\* You don't need to write any cleanup logic in the \`EndPlay\` event. It works out of the box. {% endhint %} \*\*\* ### 2. Logical "Pause" (Enum/Boolean Filter) \*\*Best for:\*\* Temporarily ignoring events (e.g., player is stunned) or stopping reaction to one specific tag while keeping others active. Since you bind to the \*Global Dispatcher\*, you cannot "unbind" from just one specific tag (like \`Game.Green\`) while keeping \`Game.Red\`. Instead, use a \*\*Enum\*\* or \*\*Boolean Variable\*\* to gate the logic. #### Implementation 1. Create a Boolean variable in your Actor (e.g., \`bIsListening\` or \`bCanReceiveDamage\`). 2. In your Event Graph, right after the \*\*OnEventReceived\*\* node (and before your Tag Switch), add a \*\*Branch\*\*. 3. Connect your boolean to the Branch. \* \*\*True:\*\* Continue to the \`Switch on Gameplay Tag\` node. \* \*\*False:\*\* Do nothing. This effectively "mutes" the events without breaking the connection. \*\*\* ### 3. Dynamic Filtering (Tag Container) \*\*Best for:\*\* Advanced actors that need to "subscribe" or "unsubscribe" from \*\*specific\*\* events on the fly during gameplay (e.g., unlocking a specific quest stage or enabling a feature). Instead of using multiple Boolean variables or unbinding the whole system, you can maintain a local \*\*"Whitelist"\*\* of tags that the actor is currently listening to. #### Implementation 1. Create a variable in your Actor (e.g., named \`BindedEvents\`). 2. Set its type to \*\*Gameplay Tag Container\*\*. 3. In your Event Graph, immediately after receiving the event, check the incoming \*\*Event Tag\*\*. 4. Use the node \*\*Matches Any Tags\*\* (Container). 5. Connect your \`BindedEvents\` variable to the \*\*Other Container\*\* pin. 6. Connect the result to a \*\*Branch\*\*. If the incoming tag exists in your container, the Branch opens, and logic executes.
#### How to Control (Subscribe/Unsubscribe) You can now modify this list at runtime using standard container nodes: \* \*\*To Subscribe:\*\* Use the \*\*Add Gameplay Tag\*\* node on your \`BindedEvents\` variable (e.g., add \`Game.Zone.Enter\` when a player spawns). \* \*\*To Unsubscribe:\*\* Use the \*\*Remove Gameplay Tag\*\* node (e.g., remove \`Game.Zone.Enter\` when the player leaves the area).
{% hint style="info" %} \*\*Tip:\*\* This effectively allows you to toggle individual event listeners on/off dynamically without breaking the connection to the global dispatcher. {% endhint %} ### 4. Manual Unbind (Hard Stop) \*\*Best for:\*\* Optimization, or when an actor changes state completely and should never listen to the Event System again (but remains alive in the world). If you want to completely stop receiving \*any\* global events on a specific actor: 1. Get the reference to the \*\*Simple Event System Component\*\* (using \`Get Simple Event System\`). 2. Drag off the component pin and search for \*\*Unbind All Events from On Global Event\*\*. 3. Call this node when you want to stop listening.
{% hint style="warning" %} \*\*Warning:\*\* This will stop \*\*ALL\*\* tags for this actor. If you have multiple logic chains listening to the system in the same blueprint, they will all stop working. {% endhint %} \*\*\* ### πŸ“ Summary | Method | When to use? | | ------------------ | -------------------------------------------------------------------------------- | | \*\*Auto Cleanup\*\* | When the actor is destroyed. (Happens automatically). | | \*\*Boolean Filter\*\* | Simple On/Off switch for the entire actor. | | \*\*Dynamic Filter\*\* | \*\*Granular control.\*\* Add or remove specific tags from a "whitelist" at runtime. | | \*\*Unbind All\*\* | When the actor is still alive but should completely disconnect from the system. | --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/simple-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/simple-event-system/introduction.md). # Introduction \*\*Simple Event System (SES)\*\* is a powerful and lightweight tool for Unreal Engine 5 that allows you to build game architecture without "spaghetti code." It is a \*\*Global Event Bus\*\* written 100% in Blueprints, designed for maximum modularity and ease of use. > \*\*TL;DR:\*\* SES allows Actor A to broadcast "Event X happened" along with data, without knowing who (Actor B, C, or D) is listening. #### Why use Simple Event System? \* \*\*100% Blueprints:\*\* Content-only plugin, making it easy to customize and migrate to new engine versions. \* \*\*Complete Decoupling:\*\* Removes the need for Hard References and "Cast To" nodes. \* \*\*Optimization:\*\* Uses lightweight Instanced Structs instead of Objects to transfer data. \* \*\*Gameplay Tags:\*\* Uses hierarchical tags (e.g., Game.State.Win) for organized event filtering. \* \*\*Replication Ready:\*\* Built-in support for Multicast (Server-to-Clients) communication. \* \*\*Global Access:\*\* Send and receive events from any Actor, Widget, or Component. \*\*\* ### Technical Requirements | Requirement | Details | | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | | \*\*Engine Version\*\* | Unreal Engine 5.3+ | | \*\*Plugins\*\* \*\*(for UE \*\*\*\*5.3\*\*\*\* and \*\*\*\*5.4\*\*\*\*)\*\* | Struct Utils (Enabled by default in UE5) | {% hint style="info" %} \*\*Note:\*\* This plugin requires UE 5.3 or higher due to reliance on modern Instanced Struct features that were unstable in previous engine versions. {% endhint %} {% hint style="warning" %} \*\*Dependency Requirement\*\* For \*\*Unreal Engine 5.3 and 5.4\*\*, please ensure the \*\*Struct Utils\*\* plugin is enabled in your project. Starting from \*\*UE 5.5\*\*, this logic became part of the Core Engine, so you \*\*do not\*\* need to enable any extra plugins. {% endhint %} --- # Switch on Payload Type | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload.md) . **Switch on Payload Type** is a custom Blueprint compiler node provided by Ultimate Event System. It allows clean, type-safe execution branching based on the runtime type contained inside an `FInstancedStruct` payload. * * * ### Why use Switch on Payload Type?[](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload#why-use-switch-on-payload-type) When a single event tag can carry different kinds of payloads (or when you want to handle primitives vs structs vs object references differently), standard blueprint casting requires long chains of `Cast To` or `Get Instanced Struct Value` checks. **Switch on Payload Type** solves this by providing a multi-output execution node similar to native `Switch on Enum` or `Switch on Int`. * * * ### Node Pins[](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload#node-pins) * **Input Exec Pin:** Main execution entry. * **Payload Pin (**`**Instanced Struct**`**):** The incoming payload container. * **Case Output Exec Pins:** One execution output for each configured case type. * **Case Value Pins:** Unpacked output data matching the case type. * **Default Exec Pin:** Executed if the payload does not match any configured case (or if payload is invalid/null). * * * ### Configuring Cases[](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload#configuring-cases) 1. Place the **Switch on Payload Type** node in your graph (category `UES -> Utilities`). 2. Select the node and locate the **Details Panel**. 3. Under **Pin Options -> Case Types**, click `**+**` **(Add Element)**. 4. Select the target struct, primitive wrapper, or object type from the dropdown. 5. The node dynamically updates on the canvas, adding a dedicated output execution pin and a typed **Value** data pin for that case! **Case Order Hierarchy:** Cases are evaluated **top-to-bottom** as configured in the Details panel. Always place more specific derived types (e.g. child object structs) **above** general base types, otherwise the general type will evaluate first and intercept execution. * * * ### Default Branch Execution[](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload#default-branch-execution) The **Default** output pin fires when: * The payload container is empty. * The contained payload type does not match any of the configured case types. * An object reference inside the payload has been destroyed by Garbage Collection (`nullptr` / stale reference). [PreviousWorking with Payloads](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads) [NextTag Hierarchy & Filtering](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy) Last updated 16 hours ago --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/simple-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/simple-event-system/advanced/networking.md). # Networking Simple Event System follows a strict \*\*Server Authoritative\*\* architecture. The core logic resides in the \`GameState\`, but \*\*only the Server\*\* has the right to trigger events to ensure security and data consistency. \*\*\* ### πŸ“‘ Sending Events: Two Modes There are two separate nodes. \*\*Both nodes have a built-in Authority check.\*\* If a Client attempts to call them, the execution is ignored. #### 1. Send Game Event (Server Local) \*\*Use for:\*\* Game Logic, AI decisions, Quest updates, Score calculations. \* \*\*Behavior:\*\* Checks for Authority. If executed by the Server, it triggers the Event Dispatcher \*\*locally on the Server only\*\*. \* \*\*Result:\*\* Only Server-side actors (GameMode, AI Controllers, Server-side logic) will receive this event. Clients will remain unaware. {% hint style="info" %} \*\*Best Practice:\*\* Use this when you need to update game state (like \`Round -= 3\`). Let standard variable replication (\`RepNotify\`) handle the synchronization to clients. {% endhint %} #### 2. Send Game Event Replicated (Multicast) \*\*Use for:\*\* \*\*UI Notifications\*\* and maybe VFX or SFX in some scenarios. \* \*\*Behavior:\*\* Checks for Authority. If executed by the Server, it triggers a \*\*NetMulticast RPC\*\*. \* \*\*Result:\*\* The event is broadcast to \*\*ALL connected Clients\*\* (and the Server itself) simultaneously.
{% hint style="info" %} \*\*Note:\*\* Use this for "Transient" eventsβ€”things that happen in a moment and don't need to be saved (like an explosion sound). {% endhint %} \*\*\* {% hint style="info" %} ### πŸ›‘οΈ Security & Client Interaction To prevent cheating, \*\*Clients cannot use these nodes directly.\*\* If a Client (Remote machine) calls \`Send Game Event\` or \`Send Game Event Replicated\`, the system will simply \*\*do nothing\*\*. This prevents hackers from injecting fake events (e.g., "Add 1000 Gold"). #### How to trigger an event from a Client? If a player performs an action (e.g., presses a button), you must route the logic through the Server: 1. \*\*Client:\*\* Calls a standard \*\*Run On Server\*\* event (RPC) inside their Character or PlayerController (e.g., \`Server\_Interact\`). 2. \*\*Server:\*\* Validates the action (Is the player close enough? Do they have the key?). 3. \*\*Server:\*\* Calls \*\*\`Send Game Event\`\*\* (for logic) or \*\*\`Send Game Event Replicated\`\*\* (for effects). {% endhint %} --- # Receiving & Subscribing | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event.md) . To listen for events broadcasted on the event bus, use the **Subscribe to Event** node. * * * ### Step 1: Add the Subscribe Node[](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event#step-1-add-the-subscribe-node) 1. Open the Blueprint that needs to listen for an event (e.g., your HUD Widget or Enemy AI Controller). 2. Right-click on the graph canvas and search for **"Subscribe to Event"** (category `UES`). 3. Place the node in an initialization flow, such as **Event BeginPlay** or **Event Construct**. * * * ### Step 2: Set Target Tag and Callback[](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event#step-2-set-target-tag-and-callback) 1. Select the **Event Tag** you wish to listen for (e.g. `Game.Player.ScoreChanged`). 2. Create or delegate a Custom Event or matching function: * Drag off the **Event** delegate pin on `Subscribe to Event` and choose **Add Custom Event**. * Name your custom event (e.g., `OnPlayerScoreChanged`). The callback event receives two parameters: * **Event Tag** (`FGameplayTag`) β€” The exact tag that triggered the event. * **Payload** (`FInstancedStruct`) β€” The generic wildcard data container. * * * ### Step 3: Store the Binding Handle[](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event#step-3-store-the-binding-handle) The `Subscribe to Event` node returns a handle of type `**FUltimateEventBindingHandle**`: **Important Practice:** Always store the returned `Binding Handle` in a Blueprint variable if you intend to manually unsubscribe later during gameplay. 1. Drag off the **Return Value** (Binding Handle) pin. 2. Select **Promote to Variable**. 3. Name it (e.g., `ScoreEventHandle`). * * * ### Step 4: Unpacking Received Data[](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event#step-4-unpacking-received-data) To extract data from the incoming `Payload` parameter inside your Custom Event: 1. Drag off the **Payload** pin. 2. Search for **"Get Instanced Struct Value"** (or use **Switch on Payload Type** for multi-type handling). 3. Connect the output to your target struct type or primitive. [Previousquickstart](https://asperazera.gitbook.io/ultimate-event-system/quickstart) [NextSending Events](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event) Last updated 16 hours ago --- # Working with Payloads | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads.md) . To pass data across the event bus without creating hard dependencies, **Ultimate Event System** relies on engine `FInstancedStruct` containers as generic wildcard payloads. * * * ### Payload Types Supported[](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads#payload-types-supported) UES supports four main data categories: 1. **Custom Blueprint / C++ Structures (**`**USTRUCT**`**)**: Any standard structure created in Content Browser or C++. 2. **Primitive Wrapper Structs**: Built-in lightweight wrappers for engine primitives (`FUltimateIntPayload`, `FUltimateFloatPayload`, `FUltimateBoolPayload`, `FUltimateStringPayload`, `FUltimateNamePayload`, `FUltimateTextPayload`, `FUltimateVectorPayload`, `FUltimateTransformPayload`). 3. **Object References (**`**FUltimateObjectPayload**`**)**: Safe wrappers for passing `UObject` / `AActor` references. 4. **Empty Payloads**: Events that act purely as signals without payload data. * * * ### Step 1: Sending Data in Blueprints[](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads#step-1-sending-data-in-blueprints) When calling `Send Event`, simply wire any variable or struct directly to the **Payload** pin: * If you wire a custom struct (e.g. `FQuestData`), UES packs it automatically. * If you wire an integer or float primitive, UES wraps it into the corresponding `FUltimateIntPayload` wrapper transparently. * * * ### Step 2: Unpacking Data on Reception[](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads#step-2-unpacking-data-on-reception) To extract payload data inside an event delegate: #### Option A: Single Known Struct Type[](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads#option-a-single-known-struct-type) 1. Drag off the **Payload** pin. 2. Search for `Get Instanced Struct Value`. 3. Connect the output **Value** pin to your target struct type or break node (e.g., `Break FQuestData`). #### Option B: Objects & Primitives[](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads#option-b-objects-and-primitives) For primitive types or object references, unbox using the appropriate helper wrapper struct: * For `UObject*` / `AActor*`: Break as `FUltimateObjectPayload` -> access the `Object` pin. * For `int32`: Break as `FUltimateIntPayload` -> access `Value`. **Tip:** For branching between multiple potential payload types on a single event tag, use the specialized **Switch on Payload Type** node documented in the next chapter. [PreviousDebugging & Tools](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging) [NextSwitch on Payload Type](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload) Last updated 16 hours ago --- # Sending Events | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event.md) . The **Send Event** node is the primary way to broadcast messages across your application in Blueprints. * * * ### Step 1: Add the Send Event Node[](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event#step-1-add-the-send-event-node) Open any Blueprint graph (Actor, Widget, Component, GameMode, etc.) where an action occurs: 1. Right-click on the graph canvas. 2. Search for **"Send Event"**. 3. Select **Send Event** (under the `UES` category). * * * ### Step 2: Configure the Event Tag[](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event#step-2-configure-the-event-tag) Events in UES are identified by **Gameplay Tags** (hierarchical topics): 1. Click the **Event Tag** pin dropdown. 2. Select an existing tag (e.g. `Event.Player.Death` or `UI.HUD.Update`). 3. Or click **Manage Gameplay Tags...** / `+` to add a new tag on the fly to `DefaultGameplayTags.ini`. **Tip:** Using structured naming schemes like `Domain.Category.Action` (e.g., `Game.Quest.Completed`) makes it easy to organize and filter events. * * * ### Step 3: (Optional) Pass a Payload[](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event#step-3-optional-pass-a-payload) If your event requires additional data (like damage amount, player state, or item struct): 1. Connect your variable or data pin directly to the **Payload** wildcard pin on the `Send Event` node. 2. The node automatically wraps primitives, custom Blueprint structs, and `UObject` references into a type-safe `FInstancedStruct` container. **No Manual Wrapping Required in BP!** The custom UES Blueprint node handles struct boxing transparently. * * * ### Step 4: Parent Tag Propagation[](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event#step-4-parent-tag-propagation) The `Send Event` node includes a boolean option **Trigger Parent Subscriptions** (`bTriggerParentSubscriptions`): * `**False**` **(Default):** Broadcasts strictly to subscribers registered for the exact tag (e.g., `UI.HUD.Health`). * `**True**`**:** Broadcasts to exact subscribers **AND** ascends the hierarchy, triggering subscribers listening to parent tags (`UI.HUD` and `UI`). Click the node pin to toggle this option according to your architecture needs. [PreviousReceiving & Subscribing](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event) Last updated 16 hours ago --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/simple-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/simple-event-system/advanced/payloads.md). # Payloads To pass data (like Points, Names, or Quest IDs) without Hard References, SES uses \*\*Instanced Structs\*\*. #### Step 1: Create a Structure Create a standard \*\*Blueprint Structure\*\* in your Content Browser (e.g., \*\*S\\\_ChatMessage\\\_Payload\*\* with a \*\*String\*\* variable).
{% hint style="info" %} \*\*Tip:\*\* There is \\\`S\\\_Generic\\\_Payload\\\` struct that comes with an asset pack. \\ It has some basic data type variables and can be used in common scenarios if you need. {% endhint %} \*\*\* #### Step 2: Sending Payload When sending an event, you need to "wrap" your structure into the generic Payload container. 1. On the \`Send Event\` node, locate the \*\*Payload\*\* pin. 2. Drag off it and search for \`Make Instanced Struct\`. 3. Create \`Make S\_ChatMessage\_Payload\` node an connect it to the \*\*Value\*\* pin of \`Make Instanced Struct\` node. 4. Fill in your data.
\*\*\* #### Step 3: Receiving Payload When you receive an event, the data comes as a generic package. You need to open it. 1. From the \*\*Payload\*\* pin on your Event node, drag off and search for \`Get Instanced Struct Value\`. 2. Drag off from the Value pin and place \`break S\_ChatMessage\_Payload\` node.
--- # Installation | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/installation.md) . Follow these steps to get the system running in your project. **Dependency Requirement** For **Unreal Engine 5.3 and 5.4**, please ensure the **Struct Utils** plugin is enabled in your project. Starting from **UE 5.5**, this logic became part of the Core Engine, so you **do not** need to enable any extra plugins. #### Add Component to GameState[](https://asperazera.gitbook.io/simple-event-system/installation#add-component-to-gamestate) The core logic lives in an Actor Component attached to your GameState. This ensures the system is accessible on both Server and Clients. 1. Open your project's `**GameState**` (or create one if you haven't already). ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FAZyLnIqyELZgszRMUHks%252Fimage.png%3Falt%3Dmedia%26token%3D3f0bb43c-ad4b-478c-9f53-73fc09e4eb4a&width=768&dpr=3&quality=100&sign=810a8fe4&sv=2) 2. In the **Components** panel (top left), click **\+ Add**. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FlEIOzuMQcuEK5dbiyg5t%252Fimage.png%3Falt%3Dmedia%26token%3D2a5a1be4-43bb-4f33-940a-032a09231a19&width=300&dpr=3&quality=100&sign=e8f0f779&sv=2) 3. Search for `**BPC_SimpleEventSystem**` and add it. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252Fvu2Vmh4n0PC7pYZlz2zn%252Fimage.png%3Falt%3Dmedia%26token%3D6ba7ba52-16bf-4363-97f7-21b592b21378&width=300&dpr=3&quality=100&sign=952ff475&sv=2) 4. **Compile and Save**. **Success:** The system is now initialized! You can access it via the helper nodes. [PreviousIntroduction](https://asperazera.gitbook.io/simple-event-system) [NextSend Event](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event) Last updated 7 months ago --- # Tag Hierarchy & Filtering | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy.md) . **Ultimate Event System** leverages native Unreal Engine **Gameplay Tags** (`FGameplayTag`) to categorize and route events. Gameplay Tags inherently support dot-separated hierarchical relationships. * * * ### Hierarchical Topic Example[](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy#hierarchical-topic-example) Consider a hierarchy of event tags defined in your project: Copy Game/ └── Event/ └── UI/ β”œβ”€β”€ HUD/ β”‚ β”œβ”€β”€ HealthChanged β”‚ └── ManaChanged └── Inventory/ └── ItemAdded * `Game.Event.UI.HUD.HealthChanged` is a leaf tag. * `Game.Event.UI.HUD` is its direct parent. * `Game.Event.UI` is an ancestor tag. * * * ### Exact Matching vs. Parent Tag Propagation[](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy#exact-matching-vs.-parent-tag-propagation) When broadcasting an event via `Send Event`, the `Trigger Parent Subscriptions` boolean (`bTriggerParentSubscriptions`) controls how the event traverses the registry: Mode `bTriggerParentSubscriptions` Behavior **Exact Mode** `False` Only subscribers listening explicitly to `Game.Event.UI.HUD.HealthChanged` receive the event. **Inclusive Mode** `True` Subscribers to `Game.Event.UI.HUD.HealthChanged`, `Game.Event.UI.HUD`, `Game.Event.UI`, and `Game.Event` ALL receive the event. * * * ### Architectural Use Cases[](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy#architectural-use-cases) #### 1\. Centralized Logging & Analytics[](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy#id-1.-centralized-logging-and-analytics) Create a global manager subscriber listening to the parent tag `Game.Event`. Set `bTriggerParentSubscriptions = True` on all game events. The analytics manager automatically captures all child events across the system without individual setup! #### 2\. Sub-System HUD Listeners[](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy#id-2.-sub-system-hud-listeners) A HUD Widget can subscribe to `Game.Event.UI.HUD`. Whenever any specific HUD event (`HealthChanged`, `ManaChanged`, `StaminaChanged`) fires with parent propagation, the widget receives the notification, inspects the incoming `Event Tag` parameter, and updates the display accordingly. **Original Tag Preserved:** When parent listeners receive a propagated event, the `Event Tag` delegate parameter always carries the **original leaf tag** that fired the event, allowing listeners to identify the exact source event. [PreviousSwitch on Payload Type](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload) [NextUnsubscribing & Lifecycle](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing) Last updated 16 hours ago --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/simple-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/simple-event-system/advanced/subscribe-to-multiple-tags.md). # Subscribe to multiple Tags Sometimes a single Actor or Widget needs to react to different types of events. Instead of creating multiple \`Bind Event\` nodes, you can handle everything inside a single Listener logic. There are \*\*three common ways\*\* to handle multiple tags, depending on your needs. \*\*\* ### 1. Distinct Events (The Switch Node) \*\*Best for:\*\* When you have a few specific, unrelated events that require different logic. This is the standard approach. The \`Switch on Gameplay Tag\` node allows you to add as many output pins as you need. In the \*\*Details panel\*\* of the node add the tags you want to listen to.
> \*\*Note:\*\* The Switch node typically performs an \*\*Exact Match\*\*. If you listen for \`Game.Start\`, it will not trigger for \`Game.Start.Round1\`. \*\*\* ### 2. Hierarchical Groups (Parent Tags) \*\*Best for:\*\* When you want to react to a \*category\* of events. Gameplay Tags are hierarchical (\`Parent.Child.SubChild\`). If you want one piece of logic to run for \*\*all\*\* sub-tags under a specific parent, use the \*\*Matches Tag\*\* node instead of a Switch. #### Example Scenario You have events: \* \`Round.Started\` \* \`Round.Finished\` \* \`Round.Paused\` You want your Actor to react to \*\*any\*\* Round related events. #### Implementation 1. Take the incoming \*\*Event Tag\*\*. 2. Search for the \*\*Matches Tag\*\* node. 3. In the \*\*Tag to Match\*\* field, select the parent tag: \`Round\`. 4. Connect the boolean result to a \*\*Branch\*\* node.
{% hint style="success" %} \*\*Result:\*\* The Branch will be \*True\* for \`Round.Started\` or any other sub-tag, because they "match" the parent category. {% endhint %} \*\*\* ### 3. Custom Lists (Matches Any Tags) \*\*Best for:\*\* When you want to trigger the \*same\* logic for a specific list of tags that are NOT hierarchically related. Sometimes you need to group unrelated events together (e.g., show a notification for both "Quest Complete" and "Level Up"). #### Implementation 1. Create a \`Make Literal Gameplay Tag Container\` node. 2. Add the specific tags you want to check (e.g., \`Quest.Complete\` and \`Player.LevelUp\`). 3. Take the incoming \*\*Event Tag\*\* and search for the \`Matches Any Tags\` node. 4. Connect your Container to the \*\*Other Container\*\* pin. 5. Connect the result to a \`Branch\`. {% hint style="info" %} \*\*Tip:\*\* Instead of \`Make Literal Gameplay Tag Container\` you can create separate \*\*variable\*\* of \*\*Gameplay Tag Container\*\* type. With it you can add and remove Tags in this variable to react on events dynamically! {% endhint %}
{% hint style="success" %} \*\*Result:\*\* The Branch will be \*True\* if the incoming event matches \*any one\* of the tags in your list. {% endhint %} \*\*\* ### πŸ’‘ Summary: Which one to choose? | Method | Node Used | Use Case | | ------------------ | ------------------------ | ----------------------------------------------------------------------------------- | | \*\*Specific Logic\*\* | \`Switch on Gameplay Tag\` | I need to do \*\*different things\*\* for different events (A -> Jump, B -> Run). | | \*\*Category Logic\*\* | \`Matches Tag\` | I need to do \*\*one thing\*\* for a whole group of events (Any Damage -> Subtract HP). | | \*\*Group Logic\*\* | \`Matches Any Tags\` | I need to do \*\*one thing\*\* for a specific list of unrelated events. | --- # Unsubscribing & Lifecycle | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing.md) . Properly managing event subscriptions ensures clean object lifecycles and prevents unexpected callbacks during game transitions. * * * ### Unsubscribing by Binding Handle[](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing#unsubscribing-by-binding-handle) When you call `Subscribe to Event`, it returns a lightweight, unique handle of type `**FUltimateEventBindingHandle**`. To unsubscribe a specific listener: 1. Call the **Unsubscribe from Event** node (category `UES`). 2. Pass the saved `Binding Handle`. 3. The event bus immediately removes the subscription record. Copy [Subscribe to Event] ──(Return Value)──> [Store Variable: Handle] β”‚ [Unsubscribe from Event] <──(Handle)β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ * * * ### Unsubscribing All Events for an Object[](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing#unsubscribing-all-events-for-an-object) If an Actor or Component subscribes to multiple event tags, you can unhook all of its active bindings at once: 1. Call **Unsubscribe from All Events** (category `UES`). 2. Pass the `Target Object` (or `Self`). 3. All handles associated with that subscriber instance are invalidated instantly. **Best Practice:** Call `Unsubscribe from All Events` inside an Actor's **Event EndPlay** or a Widget's **Destruct** event to ensure complete cleanup when assets leave the world. * * * ### Garbage Collection Protection[](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing#garbage-collection-protection) What happens if an Actor is destroyed without explicitly unsubscribing? UES is designed with **automatic Garbage Collection safety**: * Subscriptions **do not** hold strong references (`UProperty`) to subscribers. Subscriber identities are stored using weak `FObjectKey` handles. * Prior to executing any callback delegate during broadcast, UES checks if the subscriber is valid (`IsValid()`). * If a subscriber was destroyed or garbage collected, UES skips invocation automatically. * Stale entries are periodically pruned from memory by a background cleanup timer (`CleanupStaleSubscriptions`). **No Crashes or Memory Leaks:** Destroyed objects will never cause dangling pointer crashes or prevent Garbage Collection! [PreviousTag Hierarchy & Filtering](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy) [Nextquickstart](https://asperazera.gitbook.io/ultimate-event-system/quickstart) Last updated 16 hours ago --- # Debugging & Tools | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging.md) . **Ultimate Event System** includes a comprehensive suite of debugging tools to inspect event traffic, monitor active subscriptions, and diagnose gameplay issues in real time. * * * ### Console Commands[](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging#console-commands) Open the in-game console (tilde `~` key during PIE or Standalone) to execute UES commands: Console Command Description `UES.ListSubscriptions` Dumps all currently registered event topics, subscriber count, and binding handles to the output log. `UES.LogEvents [0/1]` Toggles real-time console logging for every event broadcast on the bus. `UES.ToggleHUD` Toggles an interactive Slate HUD overlay on screen showing live event statistics and throughput. `UES.Prune` Forces an immediate manual garbage-collection sweep of stale handles in the subscription registry. * * * ### Visual Logger (VLog) Integration[](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging#visual-logger-vlog-integration) UES records event dispatches directly into Unreal Engine's **Visual Logger**: 1. In Editor, open **Tools -> Debug -> Visual Logger**. 2. Start recording during gameplay. 3. Select any Actor in the log timeline to see all UES events dispatched or received by that specific Actor instance, complete with payload type details. * * * ### In-Engine Subsystem Metrics[](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging#in-engine-subsystem-metrics) You can query subsystem state at runtime via Blueprint or C++: * `**GetActiveSubscriptionCount()**`: Returns total active subscriber bindings. * `**GetTotalEventsDispatched()**`: Returns total count of events fired since game session startup. * * * ### Safe Re-entrancy Guarantee[](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging#safe-re-entrancy-guarantee) UES is built with safe **re-entrancy support**: * If a subscriber callback triggers a nested `Send Event` or calls `Unsubscribe`, the registry safely queues modification operations until the outermost broadcast unwinds. * Callback execution order remains deterministic, avoiding iterator corruption or array re-allocation crashes. [PreviousC++ Developer Guide](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide) [NextWorking with Payloads](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads) Last updated 16 hours ago --- # Best Practices | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/best-practices.md) . To get the most out of **Ultimate Event System**, follow these architectural recommendations for structuring events, managing lifecycles, and keeping performance optimal. * * * ### 1\. Gameplay Tag Naming Conventions[](https://asperazera.gitbook.io/ultimate-event-system/best-practices#id-1.-gameplay-tag-naming-conventions) Use a clear, standard dot-separated taxonomy for all event tags in `DefaultGameplayTags.ini`: Copy Domain . Category . Action / EventName #### Good Examples:[](https://asperazera.gitbook.io/ultimate-event-system/best-practices#good-examples) * `Game.Player.HealthChanged` * `UI.HUD.InventoryOpened` * `Weapon.Rifle.Fired` * `Quest.Chapter1.ObjectiveCompleted` #### Avoid:[](https://asperazera.gitbook.io/ultimate-event-system/best-practices#avoid) * Flat tag names without category hierarchy (e.g., `HealthEvent`). * Overly generic names (e.g., `Update`). * * * ### 2\. Payload Struct Organization[](https://asperazera.gitbook.io/ultimate-event-system/best-practices#id-2.-payload-struct-organization) * **Group related variables:** Create dedicated Blueprint/C++ payload structs (e.g. `FDamageEventPayload`) rather than passing multiple loose events. * **Use primitive wrappers for simple signals:** When passing a single scalar (like score count or sound ID), leverage primitive wrappers like `FUltimateIntPayload` or `FUltimateNamePayload` instead of creating single-variable structs. * * * ### 3\. Explicit Lifecycle Cleanup[](https://asperazera.gitbook.io/ultimate-event-system/best-practices#id-3.-explicit-lifecycle-cleanup) Although UES automatically skips destroyed subscribers via weak reference checks, **always call** `**Unsubscribe from All Events**` **in** `**EndPlay**` **/** `**Destruct**`: Copy [Event EndPlay] ───> [Unsubscribe from All Events (Target: Self)] Explicit cleanup reduces registry overhead immediately without waiting for the periodic GC pruning timer. * * * ### 4\. Prefer Subsystems over Global Managers[](https://asperazera.gitbook.io/ultimate-event-system/best-practices#id-4.-prefer-subsystems-over-global-managers) * Subscribe to global events inside `UGameInstanceSubsystem` or `UWorldSubsystem` classes when managing cross-level game state. * Subsystems are automatically managed by Unreal Engine and persistent across level travel. * * * ### 5\. Performance Optimization[](https://asperazera.gitbook.io/ultimate-event-system/best-practices#id-5.-performance-optimization) * **Avoid heavy allocation loops inside event handlers:** Handlers should perform lightweight state updates or trigger async tasks. * **Use** `**bTriggerParentSubscriptions = True**` **intentionally:** Enable parent tag propagation only when parent listeners actually exist (e.g. centralized UI or logging managers) to keep traversal paths minimal. [PreviousIntroduction](https://asperazera.gitbook.io/ultimate-event-system) [NextInstallation & Setup](https://asperazera.gitbook.io/ultimate-event-system/installation) Last updated 16 hours ago --- # Installation & Setup | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/installation.md) . Setting up **Ultimate Event System (UES)** in your Unreal Engine 5 project is quick and straightforward. * * * ### Step 1: Install the Plugin[](https://asperazera.gitbook.io/ultimate-event-system/installation#step-1-install-the-plugin) 1. Clone or copy the `UltimateEventSystem` plugin folder into your project's `Plugins/` directory: Copy YourProject/ └── Plugins/ └── UltimateEventSystem/ 2. Regenerate project files and open your `.uproject` solution. 3. In Unreal Editor, go to **Edit -> Plugins**, search for **Ultimate Event System**, and ensure it is checked **Enabled**. * * * ### Step 2: Configure Dependencies (UE 5.3 / 5.4)[](https://asperazera.gitbook.io/ultimate-event-system/installation#step-2-configure-dependencies-ue-5.3-5.4) If your project runs on Unreal Engine **5.3** or **5.4**, make sure the **Struct Utils** plugin is enabled: 1. Open **Edit -> Plugins**. 2. Search for **Struct Utils**. 3. Enable the plugin and restart the editor when prompted. **UE 5.5+ Notice:** In Unreal Engine 5.5 and later, `StructUtils` is integrated directly into CoreEngine, so no extra plugin toggling is required. * * * ### Step 3: C++ Module Dependency (Optional for C++ Projects)[](https://asperazera.gitbook.io/ultimate-event-system/installation#step-3-c-module-dependency-optional-for-c-projects) If you plan to interact with UES directly from C++, add `UltimateEventSystem` to your project's `.Build.cs` file: Copy public class MyGameProject : ModuleRules { public MyGameProject(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "GameplayTags", "StructUtils", "UltimateEventSystem" // <--- Add this line }); } } Include the main subsystem header wherever needed: Copy #include "Subsystem/UltimateSubsystem.h" * * * ### Step 4: Setup Gameplay Tags[](https://asperazera.gitbook.io/ultimate-event-system/installation#step-4-setup-gameplay-tags) UES uses **Gameplay Tags** as event topics. You can manage tags in **Project Settings -> Gameplay Tags** or add them dynamically via the tag editor dropdown in Blueprints. [PreviousBest Practices](https://asperazera.gitbook.io/ultimate-event-system/best-practices) [Nextadvanced](https://asperazera.gitbook.io/ultimate-event-system/advanced) Last updated 16 hours ago --- # Introduction | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/readme.md) . **Ultimate Event System (UES)** is a high-performance, decoupled **Event Broker** plugin for Unreal Engine 5. It is designed to replace hard references and complex interface casting with a clean, topic-based **Publisher-Subscriber architecture**. > **TL;DR:** UES allows any Actor, Component, Widget, or Subsystem to broadcast "Event X happened" with optional wildcard data (Payloads) without needing to know who is listening. * * * ### Why use Ultimate Event System?[](https://asperazera.gitbook.io/ultimate-event-system#why-use-ultimate-event-system) * **Complete Decoupling:** Eliminates hard object references, `Cast To` nodes, and direct interface bindings between actors. * **Hierarchical Topics (Gameplay Tags):** Uses native `FGameplayTag` hierarchies (e.g. `Event.Player.Health.Changed`) for organized event filtering and parent-tag propagation. * **Wildcard Payloads (**`**FInstancedStruct**`**):** Send primitives, custom structures, or `UObject` references safely without blueprint casting headaches. * **Specialized K2 Nodes:** Includes powerful Blueprint compiler nodes like **Switch on Payload Type** for type-safe branching and custom wildcard payload nodes. * **C++ & Blueprint Parity:** Built on top of `UGameInstanceSubsystem` (`UUltimateSubsystem`), providing 100% feature parity in both C++ and Blueprints. * **Memory Safety & Automatic GC Protection:** Subscriber references are tracked using weak keys (`FObjectKey`), preventing dangling subscriptions and memory leaks when actors are destroyed. * **Built-in Debug Tooling:** Comes with Visual Logger (VLog) integration, console commands, and real-time screen HUD overlays. * * * ### Technical Requirements[](https://asperazera.gitbook.io/ultimate-event-system#technical-requirements) Requirement Details **Engine Version** Unreal Engine 5.3+ **Dependencies** StructUtils (Enabled by default in UE 5.3+) **Language** C++ Engine Plugin with full Blueprint Exposure **Note:** Ultimate Event System requires **Unreal Engine 5.3 or higher** due to its core reliance on `FInstancedStruct` features from the engine's `StructUtils` module. **Dependency Requirement for UE 5.3 and 5.4** Please ensure the **Struct Utils** plugin is enabled in your `.uproject` file. In **UE 5.5+**, `StructUtils` became part of the core engine module and does not require explicit plugin activation. [NextBest Practices](https://asperazera.gitbook.io/ultimate-event-system/best-practices) Last updated 16 hours ago --- # quickstart | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/quickstart.md) . [Receiving & Subscribing](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event) [Sending Events](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event) [PreviousUnsubscribing & Lifecycle](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing) [NextReceiving & Subscribing](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event) Last updated 16 hours ago --- # advanced | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/advanced.md) . [C++ Developer Guide](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide) [Debugging & Tools](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging) [Working with Payloads](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads) [Switch on Payload Type](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload) [Tag Hierarchy & Filtering](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy) [Unsubscribing & Lifecycle](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing) [PreviousInstallation & Setup](https://asperazera.gitbook.io/ultimate-event-system/installation) [NextC++ Developer Guide](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide) Last updated 16 hours ago --- # C++ Developer Guide | Ultimate Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/ultimate-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide.md) . **Ultimate Event System** provides full C++ API parity. The system is managed by `UUltimateSubsystem`, which inherits from `UGameInstanceSubsystem`. * * * ### Accessing the Subsystem[](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide#accessing-the-subsystem) Obtain the subsystem instance from any Game Thread context (e.g. `AActor`, `UActorComponent`, `UWorld`): Copy #include "Subsystem/UltimateSubsystem.h" // Inside an AActor method: if (UGameInstance* GI = GetGameInstance()) { UUltimateSubsystem* EventSubsystem = GI->GetSubsystem(); if (EventSubsystem) { // Use subsystem API } } * * * ### Broadcasting Events in C++[](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide#broadcasting-events-in-c) Use `FInstancedStruct::Make(...)` to package C++ structures into wildcard payloads. #### Example: Broadcasting a Custom Struct[](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide#example-broadcasting-a-custom-struct) Copy #include "Subsystem/UltimateSubsystem.h" #include "StructUtils/InstancedStruct.h" // Define a custom payload struct USTRUCT(BlueprintType) FMyScorePayload { GENERATED_BODY() UPROPERTY(BlueprintReadWrite) int32 Score = 0; UPROPERTY(BlueprintReadWrite) FString PlayerName; }; // Broadcasting the event: FGameplayTag EventTag = FGameplayTag::RequestGameplayTag(FName("Game.Player.ScoreChanged")); FMyScorePayload Data; Data.Score = 150; Data.PlayerName = TEXT("Alice"); FInstancedStruct Payload = FInstancedStruct::Make(Data); // Broadcast (with parent propagation set to false) EventSubsystem->SendEvent(EventTag, Payload, false); * * * ### Subscribing to Events in C++[](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide#subscribing-to-events-in-c) Subscribe using native C++ delegates (`FUltimateEventDelegate`): Copy // 1. Declare your handler function in your class header: void AMyCharacter::OnScoreChanged(FGameplayTag EventTag, const FInstancedStruct& Payload) { if (const FMyScorePayload* Data = Payload.GetPtr()) { UE_LOG(LogTemp, Log, TEXT("Score updated to %d for %s"), Data->Score, *Data->PlayerName); } } // 2. Register subscription in BeginPlay: FGameplayTag TargetTag = FGameplayTag::RequestGameplayTag(FName("Game.Player.ScoreChanged")); FUltimateEventDelegate Delegate; Delegate.BindUObject(this, &AMyCharacter::OnScoreChanged); FUltimateEventBindingHandle BindingHandle = EventSubsystem->SubscribeToEvent(TargetTag, Delegate); * * * ### Unsubscribing in C++[](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide#unsubscribing-in-c) Unsubscribe in `EndPlay` or `BeginDestroy`: Copy void AMyCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason) { if (UGameInstance* GI = GetGameInstance()) { if (UUltimateSubsystem* EventSubsystem = GI->GetSubsystem()) { // Unsubscribe single handle: EventSubsystem->UnsubscribeFromEvent(BindingHandle); // Or unsubscribe all events registered for this object instance: EventSubsystem->UnsubscribeFromAllEvents(this); } } Super::EndPlay(EndPlayReason); } **Thread Safety Requirement:** All subsystem operations (subscribing, broadcasting, unsubscribing) must strictly execute on the **Game Thread** (`check(IsInGameThread())`). [Previousadvanced](https://asperazera.gitbook.io/ultimate-event-system/advanced) [NextDebugging & Tools](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging) Last updated 16 hours ago --- # Receive Event | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event.md) . To react to an event (like opening a door, updating UI, or playing a sound), you need to **Subscribe** (Bind) to the Simple Event System. > πŸ“ **Where to put this?** The best place to bind events is usually inside **Event BeginPlay** (for Actors) or **Event OnInitialized** (for Widgets). * * * ### Step 1: Get the System[](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event#step-1-get-the-system) First, we need to get a reference to the system component. 1. Right-click on your graph. 2. Search for **Get Simple Event System**. 3. Place node on the graph. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252F1njemXnVuMMFFjwQO3SM%252Fimage.png%3Falt%3Dmedia%26token%3Dab1045d8-3636-4207-a1b3-fd1dbb9c6b3f&width=768&dpr=3&quality=100&sign=77490d55&sv=2) * * * ### Step 2: Assign the Dispatcher[](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event#step-2-assign-the-dispatcher) Now, we bind a custom event to the system's dispatcher. 1. Drag off the blue return pin from Get Simple Event System. 2. Search for **"Assign Event System Dispatcher"**. 3. This will create two nodes: * `Bind Event to Event System Dispatcher` (The subscription). * `Custom Event` (Where your logic goes). **Tip:** You can use `Create Event` node to bind separate **Function** instead of `Custom Event`. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252F6wXSstAI1Kes4j07oH8h%252Fimage.png%3Falt%3Dmedia%26token%3De694b399-c7dd-4942-8216-5d9ab3ff29bf&width=768&dpr=3&quality=100&sign=e5befd1d&sv=2) * * * ### Step 3: Set the Tag Switch[](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event#step-3-set-the-tag-switch) By default, you will hear **every single event** in the game. You probably don't want that. 1. Locate the **Event Tag** input on the `Bind Event` node. 2. Get the `Switch on Gameplay Tag` node. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FtVHQqrh67GrUxb2GUiAg%252Fimage.png%3Falt%3Dmedia%26token%3D98801591-bf69-46f2-91b9-9941e49060a3&width=768&dpr=3&quality=100&sign=2edd16e2&sv=2) In the Details panel of Switch node select the specific **Gameplay Tag** you want to listen for (e.g., `TriggerOverlap.Start`). ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FaNAUYarEV0ergshbRWoW%252Fimage.png%3Falt%3Dmedia%26token%3D6461bc6b-0294-4957-8a54-94344f75094c&width=768&dpr=3&quality=100&sign=68c9d718&sv=2) * * * ### Step 4: Handle the Logic[](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event#step-4-handle-the-logic) Now, connect your `Bind Event` node to `BeginPlay`. Then, add your game logic to the `Custom Event` node. **Example:** * **Event:** TriggerOverlap.Start * **Logic:** Print String "Hello World". ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FpSQ9KDAOX1GynaUk7XfY%252Fimage.png%3Falt%3Dmedia%26token%3D457ca874-6617-4cb5-8417-5e2fb73db45d&width=768&dpr=3&quality=100&sign=10571dda&sv=2) [PreviousSend Event](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event) [NextPayloads](https://asperazera.gitbook.io/simple-event-system/advanced/payloads) Last updated 7 months ago --- # Send Event | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event.md) . The **Send Event** node is the primary way to broadcast a message. * * * ### Step 1: Add the Node[](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event#step-1-add-the-node) Open any Blueprint (Actor, Widget, GameInstance, etc.) where you want to trigger an event. 1. Right-click on the graph. 2. Search for **"Send Event"**. 3. Select the function under the **Simple Event System** category. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252F38CzpttNNCxo8pnQd5BZ%252Fimage.png%3Falt%3Dmedia%26token%3D76b7573f-d620-4305-92f5-3bb37fb61361&width=768&dpr=3&quality=100&sign=dee57f0b&sv=2) * * * ### Step 2: Define the Event Tag[](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event#step-2-define-the-event-tag) Events in **Simple Event System** are identified by **Gameplay Tags**. **Tip:** You don't need to define them in Project Settings beforehand; you can create them on the fly. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FTujUj9Iojr9oeFMpzWNd%252Fimage.png%3Falt%3Dmedia%26token%3Dbf8c522f-0475-4445-b88c-470b7d240710&width=768&dpr=3&quality=100&sign=5c5fd5da&sv=2) 1. Click the **Event Tag** dropdown on the node. 2. Click **Plus** Icon. 3. Type the name of your event (e.g., `TriggerOverlap.Start`). 4. Select **Source** as `DefaultGameplayTags.ini`. 5. Click **Add New Tag** to save it. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FQtKzjYG0cbwybtYyYNjP%252Fimage.png%3Falt%3Dmedia%26token%3De79e5b04-65e9-4447-878d-6db4af00d78e&width=768&dpr=3&quality=100&sign=9b97c507&sv=2) * * * ### Step 3: Select the Tag[](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event#step-3-select-the-tag) Once added, ensure the tag is selected in the dropdown. Your node is now ready to fire! ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FdNqEQZGF8MxYLWyH4bT1%252Fimage.png%3Falt%3Dmedia%26token%3D523ff738-703b-464f-bfa2-9d6b65427963&width=768&dpr=3&quality=100&sign=630f5c9f&sv=2) [PreviousInstallation](https://asperazera.gitbook.io/simple-event-system/installation) [NextReceive Event](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event) Last updated 7 months ago --- # Unknown \# Ultimate Event System ## Docs - \[Introduction\](https://asperazera.gitbook.io/ultimate-event-system/readme.md) - \[Best Practices\](https://asperazera.gitbook.io/ultimate-event-system/best-practices.md) - \[Installation & Setup\](https://asperazera.gitbook.io/ultimate-event-system/installation.md) - \[advanced\](https://asperazera.gitbook.io/ultimate-event-system/advanced.md) - \[C++ Developer Guide\](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide.md) - \[Debugging & Tools\](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging.md) - \[Working with Payloads\](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads.md) - \[Switch on Payload Type\](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload.md) - \[Tag Hierarchy & Filtering\](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy.md) - \[Unsubscribing & Lifecycle\](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing.md) - \[quickstart\](https://asperazera.gitbook.io/ultimate-event-system/quickstart.md) - \[Receiving & Subscribing\](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event.md) - \[Sending Events\](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event.md) --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload.md). # Switch on Payload Type \*\*Switch on Payload Type\*\* is a custom Blueprint compiler node provided by Ultimate Event System. It allows clean, type-safe execution branching based on the runtime type contained inside an \`FInstancedStruct\` payload. \*\*\* ### Why use Switch on Payload Type? When a single event tag can carry different kinds of payloads (or when you want to handle primitives vs structs vs object references differently), standard blueprint casting requires long chains of \`Cast To\` or \`Get Instanced Struct Value\` checks. \*\*Switch on Payload Type\*\* solves this by providing a multi-output execution node similar to native \`Switch on Enum\` or \`Switch on Int\`. \*\*\* ### Node Pins \* \*\*Input Exec Pin:\*\* Main execution entry. \* \*\*Payload Pin (\`Instanced Struct\`):\*\* The incoming payload container. \* \*\*Case Output Exec Pins:\*\* One execution output for each configured case type. \* \*\*Case Value Pins:\*\* Unpacked output data matching the case type. \* \*\*Default Exec Pin:\*\* Executed if the payload does not match any configured case (or if payload is invalid/null). \*\*\* ### Configuring Cases 1. Place the \*\*Switch on Payload Type\*\* node in your graph (category \`UES -> Utilities\`). 2. Select the node and locate the \*\*Details Panel\*\*. 3. Under \*\*Pin Options -> Case Types\*\*, click \*\*\`+\` (Add Element)\*\*. 4. Select the target struct, primitive wrapper, or object type from the dropdown. 5. The node dynamically updates on the canvas, adding a dedicated output execution pin and a typed \*\*Value\*\* data pin for that case! {% hint style="warning" %} \*\*Case Order Hierarchy:\*\* Cases are evaluated \*\*top-to-bottom\*\* as configured in the Details panel. Always place more specific derived types (e.g. child object structs) \*\*above\*\* general base types, otherwise the general type will evaluate first and intercept execution. {% endhint %} \*\*\* ### Default Branch Execution The \*\*Default\*\* output pin fires when: \* The payload container is empty. \* The contained payload type does not match any of the configured case types. \* An object reference inside the payload has been destroyed by Garbage Collection (\`nullptr\` / stale reference). --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads.md). # Working with Payloads To pass data across the event bus without creating hard dependencies, \*\*Ultimate Event System\*\* relies on engine \`FInstancedStruct\` containers as generic wildcard payloads. \*\*\* ### Payload Types Supported UES supports four main data categories: 1. \*\*Custom Blueprint / C++ Structures (\`USTRUCT\`)\*\*: Any standard structure created in Content Browser or C++. 2. \*\*Primitive Wrapper Structs\*\*: Built-in lightweight wrappers for engine primitives (\`FUltimateIntPayload\`, \`FUltimateFloatPayload\`, \`FUltimateBoolPayload\`, \`FUltimateStringPayload\`, \`FUltimateNamePayload\`, \`FUltimateTextPayload\`, \`FUltimateVectorPayload\`, \`FUltimateTransformPayload\`). 3. \*\*Object References (\`FUltimateObjectPayload\`)\*\*: Safe wrappers for passing \`UObject\` / \`AActor\` references. 4. \*\*Empty Payloads\*\*: Events that act purely as signals without payload data. \*\*\* ### Step 1: Sending Data in Blueprints When calling \`Send Event\`, simply wire any variable or struct directly to the \*\*Payload\*\* pin: \* If you wire a custom struct (e.g. \`FQuestData\`), UES packs it automatically. \* If you wire an integer or float primitive, UES wraps it into the corresponding \`FUltimateIntPayload\` wrapper transparently. \*\*\* ### Step 2: Unpacking Data on Reception To extract payload data inside an event delegate: #### Option A: Single Known Struct Type 1. Drag off the \*\*Payload\*\* pin. 2. Search for \`Get Instanced Struct Value\`. 3. Connect the output \*\*Value\*\* pin to your target struct type or break node (e.g., \`Break FQuestData\`). #### Option B: Objects & Primitives For primitive types or object references, unbox using the appropriate helper wrapper struct: \* For \`UObject\*\` / \`AActor\*\`: Break as \`FUltimateObjectPayload\` -> access the \`Object\` pin. \* For \`int32\`: Break as \`FUltimateIntPayload\` -> access \`Value\`. {% hint style="info" %} \*\*Tip:\*\* For branching between multiple potential payload types on a single event tag, use the specialized \*\*Switch on Payload Type\*\* node documented in the next chapter. {% endhint %} --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event.md). # Sending Events The \*\*Send Event\*\* node is the primary way to broadcast messages across your application in Blueprints. \*\*\* ### Step 1: Add the Send Event Node Open any Blueprint graph (Actor, Widget, Component, GameMode, etc.) where an action occurs: 1. Right-click on the graph canvas. 2. Search for \*\*"Send Event"\*\*. 3. Select \*\*Send Event\*\* (under the \`UES\` category). \*\*\* ### Step 2: Configure the Event Tag Events in UES are identified by \*\*Gameplay Tags\*\* (hierarchical topics): 1. Click the \*\*Event Tag\*\* pin dropdown. 2. Select an existing tag (e.g. \`Event.Player.Death\` or \`UI.HUD.Update\`). 3. Or click \*\*Manage Gameplay Tags...\*\* / \`+\` to add a new tag on the fly to \`DefaultGameplayTags.ini\`. {% hint style="info" %} \*\*Tip:\*\* Using structured naming schemes like \`Domain.Category.Action\` (e.g., \`Game.Quest.Completed\`) makes it easy to organize and filter events. {% endhint %} \*\*\* ### Step 3: (Optional) Pass a Payload If your event requires additional data (like damage amount, player state, or item struct): 1. Connect your variable or data pin directly to the \*\*Payload\*\* wildcard pin on the \`Send Event\` node. 2. The node automatically wraps primitives, custom Blueprint structs, and \`UObject\` references into a type-safe \`FInstancedStruct\` container. {% hint style="success" %} \*\*No Manual Wrapping Required in BP!\*\* The custom UES Blueprint node handles struct boxing transparently. {% endhint %} \*\*\* ### Step 4: Parent Tag Propagation The \`Send Event\` node includes a boolean option \*\*Trigger Parent Subscriptions\*\* (\`bTriggerParentSubscriptions\`): \* \*\*\`False\` (Default):\*\* Broadcasts strictly to subscribers registered for the exact tag (e.g., \`UI.HUD.Health\`). \* \*\*\`True\`:\*\* Broadcasts to exact subscribers \*\*AND\*\* ascends the hierarchy, triggering subscribers listening to parent tags (\`UI.HUD\` and \`UI\`). Click the node pin to toggle this option according to your architecture needs. --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/simple-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/simple-event-system/installation.md). # Installation Follow these steps to get the system running in your project. {% hint style="warning" %} \*\*Dependency Requirement\*\* For \*\*Unreal Engine 5.3 and 5.4\*\*, please ensure the \*\*Struct Utils\*\* plugin is enabled in your project. Starting from \*\*UE 5.5\*\*, this logic became part of the Core Engine, so you \*\*do not\*\* need to enable any extra plugins. {% endhint %} #### Add Component to GameState The core logic lives in an Actor Component attached to your GameState. This ensures the system is accessible on both Server and Clients. 1. Open your project's \*\*\`GameState\`\*\* (or create one if you haven't already).
2. In the \*\*Components\*\* panel (top left), click \*\*+ Add\*\*. \\ 3. Search for \*\*\`BPC\_SimpleEventSystem\`\*\* and add it. \\ 4. \*\*Compile and Save\*\*. {% hint style="success" %} \*\*Success:\*\* The system is now initialized! You can access it via the helper nodes. {% endhint %} --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event.md). # Receiving & Subscribing To listen for events broadcasted on the event bus, use the \*\*Subscribe to Event\*\* node. \*\*\* ### Step 1: Add the Subscribe Node 1. Open the Blueprint that needs to listen for an event (e.g., your HUD Widget or Enemy AI Controller). 2. Right-click on the graph canvas and search for \*\*"Subscribe to Event"\*\* (category \`UES\`). 3. Place the node in an initialization flow, such as \*\*Event BeginPlay\*\* or \*\*Event Construct\*\*. \*\*\* ### Step 2: Set Target Tag and Callback 1. Select the \*\*Event Tag\*\* you wish to listen for (e.g. \`Game.Player.ScoreChanged\`). 2. Create or delegate a Custom Event or matching function: \* Drag off the \*\*Event\*\* delegate pin on \`Subscribe to Event\` and choose \*\*Add Custom Event\*\*. \* Name your custom event (e.g., \`OnPlayerScoreChanged\`). The callback event receives two parameters: \* \*\*Event Tag\*\* (\`FGameplayTag\`) β€” The exact tag that triggered the event. \* \*\*Payload\*\* (\`FInstancedStruct\`) β€” The generic wildcard data container. \*\*\* ### Step 3: Store the Binding Handle The \`Subscribe to Event\` node returns a handle of type \*\*\`FUltimateEventBindingHandle\`\*\*: {% hint style="warning" %} \*\*Important Practice:\*\* Always store the returned \`Binding Handle\` in a Blueprint variable if you intend to manually unsubscribe later during gameplay. {% endhint %} 1. Drag off the \*\*Return Value\*\* (Binding Handle) pin. 2. Select \*\*Promote to Variable\*\*. 3. Name it (e.g., \`ScoreEventHandle\`). \*\*\* ### Step 4: Unpacking Received Data To extract data from the incoming \`Payload\` parameter inside your Custom Event: 1. Drag off the \*\*Payload\*\* pin. 2. Search for \*\*"Get Instanced Struct Value"\*\* (or use \*\*Switch on Payload Type\*\* for multi-type handling). 3. Connect the output to your target struct type or primitive. --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy.md). # Tag Hierarchy & Filtering \*\*Ultimate Event System\*\* leverages native Unreal Engine \*\*Gameplay Tags\*\* (\`FGameplayTag\`) to categorize and route events. Gameplay Tags inherently support dot-separated hierarchical relationships. \*\*\* ### Hierarchical Topic Example Consider a hierarchy of event tags defined in your project: \`\`\` Game/ └── Event/ └── UI/ β”œβ”€β”€ HUD/ β”‚ β”œβ”€β”€ HealthChanged β”‚ └── ManaChanged └── Inventory/ └── ItemAdded \`\`\` \* \`Game.Event.UI.HUD.HealthChanged\` is a leaf tag. \* \`Game.Event.UI.HUD\` is its direct parent. \* \`Game.Event.UI\` is an ancestor tag. \*\*\* ### Exact Matching vs. Parent Tag Propagation When broadcasting an event via \`Send Event\`, the \`Trigger Parent Subscriptions\` boolean (\`bTriggerParentSubscriptions\`) controls how the event traverses the registry: | Mode | \`bTriggerParentSubscriptions\` | Behavior | | ------------------ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | \*\*Exact Mode\*\* | \`False\` | Only subscribers listening explicitly to \`Game.Event.UI.HUD.HealthChanged\` receive the event. | | \*\*Inclusive Mode\*\* | \`True\` | Subscribers to \`Game.Event.UI.HUD.HealthChanged\`, \`Game.Event.UI.HUD\`, \`Game.Event.UI\`, and \`Game.Event\` ALL receive the event. | \*\*\* ### Architectural Use Cases #### 1. Centralized Logging & Analytics Create a global manager subscriber listening to the parent tag \`Game.Event\`. Set \`bTriggerParentSubscriptions = True\` on all game events. The analytics manager automatically captures all child events across the system without individual setup! #### 2. Sub-System HUD Listeners A HUD Widget can subscribe to \`Game.Event.UI.HUD\`. Whenever any specific HUD event (\`HealthChanged\`, \`ManaChanged\`, \`StaminaChanged\`) fires with parent propagation, the widget receives the notification, inspects the incoming \`Event Tag\` parameter, and updates the display accordingly. {% hint style="info" %} \*\*Original Tag Preserved:\*\* When parent listeners receive a propagated event, the \`Event Tag\` delegate parameter always carries the \*\*original leaf tag\*\* that fired the event, allowing listeners to identify the exact source event. {% endhint %} --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing.md). # Unsubscribing & Lifecycle Properly managing event subscriptions ensures clean object lifecycles and prevents unexpected callbacks during game transitions. \*\*\* ### Unsubscribing by Binding Handle When you call \`Subscribe to Event\`, it returns a lightweight, unique handle of type \*\*\`FUltimateEventBindingHandle\`\*\*. To unsubscribe a specific listener: 1. Call the \*\*Unsubscribe from Event\*\* node (category \`UES\`). 2. Pass the saved \`Binding Handle\`. 3. The event bus immediately removes the subscription record. \`\`\` \[Subscribe to Event\] ──(Return Value)──> \[Store Variable: Handle\] β”‚ \[Unsubscribe from Event\] <──(Handle)β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ \`\`\` \*\*\* ### Unsubscribing All Events for an Object If an Actor or Component subscribes to multiple event tags, you can unhook all of its active bindings at once: 1. Call \*\*Unsubscribe from All Events\*\* (category \`UES\`). 2. Pass the \`Target Object\` (or \`Self\`). 3. All handles associated with that subscriber instance are invalidated instantly. {% hint style="info" %} \*\*Best Practice:\*\* Call \`Unsubscribe from All Events\` inside an Actor's \*\*Event EndPlay\*\* or a Widget's \*\*Destruct\*\* event to ensure complete cleanup when assets leave the world. {% endhint %} \*\*\* ### Garbage Collection Protection What happens if an Actor is destroyed without explicitly unsubscribing? UES is designed with \*\*automatic Garbage Collection safety\*\*: \* Subscriptions \*\*do not\*\* hold strong references (\`UProperty\`) to subscribers. Subscriber identities are stored using weak \`FObjectKey\` handles. \* Prior to executing any callback delegate during broadcast, UES checks if the subscriber is valid (\`IsValid()\`). \* If a subscriber was destroyed or garbage collected, UES skips invocation automatically. \* Stale entries are periodically pruned from memory by a background cleanup timer (\`CleanupStaleSubscriptions\`). {% hint style="success" %} \*\*No Crashes or Memory Leaks:\*\* Destroyed objects will never cause dangling pointer crashes or prevent Garbage Collection! {% endhint %} --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/best-practices.md). # Best Practices To get the most out of \*\*Ultimate Event System\*\*, follow these architectural recommendations for structuring events, managing lifecycles, and keeping performance optimal. \*\*\* ### 1. Gameplay Tag Naming Conventions Use a clear, standard dot-separated taxonomy for all event tags in \`DefaultGameplayTags.ini\`: \`\`\` Domain . Category . Action / EventName \`\`\` #### Good Examples: \* \`Game.Player.HealthChanged\` \* \`UI.HUD.InventoryOpened\` \* \`Weapon.Rifle.Fired\` \* \`Quest.Chapter1.ObjectiveCompleted\` #### Avoid: \* Flat tag names without category hierarchy (e.g., \`HealthEvent\`). \* Overly generic names (e.g., \`Update\`). \*\*\* ### 2. Payload Struct Organization \* \*\*Group related variables:\*\* Create dedicated Blueprint/C++ payload structs (e.g. \`FDamageEventPayload\`) rather than passing multiple loose events. \* \*\*Use primitive wrappers for simple signals:\*\* When passing a single scalar (like score count or sound ID), leverage primitive wrappers like \`FUltimateIntPayload\` or \`FUltimateNamePayload\` instead of creating single-variable structs. \*\*\* ### 3. Explicit Lifecycle Cleanup Although UES automatically skips destroyed subscribers via weak reference checks, \*\*always call \`Unsubscribe from All Events\` in \`EndPlay\` / \`Destruct\`\*\*: \`\`\` \[Event EndPlay\] ───> \[Unsubscribe from All Events (Target: Self)\] \`\`\` Explicit cleanup reduces registry overhead immediately without waiting for the periodic GC pruning timer. \*\*\* ### 4. Prefer Subsystems over Global Managers \* Subscribe to global events inside \`UGameInstanceSubsystem\` or \`UWorldSubsystem\` classes when managing cross-level game state. \* Subsystems are automatically managed by Unreal Engine and persistent across level travel. \*\*\* ### 5. Performance Optimization \* \*\*Avoid heavy allocation loops inside event handlers:\*\* Handlers should perform lightweight state updates or trigger async tasks. \* \*\*Use \`bTriggerParentSubscriptions = True\` intentionally:\*\* Enable parent tag propagation only when parent listeners actually exist (e.g. centralized UI or logging managers) to keep traversal paths minimal. --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging.md). # Debugging & Tools \*\*Ultimate Event System\*\* includes a comprehensive suite of debugging tools to inspect event traffic, monitor active subscriptions, and diagnose gameplay issues in real time. \*\*\* ### Console Commands Open the in-game console (tilde \`~\` key during PIE or Standalone) to execute UES commands: | Console Command | Description | | ----------------------- | ----------------------------------------------------------------------------------------------------- | | \`UES.ListSubscriptions\` | Dumps all currently registered event topics, subscriber count, and binding handles to the output log. | | \`UES.LogEvents \[0/1\]\` | Toggles real-time console logging for every event broadcast on the bus. | | \`UES.ToggleHUD\` | Toggles an interactive Slate HUD overlay on screen showing live event statistics and throughput. | | \`UES.Prune\` | Forces an immediate manual garbage-collection sweep of stale handles in the subscription registry. | \*\*\* ### Visual Logger (VLog) Integration UES records event dispatches directly into Unreal Engine's \*\*Visual Logger\*\*: 1. In Editor, open \*\*Tools -> Debug -> Visual Logger\*\*. 2. Start recording during gameplay. 3. Select any Actor in the log timeline to see all UES events dispatched or received by that specific Actor instance, complete with payload type details. \*\*\* ### In-Engine Subsystem Metrics You can query subsystem state at runtime via Blueprint or C++: \* \*\*\`GetActiveSubscriptionCount()\`\*\*: Returns total active subscriber bindings. \* \*\*\`GetTotalEventsDispatched()\`\*\*: Returns total count of events fired since game session startup. \*\*\* ### Safe Re-entrancy Guarantee UES is built with safe \*\*re-entrancy support\*\*: \* If a subscriber callback triggers a nested \`Send Event\` or calls \`Unsubscribe\`, the registry safely queues modification operations until the outermost broadcast unwinds. \* Callback execution order remains deterministic, avoiding iterator corruption or array re-allocation crashes. --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/installation.md). # Installation & Setup Setting up \*\*Ultimate Event System (UES)\*\* in your Unreal Engine 5 project is quick and straightforward. \*\*\* ### Step 1: Install the Plugin 1. Clone or copy the \`UltimateEventSystem\` plugin folder into your project's \`Plugins/\` directory: \`\`\` YourProject/ └── Plugins/ └── UltimateEventSystem/ \`\`\` 2. Regenerate project files and open your \`.uproject\` solution. 3. In Unreal Editor, go to \*\*Edit -> Plugins\*\*, search for \*\*Ultimate Event System\*\*, and ensure it is checked \*\*Enabled\*\*. \*\*\* ### Step 2: Configure Dependencies (UE 5.3 / 5.4) If your project runs on Unreal Engine \*\*5.3\*\* or \*\*5.4\*\*, make sure the \*\*Struct Utils\*\* plugin is enabled: 1. Open \*\*Edit -> Plugins\*\*. 2. Search for \*\*Struct Utils\*\*. 3. Enable the plugin and restart the editor when prompted. {% hint style="info" %} \*\*UE 5.5+ Notice:\*\* In Unreal Engine 5.5 and later, \`StructUtils\` is integrated directly into CoreEngine, so no extra plugin toggling is required. {% endhint %} \*\*\* ### Step 3: C++ Module Dependency (Optional for C++ Projects) If you plan to interact with UES directly from C++, add \`UltimateEventSystem\` to your project's \`.Build.cs\` file: \`\`\`csharp public class MyGameProject : ModuleRules { public MyGameProject(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange(new string\[\] { "Core", "CoreUObject", "Engine", "GameplayTags", "StructUtils", "UltimateEventSystem" // <--- Add this line }); } } \`\`\` Include the main subsystem header wherever needed: \`\`\`cpp #include "Subsystem/UltimateSubsystem.h" \`\`\` \*\*\* ### Step 4: Setup Gameplay Tags UES uses \*\*Gameplay Tags\*\* as event topics. You can manage tags in \*\*Project Settings -> Gameplay Tags\*\* or add them dynamically via the tag editor dropdown in Blueprints. --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/quickstart.md). # quickstart - \[Receiving & Subscribing\](https://asperazera.gitbook.io/ultimate-event-system/quickstart/receive-event.md) - \[Sending Events\](https://asperazera.gitbook.io/ultimate-event-system/quickstart/send-event.md) --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/simple-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event.md). # Send Event The \*\*Send Event\*\* node is the primary way to broadcast a message. \*\*\* ### Step 1: Add the Node Open any Blueprint (Actor, Widget, GameInstance, etc.) where you want to trigger an event. 1. Right-click on the graph. 2. Search for \*\*"Send Event"\*\*. 3. Select the function under the \*\*Simple Event System\*\* category.
\*\*\* ### Step 2: Define the Event Tag Events in \*\*Simple Event System\*\* are identified by \*\*Gameplay Tags\*\*. {% hint style="info" %} \*\*Tip:\*\* You don't need to define them in Project Settings beforehand; you can create them on the fly. {% endhint %}
1. Click the \*\*Event Tag\*\* dropdown on the node. 2. Click \*\*Plus\*\* Icon. 3. Type the name of your event (e.g., \`TriggerOverlap.Start\`). 4. Select \*\*Source\*\* as \`DefaultGameplayTags.ini\`. 5. Click \*\*Add New Tag\*\* to save it.
\*\*\* ### Step 3: Select the Tag Once added, ensure the tag is selected in the dropdown. Your node is now ready to fire!
--- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/readme.md). # Introduction \*\*Ultimate Event System (UES)\*\* is a high-performance, decoupled \*\*Event Broker\*\* plugin for Unreal Engine 5. It is designed to replace hard references and complex interface casting with a clean, topic-based \*\*Publisher-Subscriber architecture\*\*. > \*\*TL;DR:\*\* UES allows any Actor, Component, Widget, or Subsystem to broadcast "Event X happened" with optional wildcard data (Payloads) without needing to know who is listening. \*\*\* ### Why use Ultimate Event System? \* \*\*Complete Decoupling:\*\* Eliminates hard object references, \`Cast To\` nodes, and direct interface bindings between actors. \* \*\*Hierarchical Topics (Gameplay Tags):\*\* Uses native \`FGameplayTag\` hierarchies (e.g. \`Event.Player.Health.Changed\`) for organized event filtering and parent-tag propagation. \* \*\*Wildcard Payloads (\`FInstancedStruct\`):\*\* Send primitives, custom structures, or \`UObject\` references safely without blueprint casting headaches. \* \*\*Specialized K2 Nodes:\*\* Includes powerful Blueprint compiler nodes like \*\*Switch on Payload Type\*\* for type-safe branching and custom wildcard payload nodes. \* \*\*C++ & Blueprint Parity:\*\* Built on top of \`UGameInstanceSubsystem\` (\`UUltimateSubsystem\`), providing 100% feature parity in both C++ and Blueprints. \* \*\*Memory Safety & Automatic GC Protection:\*\* Subscriber references are tracked using weak keys (\`FObjectKey\`), preventing dangling subscriptions and memory leaks when actors are destroyed. \* \*\*Built-in Debug Tooling:\*\* Comes with Visual Logger (VLog) integration, console commands, and real-time screen HUD overlays. \*\*\* ### Technical Requirements | Requirement | Details | | ------------------ | ---------------------------------------------- | | \*\*Engine Version\*\* | Unreal Engine 5.3+ | | \*\*Dependencies\*\* | StructUtils (Enabled by default in UE 5.3+) | | \*\*Language\*\* | C++ Engine Plugin with full Blueprint Exposure | {% hint style="info" %} \*\*Note:\*\* Ultimate Event System requires \*\*Unreal Engine 5.3 or higher\*\* due to its core reliance on \`FInstancedStruct\` features from the engine's \`StructUtils\` module. {% endhint %} {% hint style="warning" %} \*\*Dependency Requirement for UE 5.3 and 5.4\*\* Please ensure the \*\*Struct Utils\*\* plugin is enabled in your \`.uproject\` file. In \*\*UE 5.5+\*\*, \`StructUtils\` became part of the core engine module and does not require explicit plugin activation. {% endhint %} --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/simple-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event.md). # Receive Event To react to an event (like opening a door, updating UI, or playing a sound), you need to \*\*Subscribe\*\* (Bind) to the Simple Event System. > πŸ“ \*\*Where to put this?\*\*\\ > The best place to bind events is usually inside \*\*Event BeginPlay\*\* (for Actors) or \*\*Event OnInitialized\*\* (for Widgets). \*\*\* ### Step 1: Get the System First, we need to get a reference to the system component. 1. Right-click on your graph. 2. Search for \*\*Get Simple Event System\*\*. 3. Place node on the graph.
\*\*\* ### Step 2: Assign the Dispatcher Now, we bind a custom event to the system's dispatcher. 1. Drag off the blue return pin from Get Simple Event System. 2. Search for \*\*"Assign Event System Dispatcher"\*\*. 3. This will create two nodes: \* \`Bind Event to Event System Dispatcher\` (The subscription). \* \`Custom Event\` (Where your logic goes). {% hint style="info" %} \*\*Tip:\*\* You can use \`Create Event\` node to bind separate \*\*Function\*\* instead of \`Custom Event\`. {% endhint %}
\*\*\* ### Step 3: Set the Tag Switch By default, you will hear \*\*every single event\*\* in the game. You probably don't want that. 1. Locate the \*\*Event Tag\*\* input on the \`Bind Event\` node. 2. Get the \`Switch on Gameplay Tag\` node.
In the Details panel of Switch node select the specific \*\*Gameplay Tag\*\* you want to listen for (e.g., \`TriggerOverlap.Start\`).
\*\*\* ### Step 4: Handle the Logic Now, connect your \`Bind Event\` node to \`BeginPlay\`.\\ Then, add your game logic to the \`Custom Event\` node. \*\*Example:\*\* \* \*\*Event:\*\* TriggerOverlap.Start \* \*\*Logic:\*\* Print String "Hello World".
--- # Send Event | Simple Event System For the complete documentation index, see [llms.txt](https://asperazera.gitbook.io/simple-event-system/llms.txt) . This page is also available as [Markdown](https://asperazera.gitbook.io/simple-event-system/quickstart/send-event.md) . The **Send Event** node is the primary way to broadcast a message. * * * ### Step 1: Add the Node[](https://asperazera.gitbook.io/simple-event-system/quickstart#step-1-add-the-node) Open any Blueprint (Actor, Widget, GameInstance, etc.) where you want to trigger an event. 1. Right-click on the graph. 2. Search for **"Send Event"**. 3. Select the function under the **Simple Event System** category. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252F38CzpttNNCxo8pnQd5BZ%252Fimage.png%3Falt%3Dmedia%26token%3D76b7573f-d620-4305-92f5-3bb37fb61361&width=768&dpr=3&quality=100&sign=dee57f0b&sv=2) * * * ### Step 2: Define the Event Tag[](https://asperazera.gitbook.io/simple-event-system/quickstart#step-2-define-the-event-tag) Events in **Simple Event System** are identified by **Gameplay Tags**. **Tip:** You don't need to define them in Project Settings beforehand; you can create them on the fly. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FTujUj9Iojr9oeFMpzWNd%252Fimage.png%3Falt%3Dmedia%26token%3Dbf8c522f-0475-4445-b88c-470b7d240710&width=768&dpr=3&quality=100&sign=5c5fd5da&sv=2) 1. Click the **Event Tag** dropdown on the node. 2. Click **Plus** Icon. 3. Type the name of your event (e.g., `TriggerOverlap.Start`). 4. Select **Source** as `DefaultGameplayTags.ini`. 5. Click **Add New Tag** to save it. ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FQtKzjYG0cbwybtYyYNjP%252Fimage.png%3Falt%3Dmedia%26token%3De79e5b04-65e9-4447-878d-6db4af00d78e&width=768&dpr=3&quality=100&sign=9b97c507&sv=2) * * * ### Step 3: Select the Tag[](https://asperazera.gitbook.io/simple-event-system/quickstart#step-3-select-the-tag) Once added, ensure the tag is selected in the dropdown. Your node is now ready to fire! ![](https://asperazera.gitbook.io/simple-event-system/~gitbook/image?url=https%3A%2F%2F1432079579-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252Fxq5kDQD48YjjknWBHyrp%252Fuploads%252FdNqEQZGF8MxYLWyH4bT1%252Fimage.png%3Falt%3Dmedia%26token%3D523ff738-703b-464f-bfa2-9d6b65427963&width=768&dpr=3&quality=100&sign=630f5c9f&sv=2) [PreviousInstallation](https://asperazera.gitbook.io/simple-event-system/installation) [NextReceive Event](https://asperazera.gitbook.io/simple-event-system/quickstart/receive-event) Last updated 7 months ago --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide.md). # C++ Developer Guide \*\*Ultimate Event System\*\* provides full C++ API parity. The system is managed by \`UUltimateSubsystem\`, which inherits from \`UGameInstanceSubsystem\`. \*\*\* ### Accessing the Subsystem Obtain the subsystem instance from any Game Thread context (e.g. \`AActor\`, \`UActorComponent\`, \`UWorld\`): \`\`\`cpp #include "Subsystem/UltimateSubsystem.h" // Inside an AActor method: if (UGameInstance\* GI = GetGameInstance()) { UUltimateSubsystem\* EventSubsystem = GI->GetSubsystem(); if (EventSubsystem) { // Use subsystem API } } \`\`\` \*\*\* ### Broadcasting Events in C++ Use \`FInstancedStruct::Make(...)\` to package C++ structures into wildcard payloads. #### Example: Broadcasting a Custom Struct \`\`\`cpp #include "Subsystem/UltimateSubsystem.h" #include "StructUtils/InstancedStruct.h" // Define a custom payload struct USTRUCT(BlueprintType) FMyScorePayload { GENERATED\_BODY() UPROPERTY(BlueprintReadWrite) int32 Score = 0; UPROPERTY(BlueprintReadWrite) FString PlayerName; }; // Broadcasting the event: FGameplayTag EventTag = FGameplayTag::RequestGameplayTag(FName("Game.Player.ScoreChanged")); FMyScorePayload Data; Data.Score = 150; Data.PlayerName = TEXT("Alice"); FInstancedStruct Payload = FInstancedStruct::Make(Data); // Broadcast (with parent propagation set to false) EventSubsystem->SendEvent(EventTag, Payload, false); \`\`\` \*\*\* ### Subscribing to Events in C++ Subscribe using native C++ delegates (\`FUltimateEventDelegate\`): \`\`\`cpp // 1. Declare your handler function in your class header: void AMyCharacter::OnScoreChanged(FGameplayTag EventTag, const FInstancedStruct& Payload) { if (const FMyScorePayload\* Data = Payload.GetPtr()) { UE\_LOG(LogTemp, Log, TEXT("Score updated to %d for %s"), Data->Score, \*Data->PlayerName); } } // 2. Register subscription in BeginPlay: FGameplayTag TargetTag = FGameplayTag::RequestGameplayTag(FName("Game.Player.ScoreChanged")); FUltimateEventDelegate Delegate; Delegate.BindUObject(this, &AMyCharacter::OnScoreChanged); FUltimateEventBindingHandle BindingHandle = EventSubsystem->SubscribeToEvent(TargetTag, Delegate); \`\`\` \*\*\* ### Unsubscribing in C++ Unsubscribe in \`EndPlay\` or \`BeginDestroy\`: \`\`\`cpp void AMyCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason) { if (UGameInstance\* GI = GetGameInstance()) { if (UUltimateSubsystem\* EventSubsystem = GI->GetSubsystem()) { // Unsubscribe single handle: EventSubsystem->UnsubscribeFromEvent(BindingHandle); // Or unsubscribe all events registered for this object instance: EventSubsystem->UnsubscribeFromAllEvents(this); } } Super::EndPlay(EndPlayReason); } \`\`\` {% hint style="warning" %} \*\*Thread Safety Requirement:\*\* All subsystem operations (subscribing, broadcasting, unsubscribing) must strictly execute on the \*\*Game Thread\*\* (\`check(IsInGameThread())\`). {% endhint %} --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://asperazera.gitbook.io/ultimate-event-system/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://asperazera.gitbook.io/ultimate-event-system/advanced.md). # advanced - \[C++ Developer Guide\](https://asperazera.gitbook.io/ultimate-event-system/advanced/cpp-guide.md) - \[Debugging & Tools\](https://asperazera.gitbook.io/ultimate-event-system/advanced/debugging.md) - \[Working with Payloads\](https://asperazera.gitbook.io/ultimate-event-system/advanced/payloads.md) - \[Switch on Payload Type\](https://asperazera.gitbook.io/ultimate-event-system/advanced/switch-on-payload.md) - \[Tag Hierarchy & Filtering\](https://asperazera.gitbook.io/ultimate-event-system/advanced/tag-hierarchy.md) - \[Unsubscribing & Lifecycle\](https://asperazera.gitbook.io/ultimate-event-system/advanced/unsubscribing.md) ---