Mirror: Serialization error and syncvar hook not called

Hello,

Currently I am trying to set display names when players connect. It works on the host client, however I get this error on a joining client. The joining client does seem to update the display name syncVar, however the handler hook is not called. I’m not sure if these are related or not. If I comment out the SetDisplayName calls in the NetworkManager, I don’t get the Serialization error.

Custom NetworkManager OnServerAddPlayer

 override public void OnServerAddPlayer(NetworkConnection conn)
    {
        base.OnServerAddPlayer(conn);

        GameObject playerObj = Instantiate(playerCharacterPrefab, new Vector3(3f, 0.5f, 3f), Quaternion.identity);
        NetworkServer.Spawn(playerObj, conn);

        NetPlayer netPlayer = conn.identity.GetComponent<NetPlayer>();
        netPlayer.SetControlledEntityNetId(playerObj.GetComponent<NetworkIdentity>());
        listOfConnectedPlayers.Add(netPlayer);

        if (isSteamNetManager)
        {
            CSteamID steamId = SteamMatchmaking.GetLobbyMemberByIndex(SteamLobby.LobbyID, numPlayers - 1);
            netPlayer.SetDisplayName(SteamFriends.GetFriendPersonaName(steamId));
        }
        else
        {
            netPlayer.SetDisplayName("Player " + numPlayers);
        }
    }

NetPlayer class (Set as the Auto Created Player Prefab in Network Manager)

public class NetPlayer : NetworkBehaviour
{
    #region Display Name

    [SyncVar(hook = nameof(UpdateDisplayName))] private string displayName = "missingNo";

    [Server] public void SetDisplayName(string newDisplayName) => displayName = newDisplayName;

    public string GetDisplayName() => displayName;

    private void UpdateDisplayName(string oldDisplayName, string newDisplayName)
    {
        GameObject playerObj = NetworkIdentity.spawned[controlledEntityNetId.netId].gameObject;
        UiFollowObject ui = playerObj.GetComponent<UiFollowObject>();
        if (ui != null)
        {
            ui.SetText(newDisplayName);
        }
    }
    #endregion

    [SyncVar] private NetworkIdentity controlledEntityNetId;
    [Server] public void SetControlledEntityNetId(NetworkIdentity netId) => controlledEntityNetId = netId;
}

Console Error Log:

OnDeserialize was expected to read 11 instead of 10 bytes for object:NetPlayer(Clone) component=NetPlayer sceneId=0. Make sure that OnSerialize and OnDeserialize write/read the same amount of data in all cases.
UnityEngine.Logger:Log(LogType, Object)
Mirror.ILoggerExtensions:LogWarning(ILogger, Object) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/Logging/LogFactory.cs:93)
Mirror.NetworkIdentity:OnDeserializeSafely(NetworkBehaviour, NetworkReader, Boolean) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/NetworkIdentity.cs:1043)
Mirror.NetworkIdentity:OnDeserializeAllSafely(NetworkReader, Boolean) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/NetworkIdentity.cs:1061)
Mirror.ClientScene:ApplySpawnPayload(NetworkIdentity, SpawnMessage) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/ClientScene.cs:760)
Mirror.ClientScene:OnSpawn(SpawnMessage) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/ClientScene.cs:781)
Mirror.<>c__DisplayClass31_0`1:<RegisterHandler>b__0(NetworkConnection, SpawnMessage) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/NetworkClient.cs:328)
Mirror.<>c__DisplayClass6_0`2:<MessageHandler>b__0(NetworkConnection, NetworkReader, Int32) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/MessagePacker.cs:128)
Mirror.NetworkConnection:InvokeHandler(Int32, NetworkReader, Int32) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/NetworkConnection.cs:191)
Mirror.NetworkConnection:TransportReceive(ArraySegment`1, Int32) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/NetworkConnection.cs:249)
Mirror.NetworkClient:OnDataReceived(ArraySegment`1, Int32) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/NetworkClient.cs:174)
UnityEngine.Events.UnityEvent`2:Invoke(ArraySegment`1, Int32)
kcp2k.KcpTransport:<Awake>b__11_1(ArraySegment`1) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs:45)
kcp2k.KcpClient:<Connect>b__6_1(ArraySegment`1) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs:46)
kcp2k.KcpConnection:TickAuthenticated(UInt32) (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs:236)
kcp2k.KcpConnection:Tick() (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs:256)
kcp2k.KcpClient:Tick() (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs:91)
kcp2k.KcpTransport:LateUpdate() (at C:/Users/Alex/Documents/GitHub/sandbox-game/Assets/Plugins/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs:93)

It looks like the base OnServerAddPlayer you’re calling instantiates the player prefab, and you are also instantiating one in the override. Also I think you need to AddPlayerForConnection after instantiating the player.

Yes sorry, I forgot to mention that there are two objects being instantiated for each player, which may seem redundant, but I am trying to keep an object that represents the player on that connection separate from their in-game character, which could be destroyed or swapped out. So a GameObject called NetPlayer with the NetPlayer script on it is the default player object for the NetManager to spawn on its own when a player connects. Then, I manually spawn a player character object for that player to control in OnServerAddPlayer, and give that connection authority for that object, as well as keep a reference to that object in the NetPlayer. It all works well as far as authority and player control.

The error i am getting seems irrelevant to this manually spawned character, I am only having issues with the NetPlayer gameobject and setting the display name to that object.

I ran the code and got the same error. The error goes away if you remove the code from UpdateDisplayName so that’s a good place to start looking for the problem.

Right, not sure why I didn’t continue to just keep trying each line. But its this line specifically causing the error:

GameObject playerObj = NetworkIdentity.spawned[controlledEntityNetId.netId].gameObject;

Must be something with how I am trying to retrieve a specific gameobject by its network identity. Going to look more into how to do that properly.

Edit: Its because the net id (which i switched to just syncing the uint) is not getting set before the UpdateDisplayName runs. After reordering how variables are synced, it works now.