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