Créer une configuration pour votre mod


  • Moddeurs confirmés Rédacteurs

    Introduction

    Il est parfois nécessaire de créer un fichier de configuration pour votre mod afin de permettre à l'utilisateur de personnaliser le comportement de ce dernier ou encore de fournir des données nécessaires au bon fonctionnement de celui-ci. Deux exemples de cas d'utilisation pourraient être :

    • Récupérer les identifiants de connexion à une base de donnée dont votre mod à besoin
    • Permettre à l'utilisateur de régler les dégâts de la super épée que vous venez de créer

    Sommaire du tutoriel

    Pré-requis

    Classe des configurations

    Nous allons regrouper toutes nos variables configurables dans une même classe. Pour ce faire, créez une nouvelle classe. De mon côté, je vais l'appeler ConfigTutorial. De plus, je vais créer deux classes internes que je vais nommer Client et Server qui contiendront respectivement les configurations relatives au client et au serveur.

    Voici donc à quoi ressemble ma classe (vide) :

    public class ConfigTutorial
    {
    
        public static class Server
        {
    
        }
    
        public static class Client
        {
    
        }
    
    }
    

    Nous allons ensuite créer un constructeur à nos classes Server et Client qui prend en paramètre une instance de ForgeConfigSpec.Builder :

    public class ConfigTutorial
    {
    
        public static class Server
        {
    
            public Server(ForgeConfigSpec.Builder builder)
            {
    
            }
    
        }
    
        public static class Client
        {
    
            public Client(ForgeConfigSpec.Builder builder)
            {
    
            }
    
        }
    
    }
    

    Le builder va vous permettre de définir les valeurs à récupérer ainsi que d'autres options telles que le commentaire associé à cet attribut, la clé de traduction à utiliser pour afficher cet attribut dans le GUI de config, etc. Il vous permettra aussi de créer des catégories pour classifier vos attributs.

    Avant de définir ces attributs, nous allons déjà mettre tout en place pour qu'ils soient pris en compte. On va donc créer 4 variables statiques dans notre classe. Une de type Server, une de type Client et deux de type ForgeConfigSpec.

    public class ConfigTutorial
    {
    
        public static final ForgeConfigSpec SERVER_SPECS;
        public static final Server SERVER;
    
        public static final ForgeConfigSpec CLIENT_SPECS;
        public static final Client CLIENT;
    
        // [...]
    
    }
    

    Pour le moment, ces variables ne contiennent pas de valeur, on va donc leur en attribuer. Pour cela, nous allons créer un builder, lui passer le constructeur de la classe Client ou Server (on fera l'un puis l'autre) et l'on récupérera une Pair. Passons au code :

    public class ConfigTutorial
    {
    
        public static final ForgeConfigSpec CLIENT_SPECS;
        public static final Client CLIENT;
        
        public static final ForgeConfigSpec SERVER_SPECS;
        public static final Server SERVER;
        
        static 
        {
            Pair<Server, ForgeConfigSpec> serverPair = new ForgeConfigSpec.Builder().configure(Server::new);
            SERVER_SPECS = serverPair.getRight();
            SERVER = serverPair.getLeft();
    
            Pair<Client, ForgeConfigSpec> clientPair = new ForgeConfigSpec.Builder().configure(Client::new);
            CLIENT_SPECS = clientPair.getRight();
            CLIENT = clientPair.getLeft();
        }
    
        // [...]
    
    }
    

    Maintenant que nous avons donné une valeur à nos variables, nous allons pouvoir indiquer à Forge les spécifications de notre configuration pour le client et le serveur. Pour cela, direction la classe principale, dans le constructeur de celle-ci. On y rajoute deux appels à ModLoadingContext#registerConfig, un pour le client et l'autre pour le serveur.

    @Mod(ModTutorial.MOD_ID)
    public class ModTutorial {
    
        // [...]
    
        public ModTutorial() {
            // [...]
            ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ConfigTutorial.SERVER_SPECS);
            ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ConfigTutorial.CLIENT_SPECS);
        }
        
        // [...]
    
    }
    

    Ajouter des attributs configurables

    Maintenant que tout cela est mis en place, Forge va charger la configuration voulue suivant que vous soyez sur le client ou sur le serveur. Les fichiers de configuration sont au format TOML. Ils sont créés au démarrage du client ou du serveur dans le dossier config.

    Pour ajouter un attribut à ce fichier, il suffit de retourner dans la classe ConfigTutorial. Nous allons, par exemple, ajouter la possibilité au client de désactiver l'accès au GUI de la liste des mods. Pour cela nous allons faire quelques appels au builder passé en paramètre du constructeur de notre classe ConfigTutorial.Client.

    public static class Client
    {
    
        public final ForgeConfigSpec.BooleanValue allowModsGUI;
    
        public Client(ForgeConfigSpec.Builder builder)
        {
            builder.comment("Configuration du client")
                    .push("client");
    
            allowModsGUI = builder
                    .comment("Indique si le GUI de la liste des mods peut s'ouvrir")
                    .define("allowModsGUI", false);
    
            builder.pop();
        }
    
    }
    

    Voyons un peu ce que nous avons fait ici. Dans un premier temps, nous avons créé une nouvelle catégorie nommée client via la méthode push à laquelle nous avons ajouté un commentaire via la méthode comment. Il faut appeler la méthode comment avant ce que nous voulons commenter.

    Nous avons ensuite créer un attribut allowModsGUI de type BooleanValue, cet attribut nous permettra de récupérer la valeur se trouvant dans le fichier de configuration. Nous initialisons cet attribut avec la méthode define. La méthode define possède de nombreuses surcharges suivant le type de retour voulu. Ici, on passe en paramètre le nom de l'attribut que l'on retrouvera dans le fichier de configuration ainsi que sa valeur par défaut.

    Et enfin, nous appelons la méthode pop pour indiquer que nous sortons de la catégorie que nous avons créé précédemment (ici client).

    Nous avons donc créé un attribut dans la classe Client que l'on peut utiliser dans le reste de notre code afin de changer le comportement de notre mod en fonction de la valeur se trouvant dans le fichier de configuration.

    Utiliser un attribut configurable

    Nous allons donc utiliser la valeur indiquée par la configuration afin d'interdire ou non l'accès au GUI de la liste des mods. Pour cela nous allons souscrire à l'event GuiOpenEvent, quand celui-ci sera appelé on vérifiera si le GUI qui s'ouvre est celui de la liste des mods. Dans ce cas, on regardera si l'ouverture est permise, si ce n'est pas le cas on annulera l'événement. C'est parti.

    @Mod.EventBusSubscriber(modid = ModTutorial.MOD_ID)
    public class ConfigTutorial
    {
    
        // [...]
    
        @SubscribeEvent
        public static void cancelModsGUI(GuiOpenEvent event)
        {
            if(GuiModList.class.equals(event.getGui().getClass()) && !CLIENT.allowModsGUI.get())
            {
                event.setCanceled(true);
            }
        }
    
    }
    

    Comme vous pouvez le voir, pour récupérer la valeur se trouvant dans la configuration j'ai simplement appelé BooleanValue#get. Ici, j'ai tout mis dans la même classe mais vous pouvez bien sûr récupérer cette valeur depuis n'importe quel endroit dans votre code.

    Et voilà, à présent vous pouvez lancer votre client, vous devriez trouver un fichier nommé modtutorial-client.toml dans le dossier config de Minecraft avec pour contenu :

    #Configuration du client
    [client]
        #Indique si le GUI de la liste des mods peut s'ouvrir
        allowModsGUI = false
    

    Vous pouvez modifier cette valeur directement depuis le fichier de configuration et tester la différence en essayant de consulter la liste des mods.

    Pour les configurations relatives au serveur, vous pouvez faire exactement pareil dans la classe Server que nous avons créé plus tôt.

    Aller plus loin

    Je vous invite à regarder les méthodes que propose le builder. Il y en a pour les entiers, les booleans, les enums, etc . De plus, vous pouvez définir des clés de traduction pour le texte qui sera affiché dans le GUI de configuration.
    Vous pouvez aussi indiquer que le changement de valeur requiert un redémarrage du monde en cours pour être pris en compte.

    Pour ajouter la possibilité de modifier votre configuration depuis le GUI de configuration accessible depuis la liste des mods, il faut enregistrer une extension via ModLoadingContext#registerExtensionPoint. Il faut enregistrer l'extension ExtensionPoint#CONFIGGUIFACTORY. Cependant, cet appel n'a pas vraiment d'effet, car Forge n'a pas encore ajouté la possibilité de retourner true à ModInfo#hasConfigUI ce qui fait que le bouton pour accéder au GUI de config est désactivé.

    Résultat

    Les différentes modifications du code sont retrouvables sur le commit relatif à ce tutoriel.

    Licence et attribution

    Creative Commons

    Ce tutoriel rédigé par @BrokenSwing corrigé par @DiabolicaTrix et 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

    retour Sommaire des tutoriels



  • J'ai une petite question, ici quand on parle de side client ou serveur, c'est le side physique ou logique ?
    Si par exemple je veux modifier le comportement d'un block en fonction de la configuration. Il faut le faire coté serveur (logique). Dans ce cas, il faut mettre l'option que dans la configuration Serveur ou aussi Client (pour que ça marche aussi en solo) ?


  • Moddeurs confirmés Rédacteurs Administrateurs

    C'est du side physique.

    C'est systématiquement le cas pour les fonctions qui travail avec Dist, d'ailleurs Side.SERVER a maintenant comme nom Dist.DEDICATED_SERVER pour éviter la confusion.
    Pour la distribution logique, c'est surtout world.isRemote() qui va être utilisé.



  • J'ai plutôt l'impression que c'est le side logique. Pour register les spec, on utiliser ModConfig.Type à la place de Dist. Et dans la description de Type.Server, il y a marqué que c'est automatiquement sync avec le client, donc ça faut plus de sens si c'est le side logique (pas besoin de sync si les configs sont que sur le serveur phisique).
    Et de ce que j'ai vu, il y a un dossier serverconfig dans le dossier de mes mondes même en solo, donc à mon avis c'est là dedans qu'il met les configs Serveur.


  • Moddeurs confirmés Rédacteurs Administrateurs

    Ah peut-être, @BrokenSwing tu as plus de détails ?


  • Moddeurs confirmés Rédacteurs

    Je ne me suis pas posé autant de questions, désolé 🙂


Log in to reply