Crate lluvia

Crate lluvia 

Source
Expand description

Lluvia - A stripped down Entity Component System that allows for no-nonsense data storage in finite time.

This library lets you quickly throw together large collections of objects with varying lifetimes into one ECS. You specify the Components, create any number of reference counted Entity objects, and when an Entity goes out of scope its data will be automatically dropped as well. You can even store Entity objects as components of other entities, and everything will get dropped at once when the root Entity goes out of scope.

What sets this ECS apart is that it is very fast, very small in scope, and has a very small footprint. The implementation is ~1000 lines, and almost all operations run in O(1) time. There is no archetyping, there is no rayon integration, there is no advanced iterator pattern, and there are no dependencies. Emphasis is placed on minimizing complexity and avoiding scanning or re-organizing data, as Lluvia was designed to be the data engine for low-latency graphics programs.

Lluvia does support multi-threaded access. Entity is internally an Arc<usize>, and each Component is a data table wrapped in a RwLock. Accessing a piece of data involves going through the overhead of unlocking the Component table, but data access is immediate. calling the get and get_mut methods will return a TableRef, which internally holds the RwLock open for as long as the reference is active.

The two main gotcha’s of using Lluvia are being aware of the locking behavior from holding open references to component values, and preventing circular references from placing Entitys inside of Components. All data in Component tables is not dropped until the owning Entity is dropped, and placing two Entitys in each other’s Components causes that to never happen. As long as you are aware of these you can get decent performance and never leak memory.

Lluvia begins with creating an Instance object. This will track the validity of Entity objects in the system, and will hold references to data tables used for storage.

The Instance can then be used to add Component tables. The Component allows for getting and setting components for each Entity.

§Basic Usage

Basic usage looks like:

use lluvia as ll;
// Create the ECS holder
let mut inst = ll::Instance::new();
// Make a new entity
let entity = inst.add_entity();

// Now add our component. This will be a string, but
// we don't have to specify that for now
let mut c = inst.add_component();

// Before querying the value, we first need to set a valid value
// for this component. Afterwards, we can get it and check that
// it is unchanged.
c.set(&entity, "Hola Lluvia");
let data_ref = c.get(&entity).unwrap();
assert_eq!(*data_ref, "Hola Lluvia");

§Sparse vs Non-Sparse Components

Most entities may not have values for every Component defined in the system. In this case it doesn’t make sense to allocate an entire gigantic backing array for only 10% of the entities to be defined. For this reason the default component type in Lluvia is “Sparse”. Sparse components are non-contiguous and will only allocate “blocks” of the backing store to service Entity usage. If only a few entities set values for that component, only a few blocks are allocated.

Lluvia also handles the opposite scenario. Sometimes you really do need a contiguous array of data, and that is what the “non-sparse” component type is for. For this component type you must provide a default value and the backing array may waste memory, but it allows you to access the raw backing array if needed. Non-Sparse components are exceptionally useful for integrating with other libraries, for example keeping a list of window positions and initializing OpenGL vertex arrays from the raw backing store without having to replicate it.

§Snapshots

Snapshots are another advanced feature which allow you to update many Entity values and then apply all the changes in one commit. Snapshots are a type of Component, and only apply to one Sparse Component.

Structs§

ComponentIterator
ComponentList
EntityInternal
Instance
An Entity component system.
InstanceInternal
RawComponent
A Component holding values for each Entity
SliceContainer
A continuous non-space slice container
SliceRef
Helper struct for a slice
Snapshot
Snapshot Component
Table
TableInternal
A table containing a series of optional values.
TableRef
TableRefMut
VecContainer
Our basic vector storage
VecContainerIter

Traits§

Container
The storage backend for a particular table

Type Aliases§

Component
General Purpose Component
Entity
An abstract Entity
NonSparseComponent
Component with non-sparse data allocation