UnityEvent.AddPersistentListener?

Hi,

can we have an UnityEvent.AddPersistantListener?

Alternatively, could UnityEvent.AddListener automatically look whether the Target property of the passed action is an UnityEngine.Object and the Method function is public and then treat the listener as if it was registered in the editor?

At the moment, UnityEvent is only really sensible when used with the editor to attach persistent listener. Listener added via AddListener() method neither show up in the editor nor do they survive an assembly reload during play :frowning:

So basically, UnityEvent is not a good replacement for just an simple “Action” field, except in the case where I assign callbacks in the editor.

I am aware that it is probably a no-go to serialize an arbitrary function from any type. But can’t there be a way to add a function to the persistent list with the same restrictions as you have in the editor?

Ciao, Imi.

TL;DR: “Can we have UnityEventTools.AddPersistentListener() moved to UnityEngine?”

:smile:

So a normal listener does not need to be a serializable type (this is a good thing because they can bind statically or to non UnityEngine.Object types). In these cases we can’t serialize them at all. It makes more sense for us to maybe show a list of ‘runtime’ listeners that are non editable in the inspector. We really want to keep the idea of adding persistent things as an editor concept as serialization ect doesn’t happen when you are playing in a player (saving ect).

“this is a good thing because they can bind statically or to non UnityEngine.Object types”

Yes, this degree of flexibility is extremely valuable a language where you create a new type with some functions with just “x => x*y”.
But in lots of cases, the target just IS a serializable type (or can be very easily refactored into using one).

“We really want to keep the idea of adding persistent things as an editor concept as serialization ect doesn’t happen when you are playing in a player (saving ect).”

With this line of argument, you could make dynamically added entries to a list of strings read-only too or hide them alltogether.

For me as a developer, one of Unitys best things about the editor is, that you can easily inspect and change the “current” state of objects while playing. This is invaluable to reproduce strange bug-situations.

What about “Reload assemblies during play”? Well, TBH it was never a feature that worked for more than just toy example games… But throwing it overboard too easily? If we want our games to be able to survive an assembly reload, we can not use the current UnityEvent’s dynamically.

Is there a tecnical difficulty in doing it like this?

  • When AddListener is called, test whether listener.Target is UnityEngine.Object. If so, add the listener as persistent listener (probably by storing its method name, or however it is handled under-the-hood).
  • If not, so what… its gonna not survive an assembly reload.
  • In the editor, show an greyed-out line for “unknown” listener callbacks.

If you feel good and have some spare hacking time, you could call ToString on the Target of these “unknown” callbacks and remove some Mono-mangling of annonymous types (like stripping the “<>m_this” suffix and stuff).

You could even continue and peel out the this-pointer of anonymous types via reflection and test whether this is an UnityEngine.Object, ONLY to show it in the inspector.

The only thing a user can do with these grayed out lines is to remove them.

Ciao, Imi.

Tim C proposed to:
“[…] maybe show a list of ‘runtime’ listeners that are non editable in the inspector”

This would be really, really great! Did this feature made it to the todo list?