Convert package to a lib, get resources from views
This commit is contained in:
parent
08a458eb9c
commit
6fedb270b9
|
@ -32,7 +32,9 @@
|
|||
"--no-run",
|
||||
"--bin=lyra-ecs",
|
||||
"--package=lyra-ecs",
|
||||
"query::resource::tests::query",
|
||||
"--",
|
||||
"--exact",
|
||||
"--nocapture"
|
||||
],
|
||||
"filter": {
|
||||
|
|
|
@ -19,7 +19,7 @@ I couldn't find anything that fulfilled my needs, specifically an ECS that can s
|
|||
- [ ] Mutable views
|
||||
- [ ] Make it possible so that ONLY `ViewMut` can borrow mutably
|
||||
- [x] Resources
|
||||
- [ ] Get resources in views somehow
|
||||
- [x] Get resources in views somehow
|
||||
- [ ] Relationships (maybe this can be done through queries, idk)
|
||||
- [ ] Dynamic queries
|
||||
* Needed for scripting engines that can create their own components that Rust does not know the types of.
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
use crate::world::World;
|
||||
|
||||
mod archetype;
|
||||
pub use archetype::*;
|
||||
|
||||
pub mod world;
|
||||
pub use world::*;
|
||||
|
||||
mod bundle;
|
||||
pub use bundle::*;
|
||||
|
||||
mod component;
|
||||
pub use component::*;
|
||||
|
||||
mod query;
|
||||
pub use query::*;
|
||||
|
||||
mod component_info;
|
||||
pub use component_info::*;
|
||||
|
||||
mod resource;
|
||||
pub use resource::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
|
@ -1,22 +0,0 @@
|
|||
use crate::world::World;
|
||||
|
||||
mod archetype;
|
||||
mod world;
|
||||
mod bundle;
|
||||
mod component;
|
||||
mod query;
|
||||
mod component_info;
|
||||
mod resource;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Position2d(i32, i32);
|
||||
|
||||
fn main() {
|
||||
let mut world = World::new();
|
||||
|
||||
let pos = Position2d(836, 348);
|
||||
let _e = world.spawn((pos,));
|
||||
}
|
|
@ -37,9 +37,9 @@ where
|
|||
/// A Query for borrowing components from archetypes.
|
||||
///
|
||||
/// Since [`AsQuery`] is implemented for `&T`, you can use this query like this:
|
||||
/// ```rust
|
||||
/// ```nobuild
|
||||
/// for ts in world.view::<&T>() {
|
||||
/// println!("Got an &T!");
|
||||
/// println!("Got a &T!");
|
||||
/// }
|
||||
/// ```
|
||||
pub struct QueryBorrow<T> {
|
||||
|
@ -134,9 +134,9 @@ where
|
|||
/// A Query for mutably borrowing components from archetypes.
|
||||
///
|
||||
/// Since [`AsQuery`] is implemented for `&mut T`, you can use this query like this:
|
||||
/// ```rust
|
||||
/// ```nobuild
|
||||
/// for ts in world.view::<&mut T>() {
|
||||
/// println!("Got an &T!");
|
||||
/// println!("Got an &mut T!");
|
||||
/// }
|
||||
/// ```
|
||||
pub struct QueryBorrowMut<T> {
|
||||
|
|
|
@ -15,6 +15,10 @@ pub mod tuple;
|
|||
#[allow(unused_imports)]
|
||||
pub use tuple::*;
|
||||
|
||||
pub mod resource;
|
||||
#[allow(unused_imports)]
|
||||
pub use resource::*;
|
||||
|
||||
/// A [`Fetch`]er implementation gets data out of an archetype.
|
||||
pub trait Fetch<'a> {
|
||||
/// The type that this Fetch yields
|
||||
|
@ -39,16 +43,25 @@ pub trait Query {
|
|||
/// The fetcher used for this query
|
||||
type Fetch<'a>: Fetch<'a, Item = Self::Item<'a>>;
|
||||
|
||||
/// A constant that signifies if this Query will always fetch something.
|
||||
/// [`QueryResource`] has this set to true, since they will almost always fetch
|
||||
/// something.
|
||||
///
|
||||
/// [`View`] uses this to determine if it should continue to iterate this Query.
|
||||
const ALWAYS_FETCHES: bool = false;
|
||||
|
||||
/// Returns true if the archetype should be visited or skipped.
|
||||
fn can_visit_archetype(&self, archetype: &Archetype) -> bool;
|
||||
|
||||
/// Returns true if the Query can visit the world
|
||||
/* fn can_visit_world(&self, world: &'a World) -> bool {
|
||||
let _ = world; // compiler warnings
|
||||
false
|
||||
} */
|
||||
|
||||
unsafe fn fetch<'a>(&self, world: &'a World, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a>;
|
||||
|
||||
/// Attempt to fetch only from the world.
|
||||
///
|
||||
/// This is used in [`QueryResource`].
|
||||
unsafe fn fetch_world<'a>(&self, world: &'a World) -> Option<Self::Fetch<'a>> {
|
||||
let _ = world;
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for getting the query of a type.
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
use std::{marker::PhantomData, any::TypeId, ptr::NonNull, cell::Ref};
|
||||
|
||||
use crate::{world::World, resource::ResourceObject};
|
||||
|
||||
use super::{Query, Fetch, AsQuery, DefaultQuery};
|
||||
|
||||
pub struct FetchResource<'a, T> {
|
||||
world: Option<&'a World>,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + 'static> Fetch<'a> for FetchResource<'a, T> {
|
||||
type Item = Ref<'a, T>;
|
||||
|
||||
fn dangling() -> Self {
|
||||
Self {
|
||||
world: None,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn can_visit_item(&mut self, _entity: crate::world::ArchetypeEntityId) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
unsafe fn get_item(&mut self, _entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||
let w = self.world.unwrap();
|
||||
w.get_resource::<T>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// A query type for getting Resources
|
||||
///
|
||||
/// Resources are stored in an archetype with the id of [`world::RESOURCE_ARCHETYPE_ID`]. There is only one instance of a type of resource.
|
||||
/// The resources are stored in that archetype in the first entity in the column.
|
||||
pub struct QueryResource<T> {
|
||||
_phantom: PhantomData<T>
|
||||
}
|
||||
|
||||
pub type Resource<T> = QueryResource<T>;
|
||||
|
||||
impl<T: 'static> Query for QueryResource<T> {
|
||||
type Item<'a> = Ref<'a, T>;
|
||||
|
||||
type Fetch<'a> = FetchResource<'a, T>;
|
||||
|
||||
const ALWAYS_FETCHES: bool = true;
|
||||
|
||||
fn can_visit_archetype(&self, _archetype: &crate::archetype::Archetype) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
unsafe fn fetch<'a>(&self, world: &'a World, _arch_id: crate::archetype::ArchetypeId, _archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||||
self.fetch_world(world).unwrap()
|
||||
}
|
||||
|
||||
unsafe fn fetch_world<'a>(&self, world: &'a World) -> Option<Self::Fetch<'a>> {
|
||||
Some(FetchResource {
|
||||
world: Some(world),
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: ResourceObject> AsQuery for QueryResource<R> {
|
||||
type Query = QueryResource<R>;
|
||||
}
|
||||
|
||||
impl<R: ResourceObject> DefaultQuery for QueryResource<R> {
|
||||
fn default_query() -> Self::Query {
|
||||
QueryResource::<R> {
|
||||
_phantom: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{world::World, tests::{Vec2, Vec3}};
|
||||
|
||||
use super::QueryResource;
|
||||
|
||||
struct SomeCounter(u32);
|
||||
|
||||
#[test]
|
||||
fn simple_query() {
|
||||
let mut world = World::new();
|
||||
{
|
||||
let counter = SomeCounter(0);
|
||||
world.add_resource(counter);
|
||||
println!("Added resource");
|
||||
}
|
||||
|
||||
let mut res_iter = world.view::<QueryResource<SomeCounter>>();
|
||||
let res = res_iter.next().unwrap();
|
||||
assert_eq!(res.0, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_query() {
|
||||
let mut world = World::new();
|
||||
{
|
||||
let counter = SomeCounter(0);
|
||||
|
||||
world.spawn((Vec2::rand(),));
|
||||
world.spawn((Vec2::rand(),));
|
||||
world.spawn((Vec2::rand(),));
|
||||
world.spawn((Vec3::rand(),));
|
||||
|
||||
world.add_resource(counter);
|
||||
println!("Added resource");
|
||||
}
|
||||
|
||||
let i = world.view::<(QueryResource<SomeCounter>, &Vec2)>();
|
||||
assert_eq!(i.count(), 3);
|
||||
let i = world.view::<(&Vec2, QueryResource<SomeCounter>)>();
|
||||
assert_eq!(i.count(), 3);
|
||||
|
||||
for (res, e) in world.view::<(QueryResource<SomeCounter>, &Vec2)>() {
|
||||
println!("Got res {}! and entity at {:?}", res.0, e);
|
||||
}
|
||||
|
||||
let i = world.view::<QueryResource<SomeCounter>>();
|
||||
assert_eq!(i.count(), 1);
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ where
|
|||
ViewIter {
|
||||
world: self.world,
|
||||
query: self.query,
|
||||
fetcher: Q::Fetch::dangling(),
|
||||
fetcher: None,
|
||||
archetypes: self.archetypes,
|
||||
next_archetype: 0,
|
||||
component_indices: 0..0,
|
||||
|
@ -46,7 +46,7 @@ where
|
|||
pub struct ViewIter<'a, Q: Query> {
|
||||
world: &'a World,
|
||||
query: Q,
|
||||
fetcher: Q::Fetch<'a>,
|
||||
fetcher: Option<Q::Fetch<'a>>,
|
||||
archetypes: Vec<&'a Archetype>,
|
||||
next_archetype: usize,
|
||||
component_indices: Range<u64>,
|
||||
|
@ -60,12 +60,27 @@ where
|
|||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
if Q::ALWAYS_FETCHES {
|
||||
// only fetch this query once.
|
||||
// fetcher gets set to Some after this `next` call.
|
||||
if self.fetcher.is_none() {
|
||||
if let Some(mut fetch) = unsafe { self.query.fetch_world(self.world) } {
|
||||
let res = unsafe { Some(fetch.get_item(ArchetypeEntityId(0))) };
|
||||
self.fetcher = Some(fetch);
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(entity_index) = self.component_indices.next() {
|
||||
let fetcher = self.fetcher.as_mut().unwrap();
|
||||
let entity_index = ArchetypeEntityId(entity_index);
|
||||
if !self.fetcher.can_visit_item(entity_index) {
|
||||
if !fetcher.can_visit_item(entity_index) {
|
||||
continue;
|
||||
} else {
|
||||
let i = unsafe { self.fetcher.get_item(entity_index) };
|
||||
let i = unsafe { fetcher.get_item(entity_index) };
|
||||
return Some(i);
|
||||
}
|
||||
} else {
|
||||
|
@ -85,7 +100,7 @@ where
|
|||
continue;
|
||||
}
|
||||
|
||||
self.fetcher = unsafe { self.query.fetch(self.world, ArchetypeId(arch_id as u64), arch) };
|
||||
self.fetcher = unsafe { Some(self.query.fetch(self.world, ArchetypeId(arch_id as u64), arch)) };
|
||||
self.component_indices = 0..arch.entities.len() as u64;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::{any::TypeId, alloc::Layout, cell::{RefCell, Ref, RefMut}, ptr::NonNull, alloc};
|
||||
|
||||
/// Shorthand for `Send + Sync + 'static`, so it never needs to be implemented manually.
|
||||
/* pub trait Resource: Send + Sync + 'static {}
|
||||
impl<T: Send + Sync + 'static> Resource for T {} */
|
||||
pub trait ResourceObject: Send + Sync + 'static {}
|
||||
impl<T: Send + Sync + 'static> ResourceObject for T {}
|
||||
|
||||
/// A type erased storage for a Resource.
|
||||
///
|
||||
|
|
|
@ -42,4 +42,15 @@ impl Vec3 {
|
|||
z
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rand() -> Self {
|
||||
let mut rng = rand::thread_rng();
|
||||
let range = 30.0..1853.0;
|
||||
|
||||
Vec3 {
|
||||
x: rng.gen_range(range.clone()),
|
||||
y: rng.gen_range(range.clone()),
|
||||
z: rng.gen_range(range)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue