--- title: Transactions type: docs weight: 3 --- Les transactions suivent les résultats des opérations d'inventaire dans Hytale. Chaque modification d'un `ItemContainer` retourne un objet Transaction qui décrit ce qui s'est passé. ## Interface Transaction Toutes les transactions implémentent l'interface de base `Transaction` : ```java public interface Transaction { // L'opération a-t-elle réussi ? boolean succeeded(); // Un slot spécifique a-t-il été modifié ? boolean wasSlotModified(short slot); } ``` ## Types de Transactions ### SlotTransaction Suit les changements d'un seul slot : ```java SlotTransaction transaction = container.removeItemStackFromSlot((short) 0); if (transaction.succeeded()) { // Ce qui était dans le slot avant ItemStack before = transaction.getSlotBefore(); // Ce qui est dans le slot maintenant ItemStack after = transaction.getSlotAfter(); // L'objet qui a été retiré/sorti ItemStack output = transaction.getOutput(); // Quel slot a été affecté short slot = transaction.getSlot(); // Quel type d'action (ADD, REMOVE, REPLACE) ActionType action = transaction.getAction(); } ``` ### ItemStackSlotTransaction Transaction de slot étendue avec des détails supplémentaires : ```java ItemStackSlotTransaction transaction = container.setItemStackForSlot( (short) 0, new ItemStack("iron_sword", 1) ); if (transaction.succeeded()) { short slot = transaction.getSlot(); ItemStack before = transaction.getSlotBefore(); ItemStack after = transaction.getSlotAfter(); // Vérifier les options utilisées boolean wasFiltered = transaction.isFilter(); boolean wasAllOrNothing = transaction.isAllOrNothing(); } ``` ### ItemStackTransaction Suit les opérations qui peuvent affecter plusieurs slots : ```java ItemStack toAdd = new ItemStack("stone", 128); ItemStackTransaction transaction = container.addItemStack(toAdd); if (transaction.succeeded()) { // Objets qui n'ont pas pu rentrer (null si tous ont rentré) ItemStack remainder = transaction.getRemainder(); // Objet original qu'on a essayé d'ajouter ItemStack query = transaction.getQuery(); // Liste de toutes les transactions de slot qui ont eu lieu List slotTransactions = transaction.getSlotTransactions(); for (ItemStackSlotTransaction slotTx : slotTransactions) { getLogger().at(Level.INFO).log("Slot modifié " + slotTx.getSlot()); } } ``` ### MoveTransaction Suit le déplacement d'objets entre conteneurs : ```java MoveTransaction transaction = storage.moveItemStackFromSlotToSlot( (short) 0, 32, hotbar, (short) 0 ); if (transaction.succeeded()) { // Transaction pour le retrait de la source SlotTransaction removeTransaction = transaction.getRemoveTransaction(); // Transaction pour l'ajout à la destination SlotTransaction addTransaction = transaction.getAddTransaction(); // Le conteneur de destination ItemContainer destination = transaction.getOtherContainer(); // Direction du déplacement MoveType moveType = transaction.getMoveType(); } ``` ### ListTransaction Encapsule plusieurs transactions : ```java List items = List.of( new ItemStack("stone", 64), new ItemStack("wood", 64) ); ListTransaction transaction = container.addItemStacks(items); if (transaction.succeeded()) { List results = transaction.getList(); for (ItemStackTransaction result : results) { if (result.succeeded()) { ItemStack remainder = result.getRemainder(); // ... } } } ``` ## ActionType Les opérations sont catégorisées par type d'action : ```java public enum ActionType { SET, // Objets définis (add=true, remove=false, destroy=true) ADD, // Objets ajoutés au slot (add=true, remove=false, destroy=false) REMOVE, // Objets retirés du slot (add=false, remove=true, destroy=false) REPLACE // Contenu du slot remplacé (add=true, remove=true, destroy=false) } // Vérifier les caractéristiques de l'action if (action.isAdd()) { /* opération ajoute des objets */ } if (action.isRemove()) { /* opération retire des objets */ } if (action.isDestroy()) { /* opération détruit le contenu du slot */ } ``` ## MoveType Direction des opérations de déplacement : ```java public enum MoveType { MOVE_TO_SELF, // Objets déplacés VERS ce conteneur MOVE_FROM_SELF // Objets déplacés DEPUIS ce conteneur } ``` ## Patterns Courants ### Vérifier Avant de Modifier ```java // Pattern sûr : vérifier d'abord, puis exécuter public boolean safeTransfer(ItemContainer from, ItemContainer to, String itemId, int amount) { ItemStack toRemove = new ItemStack(itemId, amount); // Vérifier que les deux opérations peuvent réussir if (!from.canRemoveItemStack(toRemove)) { return false; // Pas assez d'objets } if (!to.canAddItemStack(toRemove)) { return false; // Pas de place } // Exécuter le retrait ItemStackTransaction removeResult = from.removeItemStack(toRemove); if (!removeResult.succeeded()) { return false; } // Exécuter l'ajout ItemStack removed = removeResult.getQuery(); ItemStackTransaction addResult = to.addItemStack(removed); // Gérer les restes éventuels ItemStack remainder = addResult.getRemainder(); if (!ItemStack.isEmpty(remainder)) { // Remettre les restes from.addItemStack(remainder); } return true; } ``` ### Gérer les Restes ```java public void giveItemSafe(Player player, String itemId, int quantity) { ItemContainer storage = player.getInventory().getStorage(); ItemStack item = new ItemStack(itemId, quantity); ItemStackTransaction result = storage.addItemStack(item); if (!result.succeeded()) { player.sendMessage(Message.raw("Inventaire plein !")); return; } ItemStack remainder = result.getRemainder(); if (!ItemStack.isEmpty(remainder)) { player.sendMessage(Message.raw( "Seulement reçu " + (quantity - remainder.getQuantity()) + " objets, " + "inventaire plein !" )); } } ``` ### Opérations Atomiques ```java // allOrNothing=true garantit que les opérations partielles ne se produisent pas public boolean buyItem(Player player, String itemId, int price, int quantity) { Inventory inv = player.getInventory(); ItemContainer storage = inv.getStorage(); ItemStack currency = new ItemStack("gold_coin", price); ItemStack item = new ItemStack(itemId, quantity); // Vérifier que les deux opérations peuvent réussir complètement if (!storage.canRemoveItemStack(currency)) { player.sendMessage(Message.raw("Pas assez d'or !")); return false; } if (!storage.canAddItemStack(item)) { player.sendMessage(Message.raw("Inventaire plein !")); return false; } // Retirer la monnaie avec allOrNothing=true ItemStackTransaction removeResult = storage.removeItemStack(currency, true, true); if (!removeResult.succeeded()) { return false; } // Ajouter l'objet ItemStackTransaction addResult = storage.addItemStack(item, true, false, true); if (!addResult.succeeded()) { // Annuler : rendre la monnaie storage.addItemStack(currency); return false; } return true; } ``` ### Suivre les Changements ```java // Utiliser wasSlotModified pour vérifier des slots spécifiques public void onContainerChange(ItemContainer.ItemContainerChangeEvent event) { Transaction transaction = event.transaction(); // Vérifier si le slot 0 de la hotbar a été affecté if (transaction.wasSlotModified((short) 0)) { getLogger().at(Level.INFO).log("Premier slot modifié !"); } // Vérifier tous les slots de la hotbar for (short i = 0; i < 9; i++) { if (transaction.wasSlotModified(i)) { getLogger().at(Level.INFO).log("Slot hotbar " + i + " modifié"); } } } ``` ## Options de Transaction De nombreuses opérations acceptent des paramètres optionnels : | Paramètre | Description | Par défaut | |-----------|-------------|---------| | `allOrNothing` | Si vrai, l'opération échoue si tous les objets ne peuvent pas être traités | `false` | | `fullStacks` | Si vrai, ajoute seulement aux slots vides (pas aux piles partielles) | `false` | | `exactAmount` | Si vrai, doit retirer exactement la quantité demandée | `true` | | `filter` | Si vrai, respecte les filtres de slot | `true` | ```java // Comportement par défaut container.addItemStack(item); // Avec options container.addItemStack(item, true, false, true); // allOrNothing, fullStacks, filter container.removeItemStack(item, true, true); // allOrNothing, filter ``` ## Bonnes Pratiques {{< callout type="info" >}} **Conseils pour les Transactions :** - Toujours vérifier `succeeded()` avant d'accéder aux résultats - Gérer les restes lors de l'ajout d'objets - Utiliser `canAddItemStack()`/`canRemoveItemStack()` pour la pré-validation - Utiliser `allOrNothing=true` pour les opérations critiques - Vérifier `wasSlotModified()` pour suivre les changements de slots spécifiques {{< /callout >}} ```java // Bon : Vérifier le succès et gérer les restes ItemStackTransaction tx = container.addItemStack(item); if (tx.succeeded()) { ItemStack remainder = tx.getRemainder(); if (!ItemStack.isEmpty(remainder)) { // Gérer les objets restants } } // Mauvais : Supposer le succès container.addItemStack(item); // Pourrait échouer silencieusement ! ``` ## Référence API Transaction ### Interface Transaction | Méthode | Retour | Description | |--------|---------|-------------| | `succeeded()` | `boolean` | True si l'opération a réussi | | `wasSlotModified(short)` | `boolean` | True si le slot spécifique a été modifié | ### SlotTransaction | Méthode | Retour | Description | |--------|---------|-------------| | `getSlot()` | `short` | Index du slot affecté | | `getAction()` | `ActionType` | Type d'action effectuée | | `getSlotBefore()` | `ItemStack?` | Contenu avant l'opération | | `getSlotAfter()` | `ItemStack?` | Contenu après l'opération | | `getOutput()` | `ItemStack?` | Objets retirés/sortis | | `isAllOrNothing()` | `boolean` | Paramètre allOrNothing utilisé | | `isExactAmount()` | `boolean` | Paramètre exactAmount utilisé | | `isFilter()` | `boolean` | Paramètre filter utilisé | | Statique | Type | Description | |----------|------|-------------| | `FAILED_ADD` | `SlotTransaction` | Transaction d'ajout échouée pré-construite | ### ItemStackSlotTransaction (étend SlotTransaction) | Méthode | Retour | Description | |--------|---------|-------------| | `isAddToExistingSlot()` | `boolean` | True si ajouté à une pile existante | | `getQuery()` | `ItemStack?` | Objet original demandé | | `getRemainder()` | `ItemStack?` | Objets qui n'ont pas pu rentrer | ### ItemStackTransaction | Méthode | Retour | Description | |--------|---------|-------------| | `getAction()` | `ActionType?` | Type d'action effectuée | | `getQuery()` | `ItemStack?` | Objet original demandé | | `getRemainder()` | `ItemStack?` | Objets qui n'ont pas pu rentrer | | `isAllOrNothing()` | `boolean` | Paramètre allOrNothing utilisé | | `isFilter()` | `boolean` | Paramètre filter utilisé | | `getSlotTransactions()` | `List` | Toutes les transactions de slot | | Statique | Type | Description | |----------|------|-------------| | `FAILED_ADD` | `ItemStackTransaction` | Transaction d'ajout échouée pré-construite | ### MoveTransaction | Méthode | Retour | Description | |--------|---------|-------------| | `getRemoveTransaction()` | `SlotTransaction` | Transaction de retrait | | `getMoveType()` | `MoveType` | Direction du déplacement | | `getOtherContainer()` | `ItemContainer` | L'autre conteneur impliqué | | `getAddTransaction()` | `T` | Transaction d'ajout | | `toInverted(ItemContainer)` | `MoveTransaction` | Créer vue inversée pour l'autre conteneur | ### ListTransaction | Méthode | Retour | Description | |--------|---------|-------------| | `getList()` | `List` | Toutes les transactions de la liste | | `size()` | `int` | Nombre de transactions | | Statique | Type | Description | |----------|------|-------------| | `EMPTY_SUCCESSFUL_TRANSACTION` | `ListTransaction` | Succès vide pré-construit | | `EMPTY_FAILED_TRANSACTION` | `ListTransaction` | Échec vide pré-construit | | `getEmptyTransaction(boolean)` | `ListTransaction` | Obtenir succès/échec vide | ### Enum ActionType | Valeur | isAdd | isRemove | isDestroy | Description | |--------|-------|----------|-----------|-------------| | `SET` | true | false | true | Définir le contenu du slot | | `ADD` | true | false | false | Ajouter des objets au slot | | `REMOVE` | false | true | false | Retirer des objets du slot | | `REPLACE` | true | true | false | Remplacer le contenu du slot | ### Enum MoveType | Valeur | Description | |--------|-------------| | `MOVE_TO_SELF` | Objets déplacés vers ce conteneur | | `MOVE_FROM_SELF` | Objets déplacés depuis ce conteneur |