GithubHelp home page GithubHelp logo

sebas77 / svelto.ecs Goto Github PK

View Code? Open in Web Editor NEW
1.1K 52.0 92.0 1.63 MB

Svelto ECS C# Entity Component System

Home Page: http://www.sebaslab.com

License: MIT License

C# 99.88% Makefile 0.12%
unity ecs entity-component-system csharp ecs-framework game-development data-oriented game-engine

svelto.ecs's Introduction

Svelto.ECS C# Entity Component System framework

Real ECS framework for c#. Enables to write encapsulated, decoupled, maintainable, highly efficient, data oriented, cache friendly, code without pain. Although the framework is platform agnostic (compatible with c# 7 and above and .net standard 2.0 and above), it comes with several Unity extensions.

Svelto.ECS in pills

Svelto.ECS is easy to start with, but full of tricks for expert users. The hardest problem to overcome is usually to shift mentality from OOP programming to ECS programming rather than using the framework itself. If you would like to read an ECS faq, you can check this article: https://github.com/SanderMertens/ecs-faq

Svelto.ECS at glance

simplest setup:

using System;
using Svelto.ECS;
using Svelto.ECS.Schedulers;
using Svelto.ECS.Vanilla.Example.SimpleEntityEngine;

/// <summary>
///     This is the common pattern to declare Svelto Exclusive Groups (usually split by composition root)
/// </summary>
public static class ExclusiveGroups
{
    public static ExclusiveGroup group0 = new ExclusiveGroup();
    public static ExclusiveGroup group1 = new ExclusiveGroup();
}

namespace Svelto.ECS.Vanilla.Example
{
    /// <summary>
    ///     The Context is the application starting point.
    ///     As a Composition root, it gives to the coder the responsibility to create, initialize and
    ///     inject dependencies.
    ///     Every application can have more than one context and every context can have one
    ///     or more composition roots (a facade, but even a factory, can be a composition root)
    /// </summary>
    public class SimpleContext
    {
        public SimpleContext()
        {
            //an entity submission scheduler is needed to submit entities to the Svelto database, Svelto is not 
            //responsible to decide when to submit entities, it's the user's responsibility to do so.
            var entitySubmissionScheduler = new SimpleEntitiesSubmissionScheduler();
            //An EnginesRoot holds all the engines and entities created. it needs a EntitySubmissionScheduler to know when to
            //add previously built entities to the Svelto database. Using the SimpleEntitiesSubmissionScheduler
            //is expected as it gives complete control to the user about when the submission happens
            _enginesRoot = new EnginesRoot(entitySubmissionScheduler);

            //an entity factory allows to build entities inside engines
            var entityFactory = _enginesRoot.GenerateEntityFactory();
            //the entity functions allows other operations on entities, like remove and swap
            var entityFunctions = _enginesRoot.GenerateEntityFunctions();

            //Add the Engine to manage the SimpleEntities
            var behaviourForEntityClassEngine = new BehaviourForEntityClassEngine(entityFunctions);
            _enginesRoot.AddEngine(behaviourForEntityClassEngine);

            //build Entity with ID 0 in group0
            entityFactory.BuildEntity<SimpleEntityDescriptor>(new EGID(0, ExclusiveGroups.group0));

            //submit the previously built entities to the Svelto database
            entitySubmissionScheduler.SubmitEntities();

            //as Svelto doesn't provide an engine/system ticking system, it's the user's responsibility to
            //update engines  
            behaviourForEntityClassEngine.Update();

            Console.Log("Done - click any button to quit");

            System.Console.ReadKey();

            Environment.Exit(0);
        }

        readonly EnginesRoot _enginesRoot;
    }

    //An EntityComponent must always implement the IEntityComponent interface
    //don't worry, boxing/unboxing will never happen.
    public struct EntityComponent : IEntityComponent
    {
        public int counter;
    }

    /// <summary>
    ///     The EntityDescriptor identifies your Entity. It's essential to identify
    ///     your entities with a name that comes from the Game Design domain.
    /// </summary>
    class SimpleEntityDescriptor : GenericEntityDescriptor<EntityComponent> { }

    namespace SimpleEntityEngine
    {
        public class BehaviourForEntityClassEngine :
                //this interface makes the engine reactive, it's absolutely optional, you need to read my articles
                //and wiki about it.
                IReactOnAddEx<EntityComponent>, IReactOnSwapEx<EntityComponent>, IReactOnRemoveEx<EntityComponent>,
                //while this interface is optional too, it's almost always used as it gives access to the entitiesDB
                IQueryingEntitiesEngine
        {
            //extra entity functions
            readonly IEntityFunctions _entityFunctions;

            public BehaviourForEntityClassEngine(IEntityFunctions entityFunctions)
            {
                _entityFunctions = entityFunctions;
            }

            public EntitiesDB entitiesDB { get; set; }

            public void Ready() { }

            public void Update()
            {
                //Simple query to get all the entities with EntityComponent in group1
                var (components, entityIDs, count) = entitiesDB.QueryEntities<EntityComponent>(ExclusiveGroups.group1);

                uint entityID;
                for (var i = 0; i < count; i++)
                {
                    components[i].counter++;
                    entityID = entityIDs[i];
                }

                Console.Log("Entity Struct engine executed");
            }

            //the following methods are called by Svelto.ECS when an entity is added to a group
            public void Add((uint start, uint end) rangeOfEntities, in EntityCollection<EntityComponent> entities
              , ExclusiveGroupStruct groupID)
            {
                var (_, entityIDs, _) = entities;

                for (uint index = rangeOfEntities.start; index < rangeOfEntities.end; index++)
                    //Swap entities between groups is a very common operation and it's necessary to
                    //move entities between groups/sets. A Group represent a state/adjective of an entity, so changing
                    //group means change state/behaviour as different engines will process different groups.
                    //it's the Svelto equivalent of adding/remove components to an entity at run time
                    _entityFunctions.SwapEntityGroup<SimpleEntityDescriptor>(new EGID(entityIDs[index], groupID), ExclusiveGroups.group1);
            }

            //the following methods are called by Svelto.ECS when an entity is swapped from a group to another
            public void MovedTo((uint start, uint end) rangeOfEntities, in EntityCollection<EntityComponent> entities
              , ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup)
            {
                var (_, entityIDs, _) = entities;
                
                for (var index = rangeOfEntities.start; index < rangeOfEntities.end; index++)
                {
                    Console.Log($"entity {entityIDs[index]} moved from {fromGroup} to {toGroup}");
                    //like for the swap operation, removing entities from the Svelto database is a very common operation.
                    //For both operations is necessary to specify the EntityDescriptor to use. This has also a philosophical
                    //reason to happen, it's to always remind which entity type we are operating with. 
                    _entityFunctions.RemoveEntity<SimpleEntityDescriptor>(new EGID(entityIDs[index], toGroup));
                }
            }

            //the following methods are called by Svelto.ECS when an entity is removed from a group
            public void Remove((uint start, uint end) rangeOfEntities, in EntityCollection<EntityComponent> entities, ExclusiveGroupStruct groupID)
            {
                var (_, entityIDs, _) = entities;

                for (uint index = rangeOfEntities.start; index < rangeOfEntities.end; index++)
                    Console.Log($"entity {entityIDs[index]} removed from {groupID.ToString()}");
            }
        }
    }
}

learn more about svelto on the Wiki page: https://github.com/sebas77/Svelto.ECS/wiki

Svelto.ECS philosophy

Svelto.ECS wasn't born just from the needs of a large team, but also as a result of years of reasoning behind software engineering applied to game development. Svelto.ECS hasn't been created just to write faster code, it has been designed to help developing better code. Performance gains is just one of the benefits in using Svelto.ECS, as ECS is a great way to write cache-friendly code. Svelto.ECS has been developed with the idea of ECS being a paradigm and not just a pattern, helping the user to shift away from Object Oriented Programming with consequent improvements on the code design and code maintainability. Svelto.ECS is the result of years of iteration of the ECS paradigm applied to real game development with the intent to be as foolproof as possible. Svelto.ECS has been designed to be used by a medium-size/large team working on long term projects where the cost of maintainability is relevant.

Is it Archetype? Is it Sparse set? No it's something else :O

Svelto.ECS is loosely based on the Archetype idea. The main difference compared to any other Archetype-based model is that Svelto Archetypes are static, meaning that users cannot add or remove components at runtime. There are many design reasons behind this decision, including the fact that users are often not aware of the costs of structural changes.

While other frameworks typically limit user freedom to avoid exposing flaws in the archetype-based concept, Svelto.ECS introduces the concept of groups. This is simply an explicit way for the user to define sets of entities and iterate through them as quickly as possible.

GroupCompounds build on this idea by allowing users to change the "state"/"set"/"group" according to tags that serve effectively as adjective or state identifiers.

Entities can change state moving between sets swapping them in groups explcitly, rather than changing archetype.

Why using Svelto.ECS with Unity?

Svelto.ECS doens't use a traditional archetype model like DOTS ECS does. The novel hybrid approach based on groups instead than archetypes has been designed to allow the user to take the right decision when it comes to states management. Svelto.ECS doesn't allow archetypes to change dynamically, the user cannot add or remove components after the entity is created. Handling entities states with components can quickly lead to very intensive structural changes operations, so groups have been introduced to avoid the wild explosion of states permutations and let the user see explicitly the cost of their decisions.

Filters have been added to make the handling of multiple states even more flexible by adding a new dimension to subset creation. Using filters it's possible to subset groups while avoiding structural changes (that happens when changing groups in Svelto.ECS too). DOTS engineers also realised this and consequentially introduced the new Enableable components which are less flexible than the Svelto.ECS filters as they implicitly tie the subsets to enabled/disabled components, while Filters in Svelto.ECS don't.

Thanks to the explicit use of Groups and Filters, the Svelto user is able to find the right trade off to handle entities states.

Svelto.ECS is lean. It hasn't been designed to move a whole engine such as Unity from OOP to ECS, therefore it doesn't suffer from unjustifiable complexity overhead to try to solve problems that often are not linked to gameplay development. Svelto.ECS is fundamentally feature complete at this point of writing and new features in new versions are more nice to have than fundamental.

Unity Compatibility

Svelto.ECS is partially compatible with Unity 2019.3.x cycle as long as it's not used with any DOTS package (including collections). It is compatible with all the versions of Unity from 2020 and above.

Svelto.ECS is fully compatible with DOTS Burst and Jobs.

Svelto.ECS is designed to take full advantange of the DOTS modules and to use specifically DOTS ECS as an engine library, through the (optional) SveltoOnDOTS wrapper. Svelto.ECS native components and interfaces are fully compatible with Burst.

Why using Svelto.ECS without Unity?

There are so many c# game engines out there (Stride, Flax, Monogame, FlatRedBall, Evergine, Godot, UniEngine just to mention some) and Svelto.ECS is compatible with all of them!

Performance considerations

Aside from resizing the database absolutely when necessary, all the Svelto operations are memory allocation free. Some containers may need to be preallocated (and then disposed) but those are already advanced scenarios. When using pure ECS (no EntityViewComponents) components are stored in native collections across all the platforms, which means gaining some performance from losing the managed memory checks. With pure ECS, iterating components is automatically cache-friendly.

Note: Svelto.ECS has a ton of allocating run-time checks in debug, so if you want to profile you need to profile a release version or use PROFILE_SVELTO define

If you decide to use Svelto.ECS

Svelto.ECS is an Open Source Project provided as it is, no support is guaranteed other than the help given on the Svelto Discord channel. Issues will be fixed when possible. If you decide to adopt Svelto.ECS, it's assumed you are willing to partecipate to the development of the product if necessary.

Official Examples (A.K.A. where is the documentation?)

Documentation is costly to mantain so check the highly documented and simple mini-examples. Please study them all regardless the platform you intend to use Svelto with.

First of all please check the wiki page:

https://github.com/sebas77/Svelto.ECS/wiki

After that, you can get all the help you need from the official chat:

Official Discord Server (join to get help from me for free!)

but don't forget to check the FAQ AKA Discussions first (all the FAQ like questions will be redirected to Discussions)

https://github.com/sebas77/Svelto.ECS/discussions

Official Articles

Theory related articles (from the most recent to the oldest, read from the oldest if you are new to it):

Practical articles

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.

Users Generated Content (I removed all the outdated articles, so this is a call for new ones!)

Svelto Community Extensions

How to clone the repository:

The folders Svelto.ECS and Svelto.Common, where present, are submodules pointing to the relative repositories. If you find them empty, you need to update them through the submodule command. Check some instructions here: https://github.com/sebas77/Svelto.ECS.Vanilla.Example/wiki

Svelto distributed as Unity Package through OpenUPM openupm

or just install the package that comes from the link https://package-installer.glitch.me/v1/installer/OpenUPM/com.sebaslab.svelto.ecs?registry=https%3A%2F%2Fpackage.openupm.com

this is shown in this example too: https://github.com/sebas77/Svelto.MiniExamples/tree/master/UPM-Integration/UPM

Svelto distributed as Nuget

I am not a Nuget expert, but thanks to our contributors, Svelto.ECS can be found at https://www.nuget.org/packages/Svelto.ECS/

the Hello World example uses the nuget package directly: https://github.com/sebas77/Svelto.MiniExamples/tree/master/Example5-Net-HelloWorld

In case of bugs

Best option is to fork and clone https://github.com/sebas77/Svelto.ECS.Tests, add new tests to reproduce the problem and request a pull. I will then fix the issue. Also feel free to contact me on Discord.

Unity Installation Note:

if you are installing Svelto.ECS manually and not through OUPM, you need to copy the projecs folders under the Package folder like:

image

and add this into your manifest:

,
  "scopedRegistries": [
    {
      "name": "OpenUPM",
      "url": "https://package.openupm.com",
      "scopes": [
        "org.nuget.system.runtime.compilerservices.unsafe"
      ]
    }
  ]

looking like:

{
  "dependencies": {
...
  },
  "scopedRegistries": [
    {
      "name": "OpenUPM",
      "url": "https://package.openupm.com",
      "scopes": [
        "org.nuget.system.runtime.compilerservices.unsafe"
      ]
    }
  ]
}

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, the more we are, the 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: Stride Game, Godot, monogame, FNA or whatever supports c#. Porting to other languages, especially c++, would be awesome but probably pointless. Please check the lane dedicated to the community tasks list here: https://github.com/users/sebas77/projects/3 and let me know if you want to take something on!

Svelto Framework is used to develop the following products(*):

Toy Trains Beyond These Stars Robocraft Techblox Gamecraft Robocraft Infinity Cardlife HoleIo

*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! 🙏👊

svelto.ecs's People

Contributors

blucky87 avatar cathei avatar jlreymendez avatar mgilleronfj avatar sebas77 avatar ujinjinjin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

svelto.ecs's Issues

Does Svelto work without Unity? Any gotchas to keep in mind?

Hi!

We're currently working on a pure C# Authoritative Server for a mobile game, and we're considering the possibility of switching to an ECS architecture. In short: the server is in charge of simulating the game rules. It does that in discrete ticks, which we run via a single entry point function (i.e. an "Update" function that the server infrastructure calls every X milliseconds). The match status is sent over the network with a certain frequency, and it's used by the clients to display the status.

"Pure C#" means that there's no Unity code whatsoever in the server. We do use third-party libraries (the lighter they are in CPU and memory load, the better).

Do you think Svelto would work for us? If I understand correctly, it can be used without Unity. Is that correct? Would we need to do something "special" or to use any workaround for it to work?

Thanks!

Some important reasonings after I released Svelto ECS 2.6

In the Survival Example I use just one EntityDescriptor to create three different types of enemies which is actually good because entities are specialized through data and not code. As matter of fact, this is how ECS should be actually used to take proper advantage of meaningful data iterations.

However, while refactoring the example using Svelto ECS 2.6, I had the chance to see the code under a different point of view and realize that some design decisions could take some advanced reasoning to be understood properly.

Specifically I am talking about what happened to me while refactoring the EnemyDeathEngine CheckIfDead method.

Inside the Svelto ECS database, EntityViewStruct and EntityStructs are not grouped per entity descriptor, this means that if multiple entity descriptors generate the same shared entity view, the array returned by QueryEntities will return all the entity views generated and not just the ones of that specific entity descriptor.

Because entity views can be shared over multiple EntityDescriptors, when an iteration needs to work on different array of different entity views, it's not guaranteed that these arrays can be indexed in the same way.

if I do

- entitiesDB.QueryEntities<EnemyEntityStruct>(out count);
- entitiesDB.QueryEntities<HealthEntityStruct>(out count);
- entitiesDB.QueryEntities<EnemyEntityViewStruct>(out count);

the HealthEntityStruct and the EnemyEntityStruct arrays won't have the same size and won't be indexable in the same way as HealthEntityStruct is generated both by the EnemyEntityDescriptor and the PlayerEntityDescriptor. This is why the QueryMappedEntities function exists, that is to have a way to find entity views through EGID.

On the other hand, since EnemyEntityStruct and EnemyEntityViewStruct are generated exclusively by the EnemyEntityDescriptor, I can guarantee by specification that the two arrays are indexable in the same way. Look at the code

        IEnumerator CheckIfDead()
        {
            var enemyIterationInfo = new FasterList<EnemyIterationInfo>();
            //this struct will allow use zero allocation lambdas. When c# 7 will be available in Unity
            //this will be less awkward thanks to the new local functions feature
            var valueTuple = new LambdaParameters {Item1 = enemyIterationInfo};

            while (true)
            {
                //wait for enemies to be created
                while (entitiesDB.HasAny<EnemyEntityStruct>() == false) yield return null;

                valueTuple.Item2 = entitiesDB.QueryMappedEntities<EnemyEntityViewStruct>();

                entitiesDB.ExecuteOnEntities(ref valueTuple,
                        (ref EnemyEntityStruct enemyStruct, 
                         ref HealthEntityStruct healthEntityStruct, 
                         ref LambdaParameters _parameters) => //this lambda doesn't capture any external variable
                             {
                                 if (healthEntityStruct.dead != true) return;

                                 uint index;
                                 SetParametersForDeath(ref _parameters.Item2.entities(healthEntityStruct.ID, out index)[index]);
                                     
                                 _parameters.Item1.Add(new EnemyIterationInfo(healthEntityStruct.ID,
                                                 (int) ECSGroups.EnemyDisabledGroups + (int) enemyStruct.enemyType));
                             });

...
        } 

The QueryMappedEntities and the way I use the EGIDMapper to pass the parameters to the SetParametersForDeath is not intuitive neither is as fast as indexing directly the array of entity views.
However since performance is not an issue here I can decide to leave it as it is. Leaving as it is in the example could have the unwanted consequence to lead people to think that it's just fine to use this method, although it shouldn't be. Indexing directly should be preferred and in this case EnemyEntityViewStruct can actually be indexed directly. The code could become:

           while (true)
            {
                //wait for enemies to be created
                while (entitiesDB.HasAny<EnemyEntityStruct>() == false) yield return null;

                //fetch the current EnemyEntityViewStruct array, avoid to do it inside the iteration
                //to be faster
                int count;
                valueTuple.Item2 = entitiesDB.QueryEntities<EnemyEntityViewStruct>(out count);

                //iterate over the EnemyEntityStruct and use the healthEntityStruct that are generated by the
                //same entities. Use lambda without catching any external variable so that it won't allocate (which is
                //very important! this will be less awkward when c# 7 is out)
                entitiesDB.ExecuteOnEntities(ref valueTuple,
                        (ref EnemyEntityStruct enemyStruct, 
                         ref HealthEntityStruct healthEntityStruct, 
                         ref LambdaParameters _parameters, int iterationIndex) => 
                             {
                                 if (healthEntityStruct.dead == false) return;

                                 SetParametersForDeath(ref _parameters.Item2[iterationIndex]);
                                     
                                 _parameters.Item1.Add(new EnemyIterationInfo(healthEntityStruct.ID,
                                                 (int) ECSGroups.EnemyDisabledGroups + (int) enemyStruct.enemyType));
                             });

...

                yield return null;
            }

For example in ApplyingDamageToTargetEntitiesEngine ApplyDamage function, DamageableEntityStruct and HealthEntityStruct can be iterated with the same for-loop, because they are generated by the same entity descriptors and there is no entity descriptor that generates just one or the other.

ExecuteOnEntities make the code more awkward, especially with version of c# prior 7 as local functions cannot be exploited. However ExecuteOnEntities can ensure that Swap and Remove won't happen inside the iteration by mistake.

To conclude, I could change the database and introduce functions like entitiesDB.QueryEntities<EnemyEntityDescriptor, EnemyEntityViewStruct> and entitiesDB.QueryEntities<EnemyEntityDescriptor, HealthEntityStruct> so that the returning buffers are guaranteed to be indexable in the same way. It would make also the coder intention clearer, so it wouldn't be bad.

On the other hand it would make engines like ApplyingDamageToTargetEntitiesEngine slower, but probably not as slower as mapping an index for each EGID like it happens in the specialized engines.

If specialized engines are more common than abstract ones it could make sense to move toward this direction.

Since it's a big decision as it would break the current existing Svelto application, I need to know your point of view. If I change it, the QueryEntities function coudn't be used anymore without an EntityDescriptor parameter and for abstract engines it would be necessary to use ExecuteOnEntities to delegate to the framework the task to find the arrays that contains the entity view to iterate on

How should I integrate Nodes into my design process?

I really not understand why nodes are there and how can I keep into account them when designin the game, I feel like I'm missing something really important. There are some obscure points that probably are handled in automatic by Svelto:

  1. Implementors are instantiated by?
  2. Implementors are injected according to what..nodes?

EGID usage

I have a case about entity relations using EGID.

  1. I have a player entity that has many troop entities.
public interface IPlayerTroopComponent
{
         IList <EGID> Troops {get; } // EGID is the troop entity id
}
  1. Some of my Engine will change the group of troop entities.

The problem is: Since EGID is a struct, IPlayerTroopComponent will contains inconsistent groupIds.

What do you think about this?

Svelto.ECS on OpenUPM

Hi @sebas77,

Thanks for creating the amazing project. I'm the creator of OpenUPM, a public upm registry with automatic build pipelines that publish new package bundle based on valid git tags. You can read the announcement on medium to get the basic idea, so far it hosts 90+ packages as of Jan 2020.

UPM offering better version and dependency management, is the future to delivery reusable component in the Unity Engine. I'd like to help you convert your packages to upm format, to be able to publish on git and the OpenUPM platform.

https://github.com/sebas77/Svelto.ECS

  • adding package.json to Svelto.ECS folder
  • adding package.json to Svelto.Services folder
  • since the repo contains two packages, it's better to follow the monorepo practice to use same version string for both Svelto.ECS and Svelto.Services. It will make the GitHub release clean.

https://github.com/sebas77/Svelto.Tasks/

  • adding package.json to Svelto.Tasks folder

https://github.com/sebas77/Svelto.Common

  • already an upm package, cool!
  • however, need change to semantic version (x.y.z is valid semver, x.y is not).

Create GitHub release for all these repositories. (tag as x.y.z)

The changes will

  • enable me/you to submit the package to OpenUPM. (I can do it for you)
  • enable you to use git subtree to generate a clean upm branch for git install (optional)

Thought?

Question on ECS' events

Ciao Sebastiano:)

I've been following Svelto(both IOC and now ECS too) for a while and I found it really interesting and I hope to see soon the next version.

I really like your decision to put events inside components. As long as events are setup in a deterministic way from Engines there's no problem in having events in components, in your ECS example there's a 1to1 relationship between caller and callback (enemy in range triggered by Unity physics, and 1 engine is listening the event).

However, how much freedom do we have in using events that way? How do you see using multiple triggerers and multiple subscribers for the same event?

Let's consider following cases:

* Case 1 (1to1)*

IEnemyTrigger setup an event, PhysicsEngine trigger it (assume I implemented a custom physics engine in c#)

There's 1 to 1 caller/callee corrispondence => could we use instead 2 different interfaces? One is used with an Action setter and the other one is used to call the Action, both interfaces are used each 1 by one engine for the same Entity:

public interface IEnemyTrigger{
    System.Action<GameObject, bool> entityInRange{set;}
}
public interface IPhysTrigger{
    void triggerEntityInRange( GameObject go, bool inRange);
}

public class EnemyTrigger : IEnemyTrigger, IPhysRangeTrigger{
    private PhysAction _entityInRange;
    public PhysAction  IEnemyTrigger.entityInRange { set{ _entityInRange += value;}}
    public void IPhysTrigger.TriggerEntityInRange( GameObject go, bool inRange){
         _entityInRange( go, inRange);
    }
}

* Case 2 (X to Y)*

However what confuses me is what we should do when events are in Y to X correspondondence. How should I design around that? (in example think to an enemy with an Health bar, when enemy dies we should get rid of bar and enemy sprite too, so we have 2 pieces of code that needs to be notified: the enemy sprite and the health bar).

Question about why Svelto's log is default StackTraceLogType.None

I found out that when I use Svelto, Debug.Log doesnt show any StackTrace log. Turns out in SlowLoggerUnity class, stacktraceLog is turn off.

It seems there is no way I could override this feature outside of svelto library.

is there a way I could show StackTrace without editting svelto code?

multiple contexts

Hello.

I want to use the ECS concept described in your articles in my indie game.
But there are some questions I can not solve by myself and asking for your help.

I want to divide the whole game logic into contexts (Svelto.Context) with the maximum encapsulation.
Each context will have its own EnginesRoot.
For example, the context of the quests logic, the context of a player control, the context of the enemies control, the context of the UI control, the context of data working, etc.

But there is a little problem.
I do not see the possibility of achieving the full encapsulation.
For example, quests can turn off enemy spawn in the course of their work because that would not interfere with the player.
But to do this, I need an access to the context of the enemies from the context of the quests. And it breaks the encapsulation and is impossible in the current logic because the contexts use different EnginesRoot.

Or, it will be needed an access to the context of the player from the context of the enemies in order to know about the target to attack.

Could you advise the correct way to exchange data between Context with different EnginesRoot?

We considered an option with a variety of Context and one basic EngineRoot for all entities.
But we didn’t like this option for a number of reasons.
I will be very grateful for your advice and help!

How to install the 2.0 beta 2 release?

The latest release zip (2.0 beta 2) doesn't have a .git folder so git doesn't recognize it as a git repository. Therefore I can't initialize submodules.

[Ask] Why using C# Reflection?

Hello @sebas77,

I just get started using your framework. I like it.

I have question in my mind why are you using C# Reflection?
As we know, reflection is slow.

Discord or Slack?

I want to open a channel to discuss features with you, do you prefer Discord or Slack?

Issue with structs and groups

There is a mistake in the design that I have to fix, because of the nature of the structs, structs saved in groups and in the global DB are of course copies, so that if values are changed in one are not changed in the other. I wonder if I could get away with it storing the structs only in the groups, but then again it won't be possible to write an engine that would act globally on all the structs of the same type.

ICompositionRoot.OnContextDestroyed called twice in Example2-Unity Hybrid-Survival

image

In Example2-Unity Hybrid-Survival, if player dies, RestartGameOnPlayerDeathEngine fires SceneManager.LoadScene, and UnityContext.Awake adds Application.wantsToQuit delegate again. And when I stop the game, then above error occurs.

public class UnityContext<T> : UnityContext where T : class, ICompositionRoot, new()
    {
        void Awake()
        {
            _applicationRoot = new T();

            _applicationRoot.OnContextCreated(this);

            Application.wantsToQuit += IsQuitting;
        }
        
        bool IsQuitting() 
        { 
            _isQuitting = true;
            _applicationRoot.OnContextDestroyed();
            
            return true;
        }
}

I guess the problem is removing IsQuitting function delegate when UnityContext.OnDestroy is called I guess.

Mega change incoming

Now that I have your attention :D

the change is big, but not a breaking one. I am allowing the support of EntityView as structs. Maybe eventually I will be able to merge EntityView and EntityStruct. When EntityView as structs are used like EntityView as class, you have their flexibility but also 0 allocations (well except for the implementors which is the real difference between the two cases).

EntityView as classes will be still supported, but their use strongly discouraged

Svelto.Common submodule is outdated

Svelto.ECS can't be used by itself because it uses the updated DBC1 2 3 namespace while the included Svelto.Common submodule is still using the old DesignByContract namespace. From my testing updating Svelto.Common from its current state to the latest commit clears this particular bug.

Note:
For me it's a bit of a problem using submodules because I can't find a way to prevent submodule recursion in GitKraken. I don't know what the solution to this would be - apart from switching git clients - but for now I will stick to only learning Svelto.ECS and leave Svelto.Tasks for later.

EGID with explicit groupId works incorrectly in case if negative entityId was used

As was shown in your example, I'm using GO.GetInstanceID() to obtain IDs for my entities.
I find it's logical and convenient.

Unity often will return a negative GO ID's, which will result in a problem in cases when the non-default groupId was used to create a new EGID instance.

The problem is in the following code:

        static long MAKE_GLOBAL_ID(int entityId, int groupId)
        {
            return entityId | (long)groupId << 32;
        }

Here , if entityId is negative, it's sign bit will be extended during explicit cast of entityId to long, effectively masking group ID completely. As a result, trying to get back group ID from such EGID instance will always return -1.

Note that C# compiler issues warning about sign bit extension on that line as well:
warning CS0675: Bitwise-or operator used on a sign-extended operand; consider casting to a smaller unsigned type first

Here is a fix which works for me:

        static long MAKE_GLOBAL_ID(int entityId, int groupId)
        {
            return entityId & 0xFFFFFFFF | (long)groupId << 32;
        }

EntityView Terminology

Considering Svelto.ECS 2.0 is still in development, I thought now might be a good time to offer my opinions on some of the terminology used in the framework, before anything gets set in stone.

First of all, I agree that EntityView is a better name than Node, but I still think it is very problematic. I haven't studied your source code yet and I know you plan to write more about it on your blog, but to me "view" could be easily confused with other existing concepts associated with that word.

For example, the Model–view–controller (MVC) pattern uses "view" to mean components that are displayed to the user (graphics) and other ECS frameworks like Entitas refer to any visual representation (Sprites, Models) of entities as views. This all makes a lot of sense to me. There is also the issue of naming; what if I want to call my actual visual representations of entities, like Unity game objects, views? (e.g. PlayerView)

I never looked very deep into your framework before, but I really didn't understand what a Node was at first. However, when I heard the term EntityView I was immediately confused because I thought of the concepts mentioned above.

I also think there are many alternative names that would work much better at representing the concept. Here are a few ideas:

  • Provision
  • Proviso
  • Contract
  • Signature
  • Diagram
  • Archetype
  • Model
  • Mold
  • Motif

I also believe Unity's new ECS is using "Archetype" for a similar system. What are your thoughts on this? Am I just not understanding the concept correctly?

Svelto as .net standard library

I want to start to use c# 7 features, but Unity doesn't support it yet, so I wonder if it would be a problem to distribute the library as dll , maybe inside an unity package. Thoughts?

Mega refactoring incoming

among the other things, I am simplifying the code even more, removing the concept of global entities pool (I need to explain this in depth), introducing EntityViewStructs (They are like the entity view, so they will still need the implementors, but with zero allocation cost).

There are still some pieces that must click in place, but I am getting there.

Incorrect error description thrown

Class(EntityBuilder.CheckFields.cs)
EntityBuilder.CheckFields.Cs on Line 72 describes the error as:
ProcessError("Entity View Structs must hold entity components interfaces", type);
This is incorrect, as the error is thrown when a non-interface is found as a field. This can be confusing, as that's not what the error is checking for. As it was in my case.

I suggest the change to:
ProcessError("Entity View Structs must hold only entity components interfaces", type);

Major refactoring incoming

This refactoring started as result of a design issue regarding how entity IDs should work. I never really cared much about entityID as svelto uses them exclusively to query indexable entity views.

Because I introduced the RemoveEntity without entity descriptor, it could have worked only if globally unique ID were used.

Unluckily Cardlife was already designed to not use unique IDs which caused some issues. In any case the Svelto code wasn't designed to care much about the IDs.

At the same time I wasn't liking the direction the code was taking so I decided to simplify it and at the same time optimize it:

  • Entities are now always built in groups. You can still query all the entityviews regardless the group. If you build an entity without specifying a group, it will be built in a special group
  • Because of this, the RemoveEntity will need to know the group ID of the entity. I am still not sure if I like this, I will need to do some tests
  • I removed the concept of MetaEntites, it was confusing and probably was a practice I should not encourage.
  • I am optimizing the building of entities in general, fixing code and adding comments and new tests

issue with WeakReference<T> when then T is sub class of UnityEngine.Object and issue with method is static in WeakAction

eg.

public class Test : MonoBehaviour
{
    public void A()
    {
        Debug.LogError("A" + name);
    }


    public static void B()
    {
        Debug.LogError("B");
    }

    private void OnDestroy()
    {
        Debug.LogError("B  OnDestroy");
    }
}

var go = new GameObject();
var test = go.AddComponent<Test>();
var t = new WeakReference<Test>(test);
var weakAction = new WeakAction(Test.B);
DestroyImmediate(go);
GC.Collect();

Debug.LogError(t.IsValid);
weakAction.Invoke()

for My way

using System;
using Object = UnityEngine.Object;

public class WeakReference<T> : WeakReference where T : class
{
    private readonly bool _isUnityObject;
    private static readonly Type ObjectType = typeof(Object);

    public bool IsValid
    {
        get { return _isUnityObject ? (Object) base.Target : IsAlive; }
    }

    /// <summary>
    /// Gets or sets the object (the target) referenced by the
    /// current WeakReference{T} object.
    /// </summary>
    public new T Target
    {
        get { return (T) base.Target; }
    }

    /// <summary>
    /// Initializes a new instance of the WeakReference{T} class, referencing
    /// the specified object.
    /// </summary>
    /// <param name="target">The object to reference.</param>
    public WeakReference(T target) : base(target)
    {
        _isUnityObject = typeof(T).IsSubclassOf(ObjectType); // assumption T isn’t  the UnityEngine.Object
    }  
    
    public WeakReference(T target, bool isUnityObject) : base(target)
    {
        _isUnityObject = isUnityObject;
    }
}
using System;
using System.Reflection;
using System.Runtime.CompilerServices;

public class WeakAction<T1, T2> : WeakActionBase
{
    public WeakAction(Action<T1, T2> listener) : base(null)
    {
        var method = listener.Method;
        var isStatic = Method.IsStatic;
        if (!isStatic)
        {
            ActionBase(listener.Target, method, false);
        }
        else
        {
            ActionBase(null, method, true);
        }
    }

    public void Invoke(T1 data1, T2 data2)
    {
        _data[0] = data1;
        _data[1] = data2;

        Invoke_Internal(_data);
    }

    readonly object[] _data = new object[2];
}

public class WeakAction<T> : WeakActionBase
{
    public WeakAction(Action<T> listener) : base(null)
    {
        var method = listener.Method;
        var isStatic = Method.IsStatic;
        if (!isStatic)
        {
            ActionBase(listener.Target, method, false);
        }
        else
        {
            ActionBase(null, method, true);
        }
    }

    public void Invoke(T data)
    {
        _data[0] = data;

        Invoke_Internal(_data);
    }

    readonly object[] _data = new object[1];
}

public class WeakAction : WeakActionBase
{
    public WeakAction(Action listener) : base(listener)
    {
    }

    public WeakAction(object listener, MethodInfo method) : base(null)
    {
        ActionBase(listener, method, method.IsStatic);
    }

    public void Invoke()
    {
        Invoke_Internal(null);
    }
}

public abstract class WeakActionBase
{
    protected WeakReference<object> ObjectRef;
    protected MethodInfo Method;
    private static readonly Type ObjectType = typeof(UnityEngine.Object);
    private bool _isStatic;

    public bool IsValid
    {
        get { return ObjectRef.IsValid; }
    }

    protected WeakActionBase(Action listener)
    {
        if (listener != null)
        {
            var method = listener.Method;
            var isStatic = method.IsStatic;
            if (!isStatic)
            {
                ActionBase(listener.Target, method, false);
            }
            else
            {
                ActionBase(null, method, true);
            }
        }
    }


    protected void ActionBase(object listener, MethodInfo method, bool isStatic)
    {
        Method = method;
        _isStatic = isStatic;
        
        if (!isStatic)
        {
            var isUnityObject = listener.GetType().IsSubclassOf(ObjectType);
            ObjectRef = new WeakReference<object>(listener, isUnityObject);
        }


        if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0)
        {
            throw new ArgumentException("Cannot create weak event to anonymous method with closure.");
        }
    }


    protected void Invoke_Internal(object[] data)
    {
        if (_isStatic)
        {
            Method.Invoke(null, data);
        }
        else if (ObjectRef.IsValid)
        {
            Method.Invoke(ObjectRef.Target, data);
        }
    }
}

QueryEntityViewsAsArray null reference becase its size is changing during iteration.

Ok I found a really minor bug, but maybe it can be useful, maybe it was just a undocumented behaviour

Reproducing the bug:

        int count;
        var views = entityViewsDB.QueryEntityViewsAsArray< GeometrySourceView>(out count);

        for( int i=0; i< count; i++)
        {
            entitiesSink.RemoveEntity( views[i].id.ID); // null reference at some point
        }

When iterating a array of entities taken from the entityViewsDB if I remove them in a loop I get a null reference exception. I didn't investigated yed but I assume the array is resized as long as entities are removed. I expected this kind of stuff to happen only during "SubmitEntityViews" phase.

How I fixed it (basically copying the array locally)

        var views = entityViewsDB.QueryEntityViews< GeometrySourceView>().ToArray(); // linq copy

        for( int i=0; i< views.Count(); i++)
        {
            entitiesSink.RemoveEntity( views[i].id.ID);
        }

Also what's the difference between QueryEntityViews and QueryEntityViewsAsArray? when I should prefer one to the other?

In both cases the array is resized dynamically. Now, using "AsArray" allowed me to find the bug early because of null reference (but in the second code snippet, if I remove the ".ToArray()" I will stop getting the error (of course because "view.Count" changed accordingly) and noticing the bug become harder.

SwapEntityGroup does not work in entity pool scenario

I'm trying to build an entity pool using SwapEntityGroup method.

  1. I'm creating an entity in group of "active entities"
  2. I'm swapping this entity to group of "pooled entities", e.g. "pooling" operation
  3. I'm swapping entity back from "pooled entities" group back to "active entities" group, e.g. "un-pooling"

The 3rd step will fail deep inside during lookup in one of the internal entityview lists.
Here is a pseudo code of my scenario

var entityId = 1
var activeEntitesGroup = 101;
var pooledEntitesGroup = 102;

entityFactory.BuildEntityInGroup(entityId, activeEntitiesGroup, ...);

entityFunctions.SwapEntityGroup(entityId, activeEntitiesGroup, pooledEntitesGroup);

entityFunctions.SwapEntityGroup(entityId, pooledEntitesGroup, activeEntitiesGroup);

As far as I can see this is the conceptual problem with the way how the EGID.GID is used and fact that group ID of the entity does not change after the swap into another group (apparently in attempt to keep GID stable).

I was able to make the above scenario to work by making EGID.GID independent from group ID. I simply made GID to return value of entityID (assuming that entityID should be globally unique) and added groupID as a standalone member variable in EGID struct. This allows to keep EGID.GID stable even if the group of entity has been changed.

The second step I did is to change the group ID of the swapped entity during the swap.
Admittedly, this is not very clean way as it requires to change EGID of the entity. But I think it's important to keep group ID in sync with the group it belongs.

Perhaps it's worth considering to decouple groupID from EGID altogether which will allow it's clean change during the group swap operations?

Any chance something like this might work with UnrealCLR?

Hey there,
I am not sure if you are familiar with UnrealCLR but I was playing around with it today and was quite impressed. Being a big fan of Unitys new DOTS implementations, it made me wonder if an ECS platform that is engine agnostic might be able to be used with UnrealCLR? While it might be a bit unfortunate to not have the ease of use that the Job system can provide, having a well established ECS framework in Unreal using C# sounds pretty exciting to me!

Thanks,
-MH

Fix the Swap and Remove entity logic

Hi,

A problem recently arose regarding the use of the Swap and Remove entity related functions. Since I give the possibility to work directly with arrays to get maximum performance, these functions cannot currently be used inside an iteration because they immediately alter the arrays that store the entities. This means that an array will change while iterating, which would lead to unexpected behaviors. Leaving the responsibility of managing this situation to the user is too much, therefore we need to find a solution and your help would be appreciated.
My current idea is to copy the entity to the new group during a swap, but never remove immediately in any case. I will just mark the item as not valid anymore.
I am not sure which datastructure to use to mark it yet, as it depends if I want to give you some tools to check if an entity is valid or not. These tool would be under the form of different ways of iteration, i.e.: use ExecuteOnEntity would always skip not valid cells.
The real remove then would happen in the next frame, like it happens when submit entities.
The concept of frame is a weird one tho, but that's why you can customize when the entities are submitted overloading the Submission Scheduler behaviour.
In a not too far feature, I want to give the chance to create hierarchical Enginesroot, so that you can encapsulate the code even more and also customize the way entities are submitted.
This could be very helpful in a 100% multithreaded environment.

Using with MonoGame

I am trying to test out this ECS with a simple monogame demo but ran into a problem.
Monogame's Game Class has the Update and Draw methods for the game.

The Update method contains the logic that should be run every frame. The Draw method is run sequentially after the Update is called unless TargetElapsedTime has passed, then it will be skipped.

When setting up a Monogame project to use with Svelto.ECS I would create an EngineRoot with a IEntitySubmissionScheduler that would call a WeakAction's .Invoke() in the Game's Update method. How should I handle the Game's Draw method?

Does anyone have any experience using this library with Monogame?

GenericEntityFunctions and EnginesRoot relation

_weakReference.Target.RemoveEntity<T>(entityID);

GenericEntityFunctions.RemoveEntityFromGroup<>() call EnginesRoot.RemoveEntity<T>() instead of EnginesRoot.RemoveEntityFromGroup<T>()

_weakReference.Target.RemoveEntity<T>(metaEntityID);

GenericEntityFunctions.RemoveMetaEntity<T>() call EnginesRoot.RemoveEntity<T>() instead of EnginesRoot.RemoveMetaEntity<T>()

Are they bugs?
I don't understand exactly how the internal framework work, but GenericEntityFunctions.RemoveEntityFromGroup<T> seemed to be calling EnginesRoot.RemoveEntityFromGroup<T>.

Cannot restart an IEnumerator without a valid Reset function

Hello Thank for Svelto.ECS i am a newbie.
I tried to with Photon,Yeah it so excellent but I don't know solve problem "Cannot restart an IEnumerator without a valid Reset function, use SetEnumeratorProvider instead" Occurs when player host room disconnected already other players will get this error

w

my code adapt from Svelto.ECS.Examples.Survival What should i do to solve this problem?
Thanks

Recreate entity with same id

           _entityFactory.BuildEntity<HouseBuildingEntityDescriptor>(101, null);
            yield return new WaitForSecondsEnumerator(2);
            _entityFunctions.RemoveEntity(101);
            yield return new WaitForSecondsEnumerator(2);
            _entityFactory.BuildEntity<HouseBuildingEntityDescriptor>(101, null);

i have error, FasterDictionaryException: Key already present.

Why i can't recreate entity with same id?

Missing `UnityEngine' using directive

GameObject debugEngineObject = new GameObject("Engine Debugger");

When enable engine profiler, it show error

Svelto-ECS/ECS/EnginesRoot.cs(52,4): error CS0246: The type or namespace name GameObject' could not be found. Are you missing UnityEngine' using directive?

It should changed to this

UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject ("Engine Debugger");

NuGet package?

I really love this project.

Are there any plans for Svelto.ECS to be released as a NuGet package?

Will RemoveEntity<T> remove entity from its group?

I created an entity with specific id and group, and then remove the entity. But when i was creating same entity id and group, it threw this error

ArgumentException: An item with the same key has already been added.
System.ThrowHelper.ThrowArgumentException (System.ExceptionResource resource) (at /Users/builduser/buildslave/mono/build/mcs/class/referencesource/mscorlib/system/throwhelper.cs:72)
System.Collections.Generic.Dictionary`2[TKey,TValue].Insert (TKey key, TValue value, System.Boolean add) (at /Users/builduser/buildslave/mono/build/mcs/class/referencesource/mscorlib/system/collections/generic/dictionary.cs:336)
System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at /Users/builduser/buildslave/mono/build/mcs/class/referencesource/mscorlib/system/collections/generic/dictionary.cs:192)
Svelto.ECS.EnginesRoot.AddEntityViewsToGroupDB (System.Collections.Generic.Dictionary`2[TKey,TValue] groupEntityViewsDB, System.Collections.Generic.KeyValuePair`2[TKey,TValue] group) (at Assets/Extension/Svelto.ECS/EnginesRootSubmission.cs:106)
Svelto.ECS.EnginesRoot.AddGroupEntityViewsToTheDBAndSuitableEngines (System.Collections.Generic.Dictionary`2[TKey,TValue] groupedEntityViewsToAdd, System.Collections.Generic.Dictionary`2[TKey,TValue] groupEntityViewsDB, System.Collections.Generic.Dictionary`2[TKey,TValue] entityViewsDB) (at Assets/Extension/Svelto.ECS/EnginesRootSubmission.cs:90)
Svelto.ECS.EnginesRoot.SubmitEntityViews () (at Assets/Extension/Svelto.ECS/EnginesRootSubmission.cs:39)
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:305)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:313)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at /Users/builduser/buildslave/mono/build/mcs/class/referencesource/mscorlib/system/reflection/methodbase.cs:229)
Svelto.WeakEvents.WeakActionBase.Invoke_Internal (System.Object[] data) (at Assets/Extension/Svelto.Common/WeakEvents/WeakAction.cs:91)
Svelto.WeakEvents.WeakAction.Invoke () (at Assets/Extension/Svelto.Common/WeakEvents/WeakAction.cs:50)
Svelto.ECS.Schedulers.Unity.UnitySumbmissionEntityViewScheduler+Scheduler+<Start>c__Iterator0.MoveNext () (at Assets/Extension/Svelto.ECS/Extensions/Unity/UnitySumbmissionEntityViewScheduler .cs:39)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)

Does this mean that the entity is not removed from its group?

Update to 3.1.0 bug on Extension UECS

When Update from 3.0.3 to 3.1.0 get error, cannot detect assembly form DOT\Job

Library\PackageCache\[email protected]\Extensions\Unity\DOTS\UECS\IUECSSubmissionEngine.cs(8,58): error CS0246: The type or namespace name 'IJobifiedEngine' could not be found (are you missing a using directive or an assembly reference?)
Library\PackageCache\[email protected]\Extensions\Unity\DOTS\UECS\SveltoOverUECSEnginesGroup.cs(26,46): error CS0246: The type or namespace name 'IJobifiedEngine' could not be found (are you missing a using directive or an assembly reference?)
Library\PackageCache\[email protected]\Extensions\Unity\DOTS\UECS\SyncSveltoToUECSGroup.cs(7,42): error CS0246: The type or namespace name 'JobifiedEnginesGroup<>' could not be found (are you missing a using directive or an assembly reference?)
Library\PackageCache\[email protected]\Extensions\Unity\DOTS\UECS\SyncSveltoToUECSGroup.cs(11,64): error CS0246: The type or namespace name 'IJobifiedEngine' could not be found (are you missing a using directive or an assembly reference?)
Library\PackageCache\[email protected]\Extensions\Unity\DOTS\UECS\SyncUECSToSveltoGroup.cs(7,42): error CS0246: The type or namespace name 'JobifiedEnginesGroup<>' could not be found (are you missing a using directive or an assembly reference?)
Library\PackageCache\[email protected]\Extensions\Unity\DOTS\UECS\SyncUECSToSveltoGroup.cs(12,64): error CS0246: The type or namespace name 'IJobifiedEngine' could not be found (are you missing a using directive or an assembly reference?)

using UnityEngine Namespace

currently
Common/Components/ECSRect.cs
Extensions/Unity/GenericEntityDescriptorHolder.cs

have the 'Using UnityEngine' namespace requirements. I am trying to use the library with monogame and ran into this issue.

PreconditionException: from group not found

Because SubmitEntityViews is not called immediately. Delete the entity just created before the SubmitEntityViews call, it will throw an exception.

PreconditionException: from group not found
DBC.ECS.Check.Require (Boolean assertion, System.String message) (at Assets/Plugins/Svelto.ECS/DBC.cs:70)
Svelto.ECS.EnginesRoot.MoveEntity (Svelto.ECS.IEntityBuilder[] entityBuilders, EGID entityGID, Int32 toGroupID, System.Collections.Generic.Dictionary`2 toGroup) (at Assets/Plugins/Svelto.ECS/Svelto.ECS/EnginesRoot.Entities.cs:144)
Svelto.ECS.EnginesRoot.SubmitEntityViews () (at Assets/Plugins/Svelto.ECS/Svelto.ECS/EnginesRoot.Submission.cs:28)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)

nuget package is compiled as debug

Hey, your nuget-release github action pushs non optimized binaries as the dotnet pack command use the default configuration Debug, you should pass -c Release as argument (same for Svelto.Common).
Also you reference the package System.Runtime.CompilerServices.Unsafe version 4.6.0-preview8.19405.3 when there is newer non-prerelease versions available.

Probably not your priority as this is outside of Unity scope but I thought I would let you know :) Tried to make a benchmark of your framework with other ECS solution and BenchmarkDotNet complained about it.

Unity 5.5.0 breaks Svelto

Profiling has moved to UnityEngine.Profiling namespace, as result

GameObjectFactory.cs, Line 51

do not compile because it can't find the "Profiler" name.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.