Search Unity

Edit mode systems?

Discussion in 'Entity Component System' started by Timboc, Feb 1, 2019.

  1. Timboc

    Timboc

    Joined:
    Jun 22, 2015
    Posts:
    238
    I was hoping to implement an edit-time preview for the tween library I'm building but I've come a bit unstuck - any help would be greatly appreciated.

    So far I've been able to create a new world and add entities. Despite having [ExecuteAlways] everywhere though, I'm not sure how to get the systems running? If I manually use World.Active.GetOrCreateManager on each individual system and then manually call Update (via an editor coroutine?), I think that essentially achieves it. However I have to believe there's a better way - likely something already built-in that takes into account update order etc?

    I call
    ScriptBehaviourUpdateOrder.UpdatePlayerLoop(World.Active);
    after creating the edit mode World. I also don't see any entities after creating them but I assume that's a related issue of the RenderMesh system not updating either?

    Many thanks!
     
  2. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    You have to wrap your component or shared component in ComponentDataWrapper<> or SharedComponentDataWrapper<> that way your components will trigger the involved systems in edit mode.
     
    Timboc likes this.
  3. Timboc

    Timboc

    Joined:
    Jun 22, 2015
    Posts:
    238
    Unfortunately I'm still having no luck. I think I'm misunderstanding something. This is the simplest test I can come up with - code on a monobehaviour on a GameObject (which is gross and never cleaned up):
    Code (CSharp):
    1.     private void OnValidate()
    2.     {
    3.         if (World.Active == null)
    4.         {
    5.             World world = new World("EditorPreview");
    6.             World.Active = world;
    7.             ScriptBehaviourUpdateOrder.UpdatePlayerLoop(World.Active);
    8.         }
    9.  
    10.         EntityManager entityManager = World.Active.GetOrCreateManager<EntityManager>();
    11.         // Create player archetype
    12.         EntityArchetype ea = entityManager.CreateArchetype(
    13.             typeof(Position), typeof(Rotation), typeof(Scale), typeof(RenderMesh));
    14.  
    15.         Entity previewEntity = entityManager.CreateEntity(ea);
    16.         entityManager.SetComponentData(previewEntity, new Rotation() { Value = Quaternion.Euler(new Vector3(0f, 0f, 0f)) });
    17.         entityManager.SetComponentData(previewEntity, new Scale() { Value = Vector3.one });
    18.         entityManager.SetComponentData(previewEntity, new Position() { Value = Vector3.zero });
    19.         entityManager.SetSharedComponentData(previewEntity, new RenderMesh() { mesh = meshToUse, material = material });
    20.     }
    What I'm trying to achieve: Upon selected a gameobject (hybrid mode) or a scriptable object of the serialized animation (pure mode), create an entity dynamically in the scene at edit time and have the systems run as they would at play time. The tween entities I create are pure (no gameobjects) - do I need to be creating a gameobject & changing all my AddComponent calls to add the wrapper versions of all the components or something?
     
  4. dorianvasile

    dorianvasile

    Joined:
    Jul 1, 2020
    Posts:
    7
    Did you ever figure this out @Timboc? I'm setting up my editor world using
    DefaultWorldInitialization.DefaultLazyEditModeInitialize()
    , and while all my systems are there, none of them run OnUpdate except once when clicking off the scene somewhere (per click). I can manually update some systems like the ones I created if necessary and that works fine, but I can't do that with some internal systems like RenderBoundsUpdateSystem for translation changes. So I was wondering if there was a way to get all systems in the editor world to update as they would in play mode. I have also tried
    ScriptBehaviourUpdateOrder.AddWorldToPlayerLoop()
    , but this didn't help either. I'll note that the other person I'm working on the same project with does not have this issue with the same code, their systems update fine after creating the world. Maybe just a settings issue, just looking for some insight in case I missed any steps.
     
  5. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    992
  6. Timboc

    Timboc

    Joined:
    Jun 22, 2015
    Posts:
    238
    Afaik that doesn't work (unless you happen to have a subscene open or some similar condition).
    @dorianvasile I did get it working. The main thing is to call
    EditorApplication.QueuePlayerLoopUpdate();
    on
    EditorApplication.update
    . I don't know if this is the "correct" solution but is working for me.
    As for adding systems to the world I currently use this:
    Code (CSharp):
    1. DefaultWorldInitialization.DefaultLazyEditModeInitialize();
    2. var MyWorld = World.DefaultGameObjectInjectionWorld;
    3. List<System.Type> systems = UnityEditor.TypeCache.GetTypesDerivedFrom(typeof(ComponentSystemBase)).Where(x => x != null && !string.IsNullOrEmpty(x.Namespace) && x.Namespace.StartsWith(@"My.Namespace")).ToList();
    4. DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(MyWorld, systems);
    Please note this is not an official response and this is likely somewhat out of date.
    i.e. looking at this now I don't think this would capture ISBs.
    I welcome any advice on how to improve this.
     
  7. jasons-novaleaf

    jasons-novaleaf

    Joined:
    Sep 13, 2012
    Posts:
    181
    I was messing around with edit mode tests. It really only creates systems that you explicitly add to the world. I think this is very interesting because you have perfect control over the systems created, thus can test system depenencies/races exactly.

    I use play mode tests to test systems executing as they are during "normal" unity operation.

    That said, I always wished I had a way to load everything into an edit mode test. Maybe Timboc's reply above is the answer? I'll give it a try!

    For running update in tests, I took a different approach. Created a [UnityTest] with an IEnumerator return value. and inside a loop with a world.Update() and a yield return.

    see this post for an example: https://forum.unity.com/threads/nat...ed-up-by-burst-compiler.1049879/#post-6802574
     
    Timboc likes this.
  8. dorianvasile

    dorianvasile

    Joined:
    Jul 1, 2020
    Posts:
    7
    Thanks so much @Timboc! Calling
    EditorApplication.QueuePlayerLoopUpdate();
    was the only thing I was missing. Called that method instead of individual systems Update like I was before on
    EditorApplication.update
    like you said. Worked great since it updates my systems and all the internal ones I couldn't call.

    I'm not sure if I have things setup differently, but my systems are being added without the code snippet you posted. I just have this flag on my editor only systems
    [WorldSystemFilter(WorldSystemFilterFlags.Editor)]
    and they are automatically added to my editor world. (Do still need
    DefaultWorldInitialization.DefaultLazyEditModeInitialize();
    of course)
     
    Sarkahn, WAYNGames and Timboc like this.