Jump to content
Unity Insider Forum

Spieler Geschwindigkeiten synchronisieren (Netcode)?


Lightstorm

Recommended Posts

Ich probiere Netcode for GameObjects von Unity aus. Angenommen man möchte das Server authoritative Konzept verwenden und dabei dafür sorgen das alle Spieler die gleiche Geschwindigkeit im Spiel haben. Dann habe ich mit dem folgenden Code das Problem das Time.deltaTime die delta time des Servers und nicht des Clients ist. Man könnte die delta time des Client an den Server senden, aber es wäre schön wenn ich dem Client möglichst wenig vertrauen muss. Denn mit solchen Werten könnte man theoretisch cheaten (fliegen, schneller bewegen) und ich möchte vermeiden, dass der Server ständig berechnet, ob sich der Spieler innerhalb der erlaubten Grenzen bewegt. Außerdem könnte der Client durch mehr Aufrufe der RPC Methode auf dem Server schneller als andere Spieler werden.

 

using Unity.Netcode;
using UnityEngine;

namespace HelloWorld
{
    public class HelloWorldPlayer : NetworkBehaviour
    {
        [SerializeField]
        private CharacterController character;

        [ServerRpc]
        void MovementServerRpc(float horizontal, float vertical)
        {
            float moveSpeed = 3.07f;
            Vector3 move = new Vector3(horizontal, 0, vertical);
            character.Move(move * Time.deltaTime * moveSpeed);
        }

        void Update()
        {
            if (!IsOwner) return;
            float horizontal = Input.GetAxis("Horizontal");
            float vertical = Input.GetAxis("Vertical");
            MovementServerRpc(horizontal, vertical);
        }
    }
}

 

Ich habe eine mögliche Lösung, von dem ich nicht wirklich weiß ob es so funktioniert wie ich mir das denke. Der Client schickt wie vorher über RPC die Aufforderung für eine Bewegung, der Server führt die Bewegung jedoch nicht sofort aus sondern speichert es in der nextMove Variable. Erst durch die zeitlich fixierten Aufrufe von FixedUpdate auf dem Server wird die Bewegung ausgeführt. Somit ist es egal wie oft Update auf den Clients aufgerufen wird, ausgeführt werden die Bewegungen nach dem Takt von FixedUpdate des Servers. So muss man auch keine delta time Werte von den Clients annehmen.

Funktioniert das wie ich mir denke und welche anderen Lösungen gibt es noch? Vielleicht mache ich mir auch unnötig Gedanken darüber und irgendwas in Netcode macht das automatisch oder viel einfacher? Ich kenne mich mit Netcode noch kaum aus.

using Unity.Netcode;
using UnityEngine;

namespace HelloWorld
{
    public class HelloWorldPlayer : NetworkBehaviour
    {
        [SerializeField]
        private CharacterController character;

        private Vector3 nextMove;

        [ServerRpc]
        void MovementServerRpc(float horizontal, float vertical)
        {
            float moveSpeed = 3.07f;
            Vector3 move = new Vector3(horizontal, 0, vertical);
            nextMove = move;
        }

        void FixedUpdate()
        {
            if (IsServer && nextMove != Vector3.zero)
            {
				float speed = 3.0f;
                character.Move(nextMove * Time.fixedDeltaTime * speed);
                nextMove = Vector3.zero;
            }
        }

        void Update()
        {
            if (!IsOwner) return;
            float horizontal = Input.GetAxis("Horizontal");
            float vertical = Input.GetAxis("Vertical");
            MovementServerRpc(horizontal, vertical);
        }
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also ich sehe hier mehrere kritische Fehler.

Erst mal: Du solltest nicht jedes Update den RPC call machen. Das nicht gut, außer willst nur weniger Spieler supporten und du denkst nicht so an Performance. Check vorher mal den Delta Wert bzw, ob die neuen und alten Werte nicht dasselbe sind (z.b. oldHorizontal != horizontal), dann MovementServerRpc ausführen.

Zweitens: Also MovementServerRpc, gerade sieht es noch ok aus, aber ich würde NIEMALS die Werte was der Client schicken kann, weiter verwenden. Da könnte theoretisch auch 1000f stehen statt 1f, wenn man das gehackt bekommt. Da du das in Vector3 packst könnte da halt ungewollte Werte stehen. Ich wette mit dir, dass ich bei dir bereits Cheat Engine verwenden könnte ^^.
Am besten tut man das so. Du schaust ob horizontal / vertical inputs -1 oder 1 sind. Erstens sendest du hier einmal über das Netzwerk und nicht mehrmals. Spart man schonmal minimal Performance. Beim GetAxis steigt ja float von 0 auf 1 also wird mehrmals gesendet. Das ist aber jetzt optional udn nicht so wichtig. Ist nur ein Tip am Rande. Zweitens dann noch clampen auf -1 und 1 auf dem Server. Von da aus kannst du sagen ja möchte nach vorn oder nach hinten. Was auch immer. 

Den Rest hast schonmal gut gemacht. Das mit nextMove ist schon mal eine simple Lösung kann man machen. Ich benutze das auch so ähnlich, wenn ich lerpe oder smoothe Bewegung einbaue (z.B. schwebende Autos, Raumschiffe usw.). Allerdings reicht das ja noch nicht aus. Die Bewegung muss solange ausgeführt werden bis neue Inputs reinkommen. Also ruhig nextMove = Vector3.zero; raus nehmen.
Bei Source Engine z.B. hab ich gemerkt, dass die Spieler sich auch solange bewegen bis neue Inputs kommen. Sollte das Spiel mal einfrieren für paar Sekunden und du hast in der Zeit bereits losgelassen, läuft man aber im Spiel (auf dem Server) dennoch immer weiter. Ich denke mal das ist bei vielen Spielen so.

FixedUpdate sollte in dem Fall nur auf dem Server möglich sein. Wie wird es denn auf dem Clients synchronisiert?

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

@MaZy

Vielen Dank für deine Tipps. Mutliplayer Entwicklung ist echt eine Wissenschaft für sich.

Am 17.2.2023 um 01:28 schrieb MaZy:

Wie wird es denn auf dem Clients synchronisiert?

Mit der Network Transform Komponente von Netcode. Man fügt die Komponente einem GameObject hinzu und es synchronisiert automatisch mit den serverseitigen Bewegungen des GameObject.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...