Skip to content

Commit 2391e44

Browse files
atornityalice-i-cecilehymmMinerSebas
authored
added ability to get Res<T> from World with World::get_resource_ref (#11561)
# Objective It's sometimes desirable to get a `Res<T>` rather than `&T` from `World::get_resource`. Alternative to #9940, partly adresses #9926 ## Solution added additional methods to `World` and `UnsafeWorldCell` to retrieve a resource wrapped in a `Res`. - `UnsafeWorldCell::get_resource_ref` - `World::get_resource_ref` - `World::resource_ref` I can change it so `World::resource_mut` returns `ResMut` instead of `Mut` as well if that's desired, but that could also be added later in a seperate pr. --------- Co-authored-by: Alice Cecile <[email protected]> Co-authored-by: Mike <[email protected]> Co-authored-by: MinerSebas <[email protected]>
1 parent 56c3079 commit 2391e44

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

crates/bevy_ecs/src/world/mod.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::{
2828
removal_detection::RemovedComponentEvents,
2929
schedule::{Schedule, ScheduleLabel, Schedules},
3030
storage::{ResourceData, Storages},
31-
system::Resource,
31+
system::{Res, Resource},
3232
world::error::TryRunScheduleError,
3333
};
3434
use bevy_ptr::{OwningPtr, Ptr};
@@ -1302,6 +1302,30 @@ impl World {
13021302
}
13031303
}
13041304

1305+
/// Gets a reference to the resource of the given type
1306+
///
1307+
/// # Panics
1308+
///
1309+
/// Panics if the resource does not exist.
1310+
/// Use [`get_resource_ref`](World::get_resource_ref) instead if you want to handle this case.
1311+
///
1312+
/// If you want to instead insert a value if the resource does not exist,
1313+
/// use [`get_resource_or_insert_with`](World::get_resource_or_insert_with).
1314+
#[inline]
1315+
#[track_caller]
1316+
pub fn resource_ref<R: Resource>(&self) -> Res<R> {
1317+
match self.get_resource_ref() {
1318+
Some(x) => x,
1319+
None => panic!(
1320+
"Requested resource {} does not exist in the `World`.
1321+
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
1322+
Resources are also implicitly added via `app.add_event`,
1323+
and can be added by plugins.",
1324+
std::any::type_name::<R>()
1325+
),
1326+
}
1327+
}
1328+
13051329
/// Gets a mutable reference to the resource of the given type
13061330
///
13071331
/// # Panics
@@ -1335,6 +1359,15 @@ impl World {
13351359
unsafe { self.as_unsafe_world_cell_readonly().get_resource() }
13361360
}
13371361

1362+
/// Gets a reference including change detection to the resource of the given type if it exists.
1363+
#[inline]
1364+
pub fn get_resource_ref<R: Resource>(&self) -> Option<Res<R>> {
1365+
// SAFETY:
1366+
// - `as_unsafe_world_cell_readonly` gives permission to access everything immutably
1367+
// - `&self` ensures nothing in world is borrowed mutably
1368+
unsafe { self.as_unsafe_world_cell_readonly().get_resource_ref() }
1369+
}
1370+
13381371
/// Gets a mutable reference to the resource of the given type if it exists
13391372
#[inline]
13401373
pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {
@@ -1875,7 +1908,7 @@ impl World {
18751908
}
18761909

18771910
/// Runs both [`clear_entities`](Self::clear_entities) and [`clear_resources`](Self::clear_resources),
1878-
/// invalidating all [`Entity`] and resource fetches such as [`Res`](crate::system::Res), [`ResMut`](crate::system::ResMut)
1911+
/// invalidating all [`Entity`] and resource fetches such as [`Res`], [`ResMut`](crate::system::ResMut)
18791912
pub fn clear_all(&mut self) {
18801913
self.clear_entities();
18811914
self.clear_resources();

crates/bevy_ecs/src/world/unsafe_world_cell.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
prelude::Component,
1515
removal_detection::RemovedComponentEvents,
1616
storage::{Column, ComponentSparseSet, Storages},
17-
system::Resource,
17+
system::{Res, Resource},
1818
};
1919
use bevy_ptr::Ptr;
2020
use std::{any::TypeId, cell::UnsafeCell, fmt::Debug, marker::PhantomData};
@@ -342,6 +342,30 @@ impl<'w> UnsafeWorldCell<'w> {
342342
}
343343
}
344344

345+
/// Gets a reference including change detection to the resource of the given type if it exists.
346+
///
347+
/// # Safety
348+
/// It is the callers responsibility to ensure that
349+
/// - the [`UnsafeWorldCell`] has permission to access the resource
350+
/// - no mutable reference to the resource exists at the same time
351+
#[inline]
352+
pub unsafe fn get_resource_ref<R: Resource>(self) -> Option<Res<'w, R>> {
353+
let component_id = self.components().get_resource_id(TypeId::of::<R>())?;
354+
355+
// SAFETY: caller ensures `self` has permission to access the resource
356+
// caller also ensure that no mutable reference to the resource exists
357+
let (ptr, ticks) = unsafe { self.get_resource_with_ticks(component_id)? };
358+
359+
// SAFETY: `component_id` was obtained from the type ID of `R`
360+
let value = unsafe { ptr.deref::<R>() };
361+
362+
// SAFETY: caller ensures that no mutable reference to the resource exists
363+
let ticks =
364+
unsafe { Ticks::from_tick_cells(ticks, self.last_change_tick(), self.change_tick()) };
365+
366+
Some(Res { value, ticks })
367+
}
368+
345369
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
346370
/// The returned pointer must not be used to modify the resource, and must not be
347371
/// dereferenced after the borrow of the [`World`] ends.

0 commit comments

Comments
 (0)