Search Unity

Serializing NavMeshPaths to sync NavAgents across the network

Discussion in 'Navigation' started by sonderistic, Jun 4, 2019.

  1. sonderistic

    sonderistic

    Joined:
    Jan 4, 2017
    Posts:
    6
    Hello, as the title states, I'm trying to serialize NavMeshPaths so I can send it through the network. However, the class doesn't seem to support serialization. Has anyone accomplished this? The reason for this is so I can calculate paths on the Server and merely distribute the paths to the clients who will set their nav agents with the correct paths.

    An alternative to this which I am aware of is to instead send the destination to the clients but, I'm pretty sure that there is bound to be some discrepancy in the paths the AIs take. I also would not like to sync their positions because I wish to use root motion for each client (I've heard that root motion and network transform / lerping do not play well together).

    I've spent the better part of the month trying to find a solution to this issue. Any help would be greatly appreciated. Also, below is the error when trying to serialize a NavMeshPath.



    SerializationException: Type 'UnityEngine.AI.NavMeshPath' in Assembly 'UnityEngine.AIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
    System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers (System.RuntimeType type) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.FormatterServices+<>c__DisplayClass9_0.<GetSerializableMembers>b__0 (System.Runtime.Serialization.MemberHolder _) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.FormatterServices.GetSerializableMembers (System.Type type, System.Runtime.Serialization.StreamingContext context) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo () (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize (System.Object obj, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.Formatters.Binary.ObjectWriter objectWriter, System.Runtime.Serialization.SerializationBinder binder) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize (System.Object obj, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.Formatters.Binary.ObjectWriter objectWriter, System.Runtime.Serialization.SerializationBinder binder) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo typeNameInfo) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize (System.Object graph, System.Runtime.Remoting.Messaging.Header[] inHeaders, System.Runtime.Serialization.Formatters.Binary.__BinaryWriter serWriter, System.Boolean fCheck) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers, System.Boolean fCheck) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    ZombieServer.SerializeForNetwork (System.Object obj) (at Assets/_Testing/Bryan/BRB Zombies/Scripts/ZombieServer.cs:67)
    ZombieServer.SendUpdatedPathToClients (System.UInt16 zombieNetID, UnityEngine.AI.NavMeshPath path) (at Assets/_Testing/Bryan/BRB Zombies/Scripts/ZombieServer.cs:83)
    ZombieBrain.Update () (at Assets/_Testing/Bryan/BRB Zombies/Scripts/ZombieAI/ZombieBrain.cs:47)
     
  2. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    2,407
    The approach isn't necessary. You could serialize the corners and then issue new path requests along those on the client, but pathfinding itself is mostly deterministic. Sending destinations works fine.

    But crowd handling is not deterministic so that is really the main issue with your approach. You can't have client side pathfinding using the built in agents and have it be deterministic.

    The right approach here if your server is calculating paths is to just send position updates and use network interpolation on the client. Your client side characters won't be agents, just a transform and maybe a collider if needed and with a script moving them directly.