Stream Views
... where the real work gets done!
The magic goggles that turn your Queries into super awesome rainbow roads!
Stream<C1>
Stream<C1,C2>
Stream<C1,C2,C3>
Stream<C1,C2,C3,C4>
Stream<C1,C2,C3,C4,C5>
Entities in Queries (including Worlds) and their Components can be read and modified using the extremely light-weight Stream Views. Dubbed Stream<>
in fennecs code and loosely related to zip iterators, their inner workings are tailored specifically to high-performance Entity-Component System use cases.
STREAM VIEWS WILL LET YOU ...
... call a set of Runners, passing
Delegate Actions
where you read and write the components in your own custom code. Your action will be run in heavily optimized, super-tight, unrolled loops; most which can even be run in parallel.... enumerate each Entity in its underlying Query, together with each Component matching the View's Stream Types, as
ValueTuple(Entity, C1, C2, ...)
. This is awesome for Unit tests and easy inspection of your data, and prototyping behaviours using LINQ.... give you safe (and
unsafe
) access to all the Components of all the Entities matched by the Query - as contiguous blocks ofMemory<C>
, for you do anything with that you can imagine.
How to obtain a Stream View
You can get a Stream View from a Query, or from a World.
var stream = world.Query<Position, Velocity>().Not<Boring>().Stream();
// This is the tried-and-true way of getting a Stream View from a Query,
// similar to how it was in fennecs 0.4.x but modernized by splitting
// the resolution of the Query from the matching from the Stream's
// iteration and execution. Queries compile fast and are cached!
// Stream<>.Query provides you access to the underlying Query just in case.
var stream = world.Query().Has<Position>().Has<Velocity>().Not<Boring>().Compile();
// Query with arbitrary complexity of Expressions, and any number of Streams
var positions = query.Stream<Position>();
var velocities = query.Stream<Velocity>();
var both = query.Stream<Position, Velocity>();
var swap = query.Stream<Velocity, Position>();
var query = world.Stream<Position, Velocity>();
// The super-foxy minimal boilerplate shorthand version!
// Disadvantage: Only up to 5 simple Has<T> Query Expressions.
// Internally also compiles a (new) cached Query and returns
// a view to *that*, because even though a World *is* a Query, it
// can get too large to filter + iterate compared to simple Queries.
Internals
Each Stream has an underlying Query, and any number of Streams can be created as views into the same Query. When it comes to processing data, Stream Views are practically always your first go-to solution in fennecs.
You can get so much work done with these bad bois! (slaps roof)
Stream Types
The Type parameters, C1, C2, C3, C4, C5
are also known as the Stream Types. These are the types of Components that a specific Stream's Runners (e.g. For
, Job
and Raw
) can supply to your code.
Runners - Executing Workloads
Each Stream View offers a set of Runners to execute code in batches or parallelized on all Entities in its Query - For
, Job
, and Raw
, or the ValueTuples
in the Stream
itself. Their order is determined from your declaration of the Stream<>
.
You then pass a delegate (anonymous lambda/delegate or named method, static or instance) to one of three functions, and your code gets run for each Entity. Easy as that for starters, but with some cool twists later!
Here's a mnemonic cheat sheet, follow the links in the paragraph headlines for details.
THE CLASSIC
For
/ For<U>
One work item at a time. Call a ComponentAction
or delegate for each Entity in a Query, providing the Components that match the Stream Types as ref
to the code.
THE WORKHORSE
Job
/ Job<U>
One work item at a time, multi-threaded. Takes a ComponentAction
delegate and instantly schedules and executes the workload split into chunks, calling it many times in parallel across CPU cores.
THE FREIGHT TRAIN
Raw
/ Raw<U>
All work items at once, as contiguous memory. Using a MemoryAction
, delivers the entire stream data of each Archetype directly into your fox delegate in one Memory<T>
per Stream Type.