Comment gérer les modifications de version lors de l'enregistrement des actifs?


9

Je travaille sur un RPG depuis un certain temps et j'utilise deux techniques de sérialisation différentes.

  • Les ennemis, les armes et les objets sont aussi enregistrés que XML.
  • Les cartes et les événements sont enregistrés en tant que «binaire contrôlé» (chaque classe obtient une méthode de sauvegarde / chargement et décide ce qu'elle veut sauvegarder / charger).

Mais j'ai commencé à remettre en question mon choix pour les cartes et les événements. Mes préoccupations:

  • J'ai créé un éditeur de carte, mais il me manque encore de pouvoir changer de petites choses en ouvrant simplement le fichier.
  • Les changements gâchent tellement. Disons que je veux ajouter une variable à une classe, si je ne charge / sauvegarde pas chaque carte à nouveau, elle se cassera plus tard.

La première préoccupation est difficile à contourner sans changer ma technique. J'ai pensé à passer au JSON, mais c'est beaucoup de travail. Je pense également que cela semble assez moche avec les attributs [DataContract] et [DataMember] partout.

Cela me laisse avec ma deuxième préoccupation et je me demande comment je peux y faire face? Créez-vous un petit programme qui parcourt toutes les cartes et les ré-enregistrez avec la nouvelle variable? Parce que je commence à obtenir quelques cartes maintenant et je le fais toujours manuellement. Cela me fait réfléchir à deux fois chaque fois que je veux faire des changements car cela crée beaucoup de travail supplémentaire.

Réponses:


5

Il existe de nombreuses façons de gérer le problème de versionnage; vous pouvez le faire en ayant une fonction de chargement par version, vous pouvez essayer d'automatiser le processus en décrivant (via des attributs généralement) la transformation de la structure des actifs au fil du temps, vous pouvez faire des vérifications spécifiques à la version à l'intérieur des fonctions de chargement / sauvegarde, et cetera .

J'aime l'approche «décrire les changements», mais je trouve que tenter de le faire via des attributs devient rapidement gênant . J'utiliserais des fonctions à la place; implémentez une fonction qui transforme les données en version Nen données en version N + 1pour toute votre version appropriée. Lors du chargement, vérifiez la version par rapport à la dernière et, si ce n'est pas le cas, exécutez les données via toutes les fonctions de version appropriées. Enregistrez toujours la dernière version.

Cela fonctionne mieux si vous effectuez la transformation lorsque les données sont encore sous forme de valeur-clé d'exécution. Cela signifie que vous souhaiterez probablement implémenter une représentation pour vos données qui est une approche «sac d'exécution de propriétés», car vous ne pouvez pas utiliser la forme de valeur-clé sous-jacente de JSON ou XML si vous avez votre propre format binaire. Si vous ne le faites pas, vous devrez peut-être également conserver les anciennes définitions de classe, ce qui devient laid. Pouvoir avoir vos actifs dans ce mauvais format de propriété est également extrêmement utile pour le développement de l'éditeur de jeux.

Pendant le développement, au fur et à mesure que vous parcourez vos données, elles remonteront naturellement à la dernière version et vous pourrez éventuellement supprimer les anciennes fonctions de version. Il s'agit plus ou moins de la même approche de haut niveau que nous avons utilisée pour la version des éléments artistiques (tels que les cartes) dans Guild Wars 2.


Maintenant, tout cela dit, je pense qu'il est utile de prendre en charge à la fois le texte et la sérialisation binaire pour les actifs. Pendant le développement, conservez toutes vos données dans un format lisible par l'homme basé sur XML ou JSON. Cela peut augmenter considérablement votre capacité d'itération car vous n'avez pas besoin de créer des outils aussi complexes pour modifier les données. Vous pouvez redevenir capable de faire de simples ajustements rapides à la main.

Deuxièmement, en supposant que vous souhaitiez toujours un format binaire pour l'expédition du jeu (ce qui peut améliorer la taille du fichier ou les temps d'E / S de fichier, c'est donc un souhait valide), concevez vos API de sérialisation et de désérialisation pour gérer la gestion des versions. La gestion des versions est toujours utile dans un contexte d'expédition, car à un moment donné, vous souhaiterez peut-être envoyer des mises à jour ou des corrections de bogues. Il existe certains documents décrivant les capacités de version de la sérialisation .NET et de la sérialisation de Boost qui peuvent vous intéresser. Si vous êtes allez soutenir à la fois le texte et les formats binaires, assurez-vous de les tester de temps en temps (ou de construire des tests automatisés pour le faire, encore mieux).


Merci pour le commentaire, m'a donné quelques idées pour continuer.
user1776562

1

Utilisez un langage de balisage avec des paires attribut-valeur comme XML ou JSON.

L'analyseur peut simplement ignorer tous les attributs qu'il ne comprend pas ou utiliser les valeurs par défaut pour ceux qu'il ne trouve pas, ce qui rend la compatibilité ascendante et descendante assez facile. En outre, le format est lisible par l'homme afin que vous puissiez facilement le modifier avec un éditeur de texte.

Lorsque vous utilisez un langage établi comme XML ou JSON, vous remarquerez également que de nombreux langages de script le prennent en charge, donc lorsque vous avez encore besoin d'écrire un script pour modifier un grand nombre de fichiers, vous le trouverez beaucoup plus facile à faire.

L'inconvénient de la plupart de ces langues est qu'elles sont assez verbeuses. Cela signifie que les fichiers résultants sont beaucoup plus volumineux qu'ils ne devraient l'être avec un format binaire optimisé. De nos jours, la taille du fichier n'a pas trop d'importance dans la plupart des situations. Mais dans ceux où cela importe, la taille du fichier peut souvent être considérablement réduite en compressant le fichier avec un algorithme de stock comme zip.

Les langages de balisage n'autorisent souvent pas l'accès aléatoire à moins que le document entier ne soit lu sur le disque dur et analysé. Mais en pratique, cela n'a pas beaucoup d'importance, car les disques durs sont les plus rapides avec des lectures séquentielles. La recherche aléatoire de plusieurs fois dans différentes parties du même fichier peut souvent être beaucoup plus lente que la simple lecture du fichier en une seule fois, même lorsque cela signifie que vous lisez plus de données que nécessaire.


1

vous pouvez utiliser protobuf. https://code.google.com/p/protobuf/ Il vous offre les avantages de json / xml, que vous pouvez facilement étendre tout en étant rétrocompatible, plus l'avantage d'être binaire. Le flux de travail consiste à créer une description du format de données dans le langage protobuf, puis à générer le code source pour la sérialisation et la désérialisation. La source peut être générée pour plusieurs langues. C'est aussi un gros avantage que vous ayez une spécification claire de vos données sérialisées, contrairement à json où la spécification se fait implicitement en lecture / écriture.


Ça a l'air cool mais j'utilise c #, cela semble être pour c ++, python et java.
user1776562

Il existe une version C #. Je ne l'ai pas testé personnellement, mais il y en a un.
Arne
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.