Hello, I’m using the relay services for creating a party game and for syncing players transform i tried the AnticipatedNetworkTransform. everything seems working fine until I tried : the host player synchronization seems to be alright, but for the client, when i try to move, the final transform isnt the same as the host player
here’s the code i wrote (i use unity 2022.3.45f1 & netcode 1.11, i cant use 1.9/1.10 cuz of the fixedstringXbyte bug) :
using System.Collections.Generic;
using Unity.Netcode;
using Unity.Netcode.Components;
using UnityEngine;
public class NetworkPlayerMovement : NetworkBehaviour
{
[SerializeField] float m_MoveSpeed = 5f;
[SerializeField] float m_RotationSpeed = 150f;
[SerializeField] float m_DeltaAnticipatedTime = 0.25f;
[SerializeField] AnticipatedNetworkTransform m_AnticipatedNetworkTransform;
private NetworkPlayer m_NetworkPlayer;
[SerializeField] private List<ClientInputMap> m_ClientInputMapList = new List<ClientInputMap>();
private readonly Dictionary<PlayerInteraction, bool> m_ClientInputBuffer = new();
public NetworkPlayer ClientNetworkPlayer
{
get
{
return m_NetworkPlayer;
}
}
public bool CanHandle { get; private set; }
private void Start()
{
CanHandle = IsServer || IsOwner;
}
private void Update()
{
HandleInputMap();
HandleMovement();
}
private void HandleMovement()
{
if (CanHandle && m_NetworkPlayer)
{
Vector3 moveDirection = Vector3.zero;
if (IsPressed(PlayerInteraction.Forward))
{
moveDirection += transform.forward;
}
if (IsPressed(PlayerInteraction.Backward))
{
moveDirection -= transform.forward;
}
Vector3 newPosition = transform.position + m_MoveSpeed * Time.deltaTime * moveDirection;
transform.position = newPosition;
m_AnticipatedNetworkTransform.AnticipateMove(newPosition);
if (IsPressed(PlayerInteraction.TurnLeft))
{
Quaternion newRotation = transform.rotation * Quaternion.Euler(0, -m_RotationSpeed * Time.deltaTime, 0);
transform.rotation = newRotation;
m_AnticipatedNetworkTransform.AnticipateRotate(newRotation);
}
if (IsPressed(PlayerInteraction.TurnRight))
{
Quaternion newRotation = transform.rotation * Quaternion.Euler(0, m_RotationSpeed * Time.deltaTime, 0);
transform.rotation = newRotation;
m_AnticipatedNetworkTransform.AnticipateRotate(newRotation);
}
}
}
public override void OnReanticipate(double lastRoundTripTime)
{
m_AnticipatedNetworkTransform.Smooth(
m_AnticipatedNetworkTransform.PreviousAnticipatedState,
m_AnticipatedNetworkTransform.AuthoritativeState,
m_DeltaAnticipatedTime
);
}
private void HandleInputMap()
{
if (!IsOwner) return;
m_ClientInputBuffer.Clear();
foreach (ClientInputMap clientInputMap in m_ClientInputMapList)
{
if (Input.GetKeyDown(clientInputMap.keyCode))
{
m_ClientInputBuffer[clientInputMap.playerInteraction] = true;
}
else if (Input.GetKeyUp(clientInputMap.keyCode))
{
m_ClientInputBuffer[clientInputMap.playerInteraction] = false;
}
}
if (m_ClientInputBuffer.Count > 0)
{
SynchronizeBuffer();
}
}
private void SynchronizeBuffer()
{
List<ServerInputMapSerializable> mapList = new List<ServerInputMapSerializable>();
foreach (var element in m_ClientInputBuffer)
{
ServerInputMapSerializable sims = new()
{
playerInteraction = (int)element.Key,
value = element.Value
};
mapList.Add(sims);
}
m_NetworkPlayer.AskUpdateInputMap(mapList);
}
public void SetNetworkPlayer(NetworkPlayer networkPlayer)
{
m_NetworkPlayer = networkPlayer;
}
/// <summary>
/// Check whenever if a key associated to a player interaction is pressed by the client. Optimized for fast result.
/// </summary>
/// <param name="interaction"></param>
/// <returns></returns>
public bool IsPressed(PlayerInteraction interaction)
{
if (IsServer)
{
return m_NetworkPlayer.IsPressed(interaction);
}
return IsPressed_ClientSide(interaction);
}
private bool IsPressed_ClientSide(PlayerInteraction interaction)
{
foreach (var clientInputMap in m_ClientInputMapList)
{
if (clientInputMap.playerInteraction == interaction)
{
return Input.GetKey(clientInputMap.keyCode);
}
}
return false;
}
}
[System.Serializable]
public struct ServerInputMapSerializable : INetworkSerializable
{
public int playerInteraction;
public bool value;
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref playerInteraction);
serializer.SerializeValue(ref value);
}
}
[System.Serializable]
public struct ClientInputMap
{
public KeyCode keyCode;
public PlayerInteraction playerInteraction;
}
public enum PlayerInteraction
{
Forward,
Backward,
TurnLeft,
TurnRight
}
if anyone knows maybe how i can fix that (not necessarily by editing the Anticipation part)
