Pourquoi et comment éviter net.WriteTable

Découvre comment utiliser correctement la bibliothèque net sur Gmod

Niveau Débutant
18 minutes de lecture
Utiliser la bibliothèque net sur Gmod

Dans cette partie, nous allons traiter l'application d'une solution alternative à net.WriteTable, tout en expliquant les dangers de son utilisation.

Pourquoi vouloir envoyer une table via le réseau ?

Le fait d'envoyer une table du serveur au client ou inversément est relativement commun. Par exemple, si vous souhaitez faire une configuration en jeu pour votre addon, vous allez probablement vous retrouver à vouloir envoyer une table de configuration Lua au joueur qui souhaite pouvoir la modifier. Une fois que le joueur a fait les modifications qu'il voulait dans votre table de configuration, vous voudriez sûrement faire en sorte qu'il renvoie la table modifiée au serveur afin que les modifications soient appliquées à votre serveur. On peut aussi penser à plus simple : l'envoi d'une liste des avertissements d'un joueur à un administrateur, ou l'envoi d'une liste d'amis à un joueur. En bref, dès qu'il y a besoin d'envoyer une information qui n'est pas exactement définie, dont la taille peut changer, ou quand on souhaite lier une clé à une valeur, on se retrouve rapidement à vouloir utiliser net.WriteTable. Et pourtant, il ne faut pas.

Mais alors pourquoi net.WriteTable est dangereux ?

Si vous allez voir le code source de net.WriteTable, vous vous rendez compte que cette fonction n'est pas bien complexe. En réalité, elle ne fait qu'itérer dans la table passée comme argument, et envoie toutes les valeurs une par une. Elle envoie ensuite une valeur vide pour indiquer au client qu'il n'y a plus d'autre valeur à lire.

Comprendre le problème à travers un exemple.

Le client auquel vous envoyez votre table ne sait pas à l'avance quel type de variables votre table va contenir. Elle peut contenir 3 strings et 2 integers, comme elle peut contenir 17 vecteurs, 42 valeurs booléennes et 3 sous-tables : il faut lui indiquer. Cela signifie envoyer plus de données à travers le réseau, alors que ce n'est pas nécessaire. Lorsque vous envoyez vos valeurs manuellement, vous savez déjà à l'avance ce que vous allez envoyer et recevoir. Si vous envoyez un string côté serveur, vous savez que vous devez lire un string côté client. Mais avec un net.WriteTable, vous ne savez pas, puisque vous n'utilisez que net.ReadTable pour lire. Et le type de variables présentes dans la table qui s'apprête à être lue, Garry's Mod ne peut pas le deviner à votre place. La solution qui a été trouvée pour contourner ce problème par les développeurs de Garry's Mod est tout simplement d'envoyer aussi le type de la variable qui s'apprête à être lue. Mais ce n'est pas tout : comme c'est une table Lua, chacune de ses valeurs est liée à une clé, qui elle aussi doit être envoyée pour reconstituer exactement la même table.

Nous reviendrons sur cela au prochain point avec un exemple, pas d'inquiétude ! Toutes ces informations sont une charge conséquente d'informations qu'on peut éviter. Pour cela, nous allons envoyer toutes les informations manuellement une par une, les lire, et reconstruire nous-même la table :

Et toc, avec ce code, nous sommes parvenus à envoyer une table à travers le réseau, sans utiliser net.WriteTable. Maintenant que nous savons ça, nous allons comparer ce qu'il se passe en interne pour les 2 solutions et comprendre pourquoi l'envoi manuel des informations est la meilleure.

Comparaisons des solutions

En reprenant l'exemple de la table ci-dessus, voici ce qui est transité par le réseau dans les deux solutions.

Envoi manuel comme dans l'exemple

Comme nous savons déjà côté client ce que nous devons lire, nous n'envoyons que les valeurs. Il n'est pas nécessaire d'envoyer les clés de la table car nous reconstituons la table manuellement avec des nouvelles clés côté client.

Envoi avec net.WriteTable

Comme nous n'avons aucune information sur la table que nous allons recevoir côté client (vu qu'elle est variable et imprévisible), net.WriteTable rajoute automatiquement des informations qui serviront au client :

Vous voyez donc que, involontairement, nous avons evoyé 4 fois plus d'informations sur le réseau que si l'on avait envoyé les données manuellement. Ces informations, bien que minimes à l'échelle individuelle, peuvent avoir un impact sur les performances si la table envoyée est grande.

C'est évidemment un exemple non-contractuel pour faire comprendre le concept. Concrètement, avec net.WriteTable, 16 bits supplémentaires (soit 2 bytes) sont envoyés pour chaque élément de la table.

Relativisons un peu...

Bon, vous le voyez, si vous souhaitez avoir un code performant, il faut éviter net.WriteTable au maximum. Il faut cependant relativiser et garder en tête qu'on parle en mesure de bits. Un bit, c'est un 1 ou un 0. À titre de comparaison, si vous avez une bandwidth de 100 Mbps chez vous, cela signifie que vous pouvez faire transiter 100.000.000 bits par seconde. Sur Garry's Mod, la limite de transfert des paquets est de 64 Ko/s, soit 512.000 bits par seconde. Ce n'est pas les quelques centaines de bits de votre net.WriteTable qui impacteront réellement les performances de votre serveur, surtout avec les composants présents en 2024. Mais quand vous faites du développement, vous devez penser que ceux qui vont utiliser votre addon n'auront pas que le votre sur leur serveur. Et si les autres développeurs faisaient tous cette même mauvaise pratique, cela pourrait alors avoir un impact significatif sur l'optimisation. Vous devez également penser au fait que votre table peut devenir gigantesque avec des milliers de valeurs très rapidement, et remplir le réseau. En bref, écrivez manuellement les valeurs tant que vous le pouvez, cela ne vous coûte que quelques lignes de plus, et ça ne pourra être que bénéfique.

Les exceptions

Pour faire simple, il n'est censé n'y avoir aucune exception : vous avez TOUJOURS la possibilité d'éviter net.WriteTable, d'une manière ou d'une autre. Par exemple, si nous voulions envoyer une table de configuration complexe sans net.WriteTable, voici comment on pourrait s'y prendre :

Bon, vous le voyez, c'est beaucoup de code (dont des appels à des fonctions qui prennent des performances comme table.Count) pour sauver quelques bytes. Est-ce que cela vaut le coup ? C'est à vous de voir si vous favorisez les performances à la practicité.

Si vous avez comme objectif de vendre publiquement des addons, vous devriez le faire dans tous les cas. Sinon, vous devez juger de la pertinence de cette solution par vous-même en vous posant des questions comme :

  • Est-ce que ma table doit être envoyée souvent via le réseau ? Si oui, j'envoie les valeurs manuellement pour les performances.
  • Est-ce que ma table a une structure basique ? Si oui, j'envoie les valeurs manuellement car c'est facile.
  • Est-ce que ma table contient beaucoup de données ? Si oui, j'envoie les valeurs manuellement pour éviter un surplus trop important.
  • Et ainsi de suite...

Si vous ne savez pas, faites-le manuellement par défaut, cela sera toujours mieux. Si c'est vraiment trop compliqué pour vous malgré vos demandes d'aide sur Creators-Area, utilisez net.WriteTable. Faites-le toujours en connaissance de cause, quoi qu'il arrive !

Rejoindre la communauté de développeurs

Rejoins notre communauté de développeurs pour progresser et t'améliorer