This method should have been replaced by source gen

I’ve got an IJobEntity called from an OnUpdate method on an ISystem I created.

I read this error was common back when ECS was in beta like 2 or 3 years ago.

MyClass+MyJob.__ThrowCodeGenException () (at JobEntityGenerator/Unity.Entities.SourceGen.JobEntityGenerator.JobEntityGenerator/Temp/GeneratedCode/Assembly-CSharp/MyClass_Bla_bla__JobEntity_30018136860.g.cs:96)
Exception: This method should have been replaced by source gen.

So it can generate code for this particular job: i removed private content but the native array is in reality a struct that hides a nativearray inside with a struct of data (floats, all of them). This job does this:

        [BurstCompile]
        public partial struct MyJob : IJobEntity
        {
            public NativeList<MyStruct> data;

            public void Execute(in AComponent id, in BComponent b)
            {
                data.Add(new MyStruct(a.val, b.val) });
            }
        }

[Edit]

I found the generated file from ECS. It contains a call to show that log for every Job related call. So it’s not generating the code.

....
    global::Unity.Jobs.JobHandle __ThrowCodeGenException() => throw new global::System.Exception("This method should have been replaced by source gen.");
    
    // Emitted to disambiguate scheduling method invocations
    public void Run() => __ThrowCodeGenException();
    public void RunByRef() => __ThrowCodeGenException();
    public void Run(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
    public void RunByRef(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
    public global::Unity.Jobs.JobHandle Schedule(global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
    public global::Unity.Jobs.JobHandle ScheduleByRef(global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
    public global::Unity.Jobs.JobHandle Schedule(global::Unity.Entities.EntityQuery query, global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
    public global::Unity.Jobs.JobHandle ScheduleByRef(global::Unity.Entities.EntityQuery query, global::Unity.Jobs.JobHandle dependsOn) => __ThrowCodeGenException();
    public void Schedule() => __ThrowCodeGenException();
    public void ScheduleByRef() => __ThrowCodeGenException();
    public void Schedule(global::Unity.Entities.EntityQuery query) => __ThrowCodeGenException();
...

So yeah, it’s not able to generate anything from that job. Why? Is there any way to see the errors in generation?

[Edit]

So I’m starting to think that I’m not using IJobEntity the way it’s supposed to be used. I’m using an external NativeArray without an index. Maybe I should write a particular IJobChunk or another type of parallel job and pass the contents of the chunks. Because I’m not really doing ECS stuff here, I’m just gathering stuff from entities components and putting it outside of the chunks.

No, that part is fine. The Methods seen in generated code for IJobEntity are stubs. Usage of the job type outside appropriate places uses these implementations which always throw, which is intended. System codegen replaces invocations of those stubs with the correct underlying internal invocation. The generated code for the system is the problematic part that you must inspect.

1 Like

But… The schedule() method is the one I call. And it’s returning that log. Isn’t that expected? I thought I was maybe calling the job wrong.

I’m seeing the IJobChunk automatically generated with the job. I’ll take a look at the job chunk code then…

The invocation in the source code (within the system) is meant to be swapped out by the source generator that is used to produce the actual system methods used at runtime, replacing usages of entity jobs and SystemAPI with the realized implementations which can look different from the original source code. In effect, the generated stub does not matter unless invoked somewhere where the system’s source generator is unable to produce an appropriate replacement. As I said, the generated code for the system is what you should be looking at. Post it if you’re not sure about it yourself.

I didn’t read this correctly.

This is the call stack:

  • ISystem’s OnUpdate creates an instance of a struct
  • The struct constructor receives a JobHandle
  • It calls several (for now , just one) methods on a static class
  • That method Schedules the job and returns the handle

Is there anything in that chain that is unappropiate? Static class maybe?

The source generator doesn’t extend outside the system when creating replacement methods. Code that needs replacement for implementation needs to all be part of the system itself.

So the job should be placed inside the System. That’s interesting… I see… I didn’t read anything about it in the docs! :frowning:
How do I see the final generated code?

No. Only the invocation of critical methods like scheduling entity jobs and SystemAPI need to be in a valid context, i.e. inside the system type. The job type can be defined anywhere. The two hook together automatically based on codegen.

Proper IDEs allow inspection of source generated assets. Rider for example shows these in the Dependencies section of a project. There’s also DOTS_OUTPUT_SOURCEGEN_FILES if absolutely necessary, though you really should just use IDE functionality.

1 Like

Also, there’s another related question that contains more info about this problem.