Hi, I hope you’re all doing well. I’m trying to implement pathfinding in my ECS + Netcode for Entities project—a combination that’s not exactly straightforward. For pathfinding, I’m using the Agent Navigation asset and the A* Project.
I’ve placed the AstarPath component outside the subscene, while all the scene decorations are inside the subscene. I’m using the Recast Graph to generate the grid, and my agents are instantiated at runtime in random positions. Of course, these are entities, not GameObjects.
When my entity is instantiated, the log shows the error message in question. Then, when I set a destination for my agent, the messages multiply for each node, but the entity moves in a random direction rather than toward the destination I set.
If I instead generate a startup cache on AstarPath, I don’t get any error messages in the log. However, the agent still moves randomly.
Is this something you’ve noticed and resolved? Could Unity.Physics be causing issues? The package is supposed to be compatible with DOTS.
Sorry for all the questions, but I’m trying to avoid building the pathfinding system myself.
Path Failed : Computation Time 0.00 ms Searched Nodes 0
Error: Couldn't find a node close to the start point
Path Number 363 (unique id)
UnityEngine.Debug:LogWarning (object)
AstarPath:LogPathResults (Pathfinding.Path) (at ./Packages/com.arongranberg.astar/Core/AstarPath.cs:829)
AstarPath:<.ctor>b84_3 (Pathfinding.Path) (at ./Packages/com.arongranberg.astar/Core/AstarPath.cs:645)
Pathfinding.PathProcessor:CalculatePathsThreaded (Pathfinding.PathHandler,Pathfinding.Sync.BlockableChannel`1/Receiver<Pathfinding.Path>) (at ./Packages/com.arongranberg.astar/Core/Pathfinding/PathProcessor.cs:367)
Pathfinding.PathProcessor/<>cDisplayClass27_0:<StartThreads>b__0 () (at ./Packages/com.arongranberg.astar/Core/Pathfinding/PathProcessor.cs:122)
System.Threading.ThreadHelper:ThreadStart ()
It seems to be related to the use of Netcode for Entities and the separation between client and server. However, I’m trying to figure out if it’s a configuration issue instead.
Would you be able to see if this happens in a project not using Netcode for Entities? I’m wondering if this is an issue with subscenes rather than Netcode.
Unfortunately, I can’t easily replicate the same conditions in a project without Netcode, but I noticed that if I place the AstarPath in the subscene, the error disappears. However, in both cases, the movement of my unit works fine, despite the multitude of warnings. Is there any information I can provide to help you assess the issue?
Can you send over the project? I want to see if I have the same errors. Tried to recreate it but I don’t know the full structure so it’s probs just better if sent over.
I have had similar behavior with my pure entity units when the subscene is enabled. I forget what the error I get is though. If your subscene is enabled when you test, try disabling it.
One other thing to note, AstarPath cannot use anything in a subscene to bake the graph. So you need to bake it in the editor with the subscene enabled, then turn off AstarPath bake on start (or whatever that setting is called) or else the editor bake gets overwritten when the game starts.
Now I understand the reason behind this behavior and why dynamic obstacles don’t work. How did you solve the issue with dynamic obstacles? Did you also place them outside the subscene?
I havent used any dynamic obstacles, but I assume it would be similar to Navmesh Cut which you do need a gameobject for. Something similar to that system I showed in the other thread, but with the gameobject moving with the entity.
Well, I created a hybrid GameObject for all the dynamic obstacles, but it doesn’t work. I think it’s partly my lack of knowledge about how to use the A* package and perhaps also a lack of full compatibility with Netcode for Entities, which isn’t exactly a user-friendly system. I think, in the end, a system is needed that’s not only ECS-based but also tested with Netcode. However, I don’t expect major advancements since it’s a young system for Unity—imagine what it’s like for external ones.
I see the error on my end now, thanks for the sample! So yeah, like @Curtis said (thanks for the assist!) It looks like Astar isn’t able to scan inside the subscene- even when I spawn a unit in the sample and give it a destination, it really doesn’t care about the obstacles. And when I move AstarPath inside the sub scene, it works fine
As an aside I never got an agent moving “randomly”- can you post a video of that?
Ok, I dabbled with DynamicObstacle and it was acting odd for me. It seems to just remove from the navmesh and wasn’t respecting the collider bounds.
So I made some changes to my NavmeshCutSystem so that position and rotation can be updated. I think the only changes you have to make for Netcode is to determine which world the system should be run (client/server/both). I don’t know much about this though other than it has something to do with Group flags similar to how I do with TransformSystemGroup.
Components + System
using Unity.Collections;
using Unity.Entities;
using Unity.Transforms;
using UnityEngine;
public class NavmeshCutData : IComponentData
{
public GameObject NavmeshCutGO;
public bool UpdatePosition;
public bool UpdateRotation;
}
public class NavmeshCutLink : ICleanupComponentData
{
public GameObject NavmeshCutGO;
}
[UpdateInGroup(typeof(TransformSystemGroup))]
public partial struct NavmeshCutSystem : ISystem
{
void OnUpdate(ref SystemState state)
{
var ecb = new EntityCommandBuffer(Allocator.Temp);
//Create a gameobject navmesh cutter for those without links setup
foreach (var (navmeshCutter, localTransform, entity) in SystemAPI.Query<NavmeshCutData, LocalTransform>().WithNone<NavmeshCutLink>().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 NavmeshCutLink { NavmeshCutGO = instance });
}
//Update the linked navmesh cut to match the entity
foreach (var (navmeshCut, navmeshCutLink, localTransform) in SystemAPI.Query<NavmeshCutData, NavmeshCutLink, LocalTransform>())
{
if (navmeshCutLink.NavmeshCutGO != null)
{
if (navmeshCut.UpdatePosition)
{
navmeshCutLink.NavmeshCutGO.transform.position = localTransform.Position;
}
if (navmeshCut.UpdateRotation)
{
navmeshCutLink.NavmeshCutGO.transform.rotation = localTransform.Rotation;
}
}
}
//Any links that no longer have NavmeshCutData have been destroyed, the linked gameobjects needs to be destroyed and cleaned up
foreach (var (navmeshCutLink, entity) in SystemAPI.Query<NavmeshCutLink>().WithNone<NavmeshCutData>().WithEntityAccess())
{
GameObject.Destroy(navmeshCutLink.NavmeshCutGO);
ecb.RemoveComponent(entity, new ComponentTypeSet(typeof(NavmeshCutLink)));
}
ecb.Playback(state.EntityManager);
ecb.Dispose();
}
}
Authoring
using Pathfinding;
using Unity.Entities;
using UnityEngine;
//Entities need gameobjects with a NavmeshCut to modify the navmesh
public class NavmeshCutAuthoring : MonoBehaviour
{
public NavmeshCut navmeshCut;
public bool updatePosition;
public bool updateRotation;
public class Baker : Baker<NavmeshCutAuthoring>
{
public override void Bake(NavmeshCutAuthoring authoring)
{
Entity entity = GetEntity(TransformUsageFlags.Dynamic);
AddComponentObject(entity, new NavmeshCutData {
NavmeshCutGO = authoring.navmeshCut.gameObject,
UpdatePosition = authoring.updatePosition,
UpdateRotation = authoring.updateRotation
});
}
}
}
Setup
Add the authoring to the entity
Create a separate child on the entity with only a NavmeshCut
Assign the child to the authoring
Move the entity around at runtime and the cut should follow it.
Note: Run in editor with the subscene disabled. If you run enabled there is a second cut that stays at the start position. Not exactly sure why, I think everything exists as both a GameObject and an Entity when you leave the subscene enabled.
I haven’t tested this in depth, but it’s working for my simple reposition test with default box NavmeshCut. If you need tons of moving obstacles, it could be improved by turning the update positioning loop into a ParallelJob.
First of all, thanks! I’ll try implementing your solution directly in my main project. I’m really behind on development and need to catch up.
Regarding Netcode, the world where it should be placed is the ServerWorld. This is because, being a server-authoritative system, the only actions allowed for clients are sending input to the server. Everything else is centralized on the server world.
Theoretically, you could put the entire NavMesh on the server because the server itself decides how to replicate movements to the client.
Anyway, I’ll let you know if it works for me or not!
I implemented your solution, but I’m getting completely different behavior. At this point, I think it might be an issue with the Unity.Physics component, but that’s just a gut feeling.
No, no, physics in Netcode is much less managed. To make a raycast work, you need to add the NetCodePhysicsConfig script to use lag compensation; otherwise, the ray just passes through the object. It gives me the impression that everything is a bit unstable.
For example, colliders are converted into PhysicsCollider. It wouldn’t surprise me if I found out that I’m handling that aspect incorrectly.
That could be, I don’t use any physics at all. I use a hashmap system since its way more efficient at the cost of some precision.
I think it’s more likely the Netcode, probably something is running on the client still that is conflicting with the server. I have had this happen before and it causes some weird bugs. When I did some work with Fishnet on a different project I removed everything from prefabs that wasn’t needed on the client just to avoid these situations.
Might be worth trying to get basic pathfinding features you need working locally with no Netcode or physics, then upgrading it one piece at a time to see where the problems start. If Netcode is causing headaches it might be worth trying more stable networking systems like Fishnet. I tried Netcode for Entities for a few days and just ended up frustrated, but Fishnet was easy to understand and build upon.