Skip to main content

Overview

The InventoryManager handles inventory operations, timing, and state tracking. It provides a sophisticated scheduling system for inventory actions that respects constraints like delays, inventory state, and action ordering.

Properties

isInventoryOpen

Indicates whether the player inventory is currently open.
val isInventoryOpen: Boolean
Returns true if:
  • Player is in inventory screen, OR
  • Inventory is open server-side (e.g., via silent inventory on 1.11.1-)
Example:
if (InventoryManager.isInventoryOpen) {
    // Safe to perform inventory actions
}

isHandledScreenOpen

Indicates if any container screen is open (chest, furnace, etc.).
val isHandledScreenOpen: Boolean

isInventoryOpenServerSide

Indicates if inventory is open on the server (important for silent inventory).
var isInventoryOpenServerSide: Boolean

lastClickedSlot

The most recently clicked inventory slot.
var lastClickedSlot: Int

Inventory Actions

Inventory actions are scheduled through the event system.

ScheduleInventoryActionEvent

Fired every tick to collect inventory actions from modules.
val handler = handler<ScheduleInventoryActionEvent> { event ->
    // Add action to schedule
    event.schedule.add(actionChain)
}

Action Types

Click Action

Click an inventory slot.
InventoryAction.Click(
    slot = 36,  // Hotbar slot 0
    actionType = ClickType.PICKUP
)

Swap Action

Swap items between slots.
InventoryAction.Swap(
    from = sourceSlot,
    to = targetSlot
)

Throw Action

Throw an item.
InventoryAction.Click(
    slot = slot,
    actionType = ClickType.THROW
)

Close Screen Action

Close the current screen.
InventoryAction.CloseScreen()

Action Chains

Actions are organized into chains with constraints.
val chain = InventoryAction.Chain(
    actions = listOf(
        InventoryAction.Click(slot = 9, actionType = ClickType.PICKUP),
        InventoryAction.Click(slot = 36, actionType = ClickType.PICKUP)
    ),
    inventoryConstraints = InventoryConstraints(
        startDelay = 1..3,
        clickDelay = 2..4,
        closeDelay = 1..2,
        missChance = 0..5
    ),
    priority = 100
)

Inventory Constraints

Control timing and behavior of inventory actions.
data class InventoryConstraints(
    val startDelay: IntRange = 0..0,      // Ticks before first action
    val clickDelay: IntRange = 0..0,      // Ticks between actions
    val closeDelay: IntRange = 0..0,      // Ticks before closing inventory
    val missChance: IntRange = 0..0        // Percentage chance to miss-click
)

Scheduling Actions

Basic Example

val scheduleHandler = handler<ScheduleInventoryActionEvent> { event ->
    val sword = findSwordInInventory() ?: return@handler
    val hotbarSlot = 36  // First hotbar slot
    
    if (sword.slot != hotbarSlot) {
        event.schedule.add(
            InventoryAction.Chain(
                actions = listOf(
                    InventoryAction.Swap(
                        from = sword.slot,
                        to = hotbarSlot
                    )
                ),
                inventoryConstraints = InventoryConstraints(
                    startDelay = 2..5,
                    clickDelay = 1..3
                ),
                priority = 100
            )
        )
    }
}

Multiple Actions

val scheduleHandler = handler<ScheduleInventoryActionEvent> { event ->
    // Find armor pieces
    val helmet = findBestHelmet()
    val chestplate = findBestChestplate()
    
    val actions = mutableListOf<InventoryAction>()
    
    // Equip helmet (slot 5 is helmet slot)
    if (helmet != null) {
        actions.add(InventoryAction.Click(
            slot = helmet.slot,
            actionType = ClickType.PICKUP
        ))
        actions.add(InventoryAction.Click(
            slot = 5,
            actionType = ClickType.PICKUP
        ))
    }
    
    if (actions.isNotEmpty()) {
        event.schedule.add(
            InventoryAction.Chain(
                actions = actions,
                inventoryConstraints = inventoryConstraints,
                priority = 50
            )
        )
    }
}

Inventory State Tracking

The manager automatically tracks:
  • When inventory opens/closes
  • When clicks occur
  • Server-side inventory state
  • Recent inventory operations

Events Tracked

  • ServerboundContainerClickPacket - Click tracking
  • ClientboundContainerClosePacket - Close tracking
  • ClientboundOpenScreenPacket - Open tracking
  • ScreenEvent - Screen changes

Action Execution Flow

  1. Collection - Actions collected via ScheduleInventoryActionEvent
  2. Validation - Actions validated (canPerformAction())
  3. Sorting - Actions sorted by:
    • Inventory open requirements
    • Priority (descending)
  4. Execution - Actions executed with delays:
    • Start delay before first action
    • Click delay between actions
    • Close delay before closing inventory
  5. State Update - Inventory state updated

Slot Numbers

Player Inventory Slots

  • 0-4: Crafting output and input
  • 5-8: Armor (helmet, chestplate, leggings, boots)
  • 9-35: Main inventory (9-17 is hotbar in screen)
  • 36-44: Hotbar
  • 45: Offhand

Accessing Slots

// Hotbar slot 0
val hotbarSlot0 = 36

// Armor slots
val helmetSlot = 5
val chestplateSlot = 6
val leggingsSlot = 7
val bootsSlot = 8

// Current held item
val currentSlot = 36 + player.inventory.selected

Usage Examples

Auto Armor

val armorHandler = handler<ScheduleInventoryActionEvent> { event ->
    val armorSlots = mapOf(
        5 to findBestHelmet(),
        6 to findBestChestplate(),
        7 to findBestLeggings(),
        8 to findBestBoots()
    )
    
    val actions = mutableListOf<InventoryAction>()
    
    for ((armorSlot, bestArmor) in armorSlots) {
        if (bestArmor != null && !isWearing(armorSlot)) {
            // Pick up armor piece
            actions.add(InventoryAction.Click(
                slot = bestArmor.slot,
                actionType = ClickType.PICKUP
            ))
            // Place in armor slot
            actions.add(InventoryAction.Click(
                slot = armorSlot,
                actionType = ClickType.PICKUP
            ))
        }
    }
    
    if (actions.isNotEmpty()) {
        event.schedule.add(
            InventoryAction.Chain(
                actions = actions,
                inventoryConstraints = InventoryConstraints(
                    startDelay = 1..2,
                    clickDelay = 1..2,
                    closeDelay = 1..2
                ),
                priority = 100
            )
        )
    }
}

Inventory Cleaner

val cleanHandler = handler<ScheduleInventoryActionEvent> { event ->
    val junkItems = findJunkItems()
    
    val actions = junkItems.map { slot ->
        InventoryAction.Click(
            slot = slot,
            actionType = ClickType.THROW
        )
    }
    
    if (actions.isNotEmpty()) {
        event.schedule.add(
            InventoryAction.Chain(
                actions = actions,
                inventoryConstraints = InventoryConstraints(
                    startDelay = 5..10,
                    clickDelay = 2..4
                ),
                priority = 10  // Low priority
            )
        )
    }
}

Silent Hotbar Swap

val swapHandler = handler<ScheduleInventoryActionEvent> { event ->
    val targetSlot = 36  // First hotbar slot
    val bestSword = findBestWeapon() ?: return@handler
    
    if (bestSword.slot != targetSlot) {
        event.schedule.add(
            InventoryAction.Chain(
                actions = listOf(
                    InventoryAction.Swap(bestSword.slot, targetSlot)
                ),
                inventoryConstraints = InventoryConstraints(
                    startDelay = 0..1,
                    clickDelay = 0..0
                ),
                priority = 200  // High priority
            )
        )
    }
}

Best Practices

Use appropriate priorities: combat-related swaps should be high priority (100+), utility actions lower (50-).
Don’t schedule too many actions at once. Break up large operations across multiple ticks.
The InventoryManager automatically handles opening/closing the inventory and respects timing constraints to appear more human-like.

Constraint Recommendations

Fast Actions (PvP)

InventoryConstraints(
    startDelay = 0..1,
    clickDelay = 0..1,
    closeDelay = 0..1,
    missChance = 0..0
)

Normal Actions

InventoryConstraints(
    startDelay = 2..5,
    clickDelay = 2..4,
    closeDelay = 1..3,
    missChance = 0..5
)

Slow/Human-like

InventoryConstraints(
    startDelay = 5..15,
    clickDelay = 3..8,
    closeDelay = 2..5,
    missChance = 5..15
)

See Also

Build docs developers (and LLMs) love