Persistance des données avec WorldSavedData



  • Sommaire

    Introduction

    Ce tutoriel va vous présenter tout ce qu'il y a à savoir sur la persistance de vos données via la classe WorldSavedData.
    WorldSavedData est une classe abstraite qu'il vous faudra étendre afin de sauvegarder vos données via le système de sauvegarde Minecraft.

    Prérequis

    • Savoir utiliser les NBTTags

    Classe de base

    ​public class MaClasseASauvegarder extends WorldSavedData {
    
        /**
        /* Ce constructeur est obligatoire
        */
        public MaClasseASauvegarder(String key) {
            super(key);
        }
    
        @Override
        public void readFromNBT(NBTTagCompound p_76184_1_) {
        // Vous remplissez les attributs de votre objet via le NBTTagCompound
    
        }
    
        @Override
        public void writeToNBT(NBTTagCompound p_76187_1_) {
        // Vous écrivez le contenu de votre objet dans le NBTTagCompound
    
        }
    }
    

    La key

    Votre objet sera stocké dans la MapStorage de votre monde ou de votre dimension, il va donc vous falloir une clé pour sauvegarder et retrouver votre objet. Si votre objet est de type singleton, ce qui sera vrai dans la plupart des cas, la clé devra être invariable. Pour les néophytes en conception, un singleton est une classe qui ne peut avoir qu'une seule instance. La classe de base de votre mod en est un.

    Ainsi je vous recommande de créer soit un attribut static final String, soit une fonction static String qui représentera votre clé.
    Pour éviter les conflits avec d'autre mods, je vous conseil de faire préfixer votre clé par le modid de votre mod.

    Charger vos données

    Voici une fonction que vous pouvez ajouter à votre code si vos données sont propres à chacune de vos dimensions, nous allons la commenter.

    ​public static MaClasseASauvegarder load(World w) {
        MapStorage storage = w.perWorldStorage; //On récupère la mapStorage de la dimension
        final String KEY = getDataStorageKey(); // Si vous avez choisis de faire une fonction static String. Quoiqu'il en soit, la variable KEY que nous utiliserons ici représente votre clé. Si vous utilisez un attribut static, utilisez le directement.
        MaClasseASauvegarder result = (MaClasseASauvegarder)storage.loadData(MaClasseASauvegarder.class, KEY);//On charge nos données
        if (result == null) { //Si nos données n'existe pas, …
            result = new MaClasseASauvegarder(KEY);// Alors on les crée …
            storage.setData(KEY, result);// Et on les ajoutes à la mapStorage.
        }
    
        return result; //On retourne notre objet qui représente les données a sauvegarder
    }
    

    Après avoir appelé cette fonction, dès que la dimension sera sauvegardée, votre objet sera pris en compte dans le processus vu qu'il est enregistré dans la mapStorage. Vous pouvez appeler cette fonction quand vous voulez dès lors que vous avez une référence vers une dimension chargée et que vous avez besoin d'une référence vers votre objet. Lorsque vos données sont liée a une dimension particulière, il est conseillé de charger vos données via l'event : WorldEvent.Load mais rien ne vous y oblige.

    Il existe une variante de tout ce que je viens de dire jusqu'à présent. Si vos données ne sont pas liées à vos dimensions mais a votre monde.
    Dans ce cas, vous pouvez reprendre la fonction load() et supprimer le paramètre World.
    Vous chargerez la mapStorage via :

    ​ if(DimensionManager.getWorlds().length < 1) return null;
    MapStorage storage = DimensionManager.getWorlds()[0].mapStorage;
    

    Et vous devrez charger vos données lorsqu'au moins une dimension est chargée. Je vous conseil d'utiliser l'event FMLServerStartedEvent à utiliser avec un @EventHandler dans votre classe principale.

    Sauvegarder vos données

    Lors de la sauvegarde de votre monde, le système vérifie si vos données doivent être sauvegardées via la méthode isDirty().
    Pour que vos données soit sauvegardées, vous devez auparavant appeler la méthode markDirty() pour que isDirty() retourne true.
    Une fois la sauvegarde effectuée, isDirty() retourne false.
    Par conséquent, après chaque changement de vos données, vous devez appeler la méthode markDirty().

    Informations utiles

    Si vos données sont propre à une dimension et ont besoin de celle-ci, votre objet devra avoir un attribut World.
    Ne le sauvegardez pas ! Inutile de faire quelque chose qui ne sert à rien.
    Initialisez plutôt votre attribut juste avant de le retourner dans la fonction load(World w).

    Crédits

    Rédaction :

    • Blackout

    Correction :

    Creative Commons
    Ce tutoriel de Blackout publié sur Minecraft Forge France est mis à disposition selon les termes de la licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International

    retourRetour vers le sommaire des tutoriels



  • C'est pas très clair je trouve. Quel est l'utilité réel ? La fonction "load" est appelée quand et comment ? Et qu'est-ce que représente la classe "WorldHealer" ?



  • @'SCAREX':

    C'est pas très clair je trouve. Quel est l'utilité réel ? La fonction "load" est appelée quand et comment ? Et qu'est-ce que représente la classe "WorldHealer" ?

    WorldHealer c'est une trace de mon mod ^^ Une erreur de ma part, j'ai remplacé tout les WorldHealer par "MaClasseASauvegarder" sauf a un endroit ^^ C'est chose faite a présent 😉

    La fonction load est appelé dès lors que tu as besoin d'une référence vers tes données.

    L'utilité c'est de sauvegarder tes données via le système de sauvegarde Minecraft avec celle du monde ou de la dimension.



  • Et tu n'as pas expliqué sur qu'il faut enregistrer dans les NBT, un exemple serait bien.

    Sinon, plutôt bon tutoriel, je connaissais pas l'existence de cette classe.



  • @'SCAREX':

    Et tu n'as pas expliqué sur qu'il faut enregistrer dans les NBT, un exemple serait bien.

    Sinon, plutôt bon tutoriel, je connaissais pas l'existence de cette classe.

    Les NBT ne sont pas propre a cette classe, donc c'est un pré-requis, je vais faire les modifs sur le post 🙂
    Je ne vais pas expliquer ce que sont les NBTTag ni comment on s'en sert, il y a déjà plein de tutoriels qui en parle.



  • J'ai pas dit çà, je dis juste que les NBT sont pour pleins de choses : entités, blocs, items, etc. Il faudrait juste mettre un exemple.



  • @'SCAREX':

    J'ai pas dit çà, je dis juste que les NBT sont pour pleins de choses : entités, blocs, items, etc. Il faudrait juste mettre un exemple.

    A partir du moment où on sait remplir un NBTTag avec n'importe quelle classe que se soit, on sait le faire pour tout et n'importe quoi.
    Sinon c'est qu'on a pas compris ce que sont les NBTTags et qu'on se contente de faire du copier/coller de tutoriels.
    Les NBTTag servent à la sérialisation au format Minecraft. A partir de la, on peut s'en servir pour toutes les classes possibles et inimaginables.



  • Oui mais tu ne dis pas où vont aller les NBT tags, est-ce que ce sera pour le monde ? Pour la dimension ? Pour tous les blocs d'une dimension ?


  • Administrateurs

    Ça sauvegarde dans la dimension. Et dans le cas où tu as besoin de sauvegarder dans le monde en général tu utilise la dimension 0. C'est précisé dans le tuto.



  • @'robin4002':

    Et dans le cas où tu as besoin de sauvegarder dans le monde en général tu utilise la dimension 0.

    Non, n'importe quel monde. Il faut juste utiliser l'attribut mapStorage qui est commun a toutes les instances de World au lieu de perWorldStorage.


  • Correcteurs

    côté serveur, il faut le faire côté serveur ou ça n'a pas d'importance?



  • Généralement les données sont sauvegardés sur le serveur. Le client n'a juste qu'une copie partielle des données.



  • Salut !

    Bon, je sais que le sujet est vieux, mais ayant galéré pendant un moment sur quelque chose de vraiment bête, je pense qu'il est utile de préciser pour les futurs lecteurs du tutoriel que l'argument String dans le constructeur de la classe est INDISPENSABLE ! En effet, pour des raisons obscures, ceci ne fonctionne pas :

    public MaClasseASauvegarder (){
         super ("maCle");
    }
    

    Il faut vraiment utiliser ceci :

    public MaClasseASauvegarder (String key){
         super (key);
    }
    

    Car sinon votre constructeur ne sera pas détecté (en tout cas c'est ce que je pense) et vous aurez une exception.
    Bonne journée !  😉


  • Administrateurs

    @'TheRedColossus':

    Bon, je sais que le sujet est vieux

    Aucun problème, les tutoriels peuvent être up à tout moment. (c'est d'ailleurs vrai pour n'importe quelle discussion du forum à partir du moment où le up apporte quelque chose à la discussion ;))