Sincronizzazione dei client con un server e tra loro


9

Qual è il modo migliore per mantenere tutti i client sincronizzati con un server e tra loro?

Attualmente, abbiamo in mente due approcci:

  1. Quando un client invia qualcosa al server, il server invia immediatamente messaggi a tutti i client, che reagiscono immediatamente.
  2. Introducendo un certo ritardo, in base al quale il server invia messaggi a tutti i client, con la direttiva, "agire su questo alla volta t.

Il secondo approccio sembra che molto probabilmente manterrebbe tutti i client in una migliore sincronizzazione (poiché provvede a un certo ritardo); ma mi chiedo se la reattività verrebbe persa in misura troppo elevata (cioè l'utente fa clic su "salta" e c'è un notevole divario tra la pressione del pulsante e il salto effettivo).

C'è anche la possibilità che i client calcolino la propria posizione (e non aspettino che i server diano "sei saltato"); ma a causa dell'inevitabile ritardo, i clienti sarebbero molto fuori sincrono.

Poi c'è l'intera domanda TCP vs. UDP; perché lo vogliamo velocemente, ma odio anche il server per dire che sei in una posizione completamente diversa da come pensavi di essere.

Con tutte queste esigenze in competizione, tutto diventa molto incerto su come dovremmo affrontare questo problema. Quale di questi approcci (o qualsiasi altro) sarebbe meglio per mantenere sincronizzati client e server? Quali sono effettivamente utilizzati nel settore?

Risposte:


7

La risposta rapida è: non esiste un approccio migliore.

I giochi contengono tutti un'architettura diversa; ogni gioco sceglierà diversi set di dati da inviare per sincronizzarsi con altre macchine, il che influenzerà le scelte che puoi fare quando scegli come gestire il ritardo.

Quello che specifichi nell'opzione 2 - che i client inviano messaggi su cui agire in futuro - è sicuramente un approccio. In effetti, il motore di origine utilizza una variante di questo approccio , in cui il rendering è sempre 100 ms dietro le azioni client locali; tutte le macchine tentano di operare contemporaneamente sulle stesse azioni. Ciò aggiunge un ritardo artificiale e impercettibile al gioco al fine di nascondere l'effettiva latenza della rete.

Se non riesci ad adottare questo approccio, puoi anche scegliere l'opzione n. 1, semplicemente inviando i dati più aggiornati e alla ricezione, utilizzare l'interpolazione e l'estrapolazione (previsione sul lato client) per cercare di nascondere la latenza. Ho usato questo approccio in almeno un gioco di spedizione - ma ancora una volta, tutto dipende dal tuo gioco; ci possono essere altri approcci che puoi adottare.

Infine, quando si sceglie tra TCP e UDP, probabilmente si desidera UDP. Esistono scenari in cui TCP è un'opzione praticabile per collegare in rete il tuo gioco, ma quando stai realizzando un gioco d'azione, desideri i dati più recenti il ​​più presto possibile. Se puoi gestire da solo i pacchetti rilasciati, UDP è la scelta migliore. (Esistono librerie, come ENet , che forniscono un wrapper attorno a UDP per sostituire la funzionalità da TCP, come pacchetti affidabili.)


Non vuoi davvero usare UDP. Il sovraccarico di una connessione TCP correttamente configurata è minimo e l'inferno di una consegna fuori servizio è qualcosa che nessuno dovrebbe superare.
coderanger,

2
Non è una questione di overhead, sebbene TCP ne aggiunga alcuni: il modo in cui TCP gestisce i pacchetti rilasciati non è fondamentalmente buono nei giochi in cui una grande latenza tra azione e reazione può fare un'enorme differenza nella giocabilità. Per un gioco come WoW, in cui le azioni sono relativamente rare, TCP funziona, ma cadrà in modo piatto in un gioco come CounterStrike, poiché un singolo pacchetto eliminato limiterà la connessione e potenzialmente ti farà "restare indietro" per un secondo o più.
Blair Holloway,

Se hai intenzione di usare UDP, è davvero meglio non scriverlo da solo; usa un wrapper come ENet che fa il duro lavoro per te. Ma la mia risposta originale è ancora valida: UDP è il modo migliore di procedere se stai realizzando un gioco con qualsiasi tipo di azione frenetica.
Blair Holloway,

Per me, RakNet ha reso estremamente semplice l'esecuzione di una connessione UDP per il mio motore di gioco. Ha molte opzioni per come si desidera inviare il pacchetto, ad es. come ordinarli, se il pacchetto dovesse essere rinviato in caso di caduta, ecc.
BarakatX2

3

Ecco un paio di buoni collegamenti che coprono moltissime reti di giochi.

E questa è la prima parte delle serie più pratiche sulle reti. http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/

Per la storia. "Siamo spiacenti, ma come meccanismo di prevenzione dello spam, i nuovi utenti possono pubblicare un massimo di un collegamento ipertestuale. Guadagna 10 reputazione per pubblicare più collegamenti ipertestuali ". Basta guardare il suo sito Web, comunque.


1

Dato che menzioni Client e Server, suppongo che stai parlando di un'architettura Client / Server in cui il Server è l'autorità sullo stato di tutti gli oggetti.

Nota: l'alternativa è un'architettura peer-to-peer in cui il proprietario di un oggetto è l'autorità per quell'oggetto.

Esiste già un metodo ben collaudato per la sincronizzazione di oggetti in movimento mediante l'architettura client-server. Si chiama Dead Reckoning. .

Un buon modo per implementarlo in un gioco sarebbe come questo:

  1. I client inviano input al server.
  2. Il server aggiorna gli oggetti di gioco (accelerazioni e direzioni) e li rimanda ai Clienti.
  3. I clienti utilizzano questi valori aggiornati per simulare il movimento degli oggetti localmente.
  4. Occasionalmente, il server invia una correzione di posizione per evitare la deriva.
  5. Risciacquare; ripetere.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.