All Downloads are FREE. Search and download functionalities are using the official Maven repository.

walkmc.extensions.Items.kt Maven / Gradle / Ivy

package walkmc.extensions

import net.minecraft.server.*
import org.bukkit.*
import org.bukkit.Material
import org.bukkit.craftbukkit.inventory.*
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.*
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.*
import org.bukkit.material.*
import walkmc.*
import walkmc.block.*
import walkmc.extensions.collections.*
import walkmc.extensions.strings.*
import walkmc.placeholder.*
import walkmc.serializer.tag.impl.*

typealias MetaTransformer = ItemMeta.() -> Unit

/**
 * Gets the minecraft item handler of this item stack.
 */
val ItemStack.handler: MinecraftItem get() = CraftItemStack.asNMSMirror(this) ?: CraftItemStack.asNMSCopy(this)

/**
 * Copies and changes this item stack to the specified [block] function.
 */
inline fun ItemStack.copy(block: ItemStack.() -> Unit) = clone().apply(block)

/**
 * Changes this item stack material type by the specified [material].
 */
fun ItemStack.changeToMaterial(material: Materials): ItemStack {
	this.material = material
	return this
}

/**
 * Changes this item stack to the specified head representation of [url].
 */
fun ItemStack.changeToHead(url: String): ItemStack {
	material = Materials.PLAYER_SKULL
	data = SkullItem(url)
	applyMetaTo {
		this.url = url
	}
	return this
}

/**
 * Changes this item stack to the specified head representation of the owner [name].
 */
fun ItemStack.changeToHeadOwner(name: String): ItemStack {
	material = Materials.PLAYER_SKULL
	applyMetaTo {
		this.owner = name
	}
	return this
}

/**
 * Changes this item stack to the specified head representation of the owner [player].
 */
fun ItemStack.changeToHeadOwner(player: OfflinePlayer): ItemStack {
	material = Materials.PLAYER_SKULL
	applyMetaTo {
		this.owner = player.name
	}
	return this
}

/**
 * Copies and changes this item stack material type by the specified [material].
 */
fun ItemStack.copyToMaterial(material: Materials) = copy {
	this.material = material
}

/**
 * Copies and changes this item stack to the specified head representation of [url].
 */
fun ItemStack.copyToHead(url: String) = copy {
	material = Materials.PLAYER_SKULL
	data = SkullItem(url)
	applyMetaTo {
		this.url = url
	}
}

/**
 * Copies and changes this item stack to the specified head representation of the owner [name].
 */
fun ItemStack.copyToHeadOwner(name: String) = copy {
	material = Materials.PLAYER_SKULL
	applyMetaTo {
		owner = name
	}
}

/**
 * Copies and changes this item stack to the specified head representation of the owner [player].
 */
fun ItemStack.copyToHeadOwner(player: OfflinePlayer) = copy {
	material = Materials.PLAYER_SKULL
	applyMetaTo {
		owner = player.name
	}
}

/**
 * Transforms this item stack meta by the specified transform.
 */
inline fun ItemStack.applyMeta(transform: MetaTransformer) = apply {
	val meta = itemMeta
	meta.apply(transform)
	itemMeta = meta
}

/**
 * Transforms this item stack meta by the specified transform.
 */
inline fun  ItemStack.applyMetaTo(transform: T.() -> Unit) = apply {
	val meta: T = itemMeta.cast()
	meta.apply(transform)
	itemMeta = meta
}

/**
 * Returns the display name of this item stack.
 */
var ItemStack.name: String
	get() = itemMeta.displayName ?: type.name
	set(value) {
		applyMeta {
			displayName = value
		}
	}

/**
 * Sets the specified name to this item stack.
 */
fun ItemStack.name(name: String) = applyMeta {
	displayName = name
}

/**
 * Returns the lore of this item stack.
 */
var ItemStack.lore: MutableList
	get() = itemMeta.lore ?: newMutableList()
	set(value) {
		applyMeta {
			lore = value
		}
	}

/**
 * Inserts the specified lore to this item stack.
 */
fun ItemStack.lore(lines: Iterable) = applyMeta {
	lore = lines.toList()
}

/**
 * Inserts the specified lore to this item stack.
 */
fun ItemStack.lore(vararg lines: String) = applyMeta {
	lore = lines.toList()
}

/**
 * Inserts the specified multiline lore to this item stack. Like:
 * ```
 * lore("""
 *   §7First line
 *   §7Second line
 * """)
 * ```
 */
fun ItemStack.lore(lines: String) = applyMeta {
	lore = lines.lines()
}

/**
 * Returns the flags of this item stack.
 */
var ItemStack.flags: MutableSet
	get() = itemMeta.itemFlags ?: mutableSetOf()
	set(value) {
		applyMeta {
			addItemFlags(*value.toTypedArray())
		}
	}

/**
 * Inserts the specified flags to this item stack.
 */
fun ItemStack.flags(vararg flags: ItemFlag) = applyMeta {
	addItemFlags(*flags)
}

/**
 * Inserts the specified enchantments to this item stack.
 */
fun ItemStack.enchantments(vararg enchantments: Pair) = apply {
	addUnsafeEnchantments(enchantments.toMap())
}

/**
 * Sets the specified amount of this item stack.
 */
fun ItemStack.amount(amount: Int) = apply {
	this.amount = amount
}

/**
 * Sets the specified durability of this item stack.
 */
fun ItemStack.durability(durability: Int) = apply {
	this.durability = durability.toShort()
}

/**
 * Sets the specified material data of this item stack.
 */
fun ItemStack.data(materialData: MaterialData) = apply {
	this.data = materialData
}

/**
 * Sets the specified material data of this item stack.
 */
fun ItemStack.data(type: Material, data: Number) = apply {
	this.data = newData(type, data)
}

/**
 * Sets the specified type of this item stack.
 */
fun ItemStack.type(type: Material) = apply {
	this.type = type
}

/**
 * Converts this item to a [MinecraftItem].
 */
fun ItemStack.asMinecraftItem(): MinecraftItem = CraftItemStack.asNMSCopy(this)

/**
 * Returns if this item stack is similar to [other] item stack
 */
infix fun ItemStack.similar(other: ItemStack?) = isSimilar(other)

/**
 * Applies the necessary data tag used to verify if a item stack
 * is part from a custom block item.
 */
inline fun  ItemStack.setCustomBlockPart() = applyTag {
	setClass("BlockClass", T::class.java)
}

/**
 * Returns if this item stack is a part from a custom block item.
 */
val ItemStack.isCustomBlockPart: Boolean
	get() = tag.hasKey("BlockClass")

/**
 * Gets the custom block part class of this item stack, or nulls
 * if this item is not a part from a custom block.
 */
val ItemStack.customBlockPart: Class?
	get() = try {
		tag.getClass("BlockClass")
	} catch (ex: Exception) {
		null
	}

/**
 * Applies the given [block] to the root tag of this item stack.
 */
inline fun ItemStack.applyTag(block: NBTTagCompound.() -> Unit) = apply {
	val handler = handler
	handler.tag = handler.tag.apply(block)
	itemMeta = CraftItemStack.getItemMeta(handler)
}

/**
 * Gets the root tag of this item stack.
 *
 * ## NOTE:
 *
 * This MUST only used to configure certains aspects of persistent data or item data that's
 * is not available in [storage], like [isUnbreakable] and others.
 *
 * For convenience, prefers using [storage] almost in all cases.
 */
var ItemStack.tag: NBTTagCompound
	get() = handler.tag ?: NBTTagCompound()
	set(value) {
		val handler = handler
		handler.tag = value
		itemMeta = CraftItemStack.getItemMeta(handler)
	}

/**
 * Applies the given [block] to the storage tag of this item stack.
 */
inline fun ItemStack.applyStorage(block: CompoundTag.() -> Unit) = apply {
	applyTag {
		val tag = getTagGroup("Storage").tag
		setTagGroup("Storage", tag.apply(block))
	}
}

/**
 * Gets the tag storage of this item stack.
 *
 * ## NOTE:
 *
 * This MUST be used in almost all cases when configuring persistent data or custom data of this item.
 * Certain things like, setting this item to [isUnbreakable] must be configured with [tag].
 *
 * For convenience, prefers using this almost in all cases.
 */
var ItemStack.storage: CompoundTag
	get() = tag.getTagGroup("Storage").tag
	set(value) {
		applyTag {
			this.setTagGroup("Storage", value)
		}
	}

/**
 * Returns if this item stack is unbreakable or not.
 */
var ItemStack.isUnbreakable: Boolean
	get() = tag.getBoolean("Unbreakable")
	set(value) {
		applyTag {
			setBoolean("Unbreakable", value)
		}
	}

/**
 * Process this item stack with the specified placeholder and value
 * by the model name and lore.
 */
fun  ItemStack.process(model: ItemStack, placeholder: Placeholder, value: T) = apply {
	name(placeholder.process(model.name, value))
	lore(placeholder.process(model.lore, value))
}

/**
 * Process this item stack with the specified placeholder and value
 * by the model name and lore.
 */
fun ItemStack.process(model: ItemStack, value: Pair) = apply {
	name(model.name.process(value))
	lore(model.lore.process(value))
}

/**
 * Process this item stack with the specified placeholder and value
 * by the model name and lore.
 */
fun ItemStack.process(model: ItemStack, vararg value: Pair) = apply {
	name(model.name.process(*value))
	lore(model.lore.process(*value))
}

/**
 * Process this item stack with the specified placeholder and value
 * by the model name and lore.
 */
fun ItemStack.process(model: ItemStack, value: Map) = apply {
	name(model.name.process(value))
	lore(model.lore.process(value))
}

/**
 * Process this item stack with the specified placeholder and value.
 */
fun  ItemStack.process(placeholder: Placeholder, value: T) = apply {
	name(placeholder.process(name, value))
	lore(placeholder.process(lore, value))
}

/**
 * Process only specified placeholder in this item stack.
 */
fun ItemStack.process(value: Pair) = apply {
	name(name.process(value))
	lore(lore.process(value))
}

/**
 * Process all specifieds placeholders in this item stack.
 */
fun ItemStack.process(vararg values: Pair) = apply {
	name(name.process(*values))
	lore(lore.process(*values))
}

/**
 * Process all specifieds placeholders in this item stack.
 */
fun ItemStack.process(values: Map) = apply {
	name(name.process(values))
	lore(lore.process(values))
}

/**
 * Process this item stack with the specified placeholder and value
 * by the model name and lore and returns a copy of them.
 */
fun  ItemStack.processCopy(model: ItemStack, placeholder: Placeholder, value: T): ItemStack =
	clone().process(model, placeholder, value)

/**
 * Process this item stack with the specified placeholder and value
 * by the model name and lore and returns a copy of them.
 */
fun ItemStack.processCopy(model: ItemStack, value: Pair) =
	clone().process(model, value)

/**
 * Process this item stack with the specified placeholder and value
 * by the model name and lore and returns a copy of them.
 */
fun ItemStack.processCopy(model: ItemStack, vararg value: Pair): ItemStack =
	clone().process(model, *value)

/**
 * Process this item stack with the specified placeholder and value
 * by the model name and lore and returns a copy of them.
 */
fun ItemStack.processCopy(model: ItemStack, value: Map): ItemStack =
	clone().process(model, value)

/**
 * Process this item stack with the specified placeholder and value and returns a copy of them.
 */
fun  ItemStack.processCopy(placeholder: Placeholder, value: T): ItemStack =
	clone().process(placeholder, value)

/**
 * Process only specified placeholder in this item stack and returns a copy of them.
 */
fun ItemStack.processCopy(value: Pair): ItemStack = clone().process(value)

/**
 * Process all specifieds placeholders in this item stack and returns a copy of them.
 */
fun ItemStack.processCopy(vararg values: Pair): ItemStack = clone().process(*values)

/**
 * Process all specifieds placeholders in this item stack and returns a copy of them.
 */
fun ItemStack.processCopy(values: Map): ItemStack = clone().process(values)

/**
 * Creates a new empty item stack.
 */
fun emptyItem(): ItemStack = ItemStack(Material.AIR, 0)

/**
 * Builds a item stack by the specified [block].
 */
inline fun buildItem(block: ItemStack.() -> Unit): ItemStack = ItemStack(Materials.AIR, 1).apply(block)

/**
 * Creates a new item stack by the specified model and amount.
 */
fun newItem(model: ItemStack, amount: Int = 1): ItemStack = model.amount(amount)

/**
 * Creates a new item stack by the specified model and name.
 */
fun newItem(model: ItemStack, name: String, amount: Int = 1): ItemStack =
	model.name(name).amount(amount)

/**
 * Creates a new item stack by the specified model and lore.
 */
fun newItem(model: ItemStack, lore: List, amount: Int = 1): ItemStack =
	model.lore(lore).amount(amount)

/**
 * Creates a new item stack by the specified model, name and lore.
 */
fun newItem(model: ItemStack, name: String, lore: List, amount: Int = 1): ItemStack =
	model.name(name).lore(lore).amount(amount)

/**
 * Creates a new item stack by the specified material.
 */
fun newItem(material: Materials, amount: Int = 1): ItemStack = material.toItem(amount)

/**
 * Creates a new item stack by the specified material data.
 */
fun newItem(material: MaterialData, amount: Int = 1): ItemStack = material.toItemStack(amount)

/**
 * Creates a new item stack by the specified material and name.
 */
fun newItem(material: Materials, name: String, amount: Int = 1): ItemStack =
	newItem(material, amount).name(name)

/**
 * Creates a new item stack by the specified material and lore.
 */
fun newItem(material: Materials, lore: List, amount: Int = 1): ItemStack =
	newItem(material, amount).lore(lore)

/**
 * Creates a new item stack by the specified material, name and lore.
 */
fun newItem(material: Materials, name: String, lore: List, amount: Int = 1): ItemStack =
	newItem(material, amount).name(name).lore(lore)

/**
 * Creates a new item stack by the specified material data and name.
 */
fun newItem(material: MaterialData, name: String, amount: Int = 1): ItemStack =
	material.toItemStack(amount).name(name)

/**
 * Creates a new item stack by the specified material data and lore.
 */
fun newItem(material: MaterialData, lore: List, amount: Int = 1): ItemStack =
	material.toItemStack(amount).lore(lore)

/**
 * Creates a new item stack by the specified material data, name and lore.
 */
fun newItem(material: MaterialData, name: String, lore: List, amount: Int = 1): ItemStack =
	material.toItemStack(amount).name(name).lore(lore)

/**
 * Creates a new item stack head by the specified player id.
 */
fun newHeadOwner(owner: String, amount: Int = 1): ItemStack = createHeadOwner(owner).amount(amount)

/**
 * Creates a new item stack head by the specified player id and lore.
 */
fun newHeadOwner(owner: String, lore: List, amount: Int = 1): ItemStack =
	createHeadOwner(owner).amount(amount).lore(lore)

/**
 * Creates a new item stack head by the specified player id and name.
 */
fun newHeadOwner(owner: String, name: String, amount: Int = 1): ItemStack =
	createHeadOwner(owner).amount(amount).name(name)

/**
 * Creates a new item stack head by the specified player id, name and lore.
 */
fun newHeadOwner(owner: String, name: String, lore: List, amount: Int = 1): ItemStack =
	createHeadOwner(owner).amount(amount).name(name).lore(lore)

/**
 * Creates a new item stack head by the specified url head.
 */
fun newHead(base: String, amount: Int = 1): ItemStack = createHead(base).amount(amount)

/**
 * Creates a new item stack head by the specified url head and lore.
 */
fun newHead(base: String, lore: List, amount: Int = 1): ItemStack =
	createHead(base).amount(amount).lore(lore)

/**
 * Creates a new item stack head by the specified url head and name.
 */
fun newHead(base: String, name: String, amount: Int = 1): ItemStack =
	createHead(base).amount(amount).name(name)

/**
 * Creates a new item stack head by the specified url head, name and lore.
 */
fun newHead(base: String, name: String, lore: List, amount: Int = 1): ItemStack =
	createHead(base).amount(amount).name(name).lore(lore)

/**
 * Internal API to create empty heads with the specified base64.
 */
internal fun createHead(base: String): ItemStack = newItem(Materials.PLAYER_SKULL).apply {
	data = SkullItem(base)
	applyMetaTo {
		url = base
	}
}

/**
 * Internal API to create empty heads with the specified player name as owner.
 */
internal fun createHeadOwner(name: String): ItemStack = newItem(Materials.PLAYER_SKULL).apply {
	applyMetaTo {
		owner = name
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy