bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Disjoint QueryData access

Open vil-mo opened this issue 1 year ago • 0 comments

What problem does this solve or what need does it fill?

In generic contexts, or when you have really complex QueryData parameters, there is currently no way to have disjoint QueryData access in a single query iteration For example, you have a generic system that changes Transform based on an output of the generic parameter:

trait EntitySystem {
    Data: QueryData;
    Out;

    fn run(data: QueryItem<Self::Data>) -> Self::Out;
}

fn change_transform<T: EntitySystem<Out = Vec3>>(mut query: Query<DataSet<(T::Data, &mut Transform)>>) {
    for mut set in query.iter_mut() {
        let desirable_translation = T::run(set.d0());
        let mut transform = set.d1();
        transform.translation = desirable_translation;
    }
}

What solution would you like?

For this feature request I will name such QueryData implementer DataSet (similar to how ParamSet for SystemParam was named)

Implementation would be similar to the ParamSet implementation. Requires cloning WorldQuery::Fetch in call to WorldQuery::fetch

pub struct DataSet<'w, T: QueryData> {
    fetch: T::Fetch<'w>,
    entity: Entity,
    table_row: TableRow,
}

What alternative(s) have you considered?

Lose much performance and ergonomics. or Implement much simpler Matches query filter. Still loses much ergonomics. There, Matches<D> is the filter that allows iterating only on those entities could have iterated on D if it was in place of Data generict parameter of Query. That would allow to:

fn alternative_function(query: Query<Entity, Matches<(D0, D1)>>, mut set: ParamSet<(Query<(D0)>, Query<(D1)>)>) {
    for entity in query.iter() {
        let p0_query = set.p0();
        let p0_data = p0_query.get_mut();
        // Code with p0 ....
        let p1_query = set.p1();
        let p1_data = p1_query.get_mut();
        // Code with p1 ....
    }
}

or

fn alternative_function(mut set: ParamSet<(Query<(Entity, D0), Matches<D1>>, Query<D1, Matches<D0>>)>) {
    let mut p0_map = EntityHashMap::new();
    for (entity, data) in set.p0().iter_mut() {
        let result = calculation_for_p0(data);
        p0_map.insert(entity, result);
    }

    for (entity, data) in set.p1().iter_mut() {
        let p0_result = p0_hash_map.get_mut(&entity).unwrap();
        // Actual code ...
    }
}

vil-mo avatar Jul 29 '24 12:07 vil-mo