Пример #1
0
        StatementSyntax MakeJobSchedulingStatement()
        {
            var jobCreationExpression = ObjectCreationExpression(
                IdentifierName(m_JobName))
                                        .WithArgumentList(ArgumentList())
                                        .WithInitializer(InitializerExpression(SyntaxKind.ObjectInitializerExpression,
                                                                               SeparatedList(m_JobInitializers)));
            var iterationContextGroupName = IterationContext.UpdateMode == UpdateMode.OnEvent
                ? SendEventTranslator.MakeQueryIncludingEventName(IterationContext, ((OnEventNodeModel)IterationContext.Query).EventTypeHandle.Resolve(IterationContext.Stencil))
                : IterationContext.GroupName;

            return(ExpressionStatement(
                       AssignmentExpression(
                           SyntaxKind.SimpleAssignmentExpression,
                           IdentifierName(RoslynEcsTranslator.InputDeps),
                           InvocationExpression(
                               MemberAccessExpression(
                                   SyntaxKind.SimpleMemberAccessExpression,
                                   IdentifierName(nameof(JobForEachExtensions)),
                                   IdentifierName(m_ScheduleSingleThreaded ? nameof(JobForEachExtensions.ScheduleSingle) : nameof(JobForEachExtensions.Schedule))))
                           .WithArgumentList(
                               ArgumentList(
                                   SeparatedList(
                                       new[]
            {
                Argument(jobCreationExpression),
                Argument(IdentifierName(iterationContextGroupName)),
                Argument(IdentifierName(RoslynEcsTranslator.InputDeps))
            })))))
                   .NormalizeWhitespace());
        }
Пример #2
0
        public override ExpressionSyntax GetEventBufferWriter(RoslynEcsTranslator.IterationContext iterationContext, ExpressionSyntax entity, Type eventType, out StatementSyntax bufferInitialization)
        {
            GetEventSystem(iterationContext, eventType);
            var bufferVariableName            = SendEventTranslator.GetBufferVariableName(iterationContext, eventType);
            var buffersFromEntityVariableName = bufferVariableName + "s";
            var cmdBuffer = GetOrDeclareCommandBuffer(true);

            bufferInitialization = RoslynBuilder.DeclareLocalVariable((Type)null, bufferVariableName, variableDeclarationType: RoslynBuilder.VariableDeclarationType.InferredType, initValue: ConditionalExpression(
                                                                          InvocationExpression(
                                                                              MemberAccessExpression(
                                                                                  SyntaxKind.SimpleMemberAccessExpression,
                                                                                  IdentifierName(buffersFromEntityVariableName),
                                                                                  IdentifierName("Exists")))
                                                                          .WithArgumentList(
                                                                              ArgumentList(
                                                                                  SingletonSeparatedList(
                                                                                      Argument(
                                                                                          IdentifierName(EntityName))))),
                                                                          ElementAccessExpression(
                                                                              IdentifierName(buffersFromEntityVariableName))
                                                                          .WithArgumentList(
                                                                              BracketedArgumentList(
                                                                                  SingletonSeparatedList(
                                                                                      Argument(
                                                                                          IdentifierName(EntityName))))),
                                                                          InvocationExpression(
                                                                              MemberAccessExpression(
                                                                                  SyntaxKind.SimpleMemberAccessExpression,
                                                                                  cmdBuffer,
                                                                                  GenericName(
                                                                                      Identifier(nameof(EntityCommandBuffer.AddBuffer)))
                                                                                  .WithTypeArgumentList(
                                                                                      TypeArgumentList(
                                                                                          SingletonSeparatedList <TypeSyntax>(
                                                                                              eventType.ToTypeSyntax())))))
                                                                          .WithArgumentList(
                                                                              ArgumentList(
                                                                                  SeparatedList <ArgumentSyntax>(
                                                                                      new SyntaxNodeOrToken[] {
                Argument(
                    IdentifierName(GetJobIndexParameterName())),
                Token(SyntaxKind.CommaToken),
                Argument(
                    IdentifierName(EntityName))
            })))));
            GetCachedValue(buffersFromEntityVariableName,
                           InvocationExpression(
                               GenericName(
                                   Identifier(nameof(JobComponentSystem.GetBufferFromEntity)))
                               .WithTypeArgumentList(
                                   TypeArgumentList(
                                       SingletonSeparatedList(
                                           eventType.ToTypeSyntax())))),
                           typeof(BufferFromEntity <>).MakeGenericType(eventType).GenerateTypeHandle(iterationContext.Stencil));

            // The BufferFromEntity<EventStruct> is not parallel-write safe. We might have multiple iterations sending
            // events to the same separate entity, so we run the job on a single thread to be safe
            m_ScheduleSingleThreaded = true;
            return(IdentifierName(bufferVariableName));
        }
        protected override StatementSyntax AddMissingEventBuffers(RoslynEcsTranslator.IterationContext iterationContext, StatementSyntax onPopContext)
        {
            BlockSyntax b      = onPopContext is BlockSyntax bl ? bl : Block(onPopContext);
            var         before = new List <StatementSyntax>();

            foreach (Type eventType in iterationContext.WrittenEventTypes)
            {
                // ClearEvents<EventType>.AddMissingBuffers(<target query>, EntityManager);
                before.Add(ExpressionStatement(
                               InvocationExpression(
                                   MemberAccessExpression(
                                       SyntaxKind.SimpleMemberAccessExpression,
                                       GenericName(
                                           Identifier("EventSystem"))
                                       .WithTypeArgumentList(
                                           TypeArgumentList(
                                               SingletonSeparatedList(
                                                   eventType.ToTypeSyntax()))),
                                       IdentifierName("AddMissingBuffers")))
                               .WithArgumentList(
                                   ArgumentList(
                                       SeparatedList(
                                           new[]
                {
                    Argument(IdentifierName("Entities")),
                    Argument(IdentifierName(SendEventTranslator.MakeMissingEventQueryName(iterationContext, eventType))),
                    Argument(IdentifierName("EntityManager"))
                })))));
            }

            b = b.WithStatements(b.Statements.InsertRange(0, before));
            return(b);
        }
        public override IdentifierNameSyntax GetEventBufferWriter(RoslynEcsTranslator.IterationContext iterationContext, ExpressionSyntax entity, Type eventType, out StatementSyntax bufferInitialization)
        {
            bufferInitialization = null;
            var bufferVariableName = SendEventTranslator.GetBufferVariableName(iterationContext, eventType);

            iterationContext.WrittenEventTypes.Add(eventType);
            if (GetEventSystem(iterationContext, eventType))
            {
                // var buffer = EntityManager.GetBuffer<EventType>(entity);
                var bufferInitValue = InvocationExpression(
                    MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        IdentifierName("EntityManager"),
                        GenericName(
                            Identifier("GetBuffer"))
                        .WithTypeArgumentList(
                            TypeArgumentList(
                                SingletonSeparatedList(
                                    eventType.ToTypeSyntax())))))
                                      .WithArgumentList(
                    ArgumentList(
                        SingletonSeparatedList(
                            Argument(entity)
                            )
                        )
                    );
                bufferInitialization = RoslynBuilder.DeclareLocalVariable((Type)null, bufferVariableName, bufferInitValue, RoslynBuilder.VariableDeclarationType.InferredType);
            }
            return(IdentifierName(bufferVariableName));
        }
Пример #5
0
        StatementSyntax BuildInner()
        {
            const string eventBufferName = "eventBuffer";
            Type         eventType       = IterationContext.UpdateMode == UpdateMode.OnEvent
                ? ((OnEventNodeModel)IterationContext.Query).EventTypeHandle.Resolve(IterationContext.Stencil)
                : null;

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

            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]; ... }
                var 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 <VariableDeclaratorSyntax>(
                                                    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(
                           addMissingStateComponents,
                           foreachClearProcessed,
                           foreachQueryMarkProcessed,
                           updateCall
                           ));
            }

            return(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)));
            }
        }
        static IEnumerable <(string, IEnumerable <ArgumentSyntax>)> BuildQueries(
            PerGroupCtxComponents ctx,
            IReadOnlyDictionary <ComponentQueryDeclarationModel, QueryStateComponent> queryHasStateTracking,
            IReadOnlyDictionary <RoslynEcsTranslator.IterationContext, string> coroutineComponents,
            IEnumerable <ArgumentSyntax> arguments,
            string contextGroupName)
        {
            IEnumerable <ArgumentSyntax> PrependComponentToArguments(string name, string methodName)
            {
                return(Enumerable.Repeat(ComponentTypeDeclarationSyntax(IdentifierName(name), methodName), 1)
                       .Concat(arguments));
            }

            IEnumerable <ArgumentSyntax> PrependComponentFromTypeToArguments(Type t, string methodName)
            {
                return(Enumerable.Repeat(ComponentTypeDeclarationSyntax(t.ToTypeSyntax(), methodName), 1)
                       .Concat(arguments));
            }

            if (ctx.Context.Query is IPrivateIteratorStackModel updateMatching)
            {
                if (updateMatching.Mode == UpdateMode.OnEvent)
                {
                    var eventType = ((OnEventNodeModel)updateMatching).EventTypeHandle.Resolve(updateMatching.GraphModel.Stencil);
                    yield return(SendEventTranslator.MakeQueryIncludingEventName(ctx.Context, eventType),
                                 PrependComponentFromTypeToArguments(
                                     eventType, nameof(ComponentType.ReadOnly)));
                }

                var queryModel = ctx.Context.Query.ComponentQueryDeclarationModel;
                if (queryHasStateTracking.TryGetValue(queryModel, out var trackingComponent))
                {
                    string methodName = null;
                    switch (updateMatching.Mode)
                    {
                    case UpdateMode.OnUpdate:
                    case UpdateMode.OnEvent:
                        methodName = nameof(ComponentType.ReadWrite);
                        break;

                    case UpdateMode.OnStart:
                        methodName = nameof(ComponentType.Exclude);
                        break;

                    case UpdateMode.OnEnd:
                        yield return(GetQueryAddStateName(contextGroupName),
                                     PrependComponentToArguments(
                                         trackingComponent.ComponentName,
                                         nameof(ComponentType.Exclude)));

                        methodName = nameof(ComponentType.ReadOnly);
                        break;
                    }

                    arguments = PrependComponentToArguments(trackingComponent.ComponentName, methodName);
                }

                // query_MissingEvents is only used in non-jobs context
                if ((ctx.Context.TranslationOptions & RoslynEcsTranslator.TranslationOptions.UseJobs) == 0)
                {
                    foreach (Type eventType in ctx.WrittenEvents)
                    {
                        yield return(SendEventTranslator.MakeMissingEventQueryName(ctx.Context, eventType),
                                     PrependComponentFromTypeToArguments(
                                         eventType, nameof(ComponentType.Exclude)));
                    }
                }
            }

            if (coroutineComponents.TryGetValue(ctx.Context, out var coroutine))
            {
                yield return(CoroutineTranslator.MakeExcludeCoroutineQueryName(ctx.Context),
                             PrependComponentToArguments(coroutine, nameof(ComponentType.Exclude)));

                arguments = PrependComponentToArguments(coroutine, nameof(ComponentType.ReadWrite));
            }

            yield return(contextGroupName, arguments);
        }