NodeCanvas Forums › Custom Nodes & Tasks › GetField from arbitrary value, not just scripts
Hello
I’ve created an action to read a field from a variable of arbitrary type, not just scripts (MonoBehaviour’s) into a blackboard variable.
One for reading a property is very similar.
Handles the case of transforming an array to a BB list parameter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using NodeCanvas.Framework; using NodeCanvas.Framework.Internal; using ParadoxNotion; using ParadoxNotion.Design; using UnityEngine; namespace NodeCanvas.Tasks.Actions { [Category("✫ Blackboard")] [Description("Copy the value of a member to a blackboard variable")] public class GetFieldFromValue : ActionTask { [SerializeField] BBObjectParameter from; [SerializeField] string fieldName; [SerializeField] [BlackboardOnly] BBObjectParameter saveAs; FieldInfo field; bool arrayToList; MethodInfo collectionClear; MethodInfo collectionAdd; protected override string info { get { if (string.IsNullOrEmpty(fieldName)) return "No Field Selected"; return string.Format("{0} = {1}.{2}", saveAs.ToString(), from.ToString(), fieldName); } } protected override string OnInit() { if (from.value == null) return "No input value"; field = from.varType.RTGetField(fieldName); if (field == null) return "Missing Field: " + fieldName; if (arrayToList = field.FieldType.IsArray) { var elementType = field.FieldType.GetElementType(); var collectionType = typeof(ICollection<>).RTMakeGenericType(elementType); collectionClear = collectionType.GetMethod("Clear"); collectionAdd = collectionType.GetMethod("Add"); } return null; } protected override void OnExecute() { if (arrayToList) { collectionClear.Invoke(saveAs.value, null); var arr = field.GetValue(from.value) as Array; if (arr != null && arr.Length > 0) { var args = new System.Object[1]; foreach (var item in arr) { args[0] = item; collectionAdd.Invoke(saveAs.value, args); } } } else { saveAs.value = field.GetValue(from.value); } EndAction(); } //////////////////////////////////////// ///////////GUI AND EDITOR STUFF///////// //////////////////////////////////////// #if UNITY_EDITOR protected override void OnTaskInspectorGUI() { if (!Application.isPlaying && GUILayout.Button("Select Field")) { System.Action<FieldInfo> FieldSelected = (field) => { from.SetType(field.DeclaringType); fieldName = field.Name; var targetType = field.FieldType; if (targetType.IsArray) targetType = typeof(List<>).RTMakeGenericType(targetType.GetElementType()); saveAs.SetType(targetType); }; var menu = new UnityEditor.GenericMenu(); foreach (var t in UserTypePrefs.GetPreferedTypesList(typeof(System.Object), true)) menu = EditorUtils.GetFieldSelectionMenu(t, typeof(object), FieldSelected, menu); if (Editor.NCPrefs.useBrowser) menu.ShowAsBrowser("Select Field", GetType()); else menu.ShowAsContext(); Event.current.Use(); } if (!string.IsNullOrEmpty(fieldName)) { GUILayout.BeginVertical("box"); UnityEditor.EditorGUILayout.LabelField("Type", from.varType.FriendlyName()); UnityEditor.EditorGUILayout.LabelField("Field", fieldName); UnityEditor.EditorGUILayout.LabelField("Field Type", saveAs.varType.FriendlyName()); GUILayout.EndVertical(); EditorUtils.BBParameterField("From", from, false); EditorUtils.BBParameterField("Save As", saveAs, true); } } #endif } } |
That’s great!
Thanks a lot for sharing! 🙂
Join us on Discord: https://discord.gg/97q2Rjh
oops, a bug slipped through…
line 81 should be:
saveAs.value = field.GetValue(from.value);