It's like a nice pair of specs, except much more uncomfortable and inconvenient
This crate is a heavily modified, stripped down version of the specs ECS
library. It is less of a framework for doing a specific style of ECS as easily
as possible and more of a DIY library for doing ECS that allows you to adapt it
to your own needs.
goggles may not be as straightforward to use as other ECS libraries, if
something like specs or legion already fits your needs then you should
probably use it.
The basic data structure design is nearly exactly the same as specs, it uses
the same basic data structures that specs does to store components and do
joins. Just like specs, it stores components in separate storages and records
their presence with a hierarchal bitset type from hibitset, and uses that same
hierarchal bitset to do joins.
On top of this, however, is a more minimal, piecemeal API than even what specs
provides. It is somewhat opinionated in what it removes: everything that I felt
was extraneous or magical, and only tries to handle what is very hard to do
otherwise or is unsafe, and mostly leaves the easier parts to the user to design
themselves.
The library contains a set of more or less independent parts, you can stop at whatever level of abstraction is appropriate:
-
The
par_seqmodule is a completely independent way of setting up and running generic parallel and sequential systems. It can be compared toshred, but it contains a much more genericSystemtrait, and does not include functionality for locking and reading resources. It simply allows you to define a set of resources inSystems, combine those systems usingParandSeq, make sure that the result doesn't have resource conflicts, then run it. -
The
system_datamodule defines aSystemDatatrait for statically defined resources for thepar_seqmodule, and provides aSystemDataimplementation for tuples ofSystemData. -
The
resource_setmodule defines aResourceSetwhich is similar to anAnyMapwith values stored in aRwLock. Unlike a set ofRwLocks though it doesn't ever block, instead it simply panics when aliasing rules are violated. It is designed so that you can use thepar_seqmodule to build systems that operate over the defined resources. It also includes convenient types for defining and requesting read / write handles to resources which implementSystemData, so they can be used in tuples like(Read<ResourceA>, Write<ResourceB>). It is very similar to theWorldtype inshred. -
The
joinmodule contains a definition for aJointrait for data stored byu32indexes and tracked by aBitSetwith fast, unsafe access. It provides the ability to iterate safely over aJoinsequentially and in parallel, and provides means to join multipleJoininstances together. It is similar to theJointrait inspecs, but redesigned for a bit more safety. -
The
storagemodule contains theRawStoragetrait as well as 3 useful implementations:VecStorage,DenseVecStorage, andHashMapStorage. This is an abstract, unsafe trait for storing values associated with indexes. It is extremely similar to the equivalent functionality inspecs. -
The
trackedmodule contains aRawStoragewrapper that keeps track of component changes. Unlikespecs, this is pretty minimal and only optionally sets a flag in anAtomicBitSeton mutable access. -
The
maskedmodule contains theMaskedStoragestruct which safely wraps aRawStoragetogether with aBitSetto keep track of which components are present.MaskedStorageis also join-able. -
The
entitymodule contains an atomic generational index allocator that also useshibitsettypes to track which indexes are alive. It also allows you to join on the allocator to output liveEntity's. -
The
worldmodule ties all of this together into something with a recognizable ECS API. If you want to understand how this works, or want to build your own abstractions instead of what's provided in this module, start here. Many of the changes tospecshave been made so that theworldmodule contains only safe code.
Here is an incomplete list of the important things removed from shred and
specs:
-
No automatic setup, you must insert / register all resource and component types.
-
No saving / loading support, you should handle this yourself.
-
No automatic system scheduling / dispatching / batching, you must design your execution strategy yourself with
parandseqand then it can be checked for conflicts at startup. -
No lazy updates, you probably want to handle this specifically for your application. There is not always a universally best way to do this.
And here is an incomplete list of the important changes from specs for
functionality that is present in both this library and specs:
-
Does not require T: Sync for mutable access to resources / components (only requires T: Send).
-
Redesigned Join trait for soundness and a bit more safety. There is an additional
IntoJointrait that allows you to participate in the convenient tuple join syntax without having to write unsafe code. -
Component
RawStorageimpls requireUnsafeCellfor soundness -
Component
RawStorageimpls always assume disjoint storages that are safe to iterate over in parallel. -
Simplified component modification tracking.
-
Removes some features of
specswhich are known to be unsound such as index component access through iterators. -
The individual parts of the library go out of their way to be more loosely coupled, sometimes at the cost of extra code or user convenience.
-
Nearly all of the internals are public in case you need to build a different abstraction.
I'd been working on a project for a while that used specs proper, and I kept
needing to redesign small pieces of it. Much to specs credit, it is already a
library that you can use in a very piecemeal, independent way, and that's
exactly what I did. At some point I looked up and realized that I only used
maybe a core 20% of what specs provided, and that was around the time that I
started needing to use messy extension traits to go further. I decided to
re-implement the core part of specs that I still used, package it up with some
of the other things I made that were more flexible (but arguably harder to use)
than what shred / specs offered, and put it here.
There's a good chance you don't need or want this crate. Still, if you find
yourself needing to break up specs into its constituent parts and build your
own APIs on top of it, this is here if you need it.
This project is directly derived from specs so most of the credit goes to
specs' creators. Anything at all in this crate that is especially clever is
probably theirs.
This is derived from specs, so similarly it is dual-licensed under Apache-2.0
/ MIT.