zakarumych / edict

Other
82 stars 6 forks source link

[Discussion] New filter API #12

Open akhilman opened 2 years ago

akhilman commented 2 years ago

I have two complains about the current edict API:

I propose this changes:

Query with this changes will look like:

// the stateful filter is created outside the loop
let mut my_filter = with::<Foo>().or(with::<Bar>()).and(modified::<Baz>());
loop {
    for _, (bar, baz) in world.query_filtered<(&Bar, &Baz)>(&mut my_filter) {
        // do something
    }
}

and with passing the tracks manually:

let mut tracks = world.tracks_now()
loop {
    world.for_each_filtered::<(&Bar, &Baz)>(
        &mut with::<Foo>()
            .or(with::<Bar>())
            .and(modified_since::<Baz>(tracks)),
         |_, (bar. baz)| { ... } );
    tracks = world.tracks_now();  // tracks is updated explicitly 
}

Solves #10

akhilman commented 2 years ago

We also can implement operators, so creating a filter would look like this:

let mut my_filter = !with::<Foo>() && (modified::<Bar>() || modified::<Baz>());
zakarumych commented 2 years ago

In this case one would need an instance of Tracks for each modified filter (implicit or explicit). Which may or may not be a bad thing. But to keep this in mind while we deciding on the API

zakarumych commented 2 years ago

The problem with putting modification filtering into, well, filters, is that it would require to lock the version arrays immutably, which would prevent locking them mutably for mutable component query.

And if filter won't lock version arrays immutably, parallel query would be able to lock them mutably and cause a minor case of nasal demons.

zakarumych commented 2 years ago

Theoretically we can lock components for complex query at once and then distribute it to sub-queries and filters and allow trackers to look at versions of mutably borrowed component. But this can make code too complex and possibly slow.