Group Details Private

Rédacteurs

  • RE: Envoie de packets non fonctionnel

    Salut,
    Déjà le premier truc que je ne comprend pas trop c'est que tu sembles avoir souscrit à l'event de tick du monde du côte client puis tu envoies un paquet au serveur ? Pourquoi ? Le serveur est capable de souscrire à l'event lui même

    posted in Support pour les moddeurs
  • RE: Erreur NullPointerException : Can't use a null-name for the registry, object Block{null}.

    @Voltorise Non mais n'importe quoi ...

    posted in Support pour les moddeurs
  • RE: OpenGL sur Minecraft

    Bonjour,

    Tu peux utiliser l'event RenderWorldLastEvent pour dessiner ta ligne. Si tu ne sais pas encore utiliser les événements je te redirige vers ce tutoriel.

    posted in Support pour les moddeurs
  • RE: OpenGL sur Minecraft

    Bonsoir,

    Déjà tu as un soucis avec ton begin. Le premier argument indique ce que tu veux dessiner (utilise les constantes d'OpenGL). Ici tu veux dessiner une ligne, utilise donc GL11.GL_LINES. Pour le second tu dois spécifier le format des données que tu vas envoyer dans le buffer. Pour ce faire, le mieux ici est d'utiliser les constantes de la classe DefaultVertexFormats de Minecraft. Je te conseille d'utilise DefaultVertexFormats.POSITION_COLOR.

    Tu obtiens donc le code suivant :

    Tessellator tessellator = Tessellator.getInstance();
    BufferBuilder buffer = tessellator.getBuffer();
    buffer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
    
    tessellator.draw();
    

    Ensuite, il suffit de renseigner tes sommets (vertices) au buffer. Ici comme j'ai utilisé DefaultVertexFormat.POSITION_COLOR il faut, pour chaque vertex, renseigner la position ainsi que la couleur.

    En regardant ton code je n'ai pas compris de où à où devrait aller ta ligne, mais disons qu'elle doit aller de (x1, y1, z1) à (x2, y2, z2) et que tu veuilles qu'elle soit verte alors ton code devrait être :

    Tessellator tessellator = Tessellator.getInstance();
    BufferBuilder buffer = tessellator.getBuffer();
    buffer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
    
    buffer.pos(x1, y1, z1).color(0f, 1f, 0f, 1f).endVertex();
    buffer.pos(x2, y2, z2).color(0f, 1f, 0f, 1f).endVertex();
    
    tessellator.draw();
    

    N'hésite pas à demander des informations complémentaires.

    posted in Support pour les moddeurs
  • Créer une configuration pour votre mod

    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

    posted in Autres
  • RE: [1.8]classe recipe

    Bonsoir,
    En tant qu'auteur de ce tutoriel je tient à m'excuser. Ce tutoriel n'a pas très bien survécu à la migration vers NodeBB. Ainsi le code est complètement cassé.

    Cependant, il ne devrait pas être nécessaire d'indiquer les imports pour la classe Map, en effet on ne fait pas de javafx ici, je ne vois pas pourquoi on utiliserai la classe Map de javafx. N'importe qui sachant un minimum coder en Java sait qu'il faut importer java.util.Map ici.

    Je t'invite à consulter le tutoriel traitant du même sujet dans la version 1.12 qui, lui, n'a pas été cassé par la migration (du moins, il a été réparé).

    posted in Support pour les moddeurs
  • RE: Une personne pour faire un tuto sur EU RF

    Salut,

    Il n'y a plus besoin d'API pour faire des mods énergétique depuis l'introduction des capabilities. Si tu ne sais pas utiliser ces dernières je te conseille le le tutoriel à ce sujet.

    Autre point qui a déjà été relevé : tu n'es pas dans la bonne section. Cette section permet aux membres ne faisant pas partie du staff de créer et partager des tutoriels.

    Ainsi, pour effectuer une demande de tutoriel, merci de poster une message en réponse de ce post.

    Bonne journée

    posted in Le salon libre
  • Les commandes

    En 1.13, Mojang a décidé de changer entièrement le système de commandes de Minecraft. Les développeurs (enfin, surtout Dinnerbone) ont ainsi créé Brigadier, une librairie open-source utilisée à présent dans Minecraft. Bien qu'elle ait été développée pour Minecraft, elle peut être utilisée dans bien d'autres programmes.
    Dans ce tutoriel, nous allons donc nous pencher sur la création de commandes pour votre mod dans le cadre du modding Minecraft.

    Sommaire

    Pré-requis

    Concept

    Avant de nous attaquer au code, on va d'abord voir comment les commandes sont vues dans Brigadier. En réalité, ce n'est pas très compliqué, c'est un simple arbre, chaque nœud de celui-ci peut être lié à aucun, un ou plusieurs autres nœuds. Quand on utilise une commande on ne fait que se déplacer dans cet arbre.
    Le premier nœud de cet arbre est <root>, lorsque que vous ajoutez une commande vous reliez en réalité un nouveau nœud à <root>.
    Voici un exemple de ce à quoi ressemble (partiellement) l'arbre représentant les commandes de Minecraft :

    firefox_2019-03-18_23-36-12.png

    Il existe plusieurs types de nœud, il y a les nœuds dits "littérales" et les nœuds de type "argument". Un nœud littéral représente un texte prédéfini à taper, la plupart des nœuds montrés plus haut sont de ce type (ex. add, query, say, difficulty, etc ...). Les nœuds de type argument représentent une donnée qui sera entrée par l'utilisateur et dont on va se servir pour exécuter la commande. Par exemple, dans l'arbre ci-dessus time <int> est un argument demandant un entier et la valeur passée sera utilisée dans l'exécution de la commande. De même que message <String> qui est un message à afficher qui sera donné par l'utilisateur.

    Lorsque l'on tape une commande, on peut s'arrêter à n'importe quel nœud, vous pouvez alors rencontrer deux cas :

    • Le nœud a défini un comportement et dans ce cas celui-ci s'exécute. Par exemple, le nœud difficulty montré plus haut a pour comportement d'afficher la difficulté actuelle.

    • Le nœud n'a pas défini de comportement et dans ce cas une erreur est affichée, c'est le cas par exemple du nœud time.

    Bon, plongeons-nous à présent dans le code.

    Code

    Nous allons créer une commande qui met le feu aux entités renseignées dans la commande ou aux blocs dans le rayon indiqué. Pour cela, nous allons créer en premier lieu une classe SetFireCommand et dans cette classe nous allons ajouter une fonction prenant en paramètre un objet CommandDispatcher<CommandSource> :

    public static void register(CommandDispatcher<CommandSource> dispatcher)
    {
    
    
    }
    

    C'est grâce à cet objet CommandDispatcher que nous allons pouvoir enregistrer nos commandes.
    Avant de commencer à coder notre commande, je vais vous donner la syntaxe que je souhaite pour ma commande.
    Mettre le feu aux entités : /setfire entities <targets> [duration]
    Mettre le feu aux blocs : /setfire blocks <radius>
    Commençons !

    Pour enregistrer une commande, il faut appeler CommandDispatcher#register en lui passant un LiteralArgumentBuilder. La chaîne de caractère passée dans ce builder sera le nom de notre commande (dans mon cas je met donc setfire).

    dispatcher.register(
            LiteralArgumentBuilder.<CommandSource>literal("setfire") // Il est nécessaire de renseigner le type générique
    );
    

    Une chose que je n'ai pas précisé est que je veux que seuls les joueurs étant opérateurs puissent utiliser la commande, je vais donc l'indiquer tout de suite à l'aide de la méthode ArgumentBuilder#requires :

    dispatcher.register(
            LiteralArgumentBuilder.<CommandSource>literal("setfire")
            .requires(src -> src.hasPermissionLevel(2))
    );
    

    Pour rajouter un nouveau nœud au nœud setfire que nous venons de créer, il faut utiliser la méthode ArgumentBuilder#then. Je vais commencer par le nœud concernant les entités :

    dispatcher.register(
            LiteralArgumentBuilder.<CommandSource>literal("setfire")
            .requires(src -> src.hasPermissionLevel(2))
            .then(
                    Commands.literal("entities")
            )
    );
    

    Je viens donc de créer un nœud littéral, si vous vous souvenez de la suite de la syntaxe de ma commande, je veux maintenant prendre en argument les entités à mettre en feu. Il faut donc que j'ajoute un nœud de type argument :

    dispatcher.register(
            LiteralArgumentBuilder.<CommandSource>literal("setfire")
            .requires(src -> src.hasPermissionLevel(2))
            .then(
                    Commands.literal("entities")
                    .then(
                            Commands.argument("targets", EntityArgument.multipleEntities())
                    )
            )
    );
    

    Pour ajouter un argument, on utilise donc Commands#argument qui demande le nom de l'argument (ici targets car il représente les cibles de la commande), puis un type d'argument. Ici, j'ai utilisé EntityArgument.multipleEntities() qui indique que j'accepte aucune, une seule ou plusieurs entités.

    Important

    Il existe plusieurs types d'arguments, je ne vais pas les présenter toutes ici, vous retrouverez la plupart dans le reste du tutoriel.

    Afin de continuer notre commande, nous allons créer une fonction dans notre classe qui aura pour but de mettre en feu une liste d'entités pendant une certaine durée :

    /**
     * Met en feu les entités données pendant la durée donnée. Indique aussi au joueur que les entités ont été mises en
     * feu.
     * @param src La source de la commande
     * @param targets Les entités à mettre en feu
     * @param duration La durée du feu
     * @return le nombre d'entités mises en feu
     */
    private static int setFireEntities(CommandSource src, Collection<? extends Entity> targets, int duration)
    {
        targets.forEach(e -> e.setFire(duration));
    
        src.sendFeedback(new TextComponentString(targets.size() + " entities burnt !"), false);
        
        return targets.size();
    }
    

    Nous pourrons donc appeler cette fonction par la suite pour mettre en feu certaines entités. Continuons notre commande, nous sommes arrivés au nœud concernant les cibles. Il reste à renseigner la durée du feu, cependant, nous voulons que si celle-ci n'est pas renseignée les entités brûlent quand même pendant 5 secondes. Faisons cela :
    Je ne mets ici qu'une partie du code de la commande

    Commands.literal("entities")
    .then(
            Commands.argument("targets", EntityArgument.multipleEntities())
            .executes(ctx -> setFireEntities(ctx.getSource(), EntityArgument.getEntitiesAllowingNone(ctx, "targets"), 5))
    )
    

    J'utilise EntityArgument#getEntitiesAllowingNone pour récupérer les cibles renseignées par l'utilisateur de la commande. J'y passe le contexte récupéré via la lambda ainsi que le nom de l'argument (ici targets).

    Attention

    Il est important que le nom passé dans EntityArgument#getEntitiesAllowingNone corresponde au nom donné dans Commands#argument.

    Maintenant, si l'utilisateur renseigne la durée du feu il faut la prendre en compte. On rajoute donc un nœud à l'argument targets :

    Commands.argument("targets", EntityArgument.multipleEntities())
    .executes(ctx -> setFireEntities(ctx.getSource(), EntityArgument.getEntitiesAllowingNone(ctx, "targets"), 5))
    .then(
            Commands.argument("duration", IntegerArgumentType.integer(0))
    )
    

    Cette fois-ci, j'utilise le type IntegerArgumentType en appelant IntegerArgumentType#integer(int: min), le 0 correspond donc au minimum (je ne veux pas un temps négatif). Il faut à présent que je mette le feu aux entités pendant la durée renseignée.

    Commands.argument("duration", IntegerArgumentType.integer(0))
    .executes(ctx -> setFireEntities(ctx.getSource(), EntityArgument.getEntitiesAllowingNone(ctx, "targets"), IntegerArgumentType.getInteger(ctx, "duration")))
    

    Là encore je récupère la durée renseignée en utilisant IntegerArgumentType#getInteger en indiquant bien duration qui est le nom du nœud que j'ai indiqué plus tôt.

    Il semblerait que nous ayons terminé la partie concernant les entités. Passons maintenant à celle concernant les blocs.

    Nous allons tout d'abord ajouter une fonction pour mettre en feu les blocs autour d'un certain rayon.

    /**
     * Mets les blocs autour de la source en feu
     * @param src La source de la commande
     * @param radius Le rayon d'action
     * @return le nombre de blocs mis en feu
     */
    private static int setFireBlocks(CommandSource src, int radius)
    {
        Vec3d srcPos = src.getPos();
        World world = src.getWorld();
        int count = 0;
        for(int x = -radius; x < radius; x++)
        {
            for(int z = -radius; z < radius; z++)
            {
                BlockPos pos = new BlockPos(srcPos.x + x, srcPos.y, srcPos.z + z);
                IBlockState state = world.getBlockState(pos);
                if(state.getBlock() == Blocks.AIR)
                {
                    world.setBlockState(pos, Blocks.FIRE.getDefaultState());
                    count++;
                }
            }
        }
    
        src.sendFeedback(new TextComponentString(count + " blocks set on fire !"), false);
    
        return count;
    }
    

    Maintenant nous allons ajouter la branche relative aux blocs à notre commande. Rappelez-vous la commande est actuellement dans cet état :

    public static void register(CommandDispatcher<CommandSource> dispatcher)
    {
        dispatcher.register(
                LiteralArgumentBuilder.<CommandSource>literal("setfire")
                .requires(src -> src.hasPermissionLevel(2))
                .then(
                        Commands.literal("entities")
                       // [...]
                )
               // Le reste du code va aller ici
        );
    }
    

    Rajoutons un nœud littéral nommé blocks puis encore un nœud de type argument qui s’appellera radius et qui sera un entier positif :

    .then(
            Commands.literal("blocks")
            .then(
                    Commands.argument("radius", IntegerArgumentType.integer(0))
            )
    )
    

    Il ne manque plus qu'à appeler notre fonction setFireBlocks lors de l'exécution :

    .then(
            Commands.literal("blocks")
            .then(
                    Commands.argument("radius", IntegerArgumentType.integer(0))
                    .executes(ctx -> setFireBlocks(ctx.getSource(), IntegerArgumentType.getInteger(ctx, "radius")))
            )
    )
    

    Rien de nouveau par rapport à ce que nous avons vu précédemment, ceci sert juste d'exemple supplémentaire, c'est pourquoi je passe rapidement dessus.

    À présent, il faut appeler SetFireCommand#register sinon nous n'aurons jamais notre commande en jeu. Pour cela rendez-vous dans la classe principale de votre mod et ajoutez la méthode suivante :

    private void serverStartingEvent(FMLServerStartingEvent event)
    {
    	SetFireCommand.register(event.getCommandDispatcher());
    }
    

    Dans cette méthode, nous enregistrons notre commande en lui passant une instance de CommandDispatcher. Pour le moment, celle-ci n'est pas appelée, pour résoudre ce problème, ajoutez ceci dans le constructeur de votre classe principale :

    public ModTutorial() {
    	// [...]
    
    	MinecraftForge.EVENT_BUS.addListener(this::serverStartingEvent);
    }
    

    Et voilà, le tour est joué. Vous pouvez lancer votre jeu et tester votre commande.

    Résultat

    java_2019-03-19_01-09-30.png
    java_2019-03-19_01-23-50.png
    java_2019-03-19_01-23-59.png

    Retrouvez le commit relatif à ce tutoriel sur le Github de Minecraft Forge France

    Crédits

    Creative Commons

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

    retourRetour vers le sommaire des tutoriels

    posted in Autres
  • Ajouter un onglet au menu créatif

    Bienvenue sur ce tutoriel à la fin duquel vous saurez tout sur les onglets créatifs aussi appelés "item groups".
    Un onglet créatif, qu'est ce que c'est ?
    La réponse est très simple, il s'agit d'une interface disponible en créatif servant à répertorier vos blocs (blocks) et vos objets (items).

    Pour faire simple, un onglet créatif c'est ça :

    tab_base.png

    Sommaire

    Pré-requis

    Code

    La classe principale:

    Pour commencer, vous allez déclarer votre onglet créatif comme ceci :

    public static final ItemGroup MFF_GROUP = new ItemGroup("mff") {
        @OnlyIn(Dist.CLIENT)
        @Override
        public ItemStack createIcon() {
            return new ItemStack(ModTutorialBlocks.BLOCK_TUTORIAL);
        }
    };
    

    Voilà, votre table créative est créée, mais il n'y a aucun bloc ni item de votre mod.

    Note

    On peut également créer une classe dédiée au groupe d'item pour y mettre ce code. C'est même recommandé si vous prévoyez avoir plusieurs groupes d'item dans votre mod.

    Les blocs et les items :

    Pour chacun de vos blocs et items, vous aller devoir appeler la méthode group() afin de définir le groupe d'items dans lequel vous voulez ranger celui-ci lors de l'enregistrement de l'item :

    event.getRegistry().register(new ItemBlock(BLOCK_TUTORIAL, new Item.Properties().group(ModTutorial.MFF_GROUP)).setRegistryName(BLOCK_TUTORIAL.getRegistryName()));
    

    Les ressources

    Dans le fichier en_us.json, rajoutez ceci :

    {
        "itemGroup.mff": "Minecraft Forge France"
    }
    

    et dans le fichier fr_fr.json, rajoutez ceci :

    {
        "itemGroup.mff": "Minecraft Forge France"
    }
    

    Bonus

    Pour ce tutoriel, je vais vous proposer trois bonus. Le premier vous montrera comment avoir une texture custom sur votre onglet créatif, le second comment avoir vos blocs ou vos items dans l'ordre que vous le souhaitez et enfin le dernier vous montrera comment avoir une barre de recherche sur votre onglet.

    Texture custom :

    Pour avoir une texture custom sur votre onglet, il vous suffira de mettre ce code dans la déclaration :

    public static final ItemGroup MFF_GROUP = new ItemGroup("mff") {
    ...
    }.setBackgroundImageName("votre_nom_de_texture.png");
    

    Attention

    La texture devra se trouver dans ce dossier : assets/minecraft/textures/gui/container/creative_inventory/ et le nom doit obligatoirement commencer par tab_.
    La texture s'appellera finalement : tab_ + votre_nom_de_texture.png

    Si pour une raison ou une autre vous souhaitez faire disparaître le titre de l'onglet, ajoutez setNoTitle à la déclaration :

    public static final ItemGroup MFF_GROUP = new ItemGroup("mff") {
    ....
    }.setNoTitle();
    

    L'avantage est que vous pouvez rendre plus immersif votre mod en proposant une texture dans l'ambiance, l’inconvénient est que si le joueur utilise un texture pack qui modifie les textures des onglets créatifs, il y aura une coupure pas très esthétique.

    public static final ItemGroup MFF_GROUP = new ItemGroup("mff") {
    ...
    }.setNoTitle().setBackgroundImageName("votre_nom_de_texture.png");
    

    Une barre de recherche :

    Pour avoir une barre de recherche, il vous suffit d'utiliser cette méthode :

    @Override
    public boolean hasSearchBar() {
        return true;
    }
    

    Et voilà, c'est aussi simple que ça, faites néanmoins attention à la longueur du nom de votre onglet qui ne doit pas être trop long.

    Attention

    il faudra manuellement définir la texture de l'onglet afin de voir correctement apparaître la barre de recherche : .setBackgroundImageName("item_search.png");

    Modifier dynamiquement la liste des items affichés :

    Il est possible de modifier dynamiquement l'affichage des items dans la liste affichée. Pour ce faire, nous allons utiliser la méthode public void fill(NonNullList<ItemStack> items) disponible dans ItemGroup.

    Note

    Cette méthode est responsable de l'affichage des items dans l'onglet. Il est donc possible de complètement modifier la liste des items présent dans l'onglet et d'annuler le comportement par défaut, à savoir aller chercher les items avec le groupe défini comme étant celui de l'onglet.

    Afin de laisser le comportement par défaut de l'onglet, nous appellerons toujours la méthode super.fill(items); en premier.

    Je vous propose de rajouter dans votre onglet le debug stick si le joueur est opérateur.
    Dans un premier temps, il va nous falloir savoir si notre joueur est justement opérateur. Pour ce faire, nous allons interroger la CommandSource de celui-ci, et vérifier que le joueur dispose du niveau de permission requis.

    Minecraft.getInstance().player.getCommandSource().hasPermissionLevel(4)
    

    Note

    La CommandSource est un objet qui permet à une entité, que ce soit un joueur, un bloc de commande ou le serveur de lancer une commande. Un opérateur a un niveau de permission valant 4.

    Il ne nous reste plus qu'à ajouter notre item en fonction du résultat de cet appel :

    if(Minecraft.getInstance().player.getCommandSource().hasPermissionLevel(4))
        items.add(0, new ItemStack(Items.DEBUG_STICK));
    

    Notez que j'ai pris la décision d'ajouter le debug stick au début de la liste, ainsi il sera le premier item visible dans notre onglet.

    Vous pouvez également effectuer d'autres actions comme un tri sur la liste des items afin de les afficher par ordre alphabétique de leur nom.

    Les livres enchantés :

    Il est également possible d'ajouter des livres enchantés dans ces groupes, pour ce faire, nous allons utiliser la méthode setRelevantEnchantmentTypes :

    public static final ItemGroup MFF_GROUP = new ItemGroup("mff") {
    ...
    }.setRelevantEnchantmentTypes(/*Tableau des types d'enchantement*/);
    

    Pour notre exemple, nous allons ajouter tous les types d'enchantements.
    Fort heureusement, l'énumération EnumEnchantmentType nous met à disposition une fonction bien utile : values()

    public static final ItemGroup MFF_GROUP = new ItemGroup("mff") {
    ...
    }.setRelevantEnchantmentTypes(EnumEnchantmentType.values());
    

    Résultat

    Onglet de base Onglet avec une barre de recherche Affichge conditionné d'un item
    tab_mff.png tab_bg.png tab_debug.png

    Les différentes modifications du code sont retrouvables sur le commit Github suivant : https://github.com/MinecraftForgeFrance/mod-tutorial-1.13.2/commit/bca94599990fdc6be2c702f7ecf84a7fdf1615dc

    Licence et attribution

    Creative Commons

    Ce tutoriel rédigé par @phenix246, corrigé par @robin4002 et @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

    posted in Les items
  • RE: Mon serveur n'est pas dans la listes

    Information

    Merci de bien vouloir passer le sujet en résolu si le problème est réglé.

    posted in Support Sponge