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