--- title: Conteneurs type: docs weight: 2 --- Les conteneurs gèrent des collections d'ItemStacks dans Hytale. Le système d'inventaire utilise `ItemContainer` comme abstraction de base avec `Inventory` comme conteneur multi-sections spécialisé du joueur. ## Structure de l'Inventaire Les inventaires des joueurs sont composés de plusieurs sections `ItemContainer` : ```java Inventory inv = player.getInventory(); // Obtenir les sections individuelles ItemContainer storage = inv.getStorage(); // Stockage principal (36 slots par défaut) ItemContainer hotbar = inv.getHotbar(); // Hotbar (9 slots par défaut) ItemContainer armor = inv.getArmor(); // Emplacements d'armure ItemContainer utility = inv.getUtility(); // Objets utilitaires (4 slots par défaut) ItemContainer backpack = inv.getBackpack(); // Sac à dos (extensible) // Conteneurs combinés pour opérations multi-sections CombinedItemContainer hotbarFirst = inv.getCombinedHotbarFirst(); CombinedItemContainer storageFirst = inv.getCombinedStorageFirst(); ``` ### IDs de Section Chaque section a un ID constant pour les opérations : | Section | ID | Constante | |---------|----|----| | Hotbar | -1 | `Inventory.HOTBAR_SECTION_ID` | | Stockage | -2 | `Inventory.STORAGE_SECTION_ID` | | Armure | -3 | `Inventory.ARMOR_SECTION_ID` | | Utilitaire | -5 | `Inventory.UTILITY_SECTION_ID` | | Outils | -8 | `Inventory.TOOLS_SECTION_ID` (déprécié) | | Sac à dos | -9 | `Inventory.BACKPACK_SECTION_ID` | ## Bases d'ItemContainer ### Lire les Objets ```java ItemContainer container = inv.getStorage(); // Obtenir la capacité (PAS getSize!) short capacity = container.getCapacity(); // Obtenir l'objet au slot (slot est de type SHORT) ItemStack item = container.getItemStack((short) 0); // Vérifier si vide boolean empty = container.isEmpty(); // Accès sécurisé aux objets ItemStack stack = container.getItemStack((short) slot); if (!ItemStack.isEmpty(stack)) { String itemId = stack.getItemId(); int quantity = stack.getQuantity(); } ``` ### Définir des Objets ```java ItemContainer container = inv.getHotbar(); // Définir l'objet au slot - retourne une Transaction ItemStackSlotTransaction transaction = container.setItemStackForSlot( (short) 0, new ItemStack("iron_sword", 1) ); // Vérifier si l'opération a réussi if (transaction.succeeded()) { // L'objet a été défini avec succès } // Vider un slot container.setItemStackForSlot((short) 0, null); ``` ### Ajouter des Objets ```java ItemContainer container = inv.getStorage(); ItemStack toAdd = new ItemStack("wood_plank", 64); // Ajouter au premier slot disponible (empile avec les objets existants d'abord) ItemStackTransaction transaction = container.addItemStack(toAdd); // Vérifier les objets restants qui n'ont pas pu rentrer ItemStack remainder = transaction.getRemainder(); if (!ItemStack.isEmpty(remainder)) { // Certains objets n'ont pas pu rentrer int leftover = remainder.getQuantity(); } // Ajouter à un slot spécifique ItemStackSlotTransaction slotTransaction = container.addItemStackToSlot( (short) 5, toAdd ); // Vérifier si le conteneur peut accueillir les objets avant d'ajouter if (container.canAddItemStack(toAdd)) { container.addItemStack(toAdd); } ``` ### Retirer des Objets ```java // Retirer d'un slot spécifique SlotTransaction transaction = container.removeItemStackFromSlot((short) 0); // Retirer une quantité spécifique du slot ItemStackSlotTransaction removeTransaction = container.removeItemStackFromSlot( (short) 0, 10 // quantité à retirer ); // Retirer un type d'objet spécifique de n'importe où dans le conteneur ItemStack toRemove = new ItemStack("iron_ore", 5); ItemStackTransaction itemTransaction = container.removeItemStack(toRemove); // Vérifier si les objets peuvent être retirés avant de retirer if (container.canRemoveItemStack(toRemove)) { container.removeItemStack(toRemove); } ``` ## Slots Actifs Les joueurs ont des slots actifs pour la hotbar et les objets utilitaires : ```java Inventory inv = player.getInventory(); // Obtenir le slot actif de la hotbar (0-8) byte activeHotbar = inv.getActiveHotbarSlot(); // Définir le slot actif de la hotbar inv.setActiveHotbarSlot((byte) 3); // Obtenir l'objet actuellement en main ItemStack handItem = inv.getItemInHand(); // Obtenir/définir le slot utilitaire actif byte activeUtility = inv.getActiveUtilitySlot(); inv.setActiveUtilitySlot((byte) 1); // Obtenir l'objet utilitaire ItemStack utilityItem = inv.getUtilityItem(); ``` ## Déplacer des Objets ### Entre les Slots ```java Inventory inv = player.getInventory(); ItemContainer storage = inv.getStorage(); ItemContainer hotbar = inv.getHotbar(); // Déplacer un objet d'un slot à un autre dans le même conteneur MoveTransaction transaction = storage.moveItemStackFromSlotToSlot( (short) 0, // depuis slot 64, // quantité storage, // vers conteneur (short) 5 // vers slot ); // Déplacer entre différents conteneurs storage.moveItemStackFromSlotToSlot( (short) 0, 32, hotbar, (short) 0 ); // Utiliser moveItem de l'Inventory pour les déplacements par section inv.moveItem( Inventory.STORAGE_SECTION_ID, // depuis section 5, // depuis slot 10, // quantité Inventory.HOTBAR_SECTION_ID, // vers section 0 // vers slot ); ``` ### Déplacement Intelligent ```java // Le déplacement intelligent considère le type d'objet pour un placement optimal inv.smartMoveItem( Inventory.STORAGE_SECTION_ID, 0, // slot 64, // quantité SmartMoveType.EquipOrMergeStack // tente d'équiper l'armure ou fusionner les piles ); ``` ## Itérer les Conteneurs ```java ItemContainer container = inv.getStorage(); // Itérer tous les slots non vides container.forEach((slot, itemStack) -> { getLogger().at(Level.INFO).log("Slot " + slot + ": " + itemStack.getItemId() + " x" + itemStack.getQuantity()); }); // Compter les objets correspondant à une condition int swordCount = container.countItemStacks( stack -> stack.getItemId().contains("sword") ); // Vérifier si le conteneur a des objets empilables ItemStack testStack = new ItemStack("stone", 1); boolean hasStackable = container.containsItemStacksStackableWith(testStack); ``` ## Vérifier le Contenu ```java ItemContainer container = inv.getStorage(); // Vérifier si l'inventaire contient un type et quantité d'objet spécifiques public boolean hasItems(ItemContainer container, String itemId, int amount) { int count = container.countItemStacks( stack -> stack.getItemId().equals(itemId) ); return count >= amount; } // Trouver le premier slot avec un objet spécifique public short findSlotWithItem(ItemContainer container, String itemId) { for (short i = 0; i < container.getCapacity(); i++) { ItemStack stack = container.getItemStack(i); if (!ItemStack.isEmpty(stack) && stack.getItemId().equals(itemId)) { return i; } } return -1; // Non trouvé } // Compter les slots vides public int countEmptySlots(ItemContainer container) { int empty = 0; for (short i = 0; i < container.getCapacity(); i++) { if (ItemStack.isEmpty(container.getItemStack(i))) { empty++; } } return empty; } ``` ## Vider les Conteneurs ```java ItemContainer container = inv.getStorage(); // Vider tout le conteneur ClearTransaction transaction = container.clear(); // Lâcher tous les objets (retourne la liste des objets lâchés) List droppedItems = container.dropAllItemStacks(); // Retirer tous les objets (retourne la liste) List removedItems = container.removeAllItemStacks(); // Vider tout l'inventaire du joueur inv.clear(); // Lâcher tout de l'inventaire du joueur List allDropped = inv.dropAllItemStacks(); ``` ## Tri Valeurs `SortType` disponibles : `NAME`, `TYPE`, `RARITY` ```java ItemContainer container = inv.getStorage(); // Trier les objets container.sortItems(SortType.NAME); // Trier via Inventory (sauvegarde aussi la préférence de tri) inv.sortStorage(SortType.NAME); inv.setSortType(SortType.RARITY); // Ou TYPE ``` ## Événements de Conteneur ```java // S'enregistrer pour les événements de changement de conteneur container.registerChangeEvent(event -> { ItemContainer changedContainer = event.container(); Transaction transaction = event.transaction(); getLogger().at(Level.INFO).log("Conteneur modifié !"); }); // Avec priorité container.registerChangeEvent(EventPriority.EARLY, event -> { // Gérer tôt }); ``` ## Système de Transactions Toutes les opérations de modification retournent des objets Transaction : ```java // Les transactions suivent le succès et les changements ItemStackTransaction transaction = container.addItemStack(itemStack); if (transaction.succeeded()) { ItemStack remainder = transaction.getRemainder(); // ... } // Les transactions de slot incluent les infos du slot ItemStackSlotTransaction slotTransaction = container.setItemStackForSlot( (short) 0, itemStack ); if (slotTransaction.succeeded()) { short slot = slotTransaction.getSlot(); ItemStack before = slotTransaction.getSlotBefore(); ItemStack after = slotTransaction.getSlotAfter(); } ``` ## Paramètres d'Opération La plupart des opérations de conteneur supportent des paramètres optionnels : ```java // Valeurs par défaut DEFAULT_ADD_ALL_OR_NOTHING = false; // Ajouts partiels autorisés DEFAULT_REMOVE_ALL_OR_NOTHING = true; // Uniquement retraits complets DEFAULT_FULL_STACKS = false; // Peut diviser les piles DEFAULT_EXACT_AMOUNT = true; // Quantités exactes uniquement DEFAULT_FILTER = true; // Applique les filtres de slot // Ajouter avec paramètres container.addItemStack(itemStack, allOrNothing, fullStacks, filter); // allOrNothing: si true, échoue entièrement si tous les objets ne rentrent pas // fullStacks: si true, remplit uniquement les slots vides (pas d'empilement) // filter: si true, respecte les filtres de slot ``` ## Retrait par Matériau et Ressource Les conteneurs supportent le retrait d'objets par type de matériau ou de ressource (utilisé pour le craft) : {{< callout type="info" >}} **Constructeur MaterialQuantity :** `MaterialQuantity(itemId, resourceTypeId, tag, quantity, metadata)` Au moins un parmi `itemId`, `resourceTypeId`, ou `tag` doit être non-null. {{< /callout >}} ```java // Retirer par matériau en utilisant itemId MaterialQuantity materialByItem = new MaterialQuantity("iron_ingot", null, null, 5, null); if (container.canRemoveMaterial(materialByItem)) { MaterialTransaction transaction = container.removeMaterial(materialByItem); } // Retirer par matériau en utilisant resourceTypeId MaterialQuantity materialByResource = new MaterialQuantity(null, "iron", null, 5, null); if (container.canRemoveMaterial(materialByResource)) { MaterialTransaction transaction = container.removeMaterial(materialByResource); } // Retirer par type de ressource (constructeur plus simple) ResourceQuantity resource = new ResourceQuantity("wood", 10); if (container.canRemoveResource(resource)) { ResourceTransaction transaction = container.removeResource(resource); } // Retirer par index de tag if (container.canRemoveTag(tagIndex, quantity)) { TagTransaction transaction = container.removeTag(tagIndex, quantity); } // Retrait en masse List materials = List.of( new MaterialQuantity("iron_ingot", null, null, 2, null), new MaterialQuantity(null, null, "Wood", 5, null) // Avec tag ); if (container.canRemoveMaterials(materials)) { container.removeMaterials(materials); } ``` ## Opérations en Masse Ajouter ou retirer plusieurs objets à la fois : ```java // Ajouter plusieurs objets List items = List.of( new ItemStack("iron_ore", 10), new ItemStack("gold_ore", 5) ); if (container.canAddItemStacks(items)) { ListTransaction transaction = container.addItemStacks(items); } // Retirer plusieurs objets if (container.canRemoveItemStacks(items)) { container.removeItemStacks(items); } // Ajouter les objets dans l'ordre (préserve les positions de slot) container.addItemStacksOrdered(items); container.addItemStacksOrdered((short) 5, items); // À partir du slot 5 ``` ## Opérations de Déplacement Avancées ```java // Déplacer tous les objets vers un autre conteneur ListTransaction> result = storage.moveAllItemStacksTo(hotbar, backpack); // Déplacer tous les objets correspondant à une condition storage.moveAllItemStacksTo( item -> item.getItemId().contains("ore"), hotbar ); // Quick stack : déplace uniquement les objets qui peuvent s'empiler avec des objets existants storage.quickStackTo(hotbar); // Combiner les petites piles dans un slot container.combineItemStacksIntoSlot(targetContainer, (short) 0); // Échanger des objets entre conteneurs storage.swapItems( (short) 0, // position source hotbar, // conteneur cible (short) 0, // position destination (short) 5 // nombre de slots à échanger ); ``` ## Opérations de Remplacement ```java // Remplacer l'objet dans le slot s'il correspond à l'attendu ItemStackSlotTransaction transaction = container.replaceItemStackInSlot( (short) 0, expectedItem, // doit correspondre à l'objet actuel pour continuer newItem ); // Remplacer tous les objets avec une fonction container.replaceAll((slot, existing) -> { if (existing.getItemId().equals("old_item")) { return new ItemStack("new_item", existing.getQuantity()); } return existing; }); ``` ## Filtres de Slot Contrôler quels objets peuvent aller dans quels slots : ```java // Définir un filtre global pour le conteneur container.setGlobalFilter(FilterType.WHITELIST); // Définir un filtre pour un slot spécifique container.setSlotFilter( FilterActionType.ADD, // Filtre sur les opérations d'ajout (short) 0, // Slot slotFilter // Implémentation du filtre ); ``` ## Bonnes Pratiques {{< callout type="info" >}} **Conseils pour les Conteneurs :** - Les indices de slot sont `short`, pas `int` - castez correctement - Vérifiez toujours `ItemStack.isEmpty(stack)` - gère null et vide - Utilisez `getQuantity()` pas `getCount()` - Vérifiez le succès de la transaction avec `succeeded()` - Utilisez les conteneurs combinés pour les opérations multi-sections - Les changements d'inventaire du joueur déclenchent `LivingEntityInventoryChangeEvent` {{< /callout >}} ```java // Pattern sécurisé pour travailler avec les conteneurs public void safeAddItem(ItemContainer container, ItemStack item) { if (ItemStack.isEmpty(item)) { return; } if (!container.canAddItemStack(item)) { // Gérer le conteneur plein return; } ItemStackTransaction transaction = container.addItemStack(item); if (!transaction.succeeded()) { // Gérer l'échec } } ``` ## Référence API ItemContainer ### Méthodes Principales | Méthode | Retour | Description | |--------|---------|-------------| | `getCapacity()` | `short` | Nombre total de slots | | `getItemStack(short)` | `ItemStack?` | Obtenir l'objet au slot | | `isEmpty()` | `boolean` | True si aucun objet | | `clone()` | `ItemContainer` | Cloner le conteneur | | `clear()` | `ClearTransaction` | Retirer tous les objets | ### Opérations d'Ajout | Méthode | Retour | Description | |--------|---------|-------------| | `canAddItemStack(ItemStack)` | `boolean` | Vérifier si peut ajouter | | `canAddItemStack(ItemStack, fullStacks, filter)` | `boolean` | Vérifier avec options | | `addItemStack(ItemStack)` | `ItemStackTransaction` | Ajouter au premier disponible | | `addItemStack(ItemStack, allOrNothing, fullStacks, filter)` | `ItemStackTransaction` | Ajouter avec options | | `canAddItemStackToSlot(short, ItemStack, allOrNothing, filter)` | `boolean` | Vérifier si peut ajouter au slot | | `addItemStackToSlot(short, ItemStack)` | `ItemStackSlotTransaction` | Ajouter à un slot spécifique | | `addItemStackToSlot(short, ItemStack, allOrNothing, filter)` | `ItemStackSlotTransaction` | Ajouter au slot avec options | | `canAddItemStacks(List)` | `boolean` | Vérifier si peut ajouter plusieurs | | `addItemStacks(List)` | `ListTransaction` | Ajouter plusieurs objets | | `addItemStacksOrdered(List)` | `ListTransaction` | Ajouter dans l'ordre | | `addItemStacksOrdered(short offset, List)` | `ListTransaction` | Ajouter dans l'ordre depuis offset | ### Opérations de Définition | Méthode | Retour | Description | |--------|---------|-------------| | `setItemStackForSlot(short, ItemStack)` | `ItemStackSlotTransaction` | Définir l'objet au slot | | `setItemStackForSlot(short, ItemStack, filter)` | `ItemStackSlotTransaction` | Définir avec option filtre | | `replaceItemStackInSlot(short, ItemStack attendu, ItemStack nouveau)` | `ItemStackSlotTransaction` | Remplacer si correspondance | | `replaceAll(SlotReplacementFunction)` | `ListTransaction` | Remplacer tous les objets | ### Opérations de Retrait | Méthode | Retour | Description | |--------|---------|-------------| | `removeItemStackFromSlot(short)` | `SlotTransaction` | Retirer tout le slot | | `removeItemStackFromSlot(short, filter)` | `SlotTransaction` | Retirer avec filtre | | `removeItemStackFromSlot(short, quantity)` | `ItemStackSlotTransaction` | Retirer une quantité | | `removeItemStackFromSlot(short, ItemStack, quantity)` | `ItemStackSlotTransaction` | Retirer objet correspondant | | `canRemoveItemStack(ItemStack)` | `boolean` | Vérifier si peut retirer | | `removeItemStack(ItemStack)` | `ItemStackTransaction` | Retirer type d'objet | | `canRemoveItemStacks(List)` | `boolean` | Vérifier si peut retirer plusieurs | | `removeItemStacks(List)` | `ListTransaction` | Retirer plusieurs objets | | `removeAllItemStacks()` | `List` | Retirer et retourner tous | | `dropAllItemStacks()` | `List` | Lâcher tous (respecte cantDrop) | | `dropAllItemStacks(filter)` | `List` | Lâcher avec option filtre | ### Retrait Matériau/Ressource/Tag | Méthode | Retour | Description | |--------|---------|-------------| | `canRemoveMaterial(MaterialQuantity)` | `boolean` | Vérifier retrait matériau | | `removeMaterial(MaterialQuantity)` | `MaterialTransaction` | Retirer par matériau | | `removeMaterialFromSlot(short, MaterialQuantity)` | `MaterialSlotTransaction` | Retirer matériau du slot | | `canRemoveMaterials(List)` | `boolean` | Vérifier plusieurs matériaux | | `removeMaterials(List)` | `ListTransaction` | Retirer plusieurs matériaux | | `canRemoveResource(ResourceQuantity)` | `boolean` | Vérifier retrait ressource | | `removeResource(ResourceQuantity)` | `ResourceTransaction` | Retirer par ressource | | `removeResourceFromSlot(short, ResourceQuantity)` | `ResourceSlotTransaction` | Retirer ressource du slot | | `canRemoveResources(List)` | `boolean` | Vérifier plusieurs ressources | | `removeResources(List)` | `ListTransaction` | Retirer plusieurs ressources | | `canRemoveTag(tagIndex, quantity)` | `boolean` | Vérifier retrait tag | | `removeTag(tagIndex, quantity)` | `TagTransaction` | Retirer par tag | | `removeTagFromSlot(short, tagIndex, quantity)` | `TagSlotTransaction` | Retirer tag du slot | ### Opérations de Déplacement | Méthode | Retour | Description | |--------|---------|-------------| | `moveItemStackFromSlot(short, ItemContainer)` | `MoveTransaction` | Déplacer slot vers conteneur | | `moveItemStackFromSlot(short, quantity, ItemContainer)` | `MoveTransaction` | Déplacer quantité | | `moveItemStackFromSlot(short, ItemContainer...)` | `ListTransaction` | Déplacer vers plusieurs conteneurs | | `moveItemStackFromSlotToSlot(short, quantity, ItemContainer, short)` | `MoveTransaction` | Déplacer vers slot spécifique | | `moveAllItemStacksTo(ItemContainer...)` | `ListTransaction` | Déplacer tous les objets | | `moveAllItemStacksTo(Predicate, ItemContainer...)` | `ListTransaction` | Déplacer objets correspondants | | `quickStackTo(ItemContainer...)` | `ListTransaction` | Déplacer uniquement empilables | | `combineItemStacksIntoSlot(ItemContainer, short)` | `ListTransaction` | Combiner piles dans slot | | `swapItems(short srcPos, ItemContainer, short destPos, short length)` | `ListTransaction` | Échanger plages d'objets | ### Méthodes Utilitaires | Méthode | Retour | Description | |--------|---------|-------------| | `forEach(ShortObjectConsumer)` | `void` | Itérer slots non vides | | `forEachWithMeta(consumer, meta)` | `void` | Itérer avec métadonnées | | `countItemStacks(Predicate)` | `int` | Compter objets correspondants (quantité totale) | | `containsItemStacksStackableWith(ItemStack)` | `boolean` | Vérifier objets empilables | | `sortItems(SortType)` | `ListTransaction` | Trier conteneur | | `registerChangeEvent(Consumer)` | `EventRegistration` | Écouter les changements | | `registerChangeEvent(EventPriority, Consumer)` | `EventRegistration` | Écouter avec priorité | | `setGlobalFilter(FilterType)` | `void` | Définir filtre conteneur | | `setSlotFilter(FilterActionType, short, SlotFilter)` | `void` | Définir filtre slot | | `containsContainer(ItemContainer)` | `boolean` | Vérifier si contient conteneur | ### Méthodes Statiques | Méthode | Retour | Description | |--------|---------|-------------| | `copy(from, to, remainder)` | `T` | Copier objets entre conteneurs | | `ensureContainerCapacity(container, capacity, supplier, remainder)` | `T` | S'assurer de la capacité | | `getNewContainer(capacity, supplier)` | `ItemContainer` | Créer ou obtenir vide | | `getMatchingResourceType(Item, resourceId)` | `ItemResourceType?` | Trouver type ressource pour objet | | `validateQuantity(int)` | `void` | Lance exception si < 0 | | `validateSlotIndex(short, capacity)` | `void` | Lance exception si hors limites | ### Constantes Statiques | Champ | Type | Description | |-------|------|-------------| | `CODEC` | `CodecMapCodec` | Codec de sérialisation | | `DEFAULT_ADD_ALL_OR_NOTHING` | `boolean` | false | | `DEFAULT_REMOVE_ALL_OR_NOTHING` | `boolean` | true | | `DEFAULT_FULL_STACKS` | `boolean` | false | | `DEFAULT_EXACT_AMOUNT` | `boolean` | true | | `DEFAULT_FILTER` | `boolean` | true | ### Classes Imbriquées | Classe | Description | |-------|-------------| | `ItemContainerChangeEvent` | Record événement avec `container()` et `transaction()` | ## Référence API Inventory | Méthode | Retour | Description | |--------|---------|-------------| | `getStorage()` | `ItemContainer` | Section de stockage principal | | `getHotbar()` | `ItemContainer` | Section hotbar | | `getArmor()` | `ItemContainer` | Section armure | | `getUtility()` | `ItemContainer` | Section utilitaire | | `getBackpack()` | `ItemContainer` | Section sac à dos | | `getSectionById(int)` | `ItemContainer?` | Obtenir section par ID | | `getItemInHand()` | `ItemStack?` | Objet actuellement tenu | | `getActiveHotbarSlot()` | `byte` | Slot actif de la hotbar | | `setActiveHotbarSlot(byte)` | `void` | Définir hotbar active | | `getCombinedHotbarFirst()` | `CombinedItemContainer` | Hotbar+Stockage combinés | | `moveItem(...)` | `void` | Déplacer entre sections | | `clear()` | `void` | Vider toutes les sections |