A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections; 3 4namespace Unity.VisualScripting 5{ 6 /// <summary> 7 /// Loops over each element of a collection. 8 /// </summary> 9 [UnitTitle("For Each Loop")] 10 [UnitCategory("Control")] 11 [UnitOrder(10)] 12 public class ForEach : LoopUnit 13 { 14 /// <summary> 15 /// The collection over which to loop. 16 /// </summary> 17 [DoNotSerialize] 18 [PortLabelHidden] 19 public ValueInput collection { get; private set; } 20 21 /// <summary> 22 /// The current index of the loop. 23 /// </summary> 24 [DoNotSerialize] 25 [PortLabel("Index")] 26 public ValueOutput currentIndex { get; private set; } 27 28 /// <summary> 29 /// The key of the current item of the loop. 30 /// </summary> 31 [DoNotSerialize] 32 [PortLabel("Key")] 33 public ValueOutput currentKey { get; private set; } 34 35 /// <summary> 36 /// The current item of the loop. 37 /// </summary> 38 [DoNotSerialize] 39 [PortLabel("Item")] 40 public ValueOutput currentItem { get; private set; } 41 42 [Serialize] 43 [Inspectable, UnitHeaderInspectable("Dictionary")] 44 [InspectorToggleLeft] 45 public bool dictionary { get; set; } 46 47 protected override void Definition() 48 { 49 base.Definition(); 50 51 if (dictionary) 52 { 53 collection = ValueInput<IDictionary>(nameof(collection)); 54 } 55 else 56 { 57 collection = ValueInput<IEnumerable>(nameof(collection)); 58 } 59 60 currentIndex = ValueOutput<int>(nameof(currentIndex)); 61 62 if (dictionary) 63 { 64 currentKey = ValueOutput<object>(nameof(currentKey)); 65 } 66 67 currentItem = ValueOutput<object>(nameof(currentItem)); 68 69 Requirement(collection, enter); 70 Assignment(enter, currentIndex); 71 Assignment(enter, currentItem); 72 73 if (dictionary) 74 { 75 Assignment(enter, currentKey); 76 } 77 } 78 79 private int Start(Flow flow, out IEnumerator enumerator, out IDictionaryEnumerator dictionaryEnumerator, out int currentIndex) 80 { 81 if (dictionary) 82 { 83 dictionaryEnumerator = flow.GetValue<IDictionary>(collection).GetEnumerator(); 84 enumerator = dictionaryEnumerator; 85 } 86 else 87 { 88 enumerator = flow.GetValue<IEnumerable>(collection).GetEnumerator(); 89 dictionaryEnumerator = null; 90 } 91 92 currentIndex = -1; 93 94 return flow.EnterLoop(); 95 } 96 97 private bool MoveNext(Flow flow, IEnumerator enumerator, IDictionaryEnumerator dictionaryEnumerator, ref int currentIndex) 98 { 99 var result = enumerator.MoveNext(); 100 101 if (result) 102 { 103 if (dictionary) 104 { 105 flow.SetValue(currentKey, dictionaryEnumerator.Key); 106 flow.SetValue(currentItem, dictionaryEnumerator.Value); 107 } 108 else 109 { 110 flow.SetValue(currentItem, enumerator.Current); 111 } 112 113 currentIndex++; 114 115 flow.SetValue(this.currentIndex, currentIndex); 116 } 117 118 return result; 119 } 120 121 protected override ControlOutput Loop(Flow flow) 122 { 123 var loop = Start(flow, out var enumerator, out var dictionaryEnumerator, out var currentIndex); 124 125 var stack = flow.PreserveStack(); 126 127 try 128 { 129 while (flow.LoopIsNotBroken(loop) && MoveNext(flow, enumerator, dictionaryEnumerator, ref currentIndex)) 130 { 131 flow.Invoke(body); 132 133 flow.RestoreStack(stack); 134 } 135 } 136 finally 137 { 138 (enumerator as IDisposable)?.Dispose(); 139 } 140 141 flow.DisposePreservedStack(stack); 142 143 flow.ExitLoop(loop); 144 145 return exit; 146 } 147 148 protected override IEnumerator LoopCoroutine(Flow flow) 149 { 150 var loop = Start(flow, out var enumerator, out var dictionaryEnumerator, out var currentIndex); 151 152 var stack = flow.PreserveStack(); 153 154 try 155 { 156 while (flow.LoopIsNotBroken(loop) && MoveNext(flow, enumerator, dictionaryEnumerator, ref currentIndex)) 157 { 158 yield return body; 159 160 flow.RestoreStack(stack); 161 } 162 } 163 finally 164 { 165 (enumerator as IDisposable)?.Dispose(); 166 } 167 168 flow.DisposePreservedStack(stack); 169 170 flow.ExitLoop(loop); 171 172 yield return exit; 173 } 174 } 175}