---
title: ItemStacks
type: docs
weight: 1
---

ItemStack représente une pile d'objets dans Hytale avec quantité, durabilité et métadonnées.

## Créer des ItemStacks

Les ItemStacks sont créés en utilisant des constructeurs avec un ID d'objet :

```java
// Créer par ID d'objet
ItemStack sword = new ItemStack("iron_sword");

// Créer avec quantité
ItemStack materials = new ItemStack("wood_plank", 64);

// Créer avec quantité et métadonnées
BsonDocument metadata = new BsonDocument();
ItemStack customItem = new ItemStack("iron_sword", 1, metadata);

// Créer avec tous les paramètres (durabilité)
ItemStack damagedSword = new ItemStack("iron_sword", 1, 50.0, 100.0, null);
// Paramètres: itemId, quantity, durability, maxDurability, metadata
```

## Propriétés d'ItemStack

```java
ItemStack stack = new ItemStack("iron_sword", 1);

// Obtenir l'ID de l'objet
String itemId = stack.getItemId();  // "iron_sword"

// Obtenir l'asset Item
Item item = stack.getItem();

// Obtenir la quantité (PAS getCount!)
int quantity = stack.getQuantity();

// Vérifier si vide
boolean empty = stack.isEmpty();

// Vérifier la validité
boolean valid = stack.isValid();

// Durabilité
double durability = stack.getDurability();
double maxDurability = stack.getMaxDurability();
boolean unbreakable = stack.isUnbreakable();  // true si maxDurability <= 0
boolean broken = stack.isBroken();  // true si durability == 0
```

## Modifier les ItemStacks

ItemStack utilise un pattern `with*` qui retourne de NOUVELLES instances :

```java
ItemStack stack = new ItemStack("iron_sword", 1);

// Changer la quantité - retourne un NOUVEL ItemStack ou null si quantité est 0
ItemStack moreItems = stack.withQuantity(32);

// Changer la durabilité
ItemStack damaged = stack.withDurability(50.0);

// Augmenter la durabilité
ItemStack repaired = stack.withIncreasedDurability(25.0);

// Restaurer la durabilité complète
ItemStack fullyRepaired = stack.withRestoredDurability(100.0);

// Changer la durabilité max
ItemStack stronger = stack.withMaxDurability(200.0);

// Changer l'état (pour les objets avec états)
ItemStack newState = stack.withState("activated");

// Ajouter/modifier les métadonnées
ItemStack withMeta = stack.withMetadata(metadataDocument);

// Ajouter une valeur de métadonnée spécifique
ItemStack tagged = stack.withMetadata("CustomKey", Codec.STRING, "CustomValue");
```

{{< callout type="warning" >}}
**Important :** `withQuantity(0)` retourne `null`, pas un ItemStack vide. Vérifiez toujours null quand vous diminuez la quantité !
{{< /callout >}}

## La Constante EMPTY

Utilisez `ItemStack.EMPTY` pour les piles vides :

```java
// Instance vide statique (singleton)
ItemStack empty = ItemStack.EMPTY;

// Vérifier si vide
if (stack.isEmpty()) {
    // La pile est vide
}

// Méthode helper statique
if (ItemStack.isEmpty(stack)) {
    // Gère les piles null et vides
}
```

## Comparer les ItemStacks

```java
ItemStack a = new ItemStack("iron_sword", 1);
ItemStack b = new ItemStack("iron_sword", 5);
ItemStack c = new ItemStack("diamond_sword", 1);

// Vérifier si empilables (même itemId, durability, maxDurability ET metadata)
// Note: Des quantités différentes peuvent s'empiler, mais les durabilités doivent correspondre exactement
boolean canStack = a.isStackableWith(b);

// Vérifier type équivalent (même itemId et metadata, ignore les durabilités)
boolean sameType = a.isEquivalentType(b);

// Vérifier même type d'objet seulement (juste itemId)
boolean sameItem = ItemStack.isSameItemType(a, c);  // false

// Helpers statiques (gèrent les nulls en sécurité)
ItemStack.isStackableWith(a, b);
ItemStack.isEquivalentType(a, b);
```

## Travailler avec les Métadonnées

ItemStack supporte les métadonnées BSON pour les données personnalisées :

```java
// Créer un codec de métadonnée
KeyedCodec<String> OWNER_KEY = new KeyedCodec<>("Owner", Codec.STRING);

// Ajouter des métadonnées
ItemStack withOwner = stack.withMetadata(OWNER_KEY, "PlayerName");

// Lire les métadonnées
String owner = stack.getFromMetadataOrNull(OWNER_KEY);

// Lire avec clé et codec
Integer level = stack.getFromMetadataOrNull("Level", Codec.INTEGER);

// Lire avec défaut depuis BuilderCodec
MyData data = stack.getFromMetadataOrDefault("Data", MyData.CODEC);
```

## Objets de Bloc

Vérifier si un objet peut être placé comme bloc :

```java
ItemStack stack = new ItemStack("stone", 1);

// Obtenir la clé de bloc associée (null si pas un objet de bloc)
String blockKey = stack.getBlockKey();
if (blockKey != null) {
    // Cet objet peut être placé comme bloc
}

// Vérifier via l'asset Item
Item item = stack.getItem();
if (item.hasBlockType()) {
    String blockId = item.getBlockId();
}
```

## Patterns Courants

### Consommer des Objets

```java
public ItemStack consumeOne(ItemStack stack) {
    if (stack == null || stack.isEmpty()) {
        return null;
    }

    int newQuantity = stack.getQuantity() - 1;

    // withQuantity retourne null si quantité est 0
    return stack.withQuantity(newQuantity);
}

// Utilisation avec conteneur
public void useItem(ItemContainer container, short slot) {
    ItemStack current = container.getItemStack(slot);
    ItemStack remaining = consumeOne(current);

    // remaining peut être null si la pile est épuisée
    container.setItemStackForSlot(slot, remaining);
}
```

### Vérifier le Type d'Objet

```java
public boolean isHoldingSword(ItemStack hand) {
    if (hand == null || hand.isEmpty()) {
        return false;
    }

    // Vérifier le type d'objet par ID
    return hand.getItemId().contains("sword");

    // Ou vérifier via l'asset Item
    // return hand.getItem().getCategory().equals("weapon");
}
```

### Diviser des Piles

```java
public ItemStack[] splitStack(ItemStack stack, int splitAmount) {
    if (stack == null || stack.isEmpty()) {
        return null;
    }

    int currentQuantity = stack.getQuantity();
    if (splitAmount >= currentQuantity) {
        return new ItemStack[] { stack, null };
    }

    // Créer deux piles
    ItemStack remaining = stack.withQuantity(currentQuantity - splitAmount);
    ItemStack split = stack.withQuantity(splitAmount);

    return new ItemStack[] { remaining, split };
}
```

### Fusionner des Piles

```java
public ItemStack[] mergeStacks(ItemStack target, ItemStack source) {
    if (!target.isStackableWith(source)) {
        return new ItemStack[] { target, source };  // Ne peut pas fusionner
    }

    int maxStack = target.getItem().getMaxStack();
    int totalQuantity = target.getQuantity() + source.getQuantity();

    if (totalQuantity <= maxStack) {
        // Fusion complète
        return new ItemStack[] {
            target.withQuantity(totalQuantity),
            null
        };
    }

    // Fusion partielle
    return new ItemStack[] {
        target.withQuantity(maxStack),
        source.withQuantity(totalQuantity - maxStack)
    };
}
```

## Bonnes Pratiques

{{< callout type="info" >}}
**Rappelez-vous :**
- Utilisez `getQuantity()` pas `getCount()` - Hytale utilise "quantity"
- `withQuantity(0)` retourne `null` - vérifiez cela !
- Utilisez `ItemStack.isEmpty(stack)` pour gérer null et vide
- Les ItemStacks sont principalement immuables - les méthodes `with*` retournent de nouvelles instances
- Utilisez `isStackableWith()` avant de tenter de fusionner des piles
- `ResourceType.Id` ne doit pas être null lors de la création d'objets via codecs
{{< /callout >}}

```java
// Bon : Gérer null de withQuantity
ItemStack result = stack.withQuantity(newQuantity);
if (result == null) {
    // Pile épuisée, gérer appropriément
}

// Bon : Vérification vide sécurisée
if (ItemStack.isEmpty(stack)) {
    // Gère à la fois null et ItemStack.EMPTY vide
}

// Mauvais : Ignorer la valeur retournée
stack.withQuantity(10);  // Retourne nouvelle pile, original inchangé !
```

## Référence API ItemStack

### Méthodes d'Instance

| Méthode | Retour | Description |
|--------|---------|-------------|
| `getItemId()` | `String` | L'identifiant du type d'objet |
| `getItem()` | `Item` | L'asset Item (retourne `Item.UNKNOWN` si non trouvé) |
| `getQuantity()` | `int` | Taille de la pile |
| `getDurability()` | `double` | Durabilité actuelle |
| `getMaxDurability()` | `double` | Durabilité maximum |
| `isEmpty()` | `boolean` | True si itemId égale "Empty" |
| `isUnbreakable()` | `boolean` | True si maxDurability <= 0 |
| `isBroken()` | `boolean` | True si PAS incassable ET durability == 0 |
| `isValid()` | `boolean` | True si vide OU l'asset existe |
| `isStackableWith(ItemStack)` | `boolean` | Même itemId, durability, maxDurability, metadata |
| `isEquivalentType(ItemStack)` | `boolean` | Même itemId et metadata (ignore durabilité) |
| `getBlockKey()` | `String?` | ID bloc si plaçable, null sinon |
| `getOverrideDroppedItemAnimation()` | `boolean` | Flag d'override animation |
| `getMetadata()` | `BsonDocument?` | **Déprécié** - Retourne metadata clonée |
| `getFromMetadataOrNull(KeyedCodec)` | `T?` | Obtenir valeur metadata typée |
| `getFromMetadataOrNull(String, Codec)` | `T?` | Obtenir metadata par clé |
| `getFromMetadataOrDefault(String, BuilderCodec)` | `T` | Obtenir metadata avec défaut |

### Méthodes de Modification (retournent nouveau ItemStack)

| Méthode | Retour | Description |
|--------|---------|-------------|
| `withQuantity(int)` | `ItemStack?` | **Retourne null si quantité est 0** |
| `withDurability(double)` | `ItemStack` | Borné à [0, maxDurability] |
| `withMaxDurability(double)` | `ItemStack` | Borne aussi la durabilité actuelle |
| `withIncreasedDurability(double)` | `ItemStack` | Ajoute à la durabilité |
| `withRestoredDurability(double)` | `ItemStack` | Définit durabilité et max |
| `withState(String)` | `ItemStack` | Change l'état de l'objet |
| `withMetadata(BsonDocument)` | `ItemStack` | Remplace toutes les metadata |
| `withMetadata(KeyedCodec, T)` | `ItemStack` | Définit metadata typée |
| `withMetadata(String, Codec, T)` | `ItemStack` | Définit metadata par clé |
| `withMetadata(String, BsonValue)` | `ItemStack` | Définit valeur BSON brute |
| `setOverrideDroppedItemAnimation(boolean)` | `void` | **Mute en place** |

### Champs Statiques

| Champ | Type | Description |
|-------|------|-------------|
| `EMPTY` | `ItemStack` | Pile vide singleton (itemId = "Empty") |
| `EMPTY_ARRAY` | `ItemStack[]` | Constante tableau vide |
| `CODEC` | `BuilderCodec<ItemStack>` | Codec de sérialisation |

### Méthodes Statiques

| Méthode | Retour | Description |
|--------|---------|-------------|
| `isEmpty(ItemStack)` | `boolean` | Vérification vide null-safe |
| `isStackableWith(ItemStack, ItemStack)` | `boolean` | Vérification empilable null-safe |
| `isEquivalentType(ItemStack, ItemStack)` | `boolean` | Vérification type null-safe |
| `isSameItemType(ItemStack, ItemStack)` | `boolean` | Compare itemId seulement |
| `fromPacket(ItemQuantity)` | `ItemStack?` | Créer depuis paquet réseau |

### Classes Imbriquées

| Classe | Description |
|-------|-------------|
| `ItemStack.Metadata` | Contient constante `BLOCK_STATE` pour clé metadata état bloc |
