miwarnec / DOTSNET

Public DOTSNET issue tracker
20 stars 0 forks source link

Add support for Companion Game Objects #10

Closed gabrjt closed 4 years ago

gabrjt commented 4 years ago

The conversion systems have a nice feature for supporting hybrid entities with GameObjects and MonoBehaviours.

While in conversion, a hybrid component can be added by calling conversionSystem.AddHybridComponent(Camera); for example. More details can be found at gametorrahod.com.

However, they are not working out of the box with DOTSNET since there is a custom bootstrap and many of these conversion/hybrid support systems have no namespace.

I've managed to get them working with an error prone workaround by changing the Bootstrap to consider systems that have "Companion"in their name as Unity Systems. I hope Unity will add them to a proper namespace in the future and they will work out of the box with current DOTSNET Bootstrap.

Bootstrap.cs

public static void CategorizeSystems(IReadOnlyList<Type> systems, out List<Type> unitySystems, out List<Type> regularSystems, out List<Type> serverSystems, out List<Type> clientSystems)
...
// [ServerWorld]?
else if (SystemHasAttribute(system, typeof(ServerWorldAttribute)))
{
    serverSystems.Add(system);
}
// [ClientWorld]?
else if (SystemHasAttribute(system, typeof(ClientWorldAttribute)) || system.Namespace == "Unity.Rendering")
{
    clientSystems.Add(system);
}
// no tag, in Unity namespace or name contains "Companion"?
else if (system.Namespace != null && system.Namespace.StartsWith("Unity.") || system.Name.Contains("Companion"))
{
    unitySystems.Add(system);
}
...
miwarnec commented 4 years ago

hey. I never used that feature. can you explain why this is necessary / how this would stop us from releasing a game?

my goal is to go pure ECS as far as possible since we'll need to replace Hybrid with pure ECS at some point anyway.

gabrjt commented 4 years ago

Sure!

So this conversionSystem.AddHybridComponent() feature is similar to EntityManager.AddComponentObject(), but instead of linking a reference to the Component from a GameObject in the scene to the entity, the GameObject with the added HybridComponents is converted and embed into the ECS World, it even disappears from the hierarchy, making thinks more simple and without having to worry about managing the GO manually.

It's from Unity ECS, and I think there's still a long road ahead of us to convert all features to pure DOTS, so it may be worth using it in the meantime. It should already have been working out of the box if Unity added these systems in a proper Unity namespace...

However, I've been using it mostly for client side stuff. Everything in the server so far is pure ECS. Even though server and client worlds share the same prefab, I did some custom logic in order to convert specific components only to a target world, like art stuff or data that does not need to exist in the client.

So suppose you have a prefab that has a particle system. Instead of keeping a GameObject in the scene with the particle system and linking it to the entity with AddComponentObject or ConvertAndInject, you can use the AddHybridComponent when converting and the particle system will be converted for the target entity, allowing it to be queried in a system where you can control its behaviour.

Here's a sample that I've used for my network entity spectator camera. Only the owned client entity instantiates a camera entity which is linked to the network entity. This way the camera is self contained in the prefab and I don't have to switch cameras for different situations, parameters, hierarchy structure or controlled entities, also without having to worry about manually setting the camera transform based on the entity transform.

using DOTSNET;
using Unity.Entities;
using UnityEngine;

[RequireComponent(typeof(Camera), typeof(AudioListener))]
public class CameraAuthoring : MonoBehaviour, IConvertGameObjectToEntity
{
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        if (dstManager.World != Bootstrap.ClientWorld) return;

        var camera = GetComponent<Camera>();

        if (camera.CompareTag("MainCamera"))
        {
            dstManager.AddComponent<MainCamera>(entity);
        }

        conversionSystem.AddHybridComponent(camera);
        conversionSystem.AddHybridComponent(GetComponent<AudioListener>());
    }
}

Here's the inspector for the camera entity from the Entity Debugger. The camera GO no longer exists in the hierarchy.

Screen Shot 2020-07-22 at 14 47 09
miwarnec commented 4 years ago

@gabrjt fix is in V1.14. thanks for explanation, very helpful!