public override string GetOrDeclareComponentArray(RoslynEcsTranslator.IterationContext ctx, string componentTypeName, out LocalDeclarationStatementSyntax arrayInitialization, out StatementSyntax arrayDisposal) { arrayInitialization = null; arrayDisposal = null; if (m_DeclaredComponentArray.TryGetValue(componentTypeName, out var arrayName)) { return(arrayName); } arrayName = ctx.GetComponentDataArrayName(componentTypeName); m_DeclaredComponentArray.Add(componentTypeName, arrayName); var field = FieldDeclaration( VariableDeclaration( GenericName( Identifier("NativeArray")) .WithTypeArgumentList( TypeArgumentList( SingletonSeparatedList <TypeSyntax>( IdentifierName(componentTypeName))))) .WithVariables( SingletonSeparatedList( VariableDeclarator( Identifier(arrayName))))) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))); m_MemberDeclarations.Add(AddAttribute(field, nameof(DeallocateOnJobCompletionAttribute))); m_JobInitializers.Add(AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName(arrayName), RootContext.MakeInitComponentDataArrayExpression(ctx, componentTypeName) )); return(ctx.GetComponentDataArrayName(componentTypeName)); }
public JobContext(IIteratorStackModel query, RootContext parent, UpdateMode mode) : base(parent) { IterationContext = new RoslynEcsTranslator.IterationContext(this, query, parent.MakeUniqueName(query.ComponentQueryDeclarationModel.VariableName), mode); m_JobName = query is OnEventNodeModel onEventNodeModel ? parent.MakeUniqueName($"On_{onEventNodeModel.EventTypeHandle.Name(IterationContext.Stencil)}_Job") : parent.MakeUniqueName($"Update_{IterationContext.GroupName}_Job"); m_ExcludedComponents = new HashSet <TypeHandle>(query.ComponentQueryDeclarationModel.Components.Where(c => c.Component.Subtract) .Select(c => c.Component.TypeHandle)); GetOrDeclareComponentQuery(IterationContext); if ((TranslationOptions & RoslynEcsTranslator.TranslationOptions.Tracing) != 0) { m_RecorderJobFieldName = (IdentifierNameSyntax)GetCachedValue(k_RecorderWriterName, InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName($"{IterationContext.GroupName}Recorder"), IdentifierName("AsWriter"))), typeof(GraphStream.Writer).GenerateTypeHandle(this.IterationContext.Stencil)); } }
Microsoft.CodeAnalysis.SyntaxTree GenerateSyntaxTree(VSGraphModel graphModel, CompilationOptions compilationOptions, bool useJobSystem) { var ecsStencil = (EcsStencil)graphModel.Stencil; ecsStencil.ClearComponentDefinitions(); //TODO fix graph name, do not use the asset name var className = graphModel.TypeName; TranslationOptions options = TranslationOptions.None; if (useJobSystem) { options |= TranslationOptions.UseJobs; } if (!compilationOptions.HasFlag(CompilationOptions.LiveEditing)) { options |= TranslationOptions.BurstCompile; } var rootContext = new RootContext(ecsStencil, className, options); context = rootContext; List <IFunctionModel> entryPoints = GetEntryPointStacks(graphModel).ToList(); BuildSpecificStack <PreUpdate>(entryPoints, rootContext); foreach (FunctionModel stack in entryPoints.Cast <FunctionModel>().OrderBy(x => x is IOrderedStack orderedStack ? orderedStack.Order : -1)) { if (stack is PreUpdate || stack is PostUpdate) { continue; } IEnumerable <SyntaxNode> entrySyntaxNode = BuildNode(stack); foreach (var node in entrySyntaxNode) { switch (node) { case null: continue; case StatementSyntax statement: context.AddStatement(statement); break; case MemberDeclarationSyntax member: rootContext.AddMember(member); break; default: Debug.LogError($"Cannot process syntax node type {node.GetType().Name}"); break; } } } // TODO: events (see KeyDownEvent) // foreach (var statementSyntax in m_EventRegistrations) rootContext.AddStatement(statementSyntax); BuildSpecificStack <PostUpdate>(entryPoints, rootContext); var referencedNamespaces = new List <string> { "System", "Unity.Burst", "Unity.Entities", "Unity.Jobs", "Unity.Mathematics", "Unity.Transforms", "Unity.Collections", "Microsoft.CSharp", "UnityEngine", }; referencedNamespaces = referencedNamespaces.Distinct().ToList(); var usingList = new List <UsingDirectiveSyntax>(); foreach (var ns in referencedNamespaces) { string[] identifiers = ns.Split(".".ToCharArray()); if (identifiers.Length == 1) { usingList.Add(UsingDirective(IdentifierName(identifiers[0]))); } else if (identifiers.Length == 2) { usingList.Add(UsingDirective(QualifiedName(IdentifierName(identifiers[0]), IdentifierName(identifiers[1])))); } else if (identifiers.Length == 3) { usingList.Add(UsingDirective(QualifiedName( QualifiedName(IdentifierName(identifiers[0]), IdentifierName(identifiers[1])), IdentifierName(identifiers[2])))); } } CompilationUnitSyntax compilationUnit = CompilationUnit() .WithUsings( List(usingList.ToArray())) .WithMembers( SingletonList <MemberDeclarationSyntax>(rootContext.Build(this, graphModel))).NormalizeWhitespace(); return(compilationUnit.SyntaxTree); }
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))); } }