### Quickstart: Fennecs ECS Setup and Usage Source: https://github.com/outfox/fennecs/blob/main/nuget/nuget.md Demonstrates how to add the fennecs package, create a world, spawn an entity with components, and iterate over entities using a query stream. The `World` implements `IDisposable` and should be disposed when no longer needed. Use `Job` instead of `For` for parallel processing. ```csharp // Declare a Component record. (we can also use most existing value & reference types) record struct Velocity(Vector3 Value); // Create a world. (fyi, World implements IDisposable) var world = new fennecs.World(); // Spawn an entity into the world with a choice of Components. (or add/remove them later) var entity = world.Spawn().Add(); // Queries are cached & we use ultra-lightweight Stream Views to feed data to our code! var stream = world.Query().Stream(); // Run code on all entities in the query. (exchange 'For' with 'Job' for parallel processing) stream.For( uniform: DeltaTime * 9.81f * Vector3.UnitZ, static (Vector3 uniform, ref Velocity velocity) => { velocity.Value -= uniform; } ); ``` -------------------------------- ### Basic Fennecs ECS Setup and Usage in C# Source: https://github.com/outfox/fennecs/blob/main/README.md Demonstrates the fundamental steps to set up and use the Fennecs ECS. This includes defining a component, creating a world, spawning an entity with components, and querying entities to modify their components. Use this for initial integration and understanding core mechanics. ```csharp record struct Velocity(Vector3 Value); var world = new fennecs.World(); var entity = world.Spawn().Add(); var stream = world.Query().Stream(); stream.For( uniform: DeltaTime * 9.81f * Vector3.UnitZ, action: (Vector3 uniform, ref Velocity velocity) => { velocity.Value -= uniform; } ); ``` -------------------------------- ### Component CRUD and Access on Entity in fennecs Source: https://context7.com/outfox/fennecs/llms.txt Demonstrates adding, removing, and checking for components on a specific entity using the `Entity` struct's fluent interface. Shows how to read component values and get mutable references. ```csharp using fennecs; record struct Position(float X, float Y); record struct Velocity(float X, float Y); record struct Name(string Value); struct Stunned; using var world = new World(); var hero = world.Spawn() .Add(new Position(5, 10)) .Add(new Velocity(0, 0)) .Add(new Name("Aria")); // Runtime add/remove hero.Add(); Console.WriteLine(hero.Has()); // true hero.Remove(); Console.WriteLine(hero.Has()); // false // Read a component value (copies the struct) var pos = hero.Get(Match.Plain); // returns Position[] Console.WriteLine(pos[0]); // Position { X = 5, Y = 10 } // Get a direct reference (mutable, valid until next structural change) ref var vel = ref hero.Ref(); vel = new Velocity(3, 4); // Dump all components for debugging Console.WriteLine(hero.Dump()); ``` -------------------------------- ### Despawn Entities with Specific Component using World.DespawnAllWith Source: https://context7.com/outfox/fennecs/llms.txt Use this method to remove all entities that have a particular component. Ensure the `fennecs` library is imported. This example demonstrates despawning entities with the `Enemy` component. ```csharp using fennecs; struct Enemy; struct Boss; using var world = new World(); world.Entity().Add().Spawn(200); world.Entity().Add().Add().Spawn(5); world.Entity().Spawn(10); // civilians Console.WriteLine(world.Count); // 215 // Despawn all entities that have the Enemy component world.DespawnAllWith(); Console.WriteLine(world.Count); // 10 — only civilians survive ``` -------------------------------- ### Entity.Ensure — Get or Create Component Reference Source: https://context7.com/outfox/fennecs/llms.txt Use Ensure to get a reference to a component, adding it with a default value if it doesn't exist. This is useful for patterns like accumulators or counters. ```csharp using fennecs; record struct HitCount(int Value); record struct Health(int Value); using var world = new World(); var entity = world.Spawn(); // Creates HitCount(0) if missing, returns ref to it ref var hits = ref entity.Ensure(); hits.Value++; // 1 // Using a custom default ref var hp = ref entity.Ensure(new Health(100)); hp.Value -= 10; // 90 Console.WriteLine(entity.Get(Match.Plain)[0]); // HitCount { Value = 1 } Console.WriteLine(entity.Get(Match.Plain)[0]); // Health { Value = 90 } ``` -------------------------------- ### World Creation and Management Source: https://context7.com/outfox/fennecs/llms.txt Demonstrates how to create a new World instance, optionally providing an initial capacity hint and setting its name. It also shows how to access the entity count, inspect world details, and manually trigger garbage collection to remove empty archetypes. Entities can be enumerated using LINQ or a foreach loop. ```APIDOC ## World `World` is the root container. It owns all entities, archetypes, and compiled queries. It implements `IDisposable` and `IEnumerable`. Create one per simulation; multiple independent worlds are supported. ```csharp using fennecs; // Create a world with optional initial capacity hint using var world = new World(initialCapacity: 4096) { Name = "GameWorld", // GC behaviour can be customised (default: ManualOnly + compact stagnant archetypes) GCBehaviour = World.GCAction.DefaultBeta, }; Console.WriteLine(world.Count); // 0 entities Console.WriteLine(world); // "World:\n 0 Archetypes\n 0 Entities\n 0 Queries\n..." // Run manual GC (removes empty archetypes) world.GC(); // Enumerate all living entities via LINQ or foreach foreach (var entity in world) Console.WriteLine(entity); ``` ``` -------------------------------- ### Create and Manage World in fennecs Source: https://context7.com/outfox/fennecs/llms.txt Demonstrates creating a World instance with an optional capacity hint and custom name. Shows how to manually trigger garbage collection for archetypes and enumerate entities. ```csharp using fennecs; // Create a world with optional initial capacity hint using var world = new World(initialCapacity: 4096) { Name = "GameWorld", // GC behaviour can be customised (default: ManualOnly + compact stagnant archetypes) GCBehaviour = World.GCAction.DefaultBeta, }; Console.WriteLine(world.Count); // 0 entities Console.WriteLine(world); // "World:\n 0 Archetypes\n 0 Entities\n 0 Queries\n..." // Run manual GC (removes empty archetypes) world.GC(); // Enumerate all living entities via LINQ or foreach foreach (var entity in world) Console.WriteLine(entity); ``` -------------------------------- ### Spawn Single Entity with Components in fennecs Source: https://context7.com/outfox/fennecs/llms.txt Shows how to spawn a single entity using the `Spawn()` method and chain `Add()` calls to attach components. Demonstrates checking entity status and despawning. ```csharp using fennecs; record struct Position(float X, float Y); record struct Velocity(float X, float Y); struct Frozen; // zero-size tag component using var world = new World(); // Spawn one entity with components var player = world.Spawn() .Add(new Position(0, 0)) .Add(new Velocity(1, 0)) .Add(); // uses default constructor Console.WriteLine(player.Alive); // true Console.WriteLine(player.Has()); // true Console.WriteLine(player.Has()); // true // Despawn an entity player.Despawn(); Console.WriteLine(player.Alive); // false ``` -------------------------------- ### Bulk Spawn Entities with fennecs EntitySpawner Source: https://context7.com/outfox/fennecs/llms.txt Illustrates using `world.Entity()` to create an `EntitySpawner` for efficiently spawning multiple identical entities in a single call, populating a specific archetype. ```csharp using fennecs; record struct Health(int Value); record struct Team(string Name); using var world = new World(); // Spawn 100 enemies with two components world.Entity() .Add(new Health(100)) .Add(new Team("Red")) .Spawn(100); // Spawn 50 allies with a different team value world.Entity() .Add(new Health(80)) .Add(new Team("Blue")) .Spawn(50); Console.WriteLine(world.Count); // 150 ``` -------------------------------- ### World.Spawn() - Spawn Single Entity Source: https://context7.com/outfox/fennecs/llms.txt Spawns a single entity and returns an `Entity` builder struct. This allows for method chaining to add components and relations before the entity is fully registered in the world. The entity becomes alive immediately upon the `Spawn()` call. Entities can also be despawned using the `Despawn()` method. ```APIDOC ## World.Spawn() — Spawn a single entity (fluent builder) Returns an `Entity` builder struct. Use method chaining to attach components before the entity is live in the world. The entity is immediately alive upon the `Spawn()` call. ```csharp using fennecs; record struct Position(float X, float Y); record struct Velocity(float X, float Y); struct Frozen; // zero-size tag component using var world = new World(); // Spawn one entity with components var player = world.Spawn() .Add(new Position(0, 0)) .Add(new Velocity(1, 0)) .Add(); // uses default constructor Console.WriteLine(player.Alive); // true Console.WriteLine(player.Has()); // true Console.WriteLine(player.Has()); // true // Despawn an entity player.Despawn(); Console.WriteLine(player.Alive); // false ``` ``` -------------------------------- ### Benchmark: CreateEntityWithThreeComponents Source: https://github.com/outfox/fennecs/blob/main/README.md This benchmark measures the performance of creating entities with three components. The results are presented in a table comparing fennecs against other ECS libraries. ```text // Benchmark Process Environment Information: // BenchmarkDotNet v0.13.12 // Runtime=.NET 8.0.5 (8.0.524.21615), X64 RyuJIT AVX2 // GC=Concurrent Workstation // HardwareIntrinsics=AVX2,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256 // Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3) // [EntityCount=100_000] ``` ```text | ECS & Method | Duration
**(less=better)** | | -------| -------:| | 🦊 fennecs | 1.458 ms | | FrifloEngineEcs | 1.926 ms | | LeopotamEcs | 4.991 ms | | LeopotamEcsLite | 4.994 ms | | Arch | 7.811 ms | | FlecsNet | 17.838 ms | | DefaultEcs | 19.818 ms | | TinyEcs | 24.458 ms | | HypEcs | 25.215 ms | | MonoGameExtended | 27.562 ms | | Myriad | 28.249 ms | | SveltoECS | 52.311 ms | | Morpeh_Stash | 64.930 ms | | RelEcs | 65.023 ms | | Morpeh_Direct | 131.363 ms | ``` -------------------------------- ### World.Entity() - Bulk Spawn Entities Source: https://context7.com/outfox/fennecs/llms.txt Provides an `EntitySpawner` fluent builder via `world.Entity()` to efficiently spawn multiple identical entities in a single operation. This is useful for populating a single archetype with many entities at once. Call `.Spawn(count)` to materialize the specified number of entities. ```APIDOC ## World.Entity() — Bulk-spawn pre-configured entities (EntitySpawner) `EntitySpawner` is a fluent builder returned by `world.Entity()` that spawns many identical entities in one call, populating a single archetype efficiently. Call `.Spawn(count)` to materialise the entities. ```csharp using fennecs; record struct Health(int Value); record struct Team(string Name); using var world = new World(); // Spawn 100 enemies with two components world.Entity() .Add(new Health(100)) .Add(new Team("Red")) .Spawn(100); // Spawn 50 allies with a different team value world.Entity() .Add(new Health(80)) .Add(new Team("Blue")) .Spawn(50); Console.WriteLine(world.Count); // 150 ``` ``` -------------------------------- ### Benchmark: SystemWithThreeComponents Source: https://github.com/outfox/fennecs/blob/main/README.md This benchmark evaluates the performance of processing systems with three components. It compares various fennecs implementations (AVX2, SSE2, Raw, For, Job) against other ECS libraries, noting optimization details. ```text // Benchmark Process Environment Information: // BenchmarkDotNet v0.13.12 // Runtime=.NET 8.0.5 (8.0.524.21615), X64 RyuJIT AVX2 // GC=Concurrent Workstation // HardwareIntrinsics=AVX2,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256 // Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3) // [EntityCount=100_000, EntityPadding=10] ``` ```text | ECS & Method | Duration
**(less=better)** | Comment | | ---------- | ----------:| --------- | | 🦊 fennecs(AVX2) | 10.43 µs | optimized Stream<>.Raw using AVX2 Intrinsics | | 🦊 fennecs(SSE2) | 11.41 µs | optimized Stream<>.Raw using SSE2 Intrinsics | | FrifloEngineEcs_MultiThread | 13.45 µs | | | FrifloEngineEcs_SIMD_MonoThread | 16.92 µs | | | TinyEcs_EachJob | 20.51 µs | | | Myriad_MultiThreadChunk | 20.73 µs | | | TinyEcs_Each | 40.84 µs | | | FrifloEngineEcs_MonoThread | 43.41 µs | | | HypEcs_MonoThread | 43.86 µs | | | 🦊 fennecs(Raw) | 46.36 µs | straightforward loop over Stream<>.Raw | | HypEcs_MultiThread | 46.80 µs | | | Myriad_SingleThreadChunk | 48.56 µs | | | Arch_MonoThread | 51.08 µs | | | Myriad_SingleThread | 55.65 µs | | | 🦊 fennecs(For) | 56.32 µs | your typical bread & butter **fenn**ecs workload | | Arch_MultiThread | 59.84 µs | | | FlecsNet_Iter | 77.47 µs | | | 🦊 fennecs(Job) | 97.70 µs | unoptimized in beta, ineffective <1M entities | | DefaultEcs_MultiThread | 102.37 µs | | | Myriad_Delegate | 109.31 µs | | | Arch_MonoThread_SourceGenerated | 134.12 µs | | | DefaultEcs_MonoThread | 142.35 µs | | | LeopotamEcs | 181.76 µs | | | FlecsNet_Each | 212.61 µs | | | LeopotamEcsLite | 230.50 µs | | | Myriad_Enumerable | 245.76 µs | | | RelEcs | 250.93 µs | | | SveltoECS | 322.30 µs | EntityPadding=0, skips benchmark with 10 | | MonoGameExtended | 387.12 µs | | | Morpeh_Stash | 992.62 µs | | | Myriad_MultiThread | 1115.44 µs | | | Morpeh_Direct | 2465.25 µs | | ``` -------------------------------- ### Bulk Query Operations with Batch, Despawn, and Truncate Source: https://context7.com/outfox/fennecs/llms.txt Perform atomic structural mutations on matched entities using `Query.Compile().Batch()`. Efficiently despawn or truncate query results. ```csharp using fennecs; struct Frozen; struct Burning; record struct Health(int Value); using var world = new World(); world.Entity().Add(new Health(100)).Spawn(1000); var healthyQuery = world.Query().Not().Compile(); var frozenQuery = world.Query().Has().Compile(); // Add Frozen to all healthy entities healthyQuery.Add(); Console.WriteLine(frozenQuery.Count); // 1000 // Remove Frozen from all frozenQuery.Remove(); Console.WriteLine(frozenQuery.Count); // 0 // Batch: add Burning and remove Frozen atomically healthyQuery .Batch(Batch.AddConflict.Skip) .Add() .Submit(); // Despawn all Burning entities var burningQuery = world.Query().Has().Compile(); burningQuery.Despawn(); Console.WriteLine(world.Count); // 0 // Respawn 500, then truncate to 100 world.Entity().Add(new Health(100)).Spawn(500); var all = world.Query().Compile(); all.Truncate(100); Console.WriteLine(world.Count); // 100 ``` -------------------------------- ### world.Query() / QueryBuilder Source: https://context7.com/outfox/fennecs/llms.txt `QueryBuilder` is the entry point for building filtered queries. Calling `.Stream()` compiles and caches the query, returning a `Stream` view. Queries are updated automatically when new archetypes are added. ```APIDOC ## world.Query() / QueryBuilder — Compile a cached query `QueryBuilder` is the entry point for building filtered queries. Calling `.Stream()` compiles and caches the query, returning a `Stream` view. Queries are updated automatically when new archetypes are added. ```csharp using fennecs; record struct Position(float X, float Y); record struct Velocity(float X, float Y); struct Frozen; struct Enemy; using var world = new World(); // Simple query: all entities that have Position and Velocity var movers = world.Query().Stream(); // Filtered query: movers that are NOT Frozen and have Enemy tag var activeEnemies = world.Query() .Has() .Not() .Stream(); // Count matched entities Console.WriteLine(movers.Count); Console.WriteLine(activeEnemies.Count); // Compile a plain (non-streaming) query for counting/presence checks var frozenQuery = world.Query().Has().Compile(); Console.WriteLine(frozenQuery.Count); Console.WriteLine(frozenQuery.IsEmpty); // Random access if (!frozenQuery.IsEmpty) { var randomFrozen = frozenQuery.Random(); Console.WriteLine(randomFrozen); } ``` ``` -------------------------------- ### Stream.For Source: https://context7.com/outfox/fennecs/llms.txt `For` is the primary per-entity workload. It iterates all matched archetypes in a single thread, providing `ref` access to each component. Four overloads exist: component-only, entity+component, uniform+component, and uniform+entity+component. ```APIDOC ## Stream.For — Single-threaded component iteration `For` is the primary per-entity workload. It iterates all matched archetypes in a single thread, providing `ref` access to each component. Four overloads exist: component-only, entity+component, uniform+component, and uniform+entity+component. ```csharp using fennecs; using System.Numerics; record struct Velocity(Vector3 Value); record struct Position(Vector3 Value); using var world = new World(); world.Entity().Add(new Position(Vector3.Zero)).Add(new Velocity(Vector3.UnitY)).Spawn(1000); var stream = world.Query().Stream(); float deltaTime = 0.016f; // Component-only action stream.For((ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * deltaTime; }); // With uniform data (avoids closure allocation) stream.For(deltaTime, static (float dt, ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * dt; }); // With entity access stream.For((in Entity e, ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * deltaTime; if (pos.Value.Y > 100f) e.Despawn(); }); // With uniform + entity stream.For(deltaTime, static (float dt, in Entity e, ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * dt; }); ``` ``` -------------------------------- ### Entity-Entity Relations Source: https://context7.com/outfox/fennecs/llms.txt Attach typed components keyed by another entity (target) to establish relations. Supports wildcard queries and cascade-despawn. Use for linking entities, e.g., ownership or alliances. ```csharp using fennecs; struct Owns; struct Ally; record struct Damage(int Value); using var world = new World(); var king = world.Spawn(); var sword = world.Spawn(); var knight = world.Spawn(); // king "Owns" sword (zero-size relation tag) king.Add(sword); // knight is an Ally of king, carrying a Damage value on the relation knight.Add(new Damage(50), king); // Check relation presence Console.WriteLine(king.Has(sword)); // true Console.WriteLine(knight.Has(king)); // true // Wildcard: does knight have ANY Damage relation to any entity? Console.WriteLine(knight.Has(Entity.Any)); // true // Query all entities that own something var owners = world.Query(Entity.Any).Stream(); Console.WriteLine($"Owners: {owners.Count}"); // 1 // When sword despawns, king's Owns relation is automatically removed sword.Despawn(); Console.WriteLine(king.Has(Entity.Any)); // false ``` -------------------------------- ### Linking Entities to Managed Objects with Link Source: https://context7.com/outfox/fennecs/llms.txt Use `Link` to attach managed objects as component targets, grouping entities by shared instances. Query for entities linked to any object or specific instances. ```csharp using fennecs; class Texture { public string Name; public Texture(string n) => Name = n; } record struct RingBearer(string Race); using var world = new World(); var grass = new Texture("grass.png"); var stone = new Texture("stone.png"); // Link multiple entities to the same texture object world.Entity().Add(Link.With(grass)).Spawn(100); world.Entity().Add(Link.With(stone)).Spawn(50); // Query: all entities linked to ANY texture (Link.Any = Match.Object) var allLinked = world.Query(Link.Any).Stream(); Console.WriteLine($"Entities with a texture link: {allLinked.Count}"); // 150 // Query: only entities linked to the specific grass texture var grassEntities = world.Query() .Has(Link.With(grass)) .Stream(); Console.WriteLine($"Grass entities: {grassEntities.Count}"); // 100 // Access the linked object via Ref grassEntities.For((in Entity e, ref Texture tex) => { Console.WriteLine(tex.Name); // "grass.png" }); ``` -------------------------------- ### LINQ Enumeration on Query and Stream Source: https://context7.com/outfox/fennecs/llms.txt Leverage LINQ for querying entities by implementing `IEnumerable` on `Query` and `Stream`. Use within `World.Lock()` for modifications or read-only access. ```csharp using fennecs; record struct Score(int Value); record struct Name(string Value); using var world = new World(); world.Entity().Add(new Score(42)).Add(new Name("Alice")).Spawn(1); world.Entity().Add(new Score(17)).Add(new Name("Bob")).Spawn(1); world.Entity().Add(new Score(99)).Add(new Name("Carol")).Spawn(1); var stream = world.Query().Stream(); // LINQ on Stream yields (Entity, C0) tuples var top = stream .Where(tuple => tuple.Item2.Value > 20) .OrderByDescending(tuple => tuple.Item2.Value) .Select(tuple => tuple.Item1) .ToList(); Console.WriteLine($"Top scorers: {top.Count}"); // 2 // Enumerate all entities via World foreach (var entity in world) Console.WriteLine(entity.Alive); ``` -------------------------------- ### Stream Subset and Exclude Filters Source: https://context7.com/outfox/fennecs/llms.txt Narrow iteration at runtime using Subset and Exclude properties on a Stream without recompiling the query. Uses Comp.Plain for component descriptors. ```csharp using fennecs; struct Lucky; struct Unlucky; record struct Alive(bool Value); using var world = new World(); world.Entity().Add().Spawn(1_000_000); // A compiled query + stream for all Alive entities var population = world.Query().Has().Compile(); var allAlive = population.Stream(); // Narrow to: Unlucky but NOT Lucky — without recompiling the query var doomed = allAlive with { Subset = [Comp.Plain], Exclude = [Comp.Plain], }; Console.WriteLine($"Doomed count: {doomed.Count}"); doomed.Despawn(); Console.WriteLine($"Survivors: {world.Count}"); ``` -------------------------------- ### Deferred Structural Changes with World.Lock Source: https://context7.com/outfox/fennecs/llms.txt Use `World.Lock()` to queue structural changes, applying them atomically when the lock is released. Essential for safe modifications during iteration. ```csharp using fennecs; struct Tagged; record struct Score(int Value); using var world = new World(); world.Entity().Add(new Score(0)).Spawn(100); var query = world.Query().Compile(); // Lock while iterating with LINQ to safely modify world structure using (var worldLock = world.Lock()) { foreach (var entity in query) { if (System.Random.Shared.Next(2) == 0) entity.Add(); // deferred until lock is released } } // ← structural changes applied here var taggedQuery = world.Query().Has().Compile(); Console.WriteLine($"Tagged: {taggedQuery.Count}"); // Nested locks — changes apply only when ALL locks are released using (var outer = world.Lock()) { using (var inner = world.Lock()) { query.Random().Add(); } // still deferred — outer lock still held } // ← now applied ``` -------------------------------- ### world.Query() / QueryBuilder — Compile Cached Queries Source: https://context7.com/outfox/fennecs/llms.txt Build filtered queries using QueryBuilder. Calling .Stream() compiles and caches the query, returning a Stream view. Queries update automatically when new archetypes are added. ```csharp using fennecs; record struct Position(float X, float Y); record struct Velocity(float X, float Y); struct Frozen; struct Enemy; using var world = new World(); // Simple query: all entities that have Position and Velocity var movers = world.Query().Stream(); // Filtered query: movers that are NOT Frozen and have Enemy tag var activeEnemies = world.Query() .Has() .Not() .Stream(); // Count matched entities Console.WriteLine(movers.Count); Console.WriteLine(activeEnemies.Count); // Compile a plain (non-streaming) query for counting/presence checks var frozenQuery = world.Query().Has().Compile(); Console.WriteLine(frozenQuery.Count); Console.WriteLine(frozenQuery.IsEmpty); // Random access if (!frozenQuery.IsEmpty) { var randomFrozen = frozenQuery.Random(); Console.WriteLine(randomFrozen); } ``` -------------------------------- ### Entity Component CRUD Source: https://context7.com/outfox/fennecs/llms.txt Details the `Entity` struct's fluent interface for managing components. It covers adding, removing, checking for the existence of, and retrieving component data for a specific entity. Supports runtime modifications and direct reference access. ```APIDOC ## Entity.Add / Entity.Remove — Component CRUD on a single entity `Entity` is a readonly record struct providing a fluent interface for adding, removing, checking, and reading components. Method chains return `this` for chaining. ```csharp using fennecs; record struct Position(float X, float Y); record struct Velocity(float X, float Y); record struct Name(string Value); struct Stunned; using var world = new World(); var hero = world.Spawn() .Add(new Position(5, 10)) .Add(new Velocity(0, 0)) .Add(new Name("Aria")); // Runtime add/remove hero.Add(); Console.WriteLine(hero.Has()); // true hero.Remove(); Console.WriteLine(hero.Has()); // false // Read a component value (copies the struct) var pos = hero.Get(Match.Plain); // returns Position[] Console.WriteLine(pos[0]); // Position { X = 5, Y = 10 } // Get a direct reference (mutable, valid until next structural change) ref var vel = ref hero.Ref(); vel = new Velocity(3, 4); // Dump all components for debugging Console.WriteLine(hero.Dump()); ``` ``` -------------------------------- ### Entity.Ensure() Source: https://context7.com/outfox/fennecs/llms.txt `Ensure` returns a `ref` to a component, adding it with the given default value if it is not already present. This is ideal for accumulator or counter patterns. ```APIDOC ## Entity.Ensure() — Get-or-create a component reference `Ensure` returns a `ref` to a component, adding it with the given default value if it is not already present. Ideal for accumulator / counter patterns. ```csharp using fennecs; record struct HitCount(int Value); record struct Health(int Value); using var world = new World(); var entity = world.Spawn(); // Creates HitCount(0) if missing, returns ref to it ref var hits = ref entity.Ensure(); hits.Value++; // 1 // Using a custom default ref var hp = ref entity.Ensure(new Health(100)); hp.Value -= 10; // 90 Console.WriteLine(entity.Get(Match.Plain)[0]); // HitCount { Value = 1 } Console.WriteLine(entity.Get(Match.Plain)[0]); // Health { Value = 90 } ``` ``` -------------------------------- ### Stream.Blit: Uniform Value Update Source: https://context7.com/outfox/fennecs/llms.txt Set all instances of a component type to the same value across all matched entities in a single bulk operation. Useful for global updates. ```csharp using fennecs; record struct Health(int Value); record struct Mana(int Value); using var world = new World(); world.Entity().Add(new Health(50)).Add(new Mana(30)).Spawn(10_000); var stream = world.Query().Stream(); // Set all Health to 100 stream.Blit(new Health(100)); // Set all Mana to 50 stream.Blit(new Mana(50)); Console.WriteLine("All entities now have Health(100) and Mana(50)."); ``` -------------------------------- ### Stream.Job Source: https://context7.com/outfox/fennecs/llms.txt `Job` dispatches the workload across .NET ThreadPool workers for parallel processing. Requires no wildcard stream types. Uses the same delegate signatures as `For`. ```APIDOC ## Stream.Job — Parallel component iteration `Job` dispatches the workload across .NET ThreadPool workers for parallel processing. Requires no wildcard stream types. Uses the same delegate signatures as `For`. ```csharp using fennecs; using System.Numerics; record struct Position(Vector3 Value); record struct Velocity(Vector3 Value); using var world = new World(); world.Entity() .Add(new Position(Vector3.Zero)) .Add(new Velocity(Vector3.UnitX)) .Spawn(500_000); var stream = world.Query().Stream(); float deltaTime = 0.016f; // Parallel iteration — safe for independent component writes stream.Job(deltaTime, static (float dt, ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * dt; }); // Parallel with single component var velocities = world.Query().Stream(); stream.Job(static (ref Velocity vel) => { vel.Value *= 0.99f; // drag }); ``` ``` -------------------------------- ### Stream.For — Single-Threaded Component Iteration Source: https://context7.com/outfox/fennecs/llms.txt Use For for per-entity workloads, iterating matched archetypes in a single thread with ref access to components. Four overloads are available for different data access needs. ```csharp using fennecs; using System.Numerics; record struct Velocity(Vector3 Value); record struct Position(Vector3 Value); using var world = new World(); world.Entity().Add(new Position(Vector3.Zero)).Add(new Velocity(Vector3.UnitY)).Spawn(1000); var stream = world.Query().Stream(); float deltaTime = 0.016f; // Component-only action stream.For((ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * deltaTime; }); // With uniform data (avoids closure allocation) stream.For(deltaTime, static (float dt, ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * dt; }); // With entity access stream.For((in Entity e, ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * deltaTime; if (pos.Value.Y > 100f) e.Despawn(); }); // With uniform + entity stream.For(deltaTime, static (float dt, in Entity e, ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * dt; }); ``` -------------------------------- ### Stream.Where: Per-Component Predicate Filtering Source: https://context7.com/outfox/fennecs/llms.txt Return a new Stream with a component-level predicate evaluated per entity during iteration. Use for filtering based on individual component values. ```csharp using fennecs; record struct Health(float Value); using var world = new World(); world.Entity().Add(new Health(100f)).Spawn(500); world.Entity().Add(new Health(10f)).Spawn(500); // low health entities var stream = world.Query().Stream(); // Only process entities with Health < 20 var lowHealth = stream.Where((in Health h) => h.Value < 20f); int count = 0; lowHealth.For((ref Health h) => { h.Value += 5f; // heal count++; }); Console.WriteLine($"Healed {count} low-health entities."); ``` -------------------------------- ### Stream.Job — Parallel Component Iteration Source: https://context7.com/outfox/fennecs/llms.txt Dispatch workloads across .NET ThreadPool workers for parallel processing using Job. This requires no wildcard stream types and uses the same delegate signatures as For. ```csharp using fennecs; using System.Numerics; record struct Position(Vector3 Value); record struct Velocity(Vector3 Value); using var world = new World(); world.Entity() .Add(new Position(Vector3.Zero)) .Add(new Velocity(Vector3.UnitX)) .Spawn(500_000); var stream = world.Query().Stream(); float deltaTime = 0.016f; // Parallel iteration — safe for independent component writes stream.Job(deltaTime, static (float dt, ref Position pos, ref Velocity vel) => { pos.Value += vel.Value * dt; }); // Parallel with single component var velocities = world.Query().Stream(); stream.Job(static (ref Velocity vel) => { vel.Value *= 0.99f; // drag }); ``` -------------------------------- ### Stream.Raw: Bulk Memory Access Source: https://context7.com/outfox/fennecs/llms.txt Access raw Memory arrays for SIMD or bulk operations. The world is locked during the callback. Use for read/write contiguous spans or with uniform data. ```csharp using fennecs; using System.Numerics; using System.Runtime.InteropServices; record struct Health(float Value); record struct MaxHealth(float Value); using var world = new World(); world.Entity().Add(new Health(100f)).Add(new MaxHealth(100f)).Spawn(100_000); var stream = world.Query().Stream(); // Read/write contiguous Memory spans — great for SIMD stream.Raw((Memory healths, Memory maxHealths) => { var hSpan = healths.Span; var mSpan = maxHealths.Span; for (int i = 0; i < hSpan.Length; i++) hSpan[i] = new Health(Math.Min(hSpan[i].Value + 5f, mSpan[i].Value)); }); // With uniform data stream.Raw(5f, static (float regen, Memory healths, Memory maxHealths) => { var hSpan = healths.Span; var mSpan = maxHealths.Span; for (int i = 0; i < hSpan.Length; i++) hSpan[i] = new Health(Math.Min(hSpan[i].Value + regen, mSpan[i].Value)); }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.