Search Unity

Editor scripting with ECS

Discussion in 'Entity Component System' started by Prastiwar, Apr 20, 2018.

  1. Prastiwar

    Prastiwar

    Joined:
    Jul 29, 2017
    Posts:
    125
    Hi,
    I'm thinking of writing editor code using ECS archtecture, which is quite interesting. I wonder if it's possible to do it without running play mode?

    I played around it for a while and stuck with this code below. However it seems ComponentSystem doesn't update. In entity debugger, everything is just fine - there is an Entity 0 in TestEditorSystem and it says, that system is running.
    So, maybe I'm doing something wrong?


    Code (CSharp):
    1. public struct SomeData : IComponentData
    2. {
    3.     public float2 someFloat;
    4. }
    5.  
    6. public class TestEditorSystem : ComponentSystem
    7. {
    8.     struct SomeGroup
    9.     {
    10.         public int Length;
    11.         public ComponentDataArray<SomeData> someDatas;
    12.     }
    13.     [Inject] SomeGroup someGroup;
    14.  
    15.     protected override void OnCreateManager(int capacity)
    16.     {
    17.         Debug.Log("OnCreateManager");  // It's printed
    18.         Debug.Log(someGroup.Length);   // "1"
    19.         base.OnCreateManager(capacity);
    20.     }
    21.  
    22.     protected override void OnUpdate()
    23.     {
    24.         Debug.Log("OnUpdate");  // It's not printed
    25.     }
    26. }
    27.  
    Code (CSharp):
    1. public class SomeEditorWindow : EditorWindow
    2. {
    3.     [MenuItem("CustomMenu/Window")]
    4.     public static void OpenWindow()
    5.     {
    6.         GetWindow<SomeEditorWindow>("Some", true);
    7.     }
    8.  
    9.     private void OnEnable()
    10.     {
    11.         World world = new World("SomeWorld");
    12.         World.Active = world;
    13.         EntityManager entityManager = world.GetOrCreateManager<EntityManager>();
    14.  
    15.         var entity = entityManager.CreateEntity(ComponentType.Create<SomeData>());
    16.         entityManager.SetComponentData(entity, new SomeData { someFloat = new float2(4, 8) });
    17.         world.CreateManager<TestEditorSystem>();
    18.     }
    19.  
    20.     private void OnDisable()
    21.     {
    22.         World.Active.Dispose();
    23.     }
    24. }
    25.  
     
    Last edited: Apr 20, 2018
  2. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    have you tried [ExecuteInEditMode]?
     
  3. Prastiwar

    Prastiwar

    Joined:
    Jul 29, 2017
    Posts:
    125
    Well, yeah, tried this but it didn't fix the issue.
     
  4. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    apparently you need to
    Code (CSharp):
    1. ScriptBehaviourUpdateOrder.UpdatePlayerLoop(world);
    to insert the world updates into Unity Update loop.
    it's done automatically only in playmode (see AutomaticWorldBootstrap.cs in the package)

    don't know if player loop works in edit mode though.
    worst case you manually Update() your system in EditorApplication.update
     
  5. Prastiwar

    Prastiwar

    Joined:
    Jul 29, 2017
    Posts:
    125
    Hmm.. this works:
    Code (CSharp):
    1. private void OnGUI()
    2. {
    3.     ScriptBehaviourUpdateOrder.UpdatePlayerLoop(EditorWorld);
    4. }
    But yeah, you can't call any gui function outside OnGUI and editorgui's functions throws null reference, so I don't really know how could I manage gui layout from systems.
    I've got idea about something like this, however I don't think it's correct hack. As far as I checked it prevents checks for entity debugger.
    Code (CSharp):
    1. private void OnGUI()
    2. {
    3.     foreach (var behaviour in EditorWorld.BehaviourManagers)
    4.     {
    5.         behaviour.Update();
    6.     }
    7. }
     
    Last edited: Apr 20, 2018
  6. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    wait, are you calling GUI/GUILayout functions in your update? I don't think it's a clean way to do it. you can use UIElements to do editor GUI stuff outside OnGUI instead

    also UpdatePlayerLoop should be called once at initialization (or when you change worlds) as it seems to do some heavy stuff (I poked at the source, and it builds the dependency graph for all systems in your world -- the UpdateBefore/UpdateAfter stuff)
     
  7. Prastiwar

    Prastiwar

    Joined:
    Jul 29, 2017
    Posts:
    125
    Ok, I just checked that, it's not that good as I thought :/ Unfortunately
    ScriptBehaviourUpdateOrder.UpdatePlayerLoop(EditorWorld); 
    on enable doesn't work.

    What UIElements do you mean? Are there any other editor functions for editor windows than editorgui/gui? I've always used GUI's.
     
  8. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
  9. Prastiwar

    Prastiwar

    Joined:
    Jul 29, 2017
    Posts:
    125
    I took a look at this, amazing, I'll dive into it. As I think about editor scripting with ecs now, I'm not so sure if I should use this design for editor scripting, however thank you for reply!
     
  10. tinyant

    tinyant

    Joined:
    Aug 28, 2015
    Posts:
    127
    I wonder we can use ECS and Job system to make Editor script too.
     
    deus0 likes this.
  11. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    346
    Here is my working solution :

    Code (CSharp):
    1.  [ExecuteAlways]
    2.     public class NoiseEditor : MonoBehaviour
    3.     {
    4.         NoiseSystem _noiseSystem;
    5.  
    6.         public void OnEnable()
    7.         {
    8.             Debug.Log("---------------------------------------------------");//helps see wich logs are from the last compile
    9.             if (EditorApplication.isPlaying || _noiseSystem != null) return;
    10.  
    11.             DefaultWorldInitialization.DefaultLazyEditModeInitialize();//boots the ECS EditorWorld
    12.  
    13.             _noiseSystem = World.Active.GetOrCreateSystem<NoiseSystem>();
    14.  
    15.             EditorApplication.update += () => _noiseSystem.Update();//makes the system tick properly, not every 2 seconds !
    16.         }
    17.  
    18.         public void OnDestroy()
    19.         {
    20.             //extra safety against post-compilation problems (typeLoadException) and spamming the console with failed updates
    21.             if (!EditorApplication.isPlaying)
    22.                 EditorApplication.update -= () => _noiseSystem.Update();
    23.         }
     
    deus0 likes this.
  12. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,163
    There was also InitializeOnLoadMethod and RuntimeInitializeOnLoadMethod attribute that I would use for ecs system
     
    Last edited: Dec 27, 2020