Sauvegarde de jeu vidéo

Comment mettre en place des fichiers de sauvegarde pour son jeu ?

Le problème exposé dans ce sujet a été résolu.

Bonjour à tous !

Dans le cadre du jeu que je suis en train de développer (ZooShell), je me pose pas mal de questions sur la manière de mettre en place un système de sauvegarde.

Dans la première version, je stockais l’état du zoo dans un bête fichier XML. C’est bien, c’est propre et c’est surtout lisible et modifiable par n’importe qui… Même s’il n’y a pas de notion de compétition dans le jeu, je ne trouve pas ça top.

Une autre solution qui serait facile à mettre en place serait de générer le-dit XML puis de convertir son contenu en Base64. Ok, ce n’est pas immédiatement lisible mais dès qu’un joueur a compris le principe, on retombe dans les travers de la première solution.

J’ai bien une dernière solution : chiffrer le fichier de sauvegarde. Mais dans ce cas, où sauvegarder la clé ? Sachant qu’il s’agit d’un jeu 100% hors-ligne.


Ces questions en amènent une autre. Une fois que le jeu sera distribué, je souhaite continuer à le mettre à jour. Par exemple (je caricature), les animaux pourraient à la sortie du jeu n’avoir qu’un nom, puis trois mois plus tard gagner un âge. Dans ce cas, les données stockées vont évoluer. Je me demande donc comment rendre compatible une sauvegarde d’une ancienne version avec la version actuelle du jeu.

Dans l’exemple précédent, il faut que le jeu soit capable de charger un animal pour lequel la notion d’âge n’apparaît pas du tout dans la sauvegarde. Je vois deux process pour traiter ce cas :

  • le côté facultatif de l’âge est traité directement dans la fonction de chargement de la sauvegarde, un truc du style :
1
2
3
4
5
if (age == null){
   animal.age = 0;
} else {
   animal.age = age;
}
  • ou un petit programme appelé avant la fonction de chargement et qui transforme l’ancienne sauvegarde en sauvegarde au format actuel ?

La seconde solution me plaît bien car elle permet de ne pas faire porter la complexité et la lourdeur de la gestion des anciens formats de sauvegarde par la fonction de chargement. Mais je suppose qu’elle a des inconvénients que je ne vois pas pour l’instant ?

De manière générale, si quelqu’un a de la documentation sur le sujet, je suis preneuse. Je n’ai pas trouvé grand chose sur Internet, au-delà des "Sauvegarde dans un fichier texte !" et des "Mais est-ce que tu sais déjà ce que tu veux sauvegarder comme infos ?".

Line

Dans la première version, je stockais l’état du zoo dans un bête fichier XML. C’est bien, c’est propre et c’est surtout lisible et modifiable par n’importe qui… Même s’il n’y a pas de notion de compétition dans le jeu, je ne trouve pas ça top.

C’est un débat, doit t-on autoriser la triche dans un jeu offline ? je serais plutôt pour mais chacun son choix.

Tu pourras pas sécuriser complètement, tu peux chiffrer les sauvegardes mais la clé doit-être avec le programme, si tu veux pouvoir déchiffrer. Tu as pas de solution qui soit incassable. Mais rien que chiffrer les sauvegardes est une solution pour moi, un bon compromis entre temps dev/sécurisation.

La seconde solution me plaît bien car elle permet de ne pas faire porter la complexité et la lourdeur de la gestion des anciens formats de sauvegarde par la fonction de chargement. Mais je suppose qu’elle a des inconvénients que je ne vois pas pour l’instant ?

C’est une bonne idée, le seul point un peu compliqué est de bien gérer le cas suivant: imagine que tu as 5 mise à jours de ton jeu. J’ai pas fait les trois dernières mise à jours car j’était trop occuper à cueillir des pissenlits. Il faut que tu puisse enchainer les mises à jours 3,4,5 ou de fournir un mécanisme qui te permette de passer de 1 à 5 directement.

+1 -0

C’est un débat, doit t-on autoriser la triche dans un jeu offline ? je serais plutôt pour mais chacun son choix.

Je suis plutôt d’accord. Autant développer ton jeu avec des sauvegardes sous forme de fichier json ou un format de ce genre et voir à la fin si tu veux développer un module qui permet de chiffrer/déchiffrer les fichiers. Et peut-être laisser le choix à l’utilisateur !

Il faut que tu puisse enchainer les mises à jours 3,4,5 ou de fournir un mécanisme qui te permette de passer de 1 à 5 directement.

Tu peux écrire tes fonctions de maj comme s’appliquant directement aux données de la maj précédente. Comme ça si un utilisateur à loupé des maj il suffira de chainer les fonctions de maj pour être sur que ça se comportera bien. La maj sera plus lente, mais ça maintient un processus clean que d’essayer de sauter les étapes.

Il suffit que la base de donnée contienne un champ indiquant de quelle version elle provient et que chaque nouvelle version contienne l’ensemble des fonctions de conversion. La nouvelle version aura juste à lire l’état de la base de données et à appliquer les fonctions nécessaires.

L’inconvénient est que chaque client devra contenir toutes les différentes fonctions de migration de base, ce qui peut vite devenir lourd et inutile. Tu peux résoudre partiellement cela en arrêtant d’intégrer les fonctions de maj a partir de par exemple 10 maj ratées et alors dire à l’utilisateur que sa version est trop ancienne et que sa sauvegarde ne peut pas être récupérée.

+0 -0

Je ne pense pas que chiffrer les sauvegardes puisse vraiment servir ton jeu. Dans des jeux type rogue like où le joueur débloque des objets, ou des secrets, au fur et à mesure de ses runs, le chiffrement des sauvegarde est une mécanique cohérente.

Comme dit au dessus, tu ne pourra de toute façon pas assurer un chiffrage incassable, a moins de passer par un serveur dédié qui se chargerais de déchiffrer le fichier, mais ton jeu ne sera plus jouable en hors ligne.

En ce qui concerne la mise à jour des fichiers, la meilleure solution a mon avis serait d’imiter le comportement des migrations de base de données. Donc ça revient à ce qui a été dit au dessus, prévoir un mécanisme permettant de migrer ton fichier de la v1 à la v2, puis de la v2 à la v3 et ainsi de suite. Pour ça, il faudra intégrer le numéro de version de ta sauvegarde dans ton fichier de sauvegarde et au chargement dudit fichier, prévenir l’utilisateur qu’il nécessite de mettre à jour son fichier.

Autre que le chiffrement de la sauvegarde, tu peux aussi ajouter une somme de contrôle.

Ça n’empêche toujours pas la triche, mais ça la rend plus difficile (il doit savoir comment tu calcules la somme, à partir de quelles données).

Pour ce qui est des mises à jour, je suis partisan de la seconde solution. Le format de données est versionné, une nouvelle version entraîne une migration de la sauvegarde.

L’inconvénient est que chaque client devra contenir toutes les différentes fonctions de migration de base, ce qui peut vite devenir lourd et inutile. Tu peux résoudre partiellement cela en arrêtant d’intégrer les fonctions de maj a partir de par exemple 10 maj ratées et alors dire à l’utilisateur que sa version est trop ancienne et que sa sauvegarde ne peut pas être récupérée.

Demandred

Pas compris cette partie. Si tu es à la v2, que tu souhaites aller à la v4, il suffit de télécharger puis exécuter les fonctions de migration pour la v3 et la v4. La v4 n’a pas besoin de contenir la fonction de migration de la v3. Et une fois appliqué on supprime les fonctions de migration (quel que soit leurs formes).

ce qui peut vite devenir lourd et inutile.

Demandred

Définis "vite" et "lourd" stp.

Là j’ai un truc où après 3-4 ans j’ai quelques centaines de migrations, au total une fois compilé ça fait environ 9Ko. C’est beaucoup trop lourd ou pas ? Est-ce que c’est plus lourd que l’image utilisée comme icône de bureau du jeu ?

+2 -0

Salut LineVa,

Si tu veux t’amuser un peu niveau programmation j’ai découvert récemment le bytecode pattern qui permet de résoudre ton problème car ton fichier de sauvegarde sera un tableau de bytes, difficilement modifiable .

Grosso modo tu vas devoir implémenter une partie qui va encoder tes datas (pour enregistrement dans un fichier) et une partie qui va les décoder (pour réutilisation dans le jeu). Ca revient à implémenter une mini VM ou un mini langage de script, très intéressant à développer.

Vu la structure de ton jeu et de tes nombreuses espèces, je pense que le Type Object pattern pourrait également t’intéresser :)

Personnellement, j’aurais simplement sérialisé la sauvegarde avec éventuellement un checksum simple.

+1 -0

Personnellement, j’aurais simplement sérialisé la sauvegarde avec éventuellement un checksum simple.

ache

La sérialisation, c’est vaste… Tu peux sérialiser en XML, JSon, ou utiliser la sérialisation standard de Java.

Et la sérialisation standard de Java ne protège rien du plus (ça complique juste l’édition du fichier, et encore).

Donc le checksum ne doit pas être éventuel, c’est la seule passe de sécurité qu’il y aurait.

+0 -0

Merci à tous pour vos réponses, vous m’avez donné de quoi réfléchir.

Dans le désordre :

  • L’idée de la checksum me plaît bien à condition de la coupler avec chiffrage/encodage quelconque. Cela devrait permettre une protection au-moins basique, à la fois contre la lecture et contre l’édition des fichiers de sauvegarde.
  • Je ne connais pas le bytecode pattern et le TypeObject, il faudra que j’aille y jeter un oeil pour voir si ça peut m’aider.
  • Pour la "mise-à-jour" des sauvegardes, je pense que je vais m’orienter vers ma seconde solution, le petit programme qui se charge de convertir les sauvegardes, puisque personne n’a soulevé de gros points négatifs. Le poids ne devrait pas être un problème a priori, je ne compte pas changer entièrement le format de sauvegarde d’une semaine à l’autre. Par contre, cela amène à une autre question : vaut-il mieux faire les conversions lorsque l’on demande à charger une sauvegarde ou convertir toutes les sauvegardes lorsque l’on télécharge une nouvelle version du logiciel ? La première solution me plaît plus car elle permet de ne convertir que les sauvegardes que l’on utilise effectivement.

Merci beaucoup à tous pour vos idées et votre aide !

Pour un jeu 100% hors ligne, il est parfaitement impossible d’empêcher la triche. Si tu veux avoir une bonne protection, il faut que tu définisses le "niveau" de menace. Pour clarifier les choses, ça ne sert à rien d’essayer de se protéger contre quelqu’un qui a assez de connaissances pour lire le binaire de ton jeu pour regarder comment il fonctionne. Donc en supposant que ton attaquant n’ai pas accès au code source de ton jeu, tu veux simplement qu’il n’ai pas moyen de comprendre la manière dont tes sauvegardes fonctionnent. Pour ça, chiffrer la sauvegarde est une possibilité suffisante.

Niveau mise à jour, il faut aussi penser qu’une sauvegarde peut être à un endroit inaccessible lors de la mise à jour du jeu. Par exemple, si quelqu’un fait une copie de la sauvegarde dans le cloud ou sur un clé USB ou n’importe où. Dans ce cas, il est tout à fait possible que le jeu ai été mis à jour il y a plusieurs mois et qu’il se retrouve quand même à devoir lire une sauvegarde sous un vieux format. Il faut donc que ton programme soit capable de faire la conversion à la lecture. En revanche, rien n’empêche de faire la conversion en plus directement lors de la mise à jour.

Salut Berdes (et les autres qui ont aussi évoqué le sujet) !

Je sais bien que je ne peux pas empêché totalement la triche. Et je ne le souhaite pas, on est bien d’accord là-dessus. Simplement, je voudrais qu’il y ait un niveau minimal de sécurité.

Par exemple, chaque animal possède une quantité de nourriture nominale, celle qui le rendra le plus heureux et qui le maintiendra en bonne santé. Le joueur ne connaît pas cette valeur et une des mécaniques du jeu est de s’en rapprocher par essais/erreurs. Cette valeur sera donc logiquement présente dans les sauvegardes de la partie. Et ça m’embêterais qu’un joueur se contente simplement de lire la valeur dans la sauvegarde…

Après, il est vrai que s’il fait ça, il se gâchera juste le plaisir lui-même, pas celui des autres. Les problématiques de sécurité sont moins importantes que pour un jeu multi-joueurs.

Personnellement, j’aurais simplement sérialisé la sauvegarde avec éventuellement un checksum simple.

ache

La sérialisation, c’est vaste… Tu peux sérialiser en XML, JSon, ou utiliser la sérialisation standard de Java.

Et la sérialisation standard de Java ne protège rien du plus (ça complique juste l’édition du fichier, et encore).

Donc le checksum ne doit pas être éventuel, c’est la seule passe de sécurité qu’il y aurait.

JuDePom

Sérialisation et JSON, pour moi, c’est pas compatible. Même si bon certaines personnes associent ces terment.

Quand je parle de sérialisation, je parle de stocker les structures dans un format binaire, dans le sens originel, c’est à dire en stockant des données de façon atomique.

J’ai jamais dis que c’était plus sécurisé. Mais je pars totalement du principe que si c’est 100% hors ligne alors tu ne peux pas empécher la triche (ce qui est vrai dans la plus part des cas).

La sérialisation à plusieurs avantages, c’est un format simple mais non trivial à modifier tout en restant très légé.

Le checksum est tout simplement là pour vérifier qu’une modification n’ai pas été réalisée sur le fichier de sauvegarde, sans apporté une sécurité solide puisque rien n’empèche de modifier le checksum. Ce qui est encore plus simple que modifier un fichier binaire.

Avec ce type de protection, on protège simplement d’un petit malin. C’est ridicule et tout aussi efficace que de chiffrer avec de l’AES 256. C’est simplement perdre du temps pour faire perdre du temps à d’autres (celui qui voudra tricher trichera).

Du coup, autant rester sur un truc simple comme protection. Ou alors on ne protège pas du tout, ce qui est plus intelligent je pense.

+0 -0

Sérialisation et JSON, pour moi, c’est pas compatible. Même si bon certaines personnes associent ces terment.

Quand je parle de sérialisation, je parle de stocker les structures dans un format binaire, dans le sens originel, c’est à dire en stockant des données de façon atomique.

ache

Il n’y a rien qui impose le codage. Tu peux faire ça en texte si tu le veux, et JSON n’empêche pas le terme "sérialisation".

L’idée n’est pas d’empêcher vraiment la triche je pense mais de la décourager en y imposant un coût minimum. Typiquement si tout est stocké en clair en json n’importe quel joueur sans aucune connaissance en informatique devrait pouvoir modifier sa sauvegarde et tricher. Si il faut déchiffrer un fichier chiffré en AES 256 alors peu de gens feront l’effort pour cela sauf si ils ont vraiment envie de tricher.

+0 -0

L’idée n’est pas d’empêcher vraiment la triche je pense mais de la décourager en y imposant un coût minimum. Typiquement si tout est stocké en clair en json n’importe quel joueur sans aucune connaissance en informatique devrait pouvoir modifier sa sauvegarde et tricher. Si il faut déchiffrer un fichier chiffré en AES 256 alors peu de gens feront l’effort pour cela sauf si ils ont vraiment envie de tricher.

Demandred

Oui si le jeu est assez répandu, il y aura des gens pour développer des outils dédiés à la triche pour ce jeu.

Il n’y a rien qui impose le codage. Tu peux faire ça en texte si tu le veux, et JSON n’empêche pas le terme "sérialisation".

Ksass`Peuk

La page wikipédia en français est plutôt floue sur ce point. Mais celle en anglais est très claire. Ce que j’appele sérialisation est dénommée ’marshalling’ en anglais. D’après Wiki, encore une fois, ce serrait traduit par ’Sérialisation, linéarisation’.

Bref, j’aurais appris un truc.

EDIT: J’ai pas été claire sur le point mais la page wikipédia anglais vous donne raison. D’où le fait que j’ai appris un truc.

+0 -0

L’idée n’est pas d’empêcher vraiment la triche je pense mais de la décourager en y imposant un coût minimum. Typiquement si tout est stocké en clair en json n’importe quel joueur sans aucune connaissance en informatique devrait pouvoir modifier sa sauvegarde et tricher. Si il faut déchiffrer un fichier chiffré en AES 256 alors peu de gens feront l’effort pour cela sauf si ils ont vraiment envie de tricher.

Demandred

Oui si le jeu est assez répandu, il y aura des gens pour développer des outils dédiés à la triche pour ce jeu.

entwanne

Si on en arrive là, je serais plus que contente ! Ca voudrait dire que j’ai pu terminer mon jeu et en faire un produit de qualité et qui plaît !

Sinon, Demandred a bien résumé mon idée : imposer un coût minimum pour tricher sans pour autant passer des jours/semaines à inventer des systèmes tordus pour l’empêcher au maximum.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte