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()); }
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)); }
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); }