diff --git a/Svelto.ECS/.github/FUNDING.yml b/Svelto.ECS/.github/FUNDING.yml
new file mode 100644
index 0000000..f6dca80
--- /dev/null
+++ b/Svelto.ECS/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+# These are supported funding model platforms
+
+custom: https://www.paypal.me/smandala
diff --git a/Svelto.ECS/.gitignore b/Svelto.ECS/.gitignore
new file mode 100644
index 0000000..7ef0a76
--- /dev/null
+++ b/Svelto.ECS/.gitignore
@@ -0,0 +1,3 @@
+/obj
+/bin/Release/netstandard2.0
+/bin/Debug/netstandard2.0
diff --git a/Svelto.ECS/.gitmodules b/Svelto.ECS/.gitmodules
new file mode 100644
index 0000000..e69de29
diff --git a/Svelto.ECS/LICENSE b/Svelto.ECS/LICENSE
new file mode 100644
index 0000000..d3cfdc7
--- /dev/null
+++ b/Svelto.ECS/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Sebastiano Mandalà
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Svelto.ECS/README.md b/Svelto.ECS/README.md
new file mode 100644
index 0000000..8452fda
--- /dev/null
+++ b/Svelto.ECS/README.md
@@ -0,0 +1,84 @@
+[](https://openupm.com/packages/com.sebaslab.svelto.ecs/)
+
+# Svelto Entity Component System 2.9
+
+=====================================
+
+Real ECS framework for c\#. Enables to write encapsulated, decoupled, maintainable, highly efficient, data oriented, cache friendly, multi-threaded (if used with Svelto.Tasks), code without pain. Although the framework is platform agnostic \(compatible with c\# 7 and .net standard 2.0\), it comes with several Unity extensions.
+
+## Why using Svelto.ECS with Unity?
+
+_Svelto.ECS wasn't born just from the needs of a large team, but also as result of years of reasoning behind software engineering applied to game development\(\*\). Compared to Unity.ECS, the main goals and reasons for Svelto.ECS to exist are different enough to justify its on going development \(plus Svelto is platform agnostic, so it has been written with portability in mind\). Svelto.ECS hasn't been written just to develop faster code, it has been built to help develop better code. Performance gain is one of the benefits in using Svelto.ECS, as ECS in general is a great way to write cache-friendly code. However Svelto.ECS has been designed around the shift of paradigm from Object Oriented Programming and the consequent improvement of the code design and maintainability. Svelto.ECS is the result of years of iteration of the ECS paradigm applied to real game development with the intent to be "junior coder proof"._
+
+## Official Examples
+
+* **Mini Examples**: [https://github.com/sebas77/Svelto.MiniExamples](https://github.com/sebas77/Svelto.MiniExamples) \(including articles\)
+* **Unity Boids Simulation**: [https://github.com/sebas77/Svelto.ECS.Examples.Boids](https://github.com/sebas77/Svelto.ECS.Examples.Boids) \(including article\)
+* **Unit Tests**: [https://github.com/sebas77/Svelto.ECS.Tests](https://github.com/sebas77/Svelto.ECS.Tests)
+
+**Official Chat \(join to get help from me!\)**
+
+* [https://discord.gg/3qAdjDb](https://discord.gg/3qAdjDb)
+
+## Official Articles
+
+**Framework articles:**
+
+* [http://www.sebaslab.com/introducing-svelto-ecs-2-9/](http://www.sebaslab.com/introducing-svelto-ecs-2-9/) \(shows what's changed since 2.8\)
+* [http://www.sebaslab.com/introducing-svelto-ecs-2-8/](http://www.sebaslab.com/introducing-svelto-ecs-2-8/) \(shows what's changed since 2.7\)
+* [http://www.sebaslab.com/svelto-2-7-whats-new-and-best-practices/](http://www.sebaslab.com/svelto-2-7-whats-new-and-best-practices/) \(shows what's changed since 2.5\)
+* [http://www.sebaslab.com/svelto-ecs-2-5-and-allocation-0-code/](http://www.sebaslab.com/svelto-ecs-2-5-and-allocation-0-code/) \(shows what's changed since 2.0\)
+* [http://www.sebaslab.com/svelto-ecs-2-0-almost-production-ready/](http://www.sebaslab.com/svelto-ecs-2-0-almost-production-ready/) \(shows what's changed since 1.0\)
+* [http://www.sebaslab.com/ecs-1-0/](http://www.sebaslab.com/ecs-1-0/)
+* [http://www.sebaslab.com/learning-svelto-ecs-by-example-the-unity-survival-example/](http://www.sebaslab.com/learning-svelto-ecs-by-example-the-unity-survival-example/)
+* [http://www.sebaslab.com/learning-svelto-ecs-by-example-the-vanilla-example/](http://www.sebaslab.com/learning-svelto-ecs-by-example-the-vanilla-example/)
+* [http://www.sebaslab.com/svelto-ecs-svelto-tasks-to-write-data-oriented-cache-friendly-multi-threaded-code-in-unity/](http://www.sebaslab.com/svelto-ecs-svelto-tasks-to-write-data-oriented-cache-friendly-multi-threaded-code-in-unity/)
+
+**Theory related articles \(in order of publishing date\):**
+
+* [http://www.sebaslab.com/ioc-container-for-unity3d-part-1/](http://www.sebaslab.com/ioc-container-for-unity3d-part-1/)
+* [http://www.sebaslab.com/ioc-container-for-unity3d-part-2/](http://www.sebaslab.com/ioc-container-for-unity3d-part-2/)
+* [http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-i-dependency-injection/](http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-i-dependency-injection/)
+* [http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-ii-inversion-of-control/](http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-ii-inversion-of-control/)
+* [http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iii-entity-component-systems/](http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iii-entity-component-systems/)
+* [http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iv-dependency-inversion-principle/](http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iv-dependency-inversion-principle/)
+* [http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-v-drifting-away-from-ioc-containers/](http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-v-drifting-away-from-ioc-containers/)
+* [http://www.sebaslab.com/the-quest-for-maintainable-code-and-the-path-to-ecs/](http://www.sebaslab.com/the-quest-for-maintainable-code-and-the-path-to-ecs/)
+
+Note: I included the IoC articles just to show how I shifted over the years from using an IoC container to use an ECS framework and the rationale behind its adoption.
+
+**The perfect companion for Svelto.ECS is Svelto.Tasks to run the logic of the Systems even on other threads!**
+
+* [https://github.com/sebas77/Svelto.Tasks](https://github.com/sebas77/Svelto.Tasks)
+
+## Users Generated Content \(may use old versions of Svelto and be quite outdated\)
+
+* [https://github.com/grovemaster/Unity3D-Game-App](https://github.com/grovemaster/Unity3D-Game-App)
+* [https://github.com/colonelsalt/ZombieDeathBoomECS](https://github.com/colonelsalt/ZombieDeathBoomECS)
+* [https://eagergames.wordpress.com/category/ecs/](https://eagergames.wordpress.com/category/ecs/) \(Dario Oliveri\)
+* [https://blogs.msdn.microsoft.com/uk\_faculty\_connection/2018/05/08/entity-component-system-in-unity-a-tutorial/](https://blogs.msdn.microsoft.com/uk_faculty_connection/2018/05/08/entity-component-system-in-unity-a-tutorial/) \(Lee Stott\)
+* [https://github.com/sebas77/Svelto.ECS.Debugger](https://github.com/sebas77/Svelto.ECS.Debugger) \(work just started\)
+* [https://github.com/NED-Studio/LGK.Inspector](https://github.com/NED-Studio/LGK.Inspector) \(probably not working anymore\)
+
+## In case of bugs
+
+Best option is to fork and clone [https://github.com/sebas77/Svelto.ECS.Tests](https://github.com/sebas77/Svelto.ECS.Tests), add a new test to reproduce the problem and request a pull. Then open a github, I come here pretty often :\). Also feel free to contact me on twitter or leave comments on the blog!
+
+## [The Github wiki page](https://github.com/sebas77/Svelto.ECS/wiki)
+
+It needs love and as far as I understood, anyone can edit it. Feel free to do so if you have a good understanding of Svelto!
+
+## I like the project, how can I help?
+
+Hey thanks a lot for considering this. You can help in several ways. The simplest is to talk about Svelto.ECS and spread the word, more we are, better it is for the community. Then you can help with the documentation, updating the wiki or writing your own articles. Svelto.ECS has all the features needed to make a game with the ECS pattern, but some areas are lacking: A visual debugger and more unit tests are needed. Other platforms other than Unity could get some love too: Xenko, Godot and monogame. Porting to other languages, expecially c++, would be awesome!
+
+## Svelto Framework is used to develop the following products\(\*\):
+
+
+
+
+
+\*if you want your products made with Svelto here, just send me an email or whatever, I'll be super happy to add them.
+
+_**Note: Dear Svelto Users : Although I am committed to help you and write articles as much as I can, I will never be able to keep all the documentation up to date. If you are a happy svelto user and you want to contribute, please feel free to update the github wiki! 🙏👊**_
+
diff --git a/Svelto.ECS/SUMMARY.md b/Svelto.ECS/SUMMARY.md
new file mode 100644
index 0000000..e6d872c
--- /dev/null
+++ b/Svelto.ECS/SUMMARY.md
@@ -0,0 +1,4 @@
+# Table of contents
+
+* [Svelto Entity Component System 2.8](README.md)
+
diff --git a/Svelto.ECS/Svelto.ECS/.github/FUNDING.yml b/Svelto.ECS/Svelto.ECS/.github/FUNDING.yml
new file mode 100644
index 0000000..f6dca80
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+# These are supported funding model platforms
+
+custom: https://www.paypal.me/smandala
diff --git a/Svelto.ECS/Svelto.ECS/.gitignore b/Svelto.ECS/Svelto.ECS/.gitignore
new file mode 100644
index 0000000..7ef0a76
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/.gitignore
@@ -0,0 +1,3 @@
+/obj
+/bin/Release/netstandard2.0
+/bin/Debug/netstandard2.0
diff --git a/Svelto.ECS/Svelto.ECS/.gitmodules b/Svelto.ECS/Svelto.ECS/.gitmodules
new file mode 100644
index 0000000..cd05d00
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "Svelto.Common"]
+ path = Svelto.Common
+ url = https://github.com/sebas77/Svelto.Common
diff --git a/Svelto.ECS/Svelto.ECS/AllowMultipleAttribute.cs b/Svelto.ECS/Svelto.ECS/AllowMultipleAttribute.cs
new file mode 100644
index 0000000..37c26ec
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/AllowMultipleAttribute.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Svelto.ECS
+{
+ public class AllowMultipleAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/AllowMultipleAttribute.cs.meta b/Svelto.ECS/Svelto.ECS/AllowMultipleAttribute.cs.meta
new file mode 100644
index 0000000..a2d75c9
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/AllowMultipleAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 29ca2992915771b4eb047f00a7a4b7a6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/CheckEntityUtilities.cs b/Svelto.ECS/Svelto.ECS/CheckEntityUtilities.cs
new file mode 100644
index 0000000..0b061f6
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/CheckEntityUtilities.cs
@@ -0,0 +1,81 @@
+#if DEBUG && !PROFILER
+using System.Collections.Generic;
+using Svelto.DataStructures;
+#else
+using System.Diagnostics;
+#endif
+
+namespace Svelto.ECS
+{
+ public partial class EnginesRoot
+ {
+#if DEBUG && !PROFILER
+ void CheckRemoveEntityID(EGID egid)
+ {
+ // Console.LogError("removed".FastConcat(egid.ToString()));
+ if (_idCheckers.TryGetValue(egid.groupID, out var hash))
+ {
+ if (hash.Contains(egid.entityID) == false)
+ throw new ECSException("Entity with not found ID is about to be removed: id: "
+ .FastConcat(egid.entityID)
+ .FastConcat(" groupid: ")
+ .FastConcat(egid.groupID));
+
+ hash.Remove(egid.entityID);
+
+ if (hash.Count == 0)
+ _idCheckers.Remove(egid.groupID);
+ }
+ else
+ {
+ throw new ECSException("Entity with not found ID is about to be removed: id: "
+ .FastConcat(egid.entityID)
+ .FastConcat(" groupid: ")
+ .FastConcat(egid.groupID));
+ }
+ }
+
+ void CheckAddEntityID(EGID egid)
+ {
+// Console.LogError("added ".FastConcat(egid.ToString()));
+
+ if (_idCheckers.TryGetValue(egid.groupID, out var hash) == false)
+ hash = _idCheckers[egid.groupID] = new HashSet();
+ else
+ {
+ if (hash.Contains(egid.entityID))
+ throw new ECSException("Entity with used ID is about to be built: '"
+ .FastConcat("' id: '")
+ .FastConcat(egid.entityID)
+ .FastConcat("' groupid: '")
+ .FastConcat(egid.groupID)
+ .FastConcat("'"));
+ }
+
+ hash.Add(egid.entityID);
+ }
+
+ void RemoveGroupID(ExclusiveGroup.ExclusiveGroupStruct groupID)
+ {
+ _idCheckers.Remove(groupID);
+ }
+
+ readonly FasterDictionary> _idCheckers = new FasterDictionary>();
+#else
+ [Conditional("_CHECKS_DISABLED")]
+ void CheckRemoveEntityID(EGID egid)
+ {
+ }
+
+ [Conditional("_CHECKS_DISABLED")]
+ void CheckAddEntityID(EGID egid)
+ {
+ }
+
+ [Conditional("_CHECKS_DISABLED")]
+ void RemoveGroupID(ExclusiveGroup.ExclusiveGroupStruct groupID)
+ {
+ }
+#endif
+ }
+}
diff --git a/Svelto.ECS/Svelto.ECS/CheckEntityUtilities.cs.meta b/Svelto.ECS/Svelto.ECS/CheckEntityUtilities.cs.meta
new file mode 100644
index 0000000..279a311
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/CheckEntityUtilities.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cda6cb7ffa71b954dbe3711e152399c2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/DBC.cs b/Svelto.ECS/Svelto.ECS/DBC.cs
new file mode 100644
index 0000000..144c690
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DBC.cs
@@ -0,0 +1,446 @@
+#if DISABLE_DBC || !DEBUG || PROFILER
+#define DISABLE_CHECKS
+using System.Diagnostics;
+#endif
+using System;
+
+namespace DBC.ECS
+{
+ ///
+ /// Design By Contract Checks.
+ ///
+ /// Each method generates an exception or
+ /// a trace assertion statement if the contract is broken.
+ ///
+ ///
+ /// This example shows how to call the Require method.
+ /// Assume DBC_CHECK_PRECONDITION is defined.
+ ///
+ /// public void Test(int x)
+ /// {
+ /// try
+ /// {
+ /// Check.Require(x > 1, "x must be > 1");
+ /// }
+ /// catch (System.Exception ex)
+ /// {
+ /// Console.WriteLine(ex.ToString());
+ /// }
+ /// }
+ ///
+ /// If you wish to use trace assertion statements, intended for Debug scenarios,
+ /// rather than exception handling then set
+ ///
+ /// Check.UseAssertions = true
+ ///
+ /// You can specify this in your application entry point and maybe make it
+ /// dependent on conditional compilation flags or configuration file settings, e.g.,
+ ///
+ /// #if DBC_USE_ASSERTIONS
+ /// Check.UseAssertions = true;
+ /// #endif
+ ///
+ /// You can direct output to a Trace listener. For example, you could insert
+ ///
+ /// Trace.Listeners.Clear();
+ /// Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
+ ///
+ ///
+ /// or direct output to a file or the Event Log.
+ ///
+ /// (Note: For ASP.NET clients use the Listeners collection
+ /// of the Debug, not the Trace, object and, for a Release build, only exception-handling
+ /// is possible.)
+ ///
+ ///
+ static class Check
+ {
+ #region Interface
+
+ ///
+ /// Precondition check.
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Require(bool assertion, string message)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new PreconditionException(message);
+ }
+ else
+ {
+ Trace.Assert(assertion, "Precondition: " + message);
+ }
+ }
+
+ ///
+ /// Precondition check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Require(bool assertion, string message, Exception inner)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new PreconditionException(message, inner);
+ }
+ else
+ {
+ Trace.Assert(assertion, "Precondition: " + message);
+ }
+ }
+
+ ///
+ /// Precondition check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Require(bool assertion)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new PreconditionException("Precondition failed.");
+ }
+ else
+ {
+ Trace.Assert(assertion, "Precondition failed.");
+ }
+ }
+
+ ///
+ /// Postcondition check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Ensure(bool assertion, string message)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new PostconditionException(message);
+ }
+ else
+ {
+ Trace.Assert(assertion, "Postcondition: " + message);
+ }
+ }
+
+ ///
+ /// Postcondition check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Ensure(bool assertion, string message, Exception inner)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new PostconditionException(message, inner);
+ }
+ else
+ {
+ Trace.Assert(assertion, "Postcondition: " + message);
+ }
+ }
+
+ ///
+ /// Postcondition check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Ensure(bool assertion)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new PostconditionException("Postcondition failed.");
+ }
+ else
+ {
+ Trace.Assert(assertion, "Postcondition failed.");
+ }
+ }
+
+ ///
+ /// Invariant check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Invariant(bool assertion, string message)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new InvariantException(message);
+ }
+ else
+ {
+ Trace.Assert(assertion, "Invariant: " + message);
+ }
+ }
+
+ ///
+ /// Invariant check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Invariant(bool assertion, string message, Exception inner)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new InvariantException(message, inner);
+ }
+ else
+ {
+ Trace.Assert(assertion, "Invariant: " + message);
+ }
+ }
+
+ ///
+ /// Invariant check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Invariant(bool assertion)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new InvariantException("Invariant failed.");
+ }
+ else
+ {
+ Trace.Assert(assertion, "Invariant failed.");
+ }
+ }
+
+ ///
+ /// Assertion check.
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Assert(bool assertion, string message)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new AssertionException(message);
+ }
+ else
+ {
+ Trace.Assert(assertion, "Assertion: " + message);
+ }
+ }
+
+ ///
+ /// Assertion check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Assert(bool assertion, string message, Exception inner)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new AssertionException(message, inner);
+ }
+ else
+ {
+ Trace.Assert(assertion, "Assertion: " + message);
+ }
+ }
+
+ ///
+ /// Assertion check.
+ ///
+ ///
+#if DISABLE_CHECKS
+ [Conditional("__NEVER_DEFINED__")]
+#endif
+ public static void Assert(bool assertion)
+ {
+ if (UseExceptions)
+ {
+ if (!assertion)
+ throw new AssertionException("Assertion failed.");
+ }
+ else
+ {
+ Trace.Assert(assertion, "Assertion failed.");
+ }
+ }
+
+ ///
+ /// Set this if you wish to use Trace Assert statements
+ /// instead of exception handling.
+ /// (The Check class uses exception handling by default.)
+ ///
+ public static bool UseAssertions
+ {
+
+ get
+ {
+ return useAssertions;
+ }
+ set
+ {
+ useAssertions = value;
+ }
+ }
+
+ #endregion // Interface
+
+ #region Implementation
+
+ // No creation
+
+ ///
+ /// Is exception handling being used?
+ ///
+ static bool UseExceptions
+ {
+ get
+ {
+ return !useAssertions;
+ }
+ }
+
+ // Are trace assertion statements being used?
+ // Default is to use exception handling.
+ static bool useAssertions;
+
+ #endregion // Implementation
+
+ } // End Check
+
+ internal class Trace
+ {
+ internal static void Assert(bool assertion, string v)
+ {
+#if NETFX_CORE
+ System.Diagnostics.Contracts.Contract.Assert(assertion, v);
+#else
+ System.Diagnostics.Trace.Assert(assertion, v);
+#endif
+ }
+ }
+
+ #region Exceptions
+
+ ///
+ /// Exception raised when a contract is broken.
+ /// Catch this exception type if you wish to differentiate between
+ /// any DesignByContract exception and other runtime exceptions.
+ ///
+ ///
+ public class DesignByContractException : Exception
+ {
+ protected DesignByContractException() {}
+ protected DesignByContractException(string message) : base(message) {}
+ protected DesignByContractException(string message, Exception inner) : base(message, inner) {}
+ }
+
+ ///
+ /// Exception raised when a precondition fails.
+ ///
+ public class PreconditionException : DesignByContractException
+ {
+ ///
+ /// Precondition Exception.
+ ///
+ public PreconditionException() {}
+ ///
+ /// Precondition Exception.
+ ///
+ public PreconditionException(string message) : base(message) {}
+ ///
+ /// Precondition Exception.
+ ///
+ public PreconditionException(string message, Exception inner) : base(message, inner) {}
+ }
+
+ ///
+ /// Exception raised when a postcondition fails.
+ ///
+ public class PostconditionException : DesignByContractException
+ {
+ ///
+ /// Postcondition Exception.
+ ///
+ public PostconditionException() {}
+ ///
+ /// Postcondition Exception.
+ ///
+ public PostconditionException(string message) : base(message) {}
+ ///
+ /// Postcondition Exception.
+ ///
+ public PostconditionException(string message, Exception inner) : base(message, inner) {}
+ }
+
+ ///
+ /// Exception raised when an invariant fails.
+ ///
+ public class InvariantException : DesignByContractException
+ {
+ ///
+ /// Invariant Exception.
+ ///
+ public InvariantException() {}
+ ///
+ /// Invariant Exception.
+ ///
+ public InvariantException(string message) : base(message) {}
+ ///
+ /// Invariant Exception.
+ ///
+ public InvariantException(string message, Exception inner) : base(message, inner) {}
+ }
+
+ ///
+ /// Exception raised when an assertion fails.
+ ///
+ public class AssertionException : DesignByContractException
+ {
+ ///
+ /// Assertion Exception.
+ ///
+ public AssertionException() {}
+ ///
+ /// Assertion Exception.
+ ///
+ public AssertionException(string message) : base(message) {}
+ ///
+ /// Assertion Exception.
+ ///
+ public AssertionException(string message, Exception inner) : base(message, inner) {}
+ }
+
+ #endregion // Exception classes
+
+} // End Design By Contract
diff --git a/Svelto.ECS/Svelto.ECS/DBC.cs.meta b/Svelto.ECS/Svelto.ECS/DBC.cs.meta
new file mode 100644
index 0000000..9b8e7c7
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DBC.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f25d12935fd762e40841aa5c56e603e4
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/DataStructures.meta b/Svelto.ECS/Svelto.ECS/DataStructures.meta
new file mode 100644
index 0000000..4f856f2
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DataStructures.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9d98d8ed291a59c4890021f6391142ca
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/DataStructures/SetEGIDWithoutBoxing.cs b/Svelto.ECS/Svelto.ECS/DataStructures/SetEGIDWithoutBoxing.cs
new file mode 100644
index 0000000..828e598
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DataStructures/SetEGIDWithoutBoxing.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Svelto.ECS.Internal
+{
+ static class SetEGIDWithoutBoxing where T : struct, IEntityStruct
+ {
+ internal delegate void ActionCast(ref T target, EGID egid);
+
+ public static readonly ActionCast SetIDWithoutBoxing = MakeSetter();
+
+ static ActionCast MakeSetter()
+ {
+ if (EntityBuilder.HAS_EGID)
+ {
+#if !ENABLE_IL2CPP
+ Type myTypeA = typeof(T);
+ PropertyInfo myFieldInfo = myTypeA.GetProperty("ID");
+
+ ParameterExpression targetExp = Expression.Parameter(typeof(T).MakeByRefType(), "target");
+ ParameterExpression valueExp = Expression.Parameter(typeof(EGID), "value");
+ MemberExpression fieldExp = Expression.Property(targetExp, myFieldInfo);
+ BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp);
+
+ var setter = Expression.Lambda(assignExp, targetExp, valueExp).Compile();
+
+ return setter;
+#else
+ return (ref T target, EGID value) =>
+ {
+ var needEgid = (target as INeedEGID);
+ needEgid.ID = value;
+ target = (T) needEgid;
+ };
+#endif
+ }
+
+ return null;
+ }
+
+ public static void Warmup()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/DataStructures/SetEGIDWithoutBoxing.cs.meta b/Svelto.ECS/Svelto.ECS/DataStructures/SetEGIDWithoutBoxing.cs.meta
new file mode 100644
index 0000000..37e4e56
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DataStructures/SetEGIDWithoutBoxing.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1e8610cc771cdeb46a808788e49b21d1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionary.cs
new file mode 100644
index 0000000..d902d72
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionary.cs
@@ -0,0 +1,222 @@
+using System;
+using Svelto.Common;
+using Svelto.DataStructures;
+
+namespace Svelto.ECS.Internal
+{
+ public interface ITypeSafeDictionary
+ {
+ int Count { get; }
+ ITypeSafeDictionary Create();
+
+ void AddEntitiesToEngines(
+ FasterDictionary, FasterList> entityViewEnginesDb,
+ ITypeSafeDictionary realDic, in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group);
+
+ void RemoveEntitiesFromEngines(FasterDictionary, FasterList> entityViewEnginesDB,
+ in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group);
+
+ void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId);
+
+ void MoveEntityFromEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup,
+ FasterDictionary, FasterList> engines, in PlatformProfiler profiler);
+
+ void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup);
+ void RemoveEntityFromDictionary(EGID fromEntityGid, in PlatformProfiler profiler);
+
+ void SetCapacity(uint size);
+ void Trim();
+ void Clear();
+ void FastClear();
+ bool Has(uint entityIdEntityId);
+ }
+
+ class TypeSafeDictionary : FasterDictionary,
+ ITypeSafeDictionary where TValue : struct, IEntityStruct
+ {
+ static readonly Type _type = typeof(TValue);
+ static readonly string _typeName = _type.Name;
+ static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type);
+
+ public TypeSafeDictionary(uint size) : base(size) {}
+ public TypeSafeDictionary() {}
+
+ public void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId)
+ {
+ var typeSafeDictionary = entitiesToSubmit as TypeSafeDictionary;
+
+ foreach (var tuple in typeSafeDictionary)
+ {
+ try
+ {
+ if (_hasEgid) SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref tuple.Value, new EGID(tuple.Key, groupId));
+
+ Add(tuple.Key, tuple.Value);
+ }
+ catch (Exception e)
+ {
+ throw new TypeSafeDictionaryException(
+ "trying to add an EntityView with the same ID more than once Entity: "
+ .FastConcat(typeof(TValue).ToString()).FastConcat(", group ").FastConcat(groupId).FastConcat(", id ").FastConcat(tuple.Key), e);
+ }
+ }
+ }
+
+ public void AddEntitiesToEngines(
+ FasterDictionary, FasterList> entityViewEnginesDB,
+ ITypeSafeDictionary realDic, in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group)
+ {
+ var typeSafeDictionary = realDic as TypeSafeDictionary;
+
+ //this can be optimized, should pass all the entities and not restart the process for each one
+ foreach (var value in this)
+ AddEntityViewToEngines(entityViewEnginesDB, ref typeSafeDictionary.GetValueByRef(value.Key), null,
+ in profiler, new EGID(value.Key, group));
+ }
+
+ public void RemoveEntitiesFromEngines(
+ FasterDictionary, FasterList> entityViewEnginesDB,
+ in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group)
+ {
+ foreach (var value in this)
+ RemoveEntityViewFromEngines(entityViewEnginesDB, ref GetValueByRef(value.Key), null, in profiler,
+ new EGID(value.Key, group));
+ }
+
+ public bool Has(uint entityIdEntityId)
+ {
+ return ContainsKey(entityIdEntityId);
+ }
+
+ public void RemoveEntityFromDictionary(EGID fromEntityGid, in PlatformProfiler profiler)
+ {
+ Remove(fromEntityGid.entityID);
+ }
+
+ public void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup)
+ {
+ var valueIndex = GetIndex(fromEntityGid.entityID);
+
+ if (toGroup != null)
+ {
+ var toGroupCasted = toGroup as TypeSafeDictionary;
+ ref var entity = ref valuesArray[valueIndex];
+
+ if (_hasEgid) SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref entity, toEntityID);
+
+ toGroupCasted.Add(fromEntityGid.entityID, entity);
+ }
+ }
+
+ public void MoveEntityFromEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup,
+ FasterDictionary, FasterList> engines, in PlatformProfiler profiler)
+ {
+ var valueIndex = GetIndex(fromEntityGid.entityID);
+
+ ref var entity = ref valuesArray[valueIndex];
+
+ if (toGroup != null)
+ {
+ RemoveEntityViewFromEngines(engines, ref entity, fromEntityGid.groupID, in profiler,
+ fromEntityGid);
+
+ var toGroupCasted = toGroup as TypeSafeDictionary;
+ var previousGroup = fromEntityGid.groupID;
+
+ if (_hasEgid) SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref entity, toEntityID.Value);
+
+ var index = toGroupCasted.GetIndex(toEntityID.Value.entityID);
+
+ AddEntityViewToEngines(engines, ref toGroupCasted.valuesArray[index], previousGroup,
+ in profiler, toEntityID.Value);
+ }
+ else
+ RemoveEntityViewFromEngines(engines, ref entity, null, in profiler, fromEntityGid);
+ }
+
+ public ITypeSafeDictionary Create()
+ {
+ return new TypeSafeDictionary();
+ }
+
+ void AddEntityViewToEngines(FasterDictionary, FasterList> entityViewEnginesDB,
+ ref TValue entity, ExclusiveGroup.ExclusiveGroupStruct? previousGroup,
+ in PlatformProfiler profiler, EGID egid)
+ {
+ //get all the engines linked to TValue
+ if (!entityViewEnginesDB.TryGetValue(new RefWrapper(_type), out var entityViewsEngines)) return;
+
+ if (previousGroup == null)
+ {
+ for (var i = 0; i < entityViewsEngines.Count; i++)
+ try
+ {
+ using (profiler.Sample(entityViewsEngines[i], _typeName))
+ {
+ (entityViewsEngines[i] as IReactOnAddAndRemove).Add(ref entity, egid);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ECSException(
+ "Code crashed inside Add callback ".FastConcat(typeof(TValue).ToString()), e);
+ }
+ }
+ else
+ {
+ for (var i = 0; i < entityViewsEngines.Count; i++)
+ try
+ {
+ using (profiler.Sample(entityViewsEngines[i], _typeName))
+ {
+ (entityViewsEngines[i] as IReactOnSwap).MovedTo(ref entity, previousGroup.Value,
+ egid);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ECSException(
+ "Code crashed inside MovedTo callback ".FastConcat(typeof(TValue).ToString()), e);
+ }
+ }
+ }
+
+ static void RemoveEntityViewFromEngines(
+ FasterDictionary, FasterList> @group, ref TValue entity,
+ ExclusiveGroup.ExclusiveGroupStruct? previousGroup, in PlatformProfiler profiler, EGID egid)
+ {
+ if (!@group.TryGetValue(new RefWrapper(_type), out var entityViewsEngines)) return;
+
+ if (previousGroup == null)
+ {
+ for (var i = 0; i < entityViewsEngines.Count; i++)
+ try
+ {
+ using (profiler.Sample(entityViewsEngines[i], _typeName))
+ (entityViewsEngines[i] as IReactOnAddAndRemove).Remove(ref entity, egid);
+ }
+ catch (Exception e)
+ {
+ throw new ECSException(
+ "Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e);
+ }
+ }
+#if SEEMS_UNNECESSARY
+ else
+ {
+ for (var i = 0; i < entityViewsEngines.Count; i++)
+ try
+ {
+ using (profiler.Sample(entityViewsEngines[i], _typeName))
+ (entityViewsEngines[i] as IReactOnSwap).MovedFrom(ref entity, egid);
+ }
+ catch (Exception e)
+ {
+ throw new ECSException(
+ "Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e);
+ }
+ }
+#endif
+ }
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionary.cs.meta b/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionary.cs.meta
new file mode 100644
index 0000000..8af9662
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionary.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5e812f7d5c7a03d4faebd6bbc9a06a2a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs b/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs
new file mode 100644
index 0000000..6f0a2c9
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Svelto.ECS
+{
+ public class TypeSafeDictionaryException : Exception
+ {
+ public TypeSafeDictionaryException(string message, Exception exception) :
+ base(message, exception)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs.meta b/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs.meta
new file mode 100644
index 0000000..2402112
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8c21456b4b0c7c9409264d02670f7f4c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/Dispatcher.meta b/Svelto.ECS/Svelto.ECS/Dispatcher.meta
new file mode 100644
index 0000000..4c0bbe2
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/Dispatcher.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 67be04a8cde247c4d93885b1ff03ddec
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnChange.cs b/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnChange.cs
new file mode 100644
index 0000000..d1ce756
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnChange.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Svelto.ECS
+{
+ public class DispatchOnChange : DispatchOnSet where T:IEquatable
+ {
+ public DispatchOnChange(EGID senderID) : base(senderID)
+ { }
+
+ public new T value
+ {
+ set
+ {
+ if (value.Equals(_value) == false)
+ base.value = value;
+ }
+
+ get => _value;
+ }
+ }
+}
diff --git a/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnChange.cs.meta b/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnChange.cs.meta
new file mode 100644
index 0000000..6d3f060
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnChange.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8b6d96ff87b04c140ad95db4cb267540
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnSet.cs b/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnSet.cs
new file mode 100644
index 0000000..d407ae8
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnSet.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace Svelto.ECS
+{
+ public class DispatchOnSet
+ {
+ public DispatchOnSet(EGID senderID)
+ {
+ _senderID = senderID;
+ }
+
+ public T value
+ {
+ set
+ {
+ _value = value;
+
+ if (_paused == false)
+ _subscribers(_senderID, value);
+ }
+ }
+
+ public void NotifyOnValueSet(Action action)
+ {
+ _subscribers += action;
+ }
+
+ public void StopNotify(Action action)
+ {
+ _subscribers -= action;
+ }
+
+ public void PauseNotify() { _paused = true; }
+ public void ResumeNotify() { _paused = false; }
+
+ protected T _value;
+ readonly EGID _senderID;
+
+ Action _subscribers;
+ bool _paused;
+ }
+}
diff --git a/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnSet.cs.meta b/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnSet.cs.meta
new file mode 100644
index 0000000..5513460
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/Dispatcher/DispatchOnSet.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f3455e49716d5f44c9ed8da0880dead2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/DynamicEntityDescriptor.cs b/Svelto.ECS/Svelto.ECS/DynamicEntityDescriptor.cs
new file mode 100644
index 0000000..f40d3e7
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DynamicEntityDescriptor.cs
@@ -0,0 +1,128 @@
+using System;
+using Svelto.DataStructures;
+
+namespace Svelto.ECS
+{
+ ///
+ /// DynamicEntityDescriptor can be used to add entity views to an existing EntityDescriptor that act as flags,
+ /// at building time.
+ /// This method allocates, so it shouldn't be abused
+ ///
+ ///
+ public struct DynamicEntityDescriptor : IEntityDescriptor where TType : IEntityDescriptor, new()
+ {
+ internal DynamicEntityDescriptor(bool isExtendible) : this()
+ {
+ var defaultEntities = EntityDescriptorTemplate.descriptor.entitiesToBuild;
+ var length = defaultEntities.Length;
+
+ _entitiesToBuild = new IEntityBuilder[length + 1];
+
+ Array.Copy(defaultEntities, 0, _entitiesToBuild, 0, length);
+
+ //assign it after otherwise the previous copy will overwrite the value in case the item
+ //is already present
+ _entitiesToBuild[length] = new EntityBuilder
+ (
+ new EntityStructInfoView
+ {
+ entitiesToBuild = _entitiesToBuild
+ }
+ );
+ }
+
+ public DynamicEntityDescriptor(IEntityBuilder[] extraEntityBuilders) : this()
+ {
+ var extraEntitiesLength = extraEntityBuilders.Length;
+
+ _entitiesToBuild = Construct(extraEntitiesLength, extraEntityBuilders,
+ EntityDescriptorTemplate.descriptor.entitiesToBuild);
+ }
+
+ public DynamicEntityDescriptor(FasterList extraEntityBuilders) : this()
+ {
+ var extraEntities = extraEntityBuilders.ToArrayFast();
+ var extraEntitiesLength = extraEntityBuilders.Count;
+
+ _entitiesToBuild = Construct(extraEntitiesLength, extraEntities,
+ EntityDescriptorTemplate.descriptor.entitiesToBuild);
+ }
+
+ public void ExtendWith() where T : IEntityDescriptor, new()
+ {
+ var newEntitiesToBuild = EntityDescriptorTemplate.descriptor.entitiesToBuild;
+
+ _entitiesToBuild = Construct(newEntitiesToBuild.Length, newEntitiesToBuild, _entitiesToBuild);
+ }
+
+ public void ExtendWith(IEntityBuilder[] extraEntities)
+ {
+ _entitiesToBuild = Construct(extraEntities.Length, extraEntities, _entitiesToBuild);
+ }
+
+ static IEntityBuilder[] Construct(int extraEntitiesLength, IEntityBuilder[] extraEntities,
+ IEntityBuilder[] startingEntities)
+ {
+ IEntityBuilder[] localEntitiesToBuild;
+
+ if (extraEntitiesLength == 0)
+ {
+ localEntitiesToBuild = startingEntities;
+ return localEntitiesToBuild;
+ }
+
+ var defaultEntities = startingEntities;
+ var length = defaultEntities.Length;
+
+ var index = SetupSpecialEntityStruct(defaultEntities, out localEntitiesToBuild, extraEntitiesLength);
+
+ Array.Copy(extraEntities, 0, localEntitiesToBuild, length, extraEntitiesLength);
+
+ //assign it after otherwise the previous copy will overwrite the value in case the item
+ //is already present
+ localEntitiesToBuild[index] = new EntityBuilder
+ (
+ new EntityStructInfoView
+ {
+ entitiesToBuild = localEntitiesToBuild
+ }
+ );
+
+ return localEntitiesToBuild;
+ }
+
+ static int SetupSpecialEntityStruct(IEntityBuilder[] defaultEntities, out IEntityBuilder[] entitiesToBuild,
+ int extraLenght)
+ {
+ int length = defaultEntities.Length;
+ int index = -1;
+
+ for (var i = 0; i < length; i++)
+ {
+ //the special entity already exists
+ if (defaultEntities[i].GetEntityType() == EntityBuilderUtilities.ENTITY_STRUCT_INFO_VIEW)
+ {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == -1)
+ {
+ index = length + extraLenght;
+ entitiesToBuild = new IEntityBuilder[index + 1];
+ }
+ else
+ entitiesToBuild = new IEntityBuilder[length + extraLenght];
+
+ Array.Copy(defaultEntities, 0, entitiesToBuild, 0, length);
+
+ return index;
+ }
+
+
+ public IEntityBuilder[] entitiesToBuild => _entitiesToBuild;
+
+ IEntityBuilder[] _entitiesToBuild;
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/DynamicEntityDescriptor.cs.meta b/Svelto.ECS/Svelto.ECS/DynamicEntityDescriptor.cs.meta
new file mode 100644
index 0000000..e75eb39
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/DynamicEntityDescriptor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f44f311aa89faee408fe3591032a1bb9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/ECSException.cs b/Svelto.ECS/Svelto.ECS/ECSException.cs
new file mode 100644
index 0000000..b815f84
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/ECSException.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Svelto.ECS
+{
+ public class ECSException : Exception
+ {
+ public ECSException(string message):base("".FastConcat(message, ""))
+ {}
+
+ public ECSException(string message, Exception innerE):base("".FastConcat(message, ""), innerE)
+ {}
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/ECSException.cs.meta b/Svelto.ECS/Svelto.ECS/ECSException.cs.meta
new file mode 100644
index 0000000..3edd782
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/ECSException.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ffc933f6fa0c64f46aa6e501ccac1eca
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/ECSResources.meta b/Svelto.ECS/Svelto.ECS/ECSResources.meta
new file mode 100644
index 0000000..5e21225
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/ECSResources.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ed2ee43790d8ab0408efcd5ee7b4e80f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/ECSResources/ECSResources.cs b/Svelto.ECS/Svelto.ECS/ECSResources/ECSResources.cs
new file mode 100644
index 0000000..70ba614
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/ECSResources/ECSResources.cs
@@ -0,0 +1,47 @@
+using Svelto.DataStructures;
+
+namespace Svelto.ECS.Experimental
+{
+ public struct ECSResources
+ {
+ internal uint id;
+
+ public static implicit operator T(ECSResources ecsString) { return ResourcesECSDB.FromECS(ecsString.id); }
+ }
+
+ static class ResourcesECSDB
+ {
+ static readonly FasterList _resources = new FasterList();
+
+ internal static ref T resources(uint id)
+ {
+ return ref _resources[(int) id - 1];
+ }
+
+ internal static uint ToECS(T resource)
+ {
+ _resources.Add(resource);
+
+ return (uint)_resources.Count;
+ }
+
+ public static T FromECS(uint id)
+ {
+ if (id - 1 < _resources.Count)
+ return _resources[(int) id - 1];
+
+ return default;
+ }
+ }
+
+ public static class ResourceExtensions
+ {
+ public static void Set(ref this ECSResources resource, T newText)
+ {
+ if (resource.id != 0)
+ ResourcesECSDB.resources(resource.id) = newText;
+ else
+ resource.id = ResourcesECSDB.ToECS(newText);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/ECSResources/ECSResources.cs.meta b/Svelto.ECS/Svelto.ECS/ECSResources/ECSResources.cs.meta
new file mode 100644
index 0000000..e3f61da
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/ECSResources/ECSResources.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5afcd85ad92ffb344b04a1aa675814bf
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/ECSResources/ECSString.cs b/Svelto.ECS/Svelto.ECS/ECSResources/ECSString.cs
new file mode 100644
index 0000000..4eac06c
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/ECSResources/ECSString.cs
@@ -0,0 +1,38 @@
+using System;
+
+namespace Svelto.ECS.Experimental
+{
+ [Serialization.DoNotSerialize]
+ public struct ECSString:IEquatable
+ {
+ uint id;
+
+ public ECSString(string newText)
+ {
+ id = ResourcesECSDB.ToECS(newText);
+ }
+
+ public static implicit operator string(ECSString ecsString)
+ {
+ return ResourcesECSDB.FromECS(ecsString.id);
+ }
+
+ public void Set(string newText)
+ {
+ if (id != 0)
+ ResourcesECSDB.resources(id) = newText;
+ else
+ id = ResourcesECSDB.ToECS(newText);
+ }
+
+ public bool Equals(ECSString other)
+ {
+ return other.id == id;
+ }
+
+ public override string ToString()
+ {
+ return ResourcesECSDB.FromECS(id);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/ECSResources/ECSString.cs.meta b/Svelto.ECS/Svelto.ECS/ECSResources/ECSString.cs.meta
new file mode 100644
index 0000000..64844e6
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/ECSResources/ECSString.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a851028d58ed0754fa529a196e952859
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/EGID.cs b/Svelto.ECS/Svelto.ECS/EGID.cs
new file mode 100644
index 0000000..4e7d768
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EGID.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+
+#pragma warning disable 660,661
+
+namespace Svelto.ECS
+{
+ //todo: add debug map
+ [Serialization.DoNotSerialize]
+ [Serializable]
+ public struct EGID:IEquatable,IEqualityComparer,IComparable
+ {
+ public uint entityID => (uint) (_GID & 0xFFFFFFFF);
+
+ public ExclusiveGroup.ExclusiveGroupStruct groupID => new ExclusiveGroup.ExclusiveGroupStruct((uint) (_GID >> 32));
+
+ public static bool operator ==(EGID obj1, EGID obj2)
+ {
+ return obj1._GID == obj2._GID;
+ }
+
+ public static bool operator !=(EGID obj1, EGID obj2)
+ {
+ return obj1._GID != obj2._GID;
+ }
+
+ public EGID(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) : this()
+ {
+ _GID = MAKE_GLOBAL_ID(entityID, groupID);
+ }
+
+ static ulong MAKE_GLOBAL_ID(uint entityId, uint groupId)
+ {
+ return (ulong)groupId << 32 | ((ulong)entityId & 0xFFFFFFFF);
+ }
+
+ public static explicit operator uint(EGID id)
+ {
+ return id.entityID;
+ }
+
+ //in the way it's used, ulong must be always the same for each id/group
+ public static explicit operator ulong(EGID id) { return id._GID; }
+
+ public bool Equals(EGID other)
+ {
+ return _GID == other._GID;
+ }
+
+ public bool Equals(EGID x, EGID y)
+ {
+ return x == y;
+ }
+
+ public int GetHashCode(EGID obj)
+ {
+ return _GID.GetHashCode();
+ }
+
+ public int CompareTo(EGID other)
+ {
+ return _GID.CompareTo(other._GID);
+ }
+
+ internal EGID(uint entityID, uint groupID) : this()
+ {
+ _GID = MAKE_GLOBAL_ID(entityID, groupID);
+ }
+
+ public override string ToString()
+ {
+ return "id ".FastConcat(entityID).FastConcat(" group ").FastConcat(groupID);
+ }
+
+ readonly ulong _GID;
+ }
+}
diff --git a/Svelto.ECS/Svelto.ECS/EGID.cs.meta b/Svelto.ECS/Svelto.ECS/EGID.cs.meta
new file mode 100644
index 0000000..794a3fb
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EGID.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 107bb03a12307bb4f961b85b782e22e1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/EGIDMapper.cs b/Svelto.ECS/Svelto.ECS/EGIDMapper.cs
new file mode 100644
index 0000000..939e20b
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EGIDMapper.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Svelto.DataStructures;
+
+namespace Svelto.ECS
+{
+ public struct EGIDMapper where T : struct, IEntityStruct
+ {
+ internal FasterDictionary map;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ref T Entity(uint entityID)
+ {
+#if DEBUG && !PROFILER
+ if (map.TryFindIndex(entityID, out var findIndex) == false)
+ throw new Exception("Entity not found in this group ".FastConcat(typeof(T).ToString()));
+#else
+ map.TryFindIndex(entityID, out var findIndex);
+#endif
+ return ref map.valuesArray[findIndex];
+ }
+
+ public bool TryGetEntity(uint entityID, out T value)
+ {
+ if (map.TryFindIndex(entityID, out var index))
+ {
+ value = map.GetDirectValue(index);
+ return true;
+ }
+
+ value = default;
+ return false;
+ }
+ }
+}
+
diff --git a/Svelto.ECS/Svelto.ECS/EGIDMapper.cs.meta b/Svelto.ECS/Svelto.ECS/EGIDMapper.cs.meta
new file mode 100644
index 0000000..e5db383
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EGIDMapper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c28b51f353894904c831577c2c725122
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs b/Svelto.ECS/Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs
new file mode 100644
index 0000000..f6077f3
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs
@@ -0,0 +1,86 @@
+using System;
+using Svelto.DataStructures;
+using Svelto.ECS.Internal;
+
+namespace Svelto.ECS
+{
+ public partial class EnginesRoot
+ {
+ internal class DoubleBufferedEntitiesToAdd
+ {
+ const int MaximumNumberOfItemsPerFrameBeforeToClear = 100;
+
+ internal void Swap()
+ {
+ Swap(ref current, ref other);
+ Swap(ref currentEntitiesCreatedPerGroup, ref otherEntitiesCreatedPerGroup);
+ }
+
+ void Swap(ref T item1, ref T item2)
+ {
+ var toSwap = item2;
+ item2 = item1;
+ item1 = toSwap;
+ }
+
+ public void ClearOther()
+ {
+ //do not clear the groups created so far, they will be reused, unless they are too many!
+ var otherCount = other.Count;
+ if (otherCount > MaximumNumberOfItemsPerFrameBeforeToClear)
+ {
+ otherEntitiesCreatedPerGroup.FastClear();
+ other.FastClear();
+ return;
+ }
+ var otherValuesArray = other.valuesArray;
+ for (int i = 0; i < otherCount; ++i)
+ {
+ var safeDictionariesCount = otherValuesArray[i].Count;
+ var safeDictionaries = otherValuesArray[i].valuesArray;
+ //do not remove the dictionaries of entities per type created so far, they will be reused
+ if (safeDictionariesCount <= MaximumNumberOfItemsPerFrameBeforeToClear)
+ {
+ for (int j = 0; j < safeDictionariesCount; ++j)
+ {
+ //clear the dictionary of entities create do far (it won't allocate though)
+ safeDictionaries[j].FastClear();
+ }
+ }
+ else
+ {
+ otherValuesArray[i].FastClear();
+ }
+ }
+
+ otherEntitiesCreatedPerGroup.FastClear();
+ }
+
+ internal FasterDictionary currentEntitiesCreatedPerGroup;
+ internal FasterDictionary otherEntitiesCreatedPerGroup;
+
+ internal FasterDictionary, ITypeSafeDictionary>> current;
+ internal FasterDictionary, ITypeSafeDictionary>> other;
+
+ readonly FasterDictionary, ITypeSafeDictionary>>
+ _entityViewsToAddBufferA =
+ new FasterDictionary, ITypeSafeDictionary>>();
+
+ readonly FasterDictionary, ITypeSafeDictionary>>
+ _entityViewsToAddBufferB =
+ new FasterDictionary, ITypeSafeDictionary>>();
+
+ readonly FasterDictionary _entitiesCreatedPerGroupA = new FasterDictionary();
+ readonly FasterDictionary _entitiesCreatedPerGroupB = new FasterDictionary();
+
+ public DoubleBufferedEntitiesToAdd()
+ {
+ currentEntitiesCreatedPerGroup = _entitiesCreatedPerGroupA;
+ otherEntitiesCreatedPerGroup = _entitiesCreatedPerGroupB;
+
+ current = _entityViewsToAddBufferA;
+ other = _entityViewsToAddBufferB;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs.meta b/Svelto.ECS/Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs.meta
new file mode 100644
index 0000000..47f493c
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EnginesRoot.DoubleBufferedEntityViews.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 317edb22c6fdcb447a576d39d928aae7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/EnginesRoot.Engines.cs b/Svelto.ECS/Svelto.ECS/EnginesRoot.Engines.cs
new file mode 100644
index 0000000..8438e5b
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EnginesRoot.Engines.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using Svelto.DataStructures;
+using Svelto.ECS.Internal;
+using Svelto.ECS.Schedulers;
+
+namespace Svelto.ECS
+{
+ public partial class EnginesRoot
+ {
+ public struct EntitiesSubmitter
+ {
+ public EntitiesSubmitter(EnginesRoot enginesRoot)
+ {
+ _weakReference = new DataStructures.WeakReference(enginesRoot);
+ }
+
+ public void Invoke()
+ {
+ if (_weakReference.IsValid)
+ _weakReference.Target.SubmitEntityViews();
+ }
+
+ readonly DataStructures.WeakReference _weakReference;
+ }
+ ///
+ /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot
+ /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks
+ /// periodically if new entity must be submitted to the database and the engines. It's an external
+ /// dependencies to be independent by the running platform as the user can define it.
+ /// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why
+ /// it must receive a weak reference of the EnginesRoot callback.
+ ///
+ public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler)
+ {
+ _entitiesOperations = new FasterDictionary();
+ _reactiveEnginesAddRemove = new FasterDictionary, FasterList>();
+ _reactiveEnginesSwap = new FasterDictionary, FasterList>();
+ _enginesSet = new FasterList();
+ _enginesTypeSet = new HashSet();
+ _disposableEngines = new FasterList();
+ _transientEntitiesOperations = new FasterList();
+
+ _groupEntityViewsDB = new FasterDictionary, ITypeSafeDictionary>>();
+ _groupsPerEntity = new FasterDictionary, FasterDictionary>();
+ _groupedEntityToAdd = new DoubleBufferedEntitiesToAdd();
+
+ _entitiesStream = new EntitiesStream();
+ _entitiesDB = new EntitiesDB(_groupEntityViewsDB, _groupsPerEntity, _entitiesStream);
+
+ _scheduler = entityViewScheduler;
+ _scheduler.onTick = new EntitiesSubmitter(this);
+ }
+
+ public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler, bool isDeserializationOnly):this(entityViewScheduler)
+ {
+ _isDeserializationOnly = isDeserializationOnly;
+ }
+
+ public void AddEngine(IEngine engine)
+ {
+ var type = engine.GetType();
+ var refWrapper = new RefWrapper(type);
+ DBC.ECS.Check.Require(
+ _enginesTypeSet.Contains(refWrapper) == false ||
+ type.ContainsCustomAttribute(typeof(AllowMultipleAttribute)) == true,
+ "The same engine has been added more than once, if intentional, use [AllowMultiple] class attribute "
+ .FastConcat(engine.ToString()));
+ try
+ {
+ if (engine is IReactOnAddAndRemove viewEngine)
+ CheckEntityViewsEngine(viewEngine, _reactiveEnginesAddRemove);
+
+ if (engine is IReactOnSwap viewEngineSwap)
+ CheckEntityViewsEngine(viewEngineSwap, _reactiveEnginesSwap);
+
+ _enginesTypeSet.Add(refWrapper);
+ _enginesSet.Add(engine);
+
+ if (engine is IDisposable)
+ _disposableEngines.Add(engine as IDisposable);
+
+ if (engine is IQueryingEntitiesEngine queryableEntityViewEngine)
+ {
+ queryableEntityViewEngine.entitiesDB = _entitiesDB;
+ queryableEntityViewEngine.Ready();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ECSException("Code crashed while adding engine ".FastConcat(engine.GetType().ToString(), " "), e);
+ }
+ }
+
+ void CheckEntityViewsEngine(T engine, FasterDictionary, FasterList> engines)
+ where T : class, IEngine
+ {
+ var interfaces = engine.GetType().GetInterfaces();
+
+ foreach (var interf in interfaces)
+ {
+ if (interf.IsGenericTypeEx() && typeof(T).IsAssignableFrom(interf))
+ {
+ var genericArguments = interf.GetGenericArgumentsEx();
+
+ AddEngine(engine, genericArguments, engines);
+ }
+ }
+ }
+
+ static void AddEngine(T engine, Type[] entityViewTypes,
+ FasterDictionary, FasterList> engines)
+ where T : class, IEngine
+ {
+ for (var i = 0; i < entityViewTypes.Length; i++)
+ {
+ var type = entityViewTypes[i];
+
+ AddEngine(engine, engines, type);
+ }
+ }
+
+ static void AddEngine(T engine, FasterDictionary, FasterList> engines, Type type)
+ where T : class, IEngine
+ {
+ if (engines.TryGetValue(new RefWrapper(type), out var list) == false)
+ {
+ list = new FasterList();
+
+ engines.Add(new RefWrapper(type), list);
+ }
+
+ list.Add(engine);
+ }
+
+ readonly FasterDictionary, FasterList> _reactiveEnginesAddRemove;
+ readonly FasterDictionary, FasterList> _reactiveEnginesSwap;
+ readonly FasterList _disposableEngines;
+
+ readonly FasterList _enginesSet;
+ readonly HashSet _enginesTypeSet;
+ }
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Svelto.ECS/EnginesRoot.Engines.cs.meta b/Svelto.ECS/Svelto.ECS/EnginesRoot.Engines.cs.meta
new file mode 100644
index 0000000..1e1c3a4
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EnginesRoot.Engines.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 63f9381d3d2e91f4eb2f890bb36c605b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Svelto.ECS/Svelto.ECS/EnginesRoot.Entities.cs b/Svelto.ECS/Svelto.ECS/EnginesRoot.Entities.cs
new file mode 100644
index 0000000..08e3ffc
--- /dev/null
+++ b/Svelto.ECS/Svelto.ECS/EnginesRoot.Entities.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using Svelto.Common;
+using Svelto.DataStructures;
+using Svelto.ECS.Internal;
+
+namespace Svelto.ECS
+{
+ public partial class EnginesRoot : IDisposable
+ {
+ ///
+ /// Dispose an EngineRoot once not used anymore, so that all the
+ /// engines are notified with the entities removed.
+ /// It's a clean up process.
+ ///
+ public void Dispose()
+ {
+ using (var profiler = new PlatformProfiler("Final Dispose"))
+ {
+ foreach (var groups in _groupEntityViewsDB)
+ {
+ foreach (var entityList in groups.Value)
+ {
+ entityList.Value.RemoveEntitiesFromEngines(_reactiveEnginesAddRemove,
+ profiler, new ExclusiveGroup.ExclusiveGroupStruct(groups.Key));
+ }
+ }
+
+ _groupEntityViewsDB.Clear();
+ _groupsPerEntity.Clear();
+
+ foreach (var engine in _disposableEngines)
+ engine.Dispose();
+
+ _disposableEngines.Clear();
+ _enginesSet.Clear();
+ _enginesTypeSet.Clear();
+ _reactiveEnginesSwap.Clear();
+ _reactiveEnginesAddRemove.Clear();
+
+ _entitiesOperations.Clear();
+ _transientEntitiesOperations.Clear();
+ _scheduler.Dispose();
+#if DEBUG && !PROFILER
+ _idCheckers.Clear();
+#endif
+ _groupedEntityToAdd = null;
+
+ _entitiesStream.Dispose();
+ }
+
+ GC.SuppressFinalize(this);
+ }
+
+ ~EnginesRoot()
+ {
+ Console.LogWarning("Engines Root has been garbage collected, don't forget to call Dispose()!");
+
+ Dispose();
+ }
+
+ ///--------------------------------------------
+ ///
+ public IEntityStreamConsumerFactory GenerateConsumerFactory()
+ {
+ return new GenericEntityStreamConsumerFactory(this);
+ }
+
+ public IEntityFactory GenerateEntityFactory()
+ {
+ return new GenericEntityFactory(this);
+ }
+
+ public IEntityFunctions GenerateEntityFunctions()
+ {
+ return new GenericEntityFunctions(this);
+ }
+
+ ///--------------------------------------------
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ EntityStructInitializer BuildEntity(EGID entityID, IEntityBuilder[] entitiesToBuild,
+ IEnumerable