I’m new to ECS (Aren’t we all?) and I was experimenting with it this morning.
I was trying to understand how best to “bootstrap” the game in a “Pure ECS” way. I figured that using a System’s OnCreate method is probably the best way to start, but in practice I discovered that the System’s OnCreate method was getting called twice.
After a few sanity checks, it would appear that my system is getting instantiated more than once. What would cause that? I thought by definition systems would be created once.
Edit: Using Unity.Entities Version 0.14.0-preview.19 - September 10, 2020
Hmm. I’ve also installed (but haven’t begun using) NetCode Version 0.4.0-preview.1 - September 17, 2020. Besides the default world, there is a server and a client world that are created by NetCode. Could that be the culprit?
Why wouldn’t it have created three instances of the system then?
Is there a way to see which world loaded which system?
That could be, but I never used NetCode, so can’t tell for sure why only 2 are being created (my assumption is that Default world is either the Client or the Server world, but can’t tell for sure).
So this was definitely the root cause; both the client and the server world had spun up an instance of MainSystem. I can see how this would be desirable.
So in NetCode, instead of Defaultworld, should I be creating the entities in whatever world the system is running in? How do I get the entity manager for the “hosting” world?
The entity manager on the system base should be the one from the world in which the system is.
I think you can tell with an attribute if you want your system to be added to the client or server world (or both).
Here’s the documentation that describes why your system is instantiated twice and how you can specify for which world it should be created: Client server Worlds | Unity NetCode | 0.4.0-preview.1 (“By default, NetCode places systems in both client and server Worlds, but not in the default World.”)
By default NetCode creates two different Worlds; one for the client, and one for the server. You can use the UpdateInWorld attribute on your system to limit which worlds it runs in. For example, to limit it only to the client, you would use:
[UpdateInGroup(typeof(ClientPresentationSystemGroup))]
public class MySystem : SystemBase
{...
In my situation, I saw the Entity being created twice because I was following tutorials that are likely outdated, or didn’t take into account NetCode.
Nearly every tutorial online uses something like this:
var em = World.DefaultGameObjectInjectionWorld.EntityManager;
var ent = em.CreateEntity();
Since I was following those tutorials, the system running in the server world and the system running in the client world were each creating an entity in the default world.
If you want to instead create an entity in the world that the system is currently running in, use:
var em = World.EntityManager;
var ent = em.CreateEntity();
Or, even more concise:
var ent = World.EntityManager.CreateEntity();
Hope this helps you!
Thanks again to @brunocoimbra who had the correct suggestion above.