Skip to content

Items personalisés


Pourquoi créer des classes d'objets personnalisées ?

Jusqu'à présent, nous avons enregistré nos objets directement dans la classe ModItems en utilisant new Item(new Item.Properties()). C'est une excellente méthode pour des items basiques (comme des lingots ou des gemmes) qui n'ont aucune logique interne.

Cependant, dès qu'un objet doit posséder un comportement unique — comme déclencher un effet magique lors d'un clic droit, afficher une infobulle spéciale (tooltip), ou interagir d'une manière précise avec l'environnement —, la classe générique Item de Minecraft ne suffit plus.

Pour y parvenir, la bonne pratique consiste à créer notre propre classe personnalisée qui hérite de Item (ou de l'une de ses sous-classes), afin de surplanter (override) ses méthodes natives.


Structure de base d'un Item personnalisé

Voici l'architecture standard à adopter pour créer votre propre objet fonctionnel :

📂 Fichier : src/main/java/net/pseudo/tutorialmod/item/custom/MonItemMagique.java

java
package net.pseudo.tutorialmod.item.custom;

import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;

public class MonItemMagique extends Item {

    // Le constructeur est obligatoire et transmet les propriétés au moteur de Minecraft
    public class MonItemMagique(Properties properties) {
        super(properties);
    }

    // EXEMPLE : On surplante la méthode de clic droit pour lui donner un comportement
    @Override
    public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
        ItemStack itemstack = player.getItemInHand(hand);

        // Code exécuté uniquement côté Serveur (logique de jeu)
        if (!level.isClientSide()) {
            // C'est ici que la magie opère (ex: soigner le joueur, lancer un projectile...)
            player.sendSystemMessage(net.minecraft.network.chat.Component.literal("La magie opère !"));
            
            // On applique un temps de recharge (cooldown) de 5 secondes (100 ticks)
            player.getCooldowns().addCooldown(this, 100);
        }

        return InteractionResultHolder.sidedSuccess(itemstack, level.isClientSide());
    }
}

Le mot-clé extends permet à notre classe de "recopier" automatiquement tout le code de la classe Item de base de Minecraft. On dit qu'elle hérite de ses capacités, ce qui nous évite de réécrire tout le système de gestion des objets depuis le début et nous permet de n'ajouter que notre code personnalisé.


Comment l'enregistrer dans ModItems ?

Une fois votre classe créée, son enregistrement change très peu. Au lieu d'instancier un new Item(), vous instanciez votre nouvelle classe :

📂 Fichier : src/main/java/net/pseudo/tutorialmod/init/ModItems.java (Extrait)

java
// Au lieu de : new Item(...)
// On utilise notre classe personnalisée :
public static final RegistryObject<Item> ARTEFACT_MYSTIQUE = ITEMS.register("artefact_mystique",
        () -> new MonItemMagique(new Item.Properties().stacksTo(1).rarity(Rarity.EPIC)));

Voici la traduction et la mise en forme markdown complète et optimisée de ton encyclopédie technique sur les items (Forge 1.20.1).



2. Répertoire Complet des Propriétés Initiales (Item.Properties)

Ces méthodes s'enchaînent dans votre classe de registre lors de l'instanciation de l'item:

Méthode du BuilderEffet et Description Technique
.stacksTo(int size)Définit la taille maximale du stack dans l'inventaire (ex: 64, 16). Incompatible avec l'attribution d'une durabilité.
.durability(int maxDamage)Attribue une jauge de durabilité à l'objet (en fait automatiquement un objet non-stackable, taille fixe de 1).
.rarity(Rarity rarity)Modifie la couleur du nom de l'item : Rarity.COMMON (blanc), UNCOMMON (jaune), RARE (aqua), EPIC (violet).
.food(FoodProperties properties)Transforme l'objet en nourriture consommable. Permet de définir les gigots restaurés, la saturation, la vitesse d'ingestion et des effets secondaires de potion appliqués à la consommation.
.craftRemainder(Item item)Spécifie l'objet résiduel renvoyé dans la grille de craft après utilisation (ex: un seau vide après un craft utilisant un seau de lait).
.fireResistant()Rend l'item immunisé au feu et à la lave lorsqu'il flotte au sol sous forme d'entité libre (comportement de la Netherite).
.requiredFeatures(FeatureFlag...)Restreint la visibilité et l'accès à l'item selon les paquets d'expérimentation actifs du monde (Vanilla experimentations).

3. Anatomie Exhaustive d'une Classe d'Item (Surcharges Logiques)

Introduisez ces méthodes directement à l'intérieur de votre classe étendant Item pour altérer dynamiquement le gameplay:

A. Clics et Interactions Immédiates

  • public InteractionResultHolder<ItemStack> use(Level lvl, Player p, InteractionHand h) Déclenché lors d'un clic droit dans le vide. Renvoie un statut d'action (sidedSuccess, pass, fail) et l'instance de l'item modifié.

  • public InteractionResult useOn(UseOnContext ctx) Déclenché lors d'un clic droit ciblant un bloc. Fournit le contexte complet (position du bloc, face cliquée). Indispensable pour les outils modifiant le terrain (houe, pelle, etc.).

  • public InteractionResult interactLivingEntity(ItemStack s, Player p, LivingEntity target, InteractionHand h) S'exécute lors d'un clic droit visant une entité vivante (ex: interaction de tonte, d'injection, ou d'application d'effets sur des monstres/animaux).

B. Gestion des Actions Continues (Consommables, Tirs, Canalisations)

  • public int getUseDuration(ItemStack s) Retourne la durée obligatoire (exprimée en ticks de jeu, où 20 ticks = 1 seconde) pendant laquelle l'utilisateur doit maintenir le clic droit enfoncé. (Standard Nourriture = 32).

  • public UseAnim getUseAnimation(ItemStack s) Définit la posture ou l'animation visuelle de l'entité pendant la canalisation : UseAnim.EAT, DRINK, BOW (arc), SPEAR (trident), CROSSBOW, BLOCK (bouclier).

  • public ItemStack finishUsingItem(ItemStack s, Level lvl, LivingEntity entity) Événement déclenché lorsque la durée de getUseDuration est totalement écoulée. C'est ici que l'on applique les effets de faim d'une nourriture ou qu'on remplace l'item par un contenant vide.

  • public void releaseUsing(ItemStack s, Level lvl, LivingEntity entity, int timeLeft) Appelé si le joueur relâche le clic droit avant le terme de la durée d'utilisation. Utilisé par les arcs pour calculer la puissance du tir sur la base du différentiel de temps (timeLeft).

C. Combat, Extraction et Gestion de la Durabilité

  • public boolean hurtEnemy(ItemStack s, LivingEntity target, LivingEntity attacker) S'exécute suite à un coup porté avec l'item. Idéal pour injecter des débuffs à la cible ou appliquer un recul personnalisé. Retourner true pour signifier que l'action doit entamer la durabilité.

  • public boolean mineBlock(ItemStack s, Level lvl, BlockState state, BlockPos pos, LivingEntity ent) Appelé au moment précis où un bloc est brisé avec cet item en main. Permet d'ajuster l'usure de l'outil selon la dureté du bloc ciblé.

  • public boolean isCorrectToolForDrops(BlockState state) Contrôle si l'item dispose du niveau de récolte ou des prérequis logiciels requis pour forcer le drop de ressources d'un bloc spécifique (ex: pioche requise pour le minerai de fer).

  • public float getDestroySpeed(ItemStack s, BlockState state) Retourne le coefficient multiplicateur de vitesse de minage face à un bloc donné. Permet de concevoir des outils ultra-rapides sur certains matériaux ciblés.

D. Logique Système, Inventaire et Cycle de Vie au Sol

  • public void inventoryTick(ItemStack s, Level lvl, Entity ent, int slotId, boolean isSelected) Exécuté à chaque tick de jeu (20Hz) pour chaque exemplaire présent dans un inventaire. Le paramètre isSelected indique si l'objet est équipé dans la main active du joueur.

  • public boolean onEntityItemUpdate(ItemStack s, ItemEntity entity)

[Spécifique Forge] S'exécute en continu lorsque l'objet est jeté au sol sous forme physique. Permet de modifier sa gravité, sa flottaison, ou de déclencher des événements s'il rencontre des fluides.

  • public boolean onDroppedByPlayer(ItemStack item, Player player)

[Spécifique Forge] Déclenché quand le joueur tente de jeter l'objet (touche Q). Retourner false bloque l'expulsion (idéal pour les objets de quête liés ou maudits).

  • public boolean hasCustomEntity(ItemStack stack) / createEntity(...)

[Spécifique Forge] Permet de substituer l'entité ItemEntity standard du sol par une entité customisée propre à votre mod afin de gérer des physiques complexes d'affichage.

E. Interfaces, Cosmétiques et Établis

  • public void appendHoverText(ItemStack s, @Nullable Level lvl, List<Component> tooltip, TooltipFlag flag) Ajoute des lignes de texte descriptives (le Lore) visibles lors du survol de la souris sur l'item dans un inventaire.

  • public boolean isFoil(ItemStack s) Retourner true applique de force l'effet d'enchantement scintillant (lueur violette) sur l'item de manière permanente (ex: Pomme d'Or Enchantée).

  • public boolean hasCraftingRemainingItem(ItemStack s) / getCraftingRemainingItem(ItemStack s) Définit des "outils permanents de craft". L'item, au lieu de disparaître de la grille d'artisanat, est remplacé par un autre item (ex: un moule réutilisable ou un marteau de forge perdant 1 de durabilité).

  • public void onCraftedBy(ItemStack s, Level lvl, Player p) Méthode interceptant l'action de récupération de l'item depuis l'emplacement de résultat d'un établi. Permet de marquer l'item via du NBT ou d'attribuer un avancement spécifique au joueur.

  • public boolean isValidRepairItem(ItemStack toRepair, ItemStack repairMaterial) Vérifie si un item fourni dans le second slot de l'enclume correspond au matériau requis pour réparer la durabilité de votre objet personnalisé.

💡 Astuce NBT dynamique : Pour rendre les comportements de vos items hautement configurables par rapport à des données changeantes (énergie accumulée, âmes capturées, munitions chargées), lisez et écrivez dans la structure NBT via l'objet stack.getOrCreateTag() à l'intérieur de n'importe quelle méthode ci-dessus.


4. Template Ultime de Code Prêt-à-Copier

Squelette de classe d'un item intégrant les cas d'usages majeurs (Cooldown, Coût, Lore et Action continue):

📂 Fichier : src/main/java/com/monmod/common/item/CustomMasterItem.java

java
package com.monmod.common.item;

import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.*;
import net.minecraft.world.level.Level;
import net.minecraft.ChatFormatting;
import org.jetbrains.annotations.Nullable;
import java.util.List;

public class CustomMasterItem extends Item {

    public CustomMasterItem(Item.Properties properties) {
        super(properties);
    }

    @Override
    public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
        tooltip.add(Component.translatable("tooltip.monmod.master_item.desc").withStyle(ChatFormatting.GOLD));
        super.appendHoverText(stack, level, tooltip, flag);
    }

    @Override
    public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
        ItemStack itemstack = player.getItemInHand(hand);
        
        // Exemple d'action : entamer une canalisation (ex: charger un sort ou viser)
        player.startUsingItem(hand);
        return InteractionResultHolder.consume(itemstack);
    }

    @Override
    public int getUseDuration(ItemStack stack) {
        return 40; // Le joueur doit maintenir l'action pendant 2 secondes (40 ticks)
    }

    @Override
    public UseAnim getUseAnimation(ItemStack stack) {
        return UseAnim.BOW; // Utilise le visuel d'armement de l'arc
    }

    @Override
    public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entity) {
        // Effet s'exécutant uniquement côté serveur à la fin du temps imparti
        if (!level.isClientSide && entity instanceof Player player) {
            player.getCooldowns().addCooldown(this, 100); // Ajoute 5 secondes de cooldown
            
            // Exemple de consommation de durabilité interne
            stack.hurtAndBreak(1, player, (p) -> p.broadcastBreakEvent(player.getUsedItemHand()));
        }
        return stack;
    }
}