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

Event System

Discussion in 'Entity Component System' started by tertle, Nov 19, 2019.

  1. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Looks cool overall, but manual dependency management kinda looks clunky. (Need to use more to adjust)
    Also, would like to see more samples / examples with Entities.ForEach in junction.
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Also, checked in Editor performance of git sample. It seems like with increase numbers of Writers performance drop by a lot. Is that expected or I am missing something?

    Leak detection disabled, burst compilation enabled, safety checks disabled.
    upload_2021-1-19_15-52-14.png

    Disabling "Use Job Threads" improves situation, but not by a lot:
    upload_2021-1-19_15-54-39.png

    This is on Ryzen 3950x.
     
    Last edited: Jan 19, 2021
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    This is probably a combination of sync point of a new frame since nothing else is running so it has to wait for previous frame to complete and the cost of scheduling 128 jobs in the example.

    Apart from allocating a small chunk of memory, the entire system works in threads so shouldn't really appear in the main thread.

    Not by a lot? You doubled performance!



    Anyway, when 0.17 is out and burstable systems are a thing, I'll finish my re-write and the remaining main thread work will mostly disappear.
     
    Last edited: Jan 19, 2021
  4. OUTTAHERE

    OUTTAHERE

    Joined:
    Sep 23, 2013
    Posts:
    656
    Is it at all within the scope of this package to pass events on into "Monobehaviour space", or would it always be required to write a Single Event Consumer System and then move / relay the events one by one?

    I'm looking into ways to handle events better between UI and the Game right now; currently each of these is a hard and immediate sync point. Any solution that processes them e.g. as a queue and then deals with all of them (i.e. all events of one type) in one tick would be much preferable.

    I need to think about a few event chains in "ECS space" as well, where this is of course vastly preferable to event Tag ICDs. But one prime example of these is my TagUIFocus, which can affect a whole slew of entities on any given player-controlled ship, and does have consequences in Mono space.
     
  5. jasons-novaleaf

    jasons-novaleaf

    Joined:
    Sep 13, 2012
    Posts:
    181
    I havent looked at @tertle's solution (yet) but I spent the last day or so playing around with this sort of problem. Here's an example of how I avoid sync points in my ecs code: (call into monobehaviours around line 67)

    Code (CSharp):
    1.  
    2. [BurstCompile]
    3. public class AudioSystem : SystemBase
    4. {
    5.  
    6.     [StructLayout(LayoutKind.Sequential, Size = 132)]
    7.     public struct AudioMessage
    8.     {
    9.         public SystemMessageType type;
    10.         public FixedString64 audioFile;
    11.     }
    12.  
    13.  
    14.     private NativeQueue<AudioMessage> _messageQueue;
    15.     public static NativeQueue<AudioMessage>.ParallelWriter messageIn;
    16.  
    17.     protected override void OnCreate()
    18.     {
    19.         base.OnCreate();
    20.  
    21.         _messageQueue = new NativeQueue<AudioMessage>(Allocator.Persistent);
    22.         messageIn = _messageQueue.AsParallelWriter();
    23.     }
    24.     protected override void OnDestroy()
    25.     {
    26.         base.OnDestroy();
    27.         _messageQueue.Dispose();    
    28.     }
    29.  
    30.     /** cache known audio files to avoid GC allocations */
    31.     private System.Collections.Generic.Dictionary<FixedString64, string> _strLookup = new System.Collections.Generic.Dictionary<FixedString64, string>();
    32.     /// <summary>
    33.     /// cache strings to avoid gc pressure
    34.     /// </summary>
    35.     /// <param name="fstr"></param>
    36.     /// <returns></returns>
    37.     private string _getString(ref FixedString64 fstr)
    38.     {
    39.         string toReturn;
    40.         if (_strLookup.TryGetValue(fstr, out toReturn))
    41.         {
    42.             return toReturn;
    43.         }
    44.         toReturn = fstr.ToString();
    45.         _strLookup.Add(fstr, toReturn);
    46.         return toReturn;
    47.     }
    48.  
    49.  
    50.     protected override void OnUpdate()
    51.     {
    52.  
    53.         var _messageQueue = this._messageQueue;
    54.         Job
    55.         //.WithReadOnly(messageQueueParallel) //guess this is not needed
    56.         .WithCode(() =>
    57.         {
    58.             while (_messageQueue.TryDequeue(out var message))
    59.             {
    60.                 var audioFileStr = _getString(ref message.audioFile);
    61.                 switch (message.type)
    62.                 {
    63.                     case SystemMessageType.Audio_Sfx:
    64.                         AudioManager.instance.PlaySfxRequest(audioFileStr);
    65.                         break;
    66.                     case SystemMessageType.Audio_Music:
    67.                         AudioManager.instance.PlayMusicRequest(audioFileStr);
    68.                         break;
    69.                     default:
    70.                         throw new System.Exception("invalid message type send to audioSystem");
    71.                 }
    72.             }
    73.         })
    74.         .WithoutBurst()
    75.         .Run();
    76.     }
    77. }
    Then in your other system, when you want to call an audio sfx for example, you'd have soemthing like this

    Code (CSharp):
    1.             var audioQueue = AudioSystem.messageIn;
    2.             Job
    3.                 .WithCode(() =>
    4.             {            
    5.                 while (onKillQueue.TryDequeue(out var tuple))
    6.                 {
    7.                     var audioMessage = new AudioSystem.AudioMessage() {audioFile=tuple.component.sfxName, type=SystemMessageType.Audio_Sfx };
    8.                     audioQueue.Enqueue(audioMessage);
    9.  
    10.                 }            
    11.             })
    12.              
    13.                 .Schedule();
    I hope that makes sense. I was playing with tuples in the example usage, so plz ignore that :D
     
  6. OUTTAHERE

    OUTTAHERE

    Joined:
    Sep 23, 2013
    Posts:
    656
    Tuples are fine, thank you for the kind example. Funny I also need to change my sound entity system to a sound event system, and was wondering how to work around native queues.

    Actually, I wonder if it would be too much to ask to have thread safe containers - not thread exclusive containers, i.e. for a queue that would be one with atomic insert and remove commands. Maybe I'm just old and knowledge of this paradigm has been lost to humanity since the late 1990s.

    And I guess that's not how Unity's main thread likes to be treated.

    Instead of a FixedString, I use an int and a function that generates a stable hash from a string (one could abuse the Shader or Animator property hash for it, but I just wrote my own); and then use a Dictionary<int, Sprite> in the UI layouter to see what the event meant (and that "Sprite" could just as well be an AudioEffect in my Sound system).
     
    Last edited: Jan 20, 2021
  7. jasons-novaleaf

    jasons-novaleaf

    Joined:
    Sep 13, 2012
    Posts:
    181
    see line 15 in the example. The queue is thread safe for enqueing. I should have included .WithReadOnly(audioQueue) above line 3 in the example usage, but I just learned about that in the last 12 hours :D
     
    Last edited: Jan 20, 2021
  8. Ylly-avvyland

    Ylly-avvyland

    Joined:
    Jan 6, 2021
    Posts:
    7
    Im not sure but this is frequent use case that i have crash with removing component in Event system or in system executed after event.

    Code (CSharp):
    1. 2021.01.24 14:46:09.538 11634 11671 Error CRASH *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    2. 2021.01.24 14:46:09.538 11634 11671 Error CRASH Version '2020.1.17f1 (9957aee8edc2)', Build type 'Release', Scripting Backend 'il2cpp', CPU 'armeabi-v7a'
    3. 2021.01.24 14:46:09.538 11634 11671 Error CRASH Build fingerprint: 'Xiaomi/dipper_ru/dipper:10/QKQ1.190828.002/V12.0.1.0.QEARUXM:user/release-keys'
    4. 2021.01.24 14:46:09.538 11634 11671 Error CRASH Revision: '0'
    5. 2021.01.24 14:46:09.538 11634 11671 Error CRASH ABI: 'arm'
    6. 2021.01.24 14:46:09.538 11634 11671 Error CRASH Timestamp: 2021-01-24 14:46:09+0300
    7. 2021.01.24 14:46:09.538 11634 11671 Error CRASH pid: 11634, tid: 11671, name: UnityMain  >>> com.avvy.app <<<
    8. 2021.01.24 14:46:09.538 11634 11671 Error CRASH uid: 10529
    9. 2021.01.24 14:46:09.538 11634 11671 Error CRASH signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xadef1000
    10. 2021.01.24 14:46:09.538 11634 11671 Error CRASH     r0  adef1000  r1  00000008  r2  00000002  r3  fffff870
    11. 2021.01.24 14:46:09.538 11634 11671 Error CRASH     r4  c77de4a0  r5  c77de1f0  r6  c663e31e  r7  c77e0aa0
    12. 2021.01.24 14:46:09.538 11634 11671 Error CRASH     r8  00000000  r9  c77e0b88  r10 00000000  r11 c77df4a0
    13. 2021.01.24 14:46:09.538 11634 11671 Error CRASH     ip  00000000  sp  c77de1f8  lr  c77de4a0  pc  c1fbea60
    14. 2021.01.24 14:46:09.539 11634 11671 Error CRASH
    15. 2021.01.24 14:46:09.539 11634 11671 Error CRASH backtrace:
    16. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #00 pc 0252ca60  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityComponentStore_CreateArchetype_m5ED7DDEF7A10C1A04A101693C05D987848D86517+6712) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    17. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #01 pc 02520c28  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityComponentStore_GetOrCreateArchetype_m0DAE7D33766CFB623F32DE902CC60C784591CDCF+384) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    18. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #02 pc 02533ca0  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityComponentStore_GetArchetypeWithRemovedComponent_mA8C0B8F8EFD2FB96CCD6B41014B9083DAA7E6CB8+996) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    19. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #03 pc 02532310  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityComponentStore_GetArchetypeChunkFilterWithRemovedComponent_mB8E7F78E9F61E21F77FF75A91FE62D650FFC8430+208) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    20. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #04 pc 025368f4  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityComponentStore_GetChunkWithEmptySlotsWithRemovedComponent_m2111A6C9ACC57C09EFB00D1B31F294527A58D4AC+128) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    21. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #05 pc 02531080  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityComponentStore_GetChunkWithEmptySlotsWithRemovedComponent_m28C67AF6297D7C5802FC02CBAA153A486712D0DF+200) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    22. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #06 pc 02530f2c  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityComponentStore_RemoveComponent_m627CFF75A3DFD59CD58A068A50477DCE2D10D1A0+120) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    23. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #07 pc 0262829c  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityDataAccess_RemoveComponentDuringStructuralChange_m85BB62E5329C4A3CB1806D094139CC04F5E9A1EC+128) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    24. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #08 pc 0262818c  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityDataAccess_RemoveComponent_m0D25ADA2F74D427F623B3B9A4F5245A72CC7EF28+248) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    25. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #09 pc 0262eec8  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityManager_RemoveComponent_mECBE9EA37BB7AA7ABE672CC5C0CA56F739AFFC16+148) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    26. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #10 pc 01cf2514  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityManager_RemoveComponent_TisRuntimeObject_mF493897B418A8680F5FFC1F0563D68C04C693E38_gshared+136) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    27. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #11 pc 0178d794  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (EntityManager_RemoveComponent_TisClearSearchBufferTag_tF726A4ED9990F31C706A32082FAB46CCB1DEDFC5_m01B82E168D0F13C4FE2C83A84E232BB20CAD6831(EntityManager_t375E301E0D409D57A32EB6EEFEE4DCFA936B3FD0*, Entity_tA8DE691EC83EB40E80A611C2E6D8C90C3C97AAF4, MethodInfo const*)+52) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    28. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #12 pc 0626a188  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ClearWorldMapSearchBufferSystem_U3COnUpdateU3Eb__0_0_m08E2B8A80BB2598AA0ED86CE864565799381286C+200) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    29. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #13 pc 01aa83a8  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (U3CU3Ec__DisplayClass_OnUpdate_LambdaJob0_OriginalLambdaBody_m69C2FD73EA1BCF3C8755A6F9F31C1B0D44DBAD7E+108) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    30. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #14 pc 01aa85f4  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (U3CU3Ec__DisplayClass_OnUpdate_LambdaJob0_PerformLambda_mAA290D66681344852404F9149003F7A4814CF5AF+400) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    31. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #15 pc 05907794  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (PerformLambdaDelegate_Invoke_mD5D06044801A1C877C141C7B868E50A9E338A558+340) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    32. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #16 pc 02742fd0  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (StructuralChangeEntityProvider_IterateEntities_mBB4379AFF0221F0534021DA21F1532C4A2340B57+464) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    33. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #17 pc 01aa87ec  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (U3CU3Ec__DisplayClass_OnUpdate_LambdaJob0_Execute_mE57CD3533659185D6ACD892AA0CC21EC094EDA03+468) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    34. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #18 pc 06269f9c  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ClearWorldMapSearchBufferSystem_OnUpdate_mFDF77DC13AF2A6FB9C06D7DAA1C7A150917FBBD8+388) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    35. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #19 pc 009d0840  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (VirtActionInvoker0::Invoke(unsigned short, Il2CppObject*)+192) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    36. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #20 pc 027437bc  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (SystemBase_Update_m0D92D889A6C4E5F50911D2F54F7D4AFAD2A8A1E9+416) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    37. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #21 pc 009d0840  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (VirtActionInvoker0::Invoke(unsigned short, Il2CppObject*)+192) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    38. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #22 pc 03d2579c  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystemGroup_UpdateAllSystems_m64E5F4CC955FE311B82029E3B5FF29B7920DB8FA+1060) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    39. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #23 pc 03d252e4  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystemGroup_OnUpdate_mECEF7D0575BFD2B045EAA8E46098148CEBDD9A3A+148) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    40. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #24 pc 009d0840  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (VirtActionInvoker0::Invoke(unsigned short, Il2CppObject*)+192) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    41. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #25 pc 03d1fd04  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystem_Update_mEF0D7970FB71282AA4C85D8E60BD33BA2A8CA4D8+408) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    42. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #26 pc 009d0840  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (VirtActionInvoker0::Invoke(unsigned short, Il2CppObject*)+192) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    43. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #27 pc 03d2579c  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystemGroup_UpdateAllSystems_m64E5F4CC955FE311B82029E3B5FF29B7920DB8FA+1060) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    44. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #28 pc 03d252e4  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystemGroup_OnUpdate_mECEF7D0575BFD2B045EAA8E46098148CEBDD9A3A+148) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    45. 2021.01.24 14:46:09.539 11634 11671 Error CRASH       #29 pc 009d0840  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (VirtActionInvoker0::Invoke(unsigned short, Il2CppObject*)+192) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    46. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #30 pc 03d1fd04  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystem_Update_mEF0D7970FB71282AA4C85D8E60BD33BA2A8CA4D8+408) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    47. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #31 pc 009d0840  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (VirtActionInvoker0::Invoke(unsigned short, Il2CppObject*)+192) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    48. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #32 pc 03d2579c  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystemGroup_UpdateAllSystems_m64E5F4CC955FE311B82029E3B5FF29B7920DB8FA+1060) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    49. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #33 pc 03d252e4  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystemGroup_OnUpdate_mECEF7D0575BFD2B045EAA8E46098148CEBDD9A3A+148) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    50. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #34 pc 009d0840  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (VirtActionInvoker0::Invoke(unsigned short, Il2CppObject*)+192) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    51. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #35 pc 03d1fd04  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (ComponentSystem_Update_mEF0D7970FB71282AA4C85D8E60BD33BA2A8CA4D8+408) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    52. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #36 pc 009d0840  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (VirtActionInvoker0::Invoke(unsigned short, Il2CppObject*)+192) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    53. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #37 pc 05907210  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (DummyDelegateWrapper_TriggerUpdate_m3B7DBA52BFE3B84CBC41FD2B80E6A8DD75954EB0+112) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    54. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #38 pc 057e9168  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (UpdateFunction_Invoke_mB17C55B92FAECE51078028F59A9F1EAC2016B1AD+572) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    55. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #39 pc 004d4808  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (RuntimeInvoker_TrueVoid_t700C6383A2A510C2CF4DD86DABD5CA9FF70ADAC5(void (*)(), MethodInfo const*, void*, void**)+56) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    56. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #40 pc 016b8f40  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (il2cpp::vm::Runtime::Invoke(MethodInfo const*, void*, void**, Il2CppException**)+312) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    57. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #41 pc 0161982c  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libil2cpp.so (il2cpp_runtime_invoke+88) (BuildId: 11d96f9a38e5bede1edb46c8adaee9ee0c3cb343)
    58. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #42 pc 00242fe5  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libunity.so (BuildId: 0992a433f0535a3697eb12bb5fb9bd1ab5c9b477)
    59. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #43 pc 0024c891  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libunity.so (BuildId: 0992a433f0535a3697eb12bb5fb9bd1ab5c9b477)
    60. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #44 pc 001bf4cf  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libunity.so (BuildId: 0992a433f0535a3697eb12bb5fb9bd1ab5c9b477)
    61. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #45 pc 001bf49d  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libunity.so (BuildId: 0992a433f0535a3697eb12bb5fb9bd1ab5c9b477)
    62. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #46 pc 001bf639  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libunity.so (BuildId: 0992a433f0535a3697eb12bb5fb9bd1ab5c9b477)
    63. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #47 pc 00297943  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libunity.so (BuildId: 0992a433f0535a3697eb12bb5fb9bd1ab5c9b477)
    64. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #48 pc 002a5dd5  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/lib/arm/libunity.so (BuildId: 0992a433f0535a3697eb12bb5fb9bd1ab5c9b477)
    65. 2021.01.24 14:46:09.540 11634 11671 Error CRASH       #49 pc 00077743  /data/app/com.avvy.app-94Asxi0qXkYQRsiD-gUhhA==/oat/arm/base.odex
    66. 2021.01.24 14:46:10.800 11634 11671 Error CRASH Tombstone written to: /storage/emulated/0/Android/data/com.avvy.app/files/tombstone_00
    67.  

    In this system was crash for example
    Code (CSharp):
    1.  public class CloudAnchorStopSearchSystem : SystemBase
    2.     {
    3.         protected override void OnUpdate()
    4.         {
    5.             Entities
    6.                 .WithoutBurst()
    7.                 .WithStructuralChanges()
    8.                 .WithAll<AzureSessionStartedTag,AzureSessionStopSearchTag,AzureSessionSearchingTag>()
    9.                 .ForEach((Entity e, SpatialAnchorSharedComponent anchorManager,ref DynamicBuffer<WorldMapSearchBuffer> searchBuffer) =>
    10.                 {
    11.                     Debug.Log(" STOP SEARCH AzureSessionStopSearchTag = "+anchorManager.SpatialAnchorWatcher);
    12.                     EntityManager.RemoveComponent<AzureSessionSearchingTag>(e);
    13.                     anchorManager.SpatialAnchorWatcher.Stop();
    14.                     searchBuffer.Clear();
    15.                 }).Run();
    16.         }
    17.     }
    System with event

    Code (CSharp):
    1. public class AnchorFoundEventSystem : ConsumeSingleEventSystemBase<FoundAnchorComponent>
    2.     {
    3.         protected override void OnEvent(FoundAnchorComponent anchorPlan)
    4.         {
    5.             Debug.Log("UNITY LOG OnAnchorLocated");
    6.             var azureEntity = GetSingletonEntity<SpatialAnchorTagSingleton>();
    7.  
    8.             var currentGridEntity = GetSingletonEntity<ArVoxelGridComponentSingleton>();
    9.             EntityManager.AddComponentData(currentGridEntity, anchorPlan);
    10.            
    11.             EntityManager.AddComponent<AzureSessionStopSearchTag>(azureEntity);
    12.         }
    13.     }
    And its execute after event system and we are suing mainthred ConsumeSingleEventSystemBase system so its strange.
     
    Last edited: Jan 25, 2021
  9. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Looking at your crash stack, I don't think this has anything to do with the event system.

    From what I can tell you are removing a component using ClearWorldMapSearchBufferSystem, but you are destroying the entity before it's played back.

    Something like this

    SystemA
    ClearWorldMapSearchBufferSystem.GetEntityCommandBuffer.RemoveComponent<TisClearSearchBufferTagT>(entity)

    SystemB
    EntityManager.DestroyEntity(entity)

    ClearWorldMapSearchBufferSystem
    Playback, entity not found - crash
     
  10. Ylly-avvyland

    Ylly-avvyland

    Joined:
    Jan 6, 2021
    Posts:
    7
    Sry for bothering you i never destroy this entity because its singleton entity. Also all of them working in main thread. All systems getting component are not destroyng it and another systems only remove /add components in my logic. May be it was coincidence that all crashes after Events system and i just suggest that can be a problem.
     
  11. Ylly-avvyland

    Ylly-avvyland

    Joined:
    Jan 6, 2021
    Posts:
    7
    Also i have question about using your system with monobehaviour.

    Some UI monobehaviour has method:
    Code (CSharp):
    1.  private void OnUIEvent<T>(T structure) where T : struct
    2. {
    3.             EventHelper.CreateEvent(structure);
    4. }
    Our EventHelper class
    Code (CSharp):
    1. public static class EventHelper
    2.     {
    3.         public static void CreateEvent<T>(params T[] events) where T : struct =>
    4.             CreateEventWithDependency(default, events);
    5.  
    6.         public static void CreateEventWithDependency<T>(JobHandle dependency, params T[] events) where T : struct
    7.         {
    8.             var es = Unity.Entities.World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<EventSystem>();
    9.             var writer = es.CreateEventWriter<T>();
    10.             foreach (var @event in events)
    11.                 writer.Write(@event);
    12.             es.AddJobHandleForConsumer<T>(dependency);
    13.         }
    14.         public static void AddListener<T, V>(IEventListener<T> listener) where T : struct
    15.             where V : EventListenerSystem<T>
    16.         {
    17.             var listenerSystem = GetListenerSystem<T,V>();
    18.             listenerSystem.AddListener(listener);
    19.         }
    20.        
    21.         public static void RemoveListener<T, V>(IEventListener<T> listener) where T : struct
    22.             where V : EventListenerSystem<T>
    23.         {
    24.             var listenerSystem = GetListenerSystem<T,V>();
    25.             listenerSystem.RemoveListener(listener);
    26.         }
    27.        
    28.         private static V GetListenerSystem<T,V>()  where T : struct
    29.             where V : EventListenerSystem<T>
    30.         {
    31.             return Unity.Entities.World.DefaultGameObjectInjectionWorld.GetExistingSystem<V>();
    32.         }
    33.     }

    and then system event handler

    Code (CSharp):
    1.  public class UIScanCompleteEventSystem : ConsumeSingleEventSystemBase<CompletedScanEventComponent>
    2.     {
    3.         protected override void OnEvent(CompletedScanEventComponent data)
    4.         {
    5.             var gridEntity = GetSingletonEntity<ArVoxelGridComponentSingleton>();
    6.  
    7.             EntityManager.AddComponent<CompletedScanEventComponent>(gridEntity);
    8.            
    9.             Debug.Log("CompletedScanEventComponent ");
    10.         }
    11.     }
    In event we are suing not struct but component

    Code (CSharp):
    1.  public struct CompletedScanEventComponent : IComponentData
    2.     { }
    And then hust ECS work this our systems which has CompletedScanEventComponent in query.

    Is it a right pipeline using events? and also in Event helper function when sending event what should i use with job handler? we are using defalt and AddJobHandleForConsumer or AddJobHandleForProducer?
     
    lclemens likes this.
  12. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Yeah that's fine. It's not required for main thread to actually pass a handle but the safety system I setup can't differentiate so will throw an error. Passing default is fine for main thread.
     
    Ylly-avvyland likes this.
  13. Ylly-avvyland

    Ylly-avvyland

    Joined:
    Jan 6, 2021
    Posts:
    7
    I have some more questions:

    1) System working in main thread with manualy iteartion on entites
    Code (CSharp):
    1.  if (requestsTagQuery.CalculateEntityCount() > 0)
    2.             {
    3.                 foreach (var tagEntity in requestsTagQuery.ToEntityArray(Unity.Collections.Allocator.Temp))
    4.                 {
    5.                     //Call Event here
    6.                 }
    7.             }
    Should i set dependency as default?

    2) Can i also call events from regular async methods also in main thread? what dependency should be set for event ?
     
  14. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Anything in main thread is fine. Calling it from another thread though will cause issues outside of jobs.
     
  15. Sylmerria

    Sylmerria

    Joined:
    Jul 2, 2012
    Posts:
    365
    [EDIT] Fixed, the read call was not done with the good event type :/

    hey tertle !

    I have encounter a strange bug today.
    Even if this code works for others events for one case it throws me errors


    ArgumentException: Reading out of bounds
    BovineLabs.Event.Containers.NativeEventStream+Reader.CheckNotReadingOutOfBounds (System.Int32 size) (at Library/PackageCache/com.bovinelabs.event@1.2.2/BovineLabs.Event/Containers/NativeEventStream.Reader.cs:150)
    BovineLabs.Event.Containers.NativeEventStream+Reader.ReadUnsafePtr (System.Int32 size) (at Library/PackageCache/com.bovinelabs.event@1.2.2/BovineLabs.Event/Containers/NativeEventStream.Reader.cs:86)
    BovineLabs.Event.Containers.NativeEventStream+Reader.Read[T] () (at Library/PackageCache/com.bovinelabs.event@1.2.2/BovineLabs.Event/Containers/NativeEventStream.Reader.cs:114)
    HMH.ECS.PathFinding.WalkabilitySystem+WalkabilityApplyEventCellRoadblockLayerUpdatedJob.Execute (BovineLabs.Event.Containers.NativeEventStream+Reader stream, System.Int32 readerIndex) (at Assets/Scripts/ECS/PathFinding/WalkabilitySystem.cs:261)
    BovineLabs.Event.Jobs.JobEventReader+EventJobReaderStruct`2[TJob,T].Execute (BovineLabs.Event.Jobs.JobEventReader+EventJobReaderStruct`2[TJob,T]& fullData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at Library/PackageCache/com.bovinelabs.event@1.2.2/BovineLabs.Event/Jobs/IJobEventReader.cs:186)


    Code (CSharp):
    1.             Dependency = new WalkabilityApplyEventCellRoadblockLayerUpdatedJob
    2.             {
    3.                 CellDataCFERO = cellDataCFERO, CellIndexToCellReader = cellIndexToCell, CellToAddAsRoadBlock = _cellToAddAsRoadBlock, CellToRemoveAsRoadBlock = _cellToRemoveAsRoadBlock
    4.             }.Schedule<WalkabilityApplyEventCellRoadblockLayerUpdatedJob, EventCellRoadblockLayerUpdated>(eventSystem, Dependency);

    Code (CSharp):
    1.         [BurstCompile]
    2.         private struct WalkabilityApplyEventCellRoadblockLayerUpdatedJob : IJobEventReader<EventCellRoadblockLayerUpdated>
    3.         {
    4.             public void Execute(NativeEventStream.Reader stream, int readerIndex)
    5.             {
    6.                 for (var foreachIndex = 0; foreachIndex < stream.ForEachCount; foreachIndex++)
    7.                 {
    8.                     var count = stream.BeginForEachIndex(foreachIndex);
    9.  
    10.                     for (var i = 0; i < count; i++)
    11.                     {
    12.                         var e = stream.Read<EventBuildingAddedToCell>();
    13.  
    14.                         var cellData = CellDataCFERO[CellIndexToCellReader[e.CellIndex]];
    15.  
    16.                         var actionListRoadBlock = cellData.IsRoadblock ? CellToRemoveAsRoadBlock : CellToAddAsRoadBlock;
    17.                         actionListRoadBlock.Add(GridHelper.GridToWorldSpace(e.CellIndex));
    18.                     }
    19.                 }
    20.             }
    21.  
    22.             #region Variables
    23.  
    24.             [ReadOnly]
    25.             public CellIndexToCellReader CellIndexToCellReader;
    26.             [ReadOnly]
    27.             public ComponentDataFromEntity<CellData> CellDataCFERO;
    28.  
    29.             public NativeList<float3> CellToAddAsRoadBlock;
    30.             public NativeList<float3> CellToRemoveAsRoadBlock;
    31.  
    32.             #endregion
    33.         }

    Have you an idea ?
     
    Last edited: Mar 24, 2021
  16. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    478
    After I found this post, I checked samples and noticed you were creating an event system in fixed step and simulation, but I can't find documentation on it or understand how it works, so I just copied the pattern and hoped for the best.
    Code (CSharp):
    1.     [ClientWorld]
    2.     [UpdateInGroup(typeof(SimulationSystemGroup))]
    3.     public class EventSystemSimulation : EventSystem { }
    Code (CSharp):
    1.     [ClientWorld]
    2.     [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    3.     public class EventSystemFixedStep : EventSystem { }
    I guess these two systems are reading from the same containers because messages are getting from one to the other, but I'm unsure if this is the correct setup as I couldn't find it mentioned in the docs. However, if I only use the default EventSystem I get an unmatched amount of reads vs writes so I guess this is the way to do it.

    In any case, with this setup I noticed that sometimes a read from EventSystemSimulation happens a frame after a write to EventSystemFixedStep, despite simulation system group running every frame and always after fixed step group.

    Is this expected or am I doing something wrong?

    Cheers, and very cool event system package!
     
  17. jasons-novaleaf

    jasons-novaleaf

    Joined:
    Sep 13, 2012
    Posts:
    181
    That seems expected to me.
    EventSystemSimulation
    is running as fast as your frame rate (eg: 200fps) while
    EventSystemFixedStep
    is running at the physics rate (eg: 60fps)
     
  18. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    So when dealing with multiple EventSystems (different update rates), they sync between each other on the EventSystems Update call so this usually introduces at least a frame delay.

    One thing to note, when dealing with fixed update you'll probably want to turn on UsePersistentAllocator.
    Note this is about 10% slower from benchmarking, but if you don't and your fixed vs normal update rate ever varies by 4x (50 vs 200 fps) you'll start leaking memory/events.
    This will be fixed properly when Unity's new memory management is released giving us control over the lifecycles.
     
    Last edited: Mar 26, 2021
    Shinyclef likes this.
  19. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    478
    In my case, fixed update was running faster than simulation update for testing purposes.
     
  20. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    478
    Right understood. I'll look into how this sync works, but I'm sure I can deal with a frame delay anyway. Cheers.
     
  21. mike1997

    mike1997

    Joined:
    Jul 1, 2016
    Posts:
    25
    Hello and first thangs for a great library.

    In using it I encountered an issue, I'm new to ecs, so could be very simple, but I just can't find a solution.

    When running a job with no passed in native arrays, it all runs fine.

    Code (CSharp):
    1. private struct OwnershipEventJob : IJobEvent<AskForItemOwnershipEvent>
    2. {
    3.  
    4.             //public NativeArray<int> test;
    5.             public void Execute(AskForItemOwnershipEvent e)
    6.             {
    7.                 Debug.Log($"===============Reading onwership requests from: {e.userId}, {e.indexPos} ");
    8.              }
    9. }
    But when I uncomment the native test array, or any other native container, I start getting this error:

    InvalidOperationException: GetEventReaders must always be balanced by a AddJobHandleForConsumer call
    GetReaders was previously called from BovineLabs.Event.Jobs.JobEvent:ScheduleInternal (Mlf.Npc.NpcOwnershipSystem+OwnershipEventJob,BovineLabs.Event.Systems.EventSystemBase,Unity.Jobs.JobHandle,System.Boolean) (at :0)
    BovineLabs.Event.Systems.EventContainer.GetReaders () (at Assets/Scripts/Imported/BovineLabs.Event/Systems/EventContainer.cs:150)

    Any help would be greatly appreciated.
     
  22. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Sure there is no other error? Can I see your schedule code.

    public NativeArray<int> test; would usually require a [ReadOnly] or something
     
  23. mike1997

    mike1997

    Joined:
    Jul 1, 2016
    Posts:
    25
    thx for a very fast reply

    Here is my complete systembase code

    Code (CSharp):
    1.  
    2.     [UpdateAfter(typeof(EndSimulationEntityCommandBufferSystem))]
    3.     public class NpcOwnershipSystem : SystemBase
    4.     {
    5.         EventSystem eventSystem;
    6.  
    7.         protected override void OnUpdate()
    8.         {
    9.            
    10.             Dependency = new OwnershipEventJob
    11.             {
    12.              
    13.             }.Schedule<OwnershipEventJob, AskForItemOwnershipEvent>(eventSystem);
    14.            
    15.         }
    16.  
    17.         protected override void OnCreate()
    18.         {
    19.             base.OnCreate();
    20.             eventSystem = World.GetOrCreateSystem<EventSystem>();
    21.         }
    22.  
    23.        
    24.  
    25.         [BurstCompile]
    26.         private struct OwnershipEventJob : IJobEvent<AskForItemOwnershipEvent>
    27.         {
    28.             [ReadOnly]
    29.             public NativeArray<int> test;
    30.  
    31.             public void Execute(AskForItemOwnershipEvent e)
    32.             {
    33.                 Debug.Log($"===============Reading onwership requests from: {e.userId}, {e.indexPos} ");
    34.             }
    35.         }
    36.  
    37.  


    I tried adding readonly, but that didn't fix it
     
  24. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Are you sure you aren't getting an exception from the safety system about not assigning that array?
     
  25. mike1997

    mike1997

    Joined:
    Jul 1, 2016
    Posts:
    25
    Yes, you were right about the dependencies.

    Thanks a lot for all the help, and for providing a great library, and support.
     
  26. Abbrew

    Abbrew

    Joined:
    Jan 1, 2018
    Posts:
    417
    Does your event system support single producers multiple consumers? Like a producer generates an event and all consumers can read and process that one event
     
    lclemens likes this.
  27. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Yes.
    You can have multi producer, multi consumer.
    It even works across different tick rates if you set it up (won't get double events or miss events).
     
    Abbrew likes this.
  28. Luxxuor

    Luxxuor

    Joined:
    Jul 18, 2019
    Posts:
    89
    First off thank you for this great package! Really love how its usage parallels that of ECBs, makes it much easier to explain the concept to new people (familiar with DOTS) imho.

    What would be the correct setup for having multi producer from a fixed update group and single consumer from the simulation step (but after the fixed group)? I understand the need for the persistent allocator but struggle to understand in which group the event system itself should update (do I understand correctly that the event stream gets "cleared" in its OnUpdate method?).
     
  29. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    You need a separate event system per update type. So you should have an event system in your fixed update group as well as the default one in the normal update. Then just make sure they target the same bus.

    The producers in the fixed update system should use the event system thats in the fixed update group and the consumer should use the regular event system (if not either you'll miss events or read them multiple times).

    Events only get disposed when every event system (that are grouped) reports back they have processed them.

    -edit-

    note that for cross update groups, events are usually delayed a frame.
    if you really need them same frame, from memory you'll need to move the eventsystem from initialization to after your fixed update group but before your consumer. this may cause issues with timing of other events now though so ideally it's better if you can just ignore a potential 1 frame delay.
     
    Last edited: Apr 20, 2021
    Luxxuor likes this.
  30. Luxxuor

    Luxxuor

    Joined:
    Jul 18, 2019
    Posts:
    89
    Thanks for the explanation, to target the same bus all that is needed is the same world mode/custom key right? I assume it would be best to have the "FixedEventSystem" at the start of the group then or does the ordering not matter?

    The 1 frame delay is indeed not a huge problem as all the gameplay logic happens in the FixedUpdateGroup and the single consumer is only for exposing certain game events to trigger visual/audio feedback for animators etc (we expose UnityEvents for them so they can do their magic).
     
  31. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Yes to world mode/key. I don't think you would have to do anything in this case since they're in the same world which is what it default binds to from memory, but just something worth checking (let's you in theory send events between worlds [not usually advised] or break your world up into different event groups etc.)

    Ordering should never matter in the sense that events should not be lost but it could introduce another frame lag so better to be first.
     
    Last edited: Apr 20, 2021
    Luxxuor likes this.
  32. Luxxuor

    Luxxuor

    Joined:
    Jul 18, 2019
    Posts:
    89
    Cool cool, I'll try it out. Thanks for the help!
     
  33. adamz

    adamz

    Joined:
    Jul 18, 2007
    Posts:
    1,192
    @toomasio Hey, I saw that you put together Playmaker Actions for XR Inputs. How am I able to get the input from the joystick? I tired using 'Input System Read Vector2 Value' and assigned a vector2 variable, but it's not working. Is there another Action I should use? Please reply either here or on the Playmaker forum. Thanks!
     
    toomasio likes this.
  34. adamz

    adamz

    Joined:
    Jul 18, 2007
    Posts:
    1,192
  35. mike1997

    mike1997

    Joined:
    Jul 1, 2016
    Posts:
    25
    Hello in one of the systems I would like to be able to delay some of the events. So based on the properties of an event, I would like to be able to choose to deal with it now, or to postpone to the next frame, what would be the best approach to let certain events live till the next frame while consuming the rest?
     
  36. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Put it in a queue and fire it off next frame.
     
  37. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    714
    This is probably a stupid question, but... is there a way to get events inside of an Entities.ForEach() instead of inheriting IJobEvent or IJobEventReaderForEach ?
     
  38. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    It doesn't make much sense to me to read events in a Entities.ForEach (Job.WithCode makes more sense to me). However, you can just manually call GetReaders from EventSystem but you get a list of readers so you need to schedule a job per reader.

    Alternative there is an extension ToNativeList which will copy all the events to a single list OR an extension for EnsureHashMapCapacity where you can then use a IJobEvent to populate a hashmap then just use this in your Entities.ForEach (using a hashmap and Entities.ForEach makes the most sense to me, you can just early out on entities that didn't get an event)

    Side note, there's a new 2.0 branch I put up a month or so ago that reworks the entire event system so that
    - it's entirely unmanage
    - is decoupled from the system during OnUpdate
    - because of the above 2, now works with ISystemBase
    - in Entities 0.18 the scheduling and job handling within the EventSystem will also be burstable
    - stripped back to what i consider the core functionality (removing features i thought went against the DOTS workflow)
     
    Last edited: Aug 4, 2021
    Egad_McDad, lclemens, NotaNaN and 3 others like this.
  39. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    714
    Wow, that's badass!! I went to the repo and checked it out, but I'm a bit lost without an example. I'm guessing for listening to events inherit ConsumeEventSystemBase<T> and implement OnEventStream()? And use NativeEventStream for writing?
     
  40. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    Yeah I haven't really updated documentation (and i've only ported like half the unit tests but it seems to work from my limited testing)

    Haven't tested this code but it's very similar to before. However now you only access the system once, register your event producer/consumer and keep a reference to that. This is then used to create writers/readers.

    Writing like this

    Code (CSharp):
    1. private EventProducer<EventType> producer;
    2.  
    3. protected override void OnCreate()
    4. {
    5.     this.producer = this.World.GetOrCreateSystem<EventSystem>().RegisterProducer<EventType>();
    6. }
    7.  
    8. protected override void OnUpdate()
    9. {
    10.     var writer = this.producer.CreateWriter();
    11.  
    12.     this.Entities.ForEach((Entity entity) =>
    13.         {
    14.             writer.Write(new EventType { Value = entity.Index });
    15.         })
    16.         .ScheduleParallel();
    17.  
    18.     this.producer.AddJobHandle(this.Dependency);
    19. }
    Reading.

    Code (CSharp):
    1.  
    2. private EventConsumer<EventType> consumer;
    3.  
    4. protected override void OnCreate()
    5. {
    6.     this.consumer = this.World.GetOrCreateSystem<EventSystem>().RegisterConsumer<EventType>();
    7. }
    8.  
    9. protected override void OnUpdate()
    10. {
    11.     this.Dependency = this.consumer.GetReaders(this.Dependency, out var readers);
    12.  
    13.     for (var r = 0; r < readers.Length; r++)
    14.     {
    15.         var reader = readers[r];
    16.  
    17.         this.Job.WithCode(() =>
    18.         {
    19.  
    20.             for (var index = 0; index < readers.Length; index++)
    21.             {
    22.                 reader.BeginForEachIndex(index);
    23.  
    24.                 while (reader.RemainingItemCount > 0)
    25.                 {
    26.                     var e = reader.Read<EventType>();
    27.                 }
    28.             }
    29.         })
    30.         .Schedule();
    31.     }
    32.  
    33.     this.consumer.AddJobHandle(this.Dependency);
    34. }
    35.  
    Reading with IJobEvent, not you no longer need to pass in generic parameters (previously you'd need something like ScheduleParallel<ReadJob, EventType>(

    Code (CSharp):
    1.         private EventConsumer<EventType> consumer;
    2.  
    3.         protected override void OnCreate()
    4.         {
    5.             this.consumer = this.World.GetOrCreateSystem<EventSystem>().RegisterConsumer<EventType>();
    6.         }
    7.  
    8.         protected override void OnUpdate()
    9.         {
    10.             this.Dependency = new ReadJob().ScheduleParallel(this.consumer, this.Dependency);
    11.         }
    12.  
    13.         [BurstCompile]
    14.         private struct ReadJob : IJobEvent<EventType>
    15.         {
    16.             public void Execute(EventType e)
    17.             {
    18.  
    19.             }
    20.         }
     
    Last edited: Aug 15, 2021
  41. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    714
    Very cool!!!! I'm all for less boilerplate :). I'm in the middle of working on my damage system, but when I'm done I'll clone the master branch and add it to my project and give it a shot.
     
    NotaNaN likes this.
  42. Ylly-avvyland

    Ylly-avvyland

    Joined:
    Jan 6, 2021
    Posts:
    7
    I know its look like a problem with PackageManager, but just cheking that instrcution at first post correct to get package.
    So we get an error

    Code (CSharp):
    1. An error occurred while resolving packages:
    2.   Project has invalid dependencies:
    3.     com.bovinelabs.event: connect ETIMEDOUT 35.247.98.4:4873
    May be now package should be register in manifest with another url or something?
     
  43. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    ok so AWS nuked my web server for some reason :shrug: so I've moved them to openupm

    https://openupm.com/packages/com.bovinelabs.event/

    I'll try to remember to update documentation this weekend
     
    Sylmerria and Ylly-avvyland like this.
  44. SpindizzyGames

    SpindizzyGames

    Joined:
    Jun 29, 2017
    Posts:
    108
    How do I install this? Which version of Unity is required?
     
  45. SpindizzyGames

    SpindizzyGames

    Joined:
    Jun 29, 2017
    Posts:
    108
    never mind... making progress :)
     
    tertle likes this.
  46. SpindizzyGames

    SpindizzyGames

    Joined:
    Jun 29, 2017
    Posts:
    108
    Tertle - I am new to DOTS but experienced with classic Unity. I am looking into events a way to communicate between ECS and classic unity.

    I'm thinking of developing a MVC (Model View Controller) pattern for my game where the UI, sound engine and maybe user input is on the classic Unity side while logic, physics and networking is on the DOTS side.

    Is your Event framework ideal for what I am trying to accomplish? It appears to be cleaner than method shown in this Code Monkey tutorial posted below, but I'd like to make sure I'm on the right path by choosing your Event framework as you're far more knowledgeable than I am. :)

    How to handle Events in Unity DOTS! (C# Events from ECS) - YouTube
     
  47. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    I think it'd work fine. The idea for the original implementation was efficiently firing events out from ECS for things like audio, telemetry, gizmos etc. I never really intended it to be used for gameplay communication between systems which I consider to be a bit of a DOTS anti pattern.

    I'd stick with V1 though (which is what is ib openupm).
    V2 is more experimental definitely designed for pure ECS in the future when everything can be unmanaged using ISystem.
    However V1 is unlikely to get many updates in the future except to fix it if it breaks as it just works and I consider it pretty stable as it's been used in at least 2 titles released on steam.
     
    SpindizzyGames likes this.
  48. Bivens32

    Bivens32

    Joined:
    Jul 8, 2013
    Posts:
    36
    Can you explain why it is an anti-pattern? I'm just curious. It seems to me that for any complex gameplay, you have to have a way to send messages from one entity to another. Like if you have a fireball flying through the air, when it hits a target, it somehow has to communicate that it hit the target and did damage/burn effect. In MB world we would just get the target component then apply effects through method call and be done. The easiest way for me in ECS has seemed to be to fire an event (tertle event or entity event) and let another system pick it up in the next frame.

    It seems to me that sending messages may be the most optimal software architecture for emergent/sandbox type games. After all, the billions/trillions of cells (entities) in a human body primarily communicate through little chemical messages or events. A cell communicates this way to itself, to nearby cells, and to far away cells. There's got to be some merit to this way of design or biological systems would not use it. Just curious for how you would handle complex emergent gameplay systems in ecs without events.
     
  49. Enzi

    Enzi

    Joined:
    Jan 28, 2013
    Posts:
    909
    Regarding the anti pattern. What you don't want for fast paced, 1 frame events, is solutions like:
    - adding/removing components because it causes structural changes and they are slow
    - creating entities, adding/setting components and destroying them again in single frame

    Been there, done that, don't do it.

    This lead to (very) bad performance. Note here, DOTS devs have acknowledged this problem in the past and probably will have solutions in the future. In the meantime, the only save way is, don't rely on it or expect your architecture to not scale well. It's not a real problem for just a few events!

    That's why ECS event systems mostly use NativeQueues, streams or any other fast way to write data that is processed by other systems then.
    This is why the typical observer/subscriber messaging pattern is an anti pattern to ECS. You don't call an event method, like X happened and then other systems that subscribed to it work on it immediately. For one, ECS doesn't even allow it and b) it goes against the ECS batch nature of working on a specific set of data and then move on to the next.

    The next thing, is even when these events are processed, they usually don't run on the chunks that have the data (AFAIK that's a thing that isn't solved in tertles framework, it's unable to work on queries/chunks), so that leaves it with being forced to read and write from/to random memory which is also not fast and scalable.

    "Events" can still be done, it's just written in a different form and are not as convenient to setup and extend. You'd have dedicated systems that check/handle events. You can setup this well with partial classes but it's still far from the convenience you get from simply creating a class and implementing an interface with a type like the OOP messaging patterns.

    For the best between the 2 worlds, use the framework form tertle. I have not used it personally in a bigger project but I know tertle has put in lots of time to make it as convenient and fast as possible.
     
    lclemens likes this.
  50. Bivens32

    Bivens32

    Joined:
    Jul 8, 2013
    Posts:
    36
    Oh yes I use tertle's event system already. I also don't really add/remove components most of the time. I typically read all events and map them to target entities using a native hashmap/multi hashmap. It works very well, though the systems that use tertle event systems seem to allocate garbage. I haven't looked into it extensively and I've never tried it in a build. I'll have to look into more later. I was really just curious why tertle thinks using his event system for gameplay is an anti-pattern.