Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change tracking #174

Closed
FeldrinH opened this issue Jul 19, 2021 · 8 comments
Closed

Change tracking #174

FeldrinH opened this issue Jul 19, 2021 · 8 comments

Comments

@FeldrinH
Copy link

The upstreaming Bevy changes issue (#71) mentioned among othert things change detection.
That issue was closed with Bevy ECS and Hecs diverging due to serving different needs.

However, change tracking seems like a useful feature to have as part of the core ECS. Especially if having an ability to query changed components could be implemented in the ECS with better time complexity than just querying all components and checking for some changed boolean.

What is the current status of this? Are there any plans to include change detection in Hecs?

@Ralith
Copy link
Owner

Ralith commented Jul 19, 2021

There have been a couple experiments, at #83 and #92. Both are just syntax sugar for stuff you can already do. As far as I'm aware, an external implementation does not sacrifice any performance. Depending on application you'll want to choose between Vec<Entity>, IndexSet<Entity>, or adding a bool component, and if hecs provided this it would just be doing the same.

@smokku
Copy link

smokku commented Aug 2, 2021

I have ported Bevy mutation tracking to current hecs master branch: https://github.com/smokku/hecs/tree/e5bd2b5

Unfortunately this changes public API.

for (id, (number, &flag)) in world.query_mut::<(&mut i32, &bool)>() {

becomes

for (id, (mut number, &flag)) in world.query_mut::<(&mut i32, &bool)>() {

@Ralith
Copy link
Owner

Ralith commented Aug 2, 2021

I'm not interested in unconditional blanket mutation tracking, as I don't believe most applications, let alone most components, require it. #92-style explicit tracking fortunately doesn't change the behavior of existing queries.

@smokku
Copy link

smokku commented Aug 2, 2021

  1. I like the approach of Introduce mutation tracking query helper #92 and I would use it if there was a way of forcing developers to use the tracking. In a large project it is easy to miss Tracked<> and mutate via &mut. This will lead to very difficult to track bugs.

  2. Introduce mutation tracking query helper #92 does not track adding and removing of components.

Would you consider such change hidden behind feature flag?

@Ralith
Copy link
Owner

Ralith commented Sep 16, 2021

Would you consider such change hidden behind feature flag?

More features, especially ones that are deeply intertwined with the core, can significantly complicate maintenance, so I'd prefer to find an alternative solution.

In a large project it is easy to miss Tracked<> and mutate via &mut. This will lead to very difficult to track bugs.

Could you address this by making the inner type private to a module, and only exporting a tracked interface to it? Providing strong static guarantees might require exposing some of the currently-internal query extension interfaces, but I think you could achieve a first approximation of this based on the draft PR today with #[doc(hidden)], type aliases, and perhaps grep as a second layer of defense in CI to ensure your internal, hidden, name isn't arising in other modules.

@akhilman
Copy link

akhilman commented Jan 18, 2022

I'm trying to implement my change tracking as a wrapper around hecs types. The basic idea is to have a BTreeMap<TypeId, AtomicBool>. and set bool value to true when the wrapper around reference is dereferenced. All I need is to know which component was changed, I don't need to know which entity was changed.

I have successfully implemented a trait that converts tuples like (&'a i32, Option<&'a mut f32>) to (TrackedRef<'a, i32>, Option<TrackedMut<'a, f32>>). At the moment I am faced with a problem that I can not solve. I don't know how to implement the trait can be used in place of Query in WorldWrapper.query<Query>() function and wrapper around QueryBorrow that will work with such trait.

Is there any example of a query wrapper? I will be grateful for any help.

Working unfinished code is here:
https://github.com/akhilman/ecstasy/blob/master/src/query/tracked.rs

Broken attempt to make Query trait is here:
https://github.com/akhilman/ecstasy/blob/broken/src/query/hecs/query.rs

@akhilman
Copy link

Here is my attempt at making trackable queries. It can only detect if some component is changed and intended to be used in the system scheduler. And yes, it is much slower then original queries.

Here is an example:

use core::any::{type_name, TypeId};
use hecs::World;
use hecs_query_tracker::{Changes, TrackableQuery};

fn main() {
    let mut world = World::default();
    world.spawn((1i32, 2u32));

    let changes = Changes::new_for::<(&i32, &u32)>();

    <(&mut i32, &mut u32)>::track(&changes)
        .query(&world)
        .iter()
        .for_each(|(_, (mut a, b))| *a = *b as i32);

    for (type_id, type_name) in [
        (TypeId::of::<i32>(), type_name::<i32>()),
        (TypeId::of::<u32>(), type_name::<u32>()),
    ] {
        if changes.is_changed(type_id) {
            println!("{} is changed", type_name);
        } else {
            println!("{} is not changed", type_name);
        }
    }
}

@Ralith
Copy link
Owner

Ralith commented Mar 16, 2024

A non-invasive equality-based helper for change tracking was added in #366.

@Ralith Ralith closed this as completed Mar 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants