Specs - Parallel ECS

Overview

Specs

Specs Parallel ECS

Build Status Crates.io Gitter MIT/Apache Docs.rs Code coverage LoC

Specs is an Entity-Component System written in Rust. Unlike most other ECS libraries out there, it provides

  • easy parallelism
  • high flexibility
    • contains 5 different storages for components, which can be extended by the user
    • its types are mostly not coupled, so you can easily write some part yourself and still use Specs
    • Systems may read from and write to components and resources, can depend on each other and you can use barriers to force several stages in system execution
  • high performance for real-world applications

Minimum Rust version: 1.40

Link to the book

Example

use specs::prelude::*;

// A component contains data
// which is associated with an entity.
#[derive(Debug)]
struct Vel(f32);

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

#[derive(Debug)]
struct Pos(f32);

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

struct SysA;

impl<'a> System<'a> for SysA {
    // These are the resources required for execution.
    // You can also define a struct and `#[derive(SystemData)]`,
    // see the `full` example.
    type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>);

    fn run(&mut self, (mut pos, vel): Self::SystemData) {
        // The `.join()` combines multiple component storages,
        // so we get access to all entities which have
        // both a position and a velocity.
        for (pos, vel) in (&mut pos, &vel).join() {
            pos.0 += vel.0;
        }
    }
}

fn main() {
    // The `World` is our
    // container for components
    // and other resources.
    let mut world = World::new();
    world.register::<Pos>();
    world.register::<Vel>();

    // An entity may or may not contain some component.

    world.create_entity().with(Vel(2.0)).with(Pos(0.0)).build();
    world.create_entity().with(Vel(4.0)).with(Pos(1.6)).build();
    world.create_entity().with(Vel(1.5)).with(Pos(5.4)).build();

    // This entity does not have `Vel`, so it won't be dispatched.
    world.create_entity().with(Pos(2.0)).build();

    // This builds a dispatcher.
    // The third parameter of `with` specifies
    // logical dependencies on other systems.
    // Since we only have one, we don't depend on anything.
    // See the `full` example for dependencies.
    let mut dispatcher = DispatcherBuilder::new().with(SysA, "sys_a", &[]).build();
    // This will call the `setup` function of every system.
    // In this example this has no effect since we already registered our components.
    dispatcher.setup(&mut world);

    // This dispatches all the systems in parallel (but blocking).
    dispatcher.dispatch(&mut world);
}

Please look into the examples directory for more.

Public dependencies

crate version
hibitset hibitset
rayon rayon
shred shred
shrev shrev

Contribution

Contribution is very welcome! If you didn't contribute before, just filter for issues with "easy" or "good first issue" label. Please note that your contributions are assumed to be dual-licensed under Apache-2.0/MIT.

Comments
  • Tracked

    Tracked

    Somehow I managed to break github with that last PR... and now it won't let me re-open it so here's a new one.

    Old PR: https://github.com/slide-rs/specs/pull/305


    This change is Reviewable

    ready 
    opened by Aceeri 34
  • Saveload custom derive

    Saveload custom derive

    Split from #434 A custom derive for IntoSerialize and FromDeserialize named #[derive(Saveload)]. It may seem odd to derive them together, but after spending significant time trying to do it the normal way (one derive per trait) it became clear that due to the requirement of "proxy" types that fill the IntoSerialize::Data and FromDeserialize::Data fields, it made sense to do it this way or you start getting into attribute hell.


    This change is Reviewable

    in progress 
    opened by WaDelma 28
  • another storage to help synchronizing with external storage

    another storage to help synchronizing with external storage

    I use specs with nphysics (actually a fork on my own but 0.8 nphysics will impl things..) I have to synchronize RigidBodyHandle in specs world and in nphysics world.

    My needs are:

    • for insert everything is sync: the method to create RigidBodyHandle component takes nphysics world and create them altogether
    • for remove I accept that some object are still alive in nphysics world but have no component in specs. and then I want to regularly sync things by removing those objects that have been deleted from specs world. But to do so I have issues:

    I tried to implement using flagged storage in current master but I can't get the deleted component I just have the index of the entity deleted and that is not enough:

    extern crate specs;
    
    use specs::prelude::*;
    
    #[derive(Debug)]
    struct Vel(usize);
    
    impl Component for Vel {
        type Storage = FlaggedStorage<Self, VecStorage<Self>>;
    }
    
    fn main() {
        let mut vels = vec![];
        let mut world = World::new();
        world.register::<Vel>();
        let mut removed_id = world.write::<Vel>().track_removed();
    
        vels.push(0.0);
        let e0 = world.create_entity().with(Vel(0)).build();
    
        {
            // remove an entity
            println!("entity removed:  {:?}", e0);
            world.delete_entity(e0).unwrap();
    
            // add an entity
            vels.push(0.3);
            let e1 = world.create_entity().with(Vel(1)).build();
            println!("entity created:  {:?}", e1);
    
            // try to find removed component
            let mut removed = BitSet::new();
            world.write::<Vel>().populate_removed(&mut removed_id, &mut removed);
    
            let entities = world.entities();
            for (e, _, v) in (&*entities, &removed, &world.read::<Vel>()).join() {
                // this does show we found new component instead
                println!("component of removed ? {:?}: {:?}", e, v);
            }
        }
    }
    

    The solution I'll implement is to create a new storage that keeps deleted component in some cache that I'll clear regularly (with removing their nphysic body). This implementation is straightforward but might be needed by others so that is why I open this issue and also to know if you have better solution.

    discussion 
    opened by thiolliere 28
  • Saveload overhaul

    Saveload overhaul

    TODO

    • [x] Commit messages need to be improved
    • [x] There is some weird lifetime error that I don't really understand

    Motivation for this PR

    • Rename some items to make the code easier to understand
    • Remove a couple of unnecessary bounds
    • Allow passing references of storages (previously you could not reuse the WriteStorage)

    Fixes #138 Fixes #282


    This change is Reviewable

    enhancement ready 
    opened by torkleyy 28
  • Custom derive for Component trait

    Custom derive for Component trait

    This PR introduces an optional specs_derive crate containing a custom derive macro for defining new components in a less verbose way. The ergonomics loosely resemble the derivative crate.

    Before

    #[derive(Debug)]
    struct Pos(f32, f32, f32);
    
    impl Component for Pos {
        type Storage = VecStorage<Pos>;
    }
    

    After

    #[derive(Component, Debug)]
    struct Pos(f32, f32, f32);
    

    The macro will store components in VecStorages by default. To specify a different storage type, you may use the #[component] attribute.

    #[derive(Component, Debug)]
    #[component(HashMapStorage)]
    struct Pos(f32, f32, f32);
    

    I also included a revised basic.rs example called basic_derive.rs to demonstrate its usage, but this can probably be omitted from the PR if people ultimately prefer implementing Component the explicit way.

    EDIT: Use DenseVecStorage by default.

    ready 
    opened by ebkalderon 26
  • wasm32 support

    wasm32 support

    Hello,

    Tried to build it with --target wasm32-unknown-unknown, haven't succeeeded. At first, I found out the dispatcher might be problematic (it's supporting parallel execution), so I went and annotated shred with conditional compilation directives (it already had it for emscripted, so I just duplicated it with analogue for target_arch = "wasm32" here. It builds fine then.

    Going back to specs, I've overriden the shred to use my branch:

    [dependencies.shred]
    git = "https://github.com/BartAdv/shred"
    rev = "4d6b1a9c4d0bc1cd8d7bba275e7fbb4d3be69f1b"
    

    only to see

    error[E0433]: failed to resolve. Use of undeclared type or module `imp`
      --> /home/bart/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.3.20/src/os.rs:35:18
       |
    35 | pub struct OsRng(imp::OsRng);
       |                  ^^^ Use of undeclared type or module `imp`
    
    error[E0433]: failed to resolve. Use of undeclared type or module `imp`
      --> /home/bart/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.3.20/src/os.rs:40:9
       |
    40 |         imp::OsRng::new().map(OsRng)
       |         ^^^ Use of undeclared type or module `imp`
    
    

    OK, I get that - rand crate relies on some sys stuff. So I wanted to fix whatever dep is wanting rand. Found out, the rayon-core uses it. As it turns out, rayon is used by hibitset (gated by feature flag parallel), so I wanted to check if I could gate the specs rayon dependncy similarily...:

    diff --git a/Cargo.toml b/Cargo.toml
    index ef2a182..a979465 100644
    --- a/Cargo.toml
    +++ b/Cargo.toml
    @@ -23,10 +23,9 @@ derivative = "1"
     fnv = "1.0"
     hibitset = { version = "0.4.1", features = ["parallel"] }
     mopa = "0.2"
    -shred = "0.5.0"
     shred-derive = "0.3"
     tuple_utils = "0.2"
    -rayon = "0.8.2"
    +rayon = { version = "0.8.2", optional = true}
     
     futures = { version = "0.1", optional = true }
     serde = { version = "1.0", optional = true, features = ["serde_derive"] }
    @@ -34,9 +33,14 @@ serde = { version = "1.0", optional = true, features = ["serde_derive"] }
     # enable rudy via --features rudy
     rudy = { version = "0.1", optional = true }
     
    +[dependencies.shred]
    +git = "https://github.com/BartAdv/shred"
    +rev = "4d6b1a9c4d0bc1cd8d7bba275e7fbb4d3be69f1b"
    +
     [features]
     common = ["futures"]
     nightly = []
    +parallel = ["hibitset/parallel", "rayon"]
     
     [package.metadata.docs.rs]
     features = ["common", "serde"]
    

    ...to no avail, the build is still giving me

    error[E0433]: failed to resolve. Use of undeclared type or module `imp`
      --> /home/bart/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.3.20/src/os.rs:35:18
       |
    35 | pub struct OsRng(imp::OsRng);
       |                  ^^^ Use of undeclared type or module `imp`
    

    Now - maybe someone more compoenent than me could try and check it? Is it planned to support wasm32-unknown-unknown target?

    feature-request hard 
    opened by BartAdv 25
  • Relicense under dual MIT/Apache-2.0

    Relicense under dual MIT/Apache-2.0

    TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that license is good for interoperation. The MIT license as an add-on can be nice for GPLv2 projects to use your code.

    Why?

    The MIT license requires reproducing countless copies of the same copyright header with different names in the copyright field, for every MIT library in use. The Apache license does not have this drawback. However, this is not the primary motivation for me creating these issues. The Apache license also has protections from patent trolls and an explicit contribution licensing clause. However, the Apache license is incompatible with GPLv2. This is why Rust is dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for GPLv2 compat), and doing so would be wise for this project. This also makes this crate suitable for inclusion and unrestricted sharing in the Rust standard distribution and other projects using dual MIT/Apache, such as my personal ulterior motive, the Robigalia project.

    Some ask, "Does this really apply to binary redistributions? Does MIT really require reproducing the whole thing?" I'm not a lawyer, and I can't give legal advice, but some Google Android apps include open source attributions using this interpretation. Others also agree with it. But, again, the copyright notice redistribution is not the primary motivation for the dual-licensing. It's stronger protections to licensees and better interoperation with the wider Rust ecosystem.

    Contributor checkoff

    To agree to relicensing, comment with :

    I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to choose either at their option.

    Checklist

    • [x] @kvark
    • [x] me
    • [x] @Aceeri
    • [x] @serprex
    • [x] @vitvakatu
    • [x] @malleusinferni
    • [x] @thiolliere
    • [x] @murarth
    • [x] @jeffparsons
    • [x] @msiglreith
    • [x] @lschmierer
    • [x] @WaDelma
    • [x] @Kimundi
    • [x] @mrZalli
    • [x] @Jragonmiris
    • [x] @minecrawler
    • [x] @futile
    • [ ] @White-Oak
    ready 
    opened by torkleyy 21
  • Idea: OpenCL-backed storage

    Idea: OpenCL-backed storage

    I have a scientific simulation / numerical computation project I've written using Specs. But last night I did a spike where I prototyped an version that offloaded the calculations to the GPU via OpenCL, and I saw a 100x performance improvement over the Specs (i.e, CPU-based) version. That's kind of hard to ignore.

    It occurred to me that if Specs had a component storage type backed by OpenCL buffers, then you could write Systems that apply OpenCL kernels to the data, and thereby make a Specs application that offloads some calculations to the GPU. You'd get to keep Specs' entity management, as well as have other systems that do CPU-based work in the same application, while shifting the heaviest lifting to the GPU.

    Has any thinking been done on this front, or any related work? What major challenges do you see in pulling this off?

    feature-request hard 
    opened by michaelmelanson 19
  • Lifetime issues with component storages

    Lifetime issues with component storages

    I originally posted about this in the users forum and then on Reddit.

    Terminology Note: When I say "owned X" in the text below, I mean that you have ownership of a value X of type T, not a reference to that value (e.g. &T or &mut T)

    You can look at this issue from two perspectives:

    1. It is hard to get a SystemData containing references to storages. Example: You can get (ReadStorage<A>, ReadStorage<B>) by calling the system_data method on World but not (&ReadStorage<A>, &ReadStorage<B>)
    2. It is not possible to use the Join trait with the owned versions of component storages. Example: You can do (&a, &b).join() but not (a, b).join()

    Both of these issues exist for good reasons, but they make code like the following very hard to write:

    fn iter_components<'a>(world: &'a World) -> impl Iterator<Item=(&Position, &Velocity)> + 'a {
        // Two *owned* storages allocated on the stack of this function
        let (positions, velocities) = world.system_data::<(ReadStorage<Position>, ReadStorage<Velocity>)>();
    
        // Returning a reference to stack allocated data (does not and should not work!)
        (&positions, &velocities).join()
    }
    

    This doesn't work and you get the following error: (copied from users forum post, see that for the full code example)

    error[E0515]: cannot return value referencing local variable `velocities`       
      --> src/main.rs:22:5                                                          
       |                                                                            
    22 |     (&positions, &velocities).join()                                       
       |     ^^^^^^^^^^^^^-----------^^^^^^^^                                       
       |     |            |                                                         
       |     |            `velocities` is borrowed here                             
       |     returns a value referencing data owned by the current function         
                                                                                    
    error[E0515]: cannot return value referencing local variable `positions`        
      --> src/main.rs:22:5                                                          
       |                                                                            
    22 |     (&positions, &velocities).join()                                       
       |     ^----------^^^^^^^^^^^^^^^^^^^^^                                       
       |     ||                                                                     
       |     |`positions` is borrowed here                                          
       |     returns a value referencing data owned by the current function
    

    If either of the two things I listed above weren't the case, this code could potentially compile:

    1. If you could get a system data instance containing references to storages: (the storages would have to be owned within the world or something)
    fn iter_components<'a>(world: &'a World) -> impl Iterator<Item=(&Position, &Velocity)> + 'a {
        // Two references to storages allocated somewhere by World
        // Notice the `&` before the `ReadStorage` types here
        let (positions, velocities) = world.system_data::<(&ReadStorage<Position>, &ReadStorage<Velocity>)>();
    
        // positions and velocities are both references, so we can use them here no problem
        (positions, velocities).join()
    }
    
    1. If it were possible to use the Join trait on owned versions of the storages:
    fn iter_components<'a>(world: &'a World) -> impl Iterator<Item=(&Position, &Velocity)> + 'a {
        // Two *owned* storages allocated on the stack of this function
        let (positions, velocities) = world.system_data::<(ReadStorage<Position>, ReadStorage<Velocity>)>();
    
        // Storages are *moved* into this tuple that we call `join` on. This works!
        (positions, velocities).join()
    }
    

    A note about this: ReadStorage makes it pretty obvious that we are immutably borrowing here, but with WriteStorage we would probably need some methods like read_owned() and write_owned() to emulate what you could do with & and &mut before. See the following code for more details:

    fn iter_components<'a>(world: &'a World) -> impl Iterator<Item=(&mut Position, &Velocity)> + 'a {
        // Two *owned* storages allocated on the stack of this function
        let (positions, velocities) = world.system_data::<(WriteStorage<Position>, WriteStorage<Velocity>)>();
    
        // You can join over either of these storages in two modes:
        // * `&positions` for read-only access to the components
        // * `&mut positions` for read-write access to the components
        // `write_owned()` could wrap the storage in a type that implements
        // the `Join` trait and allows access to mutable references
        // Instead of `read_owned()` we could default to the behaviour that
        // the owned version of a storage only allows reading
    
        // Storages are *moved* into this tuple that we call `join` on. This works!
        (positions.write_owned(), velocities.read_owned()).join()
    }
    

    I think this solution is probably the easiest to implement because it doesn't involve the World having to hold on to arbitrary storages for some extended amount of time.

    The API I would suggest is:

    • ReadStorage<T> and WriteStorage<T> implement Join and produce &T
    • WriteStorage<T> provides a method (e.g. write_owned()) that returns an owned value that implements Join and produces &mut T (perhaps something similar to MaybeJoin?)

    This may cause issues with World because it's probably not a good thing if a storage lives longer than expected. I am not familiar enough with the internals to comment on that.

    enhancement discussion 
    opened by sunjay 19
  • Start and Stop signal registration for the FlaggedStorage

    Start and Stop signal registration for the FlaggedStorage

    Sometimes you may want to perform some operations on the storage, but you don't want that these operations produce any event.

    You can use the function storage.set_event_emission(false) to suppress the event writing for of any action. When you want to re activate them you can simply call storage.set_event_emission(true)

    This change will be used to fix this: https://github.com/amethyst/amethyst/issues/1795

    Checklist

    • [x] I've added tests for all code changes and additions (where applicable)
    • [x] I've added a demonstration of the new feature to one or more examples
    • [x] I've updated the book to reflect my changes
    • [x] Usage of new public items is shown in the API docs
    opened by AndreaCatania 18
  • Externally defined systems and scripting

    Externally defined systems and scripting

    Opening an issue because I want to get shred & Specs ready for scripting!

    I'm currently working on named resources, there'll be a PR pretty soon. Then we can already write systems in Rust and compile them into a shared library. Next step will probably be exposing the Specs API via C.

    cc @Moxinilian @jojolepro

    I'm going to work on the PR and link it here once I'm done with it. In case you have any suggestions / want to help please comment ;)

    help wanted feature-request hard RFC 
    opened by torkleyy 18
  • specs uses shred 0.13.0, which depends on mopa

    specs uses shred 0.13.0, which depends on mopa

    Description

    specs currently(0.18.0) uses shred 0.13.0, which depends on mopa that is not maintained anymore. shred already removed the mopa in 0.14.0, but specs still not uses it.

    Meta

    Rust version: rustc 1.64.0 (a55dd71d5 2022-09-19) Specs version / commit: 0.18.0 Operating system: macOS Ventura

    Reproduction

    1. cargo init
    2. Add specs = { version = "0.18", features = ["derive"] } to the generated Cargo.toml

    Expected behavior

    It's good to upgrade shred to 0.14.0 to fix this issue.

    bug 
    opened by AcrylicShrimp 0
  • LazyUpdate::exec uses a &mut ref?

    LazyUpdate::exec uses a &mut ref?

    Description

    LazyUpdate has two exec fn's, exec and exec_mut. However it looks like their function signatures are identical?

    https://github.com/amethyst/specs/blob/81073f340425803c99e3292fa14ceb00245bfea5/src/world/lazy.rs#L303-L305

    https://github.com/amethyst/specs/blob/81073f340425803c99e3292fa14ceb00245bfea5/src/world/lazy.rs#L337-L339

    I was wondering what is the difference between the two?

    bug 
    opened by juliusl 0
  • Add necessity of feature flag serde to api documentation for saveload

    Add necessity of feature flag serde to api documentation for saveload

    Description

    The saveload documentation states: saveload is a module that provides mechanisms to serialize and deserialize a World, it makes use of the popular [serde](https://docs.rs/serde) library and requires the feature flag serde to be enabled for specs in your Cargo.toml file.

    The API documentation does not mention this fact, but it was at least for me the first google search hit when I got unresolved import specs::saveload. Maybe it would even be worth it to add the information to the Troubleshooting section

    Motivation

    I had to search quite a long time to find that information. I assume I'm not the only person to search the API than to read the tutorial.

    Drawbacks

    None

    • Is it a breaking change? No
    • Can it impact performance, learnability, etc? Yes
    feature-request 
    opened by andreas-wolf 1
  • ecs_bench_suite fragmented_iter unexpectedly slow

    ecs_bench_suite fragmented_iter unexpectedly slow

    Looking at the results in https://github.com/rust-gamedev/ecs_bench_suite, I'm surprised to see that Specs performs rather poorly in the fragmented_iter benchmark. IIUC, the Data-component uses VecStorage, and iterating over all Data-values should be a fairly quick for Specs?

    bug 
    opened by fabianbergmark 0
  • Best practice for borrowed resources in systems?

    Best practice for borrowed resources in systems?

    I'm halfway through the Roguelike tutorial and I would like to move my render logic into a System and use a Dispatcher instead of manually running systems. In this case bracket-lib has a tick where you mutably borrow a BTerm instance, but it feels like this is a common pattern where some kind of context is mutably borrowed.

    What's the best practice here? Should we just build a dispatcher per tick and pass the context in the system struct?

    question 
    opened by alvaro-cuesta 4
  • [Question] Is it possible to group components together (to all be accessed by 1 system)

    [Question] Is it possible to group components together (to all be accessed by 1 system)

    I have a lot of *_Animation components and I want them all to be accessed by my Animator system is there a way I can group them together similar to how you can group entities together with NullStorage components? I want to do something like this:

    impl<'a> System<'a> for Animator {
        type SystemData = (
            WriteStorage<'a, Animation>, // this is the group of animations
            WriteStorage<'a, Sprite>,
            ReadStorage<'a, AnimationState>,
        );
    }
    
    opened by DaQueenJodi 2
Releases(v0.18.0)
  • v0.18.0(Jul 5, 2022)

  • v0.17.0(Jul 3, 2022)

    • Deprecate error::NoError in favor of std::convert::Infallible ([#688])
    • Use #[non_exhaustive] for error::Error. Note this bumps the minimum supported rust version to 1.40 ([#688]).
    • Add the derive feature that enables all derive-related smaller features (specs-derive and shred-derive currently).
    Source code(tar.gz)
    Source code(zip)
  • 0.16.1(Feb 17, 2020)

    • JoinIter now implements Clone when inner types are Clone -- usually for immutable join()s. (#620)
    • Bump hibitset to 0.6.3. (#620)
    • StorageEntry::replace replaces a component, returning the previous value if any. (#622)
    Source code(tar.gz)
    Source code(zip)
  • 0.16.0(Feb 13, 2020)

    • Update syn, quote and proc-macro2 to 1.0. (#648)
    • Implement ParJoin for MaybeJoin if the inner type is ParJoin. (#655)
    • Remove "nightly" feature -- improved panic messages are available on stable. (#671)
    • Bump shred to 0.10.2. (#671, #674, #683)
    • Components and resources no longer need to be Send + Sync if parallel feature is disabled (#673, #674)
    • Bump uuid to 0.8.1. (#683)
    • Bump rayon to 1.3.0. (#683)
    Source code(tar.gz)
    Source code(zip)
  • v0.15.1(Sep 15, 2019)

  • v0.15.0(Jun 29, 2019)

    • Moved World to shred, added WorldExt trait for Specs functionality (#550)
    • Add UuidMarker for UUID <-> Entity mappings (#584)
    • Implement Join on BitSetLike trait object (#599)
    • Expose inner field of AntiStorage (#603)
    • Remove fnv in favour of hashbrown (#606)
    • Reexport hibitset, rayon, shred and shrev (#606)
    • Reexport shred_derive::SystemData when shred-derive feature is enabled (#606)
    • Reexport specs_derive::{Component, ConvertSaveload} when specs-derive feature is enabled (#606)
    Source code(tar.gz)
    Source code(zip)
  • v0.14.1(Nov 26, 2018)

  • v0.12.2(Sep 9, 2018)

  • v0.10(Oct 4, 2017)

    Changes

    • Separate CheckStorage into two variants and fix soundness issues (#203)
    • Fix Merge system and add test for it (#243, #248)
    • Add more examples, docs, tests, benchmarks (#249, #251, #254, #256, #258)
    • Use Results to make Specs more robust (#260)
    • Check code coverage with cargo-travis (#265)
    • Make common::Errors atomic and more convenient (#255, #262)
    • Add World::delete_all to clear the world (#257)
    • Fix insertion into occupied NullStorage entry ([#269])
    • Add Storage::drain method (#273)

    Upgrading

    Upgrading should be easy, because the only breaking changes were the CheckStorage and a few version bumps.

    Source code(tar.gz)
    Source code(zip)
Owner
Amethyst Engine
Data-oriented game engine written in Rust
Amethyst Engine
wecs (wckd-ecs) is a simple ECS library suitable for general use.

wecs wecs (wckd-ecs) is a simple ECS library heavily based on bevy_ecs. Motivation As part of my "Road to Rust GameDev" journey, I wanted to learn how

João Victor 9 Jul 2, 2023
High performance Rust ECS library

Legion aims to be a feature rich high performance Entity component system (ECS) library for Rust game projects with minimal boilerplate. Getting Start

Amethyst Engine 1.4k Jan 5, 2023
A tilemap rendering crate for bevy which is more ECS friendly.

bevy_ecs_tilemap A tilemap rendering plugin for bevy which is more ECS friendly by having an entity per tile. Features A tile per entity Fast renderin

John 414 Dec 30, 2022
Creative Coding Framework based on Entity Component System (ECS) written in Rust

creativity creativity is Creative Coding Framework based on Entity Component System (ECS) written in Rust. Key Features TBA Quick Start TBA How To Con

Chris Ohk 9 Nov 6, 2021
🏷️ Markers for Bevy ECS Entities

Bevy ECS Markers Adds the support for marking entites and fetching them in queries Example View the whole example here #[derive(EntityMarker)] enum Pl

Chopped Studio 2 Dec 23, 2022
Minimalistic implementation of entity kinds for Bevy ECS.

Bevy ?? Kindly This crate is a minimalistic implementation of Kinded Entities for Bevy game engine. In summary, it allows the user to define, construc

null 10 Jan 26, 2023
Bring Bevy's ECS to Godot4

bevy_godot4 Bring the design power of Bevy's ECS to the mature engine capabilities of Godot 4. WARNING: This crate is very early in development, and i

JR 4 May 8, 2023
A direct ecs to low-level server implementation for Godot 4.1

godot_ecs What if Godot 4.1 and Bevy got married? Well, you'd get one interesting duo of data driven goodness. In Development This crate is not produc

null 5 Oct 6, 2023
A simple type safety solution for Bevy ECS.

?? Moonshine Kind A simple type safety solution for Bevy ECS. Overview An Entity is a generic way to reference entities within Bevy ECS: #[derive(Comp

null 8 Nov 3, 2023
🤹‍ 2D sprite rendering extension for the specs ECS system

specs-blit 2D sprite rendering extension for the Specs ECS system. All sprites are loaded onto a big array on the heap. Example // Setup the specs wor

Thomas Versteeg 8 Aug 14, 2022
wecs (wckd-ecs) is a simple ECS library suitable for general use.

wecs wecs (wckd-ecs) is a simple ECS library heavily based on bevy_ecs. Motivation As part of my "Road to Rust GameDev" journey, I wanted to learn how

João Victor 9 Jul 2, 2023
ABQ is a universal test runner that runs test suites in parallel. It’s the best tool for splitting test suites into parallel jobs locally or on CI

?? abq.build   ?? @rwx_research   ?? discord   ?? documentation ABQ is a universal test runner that runs test suites in parallel. It’s the best tool f

RWX 13 Apr 7, 2023
Utilities for converting Vega-Lite specs from the command line and Python

VlConvert VlConvert provides a Rust library, CLI utility, and Python library for converting Vega-Lite chart specifications into static images (SVG or

Vega 24 Feb 13, 2023
specs & benchmarks for the ZPrize 3 - High Throughput Signature Verification

Zprize: High Throughput Signature Verification How fast do you think you can verify our ECDSA signatures on Aleo? This year's Zprize is winner-take-al

null 6 Oct 21, 2023
High performance Rust ECS library

Legion aims to be a feature rich high performance Entity component system (ECS) library for Rust game projects with minimal boilerplate. Getting Start

Amethyst Engine 1.4k Jan 5, 2023
A minimalist and safe ECS library for rust!

The full ECS (Entity-Component-System) library. Support an Open Source Developer! ♥️ Composed of two smaller libraries: world_dispatcher: the System p

Joël Lupien 124 Dec 19, 2022
A tilemap rendering crate for bevy which is more ECS friendly.

bevy_ecs_tilemap A tilemap rendering plugin for bevy which is more ECS friendly by having an entity per tile. Features A tile per entity Fast renderin

John 414 Dec 30, 2022
Creative Coding Framework based on Entity Component System (ECS) written in Rust

creativity creativity is Creative Coding Framework based on Entity Component System (ECS) written in Rust. Key Features TBA Quick Start TBA How To Con

Chris Ohk 9 Nov 6, 2021
ECS-friendly ldtk plugin for bevy, leveraging bevy_ecs_tilemap

bevy_ecs_ldtk An ECS-friendly ldtk plugin for bevy. Uses bevy_ecs_tilemap as a base. Not released yet, still in development. bevy_ecs_tilemap once sup

Trevor Lovell 247 Jan 10, 2023
A collection of components and widgets that are built for bevy_ui and the ECS pattern

Widgets for Bevy UI A collection of components and widgets that are built for bevy_ui and the ECS pattern. Current State This was started recently and

Gabriel Bourgeois 3 Sep 2, 2022