NavMeshCut and Pure ECS

I am using Pure ECS (so no GO in hierarchy) and am able to get an AI Script to work on my recast graph. The only issue I am having now is the NavMeshCut. I cant seem to strip it away from its base monobehavior (mainly because it needs a transform to act on I think). Has any one got the NavMeshCut to work without being attached to a GO or have any other suggestions?

So for more details, I have a NavMeshCut on my prefab and have it injected onto my Entity. But it wont function correctly and I cant subclass it to get it to work. It has internal marked methods that block me from overriding some methods using the transform (that for me is null). I am using the latest version “Version 4.3.35”. Thanks.

May need a ECS category for you topics. :slight_smile:

Hi

Right now this is impossible I’m afraid. You’d need to change some things deeper in the system for that to work.

Hey Aron,

No problem, in the end I just went back to Hybrid, using something like: conversionSystem.AddHybridComponent(seeker).

That seems to be a good compromise between GO and ECS. Its just unrealistic for us to go to pure ECS right now, the work vs the reward is NOT there for our situation.

1 Like

I too gave up on trying to do navmesh cutting without game objects. It’s lame having game objects just sitting around for no reason other than cutting a navmesh, but I couldn’t find any way around it. I ended up switching to the Agents Navigation package (which is built specifically for ECS) instead of A* Pathfinding Project, but it also has the same problem with navmesh cutting requiring game objects.

If your looking for something closer to pure ECS I made this authoring component that handles a NavmeshCut Gameobject for an Entity prefab. You can just add the authoring then create and assign a NavmeshCut child on your Entity prefab.

using Pathfinding;
using Unity.Collections;
using Unity.Entities;
using Unity.Transforms;
using UnityEngine;

//Entities need gameobjects with a NavmeshCut to modify the navmesh
public class NavmeshCutAuthoring : MonoBehaviour
{
    public NavmeshCut navmeshCut;

    public class Baker : Baker<NavmeshCutAuthoring>
    {
        public override void Bake(NavmeshCutAuthoring authoring)
        {
            Entity entity = GetEntity(TransformUsageFlags.Dynamic);
            AddComponentObject(entity, new NavmeshCutter { NavmeshCutGO = authoring.navmeshCut.gameObject });
        }
    }
}

public class NavmeshCutter : IComponentData 
{
    public GameObject NavmeshCutGO;
}

public class NavmeshCutterCleanup : ICleanupComponentData
{
    public GameObject NavmeshCutGO;
}

public partial struct NavmeshCutterSystem : ISystem
{
    void OnUpdate(ref SystemState state)
    {
        var world = World.DefaultGameObjectInjectionWorld;
        var ecb = new EntityCommandBuffer(Allocator.Temp);

        //Create a gameobject navmesh cutter for those without cleanups
        foreach (var (navmeshCutter, localTransform, entity) in SystemAPI.Query<NavmeshCutter, LocalTransform>().WithNone<NavmeshCutterCleanup>().WithEntityAccess())
        {
            var instance = GameObject.Instantiate(navmeshCutter.NavmeshCutGO, localTransform.Position, localTransform.Rotation);
            ecb.AddComponent(entity, new NavmeshCutterCleanup { NavmeshCutGO = instance });
        }

        //Any cleanups that no longer have NavmeshCutter have been destroyed, the navmeshcutter gameobjects needs to be destroyed and cleaned up
        foreach (var (navmeshCutContainer, entity) in SystemAPI.Query<NavmeshCutterCleanup>().WithNone<NavmeshCutter>().WithEntityAccess())
        {
            GameObject.Destroy(navmeshCutContainer.NavmeshCutGO);
            ecb.RemoveComponent(entity, new ComponentTypeSet(typeof(NavmeshCutterCleanup)));
        }
        ecb.Playback(world.EntityManager);
        ecb.Dispose();
    }
}

Fixed a bug in the NavmeshCutterSystem. It was creating some duplicates depending on the initial state of a subscene containing these cutters. Not exactly sure why but this seems to at least clean them up.

[UpdateInGroup(typeof(TransformSystemGroup))]
public partial struct NavmeshCutterSystem : ISystem
{
    void OnUpdate(ref SystemState state)
    {
        var world = World.DefaultGameObjectInjectionWorld;
        var ecb = new EntityCommandBuffer(Allocator.Temp);

        //Create a gameobject navmesh cutter for those without cleanups
        foreach (var (navmeshCutter, localTransform, entity) in SystemAPI.Query<NavmeshCutter, LocalTransform>().WithNone<NavmeshCutterCleanup>().WithEntityAccess())
        {
            GameObject instance = GameObject.Instantiate(navmeshCutter.NavmeshCutGO, localTransform.Position, localTransform.Rotation);
            //Sometimes duplicates are created at world center if the subscene is disabled in the hierarchy
            if (!navmeshCutter.NavmeshCutGO.scene.isSubScene)
            {
                GameObject.Destroy(navmeshCutter.NavmeshCutGO);
            }
            ecb.AddComponent(entity, new NavmeshCutterCleanup { NavmeshCutGO = instance });
        }

        //Any cleanups that no longer have NavmeshCutter have been destroyed, the navmeshcutter gameobjects needs to be destroyed and cleaned up
        foreach (var (navmeshCutContainer, entity) in SystemAPI.Query<NavmeshCutterCleanup>().WithNone<NavmeshCutter>().WithEntityAccess())
        {
            GameObject.Destroy(navmeshCutContainer.NavmeshCutGO);
            ecb.RemoveComponent(entity, new ComponentTypeSet(typeof(NavmeshCutterCleanup)));
        }
        ecb.Playback(world.EntityManager);
        ecb.Dispose();
    }
}