Home > OS >  UnityEventTools AddPersistantListener With Dynamic Type
UnityEventTools AddPersistantListener With Dynamic Type

Time:07-28

Sorry if the following is confusing...

QUESTION:

How do I go about adding a new persistent unity event action to a UnityEvent from a generic type with a dynamic entry?

EXAMPLES:

I have the following function:

public static void SetUnityEvent<T>(T targetEvent, UnityEventEntry entry) where T : UnityEventBase
{
  ...
}

and inside that function from the UnityEventEntry object I'm trying to add a new action to the UnityEvent but I'm not sure how to do that with a dynamic type:

UnityEventTools.AddObjectPersistentListener(
   targetEvent,
   unityaction,
   <what do I add here>
);

This may not be the right thing to do at all. However, this is what I mean by a dynamic parameter:

enter image description here

How would I add a new action item into a UnityEvent that is including that dynamic parameter?

Any help would be greatly appreciated.

HOW I'M CURRENT WRITING IT:

public static void SetUnityEvent<T>(T targetEvent, UnityEventEntry entry) where T : UnityEventBase
{
    UnityAction void_execute = (UnityAction)Delegate.CreateDelegate(typeof(UnityAction), entry.component, entry.function);
    UnityEventTools.AddObjectPersistentListener(
       targetEvent,
       void_execute,
       <What do i add>?
    );
}

IMPORTANT NOTE:

If I write it like:

UnityEventTools.AddVoidPersistentListener(
                    targetEvent,
                    void_execute
                );

That will work, but that's for voids and will not include that dynamic parameter. Not sure how else to do it.

Also trying to add it like:

UnityEventTools.AddPersistentListener(
  targetEvent as UnityEvent,
  void_execute
);

Will result in targetEvent being a null.

CodePudding user response:

I got it! Only 2 weeks worth of digging and coding to get up to this point. Simple when you think about it but hard when this is 100% undocumented anywhere on the web it seems like.

Here is what you want to do.

NOTE: The following will be defined like the following:

target = GameObject target of the same component you're putting this event on
targetComponent = The Component you're putting this event on
unityEventName = The name of the UnityEvent on the "targetComponent"

My script also takes advantage of the entry item which is a class that is initialized like the following:

public GameObject target = null;
public Component component = null;
public MethodInfo function = null;
public object parameter = null;
public int callState = -1;
public PersistentListenerMode mode = PersistentListenerMode.Void;
  1. Setup a "dummy" event like the following:
MethodInfo tmpFunc = GetMethodInfo(target, "SetActive", PersistentListenerMode.Bool);
UnityAction<bool> tmp_event_execute = System.Delegate.CreateDelegate(typeof(UnityAction<bool>), entry.target, tmpFunc) as UnityAction<bool>;
UnityEventTools.AddBoolPersistentListener(
    targetEvent,
    tmp_event_execute,
    false
);

This can be any event, it doesn't matter. I just use SetActive with the GameObject because it seems to be a universal thing you can do with anything.

  1. Modify that "dummy" listener entry using SerializedProperties:
// Get the listener entry to modify
SerializedObject so = new SerializedObject(targetComponent);
SerializedProperty persistentCalls = so.FindProperty(unityEventName).FindPropertyRelative("m_PersistentCalls.m_Calls");
SerializedProperty listenerEntry = persistantCalls.GetArrayElementAtIndex(persistantCalls.arraySize - 1);

// Get the individual items on that listener entry
SerializedProperty listener_Target = listenerEntry.FindPropertyRelative("m_Target");
SerializedProperty listener_CallState = listenerEntry.FindPropertyRelative("m_CallState");
SerializedProperty listener_FunctionName = listenerEntry.FindPropertyRelative("m_MethodName");
SerializedProperty listener_Mode = listenerEntry.FindPropertyRelative("m_Mode");
SerializedProperty listener_Arg = listenerEntry.FindPropertyRelative("m_Arguments");

// Modify the entry with the new target values (Notice for dynamic events I don't include an argument/parameter)
listener_Target.objectReferenceValue = (entry.component == null) ? entry.target : (UnityEngine.Object)entry.component;
listener_FunctionName.stringValue = entry.function.Name;
listener_Mode.enumValueIndex = (int)entry.mode;

listenerEntry.serializedObject.ApplyModifiedProperties();

Then boom! After doing that you now have an added persistant listener with a dynamic variable included all done via an Editor script. Also because you modify the "dummy" listener in place there is nothing to cleanup afterwards.

  • Related