Skip to content

Commit 10443ce

Browse files
committed
Start asset_v2 migration BROKEN
1 parent fcf8253 commit 10443ce

File tree

4 files changed

+110
-85
lines changed

4 files changed

+110
-85
lines changed

crates/bevy_asset/src/asset_changed.rs

Lines changed: 84 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,47 @@ use std::marker::PhantomData;
44
use bevy_ecs::{
55
archetype::{Archetype, ArchetypeComponentId},
66
component::{ComponentId, Tick},
7-
prelude::{Changed, Entity, Or, World},
7+
prelude::{Changed, Entity, Or, Resource, World},
88
query::{Access, FilteredAccess, QueryItem, ReadFetch, ReadOnlyWorldQuery, WorldQuery},
99
storage::{Table, TableRow},
1010
world::unsafe_world_cell::UnsafeWorldCell,
1111
};
1212
use bevy_utils::HashMap;
1313

14-
use crate::{asset_changes::AssetChanges, Asset, Handle, HandleId};
14+
use crate::{Asset, AssetId, Handle};
1515

16-
#[derive(Clone, Copy)]
17-
struct AssetChangeCheck<'w> {
18-
handle_change_map: &'w HashMap<HandleId, Tick>,
16+
#[doc(hidden)]
17+
#[derive(Resource)]
18+
pub struct AssetChanges<A: Asset> {
19+
pub(crate) change_ticks: HashMap<AssetId<A>, Tick>,
20+
pub(crate) last_change_tick: Tick,
21+
}
22+
impl<A: Asset> Default for AssetChanges<A> {
23+
fn default() -> Self {
24+
Self {
25+
change_ticks: Default::default(),
26+
last_change_tick: Tick::new(0),
27+
}
28+
}
29+
}
30+
31+
struct AssetChangeCheck<'w, A: Asset> {
32+
handle_change_map: &'w HashMap<AssetId<A>, Tick>,
1933
last_run: Tick,
2034
this_run: Tick,
2135
}
22-
impl<'w> AssetChangeCheck<'w> {
23-
fn new<T: Asset>(changes: &'w AssetChanges<T>, last_run: Tick, this_run: Tick) -> Self {
36+
impl<A: Asset> Clone for AssetChangeCheck<'_, A> {
37+
fn clone(&self) -> Self {
38+
AssetChangeCheck {
39+
handle_change_map: self.handle_change_map,
40+
last_run: self.last_run,
41+
this_run: self.this_run,
42+
}
43+
}
44+
}
45+
impl<A: Asset> Copy for AssetChangeCheck<'_, A> {}
46+
impl<'w, A: Asset> AssetChangeCheck<'w, A> {
47+
fn new(changes: &'w AssetChanges<A>, last_run: Tick, this_run: Tick) -> Self {
2448
Self {
2549
handle_change_map: &changes.change_ticks,
2650
last_run,
@@ -29,7 +53,7 @@ impl<'w> AssetChangeCheck<'w> {
2953
}
3054
// TODO(perf): some sort of caching? Each check has two levels of indirection,
3155
// which is not optimal.
32-
fn has_changed<T: Asset>(&self, handle: &Handle<T>) -> bool {
56+
fn has_changed(&self, handle: &Handle<A>) -> bool {
3357
if let Some(&handle_change_tick) = self.handle_change_map.get(&handle.id()) {
3458
handle_change_tick.is_newer_than(self.last_run, self.this_run)
3559
} else {
@@ -38,29 +62,29 @@ impl<'w> AssetChangeCheck<'w> {
3862
}
3963
}
4064

41-
/// A shortcut for the commonly used `Or<(Changed<Handle<T>>, AssetChanged<T>)>`
65+
/// A shortcut for the commonly used `Or<(Changed<Handle<A>>, AssetChanged<A>)>`
4266
/// query.
4367
///
44-
/// If you want to react to changes to `Handle<T>` component of an entity, you have
68+
/// If you want to react to changes to `Handle<A>` component of an entity, you have
4569
/// two cases to worry about:
46-
/// - The `Handle<T>` was changed through a `Query<&mut Handle<T>>`.
47-
/// - The `T` in `Assets<T>` pointed by `Handle<T>` was changed through a
48-
/// `ResMut<Assets<T>>::get_mut`.
70+
/// - The `Handle<A>` was changed through a `Query<&mut Handle<A>>`.
71+
/// - The `A` in `Assets<A>` pointed by `Handle<A>` was changed through a
72+
/// `ResMut<Assets<A>>::get_mut`.
4973
///
5074
/// To properly handle both those cases, you need to combine the `Changed` and `AssetChanged`
5175
/// filters. This query type does it for you.
52-
pub type AssetOrHandleChanged<T> = Or<(Changed<Handle<T>>, AssetChanged<T>)>;
76+
pub type AssetOrHandleChanged<A> = Or<(Changed<Handle<A>>, AssetChanged<A>)>;
5377

54-
/// Query filter to get all entities which `Handle<T>` component underlying asset changed.
78+
/// Query filter to get all entities which `Handle<A>` component underlying asset changed.
5579
///
56-
/// Unlike `Changed<Handle<T>>`, this filter returns entities for which **the underlying `T`
80+
/// Unlike `Changed<Handle<A>>`, this filter returns entities for which **the underlying `A`
5781
/// asset** was changed. For example, when modifying a `Mesh`, you would do so through the
58-
/// [`Assets<Mesh>::get_mut`] method. This does not change the `Handle<T>` that entities have
59-
/// as component, so `Changed<Handle<T>>` **will not do anything**. While with `AssetChanged<T>`,
82+
/// [`Assets<Mesh>::get_mut`] method. This does not change the `Handle<A>` that entities have
83+
/// as component, so `Changed<Handle<A>>` **will not do anything**. While with `AssetChanged<A>`,
6084
/// all entities with the modified mesh will be queried.
6185
///
6286
/// # Notes
63-
/// **performance**: This reads a hashmap once per entity with a `Handle<T>` component, this might
87+
/// **performance**: This reads a hashmap once per entity with a `Handle<A>` component, this might
6488
/// result in slowdown, particularly if there are a lot of such entities. Note that if there was no
6589
/// updates, it will simply skip everything.
6690
///
@@ -73,15 +97,15 @@ pub type AssetOrHandleChanged<T> = Or<(Changed<Handle<T>>, AssetChanged<T>)>;
7397
///
7498
/// [`AssetStage::AssetEvents`]: crate::AssetStage::AssetEvents
7599
/// [`Assets<Mesh>::get_mut`]: crate::Assets::get_mut
76-
pub struct AssetChanged<T>(PhantomData<T>);
100+
pub struct AssetChanged<A>(PhantomData<A>);
77101

78102
/// Fetch for [`AssetChanged`].
79103
#[doc(hidden)]
80-
pub struct AssetChangedFetch<'w, T: Asset> {
81-
inner: Option<ReadFetch<'w, Handle<T>>>,
82-
check: AssetChangeCheck<'w>,
104+
pub struct AssetChangedFetch<'w, A: Asset> {
105+
inner: Option<ReadFetch<'w, Handle<A>>>,
106+
check: AssetChangeCheck<'w, A>,
83107
}
84-
impl<'w, T: Asset> Clone for AssetChangedFetch<'w, T> {
108+
impl<'w, A: Asset> Clone for AssetChangedFetch<'w, A> {
85109
fn clone(&self) -> Self {
86110
Self {
87111
inner: self.inner,
@@ -92,31 +116,31 @@ impl<'w, T: Asset> Clone for AssetChangedFetch<'w, T> {
92116

93117
/// State for [`AssetChanged`].
94118
#[doc(hidden)]
95-
pub struct AssetChangedState<T: Asset> {
119+
pub struct AssetChangedState<A: Asset> {
96120
handle_id: ComponentId,
97121
asset_changes_id: ComponentId,
98122
asset_changes_archetype_id: ArchetypeComponentId,
99-
_asset: PhantomData<fn(T)>,
123+
_asset: PhantomData<fn(A)>,
100124
}
101125

102126
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
103-
unsafe impl<T: Asset> WorldQuery for AssetChanged<T> {
127+
unsafe impl<A: Asset> WorldQuery for AssetChanged<A> {
104128
type ReadOnly = Self;
105-
type Fetch<'w> = AssetChangedFetch<'w, T>;
106-
type State = AssetChangedState<T>;
129+
type Fetch<'w> = AssetChangedFetch<'w, A>;
130+
type State = AssetChangedState<A>;
107131

108132
type Item<'w> = bool;
109133

110134
fn shrink<'wlong: 'wshort, 'wshort>(item: QueryItem<'wlong, Self>) -> QueryItem<'wshort, Self> {
111135
item
112136
}
113137

114-
fn init_state(world: &mut World) -> AssetChangedState<T> {
138+
fn init_state(world: &mut World) -> AssetChangedState<A> {
115139
let asset_changes_resource_id =
116-
if let Some(id) = world.components().resource_id::<AssetChanges<T>>() {
140+
if let Some(id) = world.components().resource_id::<AssetChanges<A>>() {
117141
id
118142
} else {
119-
world.init_resource::<AssetChanges<T>>()
143+
world.init_resource::<AssetChanges<A>>()
120144
};
121145
let asset_changes_archetype_id = world
122146
.storages()
@@ -125,7 +149,7 @@ unsafe impl<T: Asset> WorldQuery for AssetChanged<T> {
125149
.unwrap()
126150
.id();
127151
AssetChangedState {
128-
handle_id: world.init_component::<Handle<T>>(),
152+
handle_id: world.init_component::<Handle<A>>(),
129153
asset_changes_id: asset_changes_resource_id,
130154
asset_changes_archetype_id,
131155
_asset: PhantomData,
@@ -146,27 +170,27 @@ unsafe impl<T: Asset> WorldQuery for AssetChanged<T> {
146170
) -> Self::Fetch<'w> {
147171
let err_msg = || {
148172
panic!(
149-
"AssetChanges<{ty}> was removed, please do not remove AssetChanges<{ty}> when using AssetChanged<{ty}>",
150-
ty = std::any::type_name::<T>()
151-
)
173+
"AssetChanges<{ty}> was removed, please do not remove AssetChanges<{ty}> when using AssetChanged<{ty}>",
174+
ty = std::any::type_name::<A>()
175+
)
152176
};
153177
let changes: &AssetChanges<_> = world.get_resource().unwrap_or_else(err_msg);
154178
let has_updates = changes.last_change_tick.is_newer_than(last_run, this_run);
155179
AssetChangedFetch {
156180
inner: has_updates
157181
.then(|| <&_>::init_fetch(world, &state.handle_id, last_run, this_run)),
158-
check: AssetChangeCheck::new::<T>(changes, last_run, this_run),
182+
check: AssetChangeCheck::new(changes, last_run, this_run),
159183
}
160184
}
161185

162-
const IS_DENSE: bool = <&Handle<T>>::IS_DENSE;
186+
const IS_DENSE: bool = <&Handle<A>>::IS_DENSE;
163187

164188
// This Fetch filters more than just the archetype.
165189
const IS_ARCHETYPAL: bool = false;
166190

167191
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
168192
if let Some(inner) = &mut fetch.inner {
169-
<&Handle<T>>::set_table(inner, &state.handle_id, table);
193+
<&Handle<A>>::set_table(inner, &state.handle_id, table);
170194
}
171195
}
172196

@@ -177,7 +201,7 @@ unsafe impl<T: Asset> WorldQuery for AssetChanged<T> {
177201
table: &'w Table,
178202
) {
179203
if let Some(inner) = &mut fetch.inner {
180-
<&Handle<T>>::set_archetype(inner, &state.handle_id, archetype, table);
204+
<&Handle<A>>::set_archetype(inner, &state.handle_id, archetype, table);
181205
}
182206
}
183207

@@ -187,7 +211,7 @@ unsafe impl<T: Asset> WorldQuery for AssetChanged<T> {
187211
table_row: TableRow,
188212
) -> Self::Item<'w> {
189213
fetch.inner.as_mut().map_or(false, |inner| {
190-
let handle = <&Handle<T>>::fetch(inner, entity, table_row);
214+
let handle = <&Handle<A>>::fetch(inner, entity, table_row);
191215
fetch.check.has_changed(handle)
192216
})
193217
}
@@ -203,7 +227,7 @@ unsafe impl<T: Asset> WorldQuery for AssetChanged<T> {
203227

204228
#[inline]
205229
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
206-
<&Handle<T>>::update_component_access(&state.handle_id, access);
230+
<&Handle<A>>::update_component_access(&state.handle_id, access);
207231
access.add_read(state.asset_changes_id);
208232
}
209233

@@ -214,17 +238,20 @@ unsafe impl<T: Asset> WorldQuery for AssetChanged<T> {
214238
access: &mut Access<ArchetypeComponentId>,
215239
) {
216240
access.add_read(state.asset_changes_archetype_id);
217-
<&Handle<T>>::update_archetype_component_access(&state.handle_id, archetype, access);
241+
<&Handle<A>>::update_archetype_component_access(&state.handle_id, archetype, access);
218242
}
219243
}
220244

221245
/// SAFETY: read-only access
222-
unsafe impl<T: Asset> ReadOnlyWorldQuery for AssetChanged<T> {}
246+
unsafe impl<A: Asset> ReadOnlyWorldQuery for AssetChanged<A> {}
223247

224248
#[cfg(test)]
225249
mod tests {
226-
use crate::{AddAsset, Assets};
250+
use crate::{self as bevy_asset, AssetPlugin};
251+
252+
use crate::{AssetApp, Assets};
227253
use bevy_app::{App, AppExit, Startup, Update};
254+
use bevy_core::TaskPoolPlugin;
228255
use bevy_ecs::{
229256
entity::Entity,
230257
event::EventWriter,
@@ -235,16 +262,15 @@ mod tests {
235262

236263
use super::*;
237264

238-
#[derive(bevy_reflect::TypeUuid, TypePath)]
239-
#[uuid = "44115972-f31b-46e5-be5c-2b9aece6a52f"]
265+
#[derive(Asset, TypePath, Debug)]
240266
struct MyAsset(u32, &'static str);
241267

242268
fn run_app<Marker>(system: impl IntoSystem<(), (), Marker>) {
243269
let mut app = App::new();
244-
app.add_plugins((bevy_core::FrameCountPlugin, crate::AssetPlugin::default()))
245-
.add_asset::<MyAsset>()
270+
app.add_plugins((TaskPoolPlugin::default(), AssetPlugin::default()))
271+
.init_asset::<MyAsset>()
246272
.add_systems(Update, system);
247-
app.run();
273+
app.update();
248274
}
249275

250276
#[test]
@@ -301,7 +327,7 @@ mod tests {
301327

302328
#[test]
303329
fn asset_change() {
304-
#[derive(Default, Resource)]
330+
#[derive(Default, PartialEq, Debug, Resource)]
305331
struct Counter(u32, u32);
306332

307333
let mut app = App::new();
@@ -324,12 +350,11 @@ mod tests {
324350

325351
fn update_once(mut assets: ResMut<Assets<MyAsset>>, mut run_count: Local<u32>) {
326352
let mut update_index = |i| {
327-
let handle = assets
353+
let id = assets
328354
.iter()
329355
.find_map(|(h, a)| (a.0 == i).then_some(h))
330356
.unwrap();
331-
let handle = assets.get_handle(handle);
332-
let asset = assets.get_mut(&handle).unwrap();
357+
let asset = assets.get_mut(id).unwrap();
333358
asset.1 = "new_value";
334359
};
335360
match *run_count {
@@ -339,8 +364,8 @@ mod tests {
339364
};
340365
*run_count += 1;
341366
}
342-
app.add_plugins((bevy_core::FrameCountPlugin, crate::AssetPlugin::default()))
343-
.add_asset::<MyAsset>()
367+
app.add_plugins((TaskPoolPlugin::default(), AssetPlugin::default()))
368+
.init_asset::<MyAsset>()
344369
.init_resource::<Counter>()
345370
.add_systems(
346371
Startup,
@@ -355,10 +380,10 @@ mod tests {
355380
},
356381
)
357382
.add_systems(Update, (count_update, update_once).chain());
358-
let assert_counter = |app: &App, assert: Counter| {
383+
#[track_caller]
384+
fn assert_counter(app: &App, assert: Counter) {
359385
let counter = app.world.get_resource::<Counter>().unwrap();
360-
assert_eq!(counter.0, assert.0);
361-
assert_eq!(counter.1, assert.1);
386+
assert_eq!(counter, &assert);
362387
};
363388
// First run of the app, `add_systems(Startup…)` runs.
364389
app.update(); // run_count == 0

crates/bevy_asset/src/asset_changes.rs

Lines changed: 0 additions & 23 deletions
This file was deleted.

crates/bevy_asset/src/assets.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
use crate::{Asset, AssetEvent, AssetHandleProvider, AssetId, AssetServer, Handle};
1+
use crate::{
2+
asset_changed::AssetChanges, Asset, AssetEvent, AssetHandleProvider, AssetId, AssetServer,
3+
Handle,
4+
};
25
use bevy_ecs::{
36
prelude::EventWriter,
4-
system::{Res, ResMut, Resource},
7+
system::{Res, ResMut, Resource, SystemChangeTick},
58
};
69
use bevy_reflect::{Reflect, Uuid};
710
use bevy_utils::HashMap;
@@ -478,7 +481,23 @@ impl<A: Asset> Assets<A> {
478481
/// A system that applies accumulated asset change events to the [`Events`] resource.
479482
///
480483
/// [`Events`]: bevy_ecs::event::Events
481-
pub fn asset_events(mut assets: ResMut<Self>, mut events: EventWriter<AssetEvent<A>>) {
484+
pub fn asset_events(
485+
mut assets: ResMut<Self>,
486+
mut events: EventWriter<AssetEvent<A>>,
487+
asset_changes: Option<ResMut<AssetChanges<A>>>,
488+
ticks: SystemChangeTick,
489+
) {
490+
if let Some(mut asset_changes) = asset_changes {
491+
for new_event in &assets.queued_events {
492+
use AssetEvent::{Added, LoadedWithDependencies, Modified, Removed};
493+
match new_event {
494+
Removed { id } => asset_changes.change_ticks.remove(id),
495+
Added { id } | Modified { id } | LoadedWithDependencies { id } => {
496+
asset_changes.change_ticks.insert(*id, ticks.this_run())
497+
}
498+
};
499+
}
500+
}
482501
events.send_batch(assets.queued_events.drain(..));
483502
}
484503
}

0 commit comments

Comments
 (0)