Crate shipyard[][src]

Expand description

Shipyard is an Entity Component System focused on usability and speed.

Getting started

The user guide is a great place to learn all about Shipyard!
Here’s two examples to get an idea of what it provides:

use shipyard::*;

struct Health(f32);
struct Position {
    _x: f32,
    _y: f32,
}

fn in_acid(positions: View<Position>, mut healths: ViewMut<Health>) {
    for (_, mut health) in (&positions, &mut healths)
        .iter()
        .filter(|(pos, _)| is_in_acid(pos))
    {
        health.0 -= 1.0;
    }
}

fn is_in_acid(_: &Position) -> bool {
    // it's wet season
    true
}

let world = World::new();

world.run(
    |mut entities: EntitiesViewMut,
     mut positions: ViewMut<Position>,
     mut healths: ViewMut<Health>| {
        entities.add_entity(
            (&mut positions, &mut healths),
            (Position { _x: 0.0, _y: 0.0 }, Health(1000.0)),
        );
    },
);

world.run(in_acid);

Let’s make some pigs!

use shipyard::*;

struct Health(f32);
struct Fat(f32);

fn reproduction(
    mut fats: ViewMut<Fat>,
    mut healths: ViewMut<Health>,
    mut entities: EntitiesViewMut,
) {
    let count = (&healths, &fats)
        .iter()
        .filter(|(health, fat)| health.0 > 40.0 && fat.0 > 20.0)
        .count();

    for _ in 0..count {
        entities.add_entity((&mut healths, &mut fats), (Health(100.0), Fat(0.0)));
    }
}

fn meal(mut fats: ViewMut<Fat>) {
    for slice in (&mut fats).iter().into_chunk(8).ok().unwrap() {
        for fat in slice {
            fat.0 += 3.0;
        }
    }
}

fn age(mut healths: ViewMut<Health>, thread_pool: ThreadPoolView) {
    use rayon::prelude::ParallelIterator;

    thread_pool.install(|| {
        (&mut healths).par_iter().for_each(|health| {
            health.0 -= 4.0;
        });
    });
}

let world = World::new();

world.run(
    |mut entities: EntitiesViewMut, mut healths: ViewMut<Health>, mut fats: ViewMut<Fat>| {
        for _ in 0..100 {
            entities.add_entity((&mut healths, &mut fats), (Health(100.0), Fat(0.0)));
        }
    },
);

world
    .add_workload("Life")
    .with_system(system!(meal))
    .with_system(system!(age))
    .build();
world
    .add_workload("Reproduction")
    .with_system(system!(reproduction))
    .build();

for day in 0..100 {
    if day % 6 == 0 {
        world.run_workload("Reproduction");
    }
    world.run_default();
}

world.run(|healths: View<Health>| {
    // we've got some new pigs
    assert_eq!(healths.len(), 900);
});

Features

  • parallel (default) — adds parallel iterators and dispatch
  • serde — adds (de)serialization support with serde
  • non_send — add methods and types required to work with !Send components
  • non_sync — add methods and types required to work with !Sync components
  • std (default) — let shipyard use the standard library

Unsafe

This crate uses unsafe both because sometimes there’s no way around it, and for performance gain.
Releases should have all invocation of unsafe explained.
If you find places where a safe alternative is possible without repercussion (small ones are sometimes acceptable) feel free to open an issue or a PR.

Modules

Contains all error types.

Macros

Reduce boilerplace to add a system to a workload and make it less error prone.

Reduce boilerplace to add a fallible system to a workload and make it less error prone.

Structs

Contains all components present in the World.

Exclusive view over AllStorages.

Entities holds the EntityIds to all entities: living, removed and dead.

Type used to borrow Entities mutably.

Shared view over Entities storage.

Exclusive view over Entities storage.

A Key is a handle to an entity.
It has two parts, the index and the version.
The index is 48 bits long and the version 16.

Shiperator yielding iteration count as well.

Mimics an exclusive borrow of T without actually doing it.

Shiperator filtering all components with pred.

Shiperator mapping all components with f.

NonSendnon_send

Type used to access !Send storages.

NonSendSyncnon_send and non_sync

Type used to access !Send + !Sync storages.

NonSyncnon_sync

Type used to access !Sync storages.

Used to filter out components. Get and iterators will skip entities that have this component.

Component storage.

Shared view over the thread_pool.

Shared view over a unique component storage.

Exclusive view over a unique component storage.

Shared view over a component storage.

Exclusive view over a component storage.

Shared slice of a storage.

Exclusive slice of a storage.

Shiperator yielding EntityId as well.

Keeps information to create a workload.

Holds all components and keeps track of entities and what they own.

Traits

Trait extending Shiperator to be able to iterate ids alongside components.

Trait used to delete component(s).

A Shiperator with a known fixed length.

Retrives components based on their type and entity id.

Trait used to create iterators.

Shorthand for a Shiperator only yielding ids.

Trait used to sort storage(s).

Trait used to loose pack storage(s).

Removes component from entities.

Iterator-like trait able to make the difference between visited and yielded components.

Trait used to tight pack storage(s).