From 41601d6e97390eb1f7cb9442def52cc1a1655679 Mon Sep 17 00:00:00 2001 From: ArjhanToteck <38510221+ArjhanToteck@users.noreply.github.com> Date: Sun, 7 May 2023 21:35:24 -0600 Subject: [PATCH] Put the whole package in a namespace Everything is now inside of a SerializableCallback and a SerializableCallback.Editor namespace --- .vscode/settings.json | 2 + Editor/SerializableCallbackDrawer.cs | 558 +++++++++--------- .../Attributes/TargetConstraintAttribute.cs | 16 +- Runtime/InvokableCallback.cs | 178 +++--- Runtime/InvokableCallbackBase.cs | 6 +- Runtime/InvokableEvent.cs | 152 ++--- Runtime/InvokableEventBase.cs | 6 +- Runtime/SerializableCallback.cs | 164 ++--- Runtime/SerializableCallbackBase.cs | 284 ++++----- Runtime/SerializableEvent.cs | 166 +++--- Runtime/SerializableEventBase.cs | 60 +- Runtime/Test.cs | 128 ++-- 12 files changed, 872 insertions(+), 848 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/Editor/SerializableCallbackDrawer.cs b/Editor/SerializableCallbackDrawer.cs index 561796c..f68d2ce 100644 --- a/Editor/SerializableCallbackDrawer.cs +++ b/Editor/SerializableCallbackDrawer.cs @@ -7,321 +7,323 @@ using UnityEngine; using Object = UnityEngine.Object; -[CustomPropertyDrawer(typeof(TargetConstraintAttribute))] -[CustomPropertyDrawer(typeof(SerializableCallbackBase), true)] -public class SerializableCallbackDrawer : PropertyDrawer { - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - // Without this, you can't edit fields above the SerializedProperty - property.serializedObject.ApplyModifiedProperties(); - - // Indent label - label.text = " " + label.text; - -#if UNITY_2019_1_OR_NEWER - GUI.Box(position, ""); -#else - GUI.Box(position, "", (GUIStyle) - "flow overlay box"); -#endif - position.y += 4; - // Using BeginProperty / EndProperty on the parent property means that - // prefab override logic works on the entire property. - property.serializedObject.Update(); - EditorGUI.BeginProperty(position, label, property); - // Draw label - Rect pos = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); - - Rect targetRect = new Rect(pos.x, pos.y, pos.width, EditorGUIUtility.singleLineHeight); - - // Get target - SerializedProperty targetProp = property.FindPropertyRelative("_target"); - object target = targetProp.objectReferenceValue; - if (attribute != null && attribute is TargetConstraintAttribute) { - Type targetType = (attribute as TargetConstraintAttribute).targetType; - EditorGUI.ObjectField(targetRect, targetProp, targetType, GUIContent.none); - } else EditorGUI.PropertyField(targetRect, targetProp, GUIContent.none); - - if (target == null) { - Rect helpBoxRect = new Rect(position.x + 8, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width - 16, EditorGUIUtility.singleLineHeight); - string msg = "Call not set. Execution will be slower."; - EditorGUI.HelpBox(helpBoxRect, msg, MessageType.Warning); - } else if (target is MonoScript) { - Rect helpBoxRect = new Rect(position.x + 8, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width - 16, EditorGUIUtility.singleLineHeight + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing); - string msg = "Assign a GameObject, Component or a ScriptableObject, not a script."; - EditorGUI.HelpBox(helpBoxRect, msg, MessageType.Warning); - } else { - int indent = EditorGUI.indentLevel; - EditorGUI.indentLevel++; - - // Get method name - SerializedProperty methodProp = property.FindPropertyRelative("_methodName"); - string methodName = methodProp.stringValue; - - // Get args - SerializedProperty argProps = property.FindPropertyRelative("_args"); - Type[] argTypes = GetArgTypes(argProps); - - // Get dynamic - SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); - bool dynamic = dynamicProp.boolValue; - - // Get active method - MethodInfo activeMethod = GetMethod(target, methodName, argTypes); - - GUIContent methodlabel = new GUIContent("n/a"); - if (activeMethod != null) methodlabel = new GUIContent(PrettifyMethod(activeMethod)); - else if (!string.IsNullOrEmpty(methodName)) methodlabel = new GUIContent("Missing (" + PrettifyMethod(methodName, argTypes) + ")"); - - Rect methodRect = new Rect(position.x, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); - - // Method select button - pos = EditorGUI.PrefixLabel(methodRect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent(dynamic ? "Method (dynamic)" : "Method")); - if (EditorGUI.DropdownButton(pos, methodlabel, FocusType.Keyboard)) { - MethodSelector(property); - } +namespace SerializableCallback.Editor { + [CustomPropertyDrawer(typeof(TargetConstraintAttribute))] + [CustomPropertyDrawer(typeof(SerializableCallbackBase), true)] + public class SerializableCallbackDrawer : PropertyDrawer { + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + // Without this, you can't edit fields above the SerializedProperty + property.serializedObject.ApplyModifiedProperties(); + + // Indent label + label.text = " " + label.text; + + #if UNITY_2019_1_OR_NEWER + GUI.Box(position, ""); + #else + GUI.Box(position, "", (GUIStyle) + "flow overlay box"); + #endif + position.y += 4; + // Using BeginProperty / EndProperty on the parent property means that + // prefab override logic works on the entire property. + property.serializedObject.Update(); + EditorGUI.BeginProperty(position, label, property); + // Draw label + Rect pos = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); + + Rect targetRect = new Rect(pos.x, pos.y, pos.width, EditorGUIUtility.singleLineHeight); + + // Get target + SerializedProperty targetProp = property.FindPropertyRelative("_target"); + object target = targetProp.objectReferenceValue; + if (attribute != null && attribute is TargetConstraintAttribute) { + Type targetType = (attribute as TargetConstraintAttribute).targetType; + EditorGUI.ObjectField(targetRect, targetProp, targetType, GUIContent.none); + } else EditorGUI.PropertyField(targetRect, targetProp, GUIContent.none); + + if (target == null) { + Rect helpBoxRect = new Rect(position.x + 8, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width - 16, EditorGUIUtility.singleLineHeight); + string msg = "Call not set. Execution will be slower."; + EditorGUI.HelpBox(helpBoxRect, msg, MessageType.Warning); + } else if (target is MonoScript) { + Rect helpBoxRect = new Rect(position.x + 8, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width - 16, EditorGUIUtility.singleLineHeight + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing); + string msg = "Assign a GameObject, Component or a ScriptableObject, not a script."; + EditorGUI.HelpBox(helpBoxRect, msg, MessageType.Warning); + } else { + int indent = EditorGUI.indentLevel; + EditorGUI.indentLevel++; + + // Get method name + SerializedProperty methodProp = property.FindPropertyRelative("_methodName"); + string methodName = methodProp.stringValue; + + // Get args + SerializedProperty argProps = property.FindPropertyRelative("_args"); + Type[] argTypes = GetArgTypes(argProps); + + // Get dynamic + SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); + bool dynamic = dynamicProp.boolValue; + + // Get active method + MethodInfo activeMethod = GetMethod(target, methodName, argTypes); + + GUIContent methodlabel = new GUIContent("n/a"); + if (activeMethod != null) methodlabel = new GUIContent(PrettifyMethod(activeMethod)); + else if (!string.IsNullOrEmpty(methodName)) methodlabel = new GUIContent("Missing (" + PrettifyMethod(methodName, argTypes) + ")"); + + Rect methodRect = new Rect(position.x, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); + + // Method select button + pos = EditorGUI.PrefixLabel(methodRect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent(dynamic ? "Method (dynamic)" : "Method")); + if (EditorGUI.DropdownButton(pos, methodlabel, FocusType.Keyboard)) { + MethodSelector(property); + } - if (activeMethod != null && !dynamic) { - // Args - ParameterInfo[] activeParameters = activeMethod.GetParameters(); - Rect argRect = new Rect(position.x, methodRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); - string[] types = new string[argProps.arraySize]; - for (int i = 0; i < types.Length; i++) { - SerializedProperty argProp = argProps.FindPropertyRelative("Array.data[" + i + "]"); - GUIContent argLabel = new GUIContent(ObjectNames.NicifyVariableName(activeParameters[i].Name)); - - EditorGUI.BeginChangeCheck(); - switch ((Arg.ArgType) argProp.FindPropertyRelative("argType").enumValueIndex) { - case Arg.ArgType.Bool: - EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("boolValue"), argLabel); - break; - case Arg.ArgType.Int: - EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("intValue"), argLabel); - break; - case Arg.ArgType.Float: - EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("floatValue"), argLabel); - break; - case Arg.ArgType.String: - EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("stringValue"), argLabel); - break; - case Arg.ArgType.Object: - SerializedProperty typeProp = argProp.FindPropertyRelative("_typeName"); - SerializedProperty objProp = argProp.FindPropertyRelative("objectValue"); - - if (typeProp != null) { - Type objType = Type.GetType(typeProp.stringValue, false); - EditorGUI.BeginChangeCheck(); - Object obj = objProp.objectReferenceValue; - obj = EditorGUI.ObjectField(argRect, argLabel, obj, objType, true); - if (EditorGUI.EndChangeCheck()) { - objProp.objectReferenceValue = obj; + if (activeMethod != null && !dynamic) { + // Args + ParameterInfo[] activeParameters = activeMethod.GetParameters(); + Rect argRect = new Rect(position.x, methodRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); + string[] types = new string[argProps.arraySize]; + for (int i = 0; i < types.Length; i++) { + SerializedProperty argProp = argProps.FindPropertyRelative("Array.data[" + i + "]"); + GUIContent argLabel = new GUIContent(ObjectNames.NicifyVariableName(activeParameters[i].Name)); + + EditorGUI.BeginChangeCheck(); + switch ((Arg.ArgType) argProp.FindPropertyRelative("argType").enumValueIndex) { + case Arg.ArgType.Bool: + EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("boolValue"), argLabel); + break; + case Arg.ArgType.Int: + EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("intValue"), argLabel); + break; + case Arg.ArgType.Float: + EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("floatValue"), argLabel); + break; + case Arg.ArgType.String: + EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("stringValue"), argLabel); + break; + case Arg.ArgType.Object: + SerializedProperty typeProp = argProp.FindPropertyRelative("_typeName"); + SerializedProperty objProp = argProp.FindPropertyRelative("objectValue"); + + if (typeProp != null) { + Type objType = Type.GetType(typeProp.stringValue, false); + EditorGUI.BeginChangeCheck(); + Object obj = objProp.objectReferenceValue; + obj = EditorGUI.ObjectField(argRect, argLabel, obj, objType, true); + if (EditorGUI.EndChangeCheck()) { + objProp.objectReferenceValue = obj; + } + } else { + EditorGUI.PropertyField(argRect, objProp, argLabel); } - } else { - EditorGUI.PropertyField(argRect, objProp, argLabel); - } - break; - } - if (EditorGUI.EndChangeCheck()) { - property.FindPropertyRelative("dirty").boolValue = true; + break; + } + if (EditorGUI.EndChangeCheck()) { + property.FindPropertyRelative("dirty").boolValue = true; + } + argRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; } - argRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; } + EditorGUI.indentLevel = indent; } - EditorGUI.indentLevel = indent; - } - // Set indent back to what it was - EditorGUI.EndProperty(); - property.serializedObject.ApplyModifiedProperties(); - } + // Set indent back to what it was + EditorGUI.EndProperty(); + property.serializedObject.ApplyModifiedProperties(); + } - private class MenuItem { - public GenericMenu.MenuFunction action; - public string path; - public GUIContent label; + private class MenuItem { + public GenericMenu.MenuFunction action; + public string path; + public GUIContent label; - public MenuItem(string path, string name, GenericMenu.MenuFunction action) { - this.action = action; - this.label = new GUIContent(path + '/' + name); - this.path = path; - } - } - void MethodSelector(SerializedProperty property) { - // Return type constraint - Type returnType = null; - // Arg type constraint - Type[] argTypes = new Type[0]; - - // Get return type and argument constraints - SerializableCallbackBase dummy = GetDummyFunction(property); - Type[] genericTypes = dummy.GetType().BaseType.GetGenericArguments(); - // SerializableEventBase is always void return type - if (dummy is SerializableEventBase) { - returnType = typeof(void); - if (genericTypes.Length > 0) { - argTypes = new Type[genericTypes.Length]; - Array.Copy(genericTypes, argTypes, genericTypes.Length); + public MenuItem(string path, string name, GenericMenu.MenuFunction action) { + this.action = action; + this.label = new GUIContent(path + '/' + name); + this.path = path; } - } else { - if (genericTypes != null && genericTypes.Length > 0) { - // The last generic argument is the return type - returnType = genericTypes[genericTypes.Length - 1]; - if (genericTypes.Length > 1) { - argTypes = new Type[genericTypes.Length - 1]; - Array.Copy(genericTypes, argTypes, genericTypes.Length - 1); + } + void MethodSelector(SerializedProperty property) { + // Return type constraint + Type returnType = null; + // Arg type constraint + Type[] argTypes = new Type[0]; + + // Get return type and argument constraints + SerializableCallbackBase dummy = GetDummyFunction(property); + Type[] genericTypes = dummy.GetType().BaseType.GetGenericArguments(); + // SerializableEventBase is always void return type + if (dummy is SerializableEventBase) { + returnType = typeof(void); + if (genericTypes.Length > 0) { + argTypes = new Type[genericTypes.Length]; + Array.Copy(genericTypes, argTypes, genericTypes.Length); + } + } else { + if (genericTypes != null && genericTypes.Length > 0) { + // The last generic argument is the return type + returnType = genericTypes[genericTypes.Length - 1]; + if (genericTypes.Length > 1) { + argTypes = new Type[genericTypes.Length - 1]; + Array.Copy(genericTypes, argTypes, genericTypes.Length - 1); + } } } - } - SerializedProperty targetProp = property.FindPropertyRelative("_target"); + SerializedProperty targetProp = property.FindPropertyRelative("_target"); - List dynamicItems = new List(); - List staticItems = new List(); + List dynamicItems = new List(); + List staticItems = new List(); - List targets = new List() { targetProp.objectReferenceValue }; + List targets = new List() { targetProp.objectReferenceValue }; - if (targets[0] is Component) { - targets = (targets[0] as Component).gameObject.GetComponents().ToList(); - targets.Add((targetProp.objectReferenceValue as Component).gameObject); - } else if (targets[0] is GameObject) { - targets = (targets[0] as GameObject).GetComponents().ToList(); - targets.Add(targetProp.objectReferenceValue as GameObject); - } - for (int c = 0; c < targets.Count; c++) { - Object t = targets[c]; - MethodInfo[] methods = targets[c].GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); + if (targets[0] is Component) { + targets = (targets[0] as Component).gameObject.GetComponents().ToList(); + targets.Add((targetProp.objectReferenceValue as Component).gameObject); + } else if (targets[0] is GameObject) { + targets = (targets[0] as GameObject).GetComponents().ToList(); + targets.Add(targetProp.objectReferenceValue as GameObject); + } + for (int c = 0; c < targets.Count; c++) { + Object t = targets[c]; + MethodInfo[] methods = targets[c].GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); - for (int i = 0; i < methods.Length; i++) { - MethodInfo method = methods[i]; + for (int i = 0; i < methods.Length; i++) { + MethodInfo method = methods[i]; - // Skip methods with wrong return type - if (returnType != null && method.ReturnType != returnType) continue; - // Skip methods with null return type - // if (method.ReturnType == typeof(void)) continue; - // Skip generic methods - if (method.IsGenericMethod) continue; + // Skip methods with wrong return type + if (returnType != null && method.ReturnType != returnType) continue; + // Skip methods with null return type + // if (method.ReturnType == typeof(void)) continue; + // Skip generic methods + if (method.IsGenericMethod) continue; - Type[] parms = method.GetParameters().Select(x => x.ParameterType).ToArray(); + Type[] parms = method.GetParameters().Select(x => x.ParameterType).ToArray(); - // Skip methods with more than 4 args - if (parms.Length > 4) continue; - // Skip methods with unsupported args - if (parms.Any(x => !Arg.IsSupported(x))) continue; + // Skip methods with more than 4 args + if (parms.Length > 4) continue; + // Skip methods with unsupported args + if (parms.Any(x => !Arg.IsSupported(x))) continue; - string methodPrettyName = PrettifyMethod(methods[i]); - staticItems.Add(new MenuItem(targets[c].GetType().Name + "/" + methods[i].DeclaringType.Name, methodPrettyName, () => SetMethod(property, t, method, false))); + string methodPrettyName = PrettifyMethod(methods[i]); + staticItems.Add(new MenuItem(targets[c].GetType().Name + "/" + methods[i].DeclaringType.Name, methodPrettyName, () => SetMethod(property, t, method, false))); - // Skip methods with wrong constrained args - if (argTypes.Length == 0 || !Enumerable.SequenceEqual(argTypes, parms)) continue; + // Skip methods with wrong constrained args + if (argTypes.Length == 0 || !Enumerable.SequenceEqual(argTypes, parms)) continue; - dynamicItems.Add(new MenuItem(targets[c].GetType().Name + "/" + methods[i].DeclaringType.Name, methods[i].Name, () => SetMethod(property, t, method, true))); + dynamicItems.Add(new MenuItem(targets[c].GetType().Name + "/" + methods[i].DeclaringType.Name, methods[i].Name, () => SetMethod(property, t, method, true))); + } } - } - // Construct and display context menu - GenericMenu menu = new GenericMenu(); - if (dynamicItems.Count > 0) { - string[] paths = dynamicItems.GroupBy(x => x.path).Select(x => x.First().path).ToArray(); - foreach (string path in paths) { - menu.AddItem(new GUIContent(path + "/Dynamic " + PrettifyTypes(argTypes)), false, null); - } - for (int i = 0; i < dynamicItems.Count; i++) { - menu.AddItem(dynamicItems[i].label, false, dynamicItems[i].action); + // Construct and display context menu + GenericMenu menu = new GenericMenu(); + if (dynamicItems.Count > 0) { + string[] paths = dynamicItems.GroupBy(x => x.path).Select(x => x.First().path).ToArray(); + foreach (string path in paths) { + menu.AddItem(new GUIContent(path + "/Dynamic " + PrettifyTypes(argTypes)), false, null); + } + for (int i = 0; i < dynamicItems.Count; i++) { + menu.AddItem(dynamicItems[i].label, false, dynamicItems[i].action); + } + foreach (string path in paths) { + menu.AddItem(new GUIContent(path + "/ "), false, null); + menu.AddItem(new GUIContent(path + "/Static parameters"), false, null); + } } - foreach (string path in paths) { - menu.AddItem(new GUIContent(path + "/ "), false, null); - menu.AddItem(new GUIContent(path + "/Static parameters"), false, null); + for (int i = 0; i < staticItems.Count; i++) { + menu.AddItem(staticItems[i].label, false, staticItems[i].action); } + if (menu.GetItemCount() == 0) menu.AddDisabledItem(new GUIContent("No methods with return type '" + GetTypeName(returnType) + "'")); + menu.ShowAsContext(); } - for (int i = 0; i < staticItems.Count; i++) { - menu.AddItem(staticItems[i].label, false, staticItems[i].action); - } - if (menu.GetItemCount() == 0) menu.AddDisabledItem(new GUIContent("No methods with return type '" + GetTypeName(returnType) + "'")); - menu.ShowAsContext(); - } - string PrettifyMethod(string methodName, Type[] parmTypes) { - string parmnames = PrettifyTypes(parmTypes); - return methodName + "(" + parmnames + ")"; - } + string PrettifyMethod(string methodName, Type[] parmTypes) { + string parmnames = PrettifyTypes(parmTypes); + return methodName + "(" + parmnames + ")"; + } - string PrettifyMethod(MethodInfo methodInfo) { - if (methodInfo == null) throw new ArgumentNullException("methodInfo"); - ParameterInfo[] parms = methodInfo.GetParameters(); - string parmnames = PrettifyTypes(parms.Select(x => x.ParameterType).ToArray()); - return GetTypeName(methodInfo.ReturnParameter.ParameterType) + " " + methodInfo.Name + "(" + parmnames + ")"; - } + string PrettifyMethod(MethodInfo methodInfo) { + if (methodInfo == null) throw new ArgumentNullException("methodInfo"); + ParameterInfo[] parms = methodInfo.GetParameters(); + string parmnames = PrettifyTypes(parms.Select(x => x.ParameterType).ToArray()); + return GetTypeName(methodInfo.ReturnParameter.ParameterType) + " " + methodInfo.Name + "(" + parmnames + ")"; + } - string PrettifyTypes(Type[] types) { - if (types == null) throw new ArgumentNullException("types"); - return string.Join(", ", types.Select(x => GetTypeName(x)).ToArray()); - } + string PrettifyTypes(Type[] types) { + if (types == null) throw new ArgumentNullException("types"); + return string.Join(", ", types.Select(x => GetTypeName(x)).ToArray()); + } - MethodInfo GetMethod(object target, string methodName, Type[] types) { - MethodInfo activeMethod = target.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, null, CallingConventions.Any, types, null); - return activeMethod; - } + MethodInfo GetMethod(object target, string methodName, Type[] types) { + MethodInfo activeMethod = target.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, null, CallingConventions.Any, types, null); + return activeMethod; + } - private Type[] GetArgTypes(SerializedProperty argsProp) { - Type[] types = new Type[argsProp.arraySize]; - for (int i = 0; i < argsProp.arraySize; i++) { - SerializedProperty argProp = argsProp.GetArrayElementAtIndex(i); - SerializedProperty typeNameProp = argProp.FindPropertyRelative("_typeName"); - if (typeNameProp != null) types[i] = Type.GetType(typeNameProp.stringValue, false); - if (types[i] == null) types[i] = Arg.RealType((Arg.ArgType) argProp.FindPropertyRelative("argType").enumValueIndex); + private Type[] GetArgTypes(SerializedProperty argsProp) { + Type[] types = new Type[argsProp.arraySize]; + for (int i = 0; i < argsProp.arraySize; i++) { + SerializedProperty argProp = argsProp.GetArrayElementAtIndex(i); + SerializedProperty typeNameProp = argProp.FindPropertyRelative("_typeName"); + if (typeNameProp != null) types[i] = Type.GetType(typeNameProp.stringValue, false); + if (types[i] == null) types[i] = Arg.RealType((Arg.ArgType) argProp.FindPropertyRelative("argType").enumValueIndex); + } + return types; } - return types; - } - private void SetMethod(SerializedProperty property, UnityEngine.Object target, MethodInfo methodInfo, bool dynamic) { - SerializedProperty targetProp = property.FindPropertyRelative("_target"); - targetProp.objectReferenceValue = target; - SerializedProperty methodProp = property.FindPropertyRelative("_methodName"); - methodProp.stringValue = methodInfo.Name; - SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); - dynamicProp.boolValue = dynamic; - SerializedProperty argProp = property.FindPropertyRelative("_args"); - ParameterInfo[] parameters = methodInfo.GetParameters(); - argProp.arraySize = parameters.Length; - for (int i = 0; i < parameters.Length; i++) { - argProp.FindPropertyRelative("Array.data[" + i + "].argType").enumValueIndex = (int) Arg.FromRealType(parameters[i].ParameterType); - argProp.FindPropertyRelative("Array.data[" + i + "]._typeName").stringValue = parameters[i].ParameterType.AssemblyQualifiedName; + private void SetMethod(SerializedProperty property, UnityEngine.Object target, MethodInfo methodInfo, bool dynamic) { + SerializedProperty targetProp = property.FindPropertyRelative("_target"); + targetProp.objectReferenceValue = target; + SerializedProperty methodProp = property.FindPropertyRelative("_methodName"); + methodProp.stringValue = methodInfo.Name; + SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); + dynamicProp.boolValue = dynamic; + SerializedProperty argProp = property.FindPropertyRelative("_args"); + ParameterInfo[] parameters = methodInfo.GetParameters(); + argProp.arraySize = parameters.Length; + for (int i = 0; i < parameters.Length; i++) { + argProp.FindPropertyRelative("Array.data[" + i + "].argType").enumValueIndex = (int) Arg.FromRealType(parameters[i].ParameterType); + argProp.FindPropertyRelative("Array.data[" + i + "]._typeName").stringValue = parameters[i].ParameterType.AssemblyQualifiedName; + } + property.FindPropertyRelative("dirty").boolValue = true; + property.serializedObject.ApplyModifiedProperties(); + property.serializedObject.Update(); } - property.FindPropertyRelative("dirty").boolValue = true; - property.serializedObject.ApplyModifiedProperties(); - property.serializedObject.Update(); - } - private static string GetTypeName(Type t) { - if (t == typeof(int)) return "int"; - else if (t == typeof(float)) return "float"; - else if (t == typeof(string)) return "string"; - else if (t == typeof(bool)) return "bool"; - else if (t == typeof(void)) return "void"; - else return t.Name; - } + private static string GetTypeName(Type t) { + if (t == typeof(int)) return "int"; + else if (t == typeof(float)) return "float"; + else if (t == typeof(string)) return "string"; + else if (t == typeof(bool)) return "bool"; + else if (t == typeof(void)) return "void"; + else return t.Name; + } - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - float lineheight = EditorGUIUtility.standardVerticalSpacing + EditorGUIUtility.singleLineHeight; - SerializedProperty targetProp = property.FindPropertyRelative("_target"); - SerializedProperty argProps = property.FindPropertyRelative("_args"); - SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); - float height = lineheight + lineheight; - if (targetProp.objectReferenceValue != null && targetProp.objectReferenceValue is MonoScript) height += lineheight; - else if (targetProp.objectReferenceValue != null && !dynamicProp.boolValue) height += argProps.arraySize * lineheight; - height += 8; - return height; - } + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + float lineheight = EditorGUIUtility.standardVerticalSpacing + EditorGUIUtility.singleLineHeight; + SerializedProperty targetProp = property.FindPropertyRelative("_target"); + SerializedProperty argProps = property.FindPropertyRelative("_args"); + SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); + float height = lineheight + lineheight; + if (targetProp.objectReferenceValue != null && targetProp.objectReferenceValue is MonoScript) height += lineheight; + else if (targetProp.objectReferenceValue != null && !dynamicProp.boolValue) height += argProps.arraySize * lineheight; + height += 8; + return height; + } - private static SerializableCallbackBase GetDummyFunction(SerializedProperty prop) { - string stringValue = prop.FindPropertyRelative("_typeName").stringValue; - Type type = Type.GetType(stringValue, false); - SerializableCallbackBase result; - if (type == null) { - return null; - } else { - result = (Activator.CreateInstance(type) as SerializableCallbackBase); + private static SerializableCallbackBase GetDummyFunction(SerializedProperty prop) { + string stringValue = prop.FindPropertyRelative("_typeName").stringValue; + Type type = Type.GetType(stringValue, false); + SerializableCallbackBase result; + if (type == null) { + return null; + } else { + result = (Activator.CreateInstance(type) as SerializableCallbackBase); + } + return result; } - return result; } -} +} \ No newline at end of file diff --git a/Runtime/Attributes/TargetConstraintAttribute.cs b/Runtime/Attributes/TargetConstraintAttribute.cs index e457e06..7900be5 100644 --- a/Runtime/Attributes/TargetConstraintAttribute.cs +++ b/Runtime/Attributes/TargetConstraintAttribute.cs @@ -1,12 +1,14 @@ using UnityEngine; using System; -/// Add to fields of your class extending SerializableCallbackBase to limit which types can be assigned to it. -public class TargetConstraintAttribute : PropertyAttribute { - public Type targetType; - +namespace SerializableCallback { /// Add to fields of your class extending SerializableCallbackBase to limit which types can be assigned to it. - public TargetConstraintAttribute(Type targetType) { - this.targetType = targetType; + public class TargetConstraintAttribute : PropertyAttribute { + public Type targetType; + + /// Add to fields of your class extending SerializableCallbackBase to limit which types can be assigned to it. + public TargetConstraintAttribute(Type targetType) { + this.targetType = targetType; + } } -} +} \ No newline at end of file diff --git a/Runtime/InvokableCallback.cs b/Runtime/InvokableCallback.cs index 2819874..f94ae52 100644 --- a/Runtime/InvokableCallback.cs +++ b/Runtime/InvokableCallback.cs @@ -3,126 +3,128 @@ using System.Collections.Generic; using UnityEngine; -public class InvokableCallback : InvokableCallbackBase { +namespace SerializableCallback { + public class InvokableCallback : InvokableCallbackBase { - public Func func; + public Func func; - public TReturn Invoke() { - return func(); - } + public TReturn Invoke() { + return func(); + } - public override TReturn Invoke(params object[] args) { - return func(); - } + public override TReturn Invoke(params object[] args) { + return func(); + } - /// Constructor - public InvokableCallback(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - func = () => default(TReturn); - } else { - func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + /// Constructor + public InvokableCallback(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + func = () => default(TReturn); + } else { + func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + } } } -} -public class InvokableCallback : InvokableCallbackBase { + public class InvokableCallback : InvokableCallbackBase { - public Func func; + public Func func; - public TReturn Invoke(T0 arg0) { - return func(arg0); - } + public TReturn Invoke(T0 arg0) { + return func(arg0); + } - public override TReturn Invoke(params object[] args) { - // Convert from special "unity-nulls" to true null - if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; - return func((T0) args[0]); - } + public override TReturn Invoke(params object[] args) { + // Convert from special "unity-nulls" to true null + if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; + return func((T0) args[0]); + } - /// Constructor - public InvokableCallback(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - func = x => default(TReturn); - } else { - func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + /// Constructor + public InvokableCallback(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + func = x => default(TReturn); + } else { + func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + } } } -} -public class InvokableCallback : InvokableCallbackBase { + public class InvokableCallback : InvokableCallbackBase { - public Func func; + public Func func; - public TReturn Invoke(T0 arg0, T1 arg1) { - return func(arg0, arg1); - } + public TReturn Invoke(T0 arg0, T1 arg1) { + return func(arg0, arg1); + } - public override TReturn Invoke(params object[] args) { - // Convert from special "unity-nulls" to true null - if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; - if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; - return func((T0) args[0], (T1) args[1]); - } + public override TReturn Invoke(params object[] args) { + // Convert from special "unity-nulls" to true null + if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; + if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; + return func((T0) args[0], (T1) args[1]); + } - /// Constructor - public InvokableCallback(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - func = (x, y) => default(TReturn); - } else { - func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + /// Constructor + public InvokableCallback(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + func = (x, y) => default(TReturn); + } else { + func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + } } } -} -public class InvokableCallback : InvokableCallbackBase { + public class InvokableCallback : InvokableCallbackBase { - public Func func; + public Func func; - public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2) { - return func(arg0, arg1, arg2); - } + public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2) { + return func(arg0, arg1, arg2); + } - public override TReturn Invoke(params object[] args) { - // Convert from special "unity-nulls" to true null - if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; - if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; - if (args[2] is UnityEngine.Object && (UnityEngine.Object) args[2] == null) args[2] = null; - return func((T0) args[0], (T1) args[1], (T2) args[2]); - } + public override TReturn Invoke(params object[] args) { + // Convert from special "unity-nulls" to true null + if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; + if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; + if (args[2] is UnityEngine.Object && (UnityEngine.Object) args[2] == null) args[2] = null; + return func((T0) args[0], (T1) args[1], (T2) args[2]); + } - /// Constructor - public InvokableCallback(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - func = (x, y, z) => default(TReturn); - } else { - func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + /// Constructor + public InvokableCallback(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + func = (x, y, z) => default(TReturn); + } else { + func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + } } } -} -public class InvokableCallback : InvokableCallbackBase { + public class InvokableCallback : InvokableCallbackBase { - public Func func; + public Func func; - public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { - return func(arg0, arg1, arg2, arg3); - } + public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { + return func(arg0, arg1, arg2, arg3); + } - public override TReturn Invoke(params object[] args) { - // Convert from special "unity-nulls" to true null - if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; - if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; - if (args[2] is UnityEngine.Object && (UnityEngine.Object) args[2] == null) args[2] = null; - if (args[3] is UnityEngine.Object && (UnityEngine.Object) args[3] == null) args[3] = null; - return func((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3]); - } + public override TReturn Invoke(params object[] args) { + // Convert from special "unity-nulls" to true null + if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; + if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; + if (args[2] is UnityEngine.Object && (UnityEngine.Object) args[2] == null) args[2] = null; + if (args[3] is UnityEngine.Object && (UnityEngine.Object) args[3] == null) args[3] = null; + return func((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3]); + } - /// Constructor - public InvokableCallback(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - func = (x, y, z, w) => default(TReturn); - } else { - func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + /// Constructor + public InvokableCallback(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + func = (x, y, z, w) => default(TReturn); + } else { + func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); + } } } } \ No newline at end of file diff --git a/Runtime/InvokableCallbackBase.cs b/Runtime/InvokableCallbackBase.cs index e0cd2d1..19f09c6 100644 --- a/Runtime/InvokableCallbackBase.cs +++ b/Runtime/InvokableCallbackBase.cs @@ -1,3 +1,5 @@ -public abstract class InvokableCallbackBase { - public abstract TReturn Invoke(params object[] args); +namespace SerializableCallback { + public abstract class InvokableCallbackBase { + public abstract TReturn Invoke(params object[] args); + } } \ No newline at end of file diff --git a/Runtime/InvokableEvent.cs b/Runtime/InvokableEvent.cs index dd9db65..be141ca 100644 --- a/Runtime/InvokableEvent.cs +++ b/Runtime/InvokableEvent.cs @@ -1,111 +1,113 @@ using System; -public class InvokableEvent : InvokableEventBase { +namespace SerializableCallback { + public class InvokableEvent : InvokableEventBase { - public System.Action action; + public System.Action action; - public void Invoke() { - action(); - } + public void Invoke() { + action(); + } - public override void Invoke(params object[] args) { - action(); - } + public override void Invoke(params object[] args) { + action(); + } - /// Constructor - public InvokableEvent(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - action = () => { }; - } else { - action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + /// Constructor + public InvokableEvent(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + action = () => { }; + } else { + action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + } } } -} -public class InvokableEvent : InvokableEventBase { + public class InvokableEvent : InvokableEventBase { - public Action action; + public Action action; - public void Invoke(T0 arg0) { - action(arg0); - } + public void Invoke(T0 arg0) { + action(arg0); + } - public override void Invoke(params object[] args) { - action((T0) args[0]); - } + public override void Invoke(params object[] args) { + action((T0) args[0]); + } - /// Constructor - public InvokableEvent(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - action = x => { }; - } else { - action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + /// Constructor + public InvokableEvent(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + action = x => { }; + } else { + action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + } } } -} -public class InvokableEvent : InvokableEventBase { + public class InvokableEvent : InvokableEventBase { - public Action action; + public Action action; - public void Invoke(T0 arg0, T1 arg1) { - action(arg0, arg1); - } + public void Invoke(T0 arg0, T1 arg1) { + action(arg0, arg1); + } - public override void Invoke(params object[] args) { - action((T0) args[0], (T1) args[1]); - } + public override void Invoke(params object[] args) { + action((T0) args[0], (T1) args[1]); + } - /// Constructor - public InvokableEvent(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - action = (x, y) => { }; - } else { - action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + /// Constructor + public InvokableEvent(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + action = (x, y) => { }; + } else { + action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + } } } -} -public class InvokableEvent : InvokableEventBase { + public class InvokableEvent : InvokableEventBase { - public Action action; + public Action action; - public void Invoke(T0 arg0, T1 arg1, T2 arg2) { - action(arg0, arg1, arg2); - } + public void Invoke(T0 arg0, T1 arg1, T2 arg2) { + action(arg0, arg1, arg2); + } - public override void Invoke(params object[] args) { - action((T0) args[0], (T1) args[1], (T2) args[2]); - } + public override void Invoke(params object[] args) { + action((T0) args[0], (T1) args[1], (T2) args[2]); + } - /// Constructor - public InvokableEvent(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - action = (x, y, z) => { }; - } else { - action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + /// Constructor + public InvokableEvent(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + action = (x, y, z) => { }; + } else { + action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + } } } -} -public class InvokableEvent : InvokableEventBase { + public class InvokableEvent : InvokableEventBase { - public Action action; + public Action action; - public void Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { - action(arg0, arg1, arg2, arg3); - } + public void Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { + action(arg0, arg1, arg2, arg3); + } - public override void Invoke(params object[] args) { - action((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3]); - } + public override void Invoke(params object[] args) { + action((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3]); + } - /// Constructor - public InvokableEvent(object target, string methodName) { - if (target == null || string.IsNullOrEmpty(methodName)) { - action = (x, y, z, w) => { }; - } else { - action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + /// Constructor + public InvokableEvent(object target, string methodName) { + if (target == null || string.IsNullOrEmpty(methodName)) { + action = (x, y, z, w) => { }; + } else { + action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); + } } } -} +} \ No newline at end of file diff --git a/Runtime/InvokableEventBase.cs b/Runtime/InvokableEventBase.cs index 003ab7c..9096dc8 100644 --- a/Runtime/InvokableEventBase.cs +++ b/Runtime/InvokableEventBase.cs @@ -1,3 +1,5 @@ -public abstract class InvokableEventBase { - public abstract void Invoke(params object[] args); +namespace SerializableCallback { + public abstract class InvokableEventBase { + public abstract void Invoke(params object[] args); + } } \ No newline at end of file diff --git a/Runtime/SerializableCallback.cs b/Runtime/SerializableCallback.cs index e58fa3b..00a50c5 100644 --- a/Runtime/SerializableCallback.cs +++ b/Runtime/SerializableCallback.cs @@ -3,121 +3,123 @@ using System.Reflection; using UnityEngine; -public abstract class SerializableCallback : SerializableCallbackBase { - public TReturn Invoke() { - if (func == null) Cache(); - if (_dynamic) { - InvokableCallback call = func as InvokableCallback; - return call.Invoke(); - } else { - return func.Invoke(Args); - } - } - - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - func = new InvokableCallback(null, null); - } else { +namespace SerializableCallback { + public abstract class SerializableCallback : SerializableCallbackBase { + public TReturn Invoke() { + if (func == null) Cache(); if (_dynamic) { - func = new InvokableCallback(target, methodName); + InvokableCallback call = func as InvokableCallback; + return call.Invoke(); } else { - func = GetPersistentMethod(); + return func.Invoke(Args); } } - } -} -public abstract class SerializableCallback : SerializableCallbackBase { - public TReturn Invoke(T0 arg0) { - if (func == null) Cache(); - if (_dynamic) { - InvokableCallback call = func as InvokableCallback; - return call.Invoke(arg0); - } else { - return func.Invoke(Args); + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + func = new InvokableCallback(null, null); + } else { + if (_dynamic) { + func = new InvokableCallback(target, methodName); + } else { + func = GetPersistentMethod(); + } + } } } - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - func = new InvokableCallback(null, null); - } else { + public abstract class SerializableCallback : SerializableCallbackBase { + public TReturn Invoke(T0 arg0) { + if (func == null) Cache(); if (_dynamic) { - func = new InvokableCallback(target, methodName); + InvokableCallback call = func as InvokableCallback; + return call.Invoke(arg0); } else { - func = GetPersistentMethod(); + return func.Invoke(Args); } } - } -} -public abstract class SerializableCallback : SerializableCallbackBase { - public TReturn Invoke(T0 arg0, T1 arg1) { - if (func == null) Cache(); - if (_dynamic) { - InvokableCallback call = func as InvokableCallback; - return call.Invoke(arg0, arg1); - } else { - return func.Invoke(Args); + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + func = new InvokableCallback(null, null); + } else { + if (_dynamic) { + func = new InvokableCallback(target, methodName); + } else { + func = GetPersistentMethod(); + } + } } } - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - func = new InvokableCallback(null, null); - } else { + public abstract class SerializableCallback : SerializableCallbackBase { + public TReturn Invoke(T0 arg0, T1 arg1) { + if (func == null) Cache(); if (_dynamic) { - func = new InvokableCallback(target, methodName); + InvokableCallback call = func as InvokableCallback; + return call.Invoke(arg0, arg1); } else { - func = GetPersistentMethod(); + return func.Invoke(Args); } } - } -} -public abstract class SerializableCallback : SerializableCallbackBase { - public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2) { - if (func == null) Cache(); - if (_dynamic) { - InvokableCallback call = func as InvokableCallback; - return call.Invoke(arg0, arg1, arg2); - } else { - return func.Invoke(Args); + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + func = new InvokableCallback(null, null); + } else { + if (_dynamic) { + func = new InvokableCallback(target, methodName); + } else { + func = GetPersistentMethod(); + } + } } } - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - func = new InvokableCallback(null, null); - } else { + public abstract class SerializableCallback : SerializableCallbackBase { + public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2) { + if (func == null) Cache(); if (_dynamic) { - func = new InvokableCallback(target, methodName); + InvokableCallback call = func as InvokableCallback; + return call.Invoke(arg0, arg1, arg2); } else { - func = GetPersistentMethod(); + return func.Invoke(Args); } } - } -} -public abstract class SerializableCallback : SerializableCallbackBase { - public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { - if (func == null) Cache(); - if (_dynamic) { - InvokableCallback call = func as InvokableCallback; - return call.Invoke(arg0, arg1, arg2, arg3); - } else { - return func.Invoke(Args); + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + func = new InvokableCallback(null, null); + } else { + if (_dynamic) { + func = new InvokableCallback(target, methodName); + } else { + func = GetPersistentMethod(); + } + } } } - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - func = new InvokableCallback(null, null); - } else { + public abstract class SerializableCallback : SerializableCallbackBase { + public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { + if (func == null) Cache(); if (_dynamic) { - func = new InvokableCallback(target, methodName); + InvokableCallback call = func as InvokableCallback; + return call.Invoke(arg0, arg1, arg2, arg3); + } else { + return func.Invoke(Args); + } + } + + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + func = new InvokableCallback(null, null); } else { - func = GetPersistentMethod(); + if (_dynamic) { + func = new InvokableCallback(target, methodName); + } else { + func = GetPersistentMethod(); + } } } } diff --git a/Runtime/SerializableCallbackBase.cs b/Runtime/SerializableCallbackBase.cs index 34300d7..b9d487e 100644 --- a/Runtime/SerializableCallbackBase.cs +++ b/Runtime/SerializableCallbackBase.cs @@ -6,162 +6,164 @@ using UnityEngine; using Object = UnityEngine.Object; -public abstract class SerializableCallbackBase : SerializableCallbackBase { - public InvokableCallbackBase func; +namespace SerializableCallback { + public abstract class SerializableCallbackBase : SerializableCallbackBase { + public InvokableCallbackBase func; - public override void ClearCache() { - base.ClearCache(); - func = null; - } + public override void ClearCache() { + base.ClearCache(); + func = null; + } - protected InvokableCallbackBase GetPersistentMethod() { - Type[] types = new Type[ArgRealTypes.Length + 1]; - Array.Copy(ArgRealTypes, types, ArgRealTypes.Length); - types[types.Length - 1] = typeof(TReturn); - - Type genericType = null; - switch (types.Length) { - case 1: - genericType = typeof(InvokableCallback<>).MakeGenericType(types); - break; - case 2: - genericType = typeof(InvokableCallback<,>).MakeGenericType(types); - break; - case 3: - genericType = typeof(InvokableCallback<, ,>).MakeGenericType(types); - break; - case 4: - genericType = typeof(InvokableCallback<, , ,>).MakeGenericType(types); - break; - case 5: - genericType = typeof(InvokableCallback<, , , ,>).MakeGenericType(types); - break; - default: - throw new ArgumentException(types.Length + "args"); + protected InvokableCallbackBase GetPersistentMethod() { + Type[] types = new Type[ArgRealTypes.Length + 1]; + Array.Copy(ArgRealTypes, types, ArgRealTypes.Length); + types[types.Length - 1] = typeof(TReturn); + + Type genericType = null; + switch (types.Length) { + case 1: + genericType = typeof(InvokableCallback<>).MakeGenericType(types); + break; + case 2: + genericType = typeof(InvokableCallback<,>).MakeGenericType(types); + break; + case 3: + genericType = typeof(InvokableCallback<, ,>).MakeGenericType(types); + break; + case 4: + genericType = typeof(InvokableCallback<, , ,>).MakeGenericType(types); + break; + case 5: + genericType = typeof(InvokableCallback<, , , ,>).MakeGenericType(types); + break; + default: + throw new ArgumentException(types.Length + "args"); + } + return Activator.CreateInstance(genericType, new object[] { target, methodName }) as InvokableCallbackBase; } - return Activator.CreateInstance(genericType, new object[] { target, methodName }) as InvokableCallbackBase; - } -} - -/// An inspector-friendly serializable function -[System.Serializable] -public abstract class SerializableCallbackBase : ISerializationCallbackReceiver { - - /// Target object - public Object target { get { return _target; } set { _target = value; ClearCache(); } } - /// Target method name - public string methodName { get { return _methodName; } set { _methodName = value; ClearCache(); } } - public object[] Args { get { return args != null ? args : args = _args.Select(x => x.GetValue()).ToArray(); } } - public object[] args; - public Type[] ArgTypes { get { return argTypes != null ? argTypes : argTypes = _args.Select(x => Arg.RealType(x.argType)).ToArray(); } } - public Type[] argTypes; - public Type[] ArgRealTypes { get { return argRealTypes != null ? argRealTypes : argRealTypes = _args.Select(x => Type.GetType(x._typeName)).ToArray(); } } - public Type[] argRealTypes; - public bool dynamic { get { return _dynamic; } set { _dynamic = value; ClearCache(); } } - - [SerializeField] protected Object _target; - [SerializeField] protected string _methodName; - [SerializeField] protected Arg[] _args; - [SerializeField] protected bool _dynamic; -#pragma warning disable 0414 - [SerializeField] private string _typeName; -#pragma warning restore 0414 - - [SerializeField] private bool dirty; - -#if UNITY_EDITOR - protected SerializableCallbackBase() { - _typeName = base.GetType().AssemblyQualifiedName; } -#endif - public virtual void ClearCache() { - argTypes = null; - args = null; - } + /// An inspector-friendly serializable function + [System.Serializable] + public abstract class SerializableCallbackBase : ISerializationCallbackReceiver { + + /// Target object + public Object target { get { return _target; } set { _target = value; ClearCache(); } } + /// Target method name + public string methodName { get { return _methodName; } set { _methodName = value; ClearCache(); } } + public object[] Args { get { return args != null ? args : args = _args.Select(x => x.GetValue()).ToArray(); } } + public object[] args; + public Type[] ArgTypes { get { return argTypes != null ? argTypes : argTypes = _args.Select(x => Arg.RealType(x.argType)).ToArray(); } } + public Type[] argTypes; + public Type[] ArgRealTypes { get { return argRealTypes != null ? argRealTypes : argRealTypes = _args.Select(x => Type.GetType(x._typeName)).ToArray(); } } + public Type[] argRealTypes; + public bool dynamic { get { return _dynamic; } set { _dynamic = value; ClearCache(); } } + + [SerializeField] protected Object _target; + [SerializeField] protected string _methodName; + [SerializeField] protected Arg[] _args; + [SerializeField] protected bool _dynamic; + #pragma warning disable 0414 + [SerializeField] private string _typeName; + #pragma warning restore 0414 + + [SerializeField] private bool dirty; + + #if UNITY_EDITOR + protected SerializableCallbackBase() { + _typeName = base.GetType().AssemblyQualifiedName; + } + #endif - public void SetMethod(Object target, string methodName, bool dynamic, params Arg[] args) { - _target = target; - _methodName = methodName; - _dynamic = dynamic; - _args = args; - ClearCache(); - } + public virtual void ClearCache() { + argTypes = null; + args = null; + } - protected abstract void Cache(); + public void SetMethod(Object target, string methodName, bool dynamic, params Arg[] args) { + _target = target; + _methodName = methodName; + _dynamic = dynamic; + _args = args; + ClearCache(); + } - public void OnBeforeSerialize() { -#if UNITY_EDITOR - if (dirty) { ClearCache(); dirty = false; } -#endif - } + protected abstract void Cache(); - public void OnAfterDeserialize() { -#if UNITY_EDITOR - _typeName = base.GetType().AssemblyQualifiedName; -#endif - } -} - -[System.Serializable] -public struct Arg { - public enum ArgType { Unsupported, Bool, Int, Float, String, Object } - public bool boolValue; - public int intValue; - public float floatValue; - public string stringValue; - public Object objectValue; - public ArgType argType; - public string _typeName; - - public object GetValue() { - return GetValue(argType); - } + public void OnBeforeSerialize() { + #if UNITY_EDITOR + if (dirty) { ClearCache(); dirty = false; } + #endif + } - public object GetValue(ArgType type) { - switch (type) { - case ArgType.Bool: - return boolValue; - case ArgType.Int: - return intValue; - case ArgType.Float: - return floatValue; - case ArgType.String: - return stringValue; - case ArgType.Object: - return objectValue; - default: - return null; + public void OnAfterDeserialize() { + #if UNITY_EDITOR + _typeName = base.GetType().AssemblyQualifiedName; + #endif } } - public static Type RealType(ArgType type) { - switch (type) { - case ArgType.Bool: - return typeof(bool); - case ArgType.Int: - return typeof(int); - case ArgType.Float: - return typeof(float); - case ArgType.String: - return typeof(string); - case ArgType.Object: - return typeof(Object); - default: - return null; + [System.Serializable] + public struct Arg { + public enum ArgType { Unsupported, Bool, Int, Float, String, Object } + public bool boolValue; + public int intValue; + public float floatValue; + public string stringValue; + public Object objectValue; + public ArgType argType; + public string _typeName; + + public object GetValue() { + return GetValue(argType); } - } - public static ArgType FromRealType(Type type) { - if (type == typeof(bool)) return ArgType.Bool; - else if (type == typeof(int)) return ArgType.Int; - else if (type == typeof(float)) return ArgType.Float; - else if (type == typeof(String)) return ArgType.String; - else if (typeof(Object).IsAssignableFrom(type)) return ArgType.Object; - else return ArgType.Unsupported; - } + public object GetValue(ArgType type) { + switch (type) { + case ArgType.Bool: + return boolValue; + case ArgType.Int: + return intValue; + case ArgType.Float: + return floatValue; + case ArgType.String: + return stringValue; + case ArgType.Object: + return objectValue; + default: + return null; + } + } - public static bool IsSupported(Type type) { - return FromRealType(type) != ArgType.Unsupported; + public static Type RealType(ArgType type) { + switch (type) { + case ArgType.Bool: + return typeof(bool); + case ArgType.Int: + return typeof(int); + case ArgType.Float: + return typeof(float); + case ArgType.String: + return typeof(string); + case ArgType.Object: + return typeof(Object); + default: + return null; + } + } + + public static ArgType FromRealType(Type type) { + if (type == typeof(bool)) return ArgType.Bool; + else if (type == typeof(int)) return ArgType.Int; + else if (type == typeof(float)) return ArgType.Float; + else if (type == typeof(String)) return ArgType.String; + else if (typeof(Object).IsAssignableFrom(type)) return ArgType.Object; + else return ArgType.Unsupported; + } + + public static bool IsSupported(Type type) { + return FromRealType(type) != ArgType.Unsupported; + } } } \ No newline at end of file diff --git a/Runtime/SerializableEvent.cs b/Runtime/SerializableEvent.cs index 9a65ef6..03128cd 100644 --- a/Runtime/SerializableEvent.cs +++ b/Runtime/SerializableEvent.cs @@ -1,119 +1,121 @@ -[System.Serializable] -public class SerializableEvent : SerializableEventBase { - public void Invoke() { - if (invokable == null) Cache(); - if (_dynamic) { - InvokableEvent call = invokable as InvokableEvent; - call.Invoke(); - } else { - invokable.Invoke(Args); - } - } - - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - invokable = new InvokableEvent(null, null); - } else { +namespace SerializableCallback { + [System.Serializable] + public class SerializableEvent : SerializableEventBase { + public void Invoke() { + if (invokable == null) Cache(); if (_dynamic) { - invokable = new InvokableEvent(target, methodName); + InvokableEvent call = invokable as InvokableEvent; + call.Invoke(); } else { - invokable = GetPersistentMethod(); + invokable.Invoke(Args); } } - } -} -public abstract class SerializableEvent : SerializableEventBase { - public void Invoke(T0 arg0) { - if (invokable == null) Cache(); - if (_dynamic) { - InvokableEvent call = invokable as InvokableEvent; - call.Invoke(arg0); - } else { - invokable.Invoke(Args); + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + invokable = new InvokableEvent(null, null); + } else { + if (_dynamic) { + invokable = new InvokableEvent(target, methodName); + } else { + invokable = GetPersistentMethod(); + } + } } } - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - invokable = new InvokableEvent(null, null); - } else { + public abstract class SerializableEvent : SerializableEventBase { + public void Invoke(T0 arg0) { + if (invokable == null) Cache(); if (_dynamic) { - invokable = new InvokableEvent(target, methodName); + InvokableEvent call = invokable as InvokableEvent; + call.Invoke(arg0); } else { - invokable = GetPersistentMethod(); + invokable.Invoke(Args); } } - } -} -public abstract class SerializableEvent : SerializableEventBase { - public void Invoke(T0 arg0, T1 arg1) { - if (invokable == null) Cache(); - if (_dynamic) { - InvokableEvent call = invokable as InvokableEvent; - call.Invoke(arg0, arg1); - } else { - invokable.Invoke(Args); + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + invokable = new InvokableEvent(null, null); + } else { + if (_dynamic) { + invokable = new InvokableEvent(target, methodName); + } else { + invokable = GetPersistentMethod(); + } + } } } - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - invokable = new InvokableEvent(null, null); - } else { + public abstract class SerializableEvent : SerializableEventBase { + public void Invoke(T0 arg0, T1 arg1) { + if (invokable == null) Cache(); if (_dynamic) { - invokable = new InvokableEvent(target, methodName); + InvokableEvent call = invokable as InvokableEvent; + call.Invoke(arg0, arg1); } else { - invokable = GetPersistentMethod(); + invokable.Invoke(Args); } } - } -} -public abstract class SerializableEvent : SerializableEventBase { - public void Invoke(T0 arg0, T1 arg1, T2 arg2) { - if (invokable == null) Cache(); - if (_dynamic) { - InvokableEvent call = invokable as InvokableEvent; - call.Invoke(arg0, arg1, arg2); - } else { - invokable.Invoke(Args); + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + invokable = new InvokableEvent(null, null); + } else { + if (_dynamic) { + invokable = new InvokableEvent(target, methodName); + } else { + invokable = GetPersistentMethod(); + } + } } } - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - invokable = new InvokableEvent(null, null); - } else { + public abstract class SerializableEvent : SerializableEventBase { + public void Invoke(T0 arg0, T1 arg1, T2 arg2) { + if (invokable == null) Cache(); if (_dynamic) { - invokable = new InvokableEvent(target, methodName); + InvokableEvent call = invokable as InvokableEvent; + call.Invoke(arg0, arg1, arg2); } else { - invokable = GetPersistentMethod(); + invokable.Invoke(Args); } } - } -} -public abstract class SerializableEvent : SerializableEventBase { - public void Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { - if (invokable == null) Cache(); - if (_dynamic) { - InvokableEvent call = invokable as InvokableEvent; - call.Invoke(arg0, arg1, arg2, arg3); - } else { - invokable.Invoke(Args); + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + invokable = new InvokableEvent(null, null); + } else { + if (_dynamic) { + invokable = new InvokableEvent(target, methodName); + } else { + invokable = GetPersistentMethod(); + } + } } } - protected override void Cache() { - if (_target == null || string.IsNullOrEmpty(_methodName)) { - invokable = new InvokableEvent(null, null); - } else { + public abstract class SerializableEvent : SerializableEventBase { + public void Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { + if (invokable == null) Cache(); if (_dynamic) { - invokable = new InvokableEvent(target, methodName); + InvokableEvent call = invokable as InvokableEvent; + call.Invoke(arg0, arg1, arg2, arg3); + } else { + invokable.Invoke(Args); + } + } + + protected override void Cache() { + if (_target == null || string.IsNullOrEmpty(_methodName)) { + invokable = new InvokableEvent(null, null); } else { - invokable = GetPersistentMethod(); + if (_dynamic) { + invokable = new InvokableEvent(target, methodName); + } else { + invokable = GetPersistentMethod(); + } } } } diff --git a/Runtime/SerializableEventBase.cs b/Runtime/SerializableEventBase.cs index 916d553..c1e6dff 100644 --- a/Runtime/SerializableEventBase.cs +++ b/Runtime/SerializableEventBase.cs @@ -3,38 +3,40 @@ using UnityEngine; using System; -public abstract class SerializableEventBase : SerializableCallbackBase { - public InvokableEventBase invokable; +namespace SerializableCallback { + public abstract class SerializableEventBase : SerializableCallbackBase { + public InvokableEventBase invokable; - public override void ClearCache() { - base.ClearCache(); - invokable = null; - } + public override void ClearCache() { + base.ClearCache(); + invokable = null; + } - protected InvokableEventBase GetPersistentMethod() { - Type[] types = new Type[ArgTypes.Length]; - Array.Copy(ArgTypes, types, ArgTypes.Length); + protected InvokableEventBase GetPersistentMethod() { + Type[] types = new Type[ArgTypes.Length]; + Array.Copy(ArgTypes, types, ArgTypes.Length); - Type genericType = null; - switch (types.Length) { - case 0: - genericType = typeof(InvokableEvent); - break; - case 1: - genericType = typeof(InvokableEvent<>).MakeGenericType(types); - break; - case 2: - genericType = typeof(InvokableEvent<,>).MakeGenericType(types); - break; - case 3: - genericType = typeof(InvokableEvent<, ,>).MakeGenericType(types); - break; - case 4: - genericType = typeof(InvokableEvent<, , ,>).MakeGenericType(types); - break; - default: - throw new ArgumentException(types.Length + "args"); + Type genericType = null; + switch (types.Length) { + case 0: + genericType = typeof(InvokableEvent); + break; + case 1: + genericType = typeof(InvokableEvent<>).MakeGenericType(types); + break; + case 2: + genericType = typeof(InvokableEvent<,>).MakeGenericType(types); + break; + case 3: + genericType = typeof(InvokableEvent<, ,>).MakeGenericType(types); + break; + case 4: + genericType = typeof(InvokableEvent<, , ,>).MakeGenericType(types); + break; + default: + throw new ArgumentException(types.Length + "args"); + } + return Activator.CreateInstance(genericType, new object[] { target, methodName }) as InvokableEventBase; } - return Activator.CreateInstance(genericType, new object[] { target, methodName }) as InvokableEventBase; } } \ No newline at end of file diff --git a/Runtime/Test.cs b/Runtime/Test.cs index 2c258ba..662d34b 100644 --- a/Runtime/Test.cs +++ b/Runtime/Test.cs @@ -2,79 +2,81 @@ using System.Diagnostics; using UnityEngine; -public class Test : MonoBehaviour { - const int ITERATIONS = 100000; - public float f = 0.5f; - public string s; - public System.Func RegularDelegate; - public System.Func DynamicDelegate; - public Condition condition; - public SerializableEvent ev; +namespace SerializableCallback { + public class Test : MonoBehaviour { + const int ITERATIONS = 100000; + public float f = 0.5f; + public string s; + public System.Func RegularDelegate; + public System.Func DynamicDelegate; + public Condition condition; + public SerializableEvent ev; - void Start() { - RegularDelegate = TestMethod; - DynamicDelegate = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), this, "TestMethod"); - condition.Invoke(f); - } - - void Update() { - var method = Stopwatch.StartNew(); - bool methodb = false; - for (int i = 0; i < ITERATIONS; ++i) { - methodb = TestMethod(f); + void Start() { + RegularDelegate = TestMethod; + DynamicDelegate = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), this, "TestMethod"); + condition.Invoke(f); } - method.Stop(); - var regularDelegate = Stopwatch.StartNew(); - bool regularDelegateb = false; - for (int i = 0; i < ITERATIONS; ++i) { - regularDelegateb = RegularDelegate(f); - } - regularDelegate.Stop(); + void Update() { + var method = Stopwatch.StartNew(); + bool methodb = false; + for (int i = 0; i < ITERATIONS; ++i) { + methodb = TestMethod(f); + } + method.Stop(); - var dynamicDelegate = Stopwatch.StartNew(); - bool dynamicDelegateb = false; - for (int i = 0; i < ITERATIONS; ++i) { - dynamicDelegateb = DynamicDelegate(f); - } - dynamicDelegate.Stop(); + var regularDelegate = Stopwatch.StartNew(); + bool regularDelegateb = false; + for (int i = 0; i < ITERATIONS; ++i) { + regularDelegateb = RegularDelegate(f); + } + regularDelegate.Stop(); - var serializedDelegate = Stopwatch.StartNew(); - bool serializedDelegateb = false; - for (int i = 0; i < ITERATIONS; ++i) { - serializedDelegateb = condition.Invoke(f); - } - serializedDelegate.Stop(); + var dynamicDelegate = Stopwatch.StartNew(); + bool dynamicDelegateb = false; + for (int i = 0; i < ITERATIONS; ++i) { + dynamicDelegateb = DynamicDelegate(f); + } + dynamicDelegate.Stop(); - var serializedEvent = Stopwatch.StartNew(); - for (int i = 0; i < ITERATIONS; ++i) { - ev.Invoke(); - } - serializedEvent.Stop(); + var serializedDelegate = Stopwatch.StartNew(); + bool serializedDelegateb = false; + for (int i = 0; i < ITERATIONS; ++i) { + serializedDelegateb = condition.Invoke(f); + } + serializedDelegate.Stop(); - UnityEngine.Debug.Log("Method: " + methodb + method.Elapsed); - UnityEngine.Debug.Log("RegularDelegate: " + regularDelegateb + regularDelegate.Elapsed); - UnityEngine.Debug.Log("DynamicDelegate: " + dynamicDelegateb + dynamicDelegate.Elapsed); - UnityEngine.Debug.Log("SerializedCallback: " + serializedDelegateb + serializedDelegate.Elapsed); - UnityEngine.Debug.Log("SerializedEvent: " + serializedEvent.Elapsed); - } + var serializedEvent = Stopwatch.StartNew(); + for (int i = 0; i < ITERATIONS; ++i) { + ev.Invoke(); + } + serializedEvent.Stop(); - public bool TestMethod(float f) { - return f > 0.5f; - } + UnityEngine.Debug.Log("Method: " + methodb + method.Elapsed); + UnityEngine.Debug.Log("RegularDelegate: " + regularDelegateb + regularDelegate.Elapsed); + UnityEngine.Debug.Log("DynamicDelegate: " + dynamicDelegateb + dynamicDelegate.Elapsed); + UnityEngine.Debug.Log("SerializedCallback: " + serializedDelegateb + serializedDelegate.Elapsed); + UnityEngine.Debug.Log("SerializedEvent: " + serializedEvent.Elapsed); + } - public bool TestMethod(string a) { - return string.IsNullOrEmpty(a); - } + public bool TestMethod(float f) { + return f > 0.5f; + } - public bool TestMethod2(float f, string a) { - return f > 0.5f && string.IsNullOrEmpty(a); - } + public bool TestMethod(string a) { + return string.IsNullOrEmpty(a); + } + + public bool TestMethod2(float f, string a) { + return f > 0.5f && string.IsNullOrEmpty(a); + } - public void TestMethod2(string a) { - s = a; + public void TestMethod2(string a) { + s = a; + } } -} -[Serializable] -public class Condition : SerializableCallback { } \ No newline at end of file + [Serializable] + public class Condition : SerializableCallback { } +} \ No newline at end of file