Skip to content

Commit 0b67084

Browse files
committed
[assets] fix Assets being set as 'changed' each frame (#2280)
## Objective - Fixes: #2275 - `Assets` were being flagged as 'changed' each frame regardless of if the assets were actually being updated. ## Solution - Only have `Assets` change detection be triggered when the collection is actually modified. - This includes utilizing `ResMut` further down the stack instead of a `&mut Assets` directly.
1 parent f602dcf commit 0b67084

File tree

4 files changed

+34
-5
lines changed

4 files changed

+34
-5
lines changed

crates/bevy_asset/src/asset_server.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
RefChange, RefChangeChannel, SourceInfo, SourceMeta,
66
};
77
use anyhow::Result;
8-
use bevy_ecs::system::Res;
8+
use bevy_ecs::system::{Res, ResMut};
99
use bevy_log::warn;
1010
use bevy_tasks::TaskPool;
1111
use bevy_utils::{HashMap, Uuid};
@@ -466,7 +466,9 @@ impl AssetServer {
466466
}
467467
}
468468

469-
pub(crate) fn update_asset_storage<T: Asset>(&self, assets: &mut Assets<T>) {
469+
// Note: this takes a `ResMut<Assets<T>>` to ensure change detection does not get
470+
// triggered unless the `Assets` collection is actually updated.
471+
pub(crate) fn update_asset_storage<T: Asset>(&self, mut assets: ResMut<Assets<T>>) {
470472
let asset_lifecycles = self.server.asset_lifecycles.read();
471473
let asset_lifecycle = asset_lifecycles.get(&T::TYPE_UUID).unwrap();
472474
let mut asset_sources_guard = None;

crates/bevy_asset/src/assets.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,11 @@ impl<T: Asset> Assets<T> {
177177
mut events: EventWriter<AssetEvent<T>>,
178178
mut assets: ResMut<Assets<T>>,
179179
) {
180-
events.send_batch(assets.events.drain())
180+
// Check if the events are empty before calling `drain`.
181+
// As `drain` triggers change detection.
182+
if !assets.events.is_empty() {
183+
events.send_batch(assets.events.drain())
184+
}
181185
}
182186

183187
pub fn len(&self) -> usize {

crates/bevy_asset/src/loader.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ impl<T: Component> Default for AssetLifecycleChannel<T> {
203203
/// Updates the [Assets] collection according to the changes queued up by [AssetServer].
204204
pub fn update_asset_storage_system<T: Asset + AssetDynamic>(
205205
asset_server: Res<AssetServer>,
206-
mut assets: ResMut<Assets<T>>,
206+
assets: ResMut<Assets<T>>,
207207
) {
208-
asset_server.update_asset_storage(&mut assets);
208+
asset_server.update_asset_storage(assets);
209209
}

crates/bevy_ecs/src/event.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,12 @@ impl<T: Component> Events<T> {
342342
self.events_b.clear();
343343
}
344344

345+
/// Returns true if there are no events in this collection.
346+
#[inline]
347+
pub fn is_empty(&self) -> bool {
348+
self.events_a.is_empty() && self.events_b.is_empty()
349+
}
350+
345351
/// Creates a draining iterator that removes all events.
346352
pub fn drain(&mut self) -> impl Iterator<Item = T> + '_ {
347353
self.reset_start_event_count();
@@ -557,4 +563,21 @@ mod tests {
557563
.iter(&events)
558564
.eq([TestEvent { i: 0 }, TestEvent { i: 1 }].iter()));
559565
}
566+
567+
#[test]
568+
fn test_events_empty() {
569+
let mut events = Events::<TestEvent>::default();
570+
assert!(events.is_empty());
571+
572+
events.send(TestEvent { i: 0 });
573+
assert!(!events.is_empty());
574+
575+
events.update();
576+
assert!(!events.is_empty());
577+
578+
// events are only empty after the second call to update
579+
// due to double buffering.
580+
events.update();
581+
assert!(events.is_empty());
582+
}
560583
}

0 commit comments

Comments
 (0)