C# source generator for dots seems not work well

Hello there.
I make a source generator project to gen some code about ISystem like this:

public partial struct SampleSystem : ISystem
...

It works well at beginning until SystemAPI required. Looks like Entities.CompilerGenerated can’t work for these generated code (Dots dont generate code for them like other system).
Will there be any suggestion? Or what should I do to fix & adapt?
Thanks.

I’ve been working with source generation in Unity for some months now and you cannot use SystemAPI, IJobEntity, etc. because they use DOTS code generation. It’s intended functionality in that Roslyn source generators do not run on source-generated code, so the DOTS source generators do not run for the generated code.

My workarounds include using EntityQuery for SystemAPI methods like GetSingleton and idiomatic foreach queries. As an added note, you need to generate IJobChunk jobs rather than IJobEntity (as IJobEntity gets generated to IJobChunk under the hood) so that means handling all of the Entity/ComponentTypeHandle fields yourself.

There’s no documentation on how to use source generators in DOTS that I can find so perhaps there are other (better) ways but here’s an example of what I usually do in these cases, hope it helps!

MyGeneratedSystem.cs
using Unity.Burst;
using Unity.Burst.Intrinsics;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;

namespace MyNamespace
{
    public partial struct MyGeneratedISystem : ISystem
    {
        private EntityQuery _mySingletonQuery;
        private EntityQuery _myJobQuery;

        private EntityTypeHandle _entityTypeHandle;
        private ComponentTypeHandle<Foo> _fooTypeHandle;
        
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            using var builder = new EntityQueryBuilder();
            _mySingletonQuery = builder
                .WithAll<MySingletonComponent>()
                .Build(state.EntityManager);
            builder.Reset();
            _myJobQuery = builder
                .WithAll<Foo>()
                .WithNone<Bar>()
                .Build(state.EntityManager);

            _entityTypeHandle = state.GetEntityTypeHandle();
            _fooTypeHandle = state.GetComponentTypeHandle<Foo>();
            
            state.RequireForUpdate(_mySingletonQuery);
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            // Generated Singleton
            var mySingleton = _mySingletonQuery.GetSingleton<MySingletonComponent>();
            Debug.Log(mySingleton.Value);
            
            // Generated Job
            _entityTypeHandle.Update(ref state);
            _fooTypeHandle.Update(ref state);
            
            var ecb = new EntityCommandBuffer(Allocator.Temp);
            new MyGeneratedJob
            {
                EntityTypeHandle = _entityTypeHandle,
                FooTypeHandle = _fooTypeHandle,
                Ecb = ecb
            }.Schedule(_myJobQuery, state.Dependency).Complete();
            ecb.Playback(state.EntityManager);
        }

        [BurstCompile]
        public void OnDestroy(ref SystemState state)
        {
        }


        private struct MySingletonComponent : IComponentData
        {
            public FixedString32Bytes Value;
        }
        
        private struct Foo : IComponentData
        {
            public float Value;
        }

        private struct Bar : IComponentData
        {
            public uint Value;
        }
        
        [BurstCompile]
        private struct MyGeneratedJob : IJobChunk
        {
            public EntityTypeHandle EntityTypeHandle;
            public ComponentTypeHandle<Foo> FooTypeHandle;
            
            public EntityCommandBuffer Ecb;
            
            private void Execute(
                Entity entity,
                ref Foo foo)
            {
                foo.Value++;
                
                Ecb.AddComponent<Bar>(entity);
            }
            
            public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
            {
                var entityArr = chunk.GetNativeArray(EntityTypeHandle);
                var fooArr = chunk.GetNativeArray(ref FooTypeHandle);

                for (var i = 0; i < entityArr.Length; i++)
                {
                    var entity = entityArr[i];
                    var foo = fooArr[i];
                    
                    Execute(
                        entity,
                        ref foo);

                    fooArr[i] = foo;
                }
            }
        }
    }
}

Thanks for your help.
What thing I do now is generic some auto field and mark other system code by #if false and copy them out with partial. (really ugly way. XD)
It look like we have to find out what’s Entities pack do for these code and try call their api well.
Hope this topic could help dots be better ;;