bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.75k stars 3.62k forks source link

A query filter for Asset updates #5069

Open nicopap opened 2 years ago

nicopap commented 2 years ago

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

A major pain point of using Handle<Asset> as components in the ECS currently is that the assets pointed-to by the handle can change, and there is no simple way of reacting to changes to the asset in the context of the ECS.

For example: AABB calculation. We have a Handle<Mesh> and Aabb component in the ECS. We want to update Aabb whenever the Mesh for the Handle is updated. The Handle is updated in two circumstances:

  1. The user changes the Handle the entity has by replacing it in a system with a Query<&mut Handle<Mesh>> parameter
  2. The user changes the Mesh in the Assets<Mesh> in a system with a ResMut<Assets<Mesh>> parameter

To react to (1), it's trivial: just add a Changed<Handle<Mesh>> to the system that updates the Aabb.

To react to (2), it becomes harder. The only way to react to asset changes is to use the AssetEvent::Modified { handle: Handle<Mesh> } event. This event only holds a Handle<Mesh>, so you either need to iterate over ALL entities with a Handle<Mesh> and updates the ones that are equal to the Modified field, or keep a HashMap mapping handles to entities, and other gory details required to maintain this HashMap properly.

Most of asset changes are done through (2), which makes it very difficult to react to asset changes in the general case.

This was observed in https://github.com/bevyengine/bevy/pull/4944 and also in personal project related to scene hot-reloading.

What solution would you like?

Introducing a AssetChanged<A> query filter that is true for entities with a Handle<A> for which the underlying asset got modified since the last time the system ran.

What alternative(s) have you considered?

In the case of Mesh, it seems that moving Aabb calculation to the generation of the Mesh and keeping it as an optional Mesh field is a correct solution. This would fall into the category of "asset pre-processing" which is both possible today (through a constructor) and subject to future possible improvements.

But this is only a specific solution to a specific problem. In general, it seems reasonable to be able to bridge the gap between assets and ECS with such a query filter.

Additional context

See discussions:

bas-ie commented 2 months ago

I've closed linked PR #5080 due to its age and inactivity, but it appears this might still be useful work worthy of adoption if anyone's keen! At least, judging by the various cross-issue and PR mentions.