Class-independent event dispatcher?

Event dispatchers are essential for an event-driven approach, but their dependency on classes can sometimes be quite difficult to use. Is there an event dispatcher that is implemented like an interface and can be used by all classes?
In principle, I think it’s the same as an interface. But, instead of being actively executed like an event, they are passively executed by being tied to an event.

you can do this in c++ the trick is you need to know the signature

or you can use an actor component/manager class as proxy, its still a hard ref but to a lightweight class

or finally check out the GameplayMessageSubsystem

2 Likes

Gameplay Message Subsystem is interesting. If I had known about it sooner, I would have incorporated it into the entire system, but unfortunately, development was already quite advanced.
I’m worried about the limited search results, but I’ll dig a little deeper and see if I can use it partially.

For now, the best solution might be to use the Actor component. However, it still seems like it would be a lot of work to have a single component recognize completely different classes.

the component doesn’t need to, its just a proxy.

So the owner calls an event on the component, lets say HealthChanged, and a widget can bind to the component without knowing about the owner.

or you can call GenericEvents with GameplayTags.

you can make GenericEvents with payloads (UObject or FInstancedStruct) for dynamic data

Even if i use it as a proxy, don’t you still need to make the component aware of the actor? All information still resides with the actor.
If i implement all shared variables in the component, it is possible to cut off the owner and external references. But that would mean rethinking the design from the ground up.

I don’t know about Generic Events. Is this possible to do in blueprint? There are many interesting features, but BP seems to have been put on the back burner.

not exactly, the actor is the ‘Owner’ so you have a ref to it but its generic so not a hard ref

this means you could GetOwner()→UseInterface/Cast but that kinda defeats the purpose, usually youd just pass through whatever info on the dispatcher itself, so OnHealthChanged passes through a float.

you can create one, so say an event dispatched passes through a Tag and UObject, the Tag describles the payload and then you can SwitchOnTag then cast/interface to get your data from the object

Sorry, this is the first time I’ve heard of these approaches, so I can’t really picture them.

Binding to an event dispatcher requires an explicit reference. But from what you’ve said, does that mean that an actor component can execute actor events without being cast to an actor? I know Owner isn’t a explicit reference, but if it was, it probably wouldn’t be possible to get anything from Actor.

To send variables from an actor through an interface, the actor needs to know the interface holder. If an interface holder issues an event to an actor, it will not be event-driven.

dont worry i went through the same, thats why i came up with these systems.

it can actually, EventDispatchers in an actor component can be bound to by the owner automatically.

But we may not be talking about the same thing. If you just want to call a function then you can use an interface, if you want to listen for an event then use the actorcomponent with an ED

Lot of different people have published something like this. There are quite a few on FAB, there’s the Gameplay Message system from Lyra that Auran mentioned and lots of people have published versions just on GitHub for free. Including me :smiley:

You don’t have to switch your whole game over at one time. You can add an event system, create new things using it and slowly transition other systems over as you do work on them.

2 Likes

I don’t think there’s any point in creating an event dispatcher in a component. The change in the variable occurs within the actor.

Interface functions must be executed by an actor, so the actor needs to know who owns them. This is useful for controllers and game modes that can be retrieved with the Get function, but it is very tedious to retrieve manager actors and UIs that are randomly placed in the world. Also, it won’t be event-driven (this is the most important thing).

Simply, time is tight and there is little room to try new things. But I think this messaging system is definitely something worth considering.

Thanks for the new info, but I was hoping there was a simpler solution…

true but then its class dependent which was the original point

not if its an actor component on say the GameMode, ie GetGameMode()→GetComponentByClass

EventDispatchers are the definition of event driven.

maybe if you give us an example of what you need it for i can explain it better

Specifically, what I need is a unified approach to target handling in missions.

For example, enemy characters and crates to be destroyed are treated as equal targets. The UI display, post-kill process, score management, etc. are all handled in the same way.

To progress through the mission, information such as when a target is found or destroyed must be sent to various locations in an event-driven manner.
However, since characters are derived from Pawn and crates are derived from Actor, they can only share the processes described in Actor.

Using a GameMode or PlayerController as an intermediate step can be difficult to manage. Therefore, I wanted to make it work by just binding what I needed in advance.

this sounds like a job for an actor component for sure. lets say later you add something else you want to fit into the system, just slap the component on it and it works out of the box.

this sounds more like a broadcast system, the component just calls out, im dead and whoever is listening can update. you can use EDs for this but then as you said you need to bind in advance. i think it would be better to have a manager that way the UI can just bind to the manager. the component tells the manager im dead, passing through a ref to owner (if not destroyed) who killed it and any other info.

then all your systems can just bind to the manager, this is kinda what the GameState is designed for, so using that or a component of it gives you an easy medium

For now, i might have to go the classic solution.

I created a manager, but communication with the target is done through an interface, and an index is assigned to each in the order of registration. When it is destroyed, just return the index and it’s done.

Maybe I was thinking a little too hard…

Ah, I found a great solution!

You can’t create a class-independent dispatcher, but you can call a common event from completely different dispatchers.

First, get the manager through the interface and connect the actor-specific dispatcher to the manager’s events. This way, no matter which dispatcher you call, it will be processed as the same event.

Sorry, I will update the solution to this :sweat_smile:
I hope it helps someone.

1 Like