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

Add AssetChanged query filter #16810

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
451 changes: 451 additions & 0 deletions crates/bevy_asset/src/asset_changed.rs

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions crates/bevy_asset/src/assets.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::asset_changed::AssetChanges;
use crate::{
self as bevy_asset, Asset, AssetEvent, AssetHandleProvider, AssetId, AssetServer, Handle,
UntypedHandle,
};
use alloc::sync::Arc;
use bevy_ecs::{
prelude::EventWriter,
system::{Res, ResMut, Resource},
system::{Res, ResMut, Resource, SystemChangeTick},
};
use bevy_reflect::{Reflect, TypePath};
use bevy_utils::HashMap;
Expand Down Expand Up @@ -559,7 +560,24 @@ impl<A: Asset> Assets<A> {
/// A system that applies accumulated asset change events to the [`Events`] resource.
///
/// [`Events`]: bevy_ecs::event::Events
pub fn asset_events(mut assets: ResMut<Self>, mut events: EventWriter<AssetEvent<A>>) {
pub(crate) fn asset_events(
mut assets: ResMut<Self>,
mut events: EventWriter<AssetEvent<A>>,
asset_changes: Option<ResMut<AssetChanges<A>>>,
ticks: SystemChangeTick,
) {
use AssetEvent::{Added, LoadedWithDependencies, Modified, Removed};

if let Some(mut asset_changes) = asset_changes {
for new_event in &assets.queued_events {
match new_event {
Removed { id } | AssetEvent::Unused { id } => asset_changes.remove(id),
Added { id } | Modified { id } | LoadedWithDependencies { id } => {
asset_changes.insert(*id, ticks.this_run());
}
};
}
}
events.send_batch(assets.queued_events.drain(..));
}

Expand Down
16 changes: 16 additions & 0 deletions crates/bevy_asset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,15 @@
// FIXME(3492): remove once docs are ready
// FIXME(15321): solve CI failures, then replace with `#![expect()]`.
#![allow(missing_docs, reason = "Not all docs are written yet, see #3492.")]
#![allow(unsafe_code)]
tychedelia marked this conversation as resolved.
Show resolved Hide resolved
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc(
html_logo_url = "https://bevyengine.org/assets/icon.png",
html_favicon_url = "https://bevyengine.org/assets/icon.png"
)]

extern crate alloc;
extern crate core;

pub mod io;
pub mod meta;
Expand All @@ -159,13 +161,17 @@ pub mod transformer;
///
/// This includes the most common types in this crate, re-exported for your convenience.
pub mod prelude {
#[doc(hidden)]
pub use crate::asset_changed::AssetChanged;

#[doc(hidden)]
pub use crate::{
Asset, AssetApp, AssetEvent, AssetId, AssetMode, AssetPlugin, AssetServer, Assets,
DirectAssetAccessExt, Handle, UntypedHandle,
};
}

mod asset_changed;
mod assets;
mod direct_access_ext;
mod event;
Expand Down Expand Up @@ -205,6 +211,7 @@ use crate::{
};
use alloc::sync::Arc;
use bevy_app::{App, Last, Plugin, PreUpdate};
use bevy_ecs::prelude::Component;
use bevy_ecs::{
reflect::AppTypeRegistry,
schedule::{IntoSystemConfigs, IntoSystemSetConfigs, SystemSet},
Expand Down Expand Up @@ -400,6 +407,15 @@ impl Plugin for AssetPlugin {
)]
pub trait Asset: VisitAssetDependencies + TypePath + Send + Sync + 'static {}

/// A trait for newtypes that can be used as asset identifiers, i.e. handle wrappers.
tychedelia marked this conversation as resolved.
Show resolved Hide resolved
pub trait AsAssetId: Component {
/// The underlying asset type.
type Asset: Asset;

/// Converts this component to an asset id.
tychedelia marked this conversation as resolved.
Show resolved Hide resolved
fn as_asset_id(&self) -> AssetId<Self::Asset>;
}

/// This trait defines how to visit the dependencies of an asset.
/// For example, a 3D model might require both textures and meshes to be loaded.
///
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_ecs/macros/src/world_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,10 @@ pub(crate) fn world_query_impl(
}
}

fn get_state(components: &#path::component::Components) -> Option<#state_struct_name #user_ty_generics> {
fn get_state<'w>(world: impl Into<#path::world::unsafe_world_cell::UnsafeWorldCell<'w>>) -> Option<#state_struct_name #user_ty_generics> {
let world = world.into();
Some(#state_struct_name {
#(#named_field_idents: <#field_types>::get_state(components)?,)*
#(#named_field_idents: <#field_types>::get_state(world)?,)*
})
}

Expand Down
63 changes: 32 additions & 31 deletions crates/bevy_ecs/src/query/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
archetype::{Archetype, Archetypes},
bundle::Bundle,
change_detection::{MaybeThinSlicePtrLocation, Ticks, TicksMut},
component::{Component, ComponentId, Components, Mutable, StorageType, Tick},
component::{Component, ComponentId, Mutable, StorageType, Tick},
entity::{Entities, Entity, EntityLocation},
query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
storage::{ComponentSparseSet, Table, TableRow},
Expand Down Expand Up @@ -342,7 +342,7 @@ unsafe impl WorldQuery for Entity {

fn init_state(_world: &mut World) {}

fn get_state(_components: &Components) -> Option<()> {
fn get_state<'w>(_world: impl Into<UnsafeWorldCell<'w>>) -> Option<()> {
Some(())
}

Expand Down Expand Up @@ -418,7 +418,7 @@ unsafe impl WorldQuery for EntityLocation {

fn init_state(_world: &mut World) {}

fn get_state(_components: &Components) -> Option<()> {
fn get_state<'w>(_world: impl Into<UnsafeWorldCell<'w>>) -> Option<()> {
Some(())
}

Expand Down Expand Up @@ -501,7 +501,7 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> {

fn init_state(_world: &mut World) {}

fn get_state(_components: &Components) -> Option<()> {
fn get_state<'w>(_world: impl Into<UnsafeWorldCell<'w>>) -> Option<()> {
Some(())
}

Expand Down Expand Up @@ -581,7 +581,7 @@ unsafe impl<'a> WorldQuery for EntityMut<'a> {

fn init_state(_world: &mut World) {}

fn get_state(_components: &Components) -> Option<()> {
fn get_state<'w>(_world: impl Into<UnsafeWorldCell<'w>>) -> Option<()> {
Some(())
}

Expand Down Expand Up @@ -673,7 +673,7 @@ unsafe impl<'a> WorldQuery for FilteredEntityRef<'a> {
FilteredAccess::default()
}

fn get_state(_components: &Components) -> Option<Self::State> {
fn get_state<'w>(_world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
Some(FilteredAccess::default())
}

Expand Down Expand Up @@ -767,7 +767,7 @@ unsafe impl<'a> WorldQuery for FilteredEntityMut<'a> {
FilteredAccess::default()
}

fn get_state(_components: &Components) -> Option<Self::State> {
fn get_state<'w>(_world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
Some(FilteredAccess::default())
}

Expand Down Expand Up @@ -853,12 +853,12 @@ where
}

fn init_state(world: &mut World) -> Self::State {
Self::get_state(world.components()).unwrap()
Self::get_state(world).unwrap()
}

fn get_state(components: &Components) -> Option<Self::State> {
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
tychedelia marked this conversation as resolved.
Show resolved Hide resolved
let mut ids = SmallVec::new();
B::get_component_ids(components, &mut |maybe_id| {
B::get_component_ids(world.into().components(), &mut |maybe_id| {
if let Some(id) = maybe_id {
ids.push(id);
}
Expand Down Expand Up @@ -952,12 +952,12 @@ where
}

fn init_state(world: &mut World) -> Self::State {
Self::get_state(world.components()).unwrap()
Self::get_state(world).unwrap()
}

fn get_state(components: &Components) -> Option<Self::State> {
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
let mut ids = SmallVec::new();
B::get_component_ids(components, &mut |maybe_id| {
B::get_component_ids(world.into().components(), &mut |maybe_id| {
if let Some(id) = maybe_id {
ids.push(id);
}
Expand Down Expand Up @@ -1038,7 +1038,7 @@ unsafe impl WorldQuery for &Archetype {

fn init_state(_world: &mut World) {}

fn get_state(_components: &Components) -> Option<()> {
fn get_state<'w>(_world: impl Into<UnsafeWorldCell<'w>>) -> Option<()> {
Some(())
}

Expand Down Expand Up @@ -1197,8 +1197,8 @@ unsafe impl<T: Component> WorldQuery for &T {
world.register_component::<T>()
}

fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
world.into().components().component_id::<T>()
}

fn matches_component_set(
Expand Down Expand Up @@ -1396,8 +1396,8 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
world.register_component::<T>()
}

fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
world.into().components().component_id::<T>()
}

fn matches_component_set(
Expand Down Expand Up @@ -1595,8 +1595,8 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
world.register_component::<T>()
}

fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
world.into().components().component_id::<T>()
}

fn matches_component_set(
Expand Down Expand Up @@ -1699,8 +1699,8 @@ unsafe impl<'__w, T: Component> WorldQuery for Mut<'__w, T> {
}

// Forwarded to `&mut T`
fn get_state(components: &Components) -> Option<ComponentId> {
<&mut T as WorldQuery>::get_state(components)
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<ComponentId> {
<&mut T as WorldQuery>::get_state(world)
}

// Forwarded to `&mut T`
Expand Down Expand Up @@ -1826,8 +1826,8 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
T::init_state(world)
}

fn get_state(components: &Components) -> Option<Self::State> {
T::get_state(components)
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
T::get_state(world)
}

fn matches_component_set(
Expand Down Expand Up @@ -1985,8 +1985,8 @@ unsafe impl<T: Component> WorldQuery for Has<T> {
world.register_component::<T>()
}

fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
world.into().components().component_id::<T>()
}

fn matches_component_set(
Expand Down Expand Up @@ -2144,8 +2144,9 @@ macro_rules! impl_anytuple_fetch {
($($name::init_state(world),)*)
}
#[allow(unused_variables)]
fn get_state(components: &Components) -> Option<Self::State> {
Some(($($name::get_state(components)?,)*))
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
let world = world.into();
Some(($($name::get_state(world)?,)*))
}

fn matches_component_set(_state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
Expand Down Expand Up @@ -2239,8 +2240,8 @@ unsafe impl<D: QueryData> WorldQuery for NopWorldQuery<D> {
D::init_state(world)
}

fn get_state(components: &Components) -> Option<Self::State> {
D::get_state(components)
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
D::get_state(world)
}

fn matches_component_set(
Expand Down Expand Up @@ -2307,7 +2308,7 @@ unsafe impl<T: ?Sized> WorldQuery for PhantomData<T> {

fn init_state(_world: &mut World) -> Self::State {}

fn get_state(_components: &Components) -> Option<Self::State> {
fn get_state<'w>(_world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
Some(())
}

Expand Down
23 changes: 12 additions & 11 deletions crates/bevy_ecs/src/query/filter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
archetype::Archetype,
component::{Component, ComponentId, Components, StorageType, Tick},
component::{Component, ComponentId, StorageType, Tick},
entity::Entity,
query::{DebugCheckedUnwrap, FilteredAccess, StorageSwitch, WorldQuery},
storage::{ComponentSparseSet, Table, TableRow},
Expand Down Expand Up @@ -194,8 +194,8 @@ unsafe impl<T: Component> WorldQuery for With<T> {
world.register_component::<T>()
}

fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
world.into().components().component_id::<T>()
}

fn matches_component_set(
Expand Down Expand Up @@ -305,8 +305,8 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
world.register_component::<T>()
}

fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
world.into().components().component_id::<T>()
}

fn matches_component_set(
Expand Down Expand Up @@ -488,8 +488,9 @@ macro_rules! impl_or_query_filter {
($($filter::init_state(world),)*)
}

fn get_state(components: &Components) -> Option<Self::State> {
Some(($($filter::get_state(components)?,)*))
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<Self::State> {
let world = world.into();
Some(($($filter::get_state(world)?,)*))
}

fn matches_component_set(_state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
Expand Down Expand Up @@ -763,8 +764,8 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
world.register_component::<T>()
}

fn get_state(components: &Components) -> Option<ComponentId> {
components.component_id::<T>()
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<ComponentId> {
world.into().components().component_id::<T>()
}

fn matches_component_set(
Expand Down Expand Up @@ -996,8 +997,8 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
world.register_component::<T>()
}

fn get_state(components: &Components) -> Option<ComponentId> {
components.component_id::<T>()
fn get_state<'w>(world: impl Into<UnsafeWorldCell<'w>>) -> Option<ComponentId> {
world.into().components().component_id::<T>()
}

fn matches_component_set(
Expand Down
Loading
Loading