public static IEnumerable <SyntaxNode> Build( this RoslynEcsTranslator translator, RemoveComponentNodeModel model, IPortModel portModel) { var componentType = model.ComponentType.Resolve(model.GraphModel.Stencil); var entityTranslator = translator.context.GetEntityManipulationTranslator(); var entitySyntax = translator.BuildPort(model.EntityPort).SingleOrDefault() as ExpressionSyntax; return(entityTranslator.RemoveComponent(translator.context, entitySyntax, componentType)); }
public static IEnumerable <SyntaxNode> Build( this RoslynEcsTranslator translator, AddComponentNodeModel model, IPortModel portModel) { var componentType = model.ComponentType.Resolve(model.GraphModel.Stencil); var entitySyntax = translator.BuildPort(model.EntityPort).SingleOrDefault() as ExpressionSyntax; var componentInputs = model.GetPortsForComponent().ToArray(); var componentSyntax = translator.BuildComponentFromInput(componentType, componentInputs); var entityTranslator = translator.context.GetEntityManipulationTranslator(); return(entityTranslator.AddComponent(translator.context, entitySyntax, componentType, componentSyntax)); }
public static IEnumerable <SyntaxNode> Build( this RoslynEcsTranslator translator, CountEntitiesNodeModel model, IPortModel portModel) { var connected = model.InputPort.ConnectionPortModels.FirstOrDefault(); if (connected?.NodeModel is VariableNodeModel variableNode && variableNode.DeclarationModel is ComponentQueryDeclarationModel queryDeclaration) { yield return(RoslynBuilder.MethodInvocation(nameof(EntityQuery.CalculateEntityCount), SyntaxFactory.IdentifierName(queryDeclaration.VariableName), null, null)); } }
public static IEnumerable <SyntaxNode> Build(this RoslynEcsTranslator translator, SetComponentNodeModel model, IPortModel portModel) { var query = translator.context.IterationContext.Query; var queryDeclaration = query.ComponentQueryDeclarationModel; var componentTypes = model.GetComponentTypesFromEntityPort(); if (!model.ComponentType.Equals(TypeHandle.Unknown) && !componentTypes.Any(c => c == model.ComponentType)) { var componentName = model.ComponentType.Name(translator.Stencil); var queryCopy = queryDeclaration; translator.AddError( model, $"A component of type {componentName} is required, which the query {queryDeclaration.Name} " + "doesn't specify", new CompilerQuickFix( $"Add {componentName} to the query", s => s.Dispatch(new AddComponentToQueryAction( queryCopy, model.ComponentType, ComponentDefinitionFlags.None)))); return(Enumerable.Empty <SyntaxNode>()); } if (!queryDeclaration.Components.Any()) { translator.AddError(model, $"The query {queryDeclaration.Name} doesn't contain any component."); return(Enumerable.Empty <SyntaxNode>()); } if (model.ComponentType.Equals(TypeHandle.Unknown)) { translator.AddError(model, "You must select a valid component type"); return(Enumerable.Empty <SyntaxNode>()); } var entitySyntax = translator.BuildEntityFromPortOrCurrentIteration(model.EntityPort); var componentType = model.ComponentType.Resolve(model.GraphModel.Stencil); var componentInputs = model.GetPortsForComponent().ToArray(); var componentSyntax = translator.BuildComponentFromInput(componentType, componentInputs); var entityTranslator = translator.context.GetEntityManipulationTranslator(); return(entityTranslator.SetComponent(translator.context, entitySyntax, componentType, componentSyntax)); }
public static IEnumerable <SyntaxNode> BuildSetTranslation(this RoslynEcsTranslator translator, SetPositionNodeModel model, IPortModel portModel) { IPortModel entityOrComponentPort = model.InstancePort; if (!translator.GetComponentFromEntityOrComponentPort(model, entityOrComponentPort, out _, out ExpressionSyntax setValue, RoslynEcsTranslator.AccessMode.Write)) { yield break; } switch (model.Mode) { case SetPositionNodeModel.TranslationMode.Float3: yield return(RoslynBuilder.SetProperty( model.Add ? RoslynBuilder.AssignmentKind.Add : RoslynBuilder.AssignmentKind.Set, setValue, translator.BuildPort(model.GetInput(SetPositionNodeModel.InputType.Value)).FirstOrDefault() as ExpressionSyntax, nameof(Translation.Value))); break; case SetPositionNodeModel.TranslationMode.Axis: var inputTypes = new[] { Tuple.Create(SetPositionNodeModel.InputType.X, nameof(float3.x)), Tuple.Create(SetPositionNodeModel.InputType.Y, nameof(float3.y)), Tuple.Create(SetPositionNodeModel.InputType.Z, nameof(float3.z)) }; foreach (var inputType in inputTypes) { IPortModel axisPort = model.GetInput(inputType.Item1); yield return(RoslynBuilder.SetProperty( model.Add ? RoslynBuilder.AssignmentKind.Add : RoslynBuilder.AssignmentKind.Set, setValue, translator.BuildPort(axisPort).FirstOrDefault() as ExpressionSyntax, nameof(Translation.Value), inputType.Item2)); } break; } }
Type CompileGraph(CodeGenMode mode) { RoslynEcsTranslator translator = (RoslynEcsTranslator)GraphModel.CreateTranslator(); translator.AllowNoJobsFallback = false; // because of the hack in the translator constructor, override right after ((EcsStencil)Stencil).UseJobSystem = mode == CodeGenMode.Jobs; CompilationResult results = GraphModel.Compile(AssemblyType.Memory, translator, CompilationOptions.LiveEditing); if (results?.sourceCode != null && results.sourceCode.Length != 0) { LogAssert.Expect(LogType.Log, new Regex("using.*")); Debug.Log(results.sourceCode[(int)SourceCodePhases.Initial]); } Assert.That(results?.status, Is.EqualTo(CompilationStatus.Succeeded), () => $"Compilation failed, errors: {String.Join("\n", results?.errors)}"); return(EcsStencil.LiveCompileGraph(GraphModel, results, includeVscriptingAssemblies: true)); }
public static IEnumerable <SyntaxNode> BuildGetComponent(this RoslynEcsTranslator translator, GetOrCreateComponentNodeModel model, IPortModel portModel) { var entity = translator.BuildPort(model.EntityPort).First() as ExpressionSyntax; TypeSyntax componentType = TypeSystem.BuildTypeSyntax(model.ComponentType.Resolve(translator.Stencil)); yield return(InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(EntityManager)), GenericName( Identifier(model.CreateIfNeeded ? nameof(EcsHelper.GetOrCreateComponentData) : nameof(EntityManager.GetComponentData))) .WithTypeArgumentList( TypeArgumentList( SingletonSeparatedList( componentType ))))) .WithArgumentList( ArgumentList( SingletonSeparatedList( Argument( entity))))); }
public static IEnumerable <SyntaxNode> BuildInstantiateEntityTranslator(this RoslynEcsTranslator translator, InstantiateNodeModel model, IPortModel portModel) { bool hasAnyComponentInstruction = false; ExpressionSyntax newInstance = null; if (model.InstancePort.Connected) { newInstance = translator.BuildPort(model.InstancePort).SingleOrDefault() as ExpressionSyntax; hasAnyComponentInstruction = true; } // always instantiate var newEntity = InstantiateEntity(translator, model); if (hasAnyComponentInstruction) // == if connected. assignment of implicit variable is done only if it's required in the foreach loop below { yield return(RoslynBuilder.Assignment(newInstance, newEntity)); } var entityTranslator = translator.context.GetEntityManipulationTranslator(); foreach (ComponentOperation compOperation in model.GetEditableComponents()) { var componentType = compOperation.Type.Resolve(model.GraphModel.Stencil); IEnumerable <SyntaxNode> instructions; // first instruction forces the declaration of an implicit variable if not already done if (!hasAnyComponentInstruction) { hasAnyComponentInstruction = true; string entityVariableName = translator.MakeUniqueName("entity"); yield return(RoslynBuilder.DeclareLocalVariable(typeof(Entity), entityVariableName, newEntity)); newInstance = SyntaxFactory.IdentifierName(entityVariableName); } switch (compOperation.OperationType) { case ComponentOperationType.AddComponent: instructions = entityTranslator.AddComponent(translator.context, newInstance, componentType, BuildNewComponent(compOperation, componentType)); break; case ComponentOperationType.RemoveComponent: instructions = entityTranslator.RemoveComponent(translator.context, newInstance, componentType); break; case ComponentOperationType.SetComponent: instructions = entityTranslator.SetComponent(translator.context, newInstance, componentType, BuildNewComponent(compOperation, componentType)); break; default: throw new ArgumentOutOfRangeException(); } foreach (var instruction in instructions) { yield return(instruction); } } if (!hasAnyComponentInstruction) // implicit variable, never used in the loop { yield return(SyntaxFactory.ExpressionStatement(newEntity)); } ExpressionSyntax BuildNewComponent(ComponentOperation compOperation, Type componentType) { var componentInput = model.GetPortsForComponent(compOperation.Type).ToArray(); var newComponent = translator.BuildComponentFromInput(componentType, componentInput); return(newComponent); } }
public static IEnumerable <SyntaxNode> BuildOnKeyPressEcs(this RoslynEcsTranslator translator, ConditionalUpdateEntitiesNodeModel model, IPortModel portModel) { return(translator.BuildOnEntitiesEventBase(model, MakeConstraint(model))); }
public static IEnumerable <SyntaxNode> BuildSetTranslation(this RoslynEcsTranslator translator, SetRotationNodeModel model, IPortModel portModel) { ExpressionSyntax BuildPortForInput(SetRotationNodeModel.InputType inputType) { return(translator.BuildPort(model.GetInput(inputType)).FirstOrDefault() as ExpressionSyntax); } ExpressionSyntax value; switch (model.Mode) { case SetRotationNodeModel.RotationMode.Axis: var axisValue = BuildPortForInput(SetRotationNodeModel.InputType.Axis); var angleValue = BuildPortForInput(SetRotationNodeModel.InputType.Angle); axisValue = InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(math)), IdentifierName(nameof(math.normalize)))).WithArgumentList(ArgumentList(SingletonSeparatedList(Argument(axisValue)))); value = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(quaternion)), IdentifierName(nameof(quaternion.AxisAngle)))) .WithArgumentList( ArgumentList( SeparatedList(new[] { Argument(axisValue), Argument(angleValue) }))); break; case SetRotationNodeModel.RotationMode.Quaternion: value = BuildPortForInput(SetRotationNodeModel.InputType.Quaternion); break; case SetRotationNodeModel.RotationMode.Euler: value = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(quaternion)), IdentifierName(nameof(quaternion.EulerXYZ)))) .WithArgumentList( ArgumentList( SeparatedList(new[] { Argument(BuildPortForInput(SetRotationNodeModel.InputType.X)), Argument(BuildPortForInput(SetRotationNodeModel.InputType.Y)), Argument(BuildPortForInput(SetRotationNodeModel.InputType.Z)) }))); break; default: throw new ArgumentOutOfRangeException(); } if (!translator.GetComponentFromEntityOrComponentPort(model, model.InstancePort, out _, out ExpressionSyntax setValue, RoslynEcsTranslator.AccessMode.Write)) { yield break; } var finalValue = !model.Add ? value : InvocationExpression( // rot.value = math.mul(rot.value, <input>) MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(math)), IdentifierName(nameof(math.mul)))) .WithArgumentList( ArgumentList( SeparatedList(new[] { Argument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, setValue, IdentifierName(nameof(Rotation.Value)))), Argument(value) }))); yield return(RoslynBuilder.SetProperty( RoslynBuilder.AssignmentKind.Set, setValue, finalValue, nameof(Rotation.Value) )); }