Files
Documentation/content/world/entities/inventory/itemstacks.en.md
2026-01-20 20:33:59 +01:00

10 KiB

title, type, weight
title type weight
ItemStacks docs 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:

// 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

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:

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:

// 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

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:

// 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:

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

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

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

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

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 >}}
// 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