Example #1
0
        static void CheckValidity(AuthoringComponent authoringComponent)
        {
            switch (authoringComponent.Interface)
            {
            case AuthoringComponentInterface.IComponentData:
                if (authoringComponent.FromValueType &&
                    authoringComponent.FieldDescriptions.Any(d => d.FieldType == FieldType.EntityArray))
                {
                    throw new ArgumentException(
                              "Invalid use of Entity[] in a struct: IComponentData structs cannot contain managed types." +
                              "Either use an array that works in IComponentData structs (DynamicBuffer) or a IComponentData class.");
                }
                break;

            case AuthoringComponentInterface.IBufferElementData:
                if (!authoringComponent.FromValueType)
                {
                    throw new ArgumentException("IBufferElementData types must be structs.");
                }

                if (authoringComponent.FieldDescriptions.Any(d => d.FieldType == FieldType.NonEntityReferenceType || d.FieldType == FieldType.EntityArray))
                {
                    throw new ArgumentException("IBufferElementData types may only contain blittable or primitive fields.");
                }
                break;

            default:
                throw new ArgumentOutOfRangeException(
                          "The [GenerateAuthoringComponent] attribute may only be used with types " +
                          "that implement either IBufferElementData or IComponentData.");
            }
        }
Example #2
0
        private static string CreateDeclareReferencedPrefabsMethodBody(AuthoringComponent authoringComponent)
        {
            var methodBody = new StringBuilder();

            foreach (AuthoringComponentFieldDescription description in authoringComponent.FieldDescriptions)
            {
                switch (description.FieldType)
                {
                case FieldType.SingleEntity:
                    methodBody.AppendLine(
                        $@"Unity.Entities.Hybrid.Internal.GeneratedAuthoringComponentImplementation.AddReferencedPrefab(
                                   __referencedPrefabs, 
                                   {description.FieldSymbol.Name});");
                    break;

                case FieldType.EntityArray:
                    methodBody.AppendLine(
                        $@"Unity.Entities.Hybrid.Internal.GeneratedAuthoringComponentImplementation.AddReferencedPrefabs(
                                   __referencedPrefabs, 
                                   {description.FieldSymbol.Name});");
                    break;
                }
            }

            return(methodBody.ToString());
        }
Example #3
0
 static string GenerateBufferElementDataFieldAssignments(AuthoringComponent authoringComponent)
 {
     if (authoringComponent.FieldDescriptions.Count() > 1)
     {
         return(authoringComponent.FieldDescriptions.Select(description =>
         {
             string fieldName = description.FieldSymbol.Name;
             return $"{fieldName} = Values[i].{fieldName}";
         }).SeparateByCommaAndNewLine());
     }
     return($"{authoringComponent.FieldDescriptions.Single().FieldSymbol.Name} = Values[i]");
 }
Example #4
0
        internal static ClassDeclarationSyntax GenerateBufferingElementDataAuthoring(AuthoringComponent authoringComponent)
        {
            bool exactlyOneField = authoringComponent.FieldDescriptions.Count() == 1;

            if (exactlyOneField)
            {
                return(GenerateBufferingElementDataAuthoringClass(authoringComponent, authoringComponent.FieldDescriptions.Single().FieldSymbol.Type.ToString()));
            }

            string generatedStructName = $"___{authoringComponent.DeclaringType.Name}GeneratedStruct___";

            return(GenerateBufferingElementDataAuthoringClass(authoringComponent, generatedStructName, hasNestedGeneratedClass: true));
        }
Example #5
0
        static ClassDeclarationSyntax GenerateBufferingElementDataAuthoringClass(
            AuthoringComponent authoringComponent, string storedType, bool hasNestedGeneratedClass = false)
        {
            const string placeholder = "___HasNestedGeneratedClassPlaceholder___";

            string generatedClass =
                $@"[UnityEngine.DisallowMultipleComponent]
                   [System.Runtime.CompilerServices.CompilerGenerated]
                   {authoringComponent.AttributesToPreserve.Select(a => $"[{a}]").SeparateByNewLine()}
                   public class {authoringComponent.DeclaringType.Name}Authoring : UnityEngine.MonoBehaviour, Unity.Entities.IConvertGameObjectToEntity
                   {{
                        {placeholder}            

                        public {storedType}[] Values;

                        public void Convert(Unity.Entities.Entity __entity,
                                            Unity.Entities.EntityManager __dstManager, 
                                            GameObjectConversionSystem _)
                        {{
                            Unity.Entities.DynamicBuffer<{authoringComponent.FullyQualifiedTypeName}> dynamicBuffer =
                                __dstManager.AddBuffer<{authoringComponent.FullyQualifiedTypeName}>(__entity);

                            dynamicBuffer.ResizeUninitialized(Values.Length);

                            for (int i = 0; i < dynamicBuffer.Length; i++)
                            {{
                                dynamicBuffer[i] = new {authoringComponent.FullyQualifiedTypeName} 
                                                   {{ 
                                                       {GenerateBufferElementDataFieldAssignments(authoringComponent)}
                                                   }};
                            }}
                        }}
                   }}";

            if (!hasNestedGeneratedClass)
            {
                return((ClassDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(generatedClass.Replace(placeholder, String.Empty)));
            }

            string withNestedType =
                generatedClass.Replace(
                    placeholder,
                    $@"[System.Serializable]
                                [System.Runtime.CompilerServices.CompilerGenerated]
                                public struct {storedType}
                                {{
                                    {CreateBufferElementDataClassFields(authoringComponent)}
                                }}");

            return((ClassDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(withNestedType));
        }
Example #6
0
        static MemberDeclarationSyntax GenerateAuthoringTypeFrom(AuthoringComponent authoringComponent)
        {
            switch (authoringComponent.Interface)
            {
            case AuthoringComponentInterface.IComponentData:
                return(AuthoringComponentFactory.GenerateComponentDataAuthoring(authoringComponent)
                       .AddNamespaces(authoringComponent.NamespacesFromMostToLeastNested));

            case AuthoringComponentInterface.IBufferElementData:
                return(AuthoringComponentFactory.GenerateBufferingElementDataAuthoring(authoringComponent)
                       .AddNamespaces(authoringComponent.NamespacesFromMostToLeastNested));

            default:
                return(default);
            }
        }
Example #7
0
        private static string CreateConversionMethodBody(AuthoringComponent authoringComponent)
        {
            StringBuilder methodBody = new StringBuilder();

            if (authoringComponent.DeclaringType.IsValueType)
            {
                methodBody.AppendLine(
                    $"{authoringComponent.FullyQualifiedTypeName} component = default({authoringComponent.FullyQualifiedTypeName});");
            }
            else
            {
                methodBody.AppendLine(
                    $"{authoringComponent.FullyQualifiedTypeName} component = new {authoringComponent.FullyQualifiedTypeName}();");
            }

            foreach (var fieldDescription in authoringComponent.FieldDescriptions)
            {
                switch (fieldDescription.FieldType)
                {
                case FieldType.SingleEntity:
                    methodBody.AppendLine(
                        $"component.{fieldDescription.FieldSymbol.Name} = __conversionSystem.GetPrimaryEntity({fieldDescription.FieldSymbol.Name});");
                    break;

                case FieldType.EntityArray:
                    methodBody.AppendLine(
                        $@"Unity.Entities.GameObjectConversionUtility.ConvertGameObjectsToEntitiesField(
                                   __conversionSystem, 
                                   {fieldDescription.FieldSymbol.Name}, 
                                   out component.{fieldDescription.FieldSymbol.Name});");
                    break;

                default:
                    methodBody.AppendLine($"component.{fieldDescription.FieldSymbol.Name} = {fieldDescription.FieldSymbol.Name};");
                    break;
                }
            }

            methodBody.AppendLine(authoringComponent.FromValueType
                ? "__dstManager.AddComponentData(__entity, component);"
                : "Unity.Entities.EntityManagerManagedComponentExtensions.AddComponentData(__dstManager, __entity, component);");

            return(methodBody.ToString());
        }
Example #8
0
        static string CreateComponentDataAuthoringClass(AuthoringComponent authoringComponent)
        {
            string declareReferencedPrefabsInterface =
                authoringComponent.ImplementIDeclareReferencedPrefabs ? ", Unity.Entities.IDeclareReferencedPrefabs" : string.Empty;

            const string placeholder = "$$$InsertDeclareReferencedPrefabsMethodHere$$$";

            string generatedClass =
                $@"[UnityEngine.DisallowMultipleComponent]
                    [System.Runtime.CompilerServices.CompilerGenerated]
                    {authoringComponent.AttributesToPreserve.Select(a => $"[{a}]").SeparateByNewLine()}
                    public class {authoringComponent.DeclaringType.Name}Authoring : UnityEngine.MonoBehaviour, Unity.Entities.IConvertGameObjectToEntity{declareReferencedPrefabsInterface}
                    {{
                         {CreateAuthoringClassFieldDeclarations(authoringComponent)}
                    
                         public void Convert(Unity.Entities.Entity __entity, 
                                             Unity.Entities.EntityManager __dstManager, 
                                             GameObjectConversionSystem __conversionSystem)
                         {{
                             {CreateConversionMethodBody(authoringComponent)}
                         }}
                    
                         {placeholder}
                    }}";

            if (!authoringComponent.ImplementIDeclareReferencedPrefabs)
            {
                return(generatedClass.Replace(oldValue: placeholder, newValue: string.Empty));
            }

            string declareReferencedPrefabsMethod =
                $@"public void DeclareReferencedPrefabs(System.Collections.Generic.List<UnityEngine.GameObject> __referencedPrefabs) 
                   {{
                       {CreateDeclareReferencedPrefabsMethodBody(authoringComponent)}
                   }}";

            return(generatedClass.Replace(oldValue: placeholder, newValue: declareReferencedPrefabsMethod));
        }
Example #9
0
        private static string CreateAuthoringClassFieldDeclarations(AuthoringComponent authoringComponent)
        {
            var fieldDeclarations = new StringBuilder();

            foreach (var fieldDescription in authoringComponent.FieldDescriptions)
            {
                switch (fieldDescription.FieldType)
                {
                case FieldType.SingleEntity:
                    fieldDeclarations.AppendLine($"public UnityEngine.GameObject {fieldDescription.FieldSymbol.Name};");
                    break;

                case FieldType.EntityArray:
                    fieldDeclarations.AppendLine($"public UnityEngine.GameObject[] {fieldDescription.FieldSymbol.Name};");
                    break;

                default:
                    fieldDeclarations.AppendLine($"public {fieldDescription.FieldSymbol.Type} {fieldDescription.FieldSymbol.Name};");
                    break;
                }
            }
            return(fieldDeclarations.ToString());
        }
Example #10
0
        public void Execute(GeneratorExecutionContext context)
        {
            bool IsGeneratedAuthoringComponentAttribute(AttributeData data)
            {
                return(data.AttributeClass.ContainingAssembly.Name == "Unity.Entities" &&
                       data.AttributeClass.Name == "GenerateAuthoringComponentAttribute");
            }

            try
            {
                if (context.Compilation.Assembly.Name.Contains("CodeGen.Tests"))
                {
                    return;
                }

                var authoringComponentReceiver = (AuthoringComponentReceiver)context.SyntaxReceiver;

                if (!authoringComponentReceiver.CandidateSyntaxes.Any() || !context.Compilation.ReferencedAssemblyNames.Any(n => n.Name == "Unity.Entities.Hybrid"))
                {
                    // TODO: I believe it is valid to have GenerateAuthoringComponent but not reference entities (DocCodeSamples.Tests currently does this).
                    // We should probably throw a warning here though.
                    //throw new ArgumentException("Using the [GenerateAuthoringComponent] attribute requires a reference to the Unity.Entities.Hybrid assembly.");
                    return;
                }

                SourceGenHelpers.LogInfo($"Source generating assembly {context.Compilation.Assembly.Name} for authoring components...");
                var stopwatch = Stopwatch.StartNew();;

                foreach (var candidateSyntax in authoringComponentReceiver.CandidateSyntaxes)
                {
                    var semanticModel   = context.Compilation.GetSemanticModel(candidateSyntax.SyntaxTree);
                    var candidateSymbol = semanticModel.GetDeclaredSymbol(candidateSyntax);
                    LogInfo($"Parsing authoring component {candidateSymbol.Name}");

                    if (!candidateSymbol.GetAttributes().Any(IsGeneratedAuthoringComponentAttribute))
                    {
                        continue;
                    }

                    var authoringComponent = new AuthoringComponent(candidateSyntax, candidateSymbol, context);

                    CheckValidity(authoringComponent);

                    var compilationUnit =
                        CompilationUnit().AddMembers(GenerateAuthoringTypeFrom(authoringComponent))
                        .NormalizeWhitespace();

                    var generatedSourceHint     = candidateSyntax.SyntaxTree.GetGeneratedSourceFileName(context.Compilation.Assembly);
                    var generatedSourceFullPath = candidateSyntax.SyntaxTree.GetGeneratedSourceFilePath(context.Compilation.Assembly);
                    var sourceTextForNewClass   = compilationUnit.GetText(Encoding.UTF8);
                    sourceTextForNewClass = sourceTextForNewClass.WithInitialLineDirectiveToGeneratedSource(generatedSourceFullPath);
                    context.AddSource(generatedSourceHint, sourceTextForNewClass);

                    File.WriteAllLines(
                        generatedSourceFullPath,
                        sourceTextForNewClass.ToString().Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None));
                }

                stopwatch.Stop();
                SourceGenHelpers.LogInfo($"TIME : AuthoringComponent : {context.Compilation.Assembly.Name} : {stopwatch.ElapsedMilliseconds}ms");
            }
            catch (Exception exception)
            {
                //context.WaitForDebuggerInAssembly();
                context.LogError("SGICE002", "Authoring Component", exception.ToString(), context.Compilation.SyntaxTrees.First().GetRoot().GetLocation());
            }
        }
Example #11
0
 static string CreateBufferElementDataClassFields(AuthoringComponent authoringComponent)
 {
     return(authoringComponent.FieldDescriptions
            .Select(description => $"public {description.FieldSymbol.Type} {description.FieldSymbol.Name};")
            .SeparateByNewLine());
 }
Example #12
0
        internal static ClassDeclarationSyntax GenerateComponentDataAuthoring(AuthoringComponent authoringComponent)
        {
            string generatedClass = CreateComponentDataAuthoringClass(authoringComponent);

            return((ClassDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(generatedClass));
        }