friflo / Friflo.Engine.ECS

C# ECS ๐Ÿ”ฅ high-performance
https://friflo.gitbook.io/friflo.engine.ecs
GNU Lesser General Public License v3.0
158 stars 11 forks source link
csharp ecs ecs-framework entity-component-system godot monogame unity
[![friflo ECS](docs/images/friflo-ECS.svg)](https://github.com/friflo/Friflo.Engine.ECS)ย ย  ![splash](docs/images/paint-splatter.svg)
[![nuget](https://img.shields.io/nuget/v/Friflo.Engine.ECS?logo=nuget&logoColor=white)](https://www.nuget.org/packages/Friflo.Engine.ECS) [![codecov](https://img.shields.io/codecov/c/gh/friflo/Friflo.Engine.ECS?logo=codecov&logoColor=white&label=codecov)](https://app.codecov.io/gh/friflo/Friflo.Engine.ECS/tree/main/src/ECS) [![CI-Engine](https://img.shields.io/github/actions/workflow/status/friflo/Friflo.Engine.ECS/.github%2Fworkflows%2Fengine.yml?logo=github-actions&logoColor=white&label=CI)](https://github.com/friflo/Friflo.Engine.ECS/actions/workflows/engine.yml) [![Demos](https://img.shields.io/badge/Demos-22aa22?logo=github&logoColor=white)](https://github.com/friflo/Friflo.Engine.ECS-Demos) [![C# API](https://img.shields.io/badge/C%23%20API-22aaaa?logo=github&logoColor=white)](https://github.com/friflo/Friflo.Engine-docs) [![Discord](https://img.shields.io/badge/Discord-5865F2?logo=discord&logoColor=white)](https://discord.gg/nFfrhgQkb8) [![Wiki](https://img.shields.io/badge/Wiki-A200FF?logo=gitbook&logoColor=white)](https://friflo.gitbook.io/friflo.engine.ecs)

Friflo.Engine.ECS

The ECS for finishers ๐Ÿ
Leading performance in most ECS aspects.
Performance Ratio - see C# ECS Benchmark

friflo Flecs.NET TinyEcs Arch fennecs Leopotam DefaultEcs Morpeh
Ratio 1.00 2.55 3.42 6.96 19.02 2.57 3.81 21.09
Notes [^sparse] [^sparse] [^sparse]

[^sparse]: Sparse Set based ECS projects.

News

Contents

Feature highlights

Complete feature list at Wiki โ‹… Features.

Get package on nuget or use the dotnet CLI.

dotnet add package Friflo.Engine.ECS

Projects using friflo ECS

Horse Runner DX


Quote from developer: "Just wanted to let you know that Friflo ECS 2.0.0 works like a charm in my little game.
I use it for basically everything (landscape segments, vegetation, players, animations, collisions and even the floating dust particles are entities).
After some optimization there is no object allocation during gameplay - the allocation graph just stays flat - no garbage collection."

Demos

MonoGame Demo is available as WASM / WebAssembly app. Try Demo in your browser.
Demo projects on GitHub below.

MonoGame Unity Godot
*Desktop Demo performance:* Godot 202 FPS, Unity 100 FPS at 65536 entities. All example Demos - **Windows**, **macOS** & **Linux** - available as projects for **MonoGame**, **Unity** and **Godot**. See [Demos ยท GitHub](https://github.com/friflo/Friflo.Engine.ECS-Demos) ## ECS definition An entity-component-system (**ECS**) is a software architecture pattern. See [ECS โ‹… Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). It is often used in the Gaming industry - e.g. Minecraft - and used for high performant data processing. An ECS provide two strengths: 1. It enables writing *highly decoupled code*. Data is stored in **Components** which are assigned to objects - aka **Entities** - at runtime. Code decoupling is accomplished by dividing implementation in pure data structures (**Component types**) - and code (**Systems**) to process them. 2. It enables *high performant system execution* by storing components in continuous memory to leverage CPU caches L1, L2 & L3. It improves CPU branch prediction by minimizing conditional branches when processing components in tight loops.
# โฉ Examples This section contains two typical use cases when using an ECS. More examples are in the GitHub Wiki. [**Examples - General**](https://friflo.gitbook.io/friflo.engine.ecs/examples/general) Explain fundamental ECS types like *Entity*, *Component*, *Tag*, *Command Buffer*, ... and how to use them. [**Examples - Optimization**](https://friflo.gitbook.io/friflo.engine.ecs/examples/optimization) Provide techniques how to improve ECS performance. ## **๐Ÿš€ Hello World** The hello world examples demonstrates the creation of a world, some entities with components and their movement using a simple `ForEachEntity()` call. ```csharp public struct Velocity : IComponent { public Vector3 value; } public static void HelloWorld() { var world = new EntityStore(); for (int n = 0; n < 10; n++) { world.CreateEntity(new Position(n, 0, 0), new Velocity{ value = new Vector3(0, n, 0)}); } var query = world.Query(); query.ForEachEntity((ref Position position, ref Velocity velocity, Entity entity) => { position.value += velocity.value; }); } ``` In case of moving (updating) thousands or millions of entities an optimized approach can be used. See: [Enumerate Query Chunks](https://friflo.gitbook.io/friflo.engine.ecs/examples/optimization#enumerate-query-chunks), [Parallel Query Job](https://friflo.gitbook.io/friflo.engine.ecs/examples/optimization#parallel-query-job) and [Query Vectorization - SIMD](https://friflo.gitbook.io/friflo.engine.ecs/examples/optimization#query-vectorization---simd). All query optimizations are using the same `query` but with different enumeration techniques.
## **โŒ˜ Component Types** ![new](docs/images/new.svg) in **Friflo.Engine.ECS v3.0.0-preview.2** For specific use cases there is now a set of specialized component interfaces providing additional features. *Note:* Newly added features do not affect the behavior or performance of existing features. The specialized component types enable entity relationships, relations and full-text search. Typical use case for entity relationships in a game are: - Attack systems - Path finding / Route tracing - Model social networks. E.g friendship, alliances or rivalries - Build any type of a [directed graph](https://en.wikipedia.org/wiki/Directed_graph) using entities as *nodes* and links or relations as *edges*. Use cases for relations: - Inventory systems - Add multiple components of the same type to an entity | Use case / Example | Component interface type | Description | ------------------------------------------------------------------------------------------------------------------------- | ------------------------- | -------------------------------------------- | [Entity Relationships](https://friflo.gitbook.io/friflo.engine.ecs/examples/component-types#entity-relationships) | **Link Component** | A single link on an entity referencing another entity | | **Link Relation** | Multiple links on an entity referencing other entities | [Relations](https://friflo.gitbook.io/friflo.engine.ecs/examples/component-types#relations) | **Relation Component** | Add multiple components of same type to an entity | [Search & Range queries](https://friflo.gitbook.io/friflo.engine.ecs/examples/component-types#search) | **Indexed Component** | Full text search of component fields executed in O(1).
Range queries on component fields having a sort order. Big shout out to [**fenn**ecs](https://github.com/outfox/fennecs) and [**flecs**](https://github.com/SanderMertens/flecs) for the challenge to improve the feature set and performance of this project!
## **โš™๏ธ Systems** Systems are new in **Friflo.Engine.ECS v2.0.0** Systems in ECS are typically queries. So you can still use the `world.Query()` shown in the "Hello World" example. Using Systems is optional but they have some significant advantages. **System features** - Enable chaining multiple decoupled [QuerySystem](https://github.com/friflo/Friflo.Engine-docs/blob/main/api/QuerySystem.md) classes in a [SystemGroup](https://github.com/friflo/Friflo.Engine-docs/blob/main/api/SystemGroup.md). Each group provide a [CommandBuffer](https://friflo.gitbook.io/friflo.engine.ecs/examples/optimization#commandbuffer). - A system can have state - fields or properties - which can be used as parameters in `OnUpdate()`. The system state can be serialized to JSON. - Systems can be enabled/disabled or removed. The order of systems in a group can be changed. - Systems have performance monitoring build-in to measure execution times and memory allocations. If enabled systems detected as bottleneck can be optimized. A perf log (see example below) provide a clear overview of all systems their amount of entities and impact on performance. - Multiple worlds can be added to a single [SystemRoot](https://github.com/friflo/Friflo.Engine-docs/blob/main/api/SystemRoot.md) instance. `root.Update()` will execute every system on all worlds. ```csharp public static void HelloSystem() { var world = new EntityStore(); for (int n = 0; n < 10; n++) { world.CreateEntity(new Position(n, 0, 0), new Velocity(), new Scale3()); } var root = new SystemRoot(world) { new MoveSystem(), // new PulseSystem(), // new ... multiple systems can be added. The execution order still remains clear. }; root.Update(default); } class MoveSystem : QuerySystem { protected override void OnUpdate() { Query.ForEachEntity((ref Position position, ref Velocity velocity, Entity entity) => { position.value += velocity.value; }); } } ``` A valuable strength of an ECS is establishing a clear and decoupled code structure. Adding the `PulseSystem` below to the `SystemRoot` above is trivial. This system uses a `foreach (var entity in Query.Entities)` as an alternative to `Query.ForEachEntity((...) => {...})` to iterate the query result. ```csharp struct Pulsating : ITag { } class PulseSystem : QuerySystem { float frequency = 4f; public PulseSystem() => Filter.AnyTags(Tags.Get()); protected override void OnUpdate() { foreach (var entity in Query.Entities) { ref var scale = ref entity.GetComponent().value; scale = Vector3.One * (1 + 0.2f * MathF.Sin(frequency * Tick.time)); } } } ``` ### โฑ System monitoring System performance monitoring is disabled by default. To enable monitoring call: ```csharp root.SetMonitorPerf(true); ``` When enabled system monitoring captures - Number of system executions. - System execution duration in ms. - Memory heap allocations per system in bytes. - The number of entities matching a query system. #### Realtime monitoring In a game editor like Unity system monitoring is available in the **ECS System Set** component.
Screenshot: ECS System Set component in Play mode
#### Log monitoring The performance statistics available at [SystemPerf](https://github.com/friflo/Friflo.Engine-docs/blob/main/api/SystemPerf.md). To get performance statistics on console use: ```csharp root.Update(default); Console.WriteLine(root.GetPerfLog()); ``` The log result will look like: ```js stores: 1 on last ms sum ms updates last mem sum mem entities --------------------- -- -------- -------- -------- -------- -------- -------- Systems [2] + 0.076 3.322 10 128 1392 | ScaleSystem + 0.038 2.088 10 64 696 10000 | PositionSystem + 0.038 1.222 10 64 696 10000 ``` ``` on + enabled - disabled last ms, sum ms last/sum system execution time in ms updates number of executions last mem, sum mem last/sum allocated bytes entities number of entities matching a QuerySystem ```
# ๐Ÿ“– Wiki The **GitHub Wiki** provide you detailed information about the ECS and illustrate them by examples. - [**Examples - General**](https://friflo.gitbook.io/friflo.engine.ecs/examples/general) Explain fundamental ECS types like *Entity*, *Component*, *Tag*, *Command Buffer*, ... and show you how to use them. Contains an example for [Native AOT](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot) integration. - [**Examples - Optimization**](https://friflo.gitbook.io/friflo.engine.ecs/examples/optimization) Provide you techniques how to improve ECS performance. - [**Extensions**](https://friflo.gitbook.io/friflo.engine.ecs/extensions/unity-extension) Projects extending Friflo.Engine.ECS with additional features. - [**Features**](https://friflo.gitbook.io/friflo.engine.ecs/package/features) Integration possibilities, a complete feature list and performance characteristics ๐Ÿ”ฅ. - [**Library**](https://friflo.gitbook.io/friflo.engine.ecs/package/library) List supported platforms, properties of the assembly dll and build statistics. - [**Release Notes**](https://friflo.gitbook.io/friflo.engine.ecs/package/release-notes) List of changes of every release available on nuget.
# ๐Ÿ ECS Benchmarks ## ECS.CSharp.Benchmark - Common use-cases Created a new GitHub repository [ECS.CSharp.Benchmark - Common use-cases](https://github.com/friflo/ECS.CSharp.Benchmark-common-use-cases). It compares the performance of multiple ECS projects with **simple** benchmarks. So they can be used as a **guide to migrate** form one ECS to another. See discussion of [reddit announcement Post](https://www.reddit.com/r/EntityComponentSystem/comments/1e0qo62/just_published_new_github_repo_ecs_c_benchmark/). ## ECS.CSharp.Benchmark Performance comparison using popular **ECS C# benchmark** on GitHub. Two benchmarks - subset of [GitHub โ‹… Ecs.CSharp.Benchmark + PR #38](https://github.com/Doraku/Ecs.CSharp.Benchmark/pull/38) running on a Mac Mini M2. See [Benchmark results](docs/doraku-benchmark.md).
**License** This project is licensed under LGPLv3. Friflo.Engine.ECS Copyright ยฉ 2024ย ย ย Ullrich Praetz - https://github.com/friflo