Skip to content

Instantly share code, notes, and snippets.

@dumptruckman
Last active November 10, 2017 22:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dumptruckman/d43afe811a5ee1f021b5a959927c17c2 to your computer and use it in GitHub Desktop.
Save dumptruckman/d43afe811a5ee1f021b5a959927c17c2 to your computer and use it in GitHub Desktop.
A DSL for building Bukkit Inventory objects in Kotlin
/**
* Copyright 2017 Jeremy Wood
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
* the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.event.inventory.InventoryType
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.InventoryHolder
import org.bukkit.inventory.ItemStack
fun exampleUsage() {
val shopInv = inventory("Shop" ofsize 27) {
filler = ItemStack(Material.STAINED_GLASS_PANE, 1, 15)
ItemStack(Material.IRON_AXE) at topMiddle + oneRow
ItemStack(Material.PAPER) at bottomLeft
ItemStack(Material.PAPER) at bottomRight
}
val beaconInv = inventory("Diamond Beacon" oftype InventoryType.BEACON heldby beaconBlock) {
ItemStack(Material.DIAMOND) at 0
}
}
/**
* The main meat of the "inside" of an inventory function.
*/
open class InventoryBuilder(private val inv: Inventory) {
/**
* The ItemStack to use as a filler item for the inventory, filling any slots not filled with [at].
*/
var filler: ItemStack? = null
/**
* Puts the left operand ItemStack into the slot specified as the right operand.
*/
infix fun ItemStack.at(index: Int) {
if (index < 0 || index >= inv.size) {
throw IllegalArgumentException("Attempted to put item in a size ${inv.size} "
+ "inventory at invalid slot $index")
}
inv.contents[index] = this
}
/**
* Builds the inventory, filling it with [filler] if specified.
*
* Not intended for external calls. The [inventory] functions will return the inventory themselves.
*/
fun _getInventory(): Inventory {
if (filler != null) {
for (i in inv.contents.indices) {
if (inv.contents[i] == null) {
inv.contents[i] = ItemStack(filler)
}
}
}
return inv
}
}
private const val ROW_SIZE = 9
/**
* Additional helpers for the "inside" of an inventory function for chest inventories.
*/
class ChestInventoryBuilder(inv: Inventory) : InventoryBuilder(inv) {
/**
* The top left most inventory slot.
*/
val topLeft = 0
/**
* The top right most inventory slot.
*/
val topRight = 8
/**
* The bottom left most inventory slot.
*/
val bottomLeft = inv.size - ROW_SIZE
/**
* The bottom right most inventory slot.
*/
val bottomRight = inv.size - 1
/**
* The top most middle inventory slot.
*/
val topMiddle = topLeft + 4
/**
* The bottom most middle inventory slot.
*/
val bottomMiddle = bottomLeft + 4
/**
* The size of a row for adding/subtracting for moving an index down/up a row.
*/
val oneRow = ROW_SIZE
}
/*
* Inventory Constructor Helpers
*/
class NameAndSize(val name: String, val size: Int)
infix fun String.ofsize(size: Int) = NameAndSize(this, size)
class NameAndType(val name: String, val type: InventoryType)
infix fun String.oftype(type: InventoryType) = NameAndType(this, type)
class TypeAndHolder(val type: InventoryType, val holder: InventoryHolder)
infix fun InventoryType.heldby(holder: InventoryHolder) = TypeAndHolder(this, holder)
class SizeAndHolder(val size: Int, val holder: InventoryHolder)
infix fun Int.heldby(holder: InventoryHolder) = SizeAndHolder(this, holder)
class NameSizeAndHolder(val name: String, val size: Int, val holder: InventoryHolder)
infix fun NameAndSize.heldby(holder: InventoryHolder) = NameSizeAndHolder(name, size, holder)
class NameTypeAndHolder(val name: String, val type: InventoryType, val holder: InventoryHolder)
infix fun NameAndType.heldby(holder: InventoryHolder) = NameTypeAndHolder(name, type, holder)
/*
* Inventory Builder Functions
*/
inline fun inventory(size: Int, builder: ChestInventoryBuilder.() -> Unit): Inventory {
return _chestInventory(Bukkit.createInventory(null, size), builder)
}
inline fun inventory(invInfo: NameAndSize, builder: ChestInventoryBuilder.() -> Unit): Inventory {
return _chestInventory(Bukkit.createInventory(null, invInfo.size, invInfo.name), builder)
}
inline fun inventory(type: InventoryType, builder: InventoryBuilder.() -> Unit): Inventory {
if (type == InventoryType.CHEST) {
throw IllegalArgumentException("Do not specify type for chest inventories")
}
return _inventory(Bukkit.createInventory(null, type), builder)
}
inline fun inventory(invInfo: NameAndType, builder: InventoryBuilder.() -> Unit): Inventory {
if (invInfo.type == InventoryType.CHEST) {
throw IllegalArgumentException("Do not specify type for chest inventories")
}
return _inventory(Bukkit.createInventory(null, invInfo.type, invInfo.name), builder)
}
inline fun inventory(invInfo: NameSizeAndHolder, builder: ChestInventoryBuilder.() -> Unit): Inventory {
return _chestInventory(Bukkit.createInventory(invInfo.holder, invInfo.size, invInfo.name), builder)
}
inline fun inventory(invInfo: SizeAndHolder, builder: ChestInventoryBuilder.() -> Unit): Inventory {
return _chestInventory(Bukkit.createInventory(invInfo.holder, invInfo.size), builder)
}
inline fun inventory(invInfo: NameTypeAndHolder, builder: InventoryBuilder.() -> Unit): Inventory {
if (invInfo.type == InventoryType.CHEST) {
throw IllegalArgumentException("Do not specify type for chest inventories")
}
return _inventory(Bukkit.createInventory(invInfo.holder, invInfo.type, invInfo.name), builder)
}
inline fun inventory(invInfo: TypeAndHolder, builder: InventoryBuilder.() -> Unit): Inventory {
if (invInfo.type == InventoryType.CHEST) {
throw IllegalArgumentException("Do not specify type for chest inventories")
}
return _inventory(Bukkit.createInventory(invInfo.holder, invInfo.type), builder)
}
inline fun _inventory(inventory: Inventory, builder: InventoryBuilder.() -> Unit): Inventory {
val ib = InventoryBuilder(inventory)
ib.builder()
return ib._getInventory();
}
inline fun _chestInventory(inventory: Inventory, builder: ChestInventoryBuilder.() -> Unit): Inventory {
val ib = ChestInventoryBuilder(inventory)
ib.builder()
return ib._getInventory();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment