Handling serialization of vector 3 (Unity / Mirror networking)

Viewed 164

I am learning how to make a multiplayer game in Unity and I'm leveraging Mirror to handle networking. It is a point and click game that uses pathfinding (A*). The player selects a tile game object to move towards. My 'tiles' in this instance are just game objects in the scene with a script attached with basic properties for the pathfinding.

public class OverlayTile : MonoBehaviour
{
    [SerializeField] public int G;
    [SerializeField] public int H;

    public int F { get { return G + H; } }

    [SerializeField] public bool isBlocked;

    [SerializeField] public OverlayTile previous;

    [SerializeField] public Vector3Int gridLocation;

I have a function that makes a call from my player to the server to move towards a tile. Because I have a custom type for a list in my parameter (custom type OverlayTile) I have to handle serialization on my own. Custom types are not supported out of the box by Mirror. Currently I get this error without handling the serialization: NullReferenceException at (wrapper managed-to-native) UnityEngine.Component.get_transform(UnityEngine.Component). In the Mirror docs it says: Types that Inherit from UnityEngine.Component are not supported. So this to me seems the cause of my error.

So I have been trying to figure out how to support serialization for transform on my own. I have looked at examples on the official Mirror docs, they have an example for collisions on rigid bodies. I have tried to translate this approach to Transform, but I keep getting that above error. I am continually trying to figure this out on my own through trial and error but my brain is really starting to hurt. Any advice/input would be deeply appreciated. I have no clue if I am even going in the right direction here, if I even need a rigidbody in my struct.. The only source of reference that I can find at all that I've been modeling my approach is in the Mirror docs (https://mirror-networking.gitbook.io/docs/guides/serialization)

This is the function making a call to the server with the custom list type parameter:

[Command]
public void CmdMoveAlongPath(List<OverlayTile> path)
{
    var step = moveSpeed * Time.deltaTime;

    var zIndex = path[0].transform.position.z;

    character.transform.position =
        Vector2.MoveTowards(character.transform.position, path[0].transform.position, step);

    if (Vector2.Distance(character.transform.position, path[0].transform.position) < 0.0001f)
    {
        PositionCharacterOnTile(path[0]);

        path.RemoveAt(0);
    }
}

This is my attempt at adding serialization support for my components transform .. I have a read/write function for properties in my OverlayTile component and another read/write function specifically just for Vector3 (Again, not even sure if I'm approaching this correctly):

public static class TileReaderWriter
{
    public static void writeTile(this NetworkWriter writer, OverlayTile overlayTile)
    {
        writer.WriteInt(overlayTile.G);
        writer.WriteInt(overlayTile.H);
        writer.WriteBool(overlayTile.isBlocked);
        writer.WriteVector3Int(overlayTile.gridLocation);
    }


    public static OverlayTile readTile(this NetworkReader reader)
    {
        return new Tile
        {
            G = reader.ReadInt(),
            H = reader.ReadInt(),
            isBlocked = reader.ReadBool(),
            gridLocation = reader.ReadVector3Int(),
        };
    }

    public struct MyTransform
    {
        public Vector3 transform;
        public Rigidbody rigidbody;
    }

    public static void WriteMyTransform(this NetworkWriter writer, MyTransform value)
    {
        writer.WriteVector3(value.transform);

        NetworkIdentity networkIdentity = value.rigidbody.GetComponent<NetworkIdentity>();

        writer.WriteNetworkIdentity(networkIdentity);
    }

    public static MyTransform ReadMyCollision(this NetworkReader reader)
    {
        Vector3 transform = reader.ReadVector3();

        return new MyTransform
        {
            transform = transform,
        };
    }
}

For even more context here is the full error I am getting back from my server:

System.Collections.Generic.List1[OverlayTile] Disconnecting connId=1 to prevent exploits from an Exception in MessageHandler: NullReferenceException at (wrapper managed-to-native) UnityEngine.Component.get_transform(UnityEngine.Component) at PlayerMovement.UserCode_CmdMoveAlongPath__List1 (System.Collections.Generic.List1[T] path) [0x0001a] in <e1eca6a72681489bab525a1eafd2d63f>:0 at PlayerMovement.InvokeUserCode_CmdMoveAlongPath__List1 (Mirror.NetworkBehaviour obj, Mirror.NetworkReader reader, Mirror.NetworkConnectionToClient senderConnection) [0x00022] in :0 at Mirror.RemoteCalls.RemoteProcedureCalls.Invoke (System.Int32 functionHash, Mirror.RemoteCalls.RemoteCallType remoteCallType, Mirror.NetworkReader reader, Mirror.NetworkBehaviour component, Mirror.NetworkConnectionToClient senderConnection) [0x00019] in <2d57b1f41c0b4d5a90f7ef7dbcf2e469>:0 at Mirror.NetworkIdentity.HandleRemoteCall (System.Byte componentIndex, System.Int32 functionHash, Mirror.RemoteCalls.RemoteCallType remoteCallType, Mirror.NetworkReader reader, Mirror.NetworkConnectionToClient senderConnection) [0x00065] in <2d57b1f41c0b4d5a90f7ef7dbcf2e469>:0 at Mirror.NetworkServer.OnCommandMessage (Mirror.NetworkConnectionToClient conn, Mirror.CommandMessage msg, System.Int32 channelId) [0x00085] in <2d57b1f41c0b4d5a90f7ef7dbcf2e469>:0 at (wrapper delegate-invoke) System.Action3[Mirror.NetworkConnectionToClient,Mirror.CommandMessage,System.Int32].invoke_void_T1_T2_T3(Mirror.NetworkConnectionToClient,Mirror.CommandMessage,int) at Mirror.MessagePacking+<>c__DisplayClass6_02[T,C].b__0 (Mirror.NetworkConnection conn, Mirror.NetworkReader reader, System.Int32 channelId) [0x0007a] in <2d57b1f41c0b4d5a90f7ef7dbcf2e469>:0

0 Answers
Related