ecs: refactor resources

fixes unintialized global resource memory
This commit is contained in:
Carter Anderson 2020-07-19 14:23:06 -07:00
parent 2ec530da8c
commit 946d5d1024
7 changed files with 209 additions and 261 deletions

View file

@ -45,7 +45,7 @@ impl AppPlugin for ScheduleRunnerPlugin {
app.schedule.run(&mut app.world, &mut app.resources); app.schedule.run(&mut app.world, &mut app.resources);
} }
RunMode::Loop { wait } => loop { RunMode::Loop { wait } => loop {
if let Ok(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() { if let Some(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() {
if app_exit_event_reader.latest(&app_exit_events).is_some() { if app_exit_event_reader.latest(&app_exit_events).is_some() {
break; break;
} }
@ -53,7 +53,7 @@ impl AppPlugin for ScheduleRunnerPlugin {
app.schedule.run(&mut app.world, &mut app.resources); app.schedule.run(&mut app.world, &mut app.resources);
if let Ok(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() { if let Some(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() {
if app_exit_event_reader.latest(&app_exit_events).is_some() { if app_exit_event_reader.latest(&app_exit_events).is_some() {
break; break;
} }

View file

@ -1,31 +1,26 @@
use super::{FromResources, Resources};
use crate::{ use crate::{
system::{SystemId, TypeAccess}, system::{SystemId, TypeAccess},
ResourceIndex,
}; };
use core::{ use core::{
any::TypeId, any::TypeId,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
ptr::NonNull, ptr::NonNull,
}; };
use hecs::{smaller_tuples_too, MissingComponent, Component, Archetype}; use hecs::{smaller_tuples_too, Component};
use std::collections::HashMap; use std::marker::PhantomData;
use super::{Resources, FromResources};
/// Shared borrow of an entity's component /// Shared borrow of an entity's component
pub struct Res<'a, T: Component> { pub struct Res<'a, T: Component> {
archetype: &'a Archetype, value: &'a T,
target: NonNull<T>,
} }
impl<'a, T: Component> Res<'a, T> { impl<'a, T: Component> Res<'a, T> {
#[allow(missing_docs)] pub unsafe fn new(value: NonNull<T>) -> Self {
pub unsafe fn new(archetype: &'a Archetype, index: u32) -> Result<Self, MissingComponent> { Self {
let target = NonNull::new_unchecked( value: &*value.as_ptr(),
archetype }
.get::<T>()
.ok_or_else(MissingComponent::new::<T>)?
.as_ptr()
.add(index as usize),
);
Ok(Self { archetype, target })
} }
} }
@ -33,22 +28,9 @@ pub trait UnsafeClone {
unsafe fn unsafe_clone(&self) -> Self; unsafe fn unsafe_clone(&self) -> Self;
} }
// TODO: this is unsafe. lets think of a better solution that allows us to clone internally
impl<'a, T: Component> UnsafeClone for ResMut<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self {
archetype: self.archetype,
target: self.target,
}
}
}
impl<'a, T: Component> UnsafeClone for Res<'a, T> { impl<'a, T: Component> UnsafeClone for Res<'a, T> {
unsafe fn unsafe_clone(&self) -> Self { unsafe fn unsafe_clone(&self) -> Self {
Self { Self { value: self.value }
archetype: self.archetype,
target: self.target,
}
} }
} }
@ -58,27 +40,22 @@ unsafe impl<T: Component> Sync for Res<'_, T> {}
impl<'a, T: Component> Deref for Res<'a, T> { impl<'a, T: Component> Deref for Res<'a, T> {
type Target = T; type Target = T;
fn deref(&self) -> &T { fn deref(&self) -> &T {
unsafe { self.target.as_ref() } self.value
} }
} }
/// Unique borrow of a resource /// Unique borrow of a resource
pub struct ResMut<'a, T: Component> { pub struct ResMut<'a, T: Component> {
archetype: &'a Archetype, _marker: PhantomData<&'a T>,
target: NonNull<T>, value: *mut T,
} }
impl<'a, T: Component> ResMut<'a, T> { impl<'a, T: Component> ResMut<'a, T> {
#[allow(missing_docs)] pub unsafe fn new(value: NonNull<T>) -> Self {
pub unsafe fn new(archetype: &'a Archetype, index: u32) -> Result<Self, MissingComponent> { Self {
let target = NonNull::new_unchecked( value: value.as_ptr(),
archetype _marker: Default::default(),
.get::<T>() }
.ok_or_else(MissingComponent::new::<T>)?
.as_ptr()
.add(index as usize),
);
Ok(Self { archetype, target })
} }
} }
@ -88,40 +65,35 @@ unsafe impl<T: Component> Sync for ResMut<'_, T> {}
impl<'a, T: Component> Deref for ResMut<'a, T> { impl<'a, T: Component> Deref for ResMut<'a, T> {
type Target = T; type Target = T;
fn deref(&self) -> &T { fn deref(&self) -> &T {
unsafe { self.target.as_ref() } unsafe { &*self.value }
} }
} }
impl<'a, T: Component> DerefMut for ResMut<'a, T> { impl<'a, T: Component> DerefMut for ResMut<'a, T> {
fn deref_mut(&mut self) -> &mut T { fn deref_mut(&mut self) -> &mut T {
unsafe { self.target.as_mut() } unsafe { &mut *self.value }
}
}
impl<'a, T: Component> UnsafeClone for ResMut<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self {
value: self.value,
_marker: Default::default(),
}
} }
} }
pub struct Local<'a, T: Component + FromResources> { pub struct Local<'a, T: Component + FromResources> {
archetype: &'a Archetype, value: *mut T,
target: NonNull<T>, _marker: PhantomData<&'a T>,
}
impl<'a, T: Component + FromResources> Local<'a, T> {
#[allow(missing_docs)]
pub unsafe fn new(archetype: &'a Archetype, index: u32) -> Result<Self, MissingComponent> {
let target = NonNull::new_unchecked(
archetype
.get::<T>()
.ok_or_else(MissingComponent::new::<T>)?
.as_ptr()
.add(index as usize),
);
Ok(Self { archetype, target })
}
} }
impl<'a, T: Component + FromResources> UnsafeClone for Local<'a, T> { impl<'a, T: Component + FromResources> UnsafeClone for Local<'a, T> {
unsafe fn unsafe_clone(&self) -> Self { unsafe fn unsafe_clone(&self) -> Self {
Self { Self {
archetype: self.archetype, value: self.value,
target: self.target, _marker: Default::default(),
} }
} }
} }
@ -129,13 +101,13 @@ impl<'a, T: Component + FromResources> UnsafeClone for Local<'a, T> {
impl<'a, T: Component + FromResources> Deref for Local<'a, T> { impl<'a, T: Component + FromResources> Deref for Local<'a, T> {
type Target = T; type Target = T;
fn deref(&self) -> &T { fn deref(&self) -> &T {
unsafe { self.target.as_ref() } unsafe { &*self.value }
} }
} }
impl<'a, T: Component + FromResources> DerefMut for Local<'a, T> { impl<'a, T: Component + FromResources> DerefMut for Local<'a, T> {
fn deref_mut(&mut self) -> &mut T { fn deref_mut(&mut self) -> &mut T {
unsafe { self.target.as_mut() } unsafe { &mut *self.value }
} }
} }
@ -152,8 +124,8 @@ pub trait FetchResource<'a>: Sized {
type Item: UnsafeClone; type Item: UnsafeClone;
fn access() -> TypeAccess; fn access() -> TypeAccess;
fn borrow(resource_archetypes: &HashMap<TypeId, Archetype>); fn borrow(resources: &Resources);
fn release(resource_archetypes: &HashMap<TypeId, Archetype>); fn release(resources: &Resources);
/// Construct a `Fetch` for `archetype` if it should be traversed /// Construct a `Fetch` for `archetype` if it should be traversed
/// ///
@ -171,19 +143,17 @@ pub struct FetchResourceRead<T>(NonNull<T>);
impl<'a, T: Component> FetchResource<'a> for FetchResourceRead<T> { impl<'a, T: Component> FetchResource<'a> for FetchResourceRead<T> {
type Item = Res<'a, T>; type Item = Res<'a, T>;
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item { unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
resources.get_res::<T>() Res::new(resources.get_unsafe_ref::<T>(ResourceIndex::Global))
} }
fn borrow(resource_archetypes: &HashMap<TypeId, Archetype>) { fn borrow(resources: &Resources) {
if let Some(archetype) = resource_archetypes.get(&TypeId::of::<T>()) { resources.borrow::<T>();
archetype.borrow::<T>();
}
} }
fn release(resource_archetypes: &HashMap<TypeId, Archetype>) {
if let Some(archetype) = resource_archetypes.get(&TypeId::of::<T>()) { fn release(resources: &Resources) {
archetype.release::<T>(); resources.release::<T>();
}
} }
fn access() -> TypeAccess { fn access() -> TypeAccess {
let mut access = TypeAccess::default(); let mut access = TypeAccess::default();
access.immutable.insert(TypeId::of::<T>()); access.immutable.insert(TypeId::of::<T>());
@ -200,19 +170,17 @@ pub struct FetchResourceWrite<T>(NonNull<T>);
impl<'a, T: Component> FetchResource<'a> for FetchResourceWrite<T> { impl<'a, T: Component> FetchResource<'a> for FetchResourceWrite<T> {
type Item = ResMut<'a, T>; type Item = ResMut<'a, T>;
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item { unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
resources.get_res_mut::<T>() ResMut::new(resources.get_unsafe_ref::<T>(ResourceIndex::Global))
} }
fn borrow(resource_archetypes: &HashMap<TypeId, Archetype>) { fn borrow(resources: &Resources) {
if let Some(archetype) = resource_archetypes.get(&TypeId::of::<T>()) { resources.borrow_mut::<T>();
archetype.borrow_mut::<T>();
}
} }
fn release(resource_archetypes: &HashMap<TypeId, Archetype>) {
if let Some(archetype) = resource_archetypes.get(&TypeId::of::<T>()) { fn release(resources: &Resources) {
archetype.release_mut::<T>(); resources.release_mut::<T>();
}
} }
fn access() -> TypeAccess { fn access() -> TypeAccess {
let mut access = TypeAccess::default(); let mut access = TypeAccess::default();
access.mutable.insert(TypeId::of::<T>()); access.mutable.insert(TypeId::of::<T>());
@ -235,33 +203,23 @@ pub struct FetchResourceLocalMut<T>(NonNull<T>);
impl<'a, T: Component + FromResources> FetchResource<'a> for FetchResourceLocalMut<T> { impl<'a, T: Component + FromResources> FetchResource<'a> for FetchResourceLocalMut<T> {
type Item = Local<'a, T>; type Item = Local<'a, T>;
unsafe fn get(resources: &'a Resources, system_id: Option<SystemId>) -> Self::Item { unsafe fn get(resources: &'a Resources, system_id: Option<SystemId>) -> Self::Item {
if let Some(system_id) = system_id { let id = system_id.expect("Local<T> resources can only be used by systems");
let archetype = resources Local {
.resource_archetypes value: resources
.get(&TypeId::of::<T>()) .get_unsafe_ref::<T>(ResourceIndex::System(id))
.unwrap_or_else(|| { .as_ptr(),
panic!("Resource does not exist {}", std::any::type_name::<T>()) _marker: Default::default(),
});
let index = resources
.system_id_to_archetype_index
.get(&system_id.0)
.expect("System does not have this resource");
Local::new(archetype, *index).expect("Resource does not exist")
} else {
panic!("Only Systems can use Local<T> resources");
} }
} }
fn borrow(resource_archetypes: &HashMap<TypeId, Archetype>) { fn borrow(resources: &Resources) {
if let Some(archetype) = resource_archetypes.get(&TypeId::of::<T>()) { resources.borrow_mut::<T>();
archetype.borrow_mut::<T>();
}
} }
fn release(resource_archetypes: &HashMap<TypeId, Archetype>) {
if let Some(archetype) = resource_archetypes.get(&TypeId::of::<T>()) { fn release(resources: &Resources) {
archetype.release_mut::<T>(); resources.release_mut::<T>();
}
} }
fn access() -> TypeAccess { fn access() -> TypeAccess {
let mut access = TypeAccess::default(); let mut access = TypeAccess::default();
access.mutable.insert(TypeId::of::<T>()); access.mutable.insert(TypeId::of::<T>());
@ -275,13 +233,13 @@ macro_rules! tuple_impl {
type Item = ($($name::Item,)*); type Item = ($($name::Item,)*);
#[allow(unused_variables)] #[allow(unused_variables)]
fn borrow(resource_archetypes: &HashMap<TypeId, Archetype>) { fn borrow(resources: &Resources) {
$($name::borrow(resource_archetypes);)* $($name::borrow(resources);)*
} }
#[allow(unused_variables)] #[allow(unused_variables)]
fn release(resource_archetypes: &HashMap<TypeId, Archetype>) { fn release(resources: &Resources) {
$($name::release(resource_archetypes);)* $($name::release(resources);)*
} }
#[allow(unused_variables)] #[allow(unused_variables)]

View file

@ -1,78 +1,79 @@
use super::{FetchResource, Res, ResMut, ResourceQuery}; use super::{FetchResource, ResourceQuery};
use crate::system::SystemId; use crate::system::SystemId;
use core::any::TypeId; use core::any::TypeId;
use hecs::{Archetype, ComponentError, Ref, RefMut, TypeInfo}; use hecs::{Archetype, Ref, RefMut, TypeInfo};
use std::collections::HashMap; use std::{collections::HashMap, ptr::NonNull};
pub trait Resource: Send + Sync + 'static {} pub trait Resource: Send + Sync + 'static {}
impl<T: Send + Sync + 'static> Resource for T {} impl<T: Send + Sync + 'static> Resource for T {}
pub struct ResourceData {
archetype: Archetype,
default_index: Option<u32>,
system_id_to_archetype_index: HashMap<u32, u32>,
}
pub enum ResourceIndex {
Global,
System(SystemId),
}
#[derive(Default)] #[derive(Default)]
pub struct Resources { pub struct Resources {
pub(crate) resource_archetypes: HashMap<TypeId, Archetype>, pub(crate) resource_data: HashMap<TypeId, ResourceData>,
pub(crate) system_id_to_archetype_index: HashMap<u32, u32>,
} }
impl Resources { impl Resources {
pub fn insert<T: Resource>(&mut self, resource: T) { pub fn insert<T: Resource>(&mut self, resource: T) {
self.insert_index(resource, 0); self.insert_resource(resource, ResourceIndex::Global);
} }
pub fn contains<T: Resource>(&self) -> bool { pub fn contains<T: Resource>(&self) -> bool {
self.get_index::<T>(0).is_ok() self.get_resource::<T>(ResourceIndex::Global).is_some()
} }
pub fn get<T: Resource>(&self) -> Result<Ref<'_, T>, ComponentError> { pub fn get<T: Resource>(&self) -> Option<Ref<'_, T>> {
self.get_index(0) self.get_resource(ResourceIndex::Global)
} }
pub fn get_mut<T: Resource>(&self) -> Result<RefMut<'_, T>, ComponentError> { pub fn get_mut<T: Resource>(&self) -> Option<RefMut<'_, T>> {
self.get_index_mut(0) self.get_resource_mut(ResourceIndex::Global)
} }
pub fn get_local<'a, T: Resource>( pub fn get_local<'a, T: Resource>(&'a self, id: SystemId) -> Option<Ref<'a, T>> {
&'a self, self.get_resource(ResourceIndex::System(id))
id: SystemId,
) -> Result<Ref<'a, T>, ComponentError> {
self.system_id_to_archetype_index
.get(&id.0)
.ok_or_else(|| ComponentError::NoSuchEntity)
.and_then(|index| self.get_index(*index))
} }
pub fn get_local_mut<'a, T: Resource>( pub fn get_local_mut<'a, T: Resource>(&'a self, id: SystemId) -> Option<RefMut<'a, T>> {
&'a self, self.get_resource_mut(ResourceIndex::System(id))
id: SystemId,
) -> Result<RefMut<'a, T>, ComponentError> {
self.system_id_to_archetype_index
.get(&id.0)
.ok_or_else(|| ComponentError::NoSuchEntity)
.and_then(|index| self.get_index_mut(*index))
} }
pub fn insert_local<T: Resource>(&mut self, id: SystemId, resource: T) { pub fn insert_local<T: Resource>(&mut self, id: SystemId, resource: T) {
if let Some(index) = self.system_id_to_archetype_index.get(&id.0).cloned() { self.insert_resource(resource, ResourceIndex::System(id))
self.insert_index(resource, index);
} else {
let mut index = self.archetype_len::<T>();
// index 0 is reserved for the global non-system resource
if index == 0 {
self.allocate_next::<T>();
index += 1;
}
self.insert_index(resource, index);
self.system_id_to_archetype_index.insert(id.0, index);
}
} }
fn insert_index<T: Resource>(&mut self, mut resource: T, index: u32) { fn insert_resource<T: Resource>(&mut self, mut resource: T, resource_index: ResourceIndex) {
let type_id = TypeId::of::<T>(); let type_id = TypeId::of::<T>();
let archetype = self.resource_archetypes.entry(type_id).or_insert_with(|| { let data = self.resource_data.entry(type_id).or_insert_with(|| {
let mut types = Vec::new(); let mut types = Vec::new();
types.push(TypeInfo::of::<T>()); types.push(TypeInfo::of::<T>());
Archetype::new(types) ResourceData {
archetype: Archetype::new(types),
default_index: None,
system_id_to_archetype_index: HashMap::new(),
}
}); });
let archetype = &mut data.archetype;
let index = match resource_index {
ResourceIndex::Global => *data.default_index.get_or_insert_with(|| archetype.len()),
ResourceIndex::System(id) => *data
.system_id_to_archetype_index
.entry(id.0)
.or_insert_with(|| archetype.len()),
};
if index == archetype.len() { if index == archetype.len() {
unsafe { archetype.allocate(index) }; unsafe { archetype.allocate(index) };
} else if index > archetype.len() { } else if index > archetype.len() {
@ -86,42 +87,33 @@ impl Resources {
} }
} }
fn allocate_next<T: Resource>(&mut self) { fn get_resource<T: Resource>(&self, resource_index: ResourceIndex) -> Option<Ref<'_, T>> {
let type_id = TypeId::of::<T>(); self.resource_data
let archetype = self.resource_archetypes.entry(type_id).or_insert_with(|| {
let mut types = Vec::new();
types.push(TypeInfo::of::<T>());
Archetype::new(types)
});
let index = archetype.len();
unsafe { archetype.allocate(index) };
}
fn get_index<T: Resource>(&self, index: u32) -> Result<Ref<'_, T>, ComponentError> {
self.resource_archetypes
.get(&TypeId::of::<T>()) .get(&TypeId::of::<T>())
.ok_or_else(|| ComponentError::NoSuchEntity) .and_then(|data| unsafe {
.and_then(|archetype| unsafe { let index = match resource_index {
Ref::new(archetype, index).map_err(|err| ComponentError::MissingComponent(err)) ResourceIndex::Global => data.default_index?,
ResourceIndex::System(id) => *data.system_id_to_archetype_index.get(&id.0)?,
};
Ref::new(&data.archetype, index).ok()
}) })
} }
fn get_index_mut<T: Resource>(&self, index: u32) -> Result<RefMut<'_, T>, ComponentError> { fn get_resource_mut<T: Resource>(
self.resource_archetypes &self,
resource_index: ResourceIndex,
) -> Option<RefMut<'_, T>> {
self.resource_data
.get(&TypeId::of::<T>()) .get(&TypeId::of::<T>())
.ok_or_else(|| ComponentError::NoSuchEntity) .and_then(|data| unsafe {
.and_then(|archetype| unsafe { let index = match resource_index {
RefMut::new(archetype, index).map_err(|err| ComponentError::MissingComponent(err)) ResourceIndex::Global => data.default_index?,
ResourceIndex::System(id) => *data.system_id_to_archetype_index.get(&id.0)?,
};
RefMut::new(&data.archetype, index).ok()
}) })
} }
fn archetype_len<T: Resource>(&self) -> u32 {
self.resource_archetypes
.get(&TypeId::of::<T>())
.map_or(0, |a| a.len())
}
pub fn query<Q: ResourceQuery>(&self) -> <Q::Fetch as FetchResource>::Item { pub fn query<Q: ResourceQuery>(&self) -> <Q::Fetch as FetchResource>::Item {
unsafe { Q::Fetch::get(&self, None) } unsafe { Q::Fetch::get(&self, None) }
} }
@ -134,21 +126,45 @@ impl Resources {
} }
#[inline] #[inline]
pub unsafe fn get_res<T: Resource>(&self) -> Res<'_, T> { pub unsafe fn get_unsafe_ref<T: Resource>(&self, resource_index: ResourceIndex) -> NonNull<T> {
let archetype = self self.resource_data
.resource_archetypes
.get(&TypeId::of::<T>()) .get(&TypeId::of::<T>())
.unwrap_or_else(|| panic!("Resource does not exist {}", std::any::type_name::<T>())); .and_then(|data| {
Res::new(archetype, 0).expect("Resource does not exist") let index = match resource_index {
ResourceIndex::Global => data.default_index?,
ResourceIndex::System(id) => {
data.system_id_to_archetype_index.get(&id.0).cloned()?
}
};
Some(NonNull::new_unchecked(
data.archetype.get::<T>()?.as_ptr().add(index as usize),
))
})
.unwrap_or_else(|| panic!("Resource does not exist {}", std::any::type_name::<T>()))
} }
#[inline] pub fn borrow<T: Resource>(&self) {
pub unsafe fn get_res_mut<T: Resource>(&self) -> ResMut<'_, T> { if let Some(data) = self.resource_data.get(&TypeId::of::<T>()) {
let archetype = self data.archetype.borrow::<T>();
.resource_archetypes }
.get(&TypeId::of::<T>()) }
.unwrap_or_else(|| panic!("Resource does not exist {}", std::any::type_name::<T>()));
ResMut::new(archetype, 0).expect("Resource does not exist") pub fn release<T: Resource>(&self) {
if let Some(data) = self.resource_data.get(&TypeId::of::<T>()) {
data.archetype.release::<T>();
}
}
pub fn borrow_mut<T: Resource>(&self) {
if let Some(data) = self.resource_data.get(&TypeId::of::<T>()) {
data.archetype.borrow_mut::<T>();
}
}
pub fn release_mut<T: Resource>(&self) {
if let Some(data) = self.resource_data.get(&TypeId::of::<T>()) {
data.archetype.release_mut::<T>();
}
} }
} }
@ -176,7 +192,7 @@ mod tests {
#[test] #[test]
fn resource() { fn resource() {
let mut resources = Resources::default(); let mut resources = Resources::default();
assert!(resources.get::<i32>().is_err()); assert!(resources.get::<i32>().is_none());
resources.insert(123); resources.insert(123);
assert_eq!(*resources.get::<i32>().expect("resource exists"), 123); assert_eq!(*resources.get::<i32>().expect("resource exists"), 123);
@ -195,7 +211,7 @@ mod tests {
assert_eq!(*resources.get::<f64>().expect("resource exists"), -1.0); assert_eq!(*resources.get::<f64>().expect("resource exists"), -1.0);
assert!(resources.get_local::<i32>(SystemId(0)).is_err()); assert!(resources.get_local::<i32>(SystemId(0)).is_none());
resources.insert_local(SystemId(0), 111); resources.insert_local(SystemId(0), 111);
assert_eq!( assert_eq!(
*resources *resources

View file

@ -105,14 +105,14 @@ macro_rules! impl_into_foreach_system {
name: core::any::type_name::<Self>().into(), name: core::any::type_name::<Self>().into(),
id, id,
func: move |world, resources, _archetype_access, state| { func: move |world, resources, _archetype_access, state| {
<<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::borrow(&resources.resource_archetypes); <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::borrow(&resources);
{ {
let ($($resource,)*) = resources.query_system::<($($resource,)*)>(id); let ($($resource,)*) = resources.query_system::<($($resource,)*)>(id);
for ($($component,)*) in world.query::<($($component,)*)>().iter() { for ($($component,)*) in world.query::<($($component,)*)>().iter() {
fn_call!(self, ($($commands, state)*), ($($resource),*), ($($component),*)) fn_call!(self, ($($commands, state)*), ($($resource),*), ($($component),*))
} }
} }
<<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::release(&resources.resource_archetypes); <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::release(&resources);
}, },
thread_local_func: move |world, resources, state| { thread_local_func: move |world, resources, state| {
state.apply(world, resources); state.apply(world, resources);
@ -251,7 +251,7 @@ macro_rules! impl_into_query_system {
id, id,
name: core::any::type_name::<Self>().into(), name: core::any::type_name::<Self>().into(),
func: move |world, resources, archetype_access, state| { func: move |world, resources, archetype_access, state| {
<<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::borrow(&resources.resource_archetypes); <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::borrow(&resources);
{ {
let ($($resource,)*) = resources.query_system::<($($resource,)*)>(id); let ($($resource,)*) = resources.query_system::<($($resource,)*)>(id);
let mut i = 0; let mut i = 0;
@ -267,7 +267,7 @@ macro_rules! impl_into_query_system {
let commands = &state.commands; let commands = &state.commands;
fn_call!(self, ($($commands, commands)*), ($($resource),*), ($($query),*)) fn_call!(self, ($($commands, commands)*), ($($resource),*), ($($query),*))
} }
<<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::release(&resources.resource_archetypes); <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::release(&resources);
}, },
thread_local_func: move |world, resources, state| { thread_local_func: move |world, resources, state| {
state.commands.apply(world, resources); state.commands.apply(world, resources);

View file

@ -11,11 +11,11 @@ use crate::{
}; };
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_ecs::{ use bevy_ecs::{
Archetype, FetchResource, Query, Res, ResMut, ResourceQuery, Resources, SystemId, TypeAccess, FetchResource, Query, Res, ResMut, ResourceIndex, ResourceQuery, Resources, SystemId,
UnsafeClone, TypeAccess, UnsafeClone,
}; };
use bevy_property::Properties; use bevy_property::Properties;
use std::{any::TypeId, collections::HashMap, ops::Range, sync::Arc}; use std::{any::TypeId, ops::Range, sync::Arc};
use thiserror::Error; use thiserror::Error;
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
@ -150,66 +150,40 @@ pub struct FetchDrawContext;
// TODO: derive this impl // TODO: derive this impl
impl<'a> FetchResource<'a> for FetchDrawContext { impl<'a> FetchResource<'a> for FetchDrawContext {
type Item = DrawContext<'a>; type Item = DrawContext<'a>;
fn borrow(resource_archetypes: &HashMap<TypeId, Archetype>) { fn borrow(resources: &Resources) {
resource_archetypes resources.borrow_mut::<Assets<PipelineDescriptor>>();
.get(&TypeId::of::<Assets<PipelineDescriptor>>()) resources.borrow_mut::<Assets<Shader>>();
.unwrap() resources.borrow_mut::<PipelineCompiler>();
.borrow_mut::<Assets<PipelineDescriptor>>(); resources.borrow::<Box<dyn RenderResourceContext>>();
resource_archetypes resources.borrow::<VertexBufferDescriptors>();
.get(&TypeId::of::<Assets<Shader>>()) resources.borrow::<SharedBuffers>();
.unwrap()
.borrow_mut::<Assets<Shader>>();
resource_archetypes
.get(&TypeId::of::<PipelineCompiler>())
.unwrap()
.borrow_mut::<PipelineCompiler>();
resource_archetypes
.get(&TypeId::of::<Box<dyn RenderResourceContext>>())
.unwrap()
.borrow::<Box<dyn RenderResourceContext>>();
resource_archetypes
.get(&TypeId::of::<VertexBufferDescriptors>())
.unwrap()
.borrow::<VertexBufferDescriptors>();
resource_archetypes
.get(&TypeId::of::<SharedBuffers>())
.unwrap()
.borrow::<SharedBuffers>();
} }
fn release(resource_archetypes: &HashMap<TypeId, Archetype>) { fn release(resources: &Resources) {
resource_archetypes resources.release_mut::<Assets<PipelineDescriptor>>();
.get(&TypeId::of::<Assets<PipelineDescriptor>>()) resources.release_mut::<Assets<Shader>>();
.unwrap() resources.release_mut::<PipelineCompiler>();
.release_mut::<Assets<PipelineDescriptor>>(); resources.release::<Box<dyn RenderResourceContext>>();
resource_archetypes resources.release::<VertexBufferDescriptors>();
.get(&TypeId::of::<Assets<Shader>>()) resources.release::<SharedBuffers>();
.unwrap()
.release_mut::<Assets<Shader>>();
resource_archetypes
.get(&TypeId::of::<PipelineCompiler>())
.unwrap()
.release_mut::<PipelineCompiler>();
resource_archetypes
.get(&TypeId::of::<Box<dyn RenderResourceContext>>())
.unwrap()
.release::<Box<dyn RenderResourceContext>>();
resource_archetypes
.get(&TypeId::of::<VertexBufferDescriptors>())
.unwrap()
.release::<VertexBufferDescriptors>();
resource_archetypes
.get(&TypeId::of::<SharedBuffers>())
.unwrap()
.release::<SharedBuffers>();
} }
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item { unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
DrawContext { DrawContext {
pipelines: resources.get_res_mut::<Assets<PipelineDescriptor>>(), pipelines: ResMut::new(
shaders: resources.get_res_mut::<Assets<Shader>>(), resources.get_unsafe_ref::<Assets<PipelineDescriptor>>(ResourceIndex::Global),
pipeline_compiler: resources.get_res_mut::<PipelineCompiler>(), ),
render_resource_context: resources.get_res::<Box<dyn RenderResourceContext>>(), shaders: ResMut::new(resources.get_unsafe_ref::<Assets<Shader>>(ResourceIndex::Global)),
vertex_buffer_descriptors: resources.get_res::<VertexBufferDescriptors>(), pipeline_compiler: ResMut::new(
shared_buffers: resources.get_res::<SharedBuffers>(), resources.get_unsafe_ref::<PipelineCompiler>(ResourceIndex::Global),
),
render_resource_context: Res::new(
resources.get_unsafe_ref::<Box<dyn RenderResourceContext>>(ResourceIndex::Global),
),
vertex_buffer_descriptors: Res::new(
resources.get_unsafe_ref::<VertexBufferDescriptors>(ResourceIndex::Global),
),
shared_buffers: Res::new(
resources.get_unsafe_ref::<SharedBuffers>(ResourceIndex::Global),
),
current_pipeline: None, current_pipeline: None,
} }
} }

View file

@ -109,7 +109,7 @@ impl Node for PassNode {
for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() { for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
if self.default_clear_color_inputs.contains(&i) { if self.default_clear_color_inputs.contains(&i) {
if let Ok(default_clear_color) = resources.get::<ClearColor>() { if let Some(default_clear_color) = resources.get::<ClearColor>() {
color_attachment.ops.load = LoadOp::Clear(default_clear_color.0); color_attachment.ops.load = LoadOp::Clear(default_clear_color.0);
} }
} }

View file

@ -52,7 +52,7 @@ pub fn winit_runner(mut app: App) {
ControlFlow::Poll ControlFlow::Poll
}; };
if let Ok(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() { if let Some(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() {
if app_exit_event_reader.latest(&app_exit_events).is_some() { if app_exit_event_reader.latest(&app_exit_events).is_some() {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }