Search Unity

Feedback ECS Chronos Foundation

Discussion in 'Entity Component System' started by JesOb, Apr 10, 2020.

  1. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    ECS is good new tool inside unity with best extensibility but :)

    For now it lacks 2 (that I can see) core concepts:
    • infinite world support (floating origin already in works) that will work with any future asset in store without rewriting their systems or jobs
    • time control support (like this https://ludiq.io/chronos) so we can create different time zones in game like:
      • ui (2d/3d) time
      • gameplay time
      • time slowdown in zones
      • etc
    I have call it chronos foundation :)

    What we have:
    • System Time Delta so parent systems can control time for child system. With this we can easily create FixedTime Systems for physics etc.
    What we want:
    • Core concept that will allow us to change delta time for individual entities or group of entities without any rewrite in systems. This will be foundation for tools like https://ludiq.io/chronos in DOTS
    Idea:
    • Get rid of manual settings deltatime into jobs. Make it automatic may be through IJobChunkTimed and editor job checks to check that user explicitly pass System.DeltaTime into job.
    • Store DeltaTimeScale as IChunkComponentData, ISharedComponentData or IComponentData
    • Job itself must use some IJobChunkTimed Extension method that extract data stored in chunk multiply it by provided System.Time and use right delta time for each entity (like Unity do in TransformSystem)
      • If none of TimeComponents exists then nothing special to do
      • For IChunkComponentData, ISharedComponentData there is only one float for delta time that is multiplied by System.DeltaTime and used for all entities
      • For IComponentData extension method must provide NativeArray of timescales for each entity
    • For autogenerated jobs in SystemBase foreach it can be done easily inside autogenerator
    • For manual IJobChunkTimed it must be written by hand but with handy ExtensionMethods to make it almost one line improvement.
    With some thing like this Entire Unity Ecosystem will support very flexible Time manioulation in core with entity accuracy, so all systems by default will be manageable from outside of systems :)

    Additionally we will have time support in all core systems like animation, particles, physics... and can have cool timed effects in e.g. character death slowed down animation with full physics support just by adding one component to entity :)

    P.S. Entity accuracy is handy for effects like time anomaly where delta time changes when you go closer to anomaly epicenter etc. And may be we need some rules so systems from store that will write into different time component data dont overwtire data but nicely blend it :)
     
    Last edited: Apr 10, 2020
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    When adding a cross cutting feature like this, one design principle should be that it has no noticable perf impact in particular when the feature is not used. If time can be fetched per component, that has a big negative impact on code-gen.

    I think it is very very uncommon that a game truly needs per entity time values. Grouping entities together with the same time sets seems more reasonable and would result in near zero perf impact.

    Using shared component to index into a shared delta time seems like the best approach. Worst case if you truly need different per entity time values, you just pay for it in chunk fragmentation. That seems better than every game not using the feature paying for it.


    API's could look like this:

    Code (CSharp):
    1.  
    2. float ArchetypeChunk.DeltaTime
    3.  
    4. // Entities.ForEach would pass the delta time explicitly.
    5. // Internally it is known to be the same per chunk, t
    6. // thus it gets stored in a local variable and passed as param into foreach
    7. // It will be automatically inlined when the code is compiled with burst.
    8. Entities.ForEach(float deltaTime, ref Translation translation)
    9. {
    10.     translation.Value += deltaTime * float3(0, 1, 0);
    11. }.Schedule();
    12.  
    One big open question is how this would handle fixed vs dynamic delta time. Different systems update at different frequencies. And so it's really up to the system to get a fixed delta time or dynamic delta time value.

    Maybe there is a better approach here. Anyone got some good ideas?
     
    Last edited: Apr 10, 2020
  3. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Totally agree there and thanks for reply :)
    If game dont need per entity timescale than we can have Settings In ECS Preferences to disable it so codegen will have zero perf impact.
    In game where studio decide to use per entity time sacle they will be notified about codegen and runtime impact of feature. Pretty fair :)

    You are right most game dont use it, but most engines dont allow to use it without BIG BIG pain :). May be Unity will be first one that allow :) One good application of this is slow mo effects. Engines dont allow to to that and may be we have very small amount of actual uses in wild because of that :)

    In out multiplayer game we have Slow-mo on death of mob while all other world running normally and it was BIG pain to make Animation, Physics and particles be slowed down. We use Anim curve to control timescale. For this case Changing IShaderComponentData internal value is enough :)

    For IComponentData I just imagine game or games with some anomaly zone (say sphere) where all object moving though it will slowdown slowly because slowdown is depend on distance to center.

    Amazing gameplays can be created with such tool out of the box, that by default support all custom assets from store :)

    Not quite understand you, why every game that dont use IComponentData will pay for it?
    I see only perf impart of 1 if (branch) in IJobChunk. If chunk dont have IComponentData than perf impact almost zero.

    Where I'm wrong? (actually I think I understand now, but curious about details :))

    In codegen difference in inner loop is compute delta time before loop or compute deltatime inside loop using array of timescales.

    May be I'm wrong and this is overkill and having chunk fragmentation is good enough :)


    Us I wrote before we need to store in SCD only timescale, not deltatime, and just multiply systemDeltaTime by SCD time scale. With SCD timescale 1 we actually will use delta time from system itself. So it looks (for me) like it will just work. No matter what frequency of update of delta time passed from system we just make entities run slower or faster. e.g. physics bodies that just fly slower but updated exactly same amount of time as other bodies :)

    If it is TurnBased game and core logic systems have update only once per turn it will just work too because slowed down entities just change less then others.

    Code (CSharp):
    1. //may be instead of rely on param name it is better to rely on param Type
    2. Entities.ForEach(DeltaTime dt, ref Translation translation)
    3. {
    4.     translation.Value += dt.Value * float3(0, 1, 0);
    5. }.Schedule();
     
    brunocoimbra and SamOld like this.
  4. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    If it introduces a branch to calculate delta time it means that every system has to have two outer-loop code paths.
    Realistically the only way to avoid that would be something like this:

    Code (CSharp):
    1. // either per component or chunk
    2. float* timeScale;
    3. // if per chunk use zero, if per component use 1
    4. int timescaleStride = 0;
    5. float deltaTime ...;
    6.  
    7. for(int i = 0;i != chunk.Length;i++)
    8. {
    9.       float localDeltaTime = *timeScale * deltaTime;
    10.       timeScale += timescaleStride;
    11.       Execute(localDeltaTime);
    12. }
    Also code-gen is not a bulleft proof solution here. All users would have to correctly implement this logic, given that we do have low level API and it is available to users. The actual important part here is to make an API that is simple enough that everyone uses it correctly without fail.
     
    SamOld and JesOb like this.
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    That actually makes good sense.
     
    brunocoimbra likes this.
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    How does this sound:

    Problem:
    • Ensure that in the Unity.Entities eco-system time scale is supported across every system by default.
    • Make sure it has no impact on performance when the feature is not used

    New API's

    Code (CSharp):
    1. struct ArchetypeChunk
    2. {
    3.     // New Extension method on ArchetypeChunk
    4.     public float TimeScale
    5.     {
    6.         if (HasComponent<TimeScale>())
    7.             return GetSharedComponentData<TimeScale>().Value;
    8.         else
    9.             return 1.0F;
    10.     }
    11. }
    12. struct TimeScale : ISharedComponentData
    13. {
    14.     public float Value;
    15. }
    16. float World.TimeScale

    Usage

    Code (CSharp):
    1.  
    2.  
    3. // Allow simple global control over time scale
    4. World.TimeScale = 0.5F;
    5.  
    6. // Allow per entity time scale
    7. EntityManager.AddSharedComponentData(entity, new TimeScale(0.5F));
    8.  
    9.  
    10.  
    11. struct void MyJob : IJobChunk
    12. {
    13.     float deltaTime;
    14.     void Execute(ArchetypeChunk chunk)
    15.     {
    16.         // All new code must use chunk.TimeScale to multiply the systems time scale value
    17.         var localDeltaTime = chunk.TimeScale * deltaTime;
    18.         ...
    19.     }
    20. }
    21.  
    22.  
    23. // Entities.ForEach automatically supports deltaTime including timeScale
    24. Entities.ForEach(Entity entity, float deltaTime, ref Translation translation) =>
    25. {
    26.     translation.Value.y += deltaTime;
    27. }.ScheduleParallel();
     
    Orimay, WAYNGames, SamOld and 2 others like this.
  7. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Looks as good and super simple Foundation :)

    May be later we will find a way to prevent user error like forget to multiply by chunk.TimeScale :)
     
    Last edited: Apr 11, 2020
  8. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    May be useful idea :)
    A bit verbose in code but most simple and foolproof in use

    Code (CSharp):
    1.    //This interface force you to add correct delta time prop to struct
    2.    interface IJobChunkDeltaTime : IJobChunk
    3.    {
    4.        DeltaTime DeltaTime { set; }
    5.    }
    6.  
    7.    //struct just for storing delta time in a way that forbid using it without chunk.Timescale
    8.    public struct DeltaTime
    9.    {
    10.        private Single _deltaTime;
    11.  
    12.        public static implicit operator DeltaTime( Single deltaTime )   => new DeltaTime { _deltaTime = deltaTime };
    13.        public Single GetLocalDeltaTime( ArchetypeChunk chunk )   => chunk.TimeScale * _deltaTime;
    14.    }
    15.  
    16.    //usage
    17.    struct MyJob : IJobChunkDeltaTime
    18.    {
    19.        public DeltaTime DeltaTime { get; set; } //forced by interface, auto created by IDE
    20.        
    21.        public void Execute( ArchetypeChunk chunk )
    22.        {
    23.            var localDeltaTime = DeltaTime.GetLocalDeltaTime(chunk); //the only way to get delta time, can not make mistake
    24.            //...
    25.        }
    26.    }
    27.  
    28.    void Update( Single deltaTime )
    29.    {
    30.        //creating job is as simple as if DeltaTime was just Float type
    31.        new MyJob{ DeltaTime = deltaTime }.Schedule( );
    32.    }
    33.  
     
  9. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    OMG, I have done my time system. and planning to hack it into Unity Physics.
    In my System every single entity could have a TimeScale component.
    Also, each entity can have its own TimeParent, and LocalTimeScale. So it is a tree structure independent of Transform parent tree.
    if an entity does not have TimeScale it is considered TimeScale 1.
    Also, My time system has it's own WorldDefaultTime, which is the world's root time.
    Other Components like DeltaTime, ElaspedTime, FixedTimeStep are all depending on TimeScale.
     
  10. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
  11. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Nice :)

    Can you elaborate about use cases in your case for per entity time scale?
    Do your use cases will be comfortable with SCD approach?
     
  12. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    well, the code was on my private GitLab. And not prepared for public yet. Doc is missing. But I have built some test cases.
    Time Useage Can be found in LocalTestSystem.cs;

    And if you dig into
    struct TimeChunkJob : IJobChunk
    in TimeSystem.cs
    You will found DeltaTime is completely optional.
    So the core of TimeSystem is TimeScale.
    And as TimeScale has Tree structure, check on TimeParent.cs for Components.
    ChildTime will update with parent time. And this scaling is managed by TimeScaleSystem.cs
    And if there are Time Tree structural change, TimeHierarchySystem.cs is there to update change.

    No, ChunkComponent is better. as you may want to read it in IJobCHunk.
    But I'm not even using ChunkComponent.
    As I am doing it the hard way: Time Tree
     
    Last edited: Apr 11, 2020
  13. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    I'll be working on docs, but it will take some time.
    There are many useful things in the repo.
    Like
    • Event System (With Event of Custom DataType)
    • AtomicAggregator (Atomic Add Sum Min Max Avg)
    • NativeAggregator (Aggregate on an unmanaged type)
    • NativeReference (To replace Ugly NativeArray[0])
    • NativeDelegate (to override job behavior)
    • NativeCounter
    • NativeBool
    • UnsafeParallelBuffer(concurrent write, and concurrent read)
    • JobLogger (log in job)
     
    Lars-Steenhoff likes this.
  14. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Not a fan of this. Not all jobs require delta time and having separate job types creates unnecessary complexity.
     
  15. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    @Lieene-Guo

    Sounds like you have some use cases that require a lot of time scale functionality...
    Does the simpler proposal up there solve the use cases you have and make it so that you wouldn't have to implement your own time system?

    At a minimum i think the important part here is that whatever we provide gives flexibility so that all systems can build on top of it & we can enforce that the whole ecosystem implements it.

    Building all kinds of logic on top of the time scale components / Global time values is something any user can do, and i am sure there is a million things everyone wants to control there manually. But what we want to avoid is that users have to modify physics, animation or other packages to support the time needs they have.
     
    Orimay, NotaNaN, JesOb and 1 other person like this.
  16. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    I'm excited to see this feature added, fantastic thread @Jes28!

    Have you thought about whether this should propagate down transform hierarchies? I imagine that it would be more common to want children to have the same timescale as their parents than not, so maybe it should be inherited unless the child explicitly overrides? I think that that's what a new user would intuitively expect to happen. Obviously this adds design and computational complexity. Perhaps this falls into the "building all kinds of logic on top of the time scale components" camp as mentioned by @Joachim_Ante, but it seems a bit too low level to expect all users to build their own. Managing hierarchies in ECS is not the simplest thing.

    Maybe this is a bit more specific than this thread needs to go, but it's not obvious to me what it would mean to have a rigidbody collision between two bodies with different timescales. Does a body with half the timescale just act like it has half the velocity and therefore half the momentum? Or half the velocity but double the mass to preserve momentum and impact strength? Neither of those feel quite correct, I'm curious how that would be handled.
     
  17. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    OK :)
    Just trying to help with ideas :)

    I'm sure that you find good simple way to help programmers, writing jobs with delta time, to write correct :)

    Thanks for your time and that you make good start for this feature in DOTS :)
     
  18. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    I believe it will be added in some future as default feature of DOTS :)
    May be not in first Time Scale components release but some day :)
    For me it looks like good evaluation direction of Time Systems in DOTS :)

    May be component like PropogateTimeScale on entity with root TimeScale and systems that do the job every time TimeScale changes will be good starting solution :)
     
  19. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    LinkedEntityGroup seems like a good structure to use to force all entities on a logical group to be affected by time the same way. It is straight forward to make a utility method that sets up shared components on the whole hierarchy.
     
    SamOld and JesOb like this.
  20. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    That's what I did...
    The difference is TimeScale has it's own Parent-Children Tree instead of depending on transform tree
     
  21. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    My TimeSystem is doing Time tree. So time hierarchy is managed, TimeScale is updated only if it is needed.
     
  22. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    You are absolutely right. It would be perfect if ESC has built-in TimeScale pre Entity.
    But TimeScale at Chunk/SCD level could be a terrible choice.
    You want the user to be able to control TimeScale. But not finer control, just up to per chunk.
    What if the user's goal to make a Fading Time Zone, similar to a black hole, where the center is Freezed but TimeScale is Lerped to 1 as Entity getting closer to the edge.
    Then the "black hole" would be filled with 1-Entity-Chunks, as every single TimeScale could be unique.

    For my system, I am trying to do a Bullet Force Field. Which is very much like The Force of Jedi knight in StartWar. By an energy blow, Play Can damp Bullets until it stops.
    Also, Player can Slow an enemy down by using a TimeTrap. So everything on that Enemy will be slowed, physics, animation, rate of fire, loading interval, bullet speed, etc.
    That's why I need TimeScale per Entity and Time tree.
    With TimeScale per Entity, I will have finer control over TimeScale in "Black Hole".
    With Time Tree, A slowed target will pass that "Slow-Down" to all it's Time-Children

    If TimeSacle pre * is planed, then please go directly to per entity, not per Chunk or SCD.
    Why SCD anyway? you can't even read it in a job... and SCD index is an int which has the same size as a float TimeScale... it does not save any space...
    For ChunkComponent, I believe the goal is to reduce the amount of TimeScale value instances.
    But TimeScale can be an optional ComponentData, No TimeScale mean TimeScale 1. Sothe majority of Entity will be kept the same, with no TimeScale component at all.
    Parent-Children Time Tree would do a much better job grouping and updating TimeScales, than ChunkComponent.

    Please check this
    https://github.com/lieene/SRTK.DOTS/tree/master/Assets/SRTK/Dots/TimeSystem

    Ps, I am Planing on hack TimeScale into Unity.Physics. Now I am looking in Jacobins. If there is going to be built-in support, let me know.
     
    Last edited: Apr 12, 2020
  23. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    That's a bit different from what I was talking about. My point was that it should follow the transform hierarchies because that would be the expected behaviour. A separate parallel time hierarchy seems to be a different idea with a different purpose, but I don't understand what it would be. Could you give an example of when you would need an entity to have a different time parent and transform parent?
     
  24. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Character shoots a bullet, bullet can be Character's time-child be no transform-child. So when Character is slowed bullet gets slowed too. But you definitely don't want the bullet to move with the shooter...
    Or For TimeZone, if you what to slow the object inside a Tigger, it is not always okay to transform-parent entity under the trigger.
    And for transform hierarchy, destroy parents also destroy all recursive children. But for Time hierarchy it might not be the case.

    Transform hierarchy is generally for grouping parts to one object. for example child collider groups to a rigid body. Why should I expect different "parts" of the same object to have different TimeScale? If it is not what we expect, should a transform tree use to record TimeScale?

    Transform Tree is already over-reinterpreted. It is used for many different conceptual "Groups".
    But it should be as simple as a group of objects that "transforms together".

    In other words. Transform Tree, marks who belongs to who.
    But for TimeScale, it's more like who's time is relative to who else's time.
     
    Last edited: Apr 12, 2020
  25. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    ECS just needs to add a pre-Entity TimeScale ComponentData, and it is optional (default to 1 if not present). That's good enough for other ESC core system to update delta time.
    And whether TimeScale is managed by TimeTree like what I did or other group strategy, can be left to the user to decide.
    I am totally fine to make my own system to handle TimeScale.

    again, just don't do it pre-chunk.
     
    Last edited: Apr 12, 2020
  26. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    Those are interesting cases, thanks. I think that type of thing should probably be the responsibility of game logic rather than core engine functionality, though.
     
    hippocoder likes this.
  27. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,769
    I think it is potentially problematic, when two time scale physics start interacting with each other. I.e. player vs slowed down enemy bullet.

    I would consider look into Super Hot fps game.
     
  28. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Variable rate physics worlds are for optimisation purposes only and shouldn't be mixed with slow motion effects. Slow motion effects should not be per world...
     
  29. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Not a problem if you refer to General Relativity ;)

    Yes for physic:
    1. World step duration is fixed, so it is not Variable Rate
    2. RigidBody Can have variable TimeScale that results in variable DeltaTime
    By following these rules, Dynamic Integration is perfectly fine.

    But contact Jacobin Matrix could be a problem. As Momentum Conservation And Kinematic Energy Conservation Equation would have different time input for the contact pair.
    I am looking into Jacobin Matrix to see if it can be solved...
     
  30. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    For the Black Hole Case, I mentioned.
    it is not a slow-motion effect. it is a simulation of General Relativity...

    But I am not talking about Variable rate physics worlds at all.
     
  31. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Adding PerEntity timeScale can be good for fine grained control of time in games but by default it comes with performance degradation of entire Unity. In Editor mode, compilation time, and Runtime Performance.
    Even when you dont use timescale in game at all.

    Additionally it far harder to write and maintain in systems that written by hand.
    I think Burst compiler will generate less optimized code for this
    And few additional point that we just dont see right now :)

    The only option I see to support PerEntityTimeScale is make a way to completely disable this system when project dont need it something like #if DOTS_PER_ENTITY_TIME_SCALE so all autogenerated and handwritten systems will recompile

    Even there we need to do something with over complicated code inside each and every IJobChunk and friends just to support potential use of TimeScales

    Best I can write to have minimal performance impact.
    Code (CSharp):
    1. unsafe struct SomeJob : IJobChunk
    2. {
    3.     Single deltaTime;
    4.          
    5.     public void Execute( ArchetypeChunk chunk )
    6.     {
    7.         var chunkDeltaTime = deltaTime * chunk.TimeScale;
    8.          
    9.         Single  deltaTimeOne = 1;
    10.         //additional pointer to jump address even
    11.         //if we dont usePerEntityTimeScale
    12.         Int64   jumpAddr     = 0;                  
    13.         //additional pointer for per entity timescale event if we dont use it
    14.         Single* entityTimeScalePtr = &deltaTimeOne;
    15.  
    16. #if DOTS_PER_ENTITY_TIME_SCALE
    17.         //additional test for PerEntityTimeScale event if dont used
    18.         if( chunk.Has<EntityTimeScale>( ) )
    19.         {
    20.             entityTimeScalePtr = &chunk.GetNativeArray<EntityTimeScale>( );
    21.             jumpAddr = 1;
    22.         }
    23. #endif //all other stuff will be optimized by compiler +-
    24.         var count                = chunk.Count;
    25.         var i                    = 0;
    26.         var entityDeltaTime        = 0.0f;
    27.  
    28.         goto ComputeDeltaTimeLabel;
    29.  
    30.         //move by perEntityTimeScale array in case of PerEntityTimeScale chunk
    31.         OuterLoopLabel:    entityTimeScalePtr += 1;
    32.              
    33.         // additional multiplication even when PerEntityTimeScale Dont used
    34.         ComputeDeltaTimeLabel: entityDeltaTime = *entityTimeScalePtr * chunkDeltaTime;
    35.              
    36.         InnerLoopLabel:
    37.         {
    38.             //do the job with entityDeltaTime
    39.         }
    40.  
    41.         // loop branch and potentially free jump table or just store jump address
    42.         //in jumpAddr and just jump
    43.         if( ++i < count ) switch ( jumpAddr )
    44.         {
    45.             //process only inner loop so we dont pay for delta time recomputation
    46.             case 0: goto InnerLoopLabel;
    47.             //process outer loop so we move inPerEntityTimeScaleArray and
    48.             //compute new deltaTime
    49.             case 1: goto OuterLoopLabel;
    50.         }
    51.     }
    52. }
    If someone else want to have PerEntityTimeScale you need to propose something worthwhile!
    Not only say that you need it no matter what :)
     
  32. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    The proposal here is that different entities (probably on a per chunk basis) may have different timescales and that this would be supported out of the box by all of the Unity systems, and any user or third party system that uses dt. While it's obvious how this would work in many cases, it introduces design challenges and complexity in any system that uses dt to handle interactions between entities, because those systems can no longer assume that the two entities share the same timescale. Physics is an obvious example of a system like that.

    The first simple issue with that is that it means those systems now need to manage more data to keep track of timescales, and there's probably a little bit of a performance cost to that. The more major challenge is design. What does it mean to have an interaction between things with different timescales? That's not a real world concept, so as developers we will have to think through and invent intuitive behaviours for every interaction we design. That's a significant extra burden.

    Most people won't use this feature in their games, at least not in many places. I strongly suspect that the complexities of designing sensible behaviours will lead to a lot of people doing the lazy thing and just designing their systems to assume that all entities share the same timescale. Those systems will technically be broken because they won't work for the full domain of valid inputs, and if somebody does decide to introduce a timescale component down the line, everything will fall apart. That would be a maintenance nightmare. The other possibility is that people put in the effort to make their systems correct even when they probably won't use that feature. That's an unnecessary burden, a waste of productivity, and probably has a performance cost.

    I love the idea of this being built into the engine, but I'm starting to think that the costs may not be justified.

    I definitely think that it's a bad idea to transparently pre-multiply timescale into dt per @Joachim_Ante's
    Entities.ForEach(float deltaTime, ...
    suggestion. People are not going to take that into consideration when designing their systems, and that's going to become a problem.

    I still have no idea from a design perspective what it means to have a collision between two physics bodies travelling at different speeds through time. Most games are not going to want a slow motion bullet to have relativistic behaviour. I don't think there's a universal answer to that, it's going to be game specific. I'm leaning towards believing that it should be made easier for people to build these types of systems themselves, but integrating a one size fits all timescale functionality into the engine and expecting all systems to account for it is not reasonable.
     
  33. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Optional TimeScale Component will have almost zero performance impact on games that do not use TimeScale.
    For Systems Managing TimeScale Query that needs TimeScale will end up empty, so those systems will not be running at all.
    For Systems that use TimeScale, it's just a Has?EntityTimeScale:WorldTimeScale
    Code (CSharp):
    1.     public struct TimeScaleJob : IJobChunk
    2.     {
    3.         public float worldTimeScale;
    4.         public ArchetypeChunkComponentType<TimeScale> TimeScaleTp;
    5.         public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    6.         {
    7.             NativeArray<TimeScale> timeScalePreEntity = default;
    8.             if (chunk.HasChunkComponent(TimeScaleTp)) timeScalePreEntity = chunk.GetNativeArray(TimeScaleTp);
    9.             for (int i = 0, len = chunk.Count; i < len; i++)
    10.             {
    11.                 float timeScale = timeScalePreEntity.IsCreated ? (timeScalePreEntity[i] * worldTimeScale) : worldTimeScale;
    12.                 //use time scale.....
    13.             }
    14.         }
    15.     }
    It dose not look like to be any performance overhead....
    And it is perfectly fine when the game don't use TimeScale don't check for this at all.
     
  34. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    upload_2020-4-12_18-40-1.png

    I'm sure line is pretty big performance overhead :) And auto destroy big part of Burst Optimization and vectorization abilities

    My prev post shows a way to partially avoid it but still has per chunk perf degradation
     
  35. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Yes physics is a major challenge, but
    It will not fall at all.
    It is just a matter of if you are going to use it or not. It is perfectly fine not to know Each Entity can have its own TimeScale. Just Assume that it dose not exist.
     
  36. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Why? a three way operator does not even create an instruction switch... it is just super fast..
     
  37. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Yes if you look into https://github.com/lieene/SRTK.DOTS/blob/master/Assets/SRTK/Dots/TimeSystem/TimeSystem.cs
    I am using that if out-side of for loop trick.

    but for this code example. I am trying to do it the simple way.
    And I am avoiding using if. Because it creates an instruction switch, but three-way operator is different, it runs both branch and returns the chosen value. Three more instructions, how is it bad?
    Code (CSharp):
    1.     public struct TimeScaleJob : IJobChunk
    2.     {
    3.         public float worldTimeScale;
    4.         public ArchetypeChunkComponentType<TimeScale> TimeScaleTp;
    5.         public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    6.         {
    7.             NativeArray<TimeScale> timeScalePreEntity = default;
    8.             if (chunk.HasChunkComponent(TimeScaleTp)) timeScalePreEntity = chunk.GetNativeArray(TimeScaleTp);
    9.             for (int i = 0, len = chunk.Count; i < len; i++)
    10.             {
    11.                 float timeScale = timeScalePreEntity.IsCreated ? (timeScalePreEntity[i] * worldTimeScale) : worldTimeScale;
    12.                 //use time scale.....
    13.             }
    14.         }
    15.     }
    Also for Game that dont use PreEntity TimeScale
    Just go with worldTimeScale, it is perfectly fine. no compile switch is needed at all..
     
    Last edited: Apr 12, 2020
  38. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Mostly you are right.
    Not every asset can work with this correctly.
    But without this you will have guarantee that every asset will not work with timescale at all.

    Today you just know that if you want to create game with different timescales in world than you can not use any asset from store because it will not work. You need to create your own or try to rewrite that asset and then support all updates.

    Most of game code just use delta time to move object or rotate or advance some timers. All they in 95% of cases will just work with timescale even if asset authors dont think about it.

    But biggest win will be from Packages From Unity, because all they will have support for timescale and no one need to bump about Animation, Physics, Particles, Pause Menu UI and other packages :)

    It dont solve all issues that we can run into but it will greatly help :)
     
  39. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    I think that breaks modular design principles. A system should generally be built to be modular so that it sensibly processes any entity that matches its query. If we build systems under the assumption that timescale is not being used, and they break when the timescale component is added, that's a problem. Of course we could explicitly do
    WithNone<Timescale>()
    , but that's a messy extra burden that people will inevitably forget.

    The idea seems to be that everything should implement it. I know that's primarily talking about the official Unity ecosystem, but it sounds like if I make a package, I'm expected to implement it too. I love that idea in theory, but I worry about how it plays out in practice with the complexities that introduces to handle a feature which is mostly going to only be an edge case.
     
  40. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    There you dont right :)

    Ternary operator is just syntax sugar for this:
    Code (CSharp):
    1. T result = default;
    2.  
    3. if( condition )
    4.    result = expressionA;
    5. else
    6.    result = expressionB;
    Only compiler ability to optimize dictate performance of output asm code.
    Fast code is assembly level select that just set A value or B value into C based on conditional flags.

    To use it A value and B value must be computed beforehand. In another cases compiler will generate branch.

    Second issue is additional operations in inner loop. Event 1 single additional assembler instruction can cause per probkems. You can read about this in Robert Sedgewick's book
    https://www.amazon.com/Algorithms-Parts-1-4-Fundamentals-Structure/dp/0201350882

    Third is Vectorization of such code. There I can not say much bug Burst can do match less optimisations when branches and additional instructions is there
     
  41. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    The optional design means when The Entire game does not use TimeScale, Not entity with TimeScale will ever-present.
    In that case
    WithNone<Timescale>()
    is not needed at all.
    It is up to the user whether he/she wants to learn and use TimeScale or not.
    TimeScale can be hidden perfectly. like UnsafeHashMap is hidden by NativeHashMap. you can choose not to use UnsafeHashMap at all. or start using it when you understand it and feel confident.
    This type of Unsafe things are all over ESC, just a matter of if you are ready or not.
     
  42. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,769
    Isn't that,
    • Animation and Particles have their own time scale, which you can tweak at runtime;
    • Pause Menu UI is just independent from delta time;
    • Physics, how many different times, typical game need? For these, which does use such mechanics, would be at most 2. And even for 5, I would probably just create 5 components tags, to dedicate designated FixedUpdate frequency.
    Sure it is nice to have, but realistically asking, how many of devs, will be realistically even considering using such?
    I could of course miss something in need of such asset / package, and feel free to prove me wrong, but I just don't see an application of such, for significant major of devs. Maybe for creating different worlds (planets), with different time. In other words, only fraction devs probably would even consider for such feature. Maybe more for simulations, rather a games? But again, I may be wrong here.

    What I try to say, I don't feel like Unity should focus their resources, on such feature.
    It feels, we got few potential good suggestions, how problem can be solved already.
    But if asset will exists, we would see, if it gained a traction.
     
  43. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Okay, your right, it is nothing different then an if brach.
    but still, I feel that you are exaggerating how much impact it will have.
    We are forced to use if out-side of for-loop. and for case that TimeScale is present.
    one Array access and one float multiplication and one stack value assignment is the total overhead.
    if this impacts performance, it would be the job design's problem. as there are too little work for each job.

    And also, Physic is the major problem, the performance impact is totally acceptable.
     
  44. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    1. World step duration is fixed, so it is not Variable Rate
    2. RigidBody Can have variable TimeScale that results in variable DeltaTime=WorldFixedTimeStep* PreEntityTimeScale
    By following these rules, Dynamic Integration is perfectly fine.

    But contact Jacobin Matrix could be a problem. As Momentum Conservation And Kinematic Energy Conservation Equation would have different time input for the contact pair.
    I am looking into Jacobin Matrix to see if it can be solved...
     
    Last edited: Apr 12, 2020
  45. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Yes, every single particle could potentially have a different time scale...
    which looks redundant... but it is possible
     
  46. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    My perfectionist tendencies can't handle the 95% benefit for 5% brokeness thing. I'm against introducing problems like that into the ecosystem, even if the pros outweigh the cons. I can see that your way may be more pragmatic than mine.

    I would at the very least insist that the API needs to make these things explicit. For example,
    Entities.ForEach(DeltaTime deltaTime, ...)
    where
    DeltaTime
    has
    Dt
    and
    Scale
    fields which the user should manually multiply if they wish to handle timescales. This makes it impossible to forget to think about timescales and makes it more likely that systems will handle them sensibly.

    I think that timescale support should be opt-in on a per system basis, but made easy to do and encouraged by the API design. Silently pre-multiplying it into dt is going to cause developers to make bad assumptions without considering the consequences. I don't want a system to ever assume that all entities have the same timescale. It should either explicitly handle the case where they don't, refuse to process entities with modified timescales, or ignore timescales altogether. Otherwise it's a bug. The 95% case you mention can be handled by just manually doing the multiply, which would count as explicitly handling the timescale.
     
    Last edited: Apr 12, 2020
  47. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    I don't agree with that. The point of modular design is that systems should not need to know what other systems may do, within the bounds of reasonable contracts. Game dev, particularly on the indie side where Unity excels, is often very agile. I have no idea whether I'm going to add a timescale component to some entity in six months time for some edge case feature, and I don't want some of my old systems to break when I do so, particularly in the subtle ways that are likely and that I might not notice immediately.
     
  48. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    The reason Unity Dev is involved in this thread and ask about if we are okay with the SCD approach. Is that if Variable TimeScale is to be added to ECS it is better now or never. As the whole system is being designed. The Fundamental feature like Time is still not fixed, there is a world TimeSingltion but not many people are using it as I know. If this TimeScale can be handled internally, it is better to happen now, As ESC grows, it could be too hard to put it in Animation, Physics, Particle, and other systems as they would have been already too complicated. They are trying to ask how would you like to use a TimeScale if there is a TimeScale. I believe we should be focusing on how instead of if. :)

    Think of the whole DOTS as the indie game you talked about, would you rather do it now or when the game is ready for ship, and you found yourself missing TimeScale capability.
     
    Last edited: Apr 12, 2020
    JesOb likes this.
  49. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    I don't think I expressed my views well here before. I developed my opinion over the course of the thread, and came across a little muddled. I'm in favour of this functionality, but still a little sceptical of the practical impact of doing it properly. I'll try to restate more clearly.

    Let's say we're writing a turret system that makes turrets aim at an arbitrary target entity. When the target is moving, they aim ahead of it to lead the shot. The maths of leading the shot is actually a bit complicated, so let's simplify and say we're aiming at where it will be 1 second in the future. Because the system is modularly designed to work with arbitrary targets, it can't make any assumptions about them other than what it checks itself.

    When all entities can be assumed to have the same timescale, this is fairly easy. Demo code, not good code.

    Code (CSharp):
    1. this.Entities.WithAll<TurretTag>().ForEach((ref LocalToWorld transform, in Target target) => {
    2.     if (!HasComponent<LocalToWorld>(target.Entity)) return;
    3.  
    4.     var targetPosition = GetComponent<LocalToWorld>(target.Entity).Position;
    5.     var targetVelocity = HasComponent<PhysicsVelocity>(target.Entity) ? GetComponent<PhysicsVelocity>(targetEntity).Linear : 0;
    6.     var targetPositionInASecond = targetPosition + 1f * targetVelocity;
    7.  
    8.     AimAt(ref transform, targetPositionInASecond);
    9. });
    When we introduce the possibility that the arbitrary target has a modified timescale, this gets much messier. The addition of the timescale has changed the meaning of its velocity component. We would need to get its timescale and multiply. Getting the timescale involves looking up additional data for that target entity, probably in multiple places where the timescale might be set. This would be fiddly to do manually, and even with the addition of a simple helper method, this would be costly for performance.

    This extra effort would generally be wasted, as most targets aren't going to have a modified timescale. However, once we introduce timescales as a core feature, these checks would be required in order for the modular turret system to be truly correct for all expected inputs. We're forced to choose between a performance degradation and a known bug that we're hoping "probably wont matter".

    I also expect many people not to think of this edge case when writing things like turret systems, so it will be a very common accidental bug. That means we can't even rely on system authors to document the requirement properly. I'm concerned about the mess this feature introduces into the ecosystem.

    It might be possible to engineer a very fast and convenient helper method for getting the timescale from an arbitrary entity. That would help. However, it would still introduce a significant design burden for some complex systems, where the sensible interpretation of different timescales isn't clear. I expect most system authors to just assume a timescale of 1. If that becomes the standard behaviour, that significantly reduces the usefulness of the feature.

    I would love to see functionality like this in DOTS - I don't mean to be negative about it. I do think these concerns merit considerable design attention though, because if they can't be solved, the burden might be more trouble than it's worth.

    The counterargument is that a partial solution is better than no solution, and we're at least giving people a way to do this if they want to - it's up to them whether they choose to support it. I can see how that could be considered pragmatic. My concern is that we will end up with a mess of assets with differing levels of support, and poor documentation about their support. Where support is automatic because the engine premultiplied it for them, bugs may arise because the authors hadn't put the support there intentionally. I worry this design decision could have knock-on effects for lots of other things in the ecosystem.

    The alternative is that each system that chooses to support timescales could simply engineer an independent solution themselves, so you end up with
    AnimationTimescale
    ,.
    PhysicsTimescale
    ,
    AudioTimescale
    ,
    MyCustomAssetTimescale
    etc. The dev would have to do the extra work of adding those components and syncing them up when they want them, but it avoids the problem of adding an additional bit of contract that all systems are expected to adhere to. It's actually more powerful too, because sometimes you may want different systems to run at different speeds. Each system dev would always be consciously aware of the timescale situation - either they would be explicitly building that functionality, or they just wouldn't support it - no unexpected magic to consider. That wouldn't actually fix my turret example though -
    PhysicsTimescale
    would still need to be considered...
     
    Last edited: Apr 29, 2020
  50. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    It would be cheeting if the turrets know the target's velocity. I will use an aiming system that evaluates the target's speed overtime and try it's best to shot ahead. If the target has a linear motion, you will get the right speed by that evaluation no matter what time scale it has.
    It will miss when the target's speed changes unexpectedly, that's the desired dodge action.
    And If you what the turret to be 100% accurate then just let it hit and play a fake animation.