- Notifications
You must be signed in to change notification settings - Fork11
... the little C# ECS that loves you back!
License
outfox/fennecs
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
We know... oh,we know. 😩 But in a nutshell,fennecs is... 🐾 zero codegen | |
Brand new? Try thecookbook for a quick & tasty intro, ordive into the docs!
Familiar with ECS architectures? Get anoverview of new & unique concepts!
At the basic level, all you need is a 🧩component type, a number ofsmall foxes 🦊entities, and a query to ⚙️iterate and modify components, occasionally passing in some uniform 💾data.
// Declare a component record. (we can also use most existing value & reference types)recordstructVelocity(Vector3Value);// Create a world. (fyi, World implements IDisposable)varworld=newfennecs.World();// Spawn an entity into the world with a choice of components. (or add/remove them later)varentity=world.Spawn().Add<Velocity>();// Queries are cached & we use ultra-lightweight Stream Views to feed data to our code!varstream=world.Query<Velocity>().Stream();// Run code on all entities in the query. (exchange 'For' with 'Job' for parallel processing)stream.For(uniform:DeltaTime*9.81f*Vector3.UnitZ,action:(Vector3uniform,refVelocityvelocity)=>{velocity.Value-=uniform;});
By any measure, we're talking just a couple of lines to get this gravity feature up and running. Creating the world and query is the only setup – the real slam dunk is how cleanly we built the full actor/gravity logic with barely any ceremonial code in sight.
And there's more: all that simplicity doesn't force any performance trade-offs! You get to have your cake and eat it too with zero confusion or fluff!
- Modern C# 12 codebase, targeting .NET 8.
- Full Unit Test coverage.
- Powerfully intuitive ways to access data...fast!
- Workloads can be easily parallelized acrossand within Archetypes
- Expressive, queryable relations among Entities themselves & between Entities and Objects
- No code generation and no reflection required.
📕 DOCUMENTATION:fennecs.tech (official website)
Grab a cup of coffee toget started, trythe Cookbook, viewthe Demos , and more!
Preliminary (WIP) benchmarks suggest you can expect to process over 2 million components per millisecond on a 2020 CPU without even customizing your logic.
Using Doraku's syntheticEcs.CSharp.Benchmark, fennecs scores among the faster ECS in the benchmark suite.
(link goes to PR #36 to reproduce)
Warning
These are synthetic benchmarks, using aBETA BUILD offennecs. Real-world performance will vary wildly.If you need a production-ready ECStoday, 9 out of 10 foxes endorseFriflo.Engine.ECS👍 andFlecs.NET👍
Another optimization pass forfennecs ison the Roadmap.
// 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]
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 |
// 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]
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 & butterfennecs 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 |
So how doesfennecs compare to other ECSs?
This library is a tiny, tiny ECS with a focus on good performance and great simplicity. But itcares enough to provide a few things you might not expect.
Important
The idea offennecs was to fill the gaps that the author felt working with various established Entity-Component Systems. This is why this matrix is clearly imbalanced, it's a shopping list of things thatfennecs does well and was made to dowell; and things it may aspire to do but compromised on in order to be able to achieve the others.
(TL;DR - Foxes are soft, choices are hard - Unity dumb, .NET 8 really sharp.)
🥇🥈🥉 (click to expand) ECS Comparison Matrix
Here are some of the key properties wherefennecs might be a better or worse choice than its peers. Our resident fennecs have worked with all of these ECSs, and we're happy to answer any questions you might have.
fennecs | HypEcs | Entitas | Unity DOTS | DefaultECS | |
---|---|---|---|---|---|
Boilerplate-to-Feature Ratio | 3-to-1 | 5-to-1 | 12-to-1 | 27-to-1 😱 | 7-to-1 |
Entity-Component Queries | ✅ | ✅ | ✅ | ✅ | ✅ |
Entity-Entity Relations | ✅ | ✅ | ❌ | ❌ | ✅ (Map/MultiMap) |
Entity-Object-Relations | ✅ | 🟨 (System.Type only) | ❌ | ❌ | ❌ |
Target Querying (find all targets of specific relations) | ✅ | ❌ | ❌ | ❌ | ✅ |
Wildcard Semantics (match multiple relations in 1 query) | ✅ | ❌ | ❌ | ❌ | ❌ |
Journaling | ❌ | ❌ | 🟨 | ✅ | ❌ |
Shared Components | ✅ (ref types only) | ❌ | ❌ | 🟨 (restrictive) | ✅ |
Mutable Shared Components | ✅ | ❌ | ❌ | ❌ | ✅ |
Reference Component Types | ✅ | ❌ | ❌ | ❌ | ❌ |
Arbitrary Component Types | ✅ | ✅ (value types only) | ❌ | ❌ | ✅ |
Structural Change Events | 🟨 (planned) | ❌ | ✅ | ☠️ (unreliable) | ❌ |
Workload Scheduling | ❌ | ❌ | ❌ | ✅ (highly static) | ✅ |
No Code Generation Required | ✅ | ✅ | ❌ | ❌ | 🟨 (roslyn addon) |
Enqueue Structural Changes at Any Time | ✅ | ✅ | ✅ | 🟨 (restrictive) | 🟨 |
Apply Structural Changes at Any Time | ❌ | ❌ | ✅ | ❌ | ❌ |
Parallel Processing | ⭐⭐ | ⭐ | ❌ | ⭐⭐⭐ | ⭐⭐ |
Singleton / Unique Components | 🟨 (ref types only) | ❌ | ✅ | 🟨 (per system) | ✅ |
Many thanks toByteron (Aaron Winter) for creatingHypEcs andRelEcs, the inspiring libraries thatfennecs evolved from.
Neofox was created byVolpeon and is in the Creative CommonsCC BY-NC-SA 4.0, the same license applies to all Neofox-derived works made for this documentation.
About
... the little C# ECS that loves you back!