Передвижение в Unity netcode for gameobjects
Я пытаюсь изучать Netcode for gameobjects, и хочу использовать архитектуру с удалённым сервером. Я не хочу доверять клиенту поэтому хочу от клиента отсылать "сообщение о желании перемещения" а на сервере уже двигать игрока, собственно у меня все получилось: При подключении клиента я спавнюю префаб игрока (через сервер) и через дикшинари связываю объект игрока с клиентом. Далее на клиенте я считываю ввод с клавиш и отправляю ServerRPC с Vector3 в виде строки, а на сервере беру префаб игрока из дикта с ключем в виде ID игрока и двигаю его.
НО! если я в билде запускаю сервер и в эдиторе перемещаюсь то все ок, но если наоборот то клиент движется сильно медленнее чем если клиент на эдиторе. Собственно в этом и вопрос. в чем я ошибся, или может rpc для такого вообще не подходит и есть способ получше?
повторюсь я не хочу доверять клиенту и позволять ему двигать себя самому. код ниже, заранее спасибо за советы!
код клиента считывания ввода:
public class PlayerNetworkObject : NetworkBehaviour
{
private void Update()
{
if (!IsOwner || !IsClient)
return;
var direction = Vector3.zero;
if (Input.GetKey(KeyCode.W))
direction += Vector3.forward;
if (Input.GetKey(KeyCode.S))
direction += Vector3.back;
if (Input.GetKey(KeyCode.A))
direction += Vector3.left;
if (Input.GetKey(KeyCode.D))
direction += Vector3.right;
_serverManager.MoveServerRPC(direction.ToString(), new ServerRpcParams());
}
}
Код ServerManager:
public class ServerManager : NetworkBehaviour
{
[Inject] private DiContainer container;
[Header("Prefabs")]
[SerializeField] private Transform playerMovementNetworkPrefab;
private Dictionary<ulong, PlayerObjectsData> _playersTable;
private void Start()
{
_playersTable = new Dictionary<ulong, PlayerObjectsData>();
NetworkManager.Singleton.OnClientConnectedCallback += SpawnPlayerMovement;
}
#region Spawn
public void SpawnPlayerMovement(ulong clientId)
{
if(IsClient)
return;
if (!_playersTable.ContainsKey(clientId))
{
var playerMovement = container.InstantiatePrefabForComponent<PlayerMovementNetwork>(playerMovementNetworkPrefab);
playerMovement.GetComponent<NetworkObject>().Spawn(true);
_playersTable.Add(clientId, new PlayerObjectsData()
{
playerMovementNetwork = playerMovement,
});
}
}
#endregion
#region Movement
[ServerRpc(RequireOwnership = false)]
public void MoveServerRPC(string moveDirection, ServerRpcParams serverRpcParams)
{
var direction = StringToVector3(moveDirection);
if (direction.magnitude > 1)
{
Debug.LogWarning($"Client {serverRpcParams.Receive.SenderClientId} trying to move too far!");
return;
}
_playersTable[serverRpcParams.Receive.SenderClientId].playerMovementNetwork.Move(direction);
//MoveClientRPC(moveDirection, new ClientRpcParams() { Send = new ClientRpcSendParams(){TargetClientIds = new []{serverRpcParams.Receive.SenderClientId}}});
}
[ClientRpc]
private void MoveClientRPC(string moveDirection, ClientRpcParams clientRpcParams)
{
//_playersTable[clientRpcParams.Receive].Move(StringToVector3(moveDirection));
}
private Vector3 StringToVector3(string sVector)
{
// Remove the parentheses
if (sVector.StartsWith("(") && sVector.EndsWith(")"))
{
sVector = sVector.Substring(1, sVector.Length - 2);
}
// split the items
string[] sArray = sVector.Split(',');
// store as a Vector3
Vector3 result = new Vector3(
float.Parse(sArray[0].Replace('.',',')),
float.Parse(sArray[1].Replace('.',',')),
float.Parse(sArray[2].Replace('.',',')));
return result;
}
#endregion
}
Код перемещения игрока:
public class PlayerMovementNetwork : NetworkBehaviour
{
[Inject] private ServerManager serverMovementManager;
[SerializeField] private float speed = 3f;
public void Move(Vector3 direction)
{
transform.position += direction.normalized * speed * Time.deltaTime;
}
}