private void UpdateBindings() { List <MethodInfo> dispmethods = new List <MethodInfo>(); List <MethodInfo> contmethods = new List <MethodInfo>(); //We'll make custom bindings for each - except if the current bindings list already has a binding that matches the name and type. List <DisplayBinding> finaldispbinds = new List <DisplayBinding>(); List <ControlBinding> finalcontbinds = new List <ControlBinding>(); //Stop if we don't have a script if (_script != null) { //Iterate through methods and assign relevant ones to bindings list MethodInfo[] methods = _scriptType.GetMethods(BindingFlags.Instance | BindingFlags.Public); for (int i = 0; i < methods.Length; i++) { //Don't do anything if it's part of MonoBehaviour, because the developer didn't add that. if (methods[i].DeclaringType.IsAssignableFrom(typeof(MonoBehaviour))) { continue; } //Assign everything into a relevant list, if there is one. if (methods[i].ReturnType == typeof(void)) { //No return type. It can fit a control. contmethods.Add(methods[i]); } else if (methods[i].GetParameters().Length == 0) { //It has a return, but takes no parameters. It's either a getter or a method made to act like one. dispmethods.Add(methods[i]); } } //Now we've got all the methods that need bindings. //Display first. foreach (MethodInfo info in dispmethods) { bool foundoldmatch = false; //Check existing bindings for both names and return types. foreach (DisplayBinding oldbinding in _console.DisplayBindingsList) { if (oldbinding.MethodName == info.Name && _scriptType.GetMethod(oldbinding.MethodName).ReturnType == info.ReturnType) { //It's a match. Pass in the old one. finaldispbinds.Add(oldbinding); foundoldmatch = true; break; } } if (foundoldmatch == false) { DisplayBinding newdisp = new DisplayBinding { MethodName = info.Name, TypeString = info.ReturnType.Name }; finaldispbinds.Add(newdisp); } } //Now Control. foreach (MethodInfo info in contmethods) { bool foundoldmatch = false; ParameterInfo[] newparams = info.GetParameters(); // Caching because we'll compare a lot. //Check existing bindings for both names and parameters. foreach (ControlBinding oldbinding in _console.ControlBindingsList) { //if (oldbinding.MethodName == info.Name && _scriptType.GetMethod(oldbinding.MethodName).GetParameters() == newparams) if (oldbinding.MethodName == info.Name) { //The names match. Make sure the parameter types match. ParameterInfo[] oldparams = _scriptType.GetMethod(oldbinding.MethodName).GetParameters(); if (newparams.Length != oldparams.Length) { continue; } bool foundbadparam = false; for (int i = 0; i < newparams.Length; i++) { if (newparams[i].ParameterType != oldparams[i].ParameterType) { foundbadparam = true; } } if (foundbadparam) { continue; } //It's a match. Pass in the old one. finalcontbinds.Add(oldbinding); foundoldmatch = true; break; } } if (foundoldmatch == false) { //Make a string that lists the parameters for easy display string paramstring = ""; for (int i = 0; i < newparams.Length; i++) { paramstring += newparams[i].ParameterType.Name; if (i < newparams.Length - 1) { paramstring += ", "; } } ControlBinding newcont = new ControlBinding { MethodName = info.Name, ParamString = paramstring }; finalcontbinds.Add(newcont); } } } //Replace the console's list with ours. _console.DisplayBindingsList = finaldispbinds; _console.ControlBindingsList = finalcontbinds; }
public override void OnInspectorGUI() { //DrawDefaultInspector(); if (_script != _lastScript) { //The script got changed, clean house. UpdateBindings(); _lastScript = _script; } //Don't allow changing the target script during runtime EditorGUI.BeginDisabledGroup(Application.isPlaying); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Target Monoscript: ", EditorStyles.boldLabel); _script = (MonoScript)EditorGUILayout.ObjectField(_script, typeof(MonoScript), false, null); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); //Target component EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Runtime Component: ", EditorStyles.boldLabel); //_console.RuntimeScript = (Component)EditorGUILayout.ObjectField(_console.RuntimeScript, _scriptType, true, null); Component newcomponent = (Component)EditorGUILayout.ObjectField(_console.RuntimeScript, _scriptType, true, null); if (newcomponent != _console.RuntimeScript) { _console.ChangeRuntimeScript(newcomponent); } //Display bindings EditorGUILayout.Space(); EditorGUILayout.LabelField("Display Properties", EditorStyles.boldLabel); for (int i = 0; i < _console.DisplayBindingsList.Count; i++) { DisplayBinding dbind = _console.DisplayBindingsList[i]; //Shorthand EditorGUILayout.BeginHorizontal(); //Figure out the BaseDisplay type Type generic = typeof(BaseDisplay <>); Type constructed = generic.MakeGenericType(new Type[1] { _scriptType.GetMethod(dbind.MethodName).ReturnType }); //This gets called most every frame, so would be nice to optimize later. EditorGUILayout.LabelField(dbind.MethodName + " <" + dbind.TypeString + ">"); //Adding type in label since the object field won't show it properly due to serialization BaseDisplay basedisp = (BaseDisplay)EditorGUILayout.ObjectField(dbind.Display, constructed, true, null); EditorGUILayout.EndHorizontal(); //If the bound object has changed, inject this binding in place of the old one. if (dbind.Display != basedisp) { DisplayBinding replacebind = new DisplayBinding { MethodName = dbind.MethodName, Display = basedisp, TypeString = dbind.TypeString }; _console.DisplayBindingsList[i] = replacebind; Debug.Log("Replaced"); } } //Control bindings EditorGUILayout.Space(); EditorGUILayout.LabelField("Control Properties/Methods", EditorStyles.boldLabel); for (int i = 0; i < _console.ControlBindingsList.Count; i++) { ControlBinding cbind = _console.ControlBindingsList[i]; //Shorthand EditorGUILayout.BeginHorizontal(); //Figure out the BaseControl type Type generic = typeof(BaseControl <>); ParameterInfo[] paramsinfo = _scriptType.GetMethod(cbind.MethodName).GetParameters(); Type newtype = (paramsinfo.Length > 0) ? paramsinfo[0].ParameterType : typeof(void); Type constructed = generic.MakeGenericType(new Type[1] { newtype }); //This gets called most every frame, so would be nice to optimize later. //WRONG fix later EditorGUILayout.LabelField(cbind.MethodName + " <" + cbind.ParamString + ">"); //Adding type in label since the object field won't show it properly due to serialization BaseControl basecont = (BaseControl)EditorGUILayout.ObjectField(cbind.Control, constructed, true, null); EditorGUILayout.EndHorizontal(); //If the bound object has changed inject this binding in place of old one. if (cbind.Control != basecont) { ControlBinding replacebind = new ControlBinding { MethodName = cbind.MethodName, Control = basecont, ParamString = cbind.ParamString }; _console.ControlBindingsList[i] = replacebind; Debug.Log("Replaced"); } } }