High performance Rust ECS library

Overview

Legion ECS

Build Status Crates.io Docs.rs

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

Getting Started

Worlds

Worlds are collections of entities, where each entity can have an arbitrary collection of components attached.

use legion::*;
let world = World::default();

Entities can be inserted via either push (for a single entity) or extend (for a collection of entities with the same component types). The world will create a unique ID for each entity upon insertion that you can use to refer to that entity later.

// a component is any type that is 'static, sized, send and sync
#[derive(Clone, Copy, Debug, PartialEq)]
struct Position {
    x: f32,
    y: f32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
struct Velocity {
    dx: f32,
    dy: f32,
}

// push a component tuple into the world to create an entity
let entity: Entity = world.push((Position { x: 0.0, y: 0.0 }, Velocity { dx: 0.0, dy: 0.0 }));

// or extend via an IntoIterator of tuples to add many at once (this is faster)
let entities: &[Entity] = world.extend(vec![
    (Position { x: 0.0, y: 0.0 }, Velocity { dx: 0.0, dy: 0.0 }),
    (Position { x: 1.0, y: 1.0 }, Velocity { dx: 0.0, dy: 0.0 }),
    (Position { x: 2.0, y: 2.0 }, Velocity { dx: 0.0, dy: 0.0 }),
]);

You can access entities via entries. Entries allow you to query an entity to find out what types of components are attached to it, to get component references, or to add and remove components.

// entries return `None` if the entity does not exist
if let Some(mut entry) = world.entry(entity) {
    // access information about the entity's archetype
    println!("{:?} has {:?}", entity, entry.archetype().layout().component_types());

    // add an extra component
    entry.add_component(12f32);

    // access the entity's components, returns `None` if the entity does not have the component
    assert_eq!(entry.get_component::<f32>().unwrap(), &12f32);
}

Queries

Entries are not the most convenient or performant way to search or bulk-access a world. Queries allow for high performance and expressive iteration through the entities in a world.

// you define a query be declaring what components you want to find, and how you will access them
let mut query = <&Position>::query();

// you can then iterate through the components found in the world
for position in query.iter(&world) {
    println!("{:?}", position);
}

You can search for entities which have all of a set of components.

// construct a query from a "view tuple"
let mut query = <(&Velocity, &mut Position)>::query();

// this time we have &Velocity and &mut Position
for (velocity, position) in query.iter_mut(&mut world) {
    position.x += velocity.x;
    position.y += velocity.y;
}

You can augment a basic query with additional filters. For example, you can choose to exclude entities which also have a certain component, or only include entities for which a certain component has changed since the last time the query ran (this filtering is conservative and coarse-grained)

// you can use boolean expressions when adding filters
let mut query = <(&Velocity, &mut Position)>::query()
    .filter(!component::<Ignore>() & maybe_changed::<Position>());

for (velocity, position) in query.iter_mut(&mut world) {
    position.x += velocity.dx;
    position.y += velocity.dy;
}

There is much more than can be done with queries. See the module documentation for more information.

Systems

You may have noticed that when we wanted to write to a component, we needed to use iter_mut to iterate through our query. But perhaps your application wants to be able to process different components on different entities, perhaps even at the same time in parallel? While it is possible to do this manually (see World::split), this is very difficult to do when the different pieces of the application don't know what components each other need, or might or might not even have conflicting access requirements.

Systems and the Schedule automates this process, and can even schedule work at a more granular level than you can otherwise do manually. A system is a unit of work. Each system is defined as a function which is provided access to queries and shared resources. These systems can then be appended to a schedule, which is a linear sequence of systems, ordered by when side effects (such as writes to components) should be observed. The schedule will automatically parallelize the execution of all systems whilst maintaining the apparent order of execution from the perspective of each system.

// a system fn which loops through Position and Velocity components, and reads the Time shared resource
// the #[system] macro generates a fn called update_positions_system() which will construct our system
#[system(for_each)]
fn update_positions(pos: &mut Position, vel: &Velocity, #[resource] time: &Time) {
    pos.x += vel.dx * time.elapsed_seconds;
    pos.y += vel.dy * time.elapsed_seconds;
}

// construct a schedule (you should do this on init)
let mut schedule = Schedule::builder()
    .add_system(update_positions_system())
    .build();

// run our schedule (you should do this each update)
schedule.execute(&mut world, &mut resources);

See the systems module and the system proc macro for more information.

Feature Flags

Legion provides a few feature flags:

  • parallel - Enables parallel iterators and parallel schedule execution via the rayon library. Enabled by default.
  • extended-tuple-impls - Extends the maximum size of view and component tuples from 8 to 24, at the cost of increased compile times. Off by default.
  • serialize - Enables the serde serialization module and associated functionality. Enabled by default.
  • crossbeam-events - Implements the EventSender trait for crossbeam Sender channels, allowing them to be used for event subscriptions. Enabled by default.

WASM

Legion runs with parallelism on by default, which is not currently supported by Web Assembly as it runs single-threaded. Therefore, to build for WASM, ensure you set default-features = false in Cargo.toml. Additionally, if you want to use the serialize feature, you must enable either the stdweb or wasm-bindgen features, which will be proxied through to the uuid crate. See the uuid crate for more information.

legion = { version = "*", default-features = false, features = ["wasm-bindgen"] }
Comments
  • Experimental refactor in legion_experiment crate

    Experimental refactor in legion_experiment crate

    This started as a simple refactor of legion into smaller sub-modules, as some of the module files were well over 1k LoC and were getting unmaintainable. However, while moving things around, I found some soundness issues and saw some opportunity to simplify things. Those in turn caused more changes downstream, and the simplifications made other improvements that I had been planning fairly trivial to implement. This ended up being a much larger and more impactful refactor of the entire legion_core crate than I had originally planned. This work is not yet complete, but it is wide reaching enough that I want to give everyone the opportunity to see what I've been doing and collect some feedback.

    The general changes are:

    • Much shorter module files, each with a more clearly defined scope.
    • Simpler code in general. I don't have a line count yet, but I expect this to have shaved a few hundred lines off the library overall.
    • Removed many uses of unsafe.

    Changes to World (which now more closely resembles a std collection):

    • Added len to retrieve entity count.
    • Renamed insert to extend.
    • Added push as sugar for inserting a single entity.
    • Renamed delete to remove.
    • Renamed is_alive to contains.
    • Added entity(Entity) -> Entry and entity_mut(Entity) -> EntryMut functions. Entries contain the APIs for interacting with a single entity. e.g. get_component, add_component and layout (which in turn offers has_component etc).
    • iter and iter_mut for iterating through all entity entries.
    • You can now insert with a tuple of component vecs, in addition to an iterator of component tuples. This is about 50% faster.

    Changes to storage:

    • Much clearer distinction between structural changes to storage (e.g. adding entities) and the interior mutability involved in accessing components.
    • Chunk metadata has been pulled out into a LayoutIndex.
    • The layout index is optimised for search and provides a .search(EntityFilter) -> impl Iterator<Item = ArchetypeIndex> function.
    • Renamed "archetype" to "layout".
    • Renamed "chunk set" to "archetype".
    • Storage now derefs into [Archetype] and can be indexed by ArchetypeIndex.
    • Chunks no longer free their internal memory when empty. Defrag now deletes empty chunks.
    • Event subscribers can ask to recieve initial creation/insertion events for pre-existing archetypes and entities when they subscribe.

    Changes to filters:

    • No longer implemented as iterators. This was a pain without GATs (it is the canonical streaming iterator problem).
    • Filters now only provide their matching logic.
    • Distinction made between stateless layout/archetype filters and stateful chunk filters.
    • Filters can now cache their matches and incrementally update queries. System queries should do this by default in the future.

    It is likely that SystemQuery won't be needed anymore, too.

    I don't forsee any more major API changes beyond completing this rework, and legion v1.0.0 will likely closely resemble this, after which things should stabilise and breaking changes will hopefully be rare.

    opened by TomGillen 36
  • Improved public API soundess

    Improved public API soundess

    Changed World and Query APIs to require &mut World, such that it is statically impossible to write safe code with unsound borrowing. New unsafe _unchecked alternatives have been added with the previous behaviour.

    This required changing the PreparedQuery APIs to also require they be given a PreparedWorld reference, in order to control whether a system can execute two of its queries at the same time.

    PreparedWorld now provides more of the API that is available on World. PreparedWorld allows random access to components and archetypes that a system's queries declare access to. SystemBuilder::[read/write]_component can now be used to mark the system as accessing all archetypes.

    opened by TomGillen 18
  • "query attempted to access archetype unavailable via sub world": Bug or just me?

    Here is some code to reproduce (not sure if this is minimal)

    use legion::prelude::*;
    use tracing::{info, Level};
    use tracing_subscriber;
    
    #[derive(Debug)]
    struct Money(f64);
    #[derive(Debug)]
    struct Health(f64);
    struct Food(f64);
    
    
    fn main() {
        let subscriber = tracing_subscriber::fmt()
            .with_max_level(Level::TRACE)
            .init();
    
        let universe = Universe::new();
        let mut world = universe.create_world();
    
        world.insert((),
            vec![
                (Money(5.0), Food(5.0)),
            ]
        );
        
        world.insert((),
            vec![
                (Money(4.0), Health(3.0)),
                (Money(4.0), Health(3.0)),
                (Money(4.0), Health(3.0)),
            ]
        );
    
        let show_me_the_money = SystemBuilder::new("money_show")
            .with_query(<(Read<Money>, Read<Food>)>::query())
            .build(|_, world, _, query| {
                for (money, food) in query.iter(world) {
                    info!("Look at my money {:?}", money);
                }
            });
    
        let health_conscious = SystemBuilder::new("healthy")
            .with_query(<(Read<Money>, Read<Health>)>::query())
            .build(|_, world, _, query| {
                for (money, health) in query.iter(world) {
                    info!("So healthy {:?}", health);
                }
            });
    
        let mut schedule = Schedule::builder()
            .add_system(show_me_the_money)
            .flush()
            .add_system(health_conscious)
            .flush()
            .build();
    
        let mut resources = Resources::default();
        schedule.execute(&mut world, &mut resources);
    }
    

    If you comment out either of the world.insert... statements, it runs without errors. Am I doing something wrong here?

    opened by travis-leith 13
  • Random access APIs should be marked as unsafe

    Random access APIs should be marked as unsafe

    Random access APIs, such as World.get_component cannot have their safety expressed statically in Rust's type system. Instead, they are runtime borrow checked.

    However, this runtime borrow checking is only there as a diagnostic aid; it will provide more useful fail-fast behaviour and stack traces, rather than the state corruption that would otherwise have to be debugged.

    The user must still carefully consider how these APIs are used and ensure that they are not breaking any borrowing rules. Therefore, these functions should still be marked as unsafe, to more clearly communicate this responsibility.

    type: bug 
    opened by TomGillen 10
  • What is the conceptual difference between Executor and Builder?

    What is the conceptual difference between Executor and Builder?

    A Builder can be used to compose a bunch of Systems which are all Schedulable. It seems that (I may be wrong on this one because it is not yet explicitly documented as far as I can tell) that Systems can be grouped between flush calls and that Systems within such a group are executed in parallel (by default) and the groups themselves are executed sequentially.

    Have I got that right?

    An Executor is something that "Executes a sequence of systems, potentially in parallel, and then commits their command buffers."

    These seem to fulfill the same purpose to me. Is one being deprecated or do they have different use cases?

    Also, I am happy to take a stab at expanding the readme.md and/or the hello_world example with something that clarifies this, once I understand it.

    opened by travis-leith 9
  • Track component changes like resource changes

    Track component changes like resource changes

    • Track reads as well as writes
    • Writes are dependent on reads to avoid simultanious execution
    • Reads handled after writes to prevent overriting last read
    opened by Guvante 9
  • Make `Entity` (de)serializable

    Make `Entity` (de)serializable

    Hi,

    For a networking game I'd like to use Entity as an identification for players (a player client would send to the server an Entity along other data).
    If this is sound, would it be possible to make Entity (de)serializable to be able to send it in network packets ?

    opened by bestouff 8
  • Added add_system_boxed and add_thread_local_boxed

    Added add_system_boxed and add_thread_local_boxed

    Description

    Allow passing Box<dyn ParallelRunnable> and Box<dyn Runnable> directly.

    Motivation and Context

    I am storing my own systems in a Vec<Box<dyn Runnable>> for sorting before passing them into legion, but I cannot pass a Box<dyn Runnable> directly because of the explicit type requirements.

    How Has This Been Tested?

    The code passes clippy lint. I don't think testing is necessary since this is pretty straightforward.

    Checklist:

    • [x] Acknowledged that by making this pull request I release this code under an MIT/Apache 2.0 dual licensing scheme.
    • [x] My code follows the code style of this project.
    • [x] If my change required a change to the documentation I have updated the documentation accordingly.
    • [x] I have updated the content of the book if this PR would make the book outdated.
    • [ ] I have added tests to cover my changes.
    • [ ] My code is used in an example.
    opened by SOF3 7
  • allow `system` macro to use a local module for legion behind a feature instead of the crate

    allow `system` macro to use a local module for legion behind a feature instead of the crate

    fixes #178

    This is due to all paths to legion in the macro starting with :: which means that legion has to be a crate and not a module.

    I found this issue when playing with Amethyst where the system macro doesn't work with the following error:

    error[E0432]: unresolved import `legion`
      --> examples/pong_tutorial_03/systems/paddle.rs:34:1
       |
    34 | #[system]
       | ^^^^^^^^^ help: a similar path exists: `amethyst_core::legion`
       |
       = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
    
    error[E0433]: failed to resolve: could not find `legion` in `{{root}}`
      --> examples/pong_tutorial_03/systems/paddle.rs:34:1
       |
    34 | #[system]
       | ^^^^^^^^^ could not find `legion` in `{{root}}`
       |
       = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
    
    error[E0433]: failed to resolve: could not find `legion` in `{{root}}`
      --> examples/pong_tutorial_03/systems/paddle.rs:34:1
       |
    34 | #[system]
       | ^^^^^^^^^ not found in `legion::systems`
       |
       = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
    help: consider importing one of these items
       |
    1  | use amethyst::ecs::SystemBuilder;
       |
    1  | use amethyst_core::ecs::SystemBuilder;
       |
    1  | use crate::SystemBuilder;
       |
    

    If I add legion as a direct dependency, it works, but it's not ideal because it means everyone using amethyst with legion would always need to keep both in sync.

    I added a feature reexport that, when enabled, will switch the path prefix from :: to self::, which means I can now use a re-exported legion module

    opened by mockersf 7
  • Panic on unwrap when using Query::get_mut

    Panic on unwrap when using Query::get_mut

    Using the latest master, I'm getting a panic from within Legion, as follows:

    thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /home/rua/.cargo/git/checkouts/legion-6fbc02e8da0bdce7/de081f6/src/internals/query/view/write.rs:87:26
    stack backtrace:
    [...]
     14: core::option::Option<T>::unwrap
                 at /rustc/c7087fe00d2ba919df1d813c040a5d47e43b0fe7/src/libcore/macros/mod.rs:34
      15: <legion::internals::query::view::write::Write<T> as legion::internals::query::view::View>::fetch
                 at /home/rua/.cargo/git/checkouts/legion-6fbc02e8da0bdce7/de081f6/src/internals/query/view/write.rs:87
      16: <(G,H) as legion::internals::query::view::View>::fetch
                 at /home/rua/.cargo/git/checkouts/legion-6fbc02e8da0bdce7/de081f6/src/internals/query/view/mod.rs:211
      17: legion::internals::query::Query<V,F>::get_unchecked
                 at /home/rua/.cargo/git/checkouts/legion-6fbc02e8da0bdce7/de081f6/src/internals/query/mod.rs:250
      18: ferret::doom::door::door_use_system::{{closure}}
                 at src/doom/door.rs:195
    [...]
    

    The line in question contains:

    let (mut query_world, mut world) = world.split_for_query(&query);
    if let Some((ceiling_move, door_active)) = query.get_mut(&mut query_world, sector_entity) {
    

    Where query is given by the system as:

    .with_query(<(Write<CeilingMove>, Write<DoorActive>)>::query())
    

    I also get the same panic with the following line and query, and an unsplit world:

    let (floor_move, plat_active) = match query.get_mut(world, event.entity) {
    
    .with_query(<(Entity, Write<FloorMove>, Write<PlatActive>)>::query())
    
    opened by Rua 7
  • Cannot access additional components while iterating query

    Cannot access additional components while iterating query

    Before 3ee0bb9b75 change the following code (edited for brevity) used to work:

        SystemBuilder::new("monster_ai")
            .with_query(<(Write<Viewshed>, Write<Position>)>::query().filter(tag::<Monster>()))
            .write_component::<Confusion>()
            .build(
                |command_buffer, world, _, query| {
                    for (entity, (mut viewshed, mut pos)) in query.iter_entities_mut(world) {
                        let mut can_act = true;
    
                        if let Some(mut confused) = world.get_component_mut::<Confusion>(entity) {
                            confused.turns -= 1;
                            can_act = false;
                        }
    
                        if can_act {
    

    After 3ee0bb9b75 it fails to compile:

    error[E0499]: cannot borrow `*world` as mutable more than once at a time
      --> src/monster_ai_system.rs:28:49
       |
    25 |                 for (entity, (mut viewshed, mut pos)) in query.iter_entities_mut(world) {
       |                                                          ------------------------------
       |                                                          |                       |
       |                                                          |                       first mutable borrow occurs here
       |                                                          first borrow later used here
    ...
    28 |                     if let Some(mut confused) = world.get_component_mut::<Confusion>(entity) {
       |                                                 ^^^^^ second mutable borrow occurs here
    

    Is this access pattern not supported by Legion?

    If so, what is the designed use of read/write_component() function? Any tips on changing my code?

    opened by smokku 7
  • Linking legion entities with rapier2d colliders.

    Linking legion entities with rapier2d colliders.

    Hello,

    I'm trying to combine legion with rapier2d for physics calculation and 2d . So if I make a query in rapier2d and get a certain rigid body or collider I want to be able to get the legion entity.

    For this reason rapier2d provides a u128 userdata linked to each collider, however, the internal legion entity id (NonZeroU64) is private and can therefore not be used.

    Would it be possible to provide a way to get the internal entity id and create a new entity using a known id, like:

    collider.set_userdata(entity.get_id());
    ...
    let entity = World::get_entity(collider.get_userdata() as NonZeroU64).unwrap();
    

    Or do you even know of a a better solution? The only possible alternative that comes to my mind is building a separate u128 id and mapping it to legions entities. However, this is a lot of boilerplate and effectively managing ids on ids...

    Thanks in advance and thanks for this incredible ECS!

    opened by pollmaecher 0
  • Prototype game no longer working in browser after adding legion

    Prototype game no longer working in browser after adding legion

    Hi there, I'm just playing around with some game dev. I have a new project hosted here https://gitlab.com/freiguy1/strands (look at branch legion for this code) which is very small, just a main.rs so far. We had it building and deploying to GitLab Pages when our only dependency was macroquad. Now I'm experimenting with Legion. Building & running locally works great, and the wasm32 targeted build is working, but when actually visiting the web page with the game, I'm seeing errors in the browser console:

    WASM failed to load, probably incompatible gl.js version

    TypeError: import object field '__wbindgen_placeholder__' is not an Object

    In Cargo.toml I've tried both

    [target.'cfg(target_arch = "wasm32")'.dependencies]
    legion = { version = "0.4", default-features = false, features = ["codegen", "stdweb"]}
    

    and

    [target.'cfg(target_arch = "wasm32")'.dependencies]
    legion = { version = "0.4", default-features = false, features = ["codegen", "wasm-bindgen"]}
    

    And I've received the same error. You can see the build steps in the .gitlab-ci.yaml file. Perhaps we're missing a step now that we're including legion. I didn't see any additional instructions on the legion readme. Any advice?

    opened by freiguy1 0
  • Query with ordering / sorting?

    Query with ordering / sorting?

    Is there a way to query entities with a given component, sorted by a value in the component? I'm thinking of the case where entities represent 'Renderable' objects, which are sorted spatially. You'd want to visit them back->front for example. I can't see such a thing in the docs, and I get that you could build a cache of the ordering by sorting entity ids yourself....

    opened by cmaughan 0
  • Make KnownLength public

    Make KnownLength public

    • Make the KnownLength trait public as legion::storage::KnownLength.
    • Fix lints and use Iterator::reduce instead of the deprecated Itertools::fold1.

    Motivation and Context

    Closes issue https://github.com/amethyst/legion/issues/274

    CommandBuffer allows to push components for a new entity, but its signature constraints the components arguments with several traits. One of this is KownLength which at the moment is private. This unfortunately prevents from defining systems which take generic arguments as input that can be then used to create the entity components with `CommandBuffer.

    For example, in my specific case I am in a situation where I'd like to be able to do something like the following:

    #[system]
    fn clone<EntityBuilder, Components>(cmd: &mut CommandBuffer)
    where
        EntityBuilder: MyBuilderTrait<Components = Components> + Sync,
        Option<Components>: IntoComponentSource + 'static,
        <Option<Components> as IntoComponentSource>::Source: Send + Sync + KnownLength,
    {
         let builder = EntityBuilder::new(...);
         let components = builder.build();
    
         cmd.push(components);
    }
    

    How Has This Been Tested?

    Running cargo test on this branch is successful.

    Checklist:

    • [x] Acknowledged that by making this pull request I release this code under an MIT/Apache 2.0 dual licensing scheme.
    • [ ] My code follows the code style of this project.
    • [x] If my change required a change to the documentation I have updated the documentation accordingly.
    • [ ] I have updated the content of the book if this PR would make the book outdated.
    • [ ] I have added tests to cover my changes.
    • [ ] My code is used in an example.
    opened by gliderkite 0
  • Is there way to push entities with dynamic components?

    Is there way to push entities with dynamic components?

    Hi all! I want to push an entity, but I don't know what components will be exists, because it can be known on runtime.

    So currently I'm just creating an empty entity and push components on it.

    Is there better way to do? Thank you!

    opened by AcrylicShrimp 0
  • Implement LayoutFilter for Box<dyn LayoutFilter + Send>

    Implement LayoutFilter for Box

    Added implementation of the LayoutFilter trait for Box<dyn LayoutFilter + Send>.

    Description

    • Added impl LayoutFilter for Box<dyn LayoutFilter + Send> {...}.
    • Corresponding documentation entry added with an example and motivation explanations.

    Motivation and Context

    When serializing a World, world- and entity serializers are passed to World::as_serializable() by reference while the layout filter is passed by value - even though LayoutFilter::matches_layout() does not consume the filter object. Because of that, when a user tried to develop a solution that will allow systems to request world serialization (that should be performed outside the Schedule since systems do not have access to the whole World to do that) there was no way to store the desired layout filter in any type-agnostic way.

    This change allows storing layout filters inside Boxes and later passing them "as is" to World::as_serializable() without breaking the existing interface. In particular, this change solves the problem of decoupling the code that requests world serialization from the code that actually performs it, including the layout filter type. So now it's possible for different systems to store serialization requests (including custom layout filters) in Resources that will later be processed altogether outside the Schedule execution.

    An additional Send requirement was added to allow to store filters in Resources accessed by systems that don't have to be thread-local.

    How Has This Been Tested?

    I've tested these changes in my private project, but I've also added a corresponding example to the documentation (that, I suppose, could count as a doc-test).

    Checklist:

    • [x] Acknowledged that by making this pull request I release this code under an MIT/Apache 2.0 dual licensing scheme.
    • [x] My code follows the code style of this project.
    • [x] If my change required a change to the documentation I have updated the documentation accordingly.
    • [ ] I have updated the content of the book if this PR would make the book outdated.
    • [ ] I have added tests to cover my changes.
    • [x] My code is used in an example.
    opened by zedrian 0
Releases(v0.4.0)
  • v0.4.0(Feb 25, 2021)

    What's Changed

    🚀 Features and Improvements

    • [breaking] Some rearranging of serialize/deserialize code (#230) @Rua
    • [breaking] Extract canon from registry (#221) @alyjak
    • [breaking] Add Resources to CommandBuffer::exec_mut and ::flush (#214) @Rua
    • Allow Queries to be requested as parameters in #[system] (#237) @TomGillen
    • Use NonZeroU64 to store entity IDs (#238) @Rua
    • Removing derivative from dependencies (#232) @lain-dono
    • Fetching a nonexistent resource prints the name of a type (#231) @LokiVKlokeNaAndoke
    • Implement Debug for Schedule, Executor and other subtypes (#213) @Rua
    • adds EntityFilterTuple to the public API (#222) @alyjak
    • Adds CustomEntitySerializer to the public API (#220) @alyjak
    • Re-export FetchMut from systems (#209) @Veykril
    • A few minor optimizations to LocationMap (#206) @mjhostet
    • Better error message when fetching nonexistent resources (#210) @Rua
    • Show appropriate error position on invalid macro usage (#208) @tyfkda

    🐛 Bug Fixes

    • Fix parallel chunk iterator using entire index instead of split slice (#240) @TomGillen
    • Fix broken links in docs & readme.md (#236) @FluffyCreature
    • allow read in both subworlds within split in system (#235) @ezpuzz
    • Use a drop guard to prevent leaving a dangling reference in internals::serialize::id::run_as_context (#203) @autumnontape

    🧰 Maintenance

    • synchronize CI functions with Amethyst (#233) @ezpuzz
    • Use write_u64 to special-case hashing 64 bit values (#204) @mjhostet
    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(Sep 28, 2020)

    Fixes:

    • QueryResult::split_at splitting at the concorrect indexes. This fixes a critical bug which would cause the incorrect components to be returned from parallel iterators, potentially resulting in mutable aliases.
    • SystemBuilder requiring Send be implemented for its resource tuple type.
    • Various broken documentation links.
    Source code(tar.gz)
    Source code(zip)
Owner
Amethyst Engine
Data-oriented game engine written in Rust
Amethyst Engine
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
Specs - Parallel ECS

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

Amethyst Engine 2.2k Jan 8, 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
🤹‍ 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
🏷️ 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
A high-performance renderer to render glTF models that use the `KHR_materials_transmission` and `KHR_materials_volume` extensions.

This is a high-performance renderer designed among other things to render glTF models that use the KHR_materials_transmission and KHR_materials_volume

Ashley 21 Dec 5, 2022
Comparing performance of Rust math libraries for common 3D game and graphics tasks

mathbench mathbench is a suite of unit tests and benchmarks comparing the output and performance of a number of different Rust linear algebra librarie

Cameron Hart 137 Dec 8, 2022
Using bevy and custom render pipelines in order to render many objects in a forest using chunks for performance.

bevy_efficient_forest_example Using bevy and custom render pipelines in order to render many objects in a forest using chunks for performance. Grass i

Henrik Djurestål 43 Jan 5, 2023
A Rust wrapper and bindings of Allegro 5 game programming library

RustAllegro A thin Rust wrapper of Allegro 5. Game loop example extern crate allegro; extern crate allegro_font; use allegro::*; use allegro_font::*;

null 80 Dec 31, 2022
Rust library to create a Good Game Easily

ggez What is this? ggez is a Rust library to create a Good Game Easily. The current version is 0.6.0-rc0. This is a RELEASE CANDIDATE version, which m

null 3.6k Jan 7, 2023
Rust bindings for libtcod 1.6.3 (the Doryen library/roguelike toolkit)

Warning: Not Maintained This project is no longer actively developed or maintained. Please accept our apologies. Open pull requests may still get merg

Tomas Sedovic 226 Nov 17, 2022
a rust library to find near-duplicate video files

Video Duplicate Finder vid_dup_finder finds near-duplicate video files on disk. It detects videos whose frames look similar, and where the videos are

null 12 Oct 28, 2022
A Rust library for blitting 2D sprites

blit A Rust library for blitting 2D sprites Documentation Usage Add this to your Cargo.toml:

Thomas Versteeg 23 Dec 6, 2022
FPS library for gdnative written in Rust.

gd_rusty_fps FPS library for gdnative written in Rust. This projects aims to create easy to use .dll library to be used with godot engine for FPS game

null 1 Jan 4, 2022
A low-level library for OpenGL context creation, written in pure Rust.

glutin - OpenGL, UTilities and INput A low-level library for OpenGL context creation, written in pure Rust. [dependencies] glutin = "0.28.0" Documenta

Rust Windowing 1.8k Jan 5, 2023