예제 #1
0
        public static StructDeclarationSyntax GenerateFrom(JobEntityDescription jobEntityDescription)
        {
            string jobEntityBatchCode =
                $@"public struct {jobEntityDescription.GeneratedJobEntityBatchTypeName} : Unity.Entities.IJobEntityBatch
                   {{
                       public {jobEntityDescription.DeclaringTypeFullyQualifiedName} __JobData;
                       {jobEntityDescription.OnUpdateMethodParameters.Select(p => p.BatchFieldDeclaration).SeparateByNewLine()}

                       public unsafe void Execute(Unity.Entities.ArchetypeChunk batch, int batchIndex)
                       {{
                           {CreateNativeArrayUnsafePointers(jobEntityDescription.OnUpdateMethodParameters).SeparateByNewLine()}
                           for (int i = 0; i < batch.Count; i++)
                           {{
                               __JobData.OnUpdate({CreateJobOnUpdateArguments(jobEntityDescription.OnUpdateMethodParameters).SeparateByComma()});
                           }}
                       }}
                   }}";

            return((StructDeclarationSyntax)SyntaxFactory.ParseMemberDeclaration(jobEntityBatchCode));

            IEnumerable <string> CreateNativeArrayUnsafePointers(IEnumerable <OnUpdateMethodParameter> onUpdateMethodParameters)
            {
                return
                    (onUpdateMethodParameters.Select(p =>
                                                     !p.IsReadOnly
                            ? $"var {p.NativeArrayPointerName} = ({p.FullyQualifiedTypeName}*)batch.GetNativeArray({p.BatchFieldName}).GetUnsafePtr();"
                            : $"var {p.NativeArrayPointerName} = ({p.FullyQualifiedTypeName}*)batch.GetNativeArray({p.BatchFieldName}).GetUnsafeReadOnlyPtr();"));
            }

            IEnumerable <string> CreateJobOnUpdateArguments(IEnumerable <OnUpdateMethodParameter> onUpdateMethodParameters)
            {
                foreach (var parameter in onUpdateMethodParameters)
                {
                    if (parameter.IsReadOnly)
                    {
                        yield return($"in {parameter.NativeArrayPointerName}[i]");
                    }
                    else
                    {
                        yield return($"ref {parameter.NativeArrayPointerName}[i]");
                    }
                }
            }
        }
        public void Execute(GeneratorExecutionContext sourceGeneratorContext)
        {
            try
            {
                var iJobEntityReceiver = (IJobEntityReceiver)sourceGeneratorContext.SyntaxReceiver;

                if (!iJobEntityReceiver.JobEntityTypeCandidates.Any())
                {
                    return;
                }

                var syntaxTreeToCandidates =
                    iJobEntityReceiver
                    .JobEntityTypeCandidates
                    .GroupBy(j => j.TypeNode.SyntaxTree)
                    .ToDictionary(group => group.Key, group => group.ToArray());

                foreach (var kvp in syntaxTreeToCandidates)
                {
                    var syntaxTree = kvp.Key;
                    var candidates = kvp.Value;

                    try
                    {
                        foreach (var(typeNode, onUpdateMethodNode) in candidates)
                        {
                            SemanticModel semanticModel       = sourceGeneratorContext.Compilation.GetSemanticModel(typeNode.SyntaxTree);
                            ITypeSymbol   candidateTypeSymbol = (ITypeSymbol)semanticModel.GetDeclaredSymbol(typeNode);

                            if (!candidateTypeSymbol.InheritsFromInterface("Unity.Entities.IJobEntity"))
                            {
                                continue;
                            }

                            var jobEntityDescription =
                                new JobEntityDescription(typeNode, onUpdateMethodNode, candidateTypeSymbol, sourceGeneratorContext);

                            if (jobEntityDescription.FieldDescriptions.Any(f => !f.IsValueType))
                            {
                                throw new ArgumentException("IJobEntity types may only contain value-type fields.");
                            }

                            var jobEntityData = new JobEntityData
                            {
                                UserWrittenJobEntity         = jobEntityDescription,
                                GeneratedIJobEntityBatchType = JobEntityBatchTypeGenerator.GenerateFrom(jobEntityDescription),
                            };

                            AllJobEntityTypes[jobEntityDescription.DeclaringTypeFullyQualifiedName] = jobEntityData;

                            AddJobEntityBatchSourceToContext(jobEntityData, sourceGeneratorContext);
                        }
                    }
                    catch (Exception exception)
                    {
                        sourceGeneratorContext.LogError("SGICE001", "JobEntity", exception.ToString(), syntaxTree.GetRoot().GetLocation());
                    }
                }

                SyntaxNode[] entitiesInSystemBaseDerivedTypes =
                    GetEntitiesInSystemBaseDerivedTypes(
                        sourceGeneratorContext, iJobEntityReceiver.EntitiesGetterCandidates).ToArray();

                if (!entitiesInSystemBaseDerivedTypes.Any())
                {
                    return;
                }

                var syntaxTreesToEntities =
                    entitiesInSystemBaseDerivedTypes
                    .GroupBy(e => e.SyntaxTree)
                    .ToDictionary(group => group.Key, group => group.ToArray());

                foreach (var kvp in syntaxTreesToEntities)
                {
                    var syntaxTree  = kvp.Key;
                    var entityNodes = kvp.Value;

                    try
                    {
                        foreach (SyntaxNode entityNode in entityNodes)
                        {
                            var systemBaseDescription        = SystemBaseDescription.From(entityNode, sourceGeneratorContext);
                            var updatedSystemBaseDescription = UpdatedSystemBaseTypeGenerator.GenerateFrom(systemBaseDescription);

                            AddUpdatedSystemBaseSourceToContext(
                                systemBaseDescription,
                                updatedSystemBaseDescription,
                                sourceGeneratorContext);
                        }
                    }
                    catch (Exception exception)
                    {
                        sourceGeneratorContext.LogError("SGICE001", "JobEntity", exception.ToString(), syntaxTree.GetRoot().GetLocation());
                    }
                }
            }
            catch (Exception exception)
            {
                sourceGeneratorContext.LogError(
                    "SG0002",
                    "Unknown Exception",
                    exception.ToString(),
                    sourceGeneratorContext.Compilation.SyntaxTrees.First().GetRoot().GetLocation());
            }
        }