431 lines
13 KiB
Markdown
431 lines
13 KiB
Markdown
---
|
|
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<ItemStackSlotTransaction> 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<SlotTransaction> 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<ItemStack> items = List.of(
|
|
new ItemStack("stone", 64),
|
|
new ItemStack("wood", 64)
|
|
);
|
|
|
|
ListTransaction<ItemStackTransaction> transaction = container.addItemStacks(items);
|
|
|
|
if (transaction.succeeded()) {
|
|
List<ItemStackTransaction> 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<ItemStackSlotTransaction>` | Toutes les transactions de slot |
|
|
|
|
| Statique | Type | Description |
|
|
|----------|------|-------------|
|
|
| `FAILED_ADD` | `ItemStackTransaction` | Transaction d'ajout échouée pré-construite |
|
|
|
|
### MoveTransaction<T extends Transaction>
|
|
|
|
| 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<T>` | Créer vue inversée pour l'autre conteneur |
|
|
|
|
### ListTransaction<T extends Transaction>
|
|
|
|
| Méthode | Retour | Description |
|
|
|--------|---------|-------------|
|
|
| `getList()` | `List<T>` | 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<T>` | 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 |
|