DeltaECS.Systems
0.0.47
See the version list below for details.
dotnet add package DeltaECS.Systems --version 0.0.47
NuGet\Install-Package DeltaECS.Systems -Version 0.0.47
<PackageReference Include="DeltaECS.Systems" Version="0.0.47" />
<PackageVersion Include="DeltaECS.Systems" Version="0.0.47" />
<PackageReference Include="DeltaECS.Systems" />
paket add DeltaECS.Systems --version 0.0.47
#r "nuget: DeltaECS.Systems, 0.0.47"
#:package DeltaECS.Systems@0.0.47
#addin nuget:?package=DeltaECS.Systems&version=0.0.47
#tool nuget:?package=DeltaECS.Systems&version=0.0.47
DeltaECS.Systems
DeltaECS.Systems runs world-bound systems in deterministic dependency
batches. Systems that access different component ids can run together. Systems
that write the same component can also run together when their query scopes
match disjoint archetypes; structural and unknown world access forms an
exclusive phase.
The package contains the runtime contract and scheduler. When a system is
declared as a top-level partial class, the DeltaECS generator collects its
generated API calls and supplies the Access property automatically. Typed
ForEach calls that use a query stored in a readonly field keep their
component accesses scoped to that query. The scheduler compares the queries'
matching archetypes when it builds the schedule. Keep an explicit Access
property when access is dynamic or comes from an external source. The generator
treats explicit ComponentId selectors and calls outside the generated API as
unknown access; declare their actual component ids and query scopes explicitly
if you want the scheduler to distinguish those accesses.
Iteration calls return reusable deferred operations. Create one once and call
Invoke() from each system tick so the query plan and generated route stay
prepared between ticks.
using Delta.ECS;
using Delta.ECS.Systems;
using var world = new World();
world.Layouts.Register<Velocity>(new SchemaId(1));
world.Layouts.Register<Position>(new SchemaId(2));
Query movementQuery = world.WhereAll<Position, Velocity>();
Entity mover = world.Create<Position>();
world.Add(mover, new Velocity());
using var scheduler = new SystemScheduler(world);
var movement = new MovementSystem(movementQuery) { World = world };
scheduler.Add(movement);
scheduler.Tick();
public partial class MovementSystem : ISystem
{
private readonly Query _query;
private IOperation? _operation;
public World World { get; init; } = null!;
public MovementSystem(Query query) => _query = query;
public void Tick()
{
_operation ??= World.ForEach(in _query,
static (ref Position p, in Velocity v) => p.X += v.X);
_operation.Invoke();
}
}
public struct Position { public float X; }
public struct Velocity { public float X; }
SystemAccess uses the ComponentId values registered in the system's world.
Adds, Removes, entity creation/destruction, unknown access and nested use of
the DeltaECS parallel executor are exclusive to keep immediate world mutation
safe. The scheduler compiles its graph when systems are added or removed and
reuses the resulting batches on subsequent ticks when dependency-aware
scheduling is enabled. If a system creates an archetype that changes a query's
matching set, the scheduler runs the rest of that tick serially and rebuilds
the optimized schedule on the next tick.
For systems with an explicit Access property, use SystemQueryAccess to
declare component ids within a query scope. This lets the scheduler run two
systems that write the same component together when their queries match
different archetypes:
public SystemAccess Access => new(
queryAccesses: new[]
{
new SystemQueryAccess(
in _query,
writes: stackalloc ComponentId[] { _positionId })
},
readsTopology: true);
Unscoped reads, writes and stamp reads remain world-wide and conflict with
the same component in any query scope. Query filters over overlay tags do not
separate archetypes, so they remain conservative when both queries can visit
the same archetype.
Use an open generic functor in a system
Open generic functors can select their closed type with registered component
ids. This is useful for reusable operations such as copying a component into a
matching History<T> row. Register the generic component once, then call the
generated functor overload from Tick:
using Delta.ECS;
using Delta.ECS.Systems;
using var world = new World();
ComponentId positionId = world.Layouts.Register<Position>(new SchemaId(10));
ComponentId historyId = world.Layouts.Register(typeof(History<>), positionId, new SchemaId(11));
Entity entity = world.Create(positionId, historyId);
world.GetRef<Position>(entity, positionId).X = 4f;
Query query = world.WhereAll(positionId, historyId);
using var scheduler = new SystemScheduler(world);
scheduler.Add(new CaptureHistorySystem(world, query, positionId, historyId));
scheduler.Tick();
public struct Position { public float X; }
public struct CaptureHistory<T> : IForEach
{
public void Invoke(ref History<T> history, in T value) => history.Value = value;
}
public struct History<T> { public T Value; }
public sealed class CaptureHistorySystem : ISystem
{
private readonly Query _query;
private readonly ComponentId _positionId;
private readonly SystemAccess _access;
private IOperation? _captureOperation;
public CaptureHistorySystem(World world, Query query, ComponentId positionId, ComponentId historyId)
{
World = world;
_query = query;
_positionId = positionId;
_access = new SystemAccess(
queryAccesses: new[]
{
new SystemQueryAccess(
in query,
reads: stackalloc ComponentId[] { positionId },
writes: stackalloc ComponentId[] { historyId })
},
readsTopology: true);
}
public World World { get; init; }
public SystemAccess Access => _access;
public void Tick()
{
_captureOperation ??= World.ForEach(in _query, _positionId, typeof(CaptureHistory<>));
_captureOperation.Invoke();
}
}
The open functor API uses the generator package and works inside scheduled
systems like the typed ForEach forms. Because its ComponentId arguments
select generic types at runtime, automatic access analysis cannot safely infer
the selected rows. Declare SystemAccess explicitly with the corresponding
IDs when the scheduler may run this system alongside independent systems; if
access metadata is generated, this call is conservatively treated as unknown
and runs in an exclusive phase. SystemAccess accepts explicit
ReadOnlySpan<ComponentId> lists and copies them when constructed.
To run every system sequentially in registration order, disable schedule optimization:
using var scheduler = new SystemScheduler(world, optimizeSchedule: false);
Linear mode does not inspect system access metadata or create scheduler worker
threads. WorkerCount is 1 in this mode.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.50 | 0 | 10/11/2026 |
| 0.0.49 | 0 | 10/11/2026 |
| 0.0.48 | 29 | 10/10/2026 |
| 0.0.47 | 37 | 10/10/2026 |
| 0.0.46 | 46 | 10/9/2026 |
| 0.0.45 | 44 | 10/9/2026 |
| 0.0.44 | 39 | 10/9/2026 |
| 0.0.43 | 49 | 10/8/2026 |
| 0.0.42 | 46 | 10/8/2026 |
| 0.0.41 | 72 | 10/5/2026 |
| 0.0.40 | 87 | 10/4/2026 |
| 0.0.39 | 96 | 10/4/2026 |
| 0.0.38 | 91 | 10/3/2026 |
| 0.0.37 | 89 | 10/3/2026 |
| 0.0.36 | 86 | 10/2/2026 |
| 0.0.35 | 92 | 10/2/2026 |
| 0.0.34 | 84 | 10/2/2026 |
| 0.0.33 | 89 | 9/30/2026 |
| 0.0.32 | 103 | 9/22/2026 |