void BuildCoroutineNode(CoroutineNodeModel node, RoslynEcsTranslator translator, ref int currentIndex) { foreach (var variable in node.Fields.Where(v => !m_ComponentVariables.ContainsKey(v.Key))) { m_ComponentVariables.Add(variable.Key, variable.Value); } // Coroutine initialization state var initState = m_States[currentIndex]; initState.Statements.AddRange(CoroutineTranslator.BuildInitState(node, translator)); var nextStateIndex = initState.NextStateIndex; initState.NextStateIndex = m_States.Count; // Coroutine update state var updateState = RequestNewState(); updateState.SkipStateBuilding = true; var hasNextNode = node.ParentStackModel.NodeModels.Last() != node; var nextStack = GetNextStack(node.ParentStackModel); int nextIndex; if (hasNextNode || nextStack != null && !m_StackIndexes.ContainsKey(nextStack)) { nextIndex = m_States.Count; var newState = RequestNewState(); newState.NextStateIndex = nextStateIndex; } else { nextIndex = nextStateIndex == 0 ? m_States.Count : nextStateIndex; } node.NextStateIndex = nextIndex; updateState.Statements.AddRange(translator.BuildNode(node).Cast <StatementSyntax>()); currentIndex = GetCurrentStateIndex(); }
void BuildIfConditionNode(IfConditionNodeModel node, RoslynEcsTranslator translator, int stateIndex) { translator.BuildNode(node); var firstThenStack = RoslynTranslator.GetConnectedStack(node, 0); var firstElseStack = RoslynTranslator.GetConnectedStack(node, 1); var ifState = m_States[stateIndex]; var ifIndex = GetCurrentStateIndex(); var endStackIndex = 0; if (translator.EndStack != null) { m_StackIndexes.TryGetValue(translator.EndStack, out endStackIndex); } // Reserve then/else/complete states first var thenIndex = ifIndex; var thenBlock = Block().AddStatements(ReturnStatement(LiteralExpression(SyntaxKind.FalseLiteralExpression))); StateData thenState = null; if (firstThenStack != null) { if (firstThenStack == translator.EndStack && endStackIndex != 0) { thenBlock = Block().AddStatements(BuildGoToState(endStackIndex)); } else { thenIndex += 1; thenState = RequestNewState(); TryAddStackIndex(firstThenStack, thenIndex); thenBlock = Block().AddStatements(BuildGoToState(thenIndex)); } } var elseIndex = thenIndex + 1; var elseBlock = Block().AddStatements(ReturnStatement(LiteralExpression(SyntaxKind.FalseLiteralExpression))); StateData elseState = null; if (firstElseStack != null) { if (firstElseStack == translator.EndStack && endStackIndex != 0) { elseBlock = Block().AddStatements(BuildGoToState(endStackIndex)); } else { elseState = RequestNewState(); TryAddStackIndex(firstElseStack, elseIndex); elseBlock = Block().AddStatements(BuildGoToState(elseIndex)); } } // Then Build stacks ifState.Statements.Add(RoslynBuilder.IfStatement( translator.BuildPort(node.IfPort).SingleOrDefault(), thenBlock, elseBlock) .WithAdditionalAnnotations( new SyntaxAnnotation(Annotations.VSNodeMetadata, node.Guid.ToString()))); ifState.Statements.Add(ReturnStatement(LiteralExpression(SyntaxKind.TrueLiteralExpression))); ifState.SkipStateBuilding = true; var reserveEndStackState = translator.EndStack != null && translator.EndStack != firstElseStack && translator.EndStack != firstThenStack && endStackIndex == 0; if (reserveEndStackState) { var endState = RequestNewState(); endState.NextStateIndex = GetNextStateIndex(translator.EndStack); TryAddStackIndex(translator.EndStack, GetCurrentStateIndex()); } var origBuiltStacks = translator.BuiltStacks; translator.BuiltStacks = new HashSet <IStackModel>(origBuiltStacks); if (translator.EndStack != firstThenStack) { if (translator.EndStack != null && thenState != null) { thenState.NextStateIndex = m_StackIndexes[translator.EndStack]; } BuildStack(translator, firstThenStack, thenIndex, StackExitStrategy.Inherit); } var partialStacks = translator.BuiltStacks; translator.BuiltStacks = new HashSet <IStackModel>(origBuiltStacks); if (translator.EndStack != firstElseStack) { if (translator.EndStack != null && elseState != null) { elseState.NextStateIndex = m_StackIndexes[translator.EndStack]; } BuildStack(translator, firstElseStack, elseIndex, StackExitStrategy.Inherit); } translator.BuiltStacks.UnionWith(partialStacks); }
protected void BuildStack(RoslynEcsTranslator translator, IStackModel stack, int currentStateIndex, StackExitStrategy exitStrategy = StackExitStrategy.Return) { if (stack == null || stack.State == ModelState.Disabled) { return; } translator.RegisterBuiltStack(stack); if (m_StackIndexes.TryGetValue(stack, out var endStackIndex)) { currentStateIndex = endStackIndex; } // JUST in case... until we validate the previous failsafe if (m_BuiltStackCounter++ > 10000) { throw new InvalidOperationException("Infinite loop while building the script, aborting"); } var origStackExitStrategy = m_StackExitStrategy; if (exitStrategy != StackExitStrategy.Inherit) { m_StackExitStrategy = exitStrategy; } if (m_States.Count == 0) { var state = RequestNewState(); state.NextStateIndex = GetCurrentStateIndex(); } var origEndStack = translator.EndStack; foreach (var node in stack.NodeModels) { if (node.State == ModelState.Disabled) { continue; } switch (node) { case CoroutineNodeModel coroutineNode: BuildCoroutineNode(coroutineNode, translator, ref currentStateIndex); continue; case IfConditionNodeModel ifConditionNodeModel: BuildIfConditionNode(ifConditionNodeModel, translator, currentStateIndex); continue; default: { var blocks = translator.BuildNode(node); var currentState = m_States[currentStateIndex]; currentState.SkipStateBuilding = currentState.SkipStateBuilding || SkipStateBuilding; currentState.Statements.AddRange(ConvertNodesToSyntaxList(node, blocks, translator.Options)); if (!SkipStateBuilding && stack.NodeModels.Last() == node && !HasConnectedStack(stack)) { currentState.SkipStateBuilding = true; currentState.Statements.Add(ReturnStatement( LiteralExpression(SyntaxKind.FalseLiteralExpression))); } SkipStateBuilding = false; break; } } } if (stack.DelegatesOutputsToNode(out _)) { var nextStack = translator.EndStack; m_StackExitStrategy = origStackExitStrategy; if (translator.EndStack == origEndStack) { return; } translator.EndStack = origEndStack; if (nextStack != null) { BuildStack(translator, nextStack, m_StackIndexes[nextStack], exitStrategy); } return; } foreach (var outputPort in stack.OutputPorts) { foreach (var connectedStack in outputPort.ConnectionPortModels) { if (connectedStack.NodeModel is IStackModel nextStack) { if (!ReferenceEquals(nextStack, translator.EndStack)) { BuildStack(translator, nextStack, currentStateIndex, exitStrategy); } } } } m_StackExitStrategy = origStackExitStrategy; }