6
votes

Quelle est la meilleure bibliothèque de compression pour de très petites quantités de données (3-4 kib?)

Je travaille sur un moteur de jeu qui est descendu de manière lâche à partir de la Quake 2, en ajoutant des éléments tels que les effets scriptés (permettant au serveur de spécifier des effets spéciaux en détail à un client, au lieu d'avoir seulement un nombre limité d'effets codés sur lesquels Le client est capable de.) Il s'agit d'un compromis d'efficacité réseau pour la flexibilité.

J'ai frappé une barrière intéressante. Voir, la taille maximale du paquet est de 2800 octets, et un seul peut sortir par client par image.

Voici le script pour faire un effet "étincelles" (pourrait être bon pour les étincelles d'impact de balle, des chocs électriques, etc.) http://pastebin.com/m7acdf519 (si vous ne comprenez pas, ne le faites pas transpirer; c'est Une syntaxe personnalisée que j'ai faite et non pertinente pour la question que je demande.)

J'ai tout fait de tout possible pour réduire la taille de ce script. J'ai même réduit les noms de variables aux lettres simples. Mais le résultat est exactement 405 octets. Ce qui signifie que vous pouvez correspondre au plus 6 de ceux-ci par image. J'ai également à l'esprit quelques changements côté serveur qui pourraient la raser un autre 12 et un changement de protocole qui pourrait enregistrer une autre 6. Bien que les économies varient en fonction de l'écriture avec laquelle vous travaillez.

Cependant, de ces 387 octets, j'estime que seulement 41 serait unique entre plusieurs usages de l'effet. En d'autres termes, il s'agit d'un candidat principal pour la compression.

Il arrive tellement que R1Q2 (un moteur à la séquelle compatible avec un protocole réseau étendu) a un code de compression zlib. Je pourrais soulever ce code, ou au moins le suivre étroitement comme une référence.

mais zlib est-il nécessairement le meilleur choix ici? Je peux penser à au moins une alternative, Lzma, et il pourrait facilement y avoir plus.

Les exigences:

  1. doit être très rapide (doit avoir une très petite performance touchée si elle est exécutée plus de 100 fois une seconde.)
  2. doit faire du autant de données que possible en 2800 octets
  3. Petite empreinte de métadonnées
  4. Compatible GPL

    zlib est bon, mais y a-t-il quelque chose de mieux? N'oubliez pas que rien de ce code n'est encore fusionné, il y a donc beaucoup de place à l'expérimentation.

    merci, -Max

    Edit: Merci à ceux qui ont suggéré de compiler les scripts en bytecode. J'aurais dû faire cela clair-- oui, je fais ça. Si vous aimez que vous puissiez parcourir le code source concerné sur mon site Web, bien que ce ne soit toujours pas «pillé».
    Ceci est le code côté serveur:
    Composant Lua: http://meliaserlow.dyndns.tv:8000/alienarena/ lua_source / lua / scriptedfx.lua
    C Composant C: http://meliaserlow.dyndns.tv:8000/alienarena/ lua_source / game / g_scriptedfx.c
    Pour l'exemple spécifique Script i Publié, cela reçoit une source de 1172 octets à 405 octets - toujours pas assez petit. (Gardez à l'esprit que je veux en tenir l'autant que possible dans 2800 octets!)

    EDIT2: Il n'y a aucune garantie qu'un paquet donné arrivera. Chaque paquet est censé contenir «l'état du monde», sans s'appuyer sur des informations communiquées dans des paquets précédents. Généralement, ces scripts seront utilisés pour communiquer "Candy des yeux". S'il n'y a pas de place pour un, il est tombé du paquet et ce n'est pas grave. Mais si trop d'être chuté, les choses commencent à sembler étrange visuellement et cela n'est pas souhaitable.


4 commentaires

A-t-il besoin d'être rapide au côté de la compression ou seulement dans la décompression?


Je dirais que la vitesse de la compression est plus importante. Parce que différents paquets sont compressés du côté serveur pour chaque client par image (alors que le client doit uniquement décompresser un paquet par cadre supérieur.)


Même si c'est vieux, je suis curieux: pourquoi voudriez-vous envoyer des scripts entiers sur une base par trame au lieu d'une fois, lorsque le joueur se connecte (ou ajoutez même un jeu mi-jeu, mais j'envoie toujours à chacun une seule fois), puis envoyez-vous simplement un identifiant de script et des paramètres?


Ma raison originale était donc pour pouvoir envoyer des variantes légèrement différentes du script (différentes couleurs, origines, intensités, etc.) à chaque fois. Après avoir vraiment affiné mon format de bytecode, la plupart des "scripts" étaient moins de 50 octets non compressés, ce qui est quelque peu raisonnable. Cependant, j'ai fini par la mettre en cache côté client et simplement la révision des "arguments" séparément à chaque fois. Et puis, après tout cela, j'ai fini par ne pas utiliser le système FX scripté du tout. :)


6 Réponses :


4
votes

Lzo pourrait être un bon candidat à cela.


0 commentaires

1
votes

ZLIB pourrait être un bon candidat - la licence est très bonne, fonctionne vite et ses auteurs disent que cela a très peu Les frais généraux et les frais généraux sont la chose qui utilise pour de petites quantités de données problématique.


0 commentaires

0
votes

Je serais à l'encontre d'utiliser le bit le plus significatif de chaque caractère, qui est actuellement gaspillé, par des groupes de 9 octets de 9 octets, vous entrez dans 8 octets.

Vous pouvez aller plus loin et cartographier les caractères dans un petit espace - pouvez-vous les obtenir jusqu'à 6 bits (c.-à-d. Avoir 64 caractères valides) par, par exemple, ne pas permettre des lettres majuscules et soustraire 0x20 de chaque caractère (de sorte que L'espace devient la valeur 0)

Vous pouvez aller plus loin en mappant la fréquence de chaque caractère et faire une compression de type Huffman pour réduire les bits de numéro d'avariement de chaque caractère.

Je soupçonne qu'il n'y a pas d'algorithmes qui permettront de sauvegarder des données meilleures que, dans le cas général, car il n'y a essentiellement pas de redondance dans le message après les modifications apportées par Alady.


1 commentaires

Ceci est déjà "compilé" (ou peut-être devrais-je dire "assemblé") côté serveur dans un format de style bytecode très compact. Dans cet exemple, la taille du sifflement est de 1172 octets, de manière prohibitive. Merci pour la réponse cependant. :)



0
votes

Que diriez-vous d'envoyer une représentation binaire de votre script?

Donc, je pense dans les lignes d'un arbre de syntaxe abstrait avec chaque procédure ayant un identifiant.

Ceci signifie gain de préformance sur les clients en raison de l'analyse unique et de la diminution de la taille due à la suppression des noms de méthodes.


1 commentaires

J'aurais dû faire cela clair-- oui, je fais ça. Si vous aimez que vous puissiez parcourir le code source correspondant sur mon site Web, bien que ce ne soit toujours pas "reproduit". Ceci est le code côté serveur: composant Lua: MeliaSerlow.dyndndns.tv : 8000 / Alienarena / Lua_source / Lua / ... C Composant: MeliaSerlow.dyndns.tv:8000/alienarena/lua_source/game/... Cela obtient une source de 1172 octets à 405 octets - toujours pas assez petit. Bonne idée cependant; C'était assez grand que je pensais aussi! ;)



1
votes

Vous devriez regarder OPENTNL et adapter certaines des techniques qu'ils utilisent, comme le concept de chaînes de réseau


0 commentaires

2
votes

Mise à jour finale: Les deux bibliothèques semblent à peu près équivalente. Zlib donne une compression de 20% à environ 20%, tandis que la vitesse de décodage de Lzo est d'environ deux fois plus rapide, mais la performance frappée est très petite, presque négligeable. C'est ma réponse finale. Merci pour toutes les autres réponses et commentaires!

Mise à jour: Après la mise en œuvre de la compression de Lzo et ne voyant que de meilleures performances, il est clair que mon propre code est à blâmer pour le succès de la performance (nombre massivement augmenté d'effets scriptés par paquet, donc mon Effet "Interprète" s'exerçoit beaucoup plus.) J'aimerais m'excuser humblement de se mariner de blâmer, et j'espère qu'il n'y a pas de sens difficile. Je ferai du profil et je pourrai peut-être obtenir des chiffres qui seront plus utiles à quelqu'un d'autre.

message original:

OK, je me suis enfin jeté pour écrire du code pour cela. J'ai commencé avec Zlib, voici la première de mes conclusions.

La compression de Zlib est Indientalement génial. Il réduit de manière fiable des paquets de, disons, 8,5 kib sur, disons, 750 octets ou moins, même lors de la compression avec z_best_speed (au lieu de z_default_compression.) Le temps de compression est également très bon.

Cependant, je n'avais aucune idée de la vitesse de décompression de rien de pourrait même être ce mauvais. Je n'ai pas de chiffres réels, mais il doit prendre 1/8 second par paquet au moins! (Core2duo T550 à 1,83 GHz.) Totalement inacceptable.

De ce que j'ai entendu, Lzma est un compromis de pire performance vs meilleure compression par rapport à Zlib. Étant donné que la compression de Zlib est déjà surchargée et que ses performances sont déjà incroyablement mauvaises, Lzma est hors de la visibilité de la table pour l'instant.

Si le temps de décompression de Lzo est aussi bon que celui qui est prétendu être, c'est ce que j'utiliserai. Je pense que dans la fin, le serveur sera toujours en mesure d'envoyer des paquets ZLIB dans des cas extrêmes, mais les clients peuvent être configurés pour les ignorer et que ce sera la valeur par défaut.


1 commentaires

Eh bien, ce n'est peut-être pas que mal, je ne l'ai pas réellement choisi. Il est tout à fait possible qu'il y ait une sorte de réglage que je ne fais pas. Je vais regarder quelques autres codesbases et documentation à voir. En tout état de cause, les résultats ont l'air jolie poisson, je pourrais faire des synchronisations avec GZIP et quelques données de test pour voir si elle peut vraiment être si lente. Je soupçonne que ce n'est que des frais généraux, et si je décompressais quelque chose 100 fois plus grand, cela prendrait le même temps. Ou quelque chose , je ne peux tout simplement pas croire que l'algorithme alimenté GZIP est si lente.