A generated entity component system ๐ŸฆŽ

Overview

gecs ๐ŸฆŽ

A generated entity component system.

Documentation Crates.io

The gecs crate provides a compile-time generated, zero-overhead ECS for simulations on a budget. Unlike other ECS libraries, gecs takes a full ECS world structure definition from code and precompiles all queries to achieve better performance with no upfront cost or caching overhead. Queries in gecs can be inspected and checked at compile-time in order to catch what would otherwise be bugs presenting only in tests or execution. However, this comes at the cost of requiring all archetypes to be known and declared at compile-time, so that adding or removing components from entities at runtime isn't currently possible -- hybrid approaches could solve this in the future.

Archetypes in gecs can be set to contain a fixed or dynamic capacity of entities. If all of the archetypes in your ECS world declaration are set to a fixed capacity, gecs will perform zero allocations after startup. This guarantees that your ECS world will adhere to a known and predictable memory overhead for constrained environments (e.g. servers on cloud instances). Attempting to add an entity to a full archetype can either report failure or panic depending on the method you call to do so.

The goals for gecs are (in descending priority order):

  • Fast iteration and find queries
  • Fast entity creation and destruction
  • Low, predictable memory overhead
  • A user-friendly library interface
  • Simplicity and focus in features

All of the code that gecs generates in user crates is safe, and users of gecs can use #[deny(unsafe_code)] in their own crates. Note that gecs does use unsafe code internally to allow for compiler optimizations around known invariants. It is not a goal of this library to be written entirely in safe Rust.

Getting Started

See the ecs_world!, ecs_find!, and ecs_iter! macros for more information. The following example creates a world with three components and two archetypes:

use gecs::prelude::*;

// Components -- these must be pub because the world is exported as pub as well.
pub struct CompA(pub u32);
pub struct CompB(pub u32);
pub struct CompC(pub u32);

ecs_world! {
    // Declare two archetypes, ArchFoo and ArchBar.
    ecs_archetype!(ArchFoo, 100, CompA, CompB); // Fixed capacity of 100 entities.
    ecs_archetype!(ArchBar, dyn, CompA, CompC); // Dynamic (dyn) entity capacity.
}

fn main() {
    let mut world = World::default(); // Initialize an empty new ECS world.

    // Add entities to the world by pushing their components and receiving a handle.
    let entity_a = world.push::<ArchFoo>((CompA(1), CompB(20)));
    let entity_b = world.push::<ArchBar>((CompA(3), CompC(40)));

    // Each archetype now has one entity.
    assert_eq!(world.len::<ArchFoo>(), 1);
    assert_eq!(world.len::<ArchBar>(), 1);

    // Look up each entity and check its CompB or CompC value.
    assert!(ecs_find!(world, entity_a, |c: &CompB| assert_eq!(c.0, 20)));
    assert!(ecs_find!(world, entity_b, |c: &CompC| assert_eq!(c.0, 40)));

    // Add to entity_a's CompA value.
    ecs_find!(world, entity_a, |c: &mut CompA| { c.0 += 1; });

    // Sum both entities' CompA values with one iter despite being different archetypes.
    let mut sum = 0;
    ecs_iter!(world, |c: &CompA| { sum += c.0 });
    assert_eq!(sum, 5); // Adding 2 + 3 -- recall that we added 1 to entity_a's CompA.

    // Collect both entities that have a CompA component.
    let mut found = Vec::new();
    ecs_iter!(world, |entity: &EntityAny, _: &CompA| { found.push(*entity); });
    assert!(found == vec![entity_a.into(), entity_b.into()]);

    // Remove both entities -- this will return an Option containing their components.
    assert!(world.remove(entity_a).is_some());
    assert!(world.remove(entity_b).is_some());

    // Try to look up a stale entity handle -- this will return false.
    assert_eq!(ecs_find!(world, entity_a, |_: &Entity<ArchFoo>| { panic!() }), false);
}

License

This library may be used under your choice of the Apache 2.0 or MIT license.

Comments
  • Add ecs_component_id!(Component) pseudo-macro to use in the body of query lambdas

    Add ecs_component_id!(Component) pseudo-macro to use in the body of query lambdas

    Add an ecs_component_id!(Component) pseudo-macro to use in the body of query lambdas (e.g. in ecs_find_...). After evaluation this is replaced with the int literal corresponding to the ordinal/index of that component in that archetype. For example, if I declare ecs_archetype!(ArchFoo, 100, ComponentA, ComponentB, ComponentC);, the body of a query matching on ArchFoo would replace ecs_component_id!(ComponentB) with 1.

    This is handy for bitflags in network serialization, and dirty flags for change detection.

    enhancement 
    opened by recatek 2
  • Add an Entity<_> pseudotype for query closures that return a typed Entity<A> for each matched archetype

    Add an Entity<_> pseudotype for query closures that return a typed Entity for each matched archetype

    Example usage:

    use gecs::prelude::*;
    
    pub struct ComponentA;
    
    ecs_world! {
        ecs_archetype!(ArchFoo, 10, ComponentA);
        ecs_archetype!(ArchBar, 10, ComponentA);
    }
    
    fn main() {
        let mut world = World::default();
        world.push::<ArchFoo>((ComponentA));
        world.push::<ArchBar>((ComponentA));
    
        ecs_iter!(world, |entity: &Entity<_>, comp: &ComponentA| {
            // This should execute twice, once where entity is an 
            // Entity<ArchFoo>, and once where it's an Entity<ArchBar>
        });
    }
    enhancement 
    opened by recatek 0
  • Add the OneOf<A, B, C> pseudo-struct decorator in the parameter section of queries

    Add the OneOf pseudo-struct decorator in the parameter section of queries

    Allow queries to specify their parameters in the form of |foo: OneOf<ComponentA, ComponentB, ComponentC>|, which will match any archetype with any of those components. There are several situations where this could result in ambiguity, but each can be detected and reported as a compile-time error.

    enhancement 
    opened by recatek 0
  • Add the ability to specify dyn as the capacity for an archetype, turning it into a Vec-like dynamic storage

    Add the ability to specify dyn as the capacity for an archetype, turning it into a Vec-like dynamic storage

    Using the dyn keyword in the capacity parameter of an archetype! declaration pseudo-macro should create it as a Vec-like dynamically allocated storage container with no explicit bounds on the number of stored entities of that archetype.

    enhancement 
    opened by recatek 0
  • Return types for `ecs_find!` queries

    Return types for `ecs_find!` queries

    For ecs_find! and ecs_find_borrow! queries, we could support having the query macro parse a return type and return it (while also bundling it with the bool for whether or not the entity was found):

    let (found, result) = ecs_find!(world, entity, |a: &CompA| -> u64 { /* ... */ })
    

    Where found is a bool and result is the u64 we requested to return.

    opened by recatek 0
  • Add support for components with generic arguments

    Add support for components with generic arguments

    It should be straightforward to support components with generic arguments so long as they don't use any of the reserved component names (Option, OneOf, etc.).

    opened by recatek 1
  • Add basic fixed and dynamic slotmap structures

    Add basic fixed and dynamic slotmap structures

    Because gecs essentially uses slotmap storage under the hood, it would be useful for the library to provide standalone slotmap functionality. While the slotmap crate exists, it doesn't provide a fixed-capacity option.

    This is also the first step on a roadmap to allowing optional components on archetypes, using something akin to the slotmap crate's secondary maps.

    opened by recatek 0
  • Add bundles for commonly-reused `OneOf` component groups

    Add bundles for commonly-reused `OneOf` component groups

    Some components may be frequently combined together in OneOf pseudo-arguments, especially in the case of variadic workarounds (e.g. OneOf<Flags1, Flags2, Flags3, Flags4>). It would be helpful to be able to create some sort of alias for easier reuse.

    opened by recatek 0
Releases(v0.2.1)
  • v0.2.1(Jun 13, 2023)

    • Archetypes now have exposed const functions to get each of their component IDs in the form of get_id_component_name.
    • This change also suppresses a warning on ecs_world about some functions names not being snake_case.
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jun 10, 2023)

    • Adds support for archetypes with Vec-like dynamic storage capacity. This can be used by setting the keyword dyn as the capacity value in the ecs_archetype! declaration. Worlds generated by ecs_world! now have a with_capacity function with arguments for each dynamic archetype to pre-allocate storage.
      • Fixed-capacity archetypes won't have arguments in with_capacity -- they are always allocated to their full fixed capacity on world creation.
    • Adds an Entity<_> pseudo-parameter to queries. This will match any archetype like EntityAny, but will yield a typed Entity<A> for the currently-matched archetype in the query body.
    • Adds a new 32_components crate feature to go up to 32 maximum components in a single archetype. Enabling this feature may impact compile times.
    Source code(tar.gz)
    Source code(zip)
Owner
I am a meat popsicle.
null
Entity Component System focused on usability and speed.

Shipyard โš“ Shipyard is an Entity Component System focused on usability and speed. If you have any question or want to follow the development more clos

Dylan Ancel 524 Jan 1, 2023
A performant, small and versatile entity component system written in Rust

A performant, zero-dependency ECS library with a nice API written in Rust. Usage # Cargo.toml [dependecies] kiwi-ecs = "1.3" // lib.rs use kiwi_ecs::

Jonas Everaert 9 Nov 18, 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
Rust bindings for entity-gym.

EntityGym for Rust EntityGym is a Python library that defines a novel entity-based abstraction for reinforcement learning environments which enables h

null 18 Apr 15, 2023
Pure and simple Vulkan bindings generated from Vulkan-Headers!

mira Pure and simple Vulkan bindings generated from Vulkan-Headers! Mira provides a simple and straightforward way to interact with Vulkan. Everything

maresia 3 Mar 3, 2022
A safe, fast and cross-platform 2D component-based game framework written in rust

shura shura is a safe, fast and cross-platform 2D component-based game framework written in rust. shura helps you to manage big games with a component

Andri 28 Jan 17, 2023
A rollback library that buffers component state. Useful for netcode.

bevy_timewarp Buffer and rollback to states up to a few frames ago, for rollback networking. Doesn't do any networking, just concerned with buffering

Richard Jones 7 Sep 4, 2023
A nine slice/patch plugin for bevy ui nodes as single component using a fragment shader.

Bevy nine slice/patch Material Plugin Quick and easy auto-scaling nine slice/patch material for bevy ui nodes implemented as Fragment Shader. Features

Lorenz 13 Dec 14, 2023
a prototype crate for creating modular and performant 3D CPU particle systems, inspired by Unity's Shuriken Particle System.

bevy_prototype_particles This is a prototype crate for creating modular and performant 3D CPU particle systems, inspired by Unity's Shuriken Particle

James Liu 28 Sep 12, 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
Hanabi โ€” a particle system plugin for the Bevy game engine.

Hanabi โ€” a particle system plugin for the Bevy game engine

Jerome Humbert 256 Dec 30, 2022
An atomic save/load system for Bevy Game Engine.

โ˜ข๏ธ Bevy Atomic Save An atomic save/load system for Bevy. Features Save and load a World into a RON file on disk Control which entities should particip

null 11 Jan 28, 2023
Action-based animation system for Bevy.

bevy_action_animation Action-based animation system for Bevy. Introduction This plugin provides users of the Bevy game engine with an action/trigger-b

undersquire 5 Apr 15, 2023
Simple action system for Bevy.

bevy_action Simple action system for Bevy. Introduction This plugin exists mainly to facilitate a common action system for other plugins to hook in to

undersquire 4 Apr 15, 2023
A light-weight Anchor-Offset based 2D sprite rendering system for the bevy engine.

Bevy AoUI A light-weight anchor-offset based 2D sprite layout system for the bevy engine. Bevy AoUI provides a light-weight rectangular anchor-offset

Mincong Lu 4 Nov 22, 2023
๐ŸŽ† CPU-driven, batch-rendered particle system for the Bevy game engine.

Bevy Firework ?? Bevy firework is a particle system plugin where particles are simulated on the CPU and use GPU batching for rendering. This allows ea

Manuel Brea Carreras 24 Mar 12, 2024
An extendable system made up of autonomous execution services known as nodes organized in a tree of processes. Inspired by Godot!

NodeTree NodeTree is a framework to create large scalable programs and games through a tree of processes. Each process is fully autonomous and is capa

LunaticWyrm 3 Apr 10, 2024
A simple entity-component-system crate for rust with serialization support

Gallium A simple entity-component-system crate for rust with serialization support Usage You can include the library using carge: [dependencies] galli

null 7 Aug 31, 2021
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
Entity Component System focused on usability and speed.

Shipyard โš“ Shipyard is an Entity Component System focused on usability and speed. If you have any question or want to follow the development more clos

Dylan Ancel 524 Jan 1, 2023