Skip to content

L'utilisation d'un consommable


Vous avez appris à utiliser le système simplifié de nourriture (Food Properties). C'est parfait pour une pomme ou un steak : le joueur mange, l'objet disparaît de sa main, et la faim est restaurée.

Mais un problème majeur se pose si vous essayez de coder une soupe personnalisée ou un élixir magique : comment faire pour que l'objet ne disparaisse pas bêtement, mais laisse à la place un bol vide ou une fiole en verre dans la main du joueur?

Le builder de nourriture classique est incapable de gérer cela nativement. Pour y parvenir, il va falloir intercepter précisément l'instant où l'action de consommation se termine grâce à la méthode finishUsingItem(...).

1. Pourquoi le builder de base échoue ?

Par défaut, lorsqu'un consommable est entièrement ingéré, le moteur de Minecraft décrémente (réduit) la taille du pack (ItemStack) de 1. Si la pile arrive à 0, Minecraft détruit simplement l'objet.

Si vous tentez de ruser en utilisant la propriété craftRemainder (Items.BOWL) vue au cours 3, cela ne marchera que dans une table de craft, et non lorsque le joueur porte le bol à sa bouche! C'est le piège numéro un des moddeurs débutants.

2. La méthode maîtresse: finishUsingItem

Pour injecter une logique à la fin de la consommation, nous devons écraser la méthode suivante de la classe Item:

java
@Override
public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entity) {
    // 1. Exécuter d'abord la restauration de faim native
    ItemStack resultStack = super.finishUsingItem(stack, level, entity);
    
    // 2. Manipuler l'inventaire ici
    
    return resultStack;
}

Attention à l'argument LivingEntity : Minecraft permet aux monstres (comme les zombies) ou aux animaux de manger. L'argument reçu n'est pas directement un Player (joueur), mais une Living Entity (entité vivante). Avant de toucher à l'inventaire, il faudra vérifier à l'aide d'un test instanceof s'il s'agit bien d'un joueur humain.


3. Algorithme de remplacement sécurisé de l'item

Remplacer l'item mangé par son résidu (un bol ou une fiole) demande de respecter une logique stricte pour éviter d'effacer d'autres objets par erreur:

  1. Si le joueur est en mode Créatif : On ne touche à rien. Le joueur créatif doit garder son bol plein à l'infini.

  2. Si le pack de l'item est vide (taille == 0) : On peut directement renvoyer le bol vide. Il prendra la place exacte dans la main du joueur.

  3. Si le pack contenait un lot empilé (ex: 64 soupes) : La taille passe à 63. Il faut alors essayer de glisser le bol vide dans un emplacement libre de l'inventaire du joueur. Si son inventaire est complètement plein, il faut jeter le bol vide au sol.


4. Exercice Pratique : Le Breuvage Volcanique

Énoncé de l'exercice :

Créez une boisson magique appelée VolcanicElixirItem. Cet objet utilise un système de nourriture (Food Properties) pour pouvoir être bu.

Une fois consommé, l'élixir doit:

  • Appliquer ses effets normaux de nourriture.

  • Remplacer l'élixir par une fiole vide (Items.GLASS_BOTTLE) de manière sécurisée selon les règles d'inventaire.

Code complet et commenté de l'exercice :

java
package com.tutoriel.monmod.item;

import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;

public class VolcanicElixirItem extends Item {
    
    public VolcanicElixirItem(Properties properties) {
        super(properties);
    }
    
    @Override
    public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entity) {
        // Déclenche la mécanique de base (restauration faim / effets de potion attachés)
        ItemStack remainingStack = super.finishUsingItem(stack, level, entity);
        
        // ÉTAPE 1: On vérifie si l'entité qui consomme est bien un joueur
        if (entity instanceof Player player) {
            
            // RÈGLE 1: Si le joueur est en créatif, on retourne le pack inchangé
            if (player.getAbilities().instabuild) {
                return remainingStack;
            }
            
            // RÈGLE 2: Si la pile est épuisée (dernier élixir bu du lot)
            if (remainingStack.isEmpty()) {
                return new ItemStack(Items.GLASS_BOTTLE);
            }
            
            // RÈGLE 3: Si le joueur avait un lot (stack) d'élixirs
            // On tente d'ajouter la fiole vide dans son inventaire
            if (!player.getInventory().add(new ItemStack(Items.GLASS_BOTTLE))) {
                // Si l'inventaire est plein, le serveur fait spawner l'objet au sol devant le joueur
                player.drop(new ItemStack(Items.GLASS_BOTTLE), false);
            }
        }
        
        // On retourne le lot décrémenté
        return remainingStack;
    }
}

Piège à éviter lors de l'enregistrement de l'Item !

N'oubliez pas que pour que la méthode finishUsingItem s'active, votre objet doit obligatoirement posséder une configuration de nourriture lors de son enregistrement dans votre classe ModItems, sinon le jeu considèrera que l'item n'est pas comestible et le clic droit ne fera rien.

Exemple d'enregistrement obligatoire :

java
new Item.Properties().food(new FoodProperties.Builder().nutrition(4).saturationMod(0.3F).build())

Résumé des connaissances du Cours :

  • La propriété craftRemainder ne fonctionne que pour les recettes de l'établi (crafting table).

  • La méthode finishUsingItem intercepte l'instant exact de fin d'ingestion sur le serveur.

  • La gestion des contenants doit être asymétrique : elle s'adapte selon que le joueur est en mode Survie (gestion fine des piles d'inventaire) ou en mode Créatif (contenant infini).