Init
This commit is contained in:
57
content/world/entities/inventory/_index.en.md
Normal file
57
content/world/entities/inventory/_index.en.md
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: Inventory
|
||||
type: docs
|
||||
weight: 7
|
||||
---
|
||||
|
||||
The inventory system in Hytale handles items, containers, and player inventories.
|
||||
|
||||
{{< cards >}}
|
||||
{{< card link="itemstacks" title="ItemStacks" subtitle="Working with immutable item stacks" >}}
|
||||
{{< card link="containers" title="Containers" subtitle="Inventory and container types" >}}
|
||||
{{< card link="transactions" title="Transactions" subtitle="Safe item modifications" >}}
|
||||
{{< /cards >}}
|
||||
|
||||
## Overview
|
||||
|
||||
The inventory system follows an immutable pattern:
|
||||
- **ItemStack** - Immutable representation of items
|
||||
- **Inventory** - Player's personal inventory
|
||||
- **ItemContainer** - Generic container for items
|
||||
- **Transactions** - Safe way to modify items
|
||||
|
||||
## Quick Start
|
||||
|
||||
```java
|
||||
import com.hypixel.hytale.server.core.inventory.Inventory;
|
||||
import com.hypixel.hytale.server.core.inventory.ItemStack;
|
||||
import java.util.logging.Level;
|
||||
|
||||
// Get player inventory
|
||||
Player player = ...;
|
||||
Inventory inv = player.getInventory();
|
||||
|
||||
// Get item in hand (via Inventory, not directly on Player)
|
||||
ItemStack hand = inv.getItemInHand();
|
||||
|
||||
// Check if item exists
|
||||
if (hand != null && !hand.isEmpty()) {
|
||||
// Use getItemId() - Item.getName() doesn't exist
|
||||
getLogger().at(Level.INFO).log("Holding: " + hand.getItemId());
|
||||
}
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
{{< callout type="info" >}}
|
||||
ItemStack is **immutable**. Methods like `withQuantity()` return a new ItemStack rather than modifying the original.
|
||||
{{< /callout >}}
|
||||
|
||||
```java
|
||||
// Immutable pattern
|
||||
ItemStack original = new ItemStack("iron_sword", 1);
|
||||
ItemStack modified = original.withQuantity(5); // New instance
|
||||
|
||||
// original still has quantity of 1
|
||||
// modified has quantity of 5
|
||||
```
|
||||
57
content/world/entities/inventory/_index.fr.md
Normal file
57
content/world/entities/inventory/_index.fr.md
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: Inventaire
|
||||
type: docs
|
||||
weight: 7
|
||||
---
|
||||
|
||||
Le système d'inventaire dans Hytale gère les objets, conteneurs et inventaires des joueurs.
|
||||
|
||||
{{< cards >}}
|
||||
{{< card link="itemstacks" title="ItemStacks" subtitle="Travailler avec les piles d'objets immuables" >}}
|
||||
{{< card link="containers" title="Conteneurs" subtitle="Types d'inventaires et conteneurs" >}}
|
||||
{{< card link="transactions" title="Transactions" subtitle="Modifications sûres des objets" >}}
|
||||
{{< /cards >}}
|
||||
|
||||
## Aperçu
|
||||
|
||||
Le système d'inventaire suit un pattern immuable :
|
||||
- **ItemStack** - Représentation immuable des objets
|
||||
- **Inventory** - Inventaire personnel du joueur
|
||||
- **ItemContainer** - Conteneur générique pour les objets
|
||||
- **Transactions** - Moyen sûr de modifier les objets
|
||||
|
||||
## Démarrage Rapide
|
||||
|
||||
```java
|
||||
import com.hypixel.hytale.server.core.inventory.Inventory;
|
||||
import com.hypixel.hytale.server.core.inventory.ItemStack;
|
||||
import java.util.logging.Level;
|
||||
|
||||
// Obtenir l'inventaire du joueur
|
||||
Player player = ...;
|
||||
Inventory inv = player.getInventory();
|
||||
|
||||
// Obtenir l'objet en main (via Inventory, pas directement sur Player)
|
||||
ItemStack hand = inv.getItemInHand();
|
||||
|
||||
// Vérifier si l'objet existe
|
||||
if (hand != null && !hand.isEmpty()) {
|
||||
// Utiliser getItemId() - Item.getName() n'existe pas
|
||||
getLogger().at(Level.INFO).log("Tient : " + hand.getItemId());
|
||||
}
|
||||
```
|
||||
|
||||
## Concepts Clés
|
||||
|
||||
{{< callout type="info" >}}
|
||||
ItemStack est **immuable**. Les méthodes comme `withQuantity()` retournent un nouveau ItemStack plutôt que de modifier l'original.
|
||||
{{< /callout >}}
|
||||
|
||||
```java
|
||||
// Pattern immuable
|
||||
ItemStack original = new ItemStack("iron_sword", 1);
|
||||
ItemStack modified = original.withQuantity(5); // Nouvelle instance
|
||||
|
||||
// original a toujours une quantité de 1
|
||||
// modified a une quantité de 5
|
||||
```
|
||||
668
content/world/entities/inventory/containers.en.md
Normal file
668
content/world/entities/inventory/containers.en.md
Normal file
@@ -0,0 +1,668 @@
|
||||
---
|
||||
title: Containers
|
||||
type: docs
|
||||
weight: 2
|
||||
---
|
||||
|
||||
Containers hold and manage collections of ItemStacks in Hytale. The inventory system uses `ItemContainer` as the base abstraction with `Inventory` as the player's specialized multi-section container.
|
||||
|
||||
## Inventory Structure
|
||||
|
||||
Player inventories are composed of multiple `ItemContainer` sections:
|
||||
|
||||
```java
|
||||
Inventory inv = player.getInventory();
|
||||
|
||||
// Get individual sections
|
||||
ItemContainer storage = inv.getStorage(); // Main storage (36 slots default)
|
||||
ItemContainer hotbar = inv.getHotbar(); // Hotbar (9 slots default)
|
||||
ItemContainer armor = inv.getArmor(); // Armor slots
|
||||
ItemContainer utility = inv.getUtility(); // Utility items (4 slots default)
|
||||
ItemContainer backpack = inv.getBackpack(); // Backpack (expandable)
|
||||
|
||||
// Combined containers for operations across multiple sections
|
||||
CombinedItemContainer hotbarFirst = inv.getCombinedHotbarFirst();
|
||||
CombinedItemContainer storageFirst = inv.getCombinedStorageFirst();
|
||||
```
|
||||
|
||||
### Section IDs
|
||||
|
||||
Each section has a constant ID for operations:
|
||||
|
||||
| Section | ID | Constant |
|
||||
|---------|----|----|
|
||||
| Hotbar | -1 | `Inventory.HOTBAR_SECTION_ID` |
|
||||
| Storage | -2 | `Inventory.STORAGE_SECTION_ID` |
|
||||
| Armor | -3 | `Inventory.ARMOR_SECTION_ID` |
|
||||
| Utility | -5 | `Inventory.UTILITY_SECTION_ID` |
|
||||
| Tools | -8 | `Inventory.TOOLS_SECTION_ID` (deprecated) |
|
||||
| Backpack | -9 | `Inventory.BACKPACK_SECTION_ID` |
|
||||
|
||||
## ItemContainer Basics
|
||||
|
||||
### Reading Items
|
||||
|
||||
```java
|
||||
ItemContainer container = inv.getStorage();
|
||||
|
||||
// Get capacity (NOT getSize!)
|
||||
short capacity = container.getCapacity();
|
||||
|
||||
// Get item at slot (slot is SHORT type)
|
||||
ItemStack item = container.getItemStack((short) 0);
|
||||
|
||||
// Check if empty
|
||||
boolean empty = container.isEmpty();
|
||||
|
||||
// Safe item access
|
||||
ItemStack stack = container.getItemStack((short) slot);
|
||||
if (!ItemStack.isEmpty(stack)) {
|
||||
String itemId = stack.getItemId();
|
||||
int quantity = stack.getQuantity();
|
||||
}
|
||||
```
|
||||
|
||||
### Setting Items
|
||||
|
||||
```java
|
||||
ItemContainer container = inv.getHotbar();
|
||||
|
||||
// Set item at slot - returns a Transaction
|
||||
ItemStackSlotTransaction transaction = container.setItemStackForSlot(
|
||||
(short) 0,
|
||||
new ItemStack("iron_sword", 1)
|
||||
);
|
||||
|
||||
// Check if operation succeeded
|
||||
if (transaction.succeeded()) {
|
||||
// Item was set successfully
|
||||
}
|
||||
|
||||
// Clear a slot
|
||||
container.setItemStackForSlot((short) 0, null);
|
||||
```
|
||||
|
||||
### Adding Items
|
||||
|
||||
```java
|
||||
ItemContainer container = inv.getStorage();
|
||||
ItemStack toAdd = new ItemStack("wood_plank", 64);
|
||||
|
||||
// Add to first available slot (stacks with existing items first)
|
||||
ItemStackTransaction transaction = container.addItemStack(toAdd);
|
||||
|
||||
// Check for remaining items that couldn't fit
|
||||
ItemStack remainder = transaction.getRemainder();
|
||||
if (!ItemStack.isEmpty(remainder)) {
|
||||
// Some items couldn't fit
|
||||
int leftover = remainder.getQuantity();
|
||||
}
|
||||
|
||||
// Add to specific slot
|
||||
ItemStackSlotTransaction slotTransaction = container.addItemStackToSlot(
|
||||
(short) 5,
|
||||
toAdd
|
||||
);
|
||||
|
||||
// Check if container can fit items before adding
|
||||
if (container.canAddItemStack(toAdd)) {
|
||||
container.addItemStack(toAdd);
|
||||
}
|
||||
```
|
||||
|
||||
### Removing Items
|
||||
|
||||
```java
|
||||
// Remove from specific slot
|
||||
SlotTransaction transaction = container.removeItemStackFromSlot((short) 0);
|
||||
|
||||
// Remove specific quantity from slot
|
||||
ItemStackSlotTransaction removeTransaction = container.removeItemStackFromSlot(
|
||||
(short) 0,
|
||||
10 // quantity to remove
|
||||
);
|
||||
|
||||
// Remove specific item type from anywhere in container
|
||||
ItemStack toRemove = new ItemStack("iron_ore", 5);
|
||||
ItemStackTransaction itemTransaction = container.removeItemStack(toRemove);
|
||||
|
||||
// Check if items can be removed before removing
|
||||
if (container.canRemoveItemStack(toRemove)) {
|
||||
container.removeItemStack(toRemove);
|
||||
}
|
||||
```
|
||||
|
||||
## Active Slots
|
||||
|
||||
Players have active slots for hotbar and utility items:
|
||||
|
||||
```java
|
||||
Inventory inv = player.getInventory();
|
||||
|
||||
// Get active hotbar slot (0-8)
|
||||
byte activeHotbar = inv.getActiveHotbarSlot();
|
||||
|
||||
// Set active hotbar slot
|
||||
inv.setActiveHotbarSlot((byte) 3);
|
||||
|
||||
// Get item currently in hand
|
||||
ItemStack handItem = inv.getItemInHand();
|
||||
|
||||
// Get/set active utility slot
|
||||
byte activeUtility = inv.getActiveUtilitySlot();
|
||||
inv.setActiveUtilitySlot((byte) 1);
|
||||
|
||||
// Get utility item
|
||||
ItemStack utilityItem = inv.getUtilityItem();
|
||||
```
|
||||
|
||||
## Moving Items
|
||||
|
||||
### Between Slots
|
||||
|
||||
```java
|
||||
Inventory inv = player.getInventory();
|
||||
ItemContainer storage = inv.getStorage();
|
||||
ItemContainer hotbar = inv.getHotbar();
|
||||
|
||||
// Move item from one slot to another in same container
|
||||
MoveTransaction<SlotTransaction> transaction = storage.moveItemStackFromSlotToSlot(
|
||||
(short) 0, // from slot
|
||||
64, // quantity
|
||||
storage, // to container
|
||||
(short) 5 // to slot
|
||||
);
|
||||
|
||||
// Move between different containers
|
||||
storage.moveItemStackFromSlotToSlot(
|
||||
(short) 0,
|
||||
32,
|
||||
hotbar,
|
||||
(short) 0
|
||||
);
|
||||
|
||||
// Use Inventory's moveItem for section-based moves
|
||||
inv.moveItem(
|
||||
Inventory.STORAGE_SECTION_ID, // from section
|
||||
5, // from slot
|
||||
10, // quantity
|
||||
Inventory.HOTBAR_SECTION_ID, // to section
|
||||
0 // to slot
|
||||
);
|
||||
```
|
||||
|
||||
### Smart Moving
|
||||
|
||||
```java
|
||||
// Smart move considers item type for optimal placement
|
||||
inv.smartMoveItem(
|
||||
Inventory.STORAGE_SECTION_ID,
|
||||
0, // slot
|
||||
64, // quantity
|
||||
SmartMoveType.EquipOrMergeStack // tries to equip armor or merge stacks
|
||||
);
|
||||
```
|
||||
|
||||
## Iterating Containers
|
||||
|
||||
```java
|
||||
ItemContainer container = inv.getStorage();
|
||||
|
||||
// Iterate all non-empty slots
|
||||
container.forEach((slot, itemStack) -> {
|
||||
getLogger().at(Level.INFO).log("Slot " + slot + ": " +
|
||||
itemStack.getItemId() + " x" + itemStack.getQuantity());
|
||||
});
|
||||
|
||||
// Count items matching a condition
|
||||
int swordCount = container.countItemStacks(
|
||||
stack -> stack.getItemId().contains("sword")
|
||||
);
|
||||
|
||||
// Check if container has stackable items
|
||||
ItemStack testStack = new ItemStack("stone", 1);
|
||||
boolean hasStackable = container.containsItemStacksStackableWith(testStack);
|
||||
```
|
||||
|
||||
## Checking Contents
|
||||
|
||||
```java
|
||||
ItemContainer container = inv.getStorage();
|
||||
|
||||
// Check if inventory contains specific item type and quantity
|
||||
public boolean hasItems(ItemContainer container, String itemId, int amount) {
|
||||
int count = container.countItemStacks(
|
||||
stack -> stack.getItemId().equals(itemId)
|
||||
);
|
||||
return count >= amount;
|
||||
}
|
||||
|
||||
// Find first slot with specific item
|
||||
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; // Not found
|
||||
}
|
||||
|
||||
// Count empty slots
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
## Clearing Containers
|
||||
|
||||
```java
|
||||
ItemContainer container = inv.getStorage();
|
||||
|
||||
// Clear entire container
|
||||
ClearTransaction transaction = container.clear();
|
||||
|
||||
// Drop all items (returns list of dropped items)
|
||||
List<ItemStack> droppedItems = container.dropAllItemStacks();
|
||||
|
||||
// Remove all items (returns list)
|
||||
List<ItemStack> removedItems = container.removeAllItemStacks();
|
||||
|
||||
// Clear entire player inventory
|
||||
inv.clear();
|
||||
|
||||
// Drop all from player inventory
|
||||
List<ItemStack> allDropped = inv.dropAllItemStacks();
|
||||
```
|
||||
|
||||
## Sorting
|
||||
|
||||
Available `SortType` values: `NAME`, `TYPE`, `RARITY`
|
||||
|
||||
```java
|
||||
ItemContainer container = inv.getStorage();
|
||||
|
||||
// Sort items
|
||||
container.sortItems(SortType.NAME);
|
||||
|
||||
// Sort via Inventory (also saves sort preference)
|
||||
inv.sortStorage(SortType.NAME);
|
||||
inv.setSortType(SortType.RARITY); // Or TYPE
|
||||
```
|
||||
|
||||
## Container Events
|
||||
|
||||
```java
|
||||
// Register for container change events
|
||||
container.registerChangeEvent(event -> {
|
||||
ItemContainer changedContainer = event.container();
|
||||
Transaction transaction = event.transaction();
|
||||
|
||||
getLogger().at(Level.INFO).log("Container changed!");
|
||||
});
|
||||
|
||||
// With priority
|
||||
container.registerChangeEvent(EventPriority.EARLY, event -> {
|
||||
// Handle early
|
||||
});
|
||||
```
|
||||
|
||||
## Transaction System
|
||||
|
||||
All modification operations return Transaction objects:
|
||||
|
||||
```java
|
||||
// Transactions track success and changes
|
||||
ItemStackTransaction transaction = container.addItemStack(itemStack);
|
||||
|
||||
if (transaction.succeeded()) {
|
||||
ItemStack remainder = transaction.getRemainder();
|
||||
// ...
|
||||
}
|
||||
|
||||
// Slot transactions include slot info
|
||||
ItemStackSlotTransaction slotTransaction = container.setItemStackForSlot(
|
||||
(short) 0,
|
||||
itemStack
|
||||
);
|
||||
|
||||
if (slotTransaction.succeeded()) {
|
||||
short slot = slotTransaction.getSlot();
|
||||
ItemStack before = slotTransaction.getSlotBefore();
|
||||
ItemStack after = slotTransaction.getSlotAfter();
|
||||
}
|
||||
```
|
||||
|
||||
## Operation Parameters
|
||||
|
||||
Most container operations support optional parameters:
|
||||
|
||||
```java
|
||||
// Default values
|
||||
DEFAULT_ADD_ALL_OR_NOTHING = false; // Partial adds allowed
|
||||
DEFAULT_REMOVE_ALL_OR_NOTHING = true; // Only full removals
|
||||
DEFAULT_FULL_STACKS = false; // Can split stacks
|
||||
DEFAULT_EXACT_AMOUNT = true; // Exact quantities only
|
||||
DEFAULT_FILTER = true; // Apply slot filters
|
||||
|
||||
// Add with parameters
|
||||
container.addItemStack(itemStack, allOrNothing, fullStacks, filter);
|
||||
|
||||
// allOrNothing: if true, fails entirely if not all items fit
|
||||
// fullStacks: if true, only fills empty slots (no stacking)
|
||||
// filter: if true, respects slot filters
|
||||
```
|
||||
|
||||
## Material and Resource Removal
|
||||
|
||||
Containers support removing items by material type or resource type (used for crafting):
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**MaterialQuantity constructor:** `MaterialQuantity(itemId, resourceTypeId, tag, quantity, metadata)`
|
||||
|
||||
At least one of `itemId`, `resourceTypeId`, or `tag` must be non-null.
|
||||
{{< /callout >}}
|
||||
|
||||
```java
|
||||
// Remove by material using itemId
|
||||
MaterialQuantity materialByItem = new MaterialQuantity("iron_ingot", null, null, 5, null);
|
||||
if (container.canRemoveMaterial(materialByItem)) {
|
||||
MaterialTransaction transaction = container.removeMaterial(materialByItem);
|
||||
}
|
||||
|
||||
// Remove by material using resourceTypeId
|
||||
MaterialQuantity materialByResource = new MaterialQuantity(null, "iron", null, 5, null);
|
||||
if (container.canRemoveMaterial(materialByResource)) {
|
||||
MaterialTransaction transaction = container.removeMaterial(materialByResource);
|
||||
}
|
||||
|
||||
// Remove by resource type (simpler constructor)
|
||||
ResourceQuantity resource = new ResourceQuantity("wood", 10);
|
||||
if (container.canRemoveResource(resource)) {
|
||||
ResourceTransaction transaction = container.removeResource(resource);
|
||||
}
|
||||
|
||||
// Remove by tag index
|
||||
if (container.canRemoveTag(tagIndex, quantity)) {
|
||||
TagTransaction transaction = container.removeTag(tagIndex, quantity);
|
||||
}
|
||||
|
||||
// Bulk removal
|
||||
List<MaterialQuantity> materials = List.of(
|
||||
new MaterialQuantity("iron_ingot", null, null, 2, null),
|
||||
new MaterialQuantity(null, null, "Wood", 5, null) // Using tag
|
||||
);
|
||||
if (container.canRemoveMaterials(materials)) {
|
||||
container.removeMaterials(materials);
|
||||
}
|
||||
```
|
||||
|
||||
## Bulk Operations
|
||||
|
||||
Add or remove multiple items at once:
|
||||
|
||||
```java
|
||||
// Add multiple items
|
||||
List<ItemStack> items = List.of(
|
||||
new ItemStack("iron_ore", 10),
|
||||
new ItemStack("gold_ore", 5)
|
||||
);
|
||||
|
||||
if (container.canAddItemStacks(items)) {
|
||||
ListTransaction<ItemStackTransaction> transaction = container.addItemStacks(items);
|
||||
}
|
||||
|
||||
// Remove multiple items
|
||||
if (container.canRemoveItemStacks(items)) {
|
||||
container.removeItemStacks(items);
|
||||
}
|
||||
|
||||
// Add items in order (preserves slot positions)
|
||||
container.addItemStacksOrdered(items);
|
||||
container.addItemStacksOrdered((short) 5, items); // Starting at slot 5
|
||||
```
|
||||
|
||||
## Advanced Move Operations
|
||||
|
||||
```java
|
||||
// Move all items to another container
|
||||
ListTransaction<MoveTransaction<ItemStackTransaction>> result =
|
||||
storage.moveAllItemStacksTo(hotbar, backpack);
|
||||
|
||||
// Move all items matching a condition
|
||||
storage.moveAllItemStacksTo(
|
||||
item -> item.getItemId().contains("ore"),
|
||||
hotbar
|
||||
);
|
||||
|
||||
// Quick stack: only moves items that can stack with existing items
|
||||
storage.quickStackTo(hotbar);
|
||||
|
||||
// Combine small stacks into one slot
|
||||
container.combineItemStacksIntoSlot(targetContainer, (short) 0);
|
||||
|
||||
// Swap items between containers
|
||||
storage.swapItems(
|
||||
(short) 0, // source position
|
||||
hotbar, // target container
|
||||
(short) 0, // destination position
|
||||
(short) 5 // number of slots to swap
|
||||
);
|
||||
```
|
||||
|
||||
## Replace Operations
|
||||
|
||||
```java
|
||||
// Replace item in slot if it matches expected
|
||||
ItemStackSlotTransaction transaction = container.replaceItemStackInSlot(
|
||||
(short) 0,
|
||||
expectedItem, // must match current item to proceed
|
||||
newItem
|
||||
);
|
||||
|
||||
// Replace all items using a function
|
||||
container.replaceAll((slot, existing) -> {
|
||||
if (existing.getItemId().equals("old_item")) {
|
||||
return new ItemStack("new_item", existing.getQuantity());
|
||||
}
|
||||
return existing;
|
||||
});
|
||||
```
|
||||
|
||||
## Slot Filters
|
||||
|
||||
Control which items can go in which slots:
|
||||
|
||||
```java
|
||||
// Set global filter for the container
|
||||
container.setGlobalFilter(FilterType.WHITELIST);
|
||||
|
||||
// Set filter for specific slot
|
||||
container.setSlotFilter(
|
||||
FilterActionType.ADD, // Filter on add operations
|
||||
(short) 0, // Slot
|
||||
slotFilter // Filter implementation
|
||||
);
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Container Tips:**
|
||||
- Slot indices are `short`, not `int` - cast appropriately
|
||||
- Always check `ItemStack.isEmpty(stack)` - handles both null and empty
|
||||
- Use `getQuantity()` not `getCount()`
|
||||
- Check transaction success with `succeeded()`
|
||||
- Use combined containers for cross-section operations
|
||||
- Player inventory changes trigger `LivingEntityInventoryChangeEvent`
|
||||
{{< /callout >}}
|
||||
|
||||
```java
|
||||
// Safe pattern for working with containers
|
||||
public void safeAddItem(ItemContainer container, ItemStack item) {
|
||||
if (ItemStack.isEmpty(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!container.canAddItemStack(item)) {
|
||||
// Handle full container
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStackTransaction transaction = container.addItemStack(item);
|
||||
if (!transaction.succeeded()) {
|
||||
// Handle failure
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ItemContainer API Reference
|
||||
|
||||
### Core Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `getCapacity()` | `short` | Total number of slots |
|
||||
| `getItemStack(short)` | `ItemStack?` | Get item at slot |
|
||||
| `isEmpty()` | `boolean` | True if no items |
|
||||
| `clone()` | `ItemContainer` | Clone the container |
|
||||
| `clear()` | `ClearTransaction` | Remove all items |
|
||||
|
||||
### Add Operations
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `canAddItemStack(ItemStack)` | `boolean` | Check if can add |
|
||||
| `canAddItemStack(ItemStack, fullStacks, filter)` | `boolean` | Check with options |
|
||||
| `addItemStack(ItemStack)` | `ItemStackTransaction` | Add to first available |
|
||||
| `addItemStack(ItemStack, allOrNothing, fullStacks, filter)` | `ItemStackTransaction` | Add with options |
|
||||
| `canAddItemStackToSlot(short, ItemStack, allOrNothing, filter)` | `boolean` | Check if can add to slot |
|
||||
| `addItemStackToSlot(short, ItemStack)` | `ItemStackSlotTransaction` | Add to specific slot |
|
||||
| `addItemStackToSlot(short, ItemStack, allOrNothing, filter)` | `ItemStackSlotTransaction` | Add to slot with options |
|
||||
| `canAddItemStacks(List<ItemStack>)` | `boolean` | Check if can add multiple |
|
||||
| `addItemStacks(List<ItemStack>)` | `ListTransaction` | Add multiple items |
|
||||
| `addItemStacksOrdered(List<ItemStack>)` | `ListTransaction` | Add in order |
|
||||
| `addItemStacksOrdered(short offset, List<ItemStack>)` | `ListTransaction` | Add in order from offset |
|
||||
|
||||
### Set Operations
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `setItemStackForSlot(short, ItemStack)` | `ItemStackSlotTransaction` | Set item at slot |
|
||||
| `setItemStackForSlot(short, ItemStack, filter)` | `ItemStackSlotTransaction` | Set with filter option |
|
||||
| `replaceItemStackInSlot(short, ItemStack expected, ItemStack new)` | `ItemStackSlotTransaction` | Replace if matches |
|
||||
| `replaceAll(SlotReplacementFunction)` | `ListTransaction` | Replace all items |
|
||||
|
||||
### Remove Operations
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `removeItemStackFromSlot(short)` | `SlotTransaction` | Remove entire slot |
|
||||
| `removeItemStackFromSlot(short, filter)` | `SlotTransaction` | Remove with filter |
|
||||
| `removeItemStackFromSlot(short, quantity)` | `ItemStackSlotTransaction` | Remove quantity |
|
||||
| `removeItemStackFromSlot(short, ItemStack, quantity)` | `ItemStackSlotTransaction` | Remove matching item |
|
||||
| `canRemoveItemStack(ItemStack)` | `boolean` | Check if can remove |
|
||||
| `removeItemStack(ItemStack)` | `ItemStackTransaction` | Remove item type |
|
||||
| `canRemoveItemStacks(List<ItemStack>)` | `boolean` | Check if can remove multiple |
|
||||
| `removeItemStacks(List<ItemStack>)` | `ListTransaction` | Remove multiple items |
|
||||
| `removeAllItemStacks()` | `List<ItemStack>` | Remove and return all |
|
||||
| `dropAllItemStacks()` | `List<ItemStack>` | Drop all (respects cantDrop) |
|
||||
| `dropAllItemStacks(filter)` | `List<ItemStack>` | Drop with filter option |
|
||||
|
||||
### Material/Resource/Tag Removal
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `canRemoveMaterial(MaterialQuantity)` | `boolean` | Check material removal |
|
||||
| `removeMaterial(MaterialQuantity)` | `MaterialTransaction` | Remove by material |
|
||||
| `removeMaterialFromSlot(short, MaterialQuantity)` | `MaterialSlotTransaction` | Remove material from slot |
|
||||
| `canRemoveMaterials(List<MaterialQuantity>)` | `boolean` | Check multiple materials |
|
||||
| `removeMaterials(List<MaterialQuantity>)` | `ListTransaction` | Remove multiple materials |
|
||||
| `canRemoveResource(ResourceQuantity)` | `boolean` | Check resource removal |
|
||||
| `removeResource(ResourceQuantity)` | `ResourceTransaction` | Remove by resource |
|
||||
| `removeResourceFromSlot(short, ResourceQuantity)` | `ResourceSlotTransaction` | Remove resource from slot |
|
||||
| `canRemoveResources(List<ResourceQuantity>)` | `boolean` | Check multiple resources |
|
||||
| `removeResources(List<ResourceQuantity>)` | `ListTransaction` | Remove multiple resources |
|
||||
| `canRemoveTag(tagIndex, quantity)` | `boolean` | Check tag removal |
|
||||
| `removeTag(tagIndex, quantity)` | `TagTransaction` | Remove by tag |
|
||||
| `removeTagFromSlot(short, tagIndex, quantity)` | `TagSlotTransaction` | Remove tag from slot |
|
||||
|
||||
### Move Operations
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `moveItemStackFromSlot(short, ItemContainer)` | `MoveTransaction` | Move slot to container |
|
||||
| `moveItemStackFromSlot(short, quantity, ItemContainer)` | `MoveTransaction` | Move quantity |
|
||||
| `moveItemStackFromSlot(short, ItemContainer...)` | `ListTransaction` | Move to multiple containers |
|
||||
| `moveItemStackFromSlotToSlot(short, quantity, ItemContainer, short)` | `MoveTransaction` | Move to specific slot |
|
||||
| `moveAllItemStacksTo(ItemContainer...)` | `ListTransaction` | Move all items |
|
||||
| `moveAllItemStacksTo(Predicate, ItemContainer...)` | `ListTransaction` | Move matching items |
|
||||
| `quickStackTo(ItemContainer...)` | `ListTransaction` | Move stackable items only |
|
||||
| `combineItemStacksIntoSlot(ItemContainer, short)` | `ListTransaction` | Combine stacks into slot |
|
||||
| `swapItems(short srcPos, ItemContainer, short destPos, short length)` | `ListTransaction` | Swap item ranges |
|
||||
|
||||
### Utility Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `forEach(ShortObjectConsumer)` | `void` | Iterate non-empty slots |
|
||||
| `forEachWithMeta(consumer, meta)` | `void` | Iterate with metadata |
|
||||
| `countItemStacks(Predicate)` | `int` | Count matching items (total quantity) |
|
||||
| `containsItemStacksStackableWith(ItemStack)` | `boolean` | Check for stackable items |
|
||||
| `sortItems(SortType)` | `ListTransaction` | Sort container |
|
||||
| `registerChangeEvent(Consumer)` | `EventRegistration` | Listen for changes |
|
||||
| `registerChangeEvent(EventPriority, Consumer)` | `EventRegistration` | Listen with priority |
|
||||
| `setGlobalFilter(FilterType)` | `void` | Set container filter |
|
||||
| `setSlotFilter(FilterActionType, short, SlotFilter)` | `void` | Set slot filter |
|
||||
| `containsContainer(ItemContainer)` | `boolean` | Check if contains container |
|
||||
|
||||
### Static Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `copy(from, to, remainder)` | `T` | Copy items between containers |
|
||||
| `ensureContainerCapacity(container, capacity, supplier, remainder)` | `T` | Ensure container has capacity |
|
||||
| `getNewContainer(capacity, supplier)` | `ItemContainer` | Create or get empty |
|
||||
| `getMatchingResourceType(Item, resourceId)` | `ItemResourceType?` | Find resource type for item |
|
||||
| `validateQuantity(int)` | `void` | Throws if < 0 |
|
||||
| `validateSlotIndex(short, capacity)` | `void` | Throws if out of bounds |
|
||||
|
||||
### Static Constants
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `CODEC` | `CodecMapCodec<ItemContainer>` | Serialization codec |
|
||||
| `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 |
|
||||
|
||||
### Nested Classes
|
||||
|
||||
| Class | Description |
|
||||
|-------|-------------|
|
||||
| `ItemContainerChangeEvent` | Event record with `container()` and `transaction()` |
|
||||
|
||||
## Inventory API Reference
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `getStorage()` | `ItemContainer` | Main storage section |
|
||||
| `getHotbar()` | `ItemContainer` | Hotbar section |
|
||||
| `getArmor()` | `ItemContainer` | Armor section |
|
||||
| `getUtility()` | `ItemContainer` | Utility section |
|
||||
| `getBackpack()` | `ItemContainer` | Backpack section |
|
||||
| `getSectionById(int)` | `ItemContainer?` | Get section by ID |
|
||||
| `getItemInHand()` | `ItemStack?` | Currently held item |
|
||||
| `getActiveHotbarSlot()` | `byte` | Active hotbar slot |
|
||||
| `setActiveHotbarSlot(byte)` | `void` | Set active hotbar |
|
||||
| `getCombinedHotbarFirst()` | `CombinedItemContainer` | Hotbar+Storage combined |
|
||||
| `moveItem(...)` | `void` | Move between sections |
|
||||
| `clear()` | `void` | Clear all sections |
|
||||
668
content/world/entities/inventory/containers.fr.md
Normal file
668
content/world/entities/inventory/containers.fr.md
Normal file
@@ -0,0 +1,668 @@
|
||||
---
|
||||
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<SlotTransaction> 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<ItemStack> droppedItems = container.dropAllItemStacks();
|
||||
|
||||
// Retirer tous les objets (retourne la liste)
|
||||
List<ItemStack> removedItems = container.removeAllItemStacks();
|
||||
|
||||
// Vider tout l'inventaire du joueur
|
||||
inv.clear();
|
||||
|
||||
// Lâcher tout de l'inventaire du joueur
|
||||
List<ItemStack> 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<MaterialQuantity> 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<ItemStack> items = List.of(
|
||||
new ItemStack("iron_ore", 10),
|
||||
new ItemStack("gold_ore", 5)
|
||||
);
|
||||
|
||||
if (container.canAddItemStacks(items)) {
|
||||
ListTransaction<ItemStackTransaction> 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<MoveTransaction<ItemStackTransaction>> 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<ItemStack>)` | `boolean` | Vérifier si peut ajouter plusieurs |
|
||||
| `addItemStacks(List<ItemStack>)` | `ListTransaction` | Ajouter plusieurs objets |
|
||||
| `addItemStacksOrdered(List<ItemStack>)` | `ListTransaction` | Ajouter dans l'ordre |
|
||||
| `addItemStacksOrdered(short offset, List<ItemStack>)` | `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<ItemStack>)` | `boolean` | Vérifier si peut retirer plusieurs |
|
||||
| `removeItemStacks(List<ItemStack>)` | `ListTransaction` | Retirer plusieurs objets |
|
||||
| `removeAllItemStacks()` | `List<ItemStack>` | Retirer et retourner tous |
|
||||
| `dropAllItemStacks()` | `List<ItemStack>` | Lâcher tous (respecte cantDrop) |
|
||||
| `dropAllItemStacks(filter)` | `List<ItemStack>` | 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<MaterialQuantity>)` | `boolean` | Vérifier plusieurs matériaux |
|
||||
| `removeMaterials(List<MaterialQuantity>)` | `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<ResourceQuantity>)` | `boolean` | Vérifier plusieurs ressources |
|
||||
| `removeResources(List<ResourceQuantity>)` | `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<ItemContainer>` | 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 |
|
||||
354
content/world/entities/inventory/itemstacks.en.md
Normal file
354
content/world/entities/inventory/itemstacks.en.md
Normal file
@@ -0,0 +1,354 @@
|
||||
---
|
||||
title: ItemStacks
|
||||
type: docs
|
||||
weight: 1
|
||||
---
|
||||
|
||||
ItemStack represents a stack of items in Hytale with quantity, durability, and metadata.
|
||||
|
||||
## Creating ItemStacks
|
||||
|
||||
ItemStacks are created using constructors with an item ID:
|
||||
|
||||
```java
|
||||
// Create by item ID
|
||||
ItemStack sword = new ItemStack("iron_sword");
|
||||
|
||||
// Create with quantity
|
||||
ItemStack materials = new ItemStack("wood_plank", 64);
|
||||
|
||||
// Create with quantity and metadata
|
||||
BsonDocument metadata = new BsonDocument();
|
||||
ItemStack customItem = new ItemStack("iron_sword", 1, metadata);
|
||||
|
||||
// Create with full parameters (durability)
|
||||
ItemStack damagedSword = new ItemStack("iron_sword", 1, 50.0, 100.0, null);
|
||||
// Parameters: itemId, quantity, durability, maxDurability, metadata
|
||||
```
|
||||
|
||||
## ItemStack Properties
|
||||
|
||||
```java
|
||||
ItemStack stack = new ItemStack("iron_sword", 1);
|
||||
|
||||
// Get the item ID
|
||||
String itemId = stack.getItemId(); // "iron_sword"
|
||||
|
||||
// Get the Item asset
|
||||
Item item = stack.getItem();
|
||||
|
||||
// Get quantity (NOT getCount!)
|
||||
int quantity = stack.getQuantity();
|
||||
|
||||
// Check if empty
|
||||
boolean empty = stack.isEmpty();
|
||||
|
||||
// Check validity
|
||||
boolean valid = stack.isValid();
|
||||
|
||||
// Durability
|
||||
double durability = stack.getDurability();
|
||||
double maxDurability = stack.getMaxDurability();
|
||||
boolean unbreakable = stack.isUnbreakable(); // true if maxDurability <= 0
|
||||
boolean broken = stack.isBroken(); // true if durability == 0
|
||||
```
|
||||
|
||||
## Modifying ItemStacks
|
||||
|
||||
ItemStack uses a `with*` pattern that returns NEW instances:
|
||||
|
||||
```java
|
||||
ItemStack stack = new ItemStack("iron_sword", 1);
|
||||
|
||||
// Change quantity - returns NEW ItemStack or null if quantity is 0
|
||||
ItemStack moreItems = stack.withQuantity(32);
|
||||
|
||||
// Change durability
|
||||
ItemStack damaged = stack.withDurability(50.0);
|
||||
|
||||
// Increase durability
|
||||
ItemStack repaired = stack.withIncreasedDurability(25.0);
|
||||
|
||||
// Restore full durability
|
||||
ItemStack fullyRepaired = stack.withRestoredDurability(100.0);
|
||||
|
||||
// Change max durability
|
||||
ItemStack stronger = stack.withMaxDurability(200.0);
|
||||
|
||||
// Change state (for items with states)
|
||||
ItemStack newState = stack.withState("activated");
|
||||
|
||||
// Add/modify metadata
|
||||
ItemStack withMeta = stack.withMetadata(metadataDocument);
|
||||
|
||||
// Add specific metadata value
|
||||
ItemStack tagged = stack.withMetadata("CustomKey", Codec.STRING, "CustomValue");
|
||||
```
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Important:** `withQuantity(0)` returns `null`, not an empty ItemStack. Always check for null when decreasing quantity!
|
||||
{{< /callout >}}
|
||||
|
||||
## The EMPTY Constant
|
||||
|
||||
Use `ItemStack.EMPTY` for empty stacks:
|
||||
|
||||
```java
|
||||
// Static empty instance (singleton)
|
||||
ItemStack empty = ItemStack.EMPTY;
|
||||
|
||||
// Check for empty
|
||||
if (stack.isEmpty()) {
|
||||
// Stack is empty
|
||||
}
|
||||
|
||||
// Static helper method
|
||||
if (ItemStack.isEmpty(stack)) {
|
||||
// Handles null and empty stacks
|
||||
}
|
||||
```
|
||||
|
||||
## Comparing ItemStacks
|
||||
|
||||
```java
|
||||
ItemStack a = new ItemStack("iron_sword", 1);
|
||||
ItemStack b = new ItemStack("iron_sword", 5);
|
||||
ItemStack c = new ItemStack("diamond_sword", 1);
|
||||
|
||||
// Check if stackable (same itemId, durability, maxDurability, AND metadata)
|
||||
// Note: Different quantities can stack, but durability values must match exactly
|
||||
boolean canStack = a.isStackableWith(b);
|
||||
|
||||
// Check equivalent type (same itemId and metadata, ignores durability values)
|
||||
boolean sameType = a.isEquivalentType(b);
|
||||
|
||||
// Check same item type only (just itemId comparison)
|
||||
boolean sameItem = ItemStack.isSameItemType(a, c); // false
|
||||
|
||||
// Static helpers (handle nulls safely)
|
||||
ItemStack.isStackableWith(a, b);
|
||||
ItemStack.isEquivalentType(a, b);
|
||||
```
|
||||
|
||||
## Working with Metadata
|
||||
|
||||
ItemStack supports BSON metadata for custom data:
|
||||
|
||||
```java
|
||||
// Create metadata codec
|
||||
KeyedCodec<String> OWNER_KEY = new KeyedCodec<>("Owner", Codec.STRING);
|
||||
|
||||
// Add metadata
|
||||
ItemStack withOwner = stack.withMetadata(OWNER_KEY, "PlayerName");
|
||||
|
||||
// Read metadata
|
||||
String owner = stack.getFromMetadataOrNull(OWNER_KEY);
|
||||
|
||||
// Read with key and codec
|
||||
Integer level = stack.getFromMetadataOrNull("Level", Codec.INTEGER);
|
||||
|
||||
// Read with default from BuilderCodec
|
||||
MyData data = stack.getFromMetadataOrDefault("Data", MyData.CODEC);
|
||||
```
|
||||
|
||||
## Block Items
|
||||
|
||||
Check if an item can be placed as a block:
|
||||
|
||||
```java
|
||||
ItemStack stack = new ItemStack("stone", 1);
|
||||
|
||||
// Get associated block key (null if not a block item)
|
||||
String blockKey = stack.getBlockKey();
|
||||
if (blockKey != null) {
|
||||
// This item can be placed as a block
|
||||
}
|
||||
|
||||
// Check via Item asset
|
||||
Item item = stack.getItem();
|
||||
if (item.hasBlockType()) {
|
||||
String blockId = item.getBlockId();
|
||||
}
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Consuming Items
|
||||
|
||||
```java
|
||||
public ItemStack consumeOne(ItemStack stack) {
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int newQuantity = stack.getQuantity() - 1;
|
||||
|
||||
// withQuantity returns null if quantity is 0
|
||||
return stack.withQuantity(newQuantity);
|
||||
}
|
||||
|
||||
// Usage with container
|
||||
public void useItem(ItemContainer container, short slot) {
|
||||
ItemStack current = container.getItemStack(slot);
|
||||
ItemStack remaining = consumeOne(current);
|
||||
|
||||
// remaining may be null if stack was depleted
|
||||
container.setItemStackForSlot(slot, remaining);
|
||||
}
|
||||
```
|
||||
|
||||
### Checking Item Type
|
||||
|
||||
```java
|
||||
public boolean isHoldingSword(ItemStack hand) {
|
||||
if (hand == null || hand.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check item type by ID
|
||||
return hand.getItemId().contains("sword");
|
||||
|
||||
// Or check via Item asset
|
||||
// return hand.getItem().getCategory().equals("weapon");
|
||||
}
|
||||
```
|
||||
|
||||
### Splitting Stacks
|
||||
|
||||
```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 };
|
||||
}
|
||||
|
||||
// Create two stacks
|
||||
ItemStack remaining = stack.withQuantity(currentQuantity - splitAmount);
|
||||
ItemStack split = stack.withQuantity(splitAmount);
|
||||
|
||||
return new ItemStack[] { remaining, split };
|
||||
}
|
||||
```
|
||||
|
||||
### Merging Stacks
|
||||
|
||||
```java
|
||||
public ItemStack[] mergeStacks(ItemStack target, ItemStack source) {
|
||||
if (!target.isStackableWith(source)) {
|
||||
return new ItemStack[] { target, source }; // Can't merge
|
||||
}
|
||||
|
||||
int maxStack = target.getItem().getMaxStack();
|
||||
int totalQuantity = target.getQuantity() + source.getQuantity();
|
||||
|
||||
if (totalQuantity <= maxStack) {
|
||||
// Full merge
|
||||
return new ItemStack[] {
|
||||
target.withQuantity(totalQuantity),
|
||||
null
|
||||
};
|
||||
}
|
||||
|
||||
// Partial merge
|
||||
return new ItemStack[] {
|
||||
target.withQuantity(maxStack),
|
||||
source.withQuantity(totalQuantity - maxStack)
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Remember:**
|
||||
- Use `getQuantity()` not `getCount()` - Hytale uses "quantity"
|
||||
- `withQuantity(0)` returns `null` - check for this!
|
||||
- Use `ItemStack.isEmpty(stack)` to handle both null and empty
|
||||
- ItemStacks are mostly immutable - `with*` methods return new instances
|
||||
- Use `isStackableWith()` before attempting to merge stacks
|
||||
- `ResourceType.Id` must not be null when creating items via codecs
|
||||
{{< /callout >}}
|
||||
|
||||
```java
|
||||
// Good: Handle null from withQuantity
|
||||
ItemStack result = stack.withQuantity(newQuantity);
|
||||
if (result == null) {
|
||||
// Stack depleted, handle appropriately
|
||||
}
|
||||
|
||||
// Good: Safe empty check
|
||||
if (ItemStack.isEmpty(stack)) {
|
||||
// Handles both null and empty ItemStack.EMPTY
|
||||
}
|
||||
|
||||
// Bad: Ignoring the returned value
|
||||
stack.withQuantity(10); // Returns new stack, original unchanged!
|
||||
```
|
||||
|
||||
## ItemStack API Reference
|
||||
|
||||
### Instance Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `getItemId()` | `String` | The item type identifier |
|
||||
| `getItem()` | `Item` | The Item asset (returns `Item.UNKNOWN` if not found) |
|
||||
| `getQuantity()` | `int` | Stack size |
|
||||
| `getDurability()` | `double` | Current durability |
|
||||
| `getMaxDurability()` | `double` | Maximum durability |
|
||||
| `isEmpty()` | `boolean` | True if itemId equals "Empty" |
|
||||
| `isUnbreakable()` | `boolean` | True if maxDurability <= 0 |
|
||||
| `isBroken()` | `boolean` | True if NOT unbreakable AND durability == 0 |
|
||||
| `isValid()` | `boolean` | True if empty OR item asset exists |
|
||||
| `isStackableWith(ItemStack)` | `boolean` | Same itemId, durability, maxDurability, metadata |
|
||||
| `isEquivalentType(ItemStack)` | `boolean` | Same itemId and metadata (ignores durability) |
|
||||
| `getBlockKey()` | `String?` | Block ID if item is placeable, null otherwise |
|
||||
| `getOverrideDroppedItemAnimation()` | `boolean` | Animation override flag |
|
||||
| `getMetadata()` | `BsonDocument?` | **Deprecated** - Returns cloned metadata |
|
||||
| `getFromMetadataOrNull(KeyedCodec)` | `T?` | Get typed metadata value |
|
||||
| `getFromMetadataOrNull(String, Codec)` | `T?` | Get typed metadata by key |
|
||||
| `getFromMetadataOrDefault(String, BuilderCodec)` | `T` | Get metadata with default |
|
||||
|
||||
### Modifier Methods (return new ItemStack)
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `withQuantity(int)` | `ItemStack?` | **Returns null if quantity is 0** |
|
||||
| `withDurability(double)` | `ItemStack` | Clamped to [0, maxDurability] |
|
||||
| `withMaxDurability(double)` | `ItemStack` | Also clamps current durability |
|
||||
| `withIncreasedDurability(double)` | `ItemStack` | Add to current durability |
|
||||
| `withRestoredDurability(double)` | `ItemStack` | Set both durability and max |
|
||||
| `withState(String)` | `ItemStack` | Change item state |
|
||||
| `withMetadata(BsonDocument)` | `ItemStack` | Replace all metadata |
|
||||
| `withMetadata(KeyedCodec, T)` | `ItemStack` | Set typed metadata |
|
||||
| `withMetadata(String, Codec, T)` | `ItemStack` | Set metadata by key |
|
||||
| `withMetadata(String, BsonValue)` | `ItemStack` | Set raw BSON value |
|
||||
| `setOverrideDroppedItemAnimation(boolean)` | `void` | **Mutates in place** |
|
||||
|
||||
### Static Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `EMPTY` | `ItemStack` | Singleton empty stack (itemId = "Empty") |
|
||||
| `EMPTY_ARRAY` | `ItemStack[]` | Empty array constant |
|
||||
| `CODEC` | `BuilderCodec<ItemStack>` | Serialization codec |
|
||||
|
||||
### Static Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `isEmpty(ItemStack)` | `boolean` | Null-safe empty check |
|
||||
| `isStackableWith(ItemStack, ItemStack)` | `boolean` | Null-safe stackable check |
|
||||
| `isEquivalentType(ItemStack, ItemStack)` | `boolean` | Null-safe type check |
|
||||
| `isSameItemType(ItemStack, ItemStack)` | `boolean` | Compare itemId only |
|
||||
| `fromPacket(ItemQuantity)` | `ItemStack?` | Create from network packet |
|
||||
|
||||
### Nested Classes
|
||||
|
||||
| Class | Description |
|
||||
|-------|-------------|
|
||||
| `ItemStack.Metadata` | Contains `BLOCK_STATE` constant for block state metadata key |
|
||||
354
content/world/entities/inventory/itemstacks.fr.md
Normal file
354
content/world/entities/inventory/itemstacks.fr.md
Normal file
@@ -0,0 +1,354 @@
|
||||
---
|
||||
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 |
|
||||
430
content/world/entities/inventory/transactions.en.md
Normal file
430
content/world/entities/inventory/transactions.en.md
Normal file
@@ -0,0 +1,430 @@
|
||||
---
|
||||
title: Transactions
|
||||
type: docs
|
||||
weight: 3
|
||||
---
|
||||
|
||||
Transactions track the results of inventory operations in Hytale. Every modification to an `ItemContainer` returns a Transaction object that describes what happened.
|
||||
|
||||
## Transaction Interface
|
||||
|
||||
All transactions implement the base `Transaction` interface:
|
||||
|
||||
```java
|
||||
public interface Transaction {
|
||||
// Did the operation succeed?
|
||||
boolean succeeded();
|
||||
|
||||
// Was a specific slot modified?
|
||||
boolean wasSlotModified(short slot);
|
||||
}
|
||||
```
|
||||
|
||||
## Transaction Types
|
||||
|
||||
### SlotTransaction
|
||||
|
||||
Tracks changes to a single slot:
|
||||
|
||||
```java
|
||||
SlotTransaction transaction = container.removeItemStackFromSlot((short) 0);
|
||||
|
||||
if (transaction.succeeded()) {
|
||||
// What was in the slot before
|
||||
ItemStack before = transaction.getSlotBefore();
|
||||
|
||||
// What is in the slot now
|
||||
ItemStack after = transaction.getSlotAfter();
|
||||
|
||||
// The item that was removed/output
|
||||
ItemStack output = transaction.getOutput();
|
||||
|
||||
// Which slot was affected
|
||||
short slot = transaction.getSlot();
|
||||
|
||||
// What type of action (ADD, REMOVE, REPLACE)
|
||||
ActionType action = transaction.getAction();
|
||||
}
|
||||
```
|
||||
|
||||
### ItemStackSlotTransaction
|
||||
|
||||
Extended slot transaction with additional details:
|
||||
|
||||
```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();
|
||||
|
||||
// Check options used
|
||||
boolean wasFiltered = transaction.isFilter();
|
||||
boolean wasAllOrNothing = transaction.isAllOrNothing();
|
||||
}
|
||||
```
|
||||
|
||||
### ItemStackTransaction
|
||||
|
||||
Tracks operations that may affect multiple slots:
|
||||
|
||||
```java
|
||||
ItemStack toAdd = new ItemStack("stone", 128);
|
||||
ItemStackTransaction transaction = container.addItemStack(toAdd);
|
||||
|
||||
if (transaction.succeeded()) {
|
||||
// Items that couldn't fit (null if all fit)
|
||||
ItemStack remainder = transaction.getRemainder();
|
||||
|
||||
// Original item we tried to add
|
||||
ItemStack query = transaction.getQuery();
|
||||
|
||||
// List of all slot transactions that occurred
|
||||
List<ItemStackSlotTransaction> slotTransactions = transaction.getSlotTransactions();
|
||||
|
||||
for (ItemStackSlotTransaction slotTx : slotTransactions) {
|
||||
getLogger().at(Level.INFO).log("Modified slot " + slotTx.getSlot());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### MoveTransaction
|
||||
|
||||
Tracks moving items between containers:
|
||||
|
||||
```java
|
||||
MoveTransaction<SlotTransaction> transaction = storage.moveItemStackFromSlotToSlot(
|
||||
(short) 0,
|
||||
32,
|
||||
hotbar,
|
||||
(short) 0
|
||||
);
|
||||
|
||||
if (transaction.succeeded()) {
|
||||
// Transaction for removing from source
|
||||
SlotTransaction removeTransaction = transaction.getRemoveTransaction();
|
||||
|
||||
// Transaction for adding to destination
|
||||
SlotTransaction addTransaction = transaction.getAddTransaction();
|
||||
|
||||
// The destination container
|
||||
ItemContainer destination = transaction.getOtherContainer();
|
||||
|
||||
// Direction of the move
|
||||
MoveType moveType = transaction.getMoveType();
|
||||
}
|
||||
```
|
||||
|
||||
### ListTransaction
|
||||
|
||||
Wraps multiple 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
|
||||
|
||||
Operations are categorized by action type:
|
||||
|
||||
```java
|
||||
public enum ActionType {
|
||||
SET, // Items set (add=true, remove=false, destroy=true)
|
||||
ADD, // Items added to slot (add=true, remove=false, destroy=false)
|
||||
REMOVE, // Items removed from slot (add=false, remove=true, destroy=false)
|
||||
REPLACE // Slot contents replaced (add=true, remove=true, destroy=false)
|
||||
}
|
||||
|
||||
// Check action characteristics
|
||||
if (action.isAdd()) { /* operation adds items */ }
|
||||
if (action.isRemove()) { /* operation removes items */ }
|
||||
if (action.isDestroy()) { /* operation destroys slot contents */ }
|
||||
```
|
||||
|
||||
## MoveType
|
||||
|
||||
Direction of move operations:
|
||||
|
||||
```java
|
||||
public enum MoveType {
|
||||
MOVE_TO_SELF, // Items being moved TO this container
|
||||
MOVE_FROM_SELF // Items being moved FROM this container
|
||||
}
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Check Before Modify
|
||||
|
||||
```java
|
||||
// Safe pattern: verify first, then execute
|
||||
public boolean safeTransfer(ItemContainer from, ItemContainer to, String itemId, int amount) {
|
||||
ItemStack toRemove = new ItemStack(itemId, amount);
|
||||
|
||||
// Check both operations can succeed
|
||||
if (!from.canRemoveItemStack(toRemove)) {
|
||||
return false; // Not enough items
|
||||
}
|
||||
|
||||
if (!to.canAddItemStack(toRemove)) {
|
||||
return false; // No space
|
||||
}
|
||||
|
||||
// Execute removal
|
||||
ItemStackTransaction removeResult = from.removeItemStack(toRemove);
|
||||
if (!removeResult.succeeded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Execute addition
|
||||
ItemStack removed = removeResult.getQuery();
|
||||
ItemStackTransaction addResult = to.addItemStack(removed);
|
||||
|
||||
// Handle any remainder
|
||||
ItemStack remainder = addResult.getRemainder();
|
||||
if (!ItemStack.isEmpty(remainder)) {
|
||||
// Put remainder back
|
||||
from.addItemStack(remainder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
### Handling Remainders
|
||||
|
||||
```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("Inventory full!"));
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack remainder = result.getRemainder();
|
||||
if (!ItemStack.isEmpty(remainder)) {
|
||||
player.sendMessage(Message.raw(
|
||||
"Only received " + (quantity - remainder.getQuantity()) + " items, " +
|
||||
"inventory full!"
|
||||
));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Atomic Operations
|
||||
|
||||
```java
|
||||
// allOrNothing=true ensures partial operations don't happen
|
||||
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);
|
||||
|
||||
// Check both operations can succeed fully
|
||||
if (!storage.canRemoveItemStack(currency)) {
|
||||
player.sendMessage(Message.raw("Not enough gold!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!storage.canAddItemStack(item)) {
|
||||
player.sendMessage(Message.raw("Inventory full!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove currency with allOrNothing=true
|
||||
ItemStackTransaction removeResult = storage.removeItemStack(currency, true, true);
|
||||
if (!removeResult.succeeded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add item
|
||||
ItemStackTransaction addResult = storage.addItemStack(item, true, false, true);
|
||||
if (!addResult.succeeded()) {
|
||||
// Rollback: return the currency
|
||||
storage.addItemStack(currency);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
### Tracking Changes
|
||||
|
||||
```java
|
||||
// Use wasSlotModified to check specific slots
|
||||
public void onContainerChange(ItemContainer.ItemContainerChangeEvent event) {
|
||||
Transaction transaction = event.transaction();
|
||||
|
||||
// Check if hotbar slot 0 was affected
|
||||
if (transaction.wasSlotModified((short) 0)) {
|
||||
getLogger().at(Level.INFO).log("First slot was modified!");
|
||||
}
|
||||
|
||||
// Check all hotbar slots
|
||||
for (short i = 0; i < 9; i++) {
|
||||
if (transaction.wasSlotModified(i)) {
|
||||
getLogger().at(Level.INFO).log("Hotbar slot " + i + " modified");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Transaction Options
|
||||
|
||||
Many operations accept optional parameters:
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `allOrNothing` | If true, operation fails if not all items can be processed | `false` |
|
||||
| `fullStacks` | If true, only add to empty slots (not partial stacks) | `false` |
|
||||
| `exactAmount` | If true, must remove exact quantity requested | `true` |
|
||||
| `filter` | If true, respect slot filters | `true` |
|
||||
|
||||
```java
|
||||
// Default behavior
|
||||
container.addItemStack(item);
|
||||
|
||||
// With options
|
||||
container.addItemStack(item, true, false, true); // allOrNothing, fullStacks, filter
|
||||
container.removeItemStack(item, true, true); // allOrNothing, filter
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Transaction Tips:**
|
||||
- Always check `succeeded()` before accessing results
|
||||
- Handle remainders when adding items
|
||||
- Use `canAddItemStack()`/`canRemoveItemStack()` for pre-validation
|
||||
- Use `allOrNothing=true` for critical operations
|
||||
- Check `wasSlotModified()` to track specific slot changes
|
||||
{{< /callout >}}
|
||||
|
||||
```java
|
||||
// Good: Check success and handle remainder
|
||||
ItemStackTransaction tx = container.addItemStack(item);
|
||||
if (tx.succeeded()) {
|
||||
ItemStack remainder = tx.getRemainder();
|
||||
if (!ItemStack.isEmpty(remainder)) {
|
||||
// Handle leftover items
|
||||
}
|
||||
}
|
||||
|
||||
// Bad: Assume success
|
||||
container.addItemStack(item); // Might fail silently!
|
||||
```
|
||||
|
||||
## Transaction API Reference
|
||||
|
||||
### Transaction Interface
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `succeeded()` | `boolean` | True if operation succeeded |
|
||||
| `wasSlotModified(short)` | `boolean` | True if specific slot was modified |
|
||||
|
||||
### SlotTransaction
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `getSlot()` | `short` | The affected slot index |
|
||||
| `getAction()` | `ActionType` | Type of action performed |
|
||||
| `getSlotBefore()` | `ItemStack?` | Contents before operation |
|
||||
| `getSlotAfter()` | `ItemStack?` | Contents after operation |
|
||||
| `getOutput()` | `ItemStack?` | Items removed/output |
|
||||
| `isAllOrNothing()` | `boolean` | allOrNothing parameter used |
|
||||
| `isExactAmount()` | `boolean` | exactAmount parameter used |
|
||||
| `isFilter()` | `boolean` | filter parameter used |
|
||||
|
||||
| Static | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `FAILED_ADD` | `SlotTransaction` | Pre-built failed add transaction |
|
||||
|
||||
### ItemStackSlotTransaction (extends SlotTransaction)
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `isAddToExistingSlot()` | `boolean` | True if added to existing stack |
|
||||
| `getQuery()` | `ItemStack?` | Original item requested |
|
||||
| `getRemainder()` | `ItemStack?` | Items that couldn't fit |
|
||||
|
||||
### ItemStackTransaction
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `getAction()` | `ActionType?` | Type of action performed |
|
||||
| `getQuery()` | `ItemStack?` | Original item requested |
|
||||
| `getRemainder()` | `ItemStack?` | Items that couldn't fit |
|
||||
| `isAllOrNothing()` | `boolean` | allOrNothing parameter used |
|
||||
| `isFilter()` | `boolean` | filter parameter used |
|
||||
| `getSlotTransactions()` | `List<ItemStackSlotTransaction>` | All slot transactions |
|
||||
|
||||
| Static | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `FAILED_ADD` | `ItemStackTransaction` | Pre-built failed add transaction |
|
||||
|
||||
### MoveTransaction<T extends Transaction>
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `getRemoveTransaction()` | `SlotTransaction` | Transaction for removal |
|
||||
| `getMoveType()` | `MoveType` | Direction of move |
|
||||
| `getOtherContainer()` | `ItemContainer` | The other container involved |
|
||||
| `getAddTransaction()` | `T` | Transaction for addition |
|
||||
| `toInverted(ItemContainer)` | `MoveTransaction<T>` | Create inverted view for other container |
|
||||
|
||||
### ListTransaction<T extends Transaction>
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `getList()` | `List<T>` | All transactions in list |
|
||||
| `size()` | `int` | Number of transactions |
|
||||
|
||||
| Static | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `EMPTY_SUCCESSFUL_TRANSACTION` | `ListTransaction<?>` | Pre-built empty success |
|
||||
| `EMPTY_FAILED_TRANSACTION` | `ListTransaction<?>` | Pre-built empty failure |
|
||||
| `getEmptyTransaction(boolean)` | `ListTransaction<T>` | Get empty success/failure |
|
||||
|
||||
### ActionType Enum
|
||||
|
||||
| Value | isAdd | isRemove | isDestroy | Description |
|
||||
|-------|-------|----------|-----------|-------------|
|
||||
| `SET` | true | false | true | Set slot contents |
|
||||
| `ADD` | true | false | false | Add items to slot |
|
||||
| `REMOVE` | false | true | false | Remove items from slot |
|
||||
| `REPLACE` | true | true | false | Replace slot contents |
|
||||
|
||||
### MoveType Enum
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `MOVE_TO_SELF` | Items moving to this container |
|
||||
| `MOVE_FROM_SELF` | Items moving from this container |
|
||||
430
content/world/entities/inventory/transactions.fr.md
Normal file
430
content/world/entities/inventory/transactions.fr.md
Normal file
@@ -0,0 +1,430 @@
|
||||
---
|
||||
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 |
|
||||
Reference in New Issue
Block a user