[C++] Programmation d'un serveur de jeu

Programmation d'un serveur de jeu [C++] - C++ - Programmation

Marsh Posté le 31-05-2007 à 20:08:00    

Déja bonjour a tous et a tousE :p
 
Voila mon problème..i
Jaimerai programmer un jeu en réseau mais la n'est pas vraiment le problême...
Concernant la programmation du serveur et du client j'aimerai savoir queqlues trucs sur les techniques de communication entre un serveur et un client
Prenons par ex un jeu au pif comme quake (un truc que tout le monde connait) quece qui doit etre envoyé par le serveur et le client? Je veux dire est ce que les joueurs envoient leur position au serveur qui lui lenvoie aux autres joueurs ou ca se passe autrement et est ce que les calculs genre pour les collisions sont effectués sur le serveur ou sur chacun des clients enfin voila pour moi cest un peu flou si une ame charitable voudrait bien mexpliquer un peu comment tout ca se passe ca serait cool ;)
 
merci ++  

Reply

Marsh Posté le 31-05-2007 à 20:08:00   

Reply

Marsh Posté le 31-05-2007 à 20:43:18    

Les sources de quake sont dispo, elles devraient être une mine d'information à ce sujet.


---------------
Töp of the plöp
Reply

Marsh Posté le 31-05-2007 à 20:46:53    

merci pour ta réponse mais quake etait juste un exemple  
jaimerai juste quon mexplique un peu le mecanisme qui envoie quoi a qui et qui calcule quoi...:/
 
 

Reply

Marsh Posté le 31-05-2007 à 20:48:11    

quake est d'autant plus un bon exemple que ses sources sont dispo :o

Reply

Marsh Posté le 31-05-2007 à 20:54:21    

barbapapa10 a écrit :

merci pour ta réponse mais quake etait juste un exemple  
jaimerai juste quon mexplique un peu le mecanisme qui envoie quoi a qui et qui calcule quoi...:/


Quake n'est pas juste un exemple, c'est une référence dans le jeu en réseau. Et les sources sont dispos, tu verras *exactement* ce qui passe dans le tuyau.


---------------
Töp of the plöp
Reply

Marsh Posté le 31-05-2007 à 20:55:31    

wé mais bon je comprendrai rien en lisant le source de qouake ^^
yaurait pas une explication simple ou un site qui expliquerai ca?

Reply

Marsh Posté le 31-05-2007 à 20:56:38    

Ce n'est pas simple, et on est jamais mieux servi que par soi même.
 
T'as cherché sur google ?


---------------
Töp of the plöp
Reply

Marsh Posté le 31-05-2007 à 21:02:17    

bien sur j'ai cherché sur google... mais rien trouvé hélas meme si ca doit exister
et puis les forums cest fait pour ca :p:p

Reply

Marsh Posté le 31-05-2007 à 21:08:39    

sinon je me doute bien que les client y faut quils envoyent leur position au serveur puis le serveur les envoie aux autres clients mais pour une explosion par exemple (avec un moteur de particules) si chaque client calcule lexplosion elle ne sera pas la meme partout et la c'est pas bon..:/
et si c'est le serveur qui calcule ces explosions et envoie les coord des particules aux clients ca risque de bouffer beaucoup de ressources pour le serveur ainsi que beaucoup de bande passante... voila voila c'est le blazee

Reply

Marsh Posté le 31-05-2007 à 21:33:04    

Ce sujet m'intéresse aussi.
Du coup j'ai téléchargé les sources de quake 3 et ça a l'air très bien documenté ou du moins commenté. Ca à l'air d'être du C mais ce n'est pas un problème.
 
 

barbapapa10 a écrit :

sinon je me doute bien que les client y faut quils envoyent leur position au serveur puis le serveur les envoie aux autres clients mais pour une explosion par exemple (avec un moteur de particules) si chaque client calcule lexplosion elle ne sera pas la meme partout et la c'est pas bon..:/
et si c'est le serveur qui calcule ces explosions et envoie les coord des particules aux clients ca risque de bouffer beaucoup de ressources pour le serveur ainsi que beaucoup de bande passante... voila voila c'est le blazee


 
Moi j'avais pensé à faire quelque chose genre chaque client fait tourner le jeu presque comme s'il était seul, et le serveur aussi.
Le serveur envoie à tps régulier, et calculé pour etre fréquent mais pas trop, ses calculs et les clients se mettent à jour.
Du coup le serveur ne recevrait plus des clients que leur actions effectuées et calcule les évolutions du jeu. Les client fonctionnent par interpolation.
Cela risque d'entrainer des mises à jours brutales si le client a fait des calculs sur une mauvaise interpolation mais je pense que si c'est assez rapide, cela ne devrait pas trop se voir.
Comme ca si quelque chose explose, c'est le client qui calcule les particules et gère l'affichage en fonction par contre en même temps le serveur et le client calculent les dégats de l'explosion et c'est le calcul du serveur qui fait foi au prochain réajustement par le réseau.


---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 31-05-2007 à 21:33:04   

Reply

Marsh Posté le 31-05-2007 à 22:44:30    

Je comprend pas pourquoi l'explosion devrait pas être la même partout si c'est les clients qui la calculent :??: ... Le serveur dit au client "L'objet dont l'id est X c'est fait détruire par l'arme Y, calcule et affiche l'explosion", du coups normalement tous les clients auront la même explosion (peut-être pas au pixel près mais t'en a pas grand chose à scouer).. En tous cas je vois pas comment un serveur pourrait calculer TOUS les effets occasionnés sur la map de tous les points de vue (graphique + evolution du jeu) sans devoir avoir des mastodons comme serveur...

Reply

Marsh Posté le 01-06-2007 à 08:03:15    

C'est effectivement le principe: le serveur n'envoie que le minimum d'infos pour que les clients soient parfaitement synchrones, à savoir pas de temps, ordres, données cinématiques, et ceux-ci calculent tout chacun de leur coté. Ils interpolent entre 2 paquets de données.

Reply

Marsh Posté le 01-06-2007 à 11:31:02    

Content de voir que ma technique a du bon.
Je n'ai pas encore essayé de l'implémenter mais je me pose déjà une question.
Est-ce qu'envoyer à chaque client toutes les informations sur les autres n'est pas aussi très long?
Par exemple un MMORPG si 100 joueurs sont sur le même niveau. Chaque joueur possède une certaine quantité d'attributs:
position
taille
action en cours
vie
force
arme
armure
...
 
toutes ces informations sont nécessaires au client pour l'affichage et l'interpolation.  Cela ne risque pas de prendre beaucoup de temps?
Pire, un jeu de stratégie ou 8 joueurs s'affrontent et possèdent chacun une centaine d'unités...
Y'a-t-il une technique pour envoyer ces données de façon à ne pas ralentir les fps?
Peut on faire une sorte de broadcast?
Peut on n'envoyer que les données vraiment utiles au client (ne donner les infos que sur les autres joueurs visibles ou que sur les unités visibles) sachant que cela rajoute des calculs supplémentaires pour chaque client (alors s'ils sont 100...)?
Bon si les sources de quake m'en disent plus je posterai ce que j'ai trouvé mais si quelqu'un a des idées, je suis preneur.


---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 01-06-2007 à 13:46:19    

Je te dirais de jeter un oeil sur le code de TA Spring, où plusieurs milliers d'unités peuvent s'affronter en temps réel. C'est typiquement le cas de code réseau le plus complexe pour un jeu au nombre de joueurs limité (donc différent du MMORPG), mais je n'y ai jamais vraiment jeté un oeil. Toucher le code réseau d'un tel jeu est qq chose de hautement risqué.
Dans les jeux, les données sont envoyées en UDP, donc en broadcast. Elles peuvent être compressées et décompressées et accompagnées de codes de correction d'erreur. Enfin, il faut arriver à détecter les désynchronisations.

 

Pour un MMORPG, le cas est différent, le serveur central calcule le résultat des actions des différents joueurs. Il n'a pas besoin d'affichage, donc tout ce qu'il a à gérer est une vue abstraite du jeu. La charge de calcul par joueur est faible par rapport aux clients, du coup on peut avoir bcp plus de joueurs. De plus, les actions des joueurs sont très localisées, donc on peut assez facilement répartir la charge totale sur N serveurs. Par contre, on va pouvoir utiliser un langage plus dynamique, par ex. un langage de script relativement rapide genre Lua ou Python, parce que la contrainte pour le(s) serveur(s) est de pouvoir faire évoluer le monde aisément sans avoir à faire tomber le serveur.

Message cité 1 fois
Message édité par el muchacho le 01-06-2007 à 13:54:36
Reply

Marsh Posté le 01-06-2007 à 13:54:01    

merci, très bonne idée TA Spring


---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 01-06-2007 à 14:06:39    

el muchacho a écrit :

Pour un MMORPG, le cas est différent, le serveur central calcule le résultat des actions des différents joueurs. Il n'a pas besoin d'affichage, donc tout ce qu'il a à gérer est une vue abstraite du jeu. La charge de calcul par joueur est faible par rapport aux clients, du coup on peut avoir bcp plus de joueurs.


Plus ou moins vrai.
Je connais par exemple le MMORPG "Face Of Manking".
Le jeu se joue comme Quake : c'est un FPS, et tu quand tu tires, c'est la trajectoire de ta balle qui indique si tu touche ou pas, et non pas un calcul simple à partir de tes caracts.
Et pourtant, on peut faire des batailles avec plusieurs dizaines de personnes dans quelques m² :ouch:
 
Par contre, dans ces cas là, faut une bonne connexion pour arriver à suivre sans trop lagguer :D
 
En fait, je les soupçonne de s'être basé sur le code d'un FPS pour écrire le jeu, puis se sont démerdés pour le rendre clusterable (une même instance peut être répartie sur une vingtaine de serveurs si besoins).
 
Mais bon, là on commence à taper dans le caustaud...

Reply

Marsh Posté le 01-06-2007 à 20:25:46    

Y'a des bonnes idées dans ce topic :p
je vais regarder le code de TA spring et je vous tiens au courant ;)
Sinon ya un autre jeu assez vieux pourtant : Liero qui est le jeu original et liero-aI qui lui est un clone et se joue en réseau et donc dans ce jeu ya des centaines et des centaines de particules qui giclent dans tout les sens pendant le jeu  
http://www.kgivler.com/images/lshot/shell.gif
enfin essayez et vous comprendrez ;)  
donc comme dit pendant une partie ya que ca des particules dans tout les sens (que ca soit de leau, des balles, des flames, des boules, etcetc..) et pourtant ils arrivent a gérer ca en réseau.. parce que les directions des balles quand on tire par ex sont générées au pif et donc il faut bien qu'elles soit pareil chez tout les clients et de ce fait quelles passent par le serveur et on parle bien ici de centaines et de centaines de balles o_O ca reste un mystere.. surtout que le jeux est encore assez vieux donc yavait pas les connexions et les proc daujourdhui :p
voila voila voili

Reply

Marsh Posté le 01-06-2007 à 21:38:55    

Heu même des centaines de balles ... Si les trajectoires sont prédefinies (c'est-à-dire que si tu connais le vecteur quantité de mouvement et la position, tu peux prédire la suite des évènements) ,ce qui est le cas à ce que je sais de tous les jeux, c'est vraiment pas dur/lourd à gérer ... Suffi d'envoyer à chaque fois une info disant "Objet ID X vecteur p = (A,B,C) position = (x1,x2,x3)" et la balle a une trajectoire facilement calculable ... et niveau charge de réseau c'est limite insignifiant

Reply

Marsh Posté le 02-06-2007 à 01:23:57    

De plus, elles sont générées "au pif". Mais c'est très facile de générer des nombres "aléatoires" identiques sur plusieurs machines en // : il suffit d'utiliser la même lib de nombres pseudo aléatoire, et utiliser le même seed.
 
Par exemple, mettons que ma fonction de nombres aléatoires fasse :
 
sqrt(cos(seed + <valeur précédente> ))
 
(ok, c'est pas super aléatoire, mais c'est un exemple ;))
=> aucun souci, après 1 million d'appels, j'aurai le même résultat sur deux machines différentes si j'ai bien utilisé le même seed au départ.


Message édité par MagicBuzz le 02-06-2007 à 01:26:05
Reply

Marsh Posté le 02-06-2007 à 18:34:14    

Houla, il est excessivement naze, ton exemple. D'une part parcer que cos produit des nombres négatifs, donc ça va planter très rapidement, ensuite parce que choisir des fonctions flottantes est une très mauvaise idée parce que le générateur n'est plus portable en plus d'être très lent. Enfin la fonction cos est rapidement cyclique, ce qui fait que la séquence va avoir une période très courte. Bref, il valait mieux ne pas donner d'exemple. [:tinostar]


Message édité par el muchacho le 02-06-2007 à 18:34:29
Reply

Marsh Posté le 02-06-2007 à 20:15:02    

ouais mais moi j'aime donner des exemple bidons qui marche pas :o (il s'agit de montrer le principe, pas un truc qui marche :p)

Message cité 1 fois
Message édité par MagicBuzz le 02-06-2007 à 20:15:33
Reply

Marsh Posté le 02-06-2007 à 20:16:39    

ps : pis l'aspect cyclique, pour gérer la déviation d'une balle à la sortie d'un canon, c'est pas bien gênant :p

Reply

Marsh Posté le 02-06-2007 à 21:10:49    

l'exemple il sert a rien xD en plus le cos c'est "lent" :) (et le sqrt aussi)
par contre l'idée elle est bonne :p c'est vrai que si on utilise la meme lib de nombre aléatoire c'est pareil partout donc basta le rand() de la lib standard faut en faire une sois même :p  
en tout cas merci pour vos réponses

Reply

Marsh Posté le 03-06-2007 à 11:03:56    

En fait, le vrai truc, c'est qu'il faut que la fonction de nombres aléatoire soit "déterministe" (mais moi je préfère un exemple pourri qui marche pas mais qui montre ce que c'est plutôt qu'un mot qui renvoie tout lemonde dans son Larousse avant de décretter que c'est pas dans le Dico :spamafote:)
 
Issu de la doc de SQL Server (ouais, j'ai des références bizarre pour fire du C++ [:cerveau foudtag] )

Citation :

Déterminisme
Fonction déterministe
Une fonction déterministe est une fonction pour laquelle le résultat est toujours le même, pour un même jeu de données en entrée.
 
Par exemple, la fonction getdate() n'est pas déterministe, puisque le résultat dépend du moment d'exécution.
 
Pour pouvoir créer un index sur une vue, seules des fonctions déterministes doivent être utilisées dans la définition de cette vue.
 
De manière générale, la plupart des fonctions sont non-déterministes.
 
Par exemple :
 
• le résultat de (A / B) et (A + B) dépend de la position de l'option ARITHABORT
 
• le résultat de (Chaine + NULL) dépend de la position de l'option CONCAT_NULL_YIELDS_NULL
 
 
 
Certaines options doivent donc être positionnées pour pouvoir utiliser les index sur les vues.


Message édité par MagicBuzz le 03-06-2007 à 11:15:59
Reply

Marsh Posté le 03-06-2007 à 11:19:14    

PS : Je ne sais pas si en C++ les fonctions de Random acceptent un SEED en paramètre.
En .NET, passer un seed en paramètre permet d'obtenir un comportement déterministe (car c'est la création du seed -automatique lorsqu'il n'est pas fourni- qui n'est pas déterministe en fait).

Reply

Marsh Posté le 03-06-2007 à 13:08:27    

oui of course :o faut arreter de croire qu'avant .NET rien n'existait :o

Reply

Marsh Posté le 03-06-2007 à 13:35:50    

Si on en est à donner de mauvais RNG...

Code :
  1. unsigned int lcg = 1; // impair
  2. float randf() {
  3. const unsigned int a = 16807, one = 0x3f800000;
  4. union { float f; unsigned int u; } ran;
  5. lcg *= a;
  6. ran.u = lcg >> (32-23);
  7. ran.u |= one;
  8. return ran.f - 1; // [0, 1[
  9. }

... ou on reconnait le classique 7^5. Ce n'est pas un vrai lcg, mais difficile de faire mieux question taille ou rapidité.
 
 
Sinon, pour ce qui est des trajectoires et du rézo rien ne vaut une petite quantification (edit: notamment des directions)  au milieu pour alleger considerablement les flux.


Message édité par tbp le 03-06-2007 à 13:37:29
Reply

Marsh Posté le 03-06-2007 à 15:42:10    

MagicBuzz a écrit :

ouais mais moi j'aime donner des exemple bidons qui marche pas :o (il s'agit de montrer le principe, pas un truc qui marche :p)


Tant qu'à faire, on peut en donner qui marchent. Le générateur classique (dit congruentiel linéaire), fourni avec la plupart des compilos, est de la forme:

 

V[0] = un nombre premier quelconque, généralement grand (la seed)
V[n+1]= (A x V[n] + B) (modulo M)

 

où V[n] est le nombre aléatoire généré par un appel de fonction à l'étape n, et A, B et M sont des entiers judicieusement choisis. Toute la difficulté est dans le choix de ce triplet, les nombres devant répondre à certains critères particuliers.
Ex de triplet recommandé: A = 1664525, B = 1013904223, et M=2^32
Pour peu que les V[n] soient des unsigned long, tu n'as même pas besoin de faire le modulo 2^32, ton générateur se réduit à une multiplication et une addition, et un cast de V[n] en unsigned int (32 bits).


Message édité par el muchacho le 03-06-2007 à 16:31:04
Reply

Marsh Posté le 03-06-2007 à 16:12:35    

Ce n'est pas aussi trivial, pour une raison simple: pour produire 32bits même avec un 'bon' A aussi petit que souhaitable, encore ce bon vieux 7^5 c.f. plus haut, la multiplication va requérir 46 bits dans le pire des cas.
Comme une bonne partie de la randomisation vient de cette multiplication, il est vital de ne pas paumer de bits en route; d'ou generalement une immersion en 64bits etc... ce qui est couteux.
En plus, les bons lcg avec un modulo 'simple' ne courrent pas les rues (voir le classique BCPL).
 
edit: il y a aussi le problème de la graine, qui est loin d'être trivial.


Message édité par tbp le 03-06-2007 à 16:19:02
Reply

Marsh Posté le 03-06-2007 à 16:33:22    

Effectivement, j'ai corrigé mon post suivant ta remarque. Au passage, je ne sais pas si tu connais SFMT "SIMD Fast Mersenne Twister", ça pourrait t'intéresser...


Message édité par el muchacho le 03-06-2007 à 16:36:22
Reply

Marsh Posté le 03-06-2007 à 16:38:33    

Salut,
 
Si je comprends bien vos derniers posts, l'initialisation classique de la graine par l'"horaire" actuel n'est pas idéal?

Reply

Marsh Posté le 03-06-2007 à 16:43:01    

Tout dépend de l'application.[:spamafote]
Pour un jeu vidéo, une combinaison de l'horloge et de la RAM libre, voire de l'adresse IP, par ex. est probablement suffisante.
Si c'est pour générer une clef pour de la crypto, c'est clair que non. Par ex. pour générer une clef SSH, Putty demande de déplacer la souris au hasard pendant plusieurs secondes.


Message édité par el muchacho le 04-06-2007 à 11:05:57
Reply

Marsh Posté le 03-06-2007 à 17:10:10    

Il y a 2 problèmes avec les graines: fournir suffisamment de bits utiles pour obtenir des séquences suffisamment distinctes mais surtout éviter les graines pathologiques (qui dépendent du lcg choisit).
Par exemple le machin que j'ai fournit n'est pas bon, mais il est pire encore avec une graine pair.
 
PS: oui je connais le MT vectorisé, qui est non seulement plus rapide mais 'meilleur'.

Reply

Marsh Posté le 03-06-2007 à 21:35:41    

Merci à vous 2 :jap: reste plus qu'à approfondir tout ça :)

Reply

Marsh Posté le 03-06-2007 à 22:18:19    

ptitchep a écrit :

Content de voir que ma technique a du bon.
Je n'ai pas encore essayé de l'implémenter mais je me pose déjà une question.
Est-ce qu'envoyer à chaque client toutes les informations sur les autres n'est pas aussi très long?
Par exemple un MMORPG si 100 joueurs sont sur le même niveau. Chaque joueur possède une certaine quantité d'attributs:
position
taille
action en cours
vie
force
arme
armure
...
 
toutes ces informations sont nécessaires au client pour l'affichage et l'interpolation.  Cela ne risque pas de prendre beaucoup de temps?


Heuu en l'occurence seule un très petit nombre de ces infos sont nécessaires au client, on rappelle que le client ne fait aucun calcul, il ne fait que de l'affichage (graphique) donc des choses comme "forme" ou "armure" n'ont aucune raison de lui être transmis [:petrus75]
(sauf si "armure" c'est le numéro de l'armure qu'il porte histoire de pouvoir afficher de jolis modèles texturés)


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 03-06-2007 à 22:56:49    

Je pense plutôt qu'il faisait référence aux points d'armure, pas à l'armure en elle-même :)
Ce qui dans un RPG prend du sens pour laisser le serveur faire les calculs sur les combats afin d'éviter les petits malins qui iraient traffiquer les valeurs à renvoyer au serveur. Enfin, à première vue, et sans trop s'y connaître, ça me semble sensé... sauf pour la charge serveur.

Message cité 1 fois
Message édité par IrmatDen le 03-06-2007 à 22:57:08
Reply

Marsh Posté le 03-06-2007 à 23:14:02    

IrmatDen a écrit :

Je pense plutôt qu'il faisait référence aux points d'armure, pas à l'armure en elle-même :)


Moi aussi, et dans ce cas ça ne doit surtout pas voyager d'un client à l'autre, mais au cas où j'ai précisé


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 03-06-2007 à 23:20:56    

Si, pour affichage sur les caracs de son perso quand même, il a le droit de savoir ça :D

Reply

Marsh Posté le 03-06-2007 à 23:46:09    

IrmatDen a écrit :

Si, pour affichage sur les caracs de son perso quand même, il a le droit de savoir ça :D


Aucun rapport, ca c'est uniquement une communication entre un client précis et le serveur, et c'est fait on-demand (e.g. quand le joueur ouvre sa feuille de perso) donc le coût de bp est négligeable.


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 03-06-2007 à 23:51:58    

Toutes mes confuses, j'ai raté le "pour les autres", d'où HS de goret :sweat:

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed