Created
August 9, 2020 02:59
-
-
Save wesleywh/1c56d880c0289371ea2dc47661a0cdaf to your computer and use it in GitHub Desktop.
This will copy UnityEvents from one UnityEvent to Another. It should copy all the settings exactly as is. Tested on Unity2018.4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void CopyUnityEvents(object sourceObj, string source_UnityEvent, object dest, bool debug = false) | |
{ | |
FieldInfo unityEvent = sourceObj.GetType().GetField(source_UnityEvent, E_Helpers.allBindings); | |
if (unityEvent.FieldType != dest.GetType()) | |
{ | |
if (debug == true) | |
{ | |
Debug.Log("Source Type: " + unityEvent.FieldType); | |
Debug.Log("Dest Type: " + dest.GetType()); | |
Debug.Log("CopyUnityEvents - Source & Dest types don't match, exiting."); | |
} | |
return; | |
} | |
else | |
{ | |
SerializedObject so = new SerializedObject((Object)sourceObj); | |
SerializedProperty persistentCalls = so.FindProperty(source_UnityEvent).FindPropertyRelative("m_PersistentCalls.m_Calls"); | |
for (int i = 0; i < persistentCalls.arraySize; ++i) | |
{ | |
Object target = persistentCalls.GetArrayElementAtIndex(i).FindPropertyRelative("m_Target").objectReferenceValue; | |
string methodName = persistentCalls.GetArrayElementAtIndex(i).FindPropertyRelative("m_MethodName").stringValue; | |
MethodInfo method = null; | |
try | |
{ | |
method = target.GetType().GetMethod(methodName, E_Helpers.allBindings); | |
} | |
catch | |
{ | |
foreach (MethodInfo info in target.GetType().GetMethods(E_Helpers.allBindings).Where(x => x.Name == methodName)) | |
{ | |
ParameterInfo[] _params = info.GetParameters(); | |
if (_params.Length < 2) | |
{ | |
method = info; | |
} | |
} | |
} | |
ParameterInfo[] parameters = method.GetParameters(); | |
switch(parameters[0].ParameterType.Name) | |
{ | |
case nameof(System.Boolean): | |
bool bool_value = persistentCalls.GetArrayElementAtIndex(i).FindPropertyRelative("m_Arguments.m_BoolArgument").boolValue; | |
var bool_execute = System.Delegate.CreateDelegate(typeof(UnityAction<bool>), target, methodName) as UnityAction<bool>; | |
UnityEventTools.AddBoolPersistentListener( | |
dest as UnityEventBase, | |
bool_execute, | |
bool_value | |
); | |
break; | |
case nameof(System.Int32): | |
int int_value = persistentCalls.GetArrayElementAtIndex(i).FindPropertyRelative("m_Arguments.m_IntArgument").intValue; | |
var int_execute = System.Delegate.CreateDelegate(typeof(UnityAction<int>), target, methodName) as UnityAction<int>; | |
UnityEventTools.AddIntPersistentListener( | |
dest as UnityEventBase, | |
int_execute, | |
int_value | |
); | |
break; | |
case nameof(System.Single): | |
float float_value = persistentCalls.GetArrayElementAtIndex(i).FindPropertyRelative("m_Arguments.m_FloatArgument").floatValue; | |
var float_execute = System.Delegate.CreateDelegate(typeof(UnityAction<float>), target, methodName) as UnityAction<float>; | |
UnityEventTools.AddFloatPersistentListener( | |
dest as UnityEventBase, | |
float_execute, | |
float_value | |
); | |
break; | |
case nameof(System.String): | |
string str_value = persistentCalls.GetArrayElementAtIndex(i).FindPropertyRelative("m_Arguments.m_StringArgument").stringValue; | |
var str_execute = System.Delegate.CreateDelegate(typeof(UnityAction<string>), target, methodName) as UnityAction<string>; | |
UnityEventTools.AddStringPersistentListener( | |
dest as UnityEventBase, | |
str_execute, | |
str_value | |
); | |
break; | |
case nameof(System.Object): | |
Object obj_value = persistentCalls.GetArrayElementAtIndex(i).FindPropertyRelative("m_Arguments.m_ObjectArgument").objectReferenceValue; | |
var obj_execute = System.Delegate.CreateDelegate(typeof(UnityAction<Object>), target, methodName) as UnityAction<Object>; | |
UnityEventTools.AddObjectPersistentListener( | |
dest as UnityEventBase, | |
obj_execute, | |
obj_value | |
); | |
break; | |
default: | |
var void_execute = System.Delegate.CreateDelegate(typeof(UnityAction), target, methodName) as UnityAction; | |
UnityEventTools.AddPersistentListener( | |
dest as UnityEvent, | |
void_execute | |
); | |
break; | |
} | |
} | |
} | |
} |
The issue with removing the old calls came about when the source and destination were equal. Hence, this is the modification:
if (!dryRun)
{
if (removeOldCalls && (dstCalls.arraySize > 0))
{
srcCalls.ClearArray();
}
src.ApplyModifiedProperties();
if (source != destination)
{
dst.ApplyModifiedProperties();
}
}
@Vivraan @wesleywh
It not works with custom MonoBehaviour targets.
Reason: you make cast directly into UnityAction<Object>
, but target f.e MyTestScript it's a UnityAction<MyTestScript>
. When I run your code, i get execption, invalid cast.
My solutuion, works with everything:
default:
Object obj_value = persistentCalls.GetArrayElementAtIndex(i).FindPropertyRelative("m_Arguments.m_ObjectArgument").objectReferenceValue;
var obj_execute = System.Delegate.CreateDelegate(typeof(UnityAction<>).MakeGenericType(obj_value.GetType()), target,
methodName);
var info = typeof(UnityEventTools).GetMethod(
nameof(UnityEventTools.AddObjectPersistentListener));
var genericMethod = info.MakeGenericMethod(obj_value.GetType());
genericMethod.Invoke(null, new object[] { dest, obj_execute, obj_value });
break;
Hope i helps somybody :)
UPD: I think we may don't use switch. Just UnityEventTools.AddPersistentListener
and cast args with reflection by my way. We can pack all your switch into few lines of code 💯
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Okay so here's the version which incorporates all that but does away with removing the old calls because it would remove everything without copying the calls otherwise. It's trivial to delete events anyway.