A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections; 3 4namespace Unity.VisualScripting 5{ 6 /// <summary> 7 /// Loops between a first and last index at a specified step. 8 /// </summary> 9 [UnitTitle("For Loop")] 10 [UnitCategory("Control")] 11 [UnitOrder(9)] 12 public sealed class For : LoopUnit 13 { 14 /// <summary> 15 /// The index at which to start the loop (inclusive). 16 /// </summary> 17 [PortLabel("First")] 18 [DoNotSerialize] 19 public ValueInput firstIndex { get; private set; } 20 21 /// <summary> 22 /// The index at which to end the loop (exclusive). 23 /// </summary> 24 [PortLabel("Last")] 25 [DoNotSerialize] 26 public ValueInput lastIndex { get; private set; } 27 28 /// <summary> 29 /// The value by which the index will be incremented (or decremented, if negative) after each loop. 30 /// </summary> 31 [DoNotSerialize] 32 public ValueInput step { get; private set; } 33 34 /// <summary> 35 /// The current index of the loop. 36 /// </summary> 37 [PortLabel("Index")] 38 [DoNotSerialize] 39 public ValueOutput currentIndex { get; private set; } 40 41 protected override void Definition() 42 { 43 firstIndex = ValueInput(nameof(firstIndex), 0); 44 lastIndex = ValueInput(nameof(lastIndex), 10); 45 step = ValueInput(nameof(step), 1); 46 currentIndex = ValueOutput<int>(nameof(currentIndex)); 47 base.Definition(); 48 49 Requirement(firstIndex, enter); 50 Requirement(lastIndex, enter); 51 Requirement(step, enter); 52 Assignment(enter, currentIndex); 53 } 54 55 private int Start(Flow flow, out int currentIndex, out int lastIndex, out bool ascending) 56 { 57 var firstIndex = flow.GetValue<int>(this.firstIndex); 58 lastIndex = flow.GetValue<int>(this.lastIndex); 59 ascending = firstIndex <= lastIndex; 60 currentIndex = firstIndex; 61 flow.SetValue(this.currentIndex, currentIndex); 62 63 return flow.EnterLoop(); 64 } 65 66 private bool CanMoveNext(int currentIndex, int lastIndex, bool ascending) 67 { 68 if (ascending) 69 { 70 return currentIndex < lastIndex; 71 } 72 else 73 { 74 return currentIndex > lastIndex; 75 } 76 } 77 78 private void MoveNext(Flow flow, ref int currentIndex) 79 { 80 currentIndex += flow.GetValue<int>(step); 81 flow.SetValue(this.currentIndex, currentIndex); 82 } 83 84 protected override ControlOutput Loop(Flow flow) 85 { 86 var loop = Start(flow, out int currentIndex, out int lastIndex, out bool ascending); 87 88 if (!IsStepValueZero()) 89 { 90 var stack = flow.PreserveStack(); 91 92 while (flow.LoopIsNotBroken(loop) && CanMoveNext(currentIndex, lastIndex, ascending)) 93 { 94 flow.Invoke(body); 95 96 flow.RestoreStack(stack); 97 98 MoveNext(flow, ref currentIndex); 99 } 100 101 flow.DisposePreservedStack(stack); 102 } 103 104 flow.ExitLoop(loop); 105 106 return exit; 107 } 108 109 protected override IEnumerator LoopCoroutine(Flow flow) 110 { 111 var loop = Start(flow, out int currentIndex, out int lastIndex, out bool ascending); 112 113 var stack = flow.PreserveStack(); 114 115 while (flow.LoopIsNotBroken(loop) && CanMoveNext(currentIndex, lastIndex, ascending)) 116 { 117 yield return body; 118 119 flow.RestoreStack(stack); 120 121 MoveNext(flow, ref currentIndex); 122 } 123 124 flow.DisposePreservedStack(stack); 125 126 flow.ExitLoop(loop); 127 128 yield return exit; 129 } 130 131 public bool IsStepValueZero() 132 { 133 var isDefaultZero = !step.hasValidConnection && (int)defaultValues[step.key] == 0; 134 var isConnectedToLiteralZero = false; 135 136 if (step.hasValidConnection && step.connection.source.unit is Literal literal) 137 { 138 if (Convert.ToInt32(literal.value) == 0) 139 { 140 isConnectedToLiteralZero = true; 141 } 142 } 143 144 return isDefaultZero || isConnectedToLiteralZero; 145 } 146 } 147}