Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug [Entities 0.50] Systems window doesn't handle custom top-level ComponentSystemGroup

Discussion in 'Entity Component System' started by iamarugin, Apr 23, 2022.

  1. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    863
    I've added custom ComponentSystemGroup into player loop. Then if I try to open Systems window, it's empty and console is full of exceptions.

    Code (CSharp):
    1. InvalidProgramException: Couldn't find system $Common.PreUpdateSystemGroup in World
    2. Unity.Entities.Editor.WorldProxy.FindSystemIndexFor (Unity.Entities.ComponentSystemBase sys) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/SystemSchedule/PlayerLoop/WorldProxy.cs:108)
    3. Unity.Entities.Editor.SystemProxy..ctor (Unity.Entities.ComponentSystemBase b, Unity.Entities.Editor.WorldProxy worldProxy, System.Boolean belongToCurrentWorld) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/SystemSchedule/PlayerLoop/SystemProxy.cs:33)
    4. Unity.Entities.Editor.PlayerLoopSystemGraph.AddFromPlayerLoop (UnityEngine.LowLevel.PlayerLoopSystem playerLoopSystem, Unity.Entities.Editor.IPlayerLoopNode parent) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:34)
    5. Unity.Entities.Editor.PlayerLoopSystemGraph.AddFromPlayerLoop (UnityEngine.LowLevel.PlayerLoopSystem playerLoopSystem, Unity.Entities.Editor.IPlayerLoopNode parent) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:53)
    6. Unity.Entities.Editor.PlayerLoopSystemGraph.AddFromPlayerLoop (UnityEngine.LowLevel.PlayerLoopSystem playerLoopSystem, Unity.Entities.Editor.IPlayerLoopNode parent) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:53)
    7. Unity.Entities.Editor.PlayerLoopSystemGraph.ResetFromPlayerLoop (UnityEngine.LowLevel.PlayerLoopSystem rootPlayerLoopSystem) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:25)
    8. Unity.Entities.Editor.PlayerLoopSystemGraph.BuildCurrentGraph () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:14)
    9. Unity.Entities.Editor.SystemScheduleWindow.OnUpdate () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/SystemSchedule/SystemScheduleWindow.cs:313)
    10. Unity.Entities.Editor.DOTSEditorWindow.Update () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities.Editor/Common/DOTSEditorWindow.cs:203)
    11. UnityEditor.HostView.SendUpdate () (at <3371b3e2e5754acd87e600e068350da5>:0)
    12. UnityEditor.EditorApplication.Internal_CallUpdateFunctions () (at <3371b3e2e5754acd87e600e068350da5>:0)
    13.  
    While everything works as expected in the Entities debugger.
    upload_2022-4-23_16-46-7.png
     
    mbaker, Anthiese and JesOb like this.
  2. mbaker

    mbaker

    Joined:
    Jan 9, 2013
    Posts:
    52
    I have this issue too.

    In my situation I've added a new top-level PlayerLoopSystem to the player loop then added a custom ComponentSystemGroup under that.

    If I only add the top-level PlayerLoopSystem I don't have any issues. Like you mentioned, the ComponentSystemGroup seems to be the problem.
     
    iamarugin likes this.
  3. mbaker

    mbaker

    Joined:
    Jan 9, 2013
    Posts:
    52
    Digging deeper the issue seems to be that Unity.Entities.Editor.LocalWorldProxyUpdater.PopulateWorldProxy() hard codes an array of top level groups to initialize before traversing through their child systems. This means systems in custom top-level groups are never evaluated.

    LocalWorldProxyUpdater.PopulateWorldProxy()
    Code (CSharp):
    1. var rootTypes = new[]
    2.             {
    3.                 typeof(InitializationSystemGroup),
    4.                 typeof(SimulationSystemGroup),
    5.                 typeof(PresentationSystemGroup)
    6.             };
    Unfortunately, since the array is initialized inline we can't use reflection to change that array.
    Looks like an oversight on their end without a reasonable workaround/fix on our end.

    I've submitted a bug report to Unity with a sample project and will update if I hear anything.

    If anybody wants to repro
    - Throw the script below onto a GameObject in your scene
    - Press play
    - Open the new systems editor panel (Window -> DOTS -> Systems)
    - Observe exceptions in console

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using Unity.Entities;
    4. using UnityEngine.LowLevel;
    5. using UnityEngine.PlayerLoop;
    6. using System.Linq;
    7.  
    8. public class PostUpdate_Custom
    9. {
    10.     /// <summary>
    11.     /// Provides a <see cref="PlayerLoopSystem" /> instance to to identify this phase.
    12.     /// </summary>
    13.     public static PlayerLoopSystem PlayerLoopSystem
    14.     {
    15.         get => new PlayerLoopSystem()
    16.         {
    17.             type = typeof(PostUpdate_Custom)
    18.         };
    19.     }
    20. }
    21.  
    22. [DisableAutoCreation]
    23. public class PostUpdateExampleSystemGroup : ComponentSystemGroup { }
    24.  
    25. [DisableAutoCreation]
    26. public class UpdateExampleSystemGroup : ComponentSystemGroup { }
    27.  
    28. public class MainScene : MonoBehaviour
    29. {
    30.  
    31.     private static bool s_HaveCustomPhasesBeenAdded = false;
    32.  
    33.     private static void AddCustomPhasesToCurrentPlayerLoop()
    34.     {
    35.         if (s_HaveCustomPhasesBeenAdded)
    36.         {
    37.             return;
    38.         }
    39.  
    40.         // Create new top level player loop phases
    41.         PlayerLoopSystem playerLoop = PlayerLoop.GetCurrentPlayerLoop();
    42.         List<PlayerLoopSystem> topLevelPhases = playerLoop.subSystemList.ToList();
    43.  
    44.         int updatePhaseIndex = topLevelPhases.FindIndex((phase) => phase.type == typeof(Update));
    45.         Debug.Assert(updatePhaseIndex != -1, "Update phase not found");
    46.         Debug.Assert(!topLevelPhases.Any((phase) => phase.type == typeof(PostUpdate_Custom)), $"{nameof(PostUpdate_Custom)} phase already added");
    47.         topLevelPhases.Insert(updatePhaseIndex + 1, PostUpdate_Custom.PlayerLoopSystem);
    48.  
    49.         playerLoop.subSystemList = topLevelPhases.ToArray();
    50.         PlayerLoop.SetPlayerLoop(playerLoop);
    51.  
    52.         s_HaveCustomPhasesBeenAdded = true;
    53.     }
    54.  
    55.     void Start()
    56.     {
    57.         // Create a custom player loop phase
    58.         AddCustomPhasesToCurrentPlayerLoop();
    59.  
    60.         PlayerLoopSystem playerLoop = PlayerLoop.GetCurrentPlayerLoop();
    61.  
    62.         // Add a custom top level system group to the custom PostUpdate_Custom player loop phase.
    63.         // Once this system group is added to the player loop the Window -> Dots -> Systems editor panel will throw exceptions when focused.
    64.         // The exception is not thrown in the legacy system editor panel.
    65.         ComponentSystemGroup group = World.DefaultGameObjectInjectionWorld.CreateSystem<PostUpdateExampleSystemGroup>();
    66.         ScriptBehaviourUpdateOrder.AppendSystemToPlayerLoop(group, ref playerLoop, typeof(PostUpdate_Custom));
    67.  
    68.         // The same as above, but this time the system group is added to the Update phase. Also causes the Systems window to throw exceptions.
    69.         // ComponentSystemGroup group2 = World.DefaultGameObjectInjectionWorld.CreateSystem<UpdateExampleSystemGroup>();
    70.         // ScriptBehaviourUpdateOrder.AppendSystemToPlayerLoop(group2, ref playerLoop, typeof(Update));
    71.  
    72.         PlayerLoop.SetPlayerLoop(playerLoop);
    73.     }
    74. }
     
    xVergilx and Lukas_Kastern like this.
  4. XianW_Unity

    XianW_Unity

    Unity Technologies

    Joined:
    Jun 7, 2019
    Posts:
    1
    Thank you guys for the report, we will take a look into it and keep you posted with the result.
     
  5. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    863
    Tried entities 1.0.11
    Systems window is still empty.
    And I see the error in the console

    Code (CSharp):
    1. InvalidProgramException: Couldn't find system $Common.PreUpdateSystemGroup in World
    2. Unity.Entities.Editor.WorldProxy.FindSystemIndexFor (Unity.Entities.ComponentSystemBase sys) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/SystemSchedule/PlayerLoop/WorldProxy.cs:107)
    3. Unity.Entities.Editor.SystemProxy..ctor (Unity.Entities.ComponentSystemBase b, Unity.Entities.Editor.WorldProxy worldProxy, System.Boolean belongToCurrentWorld) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/SystemSchedule/PlayerLoop/SystemProxy.cs:33)
    4. Unity.Entities.Editor.PlayerLoopSystemGraph.AddFromPlayerLoop (UnityEngine.LowLevel.PlayerLoopSystem playerLoopSystem, Unity.Entities.Editor.IPlayerLoopNode parent) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:38)
    5. Unity.Entities.Editor.PlayerLoopSystemGraph.AddFromPlayerLoop (UnityEngine.LowLevel.PlayerLoopSystem playerLoopSystem, Unity.Entities.Editor.IPlayerLoopNode parent) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:57)
    6. Unity.Entities.Editor.PlayerLoopSystemGraph.AddFromPlayerLoop (UnityEngine.LowLevel.PlayerLoopSystem playerLoopSystem, Unity.Entities.Editor.IPlayerLoopNode parent) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:57)
    7. Unity.Entities.Editor.PlayerLoopSystemGraph.ResetFromPlayerLoop (UnityEngine.LowLevel.PlayerLoopSystem rootPlayerLoopSystem) (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:25)
    8. Unity.Entities.Editor.PlayerLoopSystemGraph.BuildCurrentGraph () (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/SystemSchedule/PlayerLoop/PlayerLoopSystemGraph.cs:14)
    9. Unity.Entities.Editor.SystemScheduleWindow.OnUpdate () (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/SystemSchedule/SystemScheduleWindow.cs:325)
    10. Unity.Entities.Editor.DOTSEditorWindow.Update () (at ./Library/PackageCache/com.unity.entities@1.0.11/Unity.Entities.Editor/Common/DOTSEditorWindow.cs:196)
    11. UnityEditor.HostView.SendUpdate () (at <da771086bc2e4cfc9ad0a72e083a7f98>:0)
    12. UnityEditor.EditorApplication.Internal_CallUpdateFunctions () (at <da771086bc2e4cfc9ad0a72e083a7f98>:0)
    13.  
    (PreUpdateSystem is a custom top-level system added to the DefaultInjectionWorld)
     
    xVergilx likes this.
  6. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    863
  7. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    863
    Any workarounds / patch fixed would be much appreciated.
     
  8. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    This is still the case for Entities 1.0.11;
    But Entity Debuggers is no longer available. Which means no ability to debug systems at all.
     
  9. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    As a workaround for the future readers:
    - Modify LocalWorldProxyUpdater (in Unity.Entities.Editor\SystemSchedule\PlayerLoop):
    - Move rootTypes array out to the class & make it HashSet:
    Code (CSharp):
    1. public static HashSet<Type> rootTypes = new HashSet<Type>
    2. {
    3.    typeof(InitializationSystemGroup),
    4.    typeof(SimulationSystemGroup),
    5.    typeof(PresentationSystemGroup),
    6. };
    - Also make LocalWorldProxyUpdater public;

    - In your custom bootstrap, add some kind of method to include root groups to the proxy:
    Code (CSharp):
    1.  
    2. #if UNITY_EDITOR
    3. using Unity.Entities.Editor;
    4. #endif
    5.  
    6. ...
    7. #if UNITY_EDITOR
    8.       /// <summary>
    9.       /// Entities System window will fail if root type groups are not matching changes, so apply them as well
    10.       /// </summary>
    11.       private static void OverrideEditorTypes() {
    12.          var rootTypes = LocalWorldProxyUpdater.rootTypes;
    13.      
    14.          // e.g.
    15.          rootTypes.Add(typeof(PostLateUpdateGroup));
    16.       }
    17. #endif
    I've also tried removing groups e.g. InitializationSystemGroup, and its tied to more internal classes.
    So if you do something like that as well, you'll need default system groups to be added back unfortunatelly for the window to draw properly.
     
    Last edited: Aug 7, 2023
    mbaker and iamarugin like this.
  10. mbaker

    mbaker

    Joined:
    Jan 9, 2013
    Posts:
    52
    We still haven't upgraded to 1.0 on our project. For many reasons but this bug was a blocker. Good to know that there's a work around.

    I have no idea where Unity is on a fix for this. All of the links and issue numbers I had from filing this bug with Unity are broken/missing now. Hopefully it's still on their radar!