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:
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;
- 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.
- 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.