andreakarasho / TinyEcs

A tiny bevy-like archetype-style ECS library for dotnet
MIT License
83 stars 1 forks source link

Component Lifecycle Terms #18

Open xentripetal opened 2 months ago

xentripetal commented 2 months ago

Hey I really like the direction you're taking this library! I've been bouncing between different ECS libs and this seems like a great option.

It would be very helpful if queries had support for defining filters based on the lifecycle of components.

Mainly:

  1. Changed\<T> - Evaluates to true when component T was accessed mutably or set for the entity since the last execution of the query

  2. Added\<T> - Evaluates to true when component T was added to an entity since the last execution of the query

    I'm not fully sure how bevy does this but it seems like they store a vec of watermarks alongside each column that gets updated each time an entry in the column is accessed mutably or added. Then each query tracks a watermark of when it was last ran it uses for comparison. https://github.com/bevyengine/bevy/blob/main/crates/bevy_ecs/src/change_detection.rs https://bevy-cheatbook.github.io/programming/change-detection.html

  3. Removed\<T> - Evaluates to true when component T was removed from an entity since the last execution of the query

    In bevy, removals publish out an event that systems can read if they run the next frame https://github.com/bevyengine/bevy/blob/main/crates/bevy_ecs/src/removal_detection.rs

xentripetal commented 2 months ago

Also wanted to give you a heads up that I posted a MR benchmarking this lib https://github.com/Doraku/Ecs.CSharp.Benchmark/pull/29

Showed really great results

andreakarasho commented 2 months ago

On my list! but not sure what would be the right strategy to apply honestly, because components access is always by ref. So everytime you access ref entity.Get<T>() (or when quering) it will set the component as Changed<T> [?]

xentripetal commented 2 months ago

Hmm, yeah adding variations for ref vs non ref would make the query gen way too large.

I wonder if you could introduce wrapper component types like

public ref struct ChangeTracked<T> where T : struct
{
    public ChangeTracked(Ref<T> value)
    {
        _value = value;
    }

    private Ref<T> _value;
    public bool Changed = false;

    public T Value
    {
        get => _value.Value;
        set
        {
            _value.Value = value;
            Changed = true;
        }
    }
}

that would be automatically handled by the query system to resolve down to T ComponentInfo and update the cell watermark when changed

andreakarasho commented 2 months ago

I'm not sure about that. I put on the table this too: https://github.com/SanderMertens/flecs/blob/master/docs/Queries.md#change-detection

xentripetal commented 2 months ago

I've started working on a POC where that's stored alongside the component array for chunks https://github.com/xentripetal/TinyEcs/commit/8dca1e2808a1d1a72a9e287a5f93b69c2f5593e8#diff-58f635af42e8d7ed9ebdcb7026ea8163e9fda76b51eefc446bb8ca91fe50a015R11

Add tracking is easy, but I'm not sure how to do the Change notifications either. I think your only options are

  1. Introduce a wrapper type for components
  2. Have a manual NotifyChanged method you can do on the EntityView
  3. Support non-ref struct queries
xentripetal commented 2 months ago

Though you likely want some way for a query to denote what components it reads vs writes, that way you can start tracking the dependencies of systems for parallelization. So IMO if theres a path to 3, thats the best option.

I believe flecs does it with a NotifyChange and supports parallelization via manually annotating queries

andreakarasho commented 2 months ago

More a proof of concept than anything, not sure if it will work with the full functionalities set like bevy: https://github.com/andreakarasho/TinyEcs/compare/main...feat/change-detection

xentripetal commented 2 months ago

Nice! How does that Removed flag work? If it gets flagged on the old archetype then the old arch row is marked as invalid and won't track anything

andreakarasho commented 2 months ago

Pushed more commits. Looks like it starting work. Unfortunately I have no clue how to implement the Each<> methods.

Good catch about the removed component. I didn't realize until now that you just posted the solution with your first post! Basically bevy uses the events under the hood