← Roadmap

Utils

Inventory, particles, loot

Why

Give an item without losing it when the inventory is full. Check that a player has five custom items and take them. Draw a box with particles for one player. Fill a chest with loot. Not subsystems, but functions every plugin has, each time slightly different.

Minimal example

Inventory
val result = EffectiveInventoryUtils.giveItem(RubyItem.createItemStack(), player)
if (result == GiveResult.DROPPED) player.sendMessage("inventory full")

if (EffectiveInventoryUtils.hasItems(player.inventory, RubyItem.createItemStack(), 5)) {
    EffectiveInventoryUtils.removeItems(player.inventory, RubyItem.createItemStack(), 5)
}

val held = EffectiveInventoryUtils.getUsedItemFromHands(player)

Matching is by EffectiveItem key, by material for vanilla items; meta is ignored.

Particles
val red = Particle.DustOptions(Color.RED, 1f)
EffectiveParticles.drawBox(listOf(player), 0.0, 64.0, 0.0, 10.0, 70.0, 10.0, red)
EffectiveParticles.drawLine(listOf(player), 0.0, 64.0, 0.0, 10.0, 64.0, 0.0, red, step = 0.25)

Dust particles visible only to the listed players. drawLine — point to point with a step of step blocks, drawBox — the 12 edges of a box by its min/max corners.

Components and placeholder
import ru.hukm.effectiveSpigot.minecraft.utils.plus

val line = Component.text("Ruby: ").color(NamedTextColor.RED) + count.toString()

'#' to SlotData(EffectiveItems.EMPTY(), emptyList())

CustomLootable — loot tables

Table and rolling
val CHEST_LOOT = arrayListOf(
    CustomLootable.ItemCellData(RubyItem.createItemStack(), 0.3),
    CustomLootable.ItemCellData(ItemStack(Material.BREAD, 3), 0.8),
    CustomLootable.ItemCellData(ItemStack(Material.DIAMOND), 0.05),
)

CustomLootable.putLootToContainer(chest.state as Container, CHEST_LOOT)

CustomLootable.spawnLootAtLocation(boss.location, CHEST_LOOT)

override fun getDrop() = CHEST_LOOT

ItemCellData is an item and its chance 0.0..1.0; every cell rolls independently, so a table may yield everything, nothing or any subset. putLootToContainer spreads the winners over random free slots of a chest/barrel/shulker (throws IllegalStateException if slots run out), spawnLootAtLocation drops them on the ground. EffectiveBlock.getDrop() takes the same list.

Pitfalls

  • The + operator for Component is an extension — import …minecraft.utils.plus, otherwise "Unresolved reference".
  • CustomLootable chances are independent — every item rolls on its own, it is not "one of".
  • drawBox / drawLine draw once — for a persistent frame call them in a launch loop with delay.