Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

How to manually Update systems?

Discussion in 'Data Oriented Technology Stack' started by illinar, Dec 17, 2018.

  1. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    So what is the best way to run systems at will, like the TransformSystem that needs to update world matrixes after we change transforms? Actually, I don't think I know any way to do it except making a custom bootstrap or injecting a system and calling update in a non-job system. But within a job system, I'm not sure if that would work.

    I would expect an attribute that would force a system to update, however I can't come up with a good name for it, but the idea is this
    [AfterThisSystemUpdateTheOneInBracketsHere(typof(TransformSystem))]
     
    Last edited: Dec 30, 2018
  2. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,181
    You can still inject other system and call Update in JobComponentSystem. What's the problem you are facing?
     
  3. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    I just wasn't sure what happens with the chain of dependencies if I call a system before I return the handle. Maybe it's totally fine. But currently I can't even inject the TransformSystem without a bunch of errors:

    upload_2018-12-17_13-9-40.png

    upload_2018-12-17_13-11-38.png

    I think I don't understand what happens if a system I'm calling is not a job system and executes immediately, then I can't call it after my jobs will execute. So I can only call it before some other system but that's less reliable, makes less sense, since it matters that it updates transforms after I move something, and not before a number of systems read the results, because I might not be sure who will read them first..
     
    Last edited: Dec 17, 2018
  4. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Can anyone help with my error, or suggest other ways to do this?
     
  5. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,181
    If your objective if to update transform after moving, then just complete the handle and call update on the transform system.

    What do you mean by something happen to the dependency chain? What something you fear that would happen?

    Also it should be EndFrameTransformSystem if you want to use the existing one, by using just TransformSystem you are creating a new copy and you now have 2 TransformSystem running in the world.
     
  6. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Hey, I missed your reply. Say I have jobs scheduled in system A, dependencies are chained, then I run system B and maybe it will get the latest dependency automatically and all will be fine there, but then I'm back to system A, and I don't get those dependencies from the B if I'm gonna schedule new jobs. I'm under impression that calling Job.Complete() is not a great thing because it stalls the main thread. I would expect system.Update() to take and return dependencies.

    Anyway, I'm trying a custom bootstrap, injecting EndFrameTransformSystem works. The custom bootstrap however.. I thought I can add multiple copies of the same system but it doesn't work as I expected the world creation fails if do CreateManager(T) multiple times with the same system..

    But also I thought I would be able to control the update cycle more directly. I need this to handle Fixed update and regular updates properly. There are workarounds, but still would be great to control the updates manually.

    Thank you for the help.
     
  7. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    154
    If you are controller your system updates manually, then couldn't you just create the system once and call MySystem.Update() multiple times?
     
    illinar likes this.
  8. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    I've just replaced the standard bootstrap, (all it does is creates the world and adds systems) haven't figured out how to make a custom controller. Could anyone help with that?
     
    Last edited: Dec 27, 2018
  9. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    154
    By controller you mean manually updating the systems? I do that by moving my world construction and update logic to a MonoBehaviour.

    NOTE: If you are using a hybrid approach, you MUST make sure the below MonoBehaviour is the first initialized GameObject by modifying the ScriptExecutionOrder. Otherwise, the ComponentWrappers will throw exceptions due to their not being a valid active world.

    Code (CSharp):
    1. public class TestController : MonoBehaviour
    2.     {
    3.         private World _world;
    4.  
    5.         private EntityManager _entityManager;
    6.  
    7.         private SystemA _systemA;
    8.         private SystemB _systemB;
    9.  
    10.         private void Awake()
    11.         {
    12.             _world = new World("My World");
    13.  
    14.             World.Active = _world;
    15.  
    16.             _entityManager = _world.CreateManager<EntityManager>();
    17.  
    18.             _systemA = _world.CreateManager<SystemA>();
    19.             _systemB = _world.CreateManager<SystemB>();
    20.         }
    21.  
    22.         private void Update()
    23.         {
    24.             _entityManager.Update();
    25.  
    26.             _systemA.Update();
    27.             _systemB.Update();
    28.         }
    29.  
    30.         private void OnDestroy()
    31.         {
    32.             World.Active = null;
    33.  
    34.             _world.Dispose();
    35.         }
    36.     }
    They also do a completely custom (and rather detailed) update loop in the FPS Sample if you want to check that out.
     
  10. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Awesome, thanks! So this line is reponsible for autoupdate in my code:

    ScriptBehaviourUpdateOrder.UpdatePlayerLoop(world);


    Now I have this:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Entities;
    3. using Unity.Transforms;
    4. using UnityEngine;
    5.  
    6. [DefaultExecutionOrder(-100000)]
    7. public class WorldController : MonoBehaviour
    8. {
    9.     private World _world;
    10.     private List<ScriptBehaviourManager> _systems = new List<ScriptBehaviourManager>(32);
    11.  
    12.     private void Awake()
    13.     {
    14.         _world = new World("World");
    15.         World.Active = _world;
    16.  
    17.         _systems.Add(_world.GetOrCreateManager<EntityManager>());
    18.         _systems.Add(_world.GetOrCreateManager<InputSystem>());
    19.         _systems.Add(_world.GetOrCreateManager<MovementSystem>());
    20.         _systems.Add(_world.GetOrCreateManager<GravitySystem>());
    21.         _systems.Add(_world.GetOrCreateManager<VelocityDampingSystem>());
    22.  
    23.         _systems.Add(_world.GetOrCreateManager<PhysicsUpdateSystem>());
    24.         _systems.Add(_world.GetOrCreateManager<EndFrameTransformSystem>());
    25.  
    26.         _systems.Add(_world.GetOrCreateManager<ProjectileRaycastSystem>());
    27.         _systems.Add(_world.GetOrCreateManager<RaycastSystem>());
    28.         _systems.Add(_world.GetOrCreateManager<CountdownSystem<Cooldown>>());
    29.         _systems.Add(_world.GetOrCreateManager<ShootSystem>());
    30.         _systems.Add(_world.GetOrCreateManager<EndFrameTransformSystem>());
    31.     }
    32.  
    33.     private void Update()
    34.     {
    35.         foreach (ComponentSystemBase s in _systems) s.Update();
    36.     }
    37. }
    I only need to add one line per system, I also can add the same system multiple times.

    I decided to do physics updates and all other updated at the same rate. Should work well in my case, and will definitely eliminate a lot of complexity!

    I'm really happy with this setup.
     
  11. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
    You don't need manually fill list, because World has IEnumerable<ScriptBehaviourManager>:
    Code (CSharp):
    1. foreach (var m in _world.BehaviourManagers)
    2.         {
    3.             m.Update();
    4.         }
     
  12. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Right, but its IEnumerable<ScriptBehaviourManager> probably contains each system only once, and I want multiple updates possible per system.


    Hold on, first of all, my previous code didn't work. Somehow the UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP disappeared and the default world was made.

    Now it works but without
    ScriptBehaviourUpdateOrder.UpdatePlayerLoop(_world);
    systems don't show up in the Entity Debugger. Not crucial but not ideal. If there is another way to make it work there I'd love to know.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Entities;
    3. using Unity.Transforms;
    4. using UnityEngine;
    5.  
    6. [DefaultExecutionOrder(-100000)]
    7. public class WorldController : MonoBehaviour
    8. {
    9.     private World _world;
    10.     private EntityManager _entityManager;
    11.     private List<ScriptBehaviourManager> _updateSystems = new List<ScriptBehaviourManager>(32);
    12.     private List<ScriptBehaviourManager> _initializeSystems = new List<ScriptBehaviourManager>(32);
    13.  
    14.     private void Awake()
    15.     {
    16.         _world = new World("World");
    17.         World.Active = _world;
    18.  
    19.         _entityManager = _world.GetOrCreateManager<EntityManager>();
    20.  
    21.         _initializeSystems.Add(_world.GetOrCreateManager<InitializeBuffersSystem>());
    22.         _initializeSystems.Add(_world.GetOrCreateManager<InitializeInputSystem>());
    23.         _initializeSystems.Add(_world.GetOrCreateManager<InitializeFrameRateSystem>());
    24.  
    25.         _updateSystems.Add(_world.GetOrCreateManager<InputSystem>());
    26.         _updateSystems.Add(_world.GetOrCreateManager<MovementSystem>());
    27.         _updateSystems.Add(_world.GetOrCreateManager<GravitySystem>());
    28.         _updateSystems.Add(_world.GetOrCreateManager<VelocityDampingSystem>());
    29.  
    30.         _updateSystems.Add(_world.GetOrCreateManager<UpdatePhysicsSystem>());
    31.         _updateSystems.Add(_world.GetOrCreateManager<EndFrameTransformSystem>());
    32.  
    33.         _updateSystems.Add(_world.GetOrCreateManager<ProjectileRaycastSystem>());
    34.         _updateSystems.Add(_world.GetOrCreateManager<RaycastSystem>());
    35.         _updateSystems.Add(_world.GetOrCreateManager<ShootSystem>());
    36.         _updateSystems.Add(_world.GetOrCreateManager<EndFrameTransformSystem>());
    37.  
    38.         // ScriptBehaviourUpdateOrder.UpdatePlayerLoop(_world);
    39.     }
    40.  
    41.     private void Update()
    42.     {
    43.         _entityManager.Update();
    44.         foreach (ComponentSystemBase s in _updateSystems) s.Update();
    45.     }
    46. }
     
  13. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
    No. It contains all created systems.
    Code (CSharp):
    1.  
    2. public class ChainSystemsBehaviour : MonoBehaviour
    3. {
    4.     void Start()
    5.     {
    6.         var world = new World("MY WORLD");
    7.         world.CreateManager<MySystem>();
    8.         world.CreateManager<MySystem>();
    9.         world.CreateManager<MySystem>();
    10.         Debug.Log(world.BehaviourManagers.Count());
    11.         foreach (var manager in world.BehaviourManagers)
    12.         {
    13.             Debug.Log(manager.GetType());
    14.         }
    15.     }
    16. }
    17.  
    18. public class MySystem : ComponentSystem
    19. {
    20.     protected override void OnUpdate()
    21.     {
    22.  
    23.     }
    24.  
    25.     protected override void OnCreateManager()
    26.     {
    27.         base.OnCreateManager();
    28.     }
    29.  
    30.     protected override void OnDestroyManager()
    31.     {
    32.         base.OnDestroyManager();
    33.     }
    34. }
    35.  
    upload_2018-12-28_14-14-12.png

    It's correct behaviour if you look at ED source code:
    https://forum.unity.com/threads/any...m-in-the-entity-debugger.601855/#post-4032181
     
  14. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Turns out I can't update a system twice there. If I execute any system twice it results in "A Native Collection has not been disposed" error.
     
  15. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Code (CSharp):
    1.         world.CreateManager<MySystem>();
    2.         world.CreateManager<MySystem>();
    3.         world.CreateManager<MySystem>();
    Hold on, I'll try that again. But when I did before it didn't work. Couldn't call CreateManager with the same system twice.
     
  16. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
    Wrong :)
    Code (CSharp):
    1.  
    2. public class ChainSystemsBehaviour : MonoBehaviour
    3. {
    4.     void Start()
    5.     {
    6.         var world = new World("MY WORLD");
    7.         world.CreateManager<MySystem>();
    8.         world.CreateManager<MySystem>();
    9.         world.CreateManager<MySystem>();
    10.         Debug.Log(world.BehaviourManagers.Count());
    11.  
    12.         Debug.Log("Update one");
    13.         foreach (var manager in world.BehaviourManagers)
    14.         {
    15.             manager.Update(); //x3 Update messages
    16.         }
    17.  
    18.         Debug.Log("Update two");
    19.         foreach (var manager in world.BehaviourManagers)
    20.         {
    21.             manager.Update(); //x3 Update messages
    22.         }
    23.  
    24.         Debug.Log("Update three");
    25.         foreach (var manager in world.BehaviourManagers)
    26.         {
    27.             manager.Update(); //x3 Update messages
    28.         }
    29.         //total 9 Update messages
    30.     }
    31. }
    32.  
    upload_2018-12-28_14-19-20.png
     
  17. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Yes, but you do a full loop multiple times. I added a system once and executed it twice. But maybe it should work anyway.

    Currently, I have endless bugs. If I add any system twice it creates 33 leaked container that sometimes don't go away until I restart Unity.

    A Native Collection has not been disposed, resulting in a memory leak. It was allocated at C:\Files\Projects\VRShooter\Library\PackageCache\com.unity.entities@0.0.12-preview.21\Unity.Entities\ComponentSystem.cs:99.
    X 33

    If each system is added once everything is fine.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Entities;
    3. using Unity.Transforms;
    4. using UnityEngine;
    5.  
    6. [DefaultExecutionOrder(-100000)]
    7. public class WorldController : MonoBehaviour
    8. {
    9.     private World world;
    10.  
    11.     private void Awake()
    12.     {
    13.         world = new World("World");
    14.         World.Active = world;
    15.         world.CreateManager<EntityManager>();
    16.  
    17.         world.CreateManager<InitializeBuffersSystem>();
    18.         world.CreateManager<InitializeInputSystem>();
    19.         world.CreateManager<InitializeFrameRateSystem>();
    20.  
    21.         world.CreateManager<InputSystem>();
    22.         world.CreateManager<MovementSystem>();
    23.         world.CreateManager<GravitySystem>();
    24.         world.CreateManager<VelocityDampingSystem>();
    25.  
    26.         world.CreateManager<UpdatePhysicsSystem>();
    27.  
    28.         world.CreateManager<ProjectileRaycastSystem>();
    29.         world.CreateManager<RaycastSystem>();
    30.         world.CreateManager<ShootSystem>();
    31.         world.CreateManager<EndFrameTransformSystem>();
    32.     }
    33.  
    34.     private void Update()
    35.     {
    36.         foreach (ScriptBehaviourManager m in world.BehaviourManagers) m.Update();
    37.     }
    38. }
     
  18. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Leaks might be due to the fact that I don't dispose of the world.
     
  19. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Confirmed. I added this code from the default bootstrap:

    Code (CSharp):
    1.    PlayerLoopManager.RegisterDomainUnload(DomainUnloadShutdown, 10000);
    2.     }
    3.  
    4.     static void DomainUnloadShutdown()
    5.     {
    6.         World.DisposeAllWorlds();
    7.         ScriptBehaviourUpdateOrder.UpdatePlayerLoop();
    8.     }
    Now I can use multiple copies of systems. Everything seems fine.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Entities;
    3. using Unity.Transforms;
    4. using UnityEngine;
    5.  
    6. [DefaultExecutionOrder(-100000)]
    7. public class WorldController : MonoBehaviour
    8. {
    9.     private World world;
    10.  
    11.     private void Awake()
    12.     {
    13.         world = new World("World");
    14.         World.Active = world;
    15.         world.CreateManager<EntityManager>();
    16.  
    17.         world.CreateManager<InitializeBuffersSystem>();
    18.         world.CreateManager<InitializeInputSystem>();
    19.         world.CreateManager<InitializeFrameRateSystem>();
    20.  
    21.         world.CreateManager<InputSystem>();
    22.         world.CreateManager<MovementSystem>();
    23.         world.CreateManager<GravitySystem>();
    24.         world.CreateManager<GravitySystem>();
    25.         world.CreateManager<VelocityDampingSystem>();
    26.  
    27.         world.CreateManager<UpdatePhysicsSystem>();
    28.         world.CreateManager<UpdatePhysicsSystem>();
    29.         world.CreateManager<EndFrameTransformSystem>();
    30.  
    31.         world.CreateManager<ProjectileRaycastSystem>();
    32.         world.CreateManager<RaycastSystem>();
    33.         world.CreateManager<RaycastSystem>();
    34.         world.CreateManager<RaycastSystem>();
    35.         world.CreateManager<ShootSystem>();
    36.         world.CreateManager<EndFrameTransformSystem>();
    37.  
    38.         PlayerLoopManager.RegisterDomainUnload(DomainUnloadShutdown, 10000);
    39.     }
    40.  
    41.     static void DomainUnloadShutdown()
    42.     {
    43.         World.DisposeAllWorlds();
    44.         ScriptBehaviourUpdateOrder.UpdatePlayerLoop();
    45.     }
    46.  
    47.     private void Update()
    48.     {
    49.         foreach (ScriptBehaviourManager m in world.BehaviourManagers) m.Update();
    50.     }
    51. }

    @eizenhorn Thank you, that helped a lot.
     
  20. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    154
    In entity debugger, i think you need to select Show Full Player Loop.
     
  21. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
  22. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Yeah, I'm in the middle of figuring out how to do that. So far what I got doesn't work:

    Code (CSharp):
    1.         var playerLoop = PlayerLoop.GetDefaultPlayerLoop();
    2.         var update = playerLoop.subSystemList[4];
    3.         var updateSystems = new List<PlayerLoopSystem>(update.subSystemList);
    4.         foreach (ScriptBehaviourManager m in world.BehaviourManagers)
    5.         {
    6.             updateSystems.Add(new PlayerLoopSystem()
    7.             {
    8.                 updateDelegate = m.Update,
    9.                 type = m.GetType()
    10.             });
    11.         }
    12.         update.subSystemList = updateSystems.ToArray();
    13.         playerLoop.subSystemList[4] = update;
    14.         PlayerLoop.SetPlayerLoop(playerLoop);
    15.  
    16.         ScriptBehaviourUpdateOrder.UpdatePlayerLoop();
    Is there anything wrong there?

    The world doesn't even get created it seems. Not even OnCreateManager is called. The EntityDebugger is completely empty. No entities.
     
    Last edited: Dec 28, 2018
  23. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
    Now I’m on run and from mobile :) New Year in Russia (important like Christmas in other countries) :) I can give some help only tomorrow :)
     
  24. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    @eizenhorn Thanks. I'm from Russia myself. S nastupaushim :) For now, I can live without EntityDebugger.

    I saw @5argon 's tread on some PlayerLoop loop issues, so I'll tag him in hopes that he would kindly take a look and spot the issue.

    @5argon, If you have time :) TLDR this player loop code doesn't work. The updates are not running and the systems are not showing in the debugger.

    (Edited)
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Entities;
    3. using Unity.Transforms;
    4. using UnityEngine;
    5. using UnityEngine.Experimental.LowLevel;
    6.  
    7. public static class WorldController
    8. {
    9.     private static World world;
    10.  
    11.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    12.     private static void Awake()
    13.     {
    14.         world = new World("World");
    15.         World.Active = world;
    16.         world.CreateManager<EntityManager>();
    17.  
    18.         world.CreateManager<InitializeBuffersSystem>();
    19.         world.CreateManager<InitializeInputSystem>();
    20.         world.CreateManager<InitializeFrameRateSystem>();
    21.  
    22.         world.CreateManager<InputSystem>();
    23.         world.CreateManager<MovementSystem>();
    24.         world.CreateManager<GravitySystem>();
    25.         world.CreateManager<VelocityDampingSystem>();
    26.  
    27.         world.CreateManager<UpdatePhysicsSystem>();
    28.         // world.CreateManager<EndFrameTransformSystem>();
    29.  
    30.         world.CreateManager<ProjectileRaycastSystem>();
    31.         world.CreateManager<RaycastSystem>();
    32.         world.CreateManager<ShootSystem>();
    33.         world.CreateManager<EndFrameTransformSystem>();
    34.  
    35.         var playerLoop = PlayerLoop.GetDefaultPlayerLoop();
    36.         var update = playerLoop.subSystemList[4];
    37.         var updateSystems = new List<PlayerLoopSystem>(update.subSystemList);
    38.         foreach (ScriptBehaviourManager m in world.BehaviourManagers)
    39.         {
    40.             updateSystems.Add(new PlayerLoopSystem()
    41.             {
    42.                 updateDelegate = m.Update,
    43.                 type = m.GetType()
    44.             });
    45.         }
    46.         update.subSystemList = updateSystems.ToArray();
    47.         playerLoop.subSystemList[4] = update;
    48.         PlayerLoop.SetPlayerLoop(playerLoop);
    49.  
    50.         ScriptBehaviourUpdateOrder.UpdatePlayerLoop();
    51.         PlayerLoopManager.RegisterDomainUnload(DomainUnloadShutdown, 10000);
    52.     }
    53.  
    54.     static void DomainUnloadShutdown()
    55.     {
    56.         World.DisposeAllWorlds();
    57.         ScriptBehaviourUpdateOrder.UpdatePlayerLoop();
    58.     }
    59. }
     
    Last edited: Dec 28, 2018
  25. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Does ComponentArray<> not work in a custom bootstrap like that? It throws errors on injection. Default bootstrap has those hooks:

    InjectionHookSupport.RegisterHook(new GameObjectArrayInjectionHook());
    InjectionHookSupport.RegisterHook(new TransformAccessArrayInjectionHook());
    InjectionHookSupport.RegisterHook(new ComponentArrayInjectionHook());


    I've been there a few months ago. Is it still impossible to access those? No way around? Those are internal classes!

    Code (CSharp):
    1. namespace Unity.Entities
    2. {
    3.     [CustomInjectionHookAttribute]
    4.     [Preserve]
    5.     internal sealed class GameObjectArrayInjectionHook : InjectionHook
    6.     {
    7.         public GameObjectArrayInjectionHook();
    8.  
    9.         public override Type FieldTypeOfInterest { get; }
    10.  
    11.         public override InjectionContext.Entry CreateInjectionInfoFor(FieldInfo field, bool isReadOnly);
    12.         public override bool IsInterestedInField(FieldInfo fieldInfo);
    13.         public override string ValidateField(FieldInfo field, bool isReadOnly, InjectionContext injectionInfo);
    14.     }
    15. }
     
  26. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    The workaround is to let the default world to be created to let it enable hooks.
     
  27. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
    It’s possible as before - with reflection :)
     
  28. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    I've no idea how. But I'll google.Thanks
     
  29. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
    I’m again out of PC, try to search posts from @5argon he wrote about that :)
     
  30. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Somehow this doesn't work:
    Code (CSharp):
    1. var a = typeof(GameObjectEntity).Assembly;
    2. InjectionHookSupport.RegisterHook((InjectionHook)a.CreateInstance("Unity.Entities.GameObjectArrayInjectionHook"));
    3. InjectionHookSupport.RegisterHook((InjectionHook)a.CreateInstance("Unity.Entities.TransformAccessArrayInjectionHook"));
    4. InjectionHookSupport.RegisterHook((InjectionHook)a.CreateInstance("Unity.Entities.ComponentArrayInjectionHook"));
    No errors. Objects are created. But the injection doesn't work.
     
  31. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    That's a little frustrating when the code seems correct and just doesn't work... No idea what to do in such a case.
    upload_2018-12-31_10-44-51.png
     
  32. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,181
    Roughly looking I can't see anything wrong in your code, but I have been using a code at the bottom of this file https://github.com/5argon/E7ECS/blob/master/WorldHelper/WorldHelper.cs and it works. Also if you happen to use UniRx, it will cause some problem and overwrites your custom player loop.

    I noticed you are setting player loop the hard way. There is an overload that take just `World` and update the loop accordingly. Is there a reason you are doing it this way?
     
    Last edited: Dec 31, 2018
  33. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Thanks, I'll try your code. No UniRx.

    Yes, I want multiple copies of some systems, and that player loop method doesn't accept that. Also, it doesn't respect the order in which I add system, it completely scrambles it even when I use no order attributes.

    And I want to manually order my systems because the attribute approach gets really confusing with more systems.


    I could have a visual utility which would order the systems in the Editor and add the attributes automatically, just one attribute per system [UpdateAfter()]. Not sure if I would get around to implement that.

    But that still doesn't allow me to add one system multiple times. But I could make some wrapper systems, preferably generic and update inside those.. Kinda messy though.
     
    Last edited: Dec 31, 2018
  34. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    154
    @illinar, I know I've gotten the injection hooks working using the same method you have. But at the time I was only using ScriptBehaviourUpdateOrder.UpdatePlayerLoop(world), I wasn't controlling the loop manually. You may want to play around with the ordering of (or maybe removing?) PlayerLoop.SetPlayerLoop() and/or ScriptBehaviourUpdateOrder.UpdatePlayerLoop().
     
    illinar likes this.
  35. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,181
    Oh.. I just saw a bit of code over your hook registerings. The hook take effect on `OnCreateManager` and has no use at all afterwards. You register them after all create manager had passed, so those systems creates without knowing about the hooks. (probably)
     
    illinar, dartriminis and eizenhorn like this.
  36. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Cool, thank you. Yes, it works now. Mystery solved :)

    Now I just wish my custom player loop has worked.
     
  37. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    192
    I also found the attributes to be confusing and have been trying to do this. I just got it working.
    When you call ScriptBehaviourUpdateOrder.UpdatePlayerLoop(), you are overwriting your loop with the default one. Instead, you need to call
    ScriptBehaviourUpdateOrder.SetPlayerLoop(playerLoop). It is internal, so you need to use reflection or edit the code and make it public. Also, if you want your systems to show up in the entity debugger, you have to wrap them in
    ScriptBehaviourUpdateOrder.DummyDelagateWrapper when adding them to PlayerLoopSystem.updateDelegate. That class is also internal. I edited it to make it public.
     
  38. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
    You must use PlayerLoop.SetPlayerLoop(loop); for manual setting player loop, you don’t need any reflection here. Read my post:
    https://forum.unity.com/threads/updating-systems-from-inside-a-system.604525/#post-4044868
     
  39. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    192
    From my experience, that doesn't update the entity debugger; it only updates the player loop. ScriptBehaviourUpdateOrder.UpdatePlayerLoop() calls PlayerLoop.SetPlayerLoop() within it, but it also updates ScriptBehaviourUpdateOrder.CurrentPlayerLoop which is what the Entity Debugger uses to draw its tree view.
     
  40. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,267
    Read code again. I now how ED works inside and writes this code with ED requirements, and I answers you to this before and show ED sources :)
    https://forum.unity.com/threads/any...m-in-the-entity-debugger.601855/#post-4032181
     
  41. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    192
    I appreciate you helping me before but not sure what to say. The entity debugger did not properly update for me until I changed from PlayerLoop.SetPlayerLoop() to ScriptBehaviourUpdateOrder.SetPlayerLoop().

    Edit: I just tried changing it back and it worked with PlayerLoop.SetPlayerLoop(). Not sure what was going on before. Must have been something else causing the issue.

    Edit 2: I don't understand how you're doing it without
    ScriptBehaviourUpdateOrder.DummyDelagateWrapper. It only works for me if I do this:
    Code (CSharp):
    1. new PlayerLoopSystem {
    2.     type = x.GetType(),
    3.     updateDelegate = new ScriptBehaviourUpdateOrder.DummyDelagateWrapper(system).TriggerUpdate,
    4. }
     
    Last edited: Jan 6, 2019
  42. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    Thanks for the help @Jay-Pavlina, this fixed my player loop. I can confirm that ScriptBehaviourUpdateOrder.UpdatePlayerLoop() was apparently overwriting my loop changes and, yes, it works without calling ScriptBehaviourUpdateOrder.SetPlayerLoop(playerLoop)

    I haven't added DummyDelegateWrapper yet. Have you made the type public? I'm trying to use reflection but unsuccessfully so far.
     
  43. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    192
    Yes I made it public because I didn’t want to fiddle with reflection, but if you figure it out please post.
     
  44. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    547
    @Jay-Pavlina, I'll probably give up. I can't figure out how to edit the package though. I made the class public, but it's still unavailable. Do I need to recompile? I assumed it should detect the change and recompile on its own. Or is there a dll somewhere?

    Edit: nvm. I edited the one in ProgramData. Didn't know there is package cache in the Library.

    Edit: Doesn't show any systems in the debugger. Works fine though.

    Code (CSharp):
    1.      
    2.         foreach (ScriptBehaviourManager m in world.BehaviourManagers)
    3.         {
    4.             updateSystems.Add(new PlayerLoopSystem()
    5.             {
    6.                 updateDelegate = new ScriptBehaviourUpdateOrder.DummyDelagateWrapper(m).TriggerUpdate,
    7.                 type = m.GetType()
    8.             });
    9.         }
    10.        
    Code (CSharp):
    1. using System;
    2. using System.Reflection;
    3. using System.Globalization;
    4. using System.Collections.Generic;
    5. using Unity.Entities;
    6. using Unity.Transforms;
    7. using UnityEngine;
    8. using UnityEngine.Experimental.LowLevel;
    9.  
    10. public class WorldBootstrap
    11. {
    12.     private static World world;
    13.  
    14.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    15.     private static void Awake()
    16.     {
    17.         var a = typeof(GameObjectEntity).Assembly;
    18.         InjectionHookSupport.RegisterHook((InjectionHook)a.CreateInstance("Unity.Entities.GameObjectArrayInjectionHook"));
    19.         InjectionHookSupport.RegisterHook((InjectionHook)a.CreateInstance("Unity.Entities.TransformAccessArrayInjectionHook"));
    20.         InjectionHookSupport.RegisterHook((InjectionHook)a.CreateInstance("Unity.Entities.ComponentArrayInjectionHook"));
    21.  
    22.         world = new World("World");
    23.         World.Active = world;
    24.  
    25.         world.CreateManager<EntityManager>();
    26.  
    27.         world.CreateManager<InitializeBuffersSystem>();
    28.         world.CreateManager<InitializeInputSystem>();
    29.         world.CreateManager<InitializeFrameRateSystem>();
    30.  
    31.         world.CreateManager<InputSystem>();
    32.         world.CreateManager<CalibrateLocomotionSystem>();
    33.         world.CreateManager<PlayerLocomotionSystem>();
    34.         world.CreateManager<MovementSystem>();
    35.         world.CreateManager<GravitySystem>();
    36.         world.CreateManager<VelocityDampingSystem>();
    37.  
    38.         world.CreateManager<UpdatePhysicsSystem>();
    39.  
    40.         world.CreateManager<ProjectileRaycastSystem>();
    41.         world.CreateManager<RaycastSystem>();
    42.         world.CreateManager<ShootSystem>();
    43.         world.CreateManager<EndFrameTransformSystem>();
    44.         world.CreateManager<EndFrameTransformSystem>();
    45.  
    46.         var playerLoop = PlayerLoop.GetDefaultPlayerLoop();
    47.         var update = playerLoop.subSystemList[4];
    48.         var updateSystems = new List<PlayerLoopSystem>(update.subSystemList);
    49.         foreach (ScriptBehaviourManager m in world.BehaviourManagers)
    50.         {
    51.             updateSystems.Add(new PlayerLoopSystem()
    52.             {
    53.                 updateDelegate = new ScriptBehaviourUpdateOrder.DummyDelagateWrapper(m).TriggerUpdate,
    54.                 type = m.GetType()
    55.             });
    56.         }
    57.         update.subSystemList = updateSystems.ToArray();
    58.         playerLoop.subSystemList[4] = update;
    59.         PlayerLoop.SetPlayerLoop(playerLoop);
    60.  
    61.         PlayerLoopManager.RegisterDomainUnload(DomainUnloadShutdown, 10000);
    62.     }
    63.  
    64.     static void DomainUnloadShutdown()
    65.     {
    66.         World.DisposeAllWorlds();
    67.         ScriptBehaviourUpdateOrder.UpdatePlayerLoop();
    68.     }
    69. }
     
    Last edited: Jan 11, 2019
  45. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    192
    That's strange they're not showing up in the debugger. Works fine for me.