-
Notifications
You must be signed in to change notification settings - Fork 0
Custom Items
Creating a CustomItem can be done in several ways, however using the function syntax is the easiest, and will be covered here.
// You can also use registerCustomItem(...) instead, which will automatically
// register the item whenever this variable is initialized.
val MyCustomItem = customItem(id(MyPlugin, "my_custom_item"), Material.GOLDEN_SWORD) {
// Contains all of the info for displaying an item to players.
display {
// viewer is whoever is looking at this item. Sometimes it's nobody, and sometimes
// it can't be determined, so it might be null if that's the case.
name = "Hello, ${viewer}!".colored // String.colored turns a String to a Component
text("I'm lore!".colored) // A line of lore.
text("I'm &oalso&r lore!".colored) // String.colored processes color/formatting codes
emptyLine() // An empty line of lore
}
}Note: You must register the plugin first before adding any custom items.
override fun onEnable() {
// ...
CustomItem.register(MyCustomItem)
}Up until now, the CustomItem doesn't do anything except for look pretty. We can change that by adding behaviors. Behaviors allow you to add functionality to a CustomItem in a reusable way that prevents duplicating code.
Behaviors are simply classes that contain a list of hooks (open functions) to alter the functionality of a CustomItem. Below is a list of some hooks you're able to use for an ItemBehavior.
fun onLeftClick(player: Player, item: CuTItemStack, event: PlayerInteractEvent)
fun onMiddleClick(player: Player, item: CuTItemStack, event: PlayerInteractEvent)
fun onRightClick(player: Player, item: CuTItemStack, event: PlayerInteractEvent)
fun onDrop(player: Player, item: CuTItemStack, event: PlayerDropItemEvent)
fun onObtain(player: Player, item: CuTItemStack, event: CustomItemObtainEvent)
fun onCreate(item: CuTItemStack)
fun onRender(viewer: Player?, item: CuTItemStack)
fun onTickInEitherHand(player: Player, item: CuTItemStack)
fun onTickInInventory(player: Player, item: CuTItemStack)
fun onTickEquipped(player: Player, item: CuTItemStack)
fun onOffhandEquip(player: Player, item: CuTItemStack, event: Cancellable)
fun onDamageEntity(attacker: LivingEntity, victim: LivingEntity, mainHandItem: CuTItemStack, event: EntityDamageByEntityEvent)This list may not be complete, you should view the ItemBehavior class to see all available hooks.
class LightningStrikeBehavior(damage: Int) : ItemBehavior(id(MyPlugin, "lightning_strike")) {
override fun onDamageEntity(
attacker: LivingEntity,
victim: LivingEntity,
mainHandItem: CuTItemStack,
event: EntityDamageByEntityEvent
) {
victim.damage(damage)
val world = victim.world
world.strikeLightningEffect(victim.location)
}
}If a hook that you need does not exist, then you can still use ItemBehaviors! You simply will have to fall back to a normal Bukkit Event Listener and call your own hook. You can even have an abstract class extend from ItemBehavior, then have your behaviors extend from that to implement your own hooks as well.
class MyBehavior : ItemBehavior(id(MyPlugin, "my_behavior")) {
fun onItemDamage(player: Player, item: CuTItemStack) {
// cool effects
}
}
object Events : Listener {
@EventHandler
fun onItemDamage(event: PlayerItemDamageEvent) {
val customItemStack = event.item.wrap() ?: return
customItemStack.getBehaviorOrNull<MyBehavior>()
?.onItemDamage(event.player, customItemStack)
}
}Back in your Custom Item, you can use behavior(vararg ItemBehavior) (or behavior(Collection<ItemBehavior>)) to add behaviors. Hooks are triggered in order of when behaviors are added (first behavior is triggered first).
val MyCustomItem = customItem(id(MyPlugin, "my_custom_item"), Material.GOLDEN_SWORD) {
behavior(LightningStrikeBehavior(10.0))
display {
name = "Hello, ${viewer}!".colored
text("I'm lore!".colored)
text("I'm &oalso&r lore!".colored)
emptyLine()
}
}There you go, you've just made a Custom Item using CuTAPI. Now, you're able to expand upon it by extending CuTItemStack.
CuTItemStack is a class that wraps around an ItemStack to provide additional function and utility.
// This class MUST have a constructor that takes in an ItemStack. You may also have other constructors.
class MyCuTItemStack internal constructor(handle: ItemStack) : CuTItemStack(handle) {
// Leverage Tags to store persistant data easily in the stack.
// Will never be null, and instead the default of "hello".
var persistentString by stringTag("TagName", "hello")
private var uses by intTag("Uses", 0)
// May be null.
var nullablePersistentString by nullableStringTag("AnotherTagName")
// This will not persist in the item, and will be
// cleared whenever this item is wrapped again.
private var tempBoolean = false
fun increaseUses() {
// Automatically saved to the handle ItemStack.
uses++
}
}// In your plugin class
override fun onEnable() {
// ...
CuTItemStack.registerType(
id("example:my_cut_itemstack"),
MyCuTItemStack::class,
// The constructor to MyCuTItemStack, or any function that takes
// in an ItemStack and returns an instance of your subclass.
::MyCuTItemStack
)
}// If the subtype is known
val wrapped : MyCuTItemStack? = itemStack.wrap<MyCuTItemStack>()
// If the subtype is not known, or is CuTItemStack
val wrapped : CuTItemStack? = itemStack.wrap()// Use the stack type as a generic parameter.
val MyCustomItem = customItem<MyCuTItemStack>(id(MyPlugin, "my_custom_item"), Material.GOLDEN_SWORD) {
behavior(LightningStrikeBehavior(10.0))
display {
name = "Hello, ${viewer}!".colored
text("I'm lore!".colored)
text("I'm &oalso&r lore!".colored)
emptyLine()
}
}val myCuTItemStack : MyCuTItemStack = MyCustomItem.createItemStack(1) // The parameter is the quantity.Textures are currently able to be added to an item like so:
val MyCustomItem = customItem<MyCuTItemStack>(id(MyPlugin, "my_custom_item"), Material.GOLDEN_SWORD) {
behavior(LightningStrikeBehavior(10.0))
display {
name = "Hello, ${viewer}!".colored
texture = itemTexture(MyPlugin, "/items/my_texture.png")
text("I'm lore!".colored)
text("I'm &oalso&r lore!".colored)
emptyLine()
}
}