Protocole de jeu RTS

18

J'ai pensé à un jeu RTS multi-joueurs. La partie que je n'arrive pas à contourner est de garder le mouvement de l'unité synchronisé. Si je déplace l'unité A pour repérer XY, je dois la communiquer au serveur qui relaie à l'autre client.

Je suis curieux de voir à quoi ressembleraient les communications. Pourriez-vous simplement communiquer au serveur que je déplace l'unité A vers XY de JZ? Peut-être que vous devez plutôt communiquer le mouvement coord par coord? Quelle est la méthodologie la plus efficace pour communiquer le mouvement des unités d'un client à l'autre?

ÉDITER

Il s'agit d'une question republiée par stackoverflow . J'ai trouvé que ce site était probablement un meilleur endroit pour la question.

L'une des meilleures réponses de ce post:

Je suppose que vous avez l'intention d'utiliser le paradigme de mise en réseau client-serveur? Dans ce cas, vous ne pouvez pas faire confiance aux clients pour gérer le positionnement réel des unités, vous devez déléguer cette tâche au serveur. Vous prenez ensuite la liste de commandes de chaque client par tick, et calculez le mouvement de chaque unité, une fois celle-ci terminée, vous cochez ensuite la position de chaque unité pertinente pour chaque client (soit sur une carte entière, soit par vue) et recommencez le processus.

Darthg8r
la source
2
La réponse dépend vraiment de la méthode que vous souhaitez utiliser. Client - client ou client - serveur. Le client vers le serveur est plus facile mais nécessite un serveur fiable
Cem Kalyoncu

Réponses:

25

Vous ne voulez pas synchroniser les positions de toutes les unités du serveur à chaque client; cela prendra beaucoup plus de bande passante que vous n'en avez besoin. Vous auriez également à faire face à l'interpolation / extrapolation des positions des unités, etc. Presque aucun client / serveur professionnel RTS n'utilise!

Au lieu de cela, vous souhaitez envoyer uniquement les commandes des joueurs. Plutôt que de déplacer les unités immédiatement lorsque le joueur clique, vous allez mettre en file d'attente la commande de déplacement à effectuer à un moment donné dans le futur - généralement seulement quelques images. Tout le monde envoie ses commandes à tout le monde. Quelques images plus tard, tout le monde exécute toutes les commandes, et parce que le jeu est déterministe, ils voient tous le même résultat.

L'inconvénient est que chaque joueur est aussi lent que le joueur le plus lent - si quelqu'un prend du retard dans l'envoi de commandes, tout le monde doit ralentir et attendre qu'il rattrape (dans Starcraft 2, c'est le "XXX ralentit le jeu") " dialogue).


En fait, il y a encore une chose qui se fait habituellement: éliminer complètement le serveur . Demandez à chaque client d'envoyer ses commandes à tous les autres clients. Cela réduit le décalage (au lieu d'une commande allant de vous -> serveur -> adversaire, cela vient juste de vous -> adversaire) et facilite le codage, car vous n'avez plus besoin de coder un serveur séparé. Ce type d'architecture est appelé peer-to-peer (P2P).

L'inconvénient est que vous avez maintenant besoin d'un moyen de résoudre les conflits, mais comme les commandes des joueurs sont indépendantes les unes des autres dans la plupart des RTS, ce n'est généralement pas un gros problème. De plus, cela ne se modifie pas bien - chaque fois que vous ajoutez un nouveau joueur, chaque joueur doit lui envoyer ses commandes. Vous n'allez pas créer un MMO RTS en utilisant le P2P.


Cette configuration (envoi de commandes uniquement à l'aide de P2P) est le fonctionnement de la plupart des RTS, y compris Starcraft, C&C et AoE, et c'est la seule façon dont AoE pourrait éventuellement prendre en charge 1500 unités sur une connexion à 28,8 kbps .

(image de mise en réseau dans AoE)

Voici quelques conseils supplémentaires pour écrire un RTS P2P:

  • Pour des raisons évidentes, cette configuration ne peut fonctionner que si votre jeu utilise un temps à pas fixe - vous ne voulez pas que les résultats d'un calcul dépendent du taux de rafraîchissement! L'étape fixe est plus facile à utiliser pour la plupart des choses, donc cela ne devrait pas être un problème.
  • Pour que cela fonctionne, les résultats de chaque commande doivent être complètement déterministes .
    • C'est généralement assez facile si vous vous limitez à un seul système (tel que Windows 32 bits) et forcez tous les clients à utiliser le même exécutable: assurez-vous que tous les générateurs de nombres aléatoires ont la même graine et sont toujours appelés dans le même ordre; soyez extrêmement prudent lorsque vous parcourez des collections non ordonnées ; etc.
    • C'est extrêmement difficile si vous prévoyez de rendre le jeu jouable sur différentes plates-formes ou (comme c'est souvent le cas avec Linux) de permettre aux clients de compiler le code eux-mêmes. Non seulement différentes bibliothèques système sont à peu près garanties d'utiliser différentes implémentations de rand(), cos()etc., mais presque toutes les mathématiques à virgule flottante sont hors de question (voir ici , ici et ici ) ! Dans ce cas, il vaut mieux utiliser client-serveur.
  • Vous allez vouloir envoyer toutes les positions d'unité de temps en temps, au moins pendant le débogage, pour détecter les bogues de désynchronisation (ce qui, croyez-moi, vous aurez ). Que vous gardiez cela dans le jeu final, cela dépend de vous - je synchroniserais au moins certaines unités (ou utiliserais une sorte de somme de contrôle) pour détecter les tentatives de piratage.
BlueRaja - Danny Pflughoeft
la source
Bon post. Petite chose à ajouter, même les mêmes compilateurs optimisent, le débogage / libération et d'autres indicateurs peuvent changer le résultat. Faites attention!
Peter Ølsted le
14

J'ai créé un RTS en réseau TCP, dans lequel j'ai passé les commandes elles-mêmes, plutôt que les résultats des commandes . Par exemple, un joueur donne un ordre de déplacement. Si l'ordre de déplacement est valide selon ce client, il est envoyé au serveur. Le serveur le renvoie ensuite à tous les clients, qui le valident et l'exécutent.

Ainsi, toutes les machines clientes exécutent le jeu elles-mêmes, le code serveur accepte les messages et les renvoie à tous les clients. Si un client donne un ordre de déplacement, il ne commencera à l'exécuter qu'après avoir été reçu du serveur.

Le serveur envoie également un numéro de «tick» auquel exécuter la commande, qui est quelques ticks avant le tick «actuel». De cette façon, toutes les commandes peuvent être exécutées en même temps sur toutes les machines.

Un avantage de cette méthode est qu'elle ne dépend d'aucune machine cliente individuelle pour valider la commande. Si je réussissais les résultats du déplacement, je pourrais peut-être le pirater pour déplacer mes unités plus rapidement. Tous les clients doivent exécuter la même commande et si une machine l'exécute différemment, ce sera évident.

La validation de la commande côté client avant de l'envoyer au serveur n'est pas nécessaire, mais en théorie, elle économise le trafic réseau. J'ai utilisé le même code de validation pour dire à l'interface utilisateur que le déplacement était possible, donc il n'a pas fallu écrire de code supplémentaire.

Quant à ce à quoi les messages pourraient ressembler. Je n'étais pas préoccupé par l'ultra efficacité car c'était mon premier jeu en réseau. J'ai passé des commandes sous forme de chaînes. Les commandes seraient formatées comme ceci:"<player_id>:<command>:<parameters>"

Pour un exemple artificiel, une commande de mouvement pourrait ressembler à ceci: "3:move:522:100:200". Cela signifie que le joueur 3veut moves'unir 522à ( 100, 200).

Le serveur passe la commande à tous les clients, y compris celui qui l'a envoyé, avec un numéro de tick attaché comme ceci: "153238:3:move:522:100:200".

Ensuite, les clients exécuteraient tous cette commande lorsque tick 153238 est exécuté.

Philippe
la source
J'ai ajouté un peu plus d'informations à la question. La réponse de SO semble aller à l'encontre de ce que vous avez dit et j'aimerais discuter des détails les plus fins.
Darthg8r
Oui, c'est une autre façon de le faire, mais il me semble que ce serait plus de travail de passer autant de l'état du jeu, plutôt que juste les commandes. Mon jeu était assez simple pour que tout fonctionne sur chaque machine cliente. Pour un MMO, ou pour quelque chose comme Minecraft, vous n'avez pas la simulation entière en cours d'exécution côté client, vous ne transmettez donc que les informations pertinentes pour chaque client individuellement.
Philip