NodeCanvas Forums › Support › Iterate gets stuck when list Is changed › Reply To: Iterate gets stuck when list Is changed
This is the iterator as we are currently using it.
Note:
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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
[Name("Iterate Interface List")] [Category("Decorators/Custom")] [Description("Enables to iterate any generic type of interface list and execute the child node for each element in the list. Keeps iterating until the Termination Condition is met or the whole list is iterated, in which case the last interation's child status is returned.")] [Icon("List")] public class CustomIterator : BTDecorator { public enum TerminationConditions { None, FirstSuccess, FirstFailure } [RequiredField] [BlackboardOnly] [Tooltip("The list to iterate")] public BBParameter targetList; [BlackboardOnly] [Name("Current Element")] [Tooltip("Store the current element")] public BBObjectParameter current; [BlackboardOnly] [Name("Current Index")] [Tooltip("Store the current index")] public BBParameter storeIndex; [Tooltip("The maximum count of iterations. Leave at -1 to iterate the whole list")] public BBParameter maxIteration = -1; [Tooltip("The condition when to terminate the iteration and return status")] public TerminationConditions terminationCondition = TerminationConditions.None; [Tooltip("Should the iteration start from the begining after a node reset?")] public bool resetIndexOnReset = true; [Tooltip("Should the iteration start from the begining after end of iteration has been reached?")] public bool resetIndexAfterIteration = true; private int currentIndex; private IList list { get { return targetList != null ? targetList.value : null; } } protected override Status OnExecute(Component agent, IBlackboard blackboard) { if ( decoratedConnection == null ) { return Status.Optional; } if ( list == null || list.Count == 0 ) { return Status.Failure; } if ( currentIndex > list.Count - 1 || (maxIteration.value>=0 && currentIndex > maxIteration.value - 1) ) { if ( resetIndexAfterIteration ) { currentIndex = 0; } } for ( var i = currentIndex; i < list.Count; i++ ) { current.value = list<em class="d4pbbc-italic"></em>; storeIndex.value = i; status = decoratedConnection.Execute(agent, blackboard); if ( status == Status.Success && terminationCondition == TerminationConditions.FirstSuccess ) { return Status.Success; } if ( status == Status.Failure && terminationCondition == TerminationConditions.FirstFailure ) { return Status.Failure; } if ( status == Status.Running ) { currentIndex = i; return Status.Running; } if ( currentIndex >= list.Count - 1 || (maxIteration.value>=0 && currentIndex >= maxIteration.value - 1) ) { if ( resetIndexAfterIteration ) { currentIndex = 0; } return status; } decoratedConnection.Reset(); currentIndex++; } return Status.Running; } protected override void OnReset() { if ( resetIndexOnReset ) { currentIndex = 0; } } //////////////////////////////////////// ///////////GUI AND EDITOR STUFF///////// //////////////////////////////////////// #if UNITY_EDITOR protected override void OnNodeGUI() { var leftLabelStyle = new GUIStyle(GUI.skin.GetStyle("label")); leftLabelStyle.richText = true; leftLabelStyle.alignment = TextAnchor.UpperLeft; GUILayout.Label("Anakin For Each " + current + "\nIn \t" + targetList, leftLabelStyle); if ( terminationCondition != TerminationConditions.None ) GUILayout.Label("Break on " + terminationCondition.ToString()); if ( Application.isPlaying ) GUILayout.Label("Index: " + currentIndex.ToString() + " / " + ( list != null && list.Count != 0 ? ( list.Count - 1 ).ToString() : "?" )); } protected override void OnNodeInspectorGUI() { DrawDefaultInspector(); if ( GUI.changed ) { var argType = targetList.refType != null ? GetEnumerableElementType(targetList.refType) : null; if ( current.varType != argType ) { current.SetType(argType); } } } public static Type GetEnumerableElementType(Type type) { if ( type == null ) { return null; } if ( !typeof(IEnumerable).RTIsAssignableFrom(type) ) { return null; } if ( type.HasElementType || type.RTIsArray() ) { return type.GetElementType(); } if ( type.RTIsGenericType() ) { //These are not exactly correct, but serve the purpose of usage. var args = type.RTGetGenericArguments(); if ( args.Length == 1 ) { return args[0]; } //This is special. We only support Dictionary<string, T> and always consider 1st arg to be string. if ( args.Length == 2 ) { return args[1]; } } var interfaces = type.GetInterfaces(); for (var i = 0; i < interfaces.Length; i++){ var iface = interfaces<em class="d4pbbc-italic"></em>; if (!iface.RTIsGenericType()){ continue; } var genType = iface.GetGenericTypeDefinition(); if (genType != typeof(IEnumerable<>)){ continue; } return iface.RTGetGenericArguments()[0]; } return null; } #endif } |