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.
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
- Collection - Actions collected via
ScheduleInventoryActionEvent
- Validation - Actions validated (
canPerformAction())
- Sorting - Actions sorted by:
- Inventory open requirements
- Priority (descending)
- Execution - Actions executed with delays:
- Start delay before first action
- Click delay between actions
- Close delay before closing inventory
- 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