Beispiel #1
0
        protected override StatementSyntax OnPopContext()
        {
            var coroutineParameterName = RoslynEcsBuilder.BuildCoroutineParameterName(m_ComponentTypeName);

            // Build Coroutine MoveNext call statement
            var block = Block();

            // Assign times fields
            block = block.AddStatements(ExpressionStatement(RoslynBuilder.Assignment(
                                                                RoslynBuilder.MemberReference(
                                                                    IdentifierName(coroutineParameterName),
                                                                    nameof(ICoroutine.DeltaTime)),
                                                                Parent.GetOrDeclareDeltaTime())));

            // Call MoveNext
            block = block.AddStatements(IfStatement(
                                            RoslynBuilder.MethodInvocation(
                                                k_MoveNext,
                                                IdentifierName(coroutineParameterName),
                                                m_Parameters.Keys,
                                                Enumerable.Empty <TypeSyntax>()),
                                            ReturnStatement()));

            // Remove component when coroutine is completed
            var removeStatement = Parent.GetEntityManipulationTranslator().RemoveComponent(
                Parent,
                IdentifierName(Parent.EntityName),
                m_ComponentTypeName);

            block = removeStatement.Aggregate(block, (current, syntax) => current.AddStatements(syntax));

            return(block);
        }
Beispiel #2
0
        static void BuildStack(RoslynTranslator translator, IStackModel stack,
                               ref Dictionary <string, FieldDeclarationSyntax> variables, ref List <SwitchSectionSyntax> states,
                               ref int stateIndex)
        {
            translator.RegisterBuiltStack(stack);

            foreach (var node in stack.NodeModels)
            {
                switch (node)
                {
                case IfConditionNodeModel _:
                    translator.AddError(node, "Coroutine (e.g. Wait) and Condition nodes can't coexist within the same stack for now. This feature is coming in a further release");
                    continue;

                case ReturnNodeModel _:
                    translator.AddError(node, "Coroutine (e.g. Wait) and Return nodes can't coexist within the same stack for now. This feature is coming in a further release");
                    continue;
                }

                var blocks = translator.BuildNode(node);
                if (node is CoroutineNodeModel coroutineNode)
                {
                    foreach (var variable in coroutineNode.Fields)
                    {
                        if (variables.ContainsKey(variable.Key))
                        {
                            continue;
                        }

                        variables.Add(variable.Key, variable.Value);
                    }

                    foreach (var block in blocks)
                    {
                        states.Add(SwitchSection()
                                   .WithLabels(
                                       SingletonList <SwitchLabelSyntax>(
                                           CaseSwitchLabel(
                                               LiteralExpression(
                                                   SyntaxKind.NumericLiteralExpression,
                                                   Literal(stateIndex)))))
                                   .WithStatements(
                                       SingletonList(block as StatementSyntax)));

                        stateIndex++;
                    }
                }
                else
                {
                    var statements = new List <StatementSyntax>();
                    foreach (var block in blocks)
                    {
                        switch (block)
                        {
                        case StatementSyntax statementNode:
                            statements.Add(statementNode);
                            break;

                        case ExpressionSyntax expressionNode:
                            statements.Add(
                                ExpressionStatement(expressionNode)
                                .WithAdditionalAnnotations(
                                    new SyntaxAnnotation(Annotations.AnnotationKind,
                                                         node.NodeAssetReference.GetInstanceID().ToString())));
                            break;

                        default:
                            throw new InvalidOperationException("Expected a statement or expression " +
                                                                $"node, found a {node.GetType()} when building {block}");
                        }
                    }

                    states.Add(SwitchSection()
                               .WithLabels(
                                   SingletonList <SwitchLabelSyntax>(
                                       CaseSwitchLabel(
                                           LiteralExpression(
                                               SyntaxKind.NumericLiteralExpression,
                                               Literal(stateIndex)))))
                               .WithStatements(
                                   SingletonList((StatementSyntax)Block(statements)
                                                 .AddStatements(
                                                     RoslynEcsBuilder.BuildCoroutineNextState(),
                                                     ReturnStatement(
                                                         LiteralExpression(SyntaxKind.TrueLiteralExpression))))));

                    stateIndex++;
                }
            }

            foreach (var outputPort in stack.OutputPorts)
            {
                foreach (var connectedStack in outputPort.ConnectionPortModels)
                {
                    if (connectedStack.NodeModel is IStackModel nextStack)
                    {
                        BuildStack(translator, nextStack, ref variables, ref states, ref stateIndex);
                    }
                }
            }
        }
 public override void DeclareComponent <T>(string componentName,
                                           IEnumerable <MemberDeclarationSyntax> members = null)
 {
     AddMember(RoslynEcsBuilder.DeclareComponent(componentName, typeof(T), members));
 }
Beispiel #4
0
        BaseTypeSyntax MakeJobBaseType(RoslynEcsTranslator.IterationContext iterationContext,
                                       ICollection <ParameterSyntax> functionParameters, out Type eventType)
        {
            var genericArguments = new List <TypeSyntax>();

            eventType = null;
            int componentCount = 0;
            int bufferCount    = 0;

            if (iterationContext.UpdateMode != UpdateMode.OnEnd)
            {
                if (iterationContext.UpdateMode == UpdateMode.OnEvent) // add DynamicBuffer<eventType>
                {
                    eventType = ((OnEventNodeModel)iterationContext.Query).EventTypeHandle.Resolve(iterationContext.Stencil);
                    var eventTypeSyntax = TypeSystem.BuildTypeSyntax(eventType);
                    var bufferType      = GenericName("DynamicBuffer")
                                          .WithTypeArgumentList(TypeArgumentList(SingletonSeparatedList(eventTypeSyntax)));
                    var parameterSyntax = Parameter(
                        Identifier(OnEventNodeModel.GetBufferName(eventType)))
                                          .WithType(bufferType);
                    AddReadOnlyAttribute(ref parameterSyntax);

                    bufferCount = 1;

                    functionParameters.Add(parameterSyntax);
                    genericArguments.Add(eventTypeSyntax);
                }

                foreach (ComponentDefinition definition in iterationContext.FlattenedComponentDefinitions()
                         .Where(def => !def.Subtract))
                {
                    if (!RoslynEcsTranslatorExtensions.ShouldGenerateComponentAccess(
                            definition.TypeHandle,
                            true,
                            out Type resolvedType,
                            iterationContext.Stencil,
                            out bool isShared,
                            out bool isGameObjectComponent) ||
                        isGameObjectComponent)
                    {
                        continue;
                    }

                    if (isShared)
                    {
                        throw new RoslynEcsTranslator.JobSystemNotCompatibleException(
                                  "Shared Components are not supported in jobs yet");
                    }

                    genericArguments.Add(TypeSystem.BuildTypeSyntax(resolvedType));
                    var parameterSyntax = Parameter(
                        Identifier(GetComponentVariableName(iterationContext.Query, definition.TypeHandle)))
                                          .WithModifiers(TokenList(Token(SyntaxKind.RefKeyword)))
                                          .WithType(TypeSystem.BuildTypeSyntax(resolvedType));
                    if (!m_WrittenComponents.Contains(definition.TypeHandle))
                    {
                        AddReadOnlyAttribute(ref parameterSyntax);
                    }
                    functionParameters.Add(
                        parameterSyntax);
                    componentCount++;
                }

                if (!string.IsNullOrEmpty(m_CoroutineComponentName))
                {
                    genericArguments.Add(ParseTypeName(m_CoroutineComponentName));
                    functionParameters.Add(Parameter(
                                               Identifier(RoslynEcsBuilder.BuildCoroutineParameterName(m_CoroutineComponentName)))
                                           .WithModifiers(TokenList(Token(SyntaxKind.RefKeyword)))
                                           .WithType(IdentifierName(m_CoroutineComponentName)));
                    componentCount++;
                }

                if (genericArguments.Count == 0)
                {
                    return(null);
                }
            }

            string CleanGenericName(string s)
            {
                var index = s.IndexOf('`');

                return(index == -1 ? s : s.Substring(0, index));
            }

            // IJobForEachWitEntity_EBBCCC
            string suffix = componentCount > 0 || bufferCount > 0
                ? $"_E{new String('B', bufferCount)}{new String('C', componentCount)}"
                : "";

            return(SimpleBaseType(
                       GenericName(
                           Identifier(CleanGenericName(typeof(IJobForEachWithEntity <>).Name) + suffix))
                       .WithTypeArgumentList(
                           TypeArgumentList(
                               SeparatedList(
                                   genericArguments)))));

            ParameterSyntax AddReadOnlyAttribute(ref ParameterSyntax parameterSyntax)
            {
                return(parameterSyntax = parameterSyntax.WithAttributeLists(
                           SingletonList(
                               AttributeList(
                                   SingletonSeparatedList(
                                       Attribute(
                                           IdentifierName(nameof(ReadOnlyAttribute))))))));
            }
        }
Beispiel #5
0
        StatementSyntax BuildInner()
        {
            const string eventBufferName = "eventBuffer";
            Type         eventType       = IterationContext.UpdateMode == UpdateMode.OnEvent
                ? ((OnEventNodeModel)IterationContext.Query).EventTypeHandle.Resolve(IterationContext.Stencil)
                : null;

            var parameters = new List <ParameterSyntax>
            {
                Parameter(
                    Identifier(EntityName))
                .WithType(typeof(Entity).ToTypeSyntax())
            };

            var block = Block();

            if (!string.IsNullOrEmpty(m_CoroutineComponentName))
            {
                parameters.Add(Parameter(
                                   Identifier(RoslynEcsBuilder.BuildCoroutineParameterName(m_CoroutineComponentName)))
                               .WithModifiers(TokenList(Token(SyntaxKind.RefKeyword)))
                               .WithType(IdentifierName(m_CoroutineComponentName)));
            }

            var stateComponentName = IterationContext.UpdateMode == UpdateMode.OnUpdate || IterationContext.UpdateMode == UpdateMode.OnEvent
                ? null
                : IncludeTrackingSystemStateComponent(IterationContext.Query.ComponentQueryDeclarationModel, IterationContext.UpdateMode == UpdateMode.OnEnd);
            var stateComponentParameterName = stateComponentName?.ToLowerInvariant();

            switch (IterationContext.UpdateMode)
            {
            case UpdateMode.OnUpdate:
                break;

            case UpdateMode.OnEvent:
                // Add it at the end

                break;

            case UpdateMode.OnStart:
                m_UpdateStatements.AddRange(GetEntityManipulationTranslator().AddComponent(
                                                this,
                                                IdentifierName(EntityName),
                                                DefaultExpression(IdentifierName(stateComponentName)),
                                                IdentifierName(stateComponentName),
                                                false));
                break;

            case UpdateMode.OnEnd:
                parameters.Add(MakeLambdaParameter(
                                   stateComponentParameterName,
                                   IdentifierName(stateComponentName),
                                   false,
                                   false));

                m_UpdateStatements.AddRange(GetEntityManipulationTranslator().RemoveComponent(
                                                this,
                                                IdentifierName(EntityName),
                                                IdentifierName(stateComponentName)));
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            // SharedComponents should be inserted first in ForEach
            var sortedComponents = IterationContext.FlattenedComponentDefinitions()
                                   .OrderBy(d =>
                                            !typeof(ISharedComponentData).IsAssignableFrom(d.TypeHandle.Resolve(IterationContext.Stencil)))
                                   .ToList();

            foreach (ComponentDefinition definition in sortedComponents)
            {
                if (!RoslynEcsTranslatorExtensions.ShouldGenerateComponentAccess(
                        definition.TypeHandle,
                        true,
                        out Type componentType,
                        IterationContext.Stencil,
                        out bool _,
                        out bool isGameObjectComponent))
                {
                    continue;
                }

                if (!m_WrittenComponents.TryGetValue(definition.TypeHandle, out RoslynEcsTranslator.AccessMode mode))
                {
                    mode = RoslynEcsTranslator.AccessMode.None;
                }

                if (mode == RoslynEcsTranslator.AccessMode.None)
                {
                    continue;
                }

                string componentDataName = IterationContext.GetComponentDataName(componentType);
                parameters.Add(MakeLambdaParameter(
                                   componentDataName,
                                   componentType.ToTypeSyntax(),
                                   isGameObjectComponent,
                                   typeof(ISharedComponentData).IsAssignableFrom(componentType)));
            }

            switch (IterationContext.UpdateMode)
            {
            case UpdateMode.OnEvent:
                parameters.Add(MakeLambdaParameter(
                                   eventBufferName,
                                   GenericName("DynamicBuffer").WithTypeArgumentList(TypeArgumentList(SingletonSeparatedList(eventType.ToTypeSyntax()))),
                                   false,
                                   true));
                break;
            }

            ExpressionSyntax baseQuery = InvocationExpression(
                MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    IdentifierName("Entities"),
                    IdentifierName("With")))
                                         .WithArgumentList(
                ArgumentList(
                    SingletonSeparatedList(
                        Argument(
                            IdentifierName(IterationContext.UpdateMode == UpdateMode.OnEvent
                                ? SendEventTranslator.MakeQueryIncludingEventName(IterationContext, eventType)
                                : IterationContext.GroupName)))));

            if (IterationContext.UpdateMode == UpdateMode.OnEnd)
            {
                // REPLACE query
                baseQuery = IdentifierName("Entities");
                m_UpdateStatements.Insert(0, IfStatement(
                                              MemberAccessExpression(
                                                  SyntaxKind.SimpleMemberAccessExpression,
                                                  IdentifierName(stateComponentParameterName),
                                                  IdentifierName("Processed")),
                                              ReturnStatement()));
            }

            BlockSyntax innerLambdaBody;

            if (IterationContext.UpdateMode == UpdateMode.OnEvent)
            {
                //for (int event_index = 0; event_index < eventBuffer.Length; event_index++) { T ev = eventBuffer[event_index]; ... }
                const string eventIndexName = "event_index";
                m_UpdateStatements.Insert(0, RoslynBuilder.DeclareLocalVariable(eventType, "ev",
                                                                                ElementAccessExpression(
                                                                                    IdentifierName(eventBufferName))
                                                                                .WithArgumentList(
                                                                                    BracketedArgumentList(
                                                                                        SingletonSeparatedList(
                                                                                            Argument(
                                                                                                IdentifierName(eventIndexName)))))
                                                                                .NormalizeWhitespace()));
                innerLambdaBody = Block(ForStatement(
                                            Block(m_UpdateStatements))
                                        .WithDeclaration(
                                            VariableDeclaration(
                                                PredefinedType(
                                                    Token(SyntaxKind.IntKeyword)))
                                            .WithVariables(
                                                SingletonSeparatedList(
                                                    VariableDeclarator(
                                                        Identifier(eventIndexName))
                                                    .WithInitializer(
                                                        EqualsValueClause(
                                                            LiteralExpression(
                                                                SyntaxKind.NumericLiteralExpression,
                                                                Literal(0)))))))
                                        .WithCondition(
                                            BinaryExpression(
                                                SyntaxKind.LessThanExpression,
                                                IdentifierName(eventIndexName),
                                                MemberAccessExpression(
                                                    SyntaxKind.SimpleMemberAccessExpression,
                                                    IdentifierName(eventBufferName),
                                                    IdentifierName("Length"))))
                                        .WithIncrementors(
                                            SingletonSeparatedList <ExpressionSyntax>(
                                                PostfixUnaryExpression(
                                                    SyntaxKind.PostIncrementExpression,
                                                    IdentifierName(eventIndexName))))
                                        .NormalizeWhitespace());
            }
            else
            {
                innerLambdaBody = Block(m_UpdateStatements);
            }

            var parenthesizedLambdaExpressionSyntax = ParenthesizedLambdaExpression(
                innerLambdaBody)
                                                      .WithParameterList(
                ParameterList().AddParameters(parameters.ToArray()));

            var updateCall = ExpressionStatement(
                InvocationExpression(
                    MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        baseQuery,
                        IdentifierName("ForEach")))
                .WithArgumentList(
                    ArgumentList(
                        SingletonSeparatedList(
                            Argument(
                                parenthesizedLambdaExpressionSyntax)))));

            if (IterationContext.UpdateMode == UpdateMode.OnEnd)
            {
                var addMissingStateComponents = ExpressionStatement(
                    InvocationExpression(
                        MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression,
                            IdentifierName("EntityManager"),
                            IdentifierName("AddComponent")))
                    .WithArgumentList(
                        ArgumentList(
                            SeparatedList(
                                new[]
                {
                    Argument(
                        IdentifierName(RootContext.GetQueryAddStateName(IterationContext.GroupName))),
                    Argument(
                        TypeOfExpression(
                            IdentifierName(stateComponentName)))
                }))));

                var foreachClearProcessed = ExpressionStatement(
                    InvocationExpression(
                        MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression,
                            IdentifierName("Entities"),
                            IdentifierName("ForEach")))
                    .WithArgumentList(
                        ArgumentList(
                            SingletonSeparatedList(
                                Argument(
                                    ParenthesizedLambdaExpression(
                                        MakeProcessed(false))
                                    .WithParameterList(
                                        ParameterList(
                                            SingletonSeparatedList(
                                                Parameter(
                                                    Identifier(stateComponentParameterName))
                                                .WithModifiers(
                                                    TokenList(
                                                        Token(SyntaxKind.RefKeyword)))
                                                .WithType(
                                                    IdentifierName(stateComponentName))))))))));
                var foreachQueryMarkProcessed = ExpressionStatement(
                    InvocationExpression(
                        MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression,
                            InvocationExpression(
                                MemberAccessExpression(
                                    SyntaxKind.SimpleMemberAccessExpression,
                                    IdentifierName("Entities"),
                                    IdentifierName("With")))
                            .WithArgumentList(
                                ArgumentList(
                                    SingletonSeparatedList(
                                        Argument(
                                            IdentifierName(IterationContext.GroupName))))),
                            IdentifierName("ForEach")))
                    .WithArgumentList(
                        ArgumentList(
                            SingletonSeparatedList(
                                Argument(
                                    ParenthesizedLambdaExpression(MakeProcessed(true))
                                    .WithParameterList(
                                        ParameterList(
                                            SeparatedList(parameters))))))));

                return(block.AddStatements(
                           addMissingStateComponents,
                           foreachClearProcessed,
                           foreachQueryMarkProcessed,
                           updateCall));
            }

            return(block.AddStatements(updateCall));

            ParameterSyntax MakeLambdaParameter(string componentDataName, TypeSyntax typeSyntax,
                                                bool isGameObjectComponent, bool isSharedComponent)
            {
                var modifiers = new List <SyntaxToken>();

                if (!isSharedComponent)
                {
                    modifiers.Add(Token(SyntaxKind.RefKeyword));
                }

                var parameterSyntax = Parameter(
                    Identifier(componentDataName))
                                      .WithType(
                    typeSyntax);

                if (!isGameObjectComponent)
                {
                    parameterSyntax = parameterSyntax
                                      .WithModifiers(TokenList(modifiers));
                }
                return(parameterSyntax);
            }

            AssignmentExpressionSyntax MakeProcessed(bool processed)
            {
                return(AssignmentExpression(
                           SyntaxKind.SimpleAssignmentExpression,
                           MemberAccessExpression(
                               SyntaxKind.SimpleMemberAccessExpression,
                               IdentifierName(stateComponentParameterName),
                               IdentifierName("Processed")),
                           LiteralExpression(processed
                        ? SyntaxKind.TrueLiteralExpression
                        : SyntaxKind.FalseLiteralExpression)));
            }
        }