Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Loading a system from a mod DLL in Entities 0.50.0

Discussion in 'Entity Component System' started by flagredomega, May 27, 2022.

  1. flagredomega

    flagredomega

    Joined:
    Oct 12, 2017
    Posts:
    12
    I'm trying to set up an ECS demo that loads a system from an externally created plugin.

    I load the plugin with Assembly.LoadFile(), then use reflection to get the type of an initialisation class that looks like this:
    Code (CSharp):
    1.     public class ItsAnotherMod : PluginInterface
    2.     {
    3.         public void Startup()
    4.         {
    5.             Debug.Log("Starting ItsAnotherMod");
    6.             var world = World.DefaultGameObjectInjectionWorld;
    7.             var systemGroup = world.GetOrCreateSystem<SimulationSystemGroup>();
    8.             systemGroup.AddSystemToUpdateList(world.GetOrCreateSystem<RisingCubeSystem>());
    9.             systemGroup.SortSystems();
    10.         }
    11.  
    12.         public void Update()
    13.         {
    14.         }
    15.     }
    Here's RisingCubeSystem:
    Code (CSharp):
    1.     public partial class RisingCubeSystem : SystemBase
    2.     {
    3.         protected override void OnUpdate()
    4.         {
    5.             var deltaTime = Time.DeltaTime;
    6.             Entities.ForEach((ref Translation translation, in Cube cube) =>
    7.             {
    8.                 translation.Value.y += deltaTime;
    9.             }).ScheduleParallel();
    10.         }
    11.     }
    I'm delaying the creation of a world with #UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP_RUNTIME_WORLD, then initialize it after loading the plugins with:
    Code (CSharp):
    1.         Debug.Log("Creating default world");
    2.         var world = DefaultWorldInitialization.Initialize("Default World");
    3.         World.DefaultGameObjectInjectionWorld = world;
    4.         GameObjectSceneUtility.AddGameObjectSceneReferences();
    Doing this spams my console with InvalidOperationException: Reflection data was not set up by a call to Initialize(), though. Here's the full stack trace:
    Does anyone know what's up here? I've found this thread with the same error, but it doesn't seem to be related (no generics here): https://forum.unity.com/threads/sol...s-not-set-up-by-a-call-to-initialize.1285238/

    I think it might be related to the fact that the systems aren't being found by the world automatically, and have to be manually added, but I'm not an expert on Unity's ECS system so I don't know for sure.

    Edit: After a bit more investigation, it looks like IJobEntityBatch<T>.EarlyJobInit() is supposed to be called by generated code, but isn't being called here. I'm guessing that for some reason my generated code isn't being exported in the dll I've created. I made an assembly definition for the mod, linked it against Unity and the dll for the main demo, and copied the produced dll into a mods folder for the main demo. Maybe the generated code isn't being brought across with the mod?
     
    Last edited: May 27, 2022
  2. flagredomega

    flagredomega

    Joined:
    Oct 12, 2017
    Posts:
    12
    Bumping this thread to update.

    I think I'm getting closer to the root of the issue. As described by deplinenoise here (https://forum.unity.com/threads/wil...neric-jobs-going-forward.974187/#post-6384873), jobs pre-register their reflection data during compilation/startup (I'm not sure which). I can't see that code anywhere in Temp/GeneratedCode, and I can't see how that gets done under normal circumstances, and I can't seem to step into that code in a debugger, but from reading through the source, Unity.Jobs.CodeGen.JobReflectionDataPostProcessor does it explicitly for generic jobs marked with the attribute [assembly:RegisterGenericJobType(...)].

    I tried making my job (trvially) generic, and including that attribute on it, but still no change. I don't see the generated code that I'm pretty sure should be in Temp/GeneratedCode, I also don't see any logs for it in /Temp/GeneratedCode/SourceGen.log, so I'm guessing that JobReflectionDataPostProcessor isn't running for my mod assembly.

    Here's the system I'm trying to import as it currently stands:
    Code (CSharp):
    1. [assembly:RegisterGenericJobType(typeof(RisingCubeJob<float>))]
    2. partial struct RisingCubeJob<T> : IJobEntityBatch
    3. {
    4.     public ComponentTypeHandle<Translation> TranslationTypeHandle;
    5.     public float DeltaTime;
    6.  
    7.     public void Execute(ArchetypeChunk batchInChunk, int batchIndex)
    8.     {
    9.         NativeArray<Translation> translations = batchInChunk.GetNativeArray(TranslationTypeHandle);
    10.        
    11.         for (int i = 0; i < batchInChunk.Count; i++)
    12.         {
    13.             var translation = translations[i];
    14.             float3 newTranslation = translation.Value + new float3(0, DeltaTime, 0);
    15.             translations[i] = new Translation {Value = newTranslation};
    16.         }
    17.     }
    18. }
    19.  
    20. public partial class RisingCubeSystem : SystemBase
    21. {
    22.     private EntityQuery _query;
    23.    
    24.     protected override void OnCreate()
    25.     {
    26.         _query = GetEntityQuery(new EntityQueryDesc
    27.         {
    28.             All=new[]
    29.             {
    30.                 ComponentType.ReadOnly<Cube>(),
    31.                 ComponentType.ReadWrite<Translation>()
    32.             }
    33.         });
    34.     }
    35.    
    36.     protected override void OnUpdate()
    37.     {
    38.         Debug.Log("RisingCubeSystem");
    39.         var job = new RisingCubeJob<float>{
    40.             TranslationTypeHandle = GetComponentTypeHandle<Translation>(),
    41.             DeltaTime = Time.DeltaTime
    42.         };
    43.         Dependency = job.ScheduleParallel(_query, Dependency);
    44.     }
    45. }
    If anyone who worked on Unity.Jobs is around, I'd appreciate some insight on what is needed to trigger the IL post processor to initialize this system.
     
  3. JingchengYang4

    JingchengYang4

    Joined:
    Apr 18, 2017
    Posts:
    19
    Hi, do you have any updates?
     
  4. JingchengYang4

    JingchengYang4

    Joined:
    Apr 18, 2017
    Posts:
    19
    Hi, I have figured it out. Simply calling this line of code will work:
    Code (CSharp):
    1. JobEntityBatchExtensions.EarlyJobInit<T>();
     
    flagredomega likes this.