Skip to content

Commit

Permalink
Merge #299
Browse files Browse the repository at this point in the history
299: Adds way of getting components of specific entity r=torkleyy a=WaDelma

After randomly browsing through [rhusics](https://github.com/Rhuagh/rhusics) I noticed [piece of code](https://github.com/Rhuagh/rhusics/blob/259ff9e4ea61e98919472ea9ac77005177301c1d/src/ecs/collide/systems/spatial_collision.rs#L178) and thought about API that would make it cleaner/more efficient and this is the result.

The code in question after this PR:
```rust
let (left_shape, left_pose, left_next_pose) =
    (&shapes, &poses, &next_poses).join().get(left_entity).uwnrap();

let (right_shape, right_pose, right_next_pose) =
    (&shapes, &poses, &next_poses).join().get(right_entity).uwnrap();
```

Depends on amethyst/hibitset#20

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/slide-rs/specs/299)
<!-- Reviewable:end -->
  • Loading branch information
bors[bot] committed Dec 22, 2017
2 parents 8408ef9 + 41c7ed5 commit daf1958
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ travis-ci = { repository = "slide-rs/specs" }
crossbeam = "0.3.0"
derivative = "1"
fnv = "1.0"
hibitset = "0.3.2"
hibitset = { git = "https://github.com/slide-rs/hibitset" }
mopa = "0.2"
shred = "0.5.0"
shred-derive = "0.3"
Expand Down
76 changes: 75 additions & 1 deletion src/join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use rayon::iter::ParallelIterator;
use rayon::iter::internal::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer};
use tuple_utils::Split;

use Index;
use world::Entity;
use {Index, Entities};

/// `BitAnd` is a helper method to & bitsets together resulting in a tree.
pub trait BitAnd {
Expand Down Expand Up @@ -191,6 +192,79 @@ impl<J: Join> JoinIter<J> {
}
}

impl<J: Join> JoinIter<J> {
/// Allows getting joined values for specific entity.
///
/// ## Example
///
/// ```
/// # use specs::*;
/// # #[derive(Debug, PartialEq)]
/// # struct Pos; impl Component for Pos { type Storage = VecStorage<Self>; }
/// # #[derive(Debug, PartialEq)]
/// # struct Vel; impl Component for Vel { type Storage = VecStorage<Self>; }
/// let mut world = World::new();
///
/// world.register::<Pos>();
/// world.register::<Vel>();
///
/// // This entity could be stashed anywhere (into `Component`, `Resource`, `System`s data, etc.) as it's just a number.
/// let entity = world
/// .create_entity()
/// .with(Pos)
/// .with(Vel)
/// .build();
///
/// // Later
/// {
/// let mut pos = world.write::<Pos>();
/// let vel = world.read::<Vel>();
///
/// assert_eq!(
/// Some((&mut Pos, &Vel)),
/// (&mut pos, &vel).join().get(entity, &world.entities()),
/// "The entity that was stashed still has the needed components and is alive."
/// );
/// }
///
/// // The entity has found nice spot and doesn't need to move anymore.
/// world.write::<Vel>().remove(entity);
///
/// // Even later
/// {
/// let mut pos = world.write::<Pos>();
/// let vel = world.read::<Vel>();
///
/// assert_eq!(
/// None,
/// (&mut pos, &vel).join().get(entity, &world.entities()),
/// "The entity doesn't have velocity anymore."
/// );
/// }
/// ```
pub fn get(&mut self, entity: Entity, entities: &Entities) -> Option<J::Type> {
if self.keys.contains(entity.id()) && entities.is_alive(entity) {
Some(unsafe { J::get(&mut self.values, entity.id()) })
} else {
None
}
}

/// Allows getting joined values for specific raw index.
///
/// The raw index for an `Entity` can be retrieved using `Entity::id` method.
///
/// As this method operates on raw indices, there is no check to see if the entity is still alive,
/// so the caller should ensure it instead.
pub fn get_unchecked(&mut self, index: Index) -> Option<J::Type> {
if self.keys.contains(index) {
Some(unsafe { J::get(&mut self.values, index) })
} else {
None
}
}
}

impl<J: Join> std::iter::Iterator for JoinIter<J> {
type Item = J::Type;

Expand Down
35 changes: 33 additions & 2 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ extern crate specs;
use specs::{Component, DispatcherBuilder, Entities, Entity, Fetch, FetchMut, HashMapStorage,
InsertResult, Join, ParJoin, ReadStorage, System, VecStorage, World, WriteStorage};

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
struct CompInt(i8);

impl Component for CompInt {
type Storage = VecStorage<Self>;
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
struct CompBool(bool);

impl Component for CompBool {
Expand Down Expand Up @@ -462,3 +462,34 @@ fn par_join_many_entities_and_systems() {
);
}
}

#[test]
fn getting_specific_entity_with_join() {
let mut world = create_world();
world.create_entity().with(CompInt(1)).with(CompBool(true)).build();

let entity = {
let ints = world.read::<CompInt>();
let mut bools = world.write::<CompBool>();
let entity = world.entities().join().next().unwrap();

assert_eq!(
Some((&CompInt(1), &mut CompBool(true))),
(&ints, &mut bools).join().get(entity, &world.entities())
);
bools.remove(entity);
assert_eq!(
None,
(&ints, &mut bools).join().get(entity, &world.entities())
);
entity
};
world.delete_entity(entity).unwrap();
world.create_entity().with(CompInt(2)).with(CompBool(false)).build();
let ints = world.read::<CompInt>();
let mut bools = world.write::<CompBool>();
assert_eq!(
None,
(&ints, &mut bools).join().get(entity, &world.entities())
);
}

0 comments on commit daf1958

Please sign in to comment.