Improve code style

This commit is contained in:
Jakob K
2021-05-12 14:17:44 +02:00
parent 3e9b243d3d
commit cf48510756
69 changed files with 144 additions and 609 deletions

View File

@@ -6,7 +6,6 @@ import java.awt.*;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class KColors { public class KColors {
// DEFAULT CODES // DEFAULT CODES
public static final ChatColor MAGIC = ChatColor.MAGIC; public static final ChatColor MAGIC = ChatColor.MAGIC;
@@ -877,5 +876,4 @@ public class KColors {
* <div style="border:1px solid black;width:120px;height:120px;background-color:#9ACD32;float:right;margin: 0 10px 0 0"></div> * <div style="border:1px solid black;width:120px;height:120px;background-color:#9ACD32;float:right;margin: 0 10px 0 0"></div>
*/ */
public static final ChatColor YELLOWGREEN = ChatColor.of(new Color(0.6039216f, 0.8039216f, 0.19607843f)); public static final ChatColor YELLOWGREEN = ChatColor.of(new Color(0.6039216f, 0.8039216f, 0.19607843f));
} }

View File

@@ -13,11 +13,8 @@ inline fun chatComponent(builder: KSpigotComponentBuilder.() -> Unit): Array<out
} }
class KSpigotComponentBuilder { class KSpigotComponentBuilder {
private val components = ArrayList<BaseComponent>() private val components = ArrayList<BaseComponent>()
// COMPONENTS // COMPONENTS
inline fun text(text: String, builder: TextComponent.() -> Unit = { }) { inline fun text(text: String, builder: TextComponent.() -> Unit = { }) {
this += TextComponent(text).apply(builder) this += TextComponent(text).apply(builder)
} }
@@ -40,13 +37,11 @@ class KSpigotComponentBuilder {
inline fun translatable( inline fun translatable(
translatable: String, translatable: String,
with: Array<BaseComponent>, with: Array<BaseComponent>,
builder: TranslatableComponent.() -> Unit = { } builder: TranslatableComponent.() -> Unit = { },
) { ) {
this += TranslatableComponent(translatable, with).apply(builder) this += TranslatableComponent(translatable, with).apply(builder)
} }
// SPECIAL // SPECIAL
fun legacyText(text: String, color: ChatColor = ChatColor.WHITE, builder: BaseComponent.() -> Unit = { }) { fun legacyText(text: String, color: ChatColor = ChatColor.WHITE, builder: BaseComponent.() -> Unit = { }) {
this += TextComponent.fromLegacyText(text, color).onEach { it.apply(builder) } this += TextComponent.fromLegacyText(text, color).onEach { it.apply(builder) }
} }
@@ -60,15 +55,11 @@ class KSpigotComponentBuilder {
} }
fun create() = components.toTypedArray() fun create() = components.toTypedArray()
} }
/* /*
* BASE COMPONENT * BASE COMPONENT
*/ */
// extensions // extensions
inline fun BaseComponent.hoverEventText(builder: KSpigotComponentBuilder.() -> Unit) { inline fun BaseComponent.hoverEventText(builder: KSpigotComponentBuilder.() -> Unit) {
hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text(KSpigotComponentBuilder().apply(builder).create())) hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text(KSpigotComponentBuilder().apply(builder).create()))
} }
@@ -84,7 +75,6 @@ fun BaseComponent.hoverEventEntity(type: String, id: String, baseComponent: Base
fun BaseComponent.clickEvent(action: ClickEvent.Action, value: String) { fun BaseComponent.clickEvent(action: ClickEvent.Action, value: String) {
clickEvent = ClickEvent(action, value) clickEvent = ClickEvent(action, value)
} }
/* /*
* GLOBAL SHORTCUTS * GLOBAL SHORTCUTS
*/ */

View File

@@ -19,7 +19,7 @@ import org.bukkit.event.Listener
fun Player.awaitChatInput( fun Player.awaitChatInput(
question: String = "Type your input in the chat!", question: String = "Type your input in the chat!",
timeoutSeconds: Int = 1 * 60, timeoutSeconds: Int = 1 * 60,
callback: (PlayerInputResult<String>) -> Unit callback: (PlayerInputResult<String>) -> Unit,
) { ) {
PlayerInputChat(this, callback, timeoutSeconds, question) PlayerInputChat(this, callback, timeoutSeconds, question)
} }
@@ -36,7 +36,7 @@ fun Player.awaitAnvilInput(
"submit your input!" "submit your input!"
), ),
timeoutSeconds: Int = 1 * 60, timeoutSeconds: Int = 1 * 60,
callback: (PlayerInputResult<String>) -> Unit callback: (PlayerInputResult<String>) -> Unit,
) { ) {
PlayerInputAnvilInv(this, callback, timeoutSeconds, invTitle, startText, renameItemDescription) PlayerInputAnvilInv(this, callback, timeoutSeconds, invTitle, startText, renameItemDescription)
} }
@@ -48,7 +48,7 @@ fun Player.awaitAnvilInput(
*/ */
fun Player.awaitBookInputAsString( fun Player.awaitBookInputAsString(
timeoutSeconds: Int = 1 * 60, timeoutSeconds: Int = 1 * 60,
callback: (PlayerInputResult<String>) -> Unit callback: (PlayerInputResult<String>) -> Unit,
) { ) {
PlayerInputBookComprehensive(this, callback, timeoutSeconds) PlayerInputBookComprehensive(this, callback, timeoutSeconds)
} }
@@ -61,7 +61,7 @@ fun Player.awaitBookInputAsString(
*/ */
fun Player.awaitBookInputAsList( fun Player.awaitBookInputAsList(
timeoutSeconds: Int = 1 * 60, timeoutSeconds: Int = 1 * 60,
callback: (PlayerInputResult<List<String>>) -> Unit callback: (PlayerInputResult<List<String>>) -> Unit,
) { ) {
PlayerInputBookPaged(this, callback, timeoutSeconds) PlayerInputBookPaged(this, callback, timeoutSeconds)
} }
@@ -70,17 +70,13 @@ fun Player.awaitBookInputAsList(
* @param input The input the player gave. Null on timeout or invalid input. * @param input The input the player gave. Null on timeout or invalid input.
*/ */
class PlayerInputResult<T> internal constructor(val input: T?) class PlayerInputResult<T> internal constructor(val input: T?)
internal abstract class PlayerInput<T>( internal abstract class PlayerInput<T>(
protected val player: Player, protected val player: Player,
private val callback: (PlayerInputResult<T>) -> Unit, private val callback: (PlayerInputResult<T>) -> Unit,
timeoutSeconds: Int timeoutSeconds: Int,
) { ) {
private var received = false private var received = false
protected abstract val inputListeners: List<Listener> protected abstract val inputListeners: List<Listener>
protected fun onReceive(input: T?) { protected fun onReceive(input: T?) {
if (!received) { if (!received) {
inputListeners.forEach { it.unregister() } inputListeners.forEach { it.unregister() }
@@ -99,5 +95,4 @@ internal abstract class PlayerInput<T>(
onReceive(null) onReceive(null)
} }
} }
} }

View File

@@ -19,9 +19,8 @@ internal class PlayerInputAnvilInv(
timeoutSeconds: Int, timeoutSeconds: Int,
invTitle: String, invTitle: String,
startText: String, startText: String,
renameItemDescription: List<String> renameItemDescription: List<String>,
) : PlayerInput<String>(player, callback, timeoutSeconds) { ) : PlayerInput<String>(player, callback, timeoutSeconds) {
private val anvilInv = private val anvilInv =
AnvilGUI.Builder().plugin(KSpigotMainInstance) AnvilGUI.Builder().plugin(KSpigotMainInstance)
.onClose { onReceive(null) } .onClose { onReceive(null) }
@@ -42,7 +41,6 @@ internal class PlayerInputAnvilInv(
) )
.text("${KColors.ORANGERED}$startText") .text("${KColors.ORANGERED}$startText")
.open(player) .open(player)
override val inputListeners = listOf( override val inputListeners = listOf(
listen<InventoryClickEvent> { listen<InventoryClickEvent> {
if (it.clickedInventory == anvilInv.inventory) if (it.clickedInventory == anvilInv.inventory)
@@ -53,5 +51,4 @@ internal class PlayerInputAnvilInv(
override fun onTimeout() { override fun onTimeout() {
anvilInv.inventory.closeForViewers() anvilInv.inventory.closeForViewers()
} }
} }

View File

@@ -17,7 +17,7 @@ import org.bukkit.persistence.PersistentDataType
internal class PlayerInputBookComprehensive( internal class PlayerInputBookComprehensive(
player: Player, player: Player,
callback: (PlayerInputResult<String>) -> Unit, callback: (PlayerInputResult<String>) -> Unit,
timeoutSeconds: Int timeoutSeconds: Int,
) : PlayerInputBook<String>(player, callback, timeoutSeconds) { ) : PlayerInputBook<String>(player, callback, timeoutSeconds) {
override fun loadBookContent(bookMeta: BookMeta) = bookMeta.content override fun loadBookContent(bookMeta: BookMeta) = bookMeta.content
} }
@@ -25,7 +25,7 @@ internal class PlayerInputBookComprehensive(
internal class PlayerInputBookPaged( internal class PlayerInputBookPaged(
player: Player, player: Player,
callback: (PlayerInputResult<List<String>>) -> Unit, callback: (PlayerInputResult<List<String>>) -> Unit,
timeoutSeconds: Int timeoutSeconds: Int,
) : PlayerInputBook<List<String>>(player, callback, timeoutSeconds) { ) : PlayerInputBook<List<String>>(player, callback, timeoutSeconds) {
override fun loadBookContent(bookMeta: BookMeta): List<String> = bookMeta.pages override fun loadBookContent(bookMeta: BookMeta): List<String> = bookMeta.pages
} }
@@ -33,9 +33,8 @@ internal class PlayerInputBookPaged(
internal abstract class PlayerInputBook<T>( internal abstract class PlayerInputBook<T>(
player: Player, player: Player,
callback: (PlayerInputResult<T>) -> Unit, callback: (PlayerInputResult<T>) -> Unit,
timeoutSeconds: Int timeoutSeconds: Int,
) : PlayerInput<T>(player, callback, timeoutSeconds) { ) : PlayerInput<T>(player, callback, timeoutSeconds) {
private val id = getID() private val id = getID()
init { init {
@@ -47,7 +46,6 @@ internal abstract class PlayerInputBook<T>(
} }
abstract fun loadBookContent(bookMeta: BookMeta): T abstract fun loadBookContent(bookMeta: BookMeta): T
override val inputListeners = listOf( override val inputListeners = listOf(
listen<PlayerEditBookEvent> { listen<PlayerEditBookEvent> {
val meta = it.newBookMeta val meta = it.newBookMeta
@@ -64,16 +62,12 @@ internal abstract class PlayerInputBook<T>(
} }
companion object { companion object {
val idKey = NamespacedKey(KSpigotMainInstance, "kspigot_bookinput_id") val idKey = NamespacedKey(KSpigotMainInstance, "kspigot_bookinput_id")
internal val usedIDs = ArrayList<Int>() internal val usedIDs = ArrayList<Int>()
fun getID(): Int { fun getID(): Int {
var returnID = (0..Int.MAX_VALUE).random() var returnID = (0..Int.MAX_VALUE).random()
while (usedIDs.contains(returnID)) returnID = (0..Int.MAX_VALUE).random() while (usedIDs.contains(returnID)) returnID = (0..Int.MAX_VALUE).random()
return returnID return returnID
} }
} }
} }

View File

@@ -12,7 +12,7 @@ internal class PlayerInputChat(
player: Player, player: Player,
callback: (PlayerInputResult<String>) -> Unit, callback: (PlayerInputResult<String>) -> Unit,
timeoutSeconds: Int, timeoutSeconds: Int,
question: String question: String,
) : PlayerInput<String>(player, callback, timeoutSeconds) { ) : PlayerInput<String>(player, callback, timeoutSeconds) {
init { init {
@@ -27,5 +27,4 @@ internal class PlayerInputChat(
} }
} }
) )
} }

View File

@@ -43,11 +43,9 @@ class ConfigDelegate<T : Any>(
private val configClass: KClass<T>, private val configClass: KClass<T>,
private val file: File, private val file: File,
private val saveAfterLoad: Boolean, private val saveAfterLoad: Boolean,
private val defaultCallback: (() -> T)? private val defaultCallback: (() -> T)?,
) { ) {
private var internalConfig: T = loadIt() private var internalConfig: T = loadIt()
var data: T var data: T
get() = internalConfig get() = internalConfig
set(value) { set(value) {
@@ -55,7 +53,6 @@ class ConfigDelegate<T : Any>(
} }
operator fun getValue(thisRef: Any?, property: KProperty<*>) = internalConfig operator fun getValue(thisRef: Any?, property: KProperty<*>) = internalConfig
operator fun setValue(thisRef: Any?, property: KProperty<*>, config: T): Boolean { operator fun setValue(thisRef: Any?, property: KProperty<*>, config: T): Boolean {
internalConfig = config internalConfig = config
return true return true
@@ -79,7 +76,6 @@ class ConfigDelegate<T : Any>(
} }
private fun loadIt(): T { private fun loadIt(): T {
val loaded = if (defaultCallback == null) val loaded = if (defaultCallback == null)
GsonConfigManager.loadConfig(file, configClass) GsonConfigManager.loadConfig(file, configClass)
else else
@@ -90,13 +86,10 @@ class ConfigDelegate<T : Any>(
saveIt(loaded) saveIt(loaded)
return loaded return loaded
} }
} }
internal object GsonConfigManager { internal object GsonConfigManager {
fun <T : Any> loadConfig(file: File, configClass: KClass<T>): T = fun <T : Any> loadConfig(file: File, configClass: KClass<T>): T =
FileReader(file).use { reader -> return getGson().fromJson(reader, configClass.java) } FileReader(file).use { reader -> return getGson().fromJson(reader, configClass.java) }
@@ -111,7 +104,7 @@ internal object GsonConfigManager {
file: File, file: File,
configClass: KClass<T>, configClass: KClass<T>,
pretty: Boolean = true, pretty: Boolean = true,
default: () -> T default: () -> T,
): T { ): T {
try { try {
return loadConfig(file, configClass) return loadConfig(file, configClass)
@@ -122,5 +115,4 @@ internal object GsonConfigManager {
} }
} }
} }
} }

View File

@@ -8,7 +8,6 @@ import net.minecraft.server.v1_16_R3.NBTTagCompound
@NMS_General @NMS_General
class NBTData { class NBTData {
val nbtTagCompound: NBTTagCompound val nbtTagCompound: NBTTagCompound
constructor(nbtTagCompound: NBTTagCompound?) { constructor(nbtTagCompound: NBTTagCompound?) {
@@ -60,9 +59,6 @@ class NBTData {
operator fun minusAssign(key: String) = remove(key) operator fun minusAssign(key: String) = remove(key)
companion object { companion object {
fun deserialize(nbtString: String) = NBTData(nbtString) fun deserialize(nbtString: String) = NBTData(nbtString)
} }
} }

View File

@@ -5,12 +5,10 @@ import net.minecraft.server.v1_16_R3.*
@NMS_General @NMS_General
interface NBTDataType<T> { interface NBTDataType<T> {
fun decodeNMS(nbtBase: NBTBase): T? fun decodeNMS(nbtBase: NBTBase): T?
fun writeToCompound(key: String, data: T, compound: NBTTagCompound) fun writeToCompound(key: String, data: T, compound: NBTTagCompound)
companion object { companion object {
val COMPOUND = nbtDataType<NBTData, NBTTagCompound>({ NBTData(it) }, val COMPOUND = nbtDataType<NBTData, NBTTagCompound>({ NBTData(it) },
{ key, data, compound -> compound.set(key, data.nbtTagCompound) }) { key, data, compound -> compound.set(key, data.nbtTagCompound) })
val BYTE = val BYTE =
@@ -32,9 +30,7 @@ interface NBTDataType<T> {
nbtDataType<Short, NBTTagShort>({ it.asShort() }, { key, data, compound -> compound.setShort(key, data) }) nbtDataType<Short, NBTTagShort>({ it.asShort() }, { key, data, compound -> compound.setShort(key, data) })
val STRING = nbtDataType<String, NBTTagString>({ it.asString() }, val STRING = nbtDataType<String, NBTTagString>({ it.asString() },
{ key, data, compound -> compound.setString(key, data) }) { key, data, compound -> compound.setString(key, data) })
} }
} }
/** /**
@@ -43,16 +39,11 @@ interface NBTDataType<T> {
*/ */
private inline fun <T, reified E> nbtDataType( private inline fun <T, reified E> nbtDataType(
crossinline decodeNMS: (E) -> T, crossinline decodeNMS: (E) -> T,
crossinline writeToCompound: (key: String, data: T, compound: NBTTagCompound) -> Unit crossinline writeToCompound: (key: String, data: T, compound: NBTTagCompound) -> Unit,
): NBTDataType<T> { ): NBTDataType<T> {
return object : NBTDataType<T> { return object : NBTDataType<T> {
override fun decodeNMS(nbtBase: NBTBase) = if (nbtBase is E) decodeNMS.invoke(nbtBase) else null override fun decodeNMS(nbtBase: NBTBase) = if (nbtBase is E) decodeNMS.invoke(nbtBase) else null
override fun writeToCompound(key: String, data: T, compound: NBTTagCompound) = override fun writeToCompound(key: String, data: T, compound: NBTTagCompound) =
writeToCompound.invoke(key, data, compound) writeToCompound.invoke(key, data, compound)
} }
} }

View File

@@ -28,7 +28,7 @@ fun Listener.unregister() = HandlerList.unregisterAll(this)
inline fun <reified T : Event> Listener.register( inline fun <reified T : Event> Listener.register(
priority: EventPriority = EventPriority.NORMAL, priority: EventPriority = EventPriority.NORMAL,
ignoreCancelled: Boolean = false, ignoreCancelled: Boolean = false,
noinline executor: (Listener, Event) -> Unit noinline executor: (Listener, Event) -> Unit,
) { ) {
pluginManager.registerEvent(T::class.java, this, priority, executor, KSpigotMainInstance, ignoreCancelled) pluginManager.registerEvent(T::class.java, this, priority, executor, KSpigotMainInstance, ignoreCancelled)
} }
@@ -50,7 +50,7 @@ interface SingleListener<T : Event> : Listener {
*/ */
inline fun <reified T : Event> SingleListener<T>.register( inline fun <reified T : Event> SingleListener<T>.register(
priority: EventPriority = EventPriority.NORMAL, priority: EventPriority = EventPriority.NORMAL,
ignoreCancelled: Boolean = false ignoreCancelled: Boolean = false,
) { ) {
register<T>(priority, ignoreCancelled) { _, event -> register<T>(priority, ignoreCancelled) { _, event ->
(event as? T)?.let { this.onEvent(it) } (event as? T)?.let { this.onEvent(it) }
@@ -68,7 +68,7 @@ inline fun <reified T : Event> listen(
priority: EventPriority = EventPriority.NORMAL, priority: EventPriority = EventPriority.NORMAL,
ignoreCancelled: Boolean = false, ignoreCancelled: Boolean = false,
register: Boolean = true, register: Boolean = true,
crossinline onEvent: (event: T) -> Unit crossinline onEvent: (event: T) -> Unit,
): SingleListener<T> { ): SingleListener<T> {
val listener = object : SingleListener<T> { val listener = object : SingleListener<T> {
override fun onEvent(event: T) = onEvent.invoke(event) override fun onEvent(event: T) = onEvent.invoke(event)

View File

@@ -4,7 +4,6 @@ import net.axay.kspigot.main.KSpigotMainInstance
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
import org.bukkit.entity.Entity
import org.bukkit.entity.Player import org.bukkit.entity.Player
/** /**

View File

@@ -1,7 +1,5 @@
package net.axay.kspigot.extensions.bukkit package net.axay.kspigot.extensions.bukkit
// FROM BUNGEE COLOR // FROM BUNGEE COLOR
/** /**
* Returns the corresponding Bukkit Color object. * Returns the corresponding Bukkit Color object.
*/ */
@@ -14,9 +12,7 @@ val net.md_5.bungee.api.ChatColor.bukkitColor
*/ */
val net.md_5.bungee.api.ChatColor.javaAwtColor: java.awt.Color val net.md_5.bungee.api.ChatColor.javaAwtColor: java.awt.Color
get() = color get() = color
// FROM BUKKIT COLOR // FROM BUKKIT COLOR
/** /**
* Returns the corresponding Bungee Color object. * Returns the corresponding Bungee Color object.
*/ */
@@ -28,9 +24,7 @@ val org.bukkit.Color.bungeeColor: net.md_5.bungee.api.ChatColor
*/ */
val org.bukkit.Color.javaAwtColor: java.awt.Color val org.bukkit.Color.javaAwtColor: java.awt.Color
get() = java.awt.Color(asRGB()) get() = java.awt.Color(asRGB())
// FROM JAVA AWT COLOR // FROM JAVA AWT COLOR
/** /**
* Returns the corresponding Bukkit Color object. * Returns the corresponding Bukkit Color object.
*/ */
@@ -42,9 +36,7 @@ val java.awt.Color.bukkitColor
*/ */
val java.awt.Color.bungeeColor: net.md_5.bungee.api.ChatColor val java.awt.Color.bungeeColor: net.md_5.bungee.api.ChatColor
get() = net.md_5.bungee.api.ChatColor.of(this) get() = net.md_5.bungee.api.ChatColor.of(this)
// FROM BUKKIT CHAT COLOR // FROM BUKKIT CHAT COLOR
/** /**
* Returns the corresponding Bukkit Color object. * Returns the corresponding Bukkit Color object.
*/ */

View File

@@ -133,7 +133,7 @@ fun Player.title(
subText: String? = null, subText: String? = null,
fadeIn: Int = 10, fadeIn: Int = 10,
stay: Int = 70, stay: Int = 70,
fadeOut: Int = 20 fadeOut: Int = 20,
) { ) {
sendTitle(mainText, subText, fadeIn, stay, fadeOut) sendTitle(mainText, subText, fadeIn, stay, fadeOut)
} }

View File

@@ -15,7 +15,7 @@ fun Inventory.closeForViewers() = HashSet(viewers).forEach { it.closeInventory()
val InventoryAction.isSimple val InventoryAction.isSimple
get() = when (this) { get() = when (this) {
InventoryAction.PLACE_ALL, InventoryAction.PLACE_ONE, InventoryAction.PLACE_ALL, InventoryAction.PLACE_ONE,
InventoryAction.PICKUP_ALL, InventoryAction.PICKUP_HALF, InventoryAction.PICKUP_ONE InventoryAction.PICKUP_ALL, InventoryAction.PICKUP_HALF, InventoryAction.PICKUP_ONE,
-> true -> true
else -> false else -> false
} }

View File

@@ -1,13 +1,13 @@
package net.axay.kspigot.extensions.bukkit package net.axay.kspigot.extensions.bukkit
import org.bukkit.inventory.meta.BookMeta import org.bukkit.inventory.meta.BookMeta
import java.lang.StringBuilder
val BookMeta.content get() = val BookMeta.content
StringBuilder().apply { get() =
for (it in pages) { StringBuilder().apply {
if (isNotEmpty()) for (it in pages) {
append('\n') if (isNotEmpty())
append(it) append('\n')
} append(it)
}.toString() }
}.toString()

View File

@@ -40,16 +40,12 @@ val PlayerInteractEvent.clickedBlockExceptAir: Block?
get() { get() {
return clickedBlock ?: kotlin.run { return clickedBlock ?: kotlin.run {
return@run if (this.action == Action.RIGHT_CLICK_AIR) { return@run if (this.action == Action.RIGHT_CLICK_AIR) {
val p: Player = this.player val p: Player = this.player
// check for sight blocking entities // check for sight blocking entities
for (nearbyEntity: Entity in p.getNearbyEntities(5.0, 5.0, 5.0)) for (nearbyEntity: Entity in p.getNearbyEntities(5.0, 5.0, 5.0))
if (p.hasLineOfSight(nearbyEntity)) return@run null if (p.hasLineOfSight(nearbyEntity)) return@run null
// get first block in line of sight which is not air // get first block in line of sight which is not air
p.getLineOfSight(null, 5).find { block -> !block.type.isAir } p.getLineOfSight(null, 5).find { block -> !block.type.isAir }
} else null } else null
} }
} }

View File

@@ -9,7 +9,7 @@ import org.bukkit.util.Vector
data class SimpleLocation2D( data class SimpleLocation2D(
val x: Double, val x: Double,
val y: Double val y: Double,
) { ) {
constructor(x: Number, y: Number) constructor(x: Number, y: Number)
: this(x.toDouble(), y.toDouble()) : this(x.toDouble(), y.toDouble())
@@ -19,30 +19,23 @@ data class SimpleLocation3D(
val x: Double, val x: Double,
val y: Double, val y: Double,
val z: Double, val z: Double,
val direction: Vector = vec(0, 0, 0) val direction: Vector = vec(0, 0, 0),
) { ) {
constructor(x: Number, y: Number, z: Number) constructor(x: Number, y: Number, z: Number)
: this(x.toDouble(), y.toDouble(), z.toDouble()) : this(x.toDouble(), y.toDouble(), z.toDouble())
val chunk: SimpleChunkLocation val chunk: SimpleChunkLocation
get() = SimpleChunkLocation(x.toInt() shr 4, z.toInt() shr 4) get() = SimpleChunkLocation(x.toInt() shr 4, z.toInt() shr 4)
} }
data class SimpleChunkLocation( data class SimpleChunkLocation(
val x: Int, val x: Int,
val z: Int val z: Int,
) )
// CONVERTER // CONVERTER
fun Location.toSimple() = SimpleLocation3D(x, y, z) fun Location.toSimple() = SimpleLocation3D(x, y, z)
fun Chunk.toSimple() = SimpleChunkLocation(x, z) fun Chunk.toSimple() = SimpleChunkLocation(x, z)
fun SimpleLocation3D.withWorld(world: World) = Location(world, x, y, z).apply { direction = this@withWorld.direction } fun SimpleLocation3D.withWorld(world: World) = Location(world, x, y, z).apply { direction = this@withWorld.direction }
fun SimpleChunkLocation.withWorld(world: World) = world.getChunkAt(x, z) fun SimpleChunkLocation.withWorld(world: World) = world.getChunkAt(x, z)
fun Vector.toSimpleLoc() = SimpleLocation3D(x, y, z) fun Vector.toSimpleLoc() = SimpleLocation3D(x, y, z)
fun SimpleLocation3D.toVector() = Vector(x, y, z) fun SimpleLocation3D.toVector() = Vector(x, y, z)

View File

@@ -10,21 +10,17 @@ import kotlin.math.max
import kotlin.math.min import kotlin.math.min
class SimpleLocationPair(loc1: Location, loc2: Location) { class SimpleLocationPair(loc1: Location, loc2: Location) {
val world = loc1.worldOrException.let { val world = loc1.worldOrException.let {
if (it == loc2.worldOrException) it if (it == loc2.worldOrException) it
else throw IllegalArgumentException("The given locations worlds are not the same!") else throw IllegalArgumentException("The given locations worlds are not the same!")
} }
val minSimpleLoc = SimpleLocation3D(min(loc1.x, loc2.x), min(loc1.y, loc2.y), min(loc1.z, loc2.z)) val minSimpleLoc = SimpleLocation3D(min(loc1.x, loc2.x), min(loc1.y, loc2.y), min(loc1.z, loc2.z))
val maxSimpleLoc = SimpleLocation3D(max(loc1.x, loc2.x), max(loc1.y, loc2.y), max(loc1.z, loc2.z)) val maxSimpleLoc = SimpleLocation3D(max(loc1.x, loc2.x), max(loc1.y, loc2.y), max(loc1.z, loc2.z))
fun isInArea( fun isInArea(
loc: Location, loc: Location,
check3d: Boolean = true, check3d: Boolean = true,
tolerance: Int = 0 tolerance: Int = 0,
): Boolean { ): Boolean {
// checking world // checking world
if (loc.world != world) return false if (loc.world != world) return false
@@ -37,11 +33,9 @@ class SimpleLocationPair(loc1: Location, loc2: Location) {
// checking y // checking y
if (check3d) loc.y >= minSimpleLoc.y - tolerance && loc.y <= maxSimpleLoc.y + tolerance else true if (check3d) loc.y >= minSimpleLoc.y - tolerance && loc.y <= maxSimpleLoc.y + tolerance else true
} else false } else false
} }
val touchedSimpleChunks: Set<SimpleChunkLocation> by lazy { val touchedSimpleChunks: Set<SimpleChunkLocation> by lazy {
val foundChunks = HashSet<SimpleChunkLocation>() val foundChunks = HashSet<SimpleChunkLocation>()
(minSimpleLoc.chunk.x until maxSimpleLoc.chunk.x + 1).forEach { curX -> (minSimpleLoc.chunk.x until maxSimpleLoc.chunk.x + 1).forEach { curX ->
@@ -51,13 +45,10 @@ class SimpleLocationPair(loc1: Location, loc2: Location) {
} }
return@lazy foundChunks return@lazy foundChunks
} }
} }
class LocationArea(loc1: Location, loc2: Location) { class LocationArea(loc1: Location, loc2: Location) {
var loc1: Location = loc1 var loc1: Location = loc1
set(value) { set(value) {
field = value field = value
@@ -68,19 +59,14 @@ class LocationArea(loc1: Location, loc2: Location) {
field = value field = value
simpleLocationPair = SimpleLocationPair(loc1, value) simpleLocationPair = SimpleLocationPair(loc1, value)
} }
var simpleLocationPair = SimpleLocationPair(loc1, loc2); private set var simpleLocationPair = SimpleLocationPair(loc1, loc2); private set
val world: World get() = simpleLocationPair.world val world: World get() = simpleLocationPair.world
val minLoc: Location get() = simpleLocationPair.minSimpleLoc.withWorld(simpleLocationPair.world) val minLoc: Location get() = simpleLocationPair.minSimpleLoc.withWorld(simpleLocationPair.world)
val maxLoc: Location get() = simpleLocationPair.maxSimpleLoc.withWorld(simpleLocationPair.world) val maxLoc: Location get() = simpleLocationPair.maxSimpleLoc.withWorld(simpleLocationPair.world)
val touchedChunks: Set<Chunk> get() = simpleLocationPair.touchedSimpleChunks.mapTo(HashSet()) { it.withWorld(world) } val touchedChunks: Set<Chunk> get() = simpleLocationPair.touchedSimpleChunks.mapTo(HashSet()) { it.withWorld(world) }
fun isInArea( fun isInArea(
loc: Location, loc: Location,
check3d: Boolean = true, check3d: Boolean = true,
tolerance: Int = 0 tolerance: Int = 0,
) = simpleLocationPair.isInArea(loc, check3d, tolerance) ) = simpleLocationPair.isInArea(loc, check3d, tolerance)
} }

View File

@@ -36,15 +36,10 @@ infix fun Location.reduceZ(distance: Number) = subtract(0.0, 0.0, distance)
infix fun Location.reduceXY(distance: Number) = subtract(distance, distance, 0.0) infix fun Location.reduceXY(distance: Number) = subtract(distance, distance, 0.0)
infix fun Location.reduceYZ(distance: Number) = subtract(0.0, distance, distance) infix fun Location.reduceYZ(distance: Number) = subtract(0.0, distance, distance)
infix fun Location.reduceXZ(distance: Number) = subtract(distance, 0.0, distance) infix fun Location.reduceXZ(distance: Number) = subtract(distance, 0.0, distance)
// extensions // extensions
fun Location.add(x: Number, y: Number, z: Number) = add(x.toDouble(), y.toDouble(), z.toDouble()) fun Location.add(x: Number, y: Number, z: Number) = add(x.toDouble(), y.toDouble(), z.toDouble())
fun Location.subtract(x: Number, y: Number, z: Number) = subtract(x.toDouble(), y.toDouble(), z.toDouble()) fun Location.subtract(x: Number, y: Number, z: Number) = subtract(x.toDouble(), y.toDouble(), z.toDouble())
val Location.blockLoc: Location get() = Location(world, blockX.toDouble(), blockY.toDouble(), blockZ.toDouble()) val Location.blockLoc: Location get() = Location(world, blockX.toDouble(), blockY.toDouble(), blockZ.toDouble())
infix fun Location.relationTo(loc: Location) = this.subtract(loc).toSimple() infix fun Location.relationTo(loc: Location) = this.subtract(loc).toSimple()
// operator functions // operator functions
@@ -88,11 +83,9 @@ infix fun Location.increase(loc: Location) = add(loc)
infix fun Location.reduce(loc: Location) = subtract(loc) infix fun Location.reduce(loc: Location) = subtract(loc)
infix fun Location.increase(loc: SimpleLocation3D) = add(loc.x, loc.y, loc.z) infix fun Location.increase(loc: SimpleLocation3D) = add(loc.x, loc.y, loc.z)
infix fun Location.reduce(loc: SimpleLocation3D) = subtract(loc.x, loc.y, loc.z) infix fun Location.reduce(loc: SimpleLocation3D) = subtract(loc.x, loc.y, loc.z)
/* /*
* VECTOR * VECTOR
*/ */
val Vector.isFinite: Boolean get() = x.isFinite() && y.isFinite() && z.isFinite() val Vector.isFinite: Boolean get() = x.isFinite() && y.isFinite() && z.isFinite()
// fast construct // fast construct

View File

@@ -18,13 +18,11 @@ fun buildCounterMessageCallback(
secondPlural: String = "s", secondPlural: String = "s",
hourSingular: String = hourPlural, hourSingular: String = hourPlural,
minuteSingular: String = minutePlural, minuteSingular: String = minutePlural,
secondSingular: String = secondPlural secondSingular: String = secondPlural,
): (Long) -> String = { curSeconds -> ): (Long) -> String = { curSeconds ->
StringBuilder().apply { StringBuilder().apply {
if (beforeTime != null) if (beforeTime != null)
append(beforeTime) append(beforeTime)
val hourTime = (curSeconds / 3600) val hourTime = (curSeconds / 3600)
val minuteTime = ((curSeconds % 3600) / 60) val minuteTime = ((curSeconds % 3600) / 60)
val secondsTime = (curSeconds % 60) val secondsTime = (curSeconds % 60)
@@ -46,14 +44,13 @@ fun buildCounterMessageCallback(
if (afterTime != null) if (afterTime != null)
append(afterTime) append(afterTime)
}.toString() }.toString()
} }
class GamePhase( class GamePhase(
val length: Long, val length: Long,
val start: (() -> Unit)?, val start: (() -> Unit)?,
val end: (() -> Unit)?, val end: (() -> Unit)?,
val counterMessage: ((secondsLeft: Long) -> String)? val counterMessage: ((secondsLeft: Long) -> String)?,
) { ) {
fun startIt(phaseQueue: MutableList<GamePhase>) { fun startIt(phaseQueue: MutableList<GamePhase>) {
start?.invoke() start?.invoke()
@@ -61,21 +58,17 @@ class GamePhase(
period = 20, period = 20,
howOften = (length / 20) + 1, howOften = (length / 20) + 1,
endCallback = { endCallback = {
end?.invoke() end?.invoke()
if (phaseQueue.isNotEmpty()) if (phaseQueue.isNotEmpty())
phaseQueue.removeAt(0).startIt(phaseQueue) phaseQueue.removeAt(0).startIt(phaseQueue)
} }
) { ) {
if (counterMessage != null) { if (counterMessage != null) {
val currentCounter = it.counterDownToZero val currentCounter = it.counterDownToZero
if (currentCounter?.isCounterValue == true) if (currentCounter?.isCounterValue == true)
broadcast(counterMessage.invoke(currentCounter)) broadcast(counterMessage.invoke(currentCounter))
} }
} }
} }
} }

View File

@@ -3,22 +3,17 @@
package net.axay.kspigot.game package net.axay.kspigot.game
class GamePhaseSystemBuilder { class GamePhaseSystemBuilder {
private val gamePhases = mutableListOf<GamePhase>() private val gamePhases = mutableListOf<GamePhase>()
fun build() = GamePhaseSystem(*gamePhases.toTypedArray()) fun build() = GamePhaseSystem(*gamePhases.toTypedArray())
fun phase(length: Long, builder: GamePhaseBuilder.() -> Unit) { fun phase(length: Long, builder: GamePhaseBuilder.() -> Unit) {
gamePhases += GamePhaseBuilder(length).apply(builder).build() gamePhases += GamePhaseBuilder(length).apply(builder).build()
} }
} }
class GamePhaseBuilder(val length: Long) { class GamePhaseBuilder(val length: Long) {
private var start: (() -> Unit)? = null private var start: (() -> Unit)? = null
private var end: (() -> Unit)? = null private var end: (() -> Unit)? = null
private var counterMessage: ((secondsLeft: Long) -> String)? = null private var counterMessage: ((secondsLeft: Long) -> String)? = null
fun start(callback: () -> Unit) { fun start(callback: () -> Unit) {
start = callback start = callback
} }
@@ -36,13 +31,12 @@ class GamePhaseBuilder(val length: Long) {
afterTime: String? = null, afterTime: String? = null,
hours: String = "h", hours: String = "h",
minutes: String = "m", minutes: String = "m",
seconds: String = "s" seconds: String = "s",
) { ) {
counterMessage = buildCounterMessageCallback(beforeTime, afterTime, hours, minutes, seconds) counterMessage = buildCounterMessageCallback(beforeTime, afterTime, hours, minutes, seconds)
} }
fun build() = GamePhase(length, start, end, counterMessage) fun build() = GamePhase(length, start, end, counterMessage)
} }
fun buildGame(builder: GamePhaseSystemBuilder.() -> Unit) = GamePhaseSystemBuilder().apply(builder).build() fun buildGame(builder: GamePhaseSystemBuilder.() -> Unit) = GamePhaseSystemBuilder().apply(builder).build()

View File

@@ -9,8 +9,6 @@ import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.player.PlayerQuitEvent import org.bukkit.event.player.PlayerQuitEvent
import org.bukkit.inventory.Inventory import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import java.util.*
import kotlin.collections.HashSet
class GUIData<T : ForInventory>( class GUIData<T : ForInventory>(
val guiType: GUIType<T>, val guiType: GUIType<T>,
@@ -19,13 +17,12 @@ class GUIData<T : ForInventory>(
val defaultPage: Int, val defaultPage: Int,
val transitionTo: InventoryChangeEffect?, val transitionTo: InventoryChangeEffect?,
val transitionFrom: InventoryChangeEffect?, val transitionFrom: InventoryChangeEffect?,
internal val generalOnClick: ((GUIClickEvent<T>) -> Unit)? internal val generalOnClick: ((GUIClickEvent<T>) -> Unit)?,
) )
abstract class GUI<T : ForInventory>( abstract class GUI<T : ForInventory>(
val data: GUIData<T> val data: GUIData<T>,
) { ) {
/** /**
* Returns the instance beloning to the given player. * Returns the instance beloning to the given player.
* If not existing, a new instance will be created. * If not existing, a new instance will be created.
@@ -42,20 +39,17 @@ abstract class GUI<T : ForInventory>(
* all instances. * all instances.
*/ */
abstract fun closeGUI() abstract fun closeGUI()
protected fun unregisterAndClose() { protected fun unregisterAndClose() {
getAllInstances().forEach { getAllInstances().forEach {
it.bukkitInventory.closeForViewers() it.bukkitInventory.closeForViewers()
it.unregister() it.unregister()
} }
} }
} }
class GUIShared<T : ForInventory>( class GUIShared<T : ForInventory>(
guiData: GUIData<T> guiData: GUIData<T>,
) : GUI<T>(guiData) { ) : GUI<T>(guiData) {
private var _singleInstance: GUIInstance<T>? = null private var _singleInstance: GUIInstance<T>? = null
val singleInstance val singleInstance
get() = _singleInstance ?: GUIInstance(this, null).apply { get() = _singleInstance ?: GUIInstance(this, null).apply {
@@ -64,29 +58,23 @@ class GUIShared<T : ForInventory>(
} }
override fun getInstance(player: Player) = singleInstance override fun getInstance(player: Player) = singleInstance
override fun getAllInstances() = _singleInstance?.let { listOf(it) } ?: emptyList() override fun getAllInstances() = _singleInstance?.let { listOf(it) } ?: emptyList()
override fun closeGUI() { override fun closeGUI() {
unregisterAndClose() unregisterAndClose()
_singleInstance = null _singleInstance = null
} }
} }
class GUIIndividual<T : ForInventory>( class GUIIndividual<T : ForInventory>(
guiData: GUIData<T>, guiData: GUIData<T>,
resetOnClose: Boolean, resetOnClose: Boolean,
resetOnQuit: Boolean resetOnQuit: Boolean,
) : GUI<T>(guiData) { ) : GUI<T>(guiData) {
private val playerInstances = HashMap<Player, GUIInstance<T>>() private val playerInstances = HashMap<Player, GUIInstance<T>>()
override fun getInstance(player: Player) = override fun getInstance(player: Player) =
playerInstances[player] ?: createInstance(player) playerInstances[player] ?: createInstance(player)
override fun getAllInstances() = playerInstances.values override fun getAllInstances() = playerInstances.values
private fun createInstance(player: Player) = private fun createInstance(player: Player) =
GUIInstance(this, player).apply { GUIInstance(this, player).apply {
playerInstances[player] = this playerInstances[player] = this
@@ -94,14 +82,12 @@ class GUIIndividual<T : ForInventory>(
} }
fun deleteInstance(player: Player) = playerInstances.remove(player)?.unregister() fun deleteInstance(player: Player) = playerInstances.remove(player)?.unregister()
override fun closeGUI() { override fun closeGUI() {
unregisterAndClose() unregisterAndClose()
playerInstances.clear() playerInstances.clear()
} }
init { init {
if (resetOnClose) { if (resetOnClose) {
listen<InventoryCloseEvent> { listen<InventoryCloseEvent> {
deleteInstance(it.player as? Player ?: return@listen) deleteInstance(it.player as? Player ?: return@listen)
@@ -113,22 +99,16 @@ class GUIIndividual<T : ForInventory>(
deleteInstance(it.player) deleteInstance(it.player)
} }
} }
} }
} }
class GUIInstance<T : ForInventory>( class GUIInstance<T : ForInventory>(
val gui: GUI<T>, val gui: GUI<T>,
holder: Player? holder: Player?,
) { ) {
internal val bukkitInventory = gui.data.guiType.createBukkitInv(holder, gui.data.title) internal val bukkitInventory = gui.data.guiType.createBukkitInv(holder, gui.data.title)
private val currentElements = HashSet<GUIElement<*>>() private val currentElements = HashSet<GUIElement<*>>()
internal var isInMove: Boolean = false internal var isInMove: Boolean = false
var currentPageInt: Int = gui.data.defaultPage; private set var currentPageInt: Int = gui.data.defaultPage; private set
val currentPage val currentPage
get() = getPage(currentPageInt) get() = getPage(currentPageInt)
@@ -143,15 +123,12 @@ class GUIInstance<T : ForInventory>(
} }
internal fun loadPageUnsafe(page: GUIPage<*>, offsetHorizontally: Int = 0, offsetVertically: Int = 0) { internal fun loadPageUnsafe(page: GUIPage<*>, offsetHorizontally: Int = 0, offsetVertically: Int = 0) {
val ifOffset = offsetHorizontally != 0 || offsetVertically != 0 val ifOffset = offsetHorizontally != 0 || offsetVertically != 0
if (!ifOffset) { if (!ifOffset) {
// unregister this inv from all elements on the previous page // unregister this inv from all elements on the previous page
currentElements.forEach { it.stopUsing(this) } currentElements.forEach { it.stopUsing(this) }
currentElements.clear() currentElements.clear()
// register this inv for all new elements // register this inv for all new elements
HashSet(page.slots.values).forEach { HashSet(page.slots.values).forEach {
if (it is GUIElement) { if (it is GUIElement) {
@@ -161,23 +138,18 @@ class GUIInstance<T : ForInventory>(
} }
currentPageInt = page.number currentPageInt = page.number
} }
loadContent(page.slots, offsetHorizontally, offsetVertically) loadContent(page.slots, offsetHorizontally, offsetVertically)
} }
internal fun loadContent( internal fun loadContent(
content: Map<Int, GUISlot<*>>, content: Map<Int, GUISlot<*>>,
offsetHorizontally: Int = 0, offsetHorizontally: Int = 0,
offsetVertically: Int = 0 offsetVertically: Int = 0,
) { ) {
val ifOffset = offsetHorizontally != 0 || offsetVertically != 0 val ifOffset = offsetHorizontally != 0 || offsetVertically != 0
val dimensions = gui.data.guiType.dimensions val dimensions = gui.data.guiType.dimensions
// clear the space which will be redefined // clear the space which will be redefined
if (ifOffset) { if (ifOffset) {
dimensions.invSlots.forEach { dimensions.invSlots.forEach {
@@ -185,13 +157,10 @@ class GUIInstance<T : ForInventory>(
if (slotToClear != null) bukkitInventory.clear(slotToClear) if (slotToClear != null) bukkitInventory.clear(slotToClear)
} }
} else bukkitInventory.clear() } else bukkitInventory.clear()
// render the given content // render the given content
content.forEach { content.forEach {
val slot = it.value val slot = it.value
if (slot is GUIElement) { if (slot is GUIElement) {
if (ifOffset) { if (ifOffset) {
val invSlot = InventorySlot.fromRealSlot(it.key, dimensions) val invSlot = InventorySlot.fromRealSlot(it.key, dimensions)
if (invSlot != null) { if (invSlot != null) {
@@ -199,11 +168,8 @@ class GUIInstance<T : ForInventory>(
if (offsetSlot != null) bukkitInventory.setItem(offsetSlot, slot.getItemStack(offsetSlot)) if (offsetSlot != null) bukkitInventory.setItem(offsetSlot, slot.getItemStack(offsetSlot))
} }
} else bukkitInventory.setItem(it.key, slot.getItemStack(it.key)) } else bukkitInventory.setItem(it.key, slot.getItemStack(it.key))
} }
} }
} }
/** /**
@@ -218,14 +184,11 @@ class GUIInstance<T : ForInventory>(
* GUI anymore. * GUI anymore.
*/ */
fun unregister() { fun unregister() {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
GUIHolder.unregister(this as GUIInstance<ForInventory>) GUIHolder.unregister(this as GUIInstance<ForInventory>)
// unregister this inv from all elements // unregister this inv from all elements
currentElements.forEach { it.stopUsing(this) } currentElements.forEach { it.stopUsing(this) }
currentElements.clear() currentElements.clear()
} }
/** /**
@@ -259,5 +222,4 @@ class GUIInstance<T : ForInventory>(
if (!isInMove) if (!isInMove)
loadPage(currentPage) loadPage(currentPage)
} }
} }

View File

@@ -14,9 +14,8 @@ fun <T : ForInventory> kSpigotGUI(
class GUIBuilder<T : ForInventory>( class GUIBuilder<T : ForInventory>(
val type: GUIType<T>, val type: GUIType<T>,
private val guiCreator: GUICreator<T> private val guiCreator: GUICreator<T>,
) { ) {
/** /**
* The title of this GUI. * The title of this GUI.
* This title will be visible for every page of * This title will be visible for every page of
@@ -42,9 +41,7 @@ class GUIBuilder<T : ForInventory>(
* GUI instance. * GUI instance.
*/ */
var defaultPage = 1 var defaultPage = 1
private val guiSlots = HashMap<Int, GUIPage<T>>() private val guiSlots = HashMap<Int, GUIPage<T>>()
private var onClickElement: ((GUIClickEvent<T>) -> Unit)? = null private var onClickElement: ((GUIClickEvent<T>) -> Unit)? = null
/** /**
@@ -67,21 +64,16 @@ class GUIBuilder<T : ForInventory>(
internal fun build() = guiCreator.createInstance( internal fun build() = guiCreator.createInstance(
GUIData(type, title, guiSlots, defaultPage, transitionTo, transitionFrom, onClickElement) GUIData(type, title, guiSlots, defaultPage, transitionTo, transitionFrom, onClickElement)
) )
} }
class GUIPageBuilder<T : ForInventory>( class GUIPageBuilder<T : ForInventory>(
private val type: GUIType<T>, private val type: GUIType<T>,
val page: Int val page: Int,
) { ) {
private val guiSlots = HashMap<Int, GUISlot<T>>() private val guiSlots = HashMap<Int, GUISlot<T>>()
var transitionTo: PageChangeEffect? = null var transitionTo: PageChangeEffect? = null
var transitionFrom: PageChangeEffect? = null var transitionFrom: PageChangeEffect? = null
internal fun build() = GUIPage(page, guiSlots, transitionTo, transitionFrom) internal fun build() = GUIPage(page, guiSlots, transitionTo, transitionFrom)
private fun defineSlots(slots: InventorySlotCompound<T>, element: GUISlot<T>) = private fun defineSlots(slots: InventorySlotCompound<T>, element: GUISlot<T>) =
slots.withInvType(type).forEach { curSlot -> slots.withInvType(type).forEach { curSlot ->
curSlot.realSlotIn(type.dimensions)?.let { guiSlots[it] = element } curSlot.realSlotIn(type.dimensions)?.let { guiSlots[it] = element }
@@ -118,7 +110,7 @@ class GUIPageBuilder<T : ForInventory>(
slots: InventorySlotCompound<T>, slots: InventorySlotCompound<T>,
icon: ItemStack, icon: ItemStack,
toPage: Int, toPage: Int,
onChange: ((GUIClickEvent<T>) -> Unit)? = null onChange: ((GUIClickEvent<T>) -> Unit)? = null,
) = pageChanger(slots, icon, toPage, null, onChange) ) = pageChanger(slots, icon, toPage, null, onChange)
/** /**
@@ -130,7 +122,7 @@ class GUIPageBuilder<T : ForInventory>(
icon: ItemStack, icon: ItemStack,
toPage: Int, toPage: Int,
shouldChange: ((GUIClickEvent<T>) -> Boolean)? = null, shouldChange: ((GUIClickEvent<T>) -> Boolean)? = null,
onChange: ((GUIClickEvent<T>) -> Unit)? = null onChange: ((GUIClickEvent<T>) -> Unit)? = null,
) = defineSlots( ) = defineSlots(
slots, GUIButtonPageChange( slots, GUIButtonPageChange(
icon, icon,
@@ -149,7 +141,7 @@ class GUIPageBuilder<T : ForInventory>(
fun previousPage( fun previousPage(
slots: InventorySlotCompound<T>, slots: InventorySlotCompound<T>,
icon: ItemStack, icon: ItemStack,
onChange: ((GUIClickEvent<T>) -> Unit)? = null onChange: ((GUIClickEvent<T>) -> Unit)? = null,
) = previousPage(slots, icon, null, onChange) ) = previousPage(slots, icon, null, onChange)
/** /**
@@ -161,7 +153,7 @@ class GUIPageBuilder<T : ForInventory>(
slots: InventorySlotCompound<T>, slots: InventorySlotCompound<T>,
icon: ItemStack, icon: ItemStack,
shouldChange: ((GUIClickEvent<T>) -> Boolean)? = null, shouldChange: ((GUIClickEvent<T>) -> Boolean)? = null,
onChange: ((GUIClickEvent<T>) -> Unit)? = null onChange: ((GUIClickEvent<T>) -> Unit)? = null,
) = defineSlots( ) = defineSlots(
slots, GUIButtonPageChange( slots, GUIButtonPageChange(
icon, icon,
@@ -180,7 +172,7 @@ class GUIPageBuilder<T : ForInventory>(
fun nextPage( fun nextPage(
slots: InventorySlotCompound<T>, slots: InventorySlotCompound<T>,
icon: ItemStack, icon: ItemStack,
onChange: ((GUIClickEvent<T>) -> Unit)? = null onChange: ((GUIClickEvent<T>) -> Unit)? = null,
) = nextPage(slots, icon, null, onChange) ) = nextPage(slots, icon, null, onChange)
/** /**
@@ -192,7 +184,7 @@ class GUIPageBuilder<T : ForInventory>(
slots: InventorySlotCompound<T>, slots: InventorySlotCompound<T>,
icon: ItemStack, icon: ItemStack,
shouldChange: ((GUIClickEvent<T>) -> Boolean)? = null, shouldChange: ((GUIClickEvent<T>) -> Boolean)? = null,
onChange: ((GUIClickEvent<T>) -> Unit)? = null onChange: ((GUIClickEvent<T>) -> Unit)? = null,
) = defineSlots( ) = defineSlots(
slots, GUIButtonPageChange( slots, GUIButtonPageChange(
icon, icon,
@@ -211,7 +203,7 @@ class GUIPageBuilder<T : ForInventory>(
icon: ItemStack, icon: ItemStack,
newGUI: () -> GUI<*>, newGUI: () -> GUI<*>,
newPage: Int? = null, newPage: Int? = null,
onChange: ((GUIClickEvent<T>) -> Unit)? = null onChange: ((GUIClickEvent<T>) -> Unit)? = null,
) = defineSlots( ) = defineSlots(
slots, GUIButtonInventoryChange( slots, GUIButtonInventoryChange(
icon, icon,
@@ -235,7 +227,7 @@ class GUIPageBuilder<T : ForInventory>(
*/ */
fun <E> createCompound( fun <E> createCompound(
iconGenerator: (E) -> ItemStack, iconGenerator: (E) -> ItemStack,
onClick: ((clickEvent: GUIClickEvent<T>, element: E) -> Unit)? = null onClick: ((clickEvent: GUIClickEvent<T>, element: E) -> Unit)? = null,
) = GUISpaceCompound(type, iconGenerator, onClick) ) = GUISpaceCompound(type, iconGenerator, onClick)
/** /**
@@ -244,7 +236,7 @@ class GUIPageBuilder<T : ForInventory>(
*/ */
fun <E> compoundSpace( fun <E> compoundSpace(
slots: InventorySlotCompound<T>, slots: InventorySlotCompound<T>,
compound: GUISpaceCompound<T, E> compound: GUISpaceCompound<T, E>,
) { ) {
compound.addSlots(slots) compound.addSlots(slots)
defineSlots( defineSlots(
@@ -264,14 +256,11 @@ class GUIPageBuilder<T : ForInventory>(
*/ */
fun createSimpleRectCompound( fun createSimpleRectCompound(
fromSlot: SingleInventorySlot<out T>, fromSlot: SingleInventorySlot<out T>,
toSlot: SingleInventorySlot<out T> toSlot: SingleInventorySlot<out T>,
) = createRectCompound<GUICompoundElement<T>>( ) = createRectCompound<GUICompoundElement<T>>(
fromSlot, toSlot, fromSlot, toSlot,
iconGenerator = { it.icon }, iconGenerator = { it.icon },
onClick = { clickEvent, element -> element.onClick?.invoke(clickEvent) } onClick = { clickEvent, element -> element.onClick?.invoke(clickEvent) }
) )
/** /**
@@ -283,7 +272,7 @@ class GUIPageBuilder<T : ForInventory>(
fromSlot: SingleInventorySlot<out T>, fromSlot: SingleInventorySlot<out T>,
toSlot: SingleInventorySlot<out T>, toSlot: SingleInventorySlot<out T>,
iconGenerator: (E) -> ItemStack, iconGenerator: (E) -> ItemStack,
onClick: ((clickEvent: GUIClickEvent<T>, element: E) -> Unit)? = null onClick: ((clickEvent: GUIClickEvent<T>, element: E) -> Unit)? = null,
): GUIRectSpaceCompound<T, E> { ): GUIRectSpaceCompound<T, E> {
val rectSlotCompound = fromSlot rectTo toSlot val rectSlotCompound = fromSlot rectTo toSlot
return GUIRectSpaceCompound( return GUIRectSpaceCompound(
@@ -310,7 +299,7 @@ class GUIPageBuilder<T : ForInventory>(
compound: GUISpaceCompound<T, *>, compound: GUISpaceCompound<T, *>,
scrollDistance: Int = 1, scrollDistance: Int = 1,
scrollTimes: Int = 1, scrollTimes: Int = 1,
reverse: Boolean = false reverse: Boolean = false,
) = defineSlots( ) = defineSlots(
slots, slots,
GUISpaceCompoundScrollButton(icon, compound, scrollDistance.absoluteValue, scrollTimes, reverse) GUISpaceCompoundScrollButton(icon, compound, scrollDistance.absoluteValue, scrollTimes, reverse)
@@ -325,10 +314,9 @@ class GUIPageBuilder<T : ForInventory>(
icon: ItemStack, icon: ItemStack,
compound: GUIRectSpaceCompound<T, *>, compound: GUIRectSpaceCompound<T, *>,
scrollTimes: Int = 1, scrollTimes: Int = 1,
reverse: Boolean = false reverse: Boolean = false,
) = defineSlots( ) = defineSlots(
slots, slots,
GUISpaceCompoundScrollButton(icon, compound, scrollTimes, reverse) GUISpaceCompoundScrollButton(icon, compound, scrollTimes, reverse)
) )
} }

View File

@@ -6,5 +6,5 @@ import org.bukkit.event.inventory.InventoryClickEvent
class GUIClickEvent<T : ForInventory>( class GUIClickEvent<T : ForInventory>(
val bukkitEvent: InventoryClickEvent, val bukkitEvent: InventoryClickEvent,
val guiInstance: GUIInstance<T>, val guiInstance: GUIInstance<T>,
val player: Player val player: Player,
) )

View File

@@ -10,7 +10,7 @@ class SharedGUICreator<T : ForInventory> : GUICreator<T>() {
class IndividualGUICreator<T : ForInventory>( class IndividualGUICreator<T : ForInventory>(
private val resetOnClose: Boolean = true, private val resetOnClose: Boolean = true,
private val resetOnQuit: Boolean = true private val resetOnQuit: Boolean = true,
) : GUICreator<T>() { ) : GUICreator<T>() {
override fun createInstance(guiData: GUIData<T>) = GUIIndividual(guiData, resetOnClose, resetOnQuit) override fun createInstance(guiData: GUIData<T>) = GUIIndividual(guiData, resetOnClose, resetOnQuit)
} }

View File

@@ -5,21 +5,15 @@ import org.bukkit.inventory.ItemStack
abstract class GUISlot<T : ForInventory> { abstract class GUISlot<T : ForInventory> {
abstract fun onClick(clickEvent: GUIClickEvent<T>) abstract fun onClick(clickEvent: GUIClickEvent<T>)
} }
// ELEMENT // ELEMENT
abstract class GUIElement<T : ForInventory> : GUISlot<T>() { abstract class GUIElement<T : ForInventory> : GUISlot<T>() {
abstract fun getItemStack(slot: Int): ItemStack abstract fun getItemStack(slot: Int): ItemStack
final override fun onClick(clickEvent: GUIClickEvent<T>) { final override fun onClick(clickEvent: GUIClickEvent<T>) {
clickEvent.guiInstance.gui.data.generalOnClick?.invoke(clickEvent) clickEvent.guiInstance.gui.data.generalOnClick?.invoke(clickEvent)
onClickElement(clickEvent) onClickElement(clickEvent)
} }
protected abstract fun onClickElement(clickEvent: GUIClickEvent<T>) protected abstract fun onClickElement(clickEvent: GUIClickEvent<T>)
internal open fun startUsing(gui: GUIInstance<*>) {} internal open fun startUsing(gui: GUIInstance<*>) {}
internal open fun stopUsing(gui: GUIInstance<*>) {} internal open fun stopUsing(gui: GUIInstance<*>) {}
} }

View File

@@ -9,10 +9,8 @@ fun Player.openGUI(gui: GUI<*>, page: Int? = null): InventoryView? {
} }
internal fun Player.openGUIInstance(guiInstance: GUIInstance<*>, page: Int? = null): InventoryView? { internal fun Player.openGUIInstance(guiInstance: GUIInstance<*>, page: Int? = null): InventoryView? {
if (page != null) if (page != null)
guiInstance.loadPageUnsafe(page) guiInstance.loadPageUnsafe(page)
return openInventory(guiInstance.bukkitInventory) return openInventory(guiInstance.bukkitInventory)
} }

View File

@@ -7,9 +7,7 @@ import org.bukkit.event.inventory.*
import org.bukkit.inventory.Inventory import org.bukkit.inventory.Inventory
object GUIHolder : AutoCloseable { object GUIHolder : AutoCloseable {
private val registered = HashMap<Inventory, GUIInstance<ForInventory>>() private val registered = HashMap<Inventory, GUIInstance<ForInventory>>()
fun register(guiInstance: GUIInstance<ForInventory>) { fun register(guiInstance: GUIInstance<ForInventory>) {
registered[guiInstance.bukkitInventory] = guiInstance registered[guiInstance.bukkitInventory] = guiInstance
} }
@@ -19,13 +17,9 @@ object GUIHolder : AutoCloseable {
} }
init { init {
listen<InventoryClickEvent> { listen<InventoryClickEvent> {
val clickedInv = it.clickedInventory ?: return@listen val clickedInv = it.clickedInventory ?: return@listen
val gui = registered[clickedInv] ?: return@listen val gui = registered[clickedInv] ?: return@listen
val player = it.playerOrCancel ?: return@listen val player = it.playerOrCancel ?: return@listen
if (gui.isInMove) { if (gui.isInMove) {
@@ -39,26 +33,20 @@ object GUIHolder : AutoCloseable {
} }
else else
it.isCancelled = true it.isCancelled = true
} }
listen<InventoryDragEvent> { listen<InventoryDragEvent> {
val inv = it.inventory val inv = it.inventory
val gui = registered[inv] ?: return@listen val gui = registered[inv] ?: return@listen
val player = it.playerOrCancel ?: return@listen val player = it.playerOrCancel ?: return@listen
var ifCancel = false var ifCancel = false
for (slotIndex in it.inventorySlots) { for (slotIndex in it.inventorySlots) {
val slot = gui.currentPage.slots[slotIndex] val slot = gui.currentPage.slots[slotIndex]
if (slot == null) { if (slot == null) {
ifCancel = true ifCancel = true
break break
} }
val clickEvent = InventoryClickEvent( val clickEvent = InventoryClickEvent(
it.view, it.view,
it.view.getSlotType(slotIndex), it.view.getSlotType(slotIndex),
@@ -73,26 +61,21 @@ object GUIHolder : AutoCloseable {
ifCancel = true ifCancel = true
break break
} }
} }
if (ifCancel) if (ifCancel)
it.isCancelled = true it.isCancelled = true
} }
} }
override fun close() { override fun close() {
registered.keys.forEach { it.closeForViewers() } registered.keys.forEach { it.closeForViewers() }
registered.clear() registered.clear()
} }
} }
private val InventoryAction.isGUIClick private val InventoryAction.isGUIClick
get() = this == InventoryAction.PICKUP_ALL || this == InventoryAction.PICKUP_HALF get() = this == InventoryAction.PICKUP_ALL || this == InventoryAction.PICKUP_HALF
private val InventoryInteractEvent.playerOrCancel: Player? private val InventoryInteractEvent.playerOrCancel: Player?
get() = (whoClicked as? Player) ?: kotlin.run { get() = (whoClicked as? Player) ?: kotlin.run {
isCancelled = true isCancelled = true

View File

@@ -4,5 +4,5 @@ class GUIPage<T : ForInventory>(
val number: Int, val number: Int,
internal val slots: Map<Int, GUISlot<T>>, internal val slots: Map<Int, GUISlot<T>>,
val transitionTo: PageChangeEffect?, val transitionTo: PageChangeEffect?,
val transitionFrom: PageChangeEffect? val transitionFrom: PageChangeEffect?,
) )

View File

@@ -3,7 +3,6 @@ package net.axay.kspigot.gui
import net.axay.kspigot.runnables.task import net.axay.kspigot.runnables.task
abstract class GUIPageChangeCalculator { abstract class GUIPageChangeCalculator {
abstract fun calculateNewPage(currentPage: Int, pages: Collection<Int>): Int? abstract fun calculateNewPage(currentPage: Int, pages: Collection<Int>): Int?
object GUIPreviousPageCalculator : GUIPageChangeCalculator() { object GUIPreviousPageCalculator : GUIPageChangeCalculator() {
@@ -19,7 +18,6 @@ abstract class GUIPageChangeCalculator {
class GUIConsistentPageCalculator(private val toPage: Int) : GUIPageChangeCalculator() { class GUIConsistentPageCalculator(private val toPage: Int) : GUIPageChangeCalculator() {
override fun calculateNewPage(currentPage: Int, pages: Collection<Int>) = toPage override fun calculateNewPage(currentPage: Int, pages: Collection<Int>) = toPage
} }
} }
enum class PageChangeEffect { enum class PageChangeEffect {
@@ -31,7 +29,7 @@ enum class PageChangeEffect {
} }
enum class InventoryChangeEffect( enum class InventoryChangeEffect(
val effect: PageChangeEffect val effect: PageChangeEffect,
) { ) {
INSTANT(PageChangeEffect.INSTANT) INSTANT(PageChangeEffect.INSTANT)
} }
@@ -46,18 +44,14 @@ fun GUIInstance<*>.gotoPage(page: Int, overrideEffect: PageChangeEffect? = null)
internal fun GUIInstance<*>.changePage( internal fun GUIInstance<*>.changePage(
effect: PageChangeEffect, effect: PageChangeEffect,
fromPage: GUIPage<*>, fromPage: GUIPage<*>,
toPage: GUIPage<*> toPage: GUIPage<*>,
) { ) {
val fromPageInt = fromPage.number val fromPageInt = fromPage.number
val toPageInt = toPage.number val toPageInt = toPage.number
when (effect) { when (effect) {
PageChangeEffect.INSTANT -> loadPageUnsafe(toPage) PageChangeEffect.INSTANT -> loadPageUnsafe(toPage)
PageChangeEffect.SLIDE_HORIZONTALLY -> { PageChangeEffect.SLIDE_HORIZONTALLY -> {
val width = gui.data.guiType.dimensions.width val width = gui.data.guiType.dimensions.width
changePageEffect(fromPageInt, toPageInt, width) { currentOffset, ifInverted -> changePageEffect(fromPageInt, toPageInt, width) { currentOffset, ifInverted ->
@@ -69,11 +63,8 @@ internal fun GUIInstance<*>.changePage(
loadPageUnsafe(toPage, offsetHorizontally = width - currentOffset) loadPageUnsafe(toPage, offsetHorizontally = width - currentOffset)
} }
} }
} }
PageChangeEffect.SLIDE_VERTICALLY -> { PageChangeEffect.SLIDE_VERTICALLY -> {
val height = gui.data.guiType.dimensions.height val height = gui.data.guiType.dimensions.height
changePageEffect(fromPageInt, toPageInt, height) { currentOffset, ifInverted -> changePageEffect(fromPageInt, toPageInt, height) { currentOffset, ifInverted ->
@@ -85,11 +76,8 @@ internal fun GUIInstance<*>.changePage(
loadPageUnsafe(toPage, offsetVertically = height - currentOffset) loadPageUnsafe(toPage, offsetVertically = height - currentOffset)
} }
} }
} }
PageChangeEffect.SWIPE_HORIZONTALLY -> { PageChangeEffect.SWIPE_HORIZONTALLY -> {
val width = gui.data.guiType.dimensions.width val width = gui.data.guiType.dimensions.width
changePageEffect(fromPageInt, toPageInt, width) { currentOffset, ifInverted -> changePageEffect(fromPageInt, toPageInt, width) { currentOffset, ifInverted ->
@@ -99,11 +87,8 @@ internal fun GUIInstance<*>.changePage(
loadPageUnsafe(toPage, offsetHorizontally = width - currentOffset) loadPageUnsafe(toPage, offsetHorizontally = width - currentOffset)
} }
} }
} }
PageChangeEffect.SWIPE_VERTICALLY -> { PageChangeEffect.SWIPE_VERTICALLY -> {
val height = gui.data.guiType.dimensions.height val height = gui.data.guiType.dimensions.height
changePageEffect(fromPageInt, toPageInt, height) { currentOffset, ifInverted -> changePageEffect(fromPageInt, toPageInt, height) { currentOffset, ifInverted ->
@@ -113,16 +98,14 @@ internal fun GUIInstance<*>.changePage(
loadPageUnsafe(toPage, offsetVertically = height - currentOffset) loadPageUnsafe(toPage, offsetVertically = height - currentOffset)
} }
} }
} }
} }
} }
internal fun GUIInstance<*>.changeGUI( internal fun GUIInstance<*>.changeGUI(
effect: InventoryChangeEffect, effect: InventoryChangeEffect,
fromPage: GUIPage<*>, fromPage: GUIPage<*>,
toPage: GUIPage<*> toPage: GUIPage<*>,
) = changePage(effect.effect, fromPage, toPage) ) = changePage(effect.effect, fromPage, toPage)
private inline fun changePageEffect( private inline fun changePageEffect(
@@ -131,20 +114,15 @@ private inline fun changePageEffect(
doFor: Int, doFor: Int,
crossinline effect: (currentOffset: Int, ifInverted: Boolean) -> Unit, crossinline effect: (currentOffset: Int, ifInverted: Boolean) -> Unit,
) { ) {
val ifInverted = fromPage >= toPage val ifInverted = fromPage >= toPage
var currentOffset = 1 var currentOffset = 1
task( task(
sync = true, sync = true,
period = 1, period = 1,
howOften = doFor.toLong() howOften = doFor.toLong()
) { ) {
effect.invoke(currentOffset, ifInverted) effect.invoke(currentOffset, ifInverted)
currentOffset++ currentOffset++
} }
} }

View File

@@ -5,11 +5,8 @@ package net.axay.kspigot.gui
import net.axay.kspigot.languageextensions.kotlinextensions.MinMaxPair import net.axay.kspigot.languageextensions.kotlinextensions.MinMaxPair
// INVENTORY // INVENTORY
data class InventoryDimensions(val width: Int, val height: Int) { data class InventoryDimensions(val width: Int, val height: Int) {
val slotAmount = width * height val slotAmount = width * height
val invSlots by lazy { val invSlots by lazy {
ArrayList<InventorySlot>().apply { ArrayList<InventorySlot>().apply {
(1..height).forEach { row -> (1..height).forEach { row ->
@@ -19,7 +16,6 @@ data class InventoryDimensions(val width: Int, val height: Int) {
} }
} }
} }
val invSlotsWithRealSlots by lazy { val invSlotsWithRealSlots by lazy {
HashMap<InventorySlot, Int>().apply { HashMap<InventorySlot, Int>().apply {
invSlots.forEach { curSlot -> invSlots.forEach { curSlot ->
@@ -27,15 +23,10 @@ data class InventoryDimensions(val width: Int, val height: Int) {
} }
} }
} }
val realSlots by lazy { invSlotsWithRealSlots.values } val realSlots by lazy { invSlotsWithRealSlots.values }
} }
// SLOTS // SLOTS
data class InventorySlot(val row: Int, val slotInRow: Int) : Comparable<InventorySlot> { data class InventorySlot(val row: Int, val slotInRow: Int) : Comparable<InventorySlot> {
companion object { companion object {
fun fromRealSlot(realSlot: Int, dimensions: InventoryDimensions) = fun fromRealSlot(realSlot: Int, dimensions: InventoryDimensions) =
dimensions.invSlotsWithRealSlots.toList().find { it.second == realSlot }?.first dimensions.invSlotsWithRealSlots.toList().find { it.second == realSlot }?.first
@@ -65,28 +56,21 @@ data class InventorySlot(val row: Int, val slotInRow: Int) : Comparable<Inventor
row + offsetVertically, row + offsetVertically,
slotInRow + offsetHorizontally slotInRow + offsetHorizontally
) )
} }
interface InventorySlotCompound<out T : ForInventory> { interface InventorySlotCompound<out T : ForInventory> {
fun withInvType(invType: GUIType<T>): Collection<InventorySlot> fun withInvType(invType: GUIType<T>): Collection<InventorySlot>
fun realSlotsWithInvType(invType: GUIType<T>) = fun realSlotsWithInvType(invType: GUIType<T>) =
withInvType(invType).mapNotNull { it.realSlotIn(invType.dimensions) } withInvType(invType).mapNotNull { it.realSlotIn(invType.dimensions) }
} }
open class SingleInventorySlot<T : ForInventory> internal constructor( open class SingleInventorySlot<T : ForInventory> internal constructor(
val inventorySlot: InventorySlot val inventorySlot: InventorySlot,
) : InventorySlotCompound<T> { ) : InventorySlotCompound<T> {
constructor(row: Int, slotInRow: Int) : this(InventorySlot(row, slotInRow)) constructor(row: Int, slotInRow: Int) : this(InventorySlot(row, slotInRow))
private val slotAsList = listOf(inventorySlot) private val slotAsList = listOf(inventorySlot)
override fun withInvType(invType: GUIType<T>) = slotAsList override fun withInvType(invType: GUIType<T>) = slotAsList
} }
internal enum class InventorySlotRangeType { internal enum class InventorySlotRangeType {
@@ -95,14 +79,10 @@ internal enum class InventorySlotRangeType {
} }
class InventorySlotRange<out T : ForInventory> internal constructor( class InventorySlotRange<out T : ForInventory> internal constructor(
startSlot: SingleInventorySlot<out T>, startSlot: SingleInventorySlot<out T>,
endSlot: SingleInventorySlot<out T>, endSlot: SingleInventorySlot<out T>,
private val type: InventorySlotRangeType,
private val type: InventorySlotRangeType
) : InventorySlotCompound<T>, ClosedRange<InventorySlot> { ) : InventorySlotCompound<T>, ClosedRange<InventorySlot> {
override val start: InventorySlot override val start: InventorySlot
override val endInclusive: InventorySlot override val endInclusive: InventorySlot
@@ -114,7 +94,6 @@ class InventorySlotRange<out T : ForInventory> internal constructor(
override fun withInvType(invType: GUIType<T>) = LinkedHashSet<InventorySlot>().apply { override fun withInvType(invType: GUIType<T>) = LinkedHashSet<InventorySlot>().apply {
when (type) { when (type) {
InventorySlotRangeType.RECTANGLE -> { InventorySlotRangeType.RECTANGLE -> {
// all possible combinations between the two slots // all possible combinations between the two slots
// -> form a rectangle // -> form a rectangle
@@ -122,7 +101,6 @@ class InventorySlotRange<out T : ForInventory> internal constructor(
for (slotInRow in start.slotInRow..endInclusive.slotInRow) for (slotInRow in start.slotInRow..endInclusive.slotInRow)
this += InventorySlot(row, slotInRow) this += InventorySlot(row, slotInRow)
} }
InventorySlotRangeType.LINEAR -> { InventorySlotRangeType.LINEAR -> {
if (endInclusive.row > start.row) { if (endInclusive.row > start.row) {
// from start --->| to end of row // from start --->| to end of row
@@ -142,10 +120,8 @@ class InventorySlotRange<out T : ForInventory> internal constructor(
this += InventorySlot(start.row, slotInRow) this += InventorySlot(start.row, slotInRow)
} }
} }
} }
} }
} }
/** /**
@@ -163,33 +139,27 @@ infix fun <T : ForInventory> SingleInventorySlot<out T>.rectTo(slot: SingleInven
InventorySlotRange(this, slot, InventorySlotRangeType.RECTANGLE) InventorySlotRange(this, slot, InventorySlotRangeType.RECTANGLE)
class InventoryRowSlots<T : ForInventory> internal constructor( class InventoryRowSlots<T : ForInventory> internal constructor(
val row: Int val row: Int,
) : InventorySlotCompound<T> { ) : InventorySlotCompound<T> {
override fun withInvType(invType: GUIType<T>) = HashSet<InventorySlot>().apply { override fun withInvType(invType: GUIType<T>) = HashSet<InventorySlot>().apply {
for (slotInRow in 1..invType.dimensions.width) for (slotInRow in 1..invType.dimensions.width)
this += InventorySlot(row, slotInRow) this += InventorySlot(row, slotInRow)
} }
} }
class InventoryColumnSlots<T : ForInventory> internal constructor( class InventoryColumnSlots<T : ForInventory> internal constructor(
val column: Int val column: Int,
) : InventorySlotCompound<T> { ) : InventorySlotCompound<T> {
override fun withInvType(invType: GUIType<T>) = HashSet<InventorySlot>().apply { override fun withInvType(invType: GUIType<T>) = HashSet<InventorySlot>().apply {
for (row in 1..invType.dimensions.height) for (row in 1..invType.dimensions.height)
this += InventorySlot(row, column) this += InventorySlot(row, column)
} }
} }
class InventoryBorderSlots<T : ForInventory> internal constructor( class InventoryBorderSlots<T : ForInventory> internal constructor(
val padding: Int val padding: Int,
) : InventorySlotCompound<T> { ) : InventorySlotCompound<T> {
override fun withInvType(invType: GUIType<T>) = HashSet<InventorySlot>().apply { override fun withInvType(invType: GUIType<T>) = HashSet<InventorySlot>().apply {
val dimensions = invType.dimensions val dimensions = invType.dimensions
for (currentPadding in 0 until padding) { for (currentPadding in 0 until padding) {
@@ -202,39 +172,30 @@ class InventoryBorderSlots<T : ForInventory> internal constructor(
this += InventorySlot(row, dimensions.width) this += InventorySlot(row, dimensions.width)
} }
} }
} }
} }
class InventoryCornerSlots<T : ForInventory> internal constructor( class InventoryCornerSlots<T : ForInventory> internal constructor(
val ifBottomLeft: Boolean = false, val ifBottomLeft: Boolean = false,
val ifBottomRight: Boolean = false, val ifBottomRight: Boolean = false,
val ifTopLeft: Boolean = false, val ifTopLeft: Boolean = false,
val ifTopRight: Boolean = false val ifTopRight: Boolean = false,
) : InventorySlotCompound<T> { ) : InventorySlotCompound<T> {
override fun withInvType(invType: GUIType<T>) = HashSet<InventorySlot>().apply { override fun withInvType(invType: GUIType<T>) = HashSet<InventorySlot>().apply {
val dimensions = invType.dimensions val dimensions = invType.dimensions
if (ifBottomLeft) this += InventorySlot(1, 1) if (ifBottomLeft) this += InventorySlot(1, 1)
if (ifBottomRight) this += InventorySlot(1, dimensions.width) if (ifBottomRight) this += InventorySlot(1, dimensions.width)
if (ifTopLeft) this += InventorySlot(dimensions.height, 1) if (ifTopLeft) this += InventorySlot(dimensions.height, 1)
if (ifTopRight) this += InventorySlot(dimensions.height, dimensions.width) if (ifTopRight) this += InventorySlot(dimensions.height, dimensions.width)
} }
} }
class InventoryAllSlots<T : ForInventory> : InventorySlotCompound<T> { class InventoryAllSlots<T : ForInventory> : InventorySlotCompound<T> {
override fun withInvType(invType: GUIType<T>) = invType.dimensions.invSlots override fun withInvType(invType: GUIType<T>) = invType.dimensions.invSlots
} }
// SLOT TYPE SAFETY // SLOT TYPE SAFETY
// COLUMNS // COLUMNS
interface ForColumnOne : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine interface ForColumnOne : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine
interface ForColumnTwo : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine interface ForColumnTwo : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine
interface ForColumnThree : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine interface ForColumnThree : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine
@@ -244,9 +205,7 @@ interface ForColumnSix : ForInventoryWidthNine
interface ForColumnSeven : ForInventoryWidthNine interface ForColumnSeven : ForInventoryWidthNine
interface ForColumnEight : ForInventoryWidthNine interface ForColumnEight : ForInventoryWidthNine
interface ForColumnNine : ForInventoryWidthNine interface ForColumnNine : ForInventoryWidthNine
// ROWS // ROWS
interface ForRowOne : ForInventoryOneByNine, ForInventoryTwoByNine, ForInventoryThreeByNine, ForInventoryFourByNine, interface ForRowOne : ForInventoryOneByNine, ForInventoryTwoByNine, ForInventoryThreeByNine, ForInventoryFourByNine,
ForInventoryFiveByNine, ForInventorySixByNine ForInventoryFiveByNine, ForInventorySixByNine
@@ -273,9 +232,7 @@ interface ForRowThreeSlotOneToThree : ForRowThree, ForInventoryThreeByThree
interface ForCompleteRowOne : ForRowOne, ForRowOneSlotOneToThree, ForRowOneSlotFourToFive interface ForCompleteRowOne : ForRowOne, ForRowOneSlotOneToThree, ForRowOneSlotFourToFive
interface ForCompleteRowTwo : ForRowTwo, ForRowTwoSlotOneToThree interface ForCompleteRowTwo : ForRowTwo, ForRowTwoSlotOneToThree
interface ForCompleteRowThree : ForRowThree, ForRowThreeSlotOneToThree interface ForCompleteRowThree : ForRowThree, ForRowThreeSlotOneToThree
object Slots { object Slots {
// ROW ONE // ROW ONE
val RowOneSlotOne = SingleInventorySlot<ForRowOneSlotOneToThree>(1, 1) val RowOneSlotOne = SingleInventorySlot<ForRowOneSlotOneToThree>(1, 1)
val RowOneSlotTwo = SingleInventorySlot<ForRowOneSlotOneToThree>(1, 2) val RowOneSlotTwo = SingleInventorySlot<ForRowOneSlotOneToThree>(1, 2)
@@ -380,5 +337,4 @@ object Slots {
// ALL // ALL
val All = InventoryAllSlots<ForEveryInventory>() val All = InventoryAllSlots<ForEveryInventory>()
} }

View File

@@ -9,11 +9,9 @@ import org.bukkit.inventory.InventoryHolder
class GUIType<in T : ForInventory>( class GUIType<in T : ForInventory>(
val dimensions: InventoryDimensions, val dimensions: InventoryDimensions,
val bukkitType: InventoryType? = null val bukkitType: InventoryType? = null,
) { ) {
companion object { companion object {
val ONE_BY_NINE = GUIType<ForInventoryOneByNine>(InventoryDimensions(9, 1)) val ONE_BY_NINE = GUIType<ForInventoryOneByNine>(InventoryDimensions(9, 1))
val TWO_BY_NINE = GUIType<ForInventoryTwoByNine>(InventoryDimensions(9, 2)) val TWO_BY_NINE = GUIType<ForInventoryTwoByNine>(InventoryDimensions(9, 2))
val THREE_BY_NINE = GUIType<ForInventoryThreeByNine>(InventoryDimensions(9, 3)) val THREE_BY_NINE = GUIType<ForInventoryThreeByNine>(InventoryDimensions(9, 3))
@@ -24,7 +22,6 @@ class GUIType<in T : ForInventory>(
GUIType<ForInventoryOneByFive>(InventoryDimensions(5, 1), bukkitType = InventoryType.HOPPER) GUIType<ForInventoryOneByFive>(InventoryDimensions(5, 1), bukkitType = InventoryType.HOPPER)
val THREE_BY_THREE = val THREE_BY_THREE =
GUIType<ForInventoryThreeByThree>(InventoryDimensions(3, 3), bukkitType = InventoryType.DROPPER) GUIType<ForInventoryThreeByThree>(InventoryDimensions(3, 3), bukkitType = InventoryType.DROPPER)
} }
fun createBukkitInv(holder: InventoryHolder? = null, title: String? = null): Inventory { fun createBukkitInv(holder: InventoryHolder? = null, title: String? = null): Inventory {
@@ -34,13 +31,9 @@ class GUIType<in T : ForInventory>(
else -> Bukkit.createInventory(holder, dimensions.slotAmount, realTitle) else -> Bukkit.createInventory(holder, dimensions.slotAmount, realTitle)
} }
} }
} }
// INVENTORY TYPE SAFETY // INVENTORY TYPE SAFETY
interface ForInventory interface ForInventory
interface ForInventoryThreeByThree : ForInventoryThreeByNine interface ForInventoryThreeByThree : ForInventoryThreeByNine
interface ForInventoryOneByFive : ForInventoryOneByNine interface ForInventoryOneByFive : ForInventoryOneByNine
interface ForInventoryOneByNine : ForInventoryTwoByNine interface ForInventoryOneByNine : ForInventoryTwoByNine
@@ -49,7 +42,6 @@ interface ForInventoryThreeByNine : ForInventoryFourByNine
interface ForInventoryFourByNine : ForInventoryFiveByNine interface ForInventoryFourByNine : ForInventoryFiveByNine
interface ForInventoryFiveByNine : ForInventorySixByNine interface ForInventoryFiveByNine : ForInventorySixByNine
interface ForInventorySixByNine : ForInventory interface ForInventorySixByNine : ForInventory
interface ForEveryInventory interface ForEveryInventory
: ForInventoryOneByNine, ForInventoryTwoByNine, ForInventoryThreeByNine, : ForInventoryOneByNine, ForInventoryTwoByNine, ForInventoryThreeByNine,
ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine, ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine,

View File

@@ -9,12 +9,9 @@ open class GUIButton<T : ForInventory>(
private val icon: ItemStack, private val icon: ItemStack,
private val action: (GUIClickEvent<T>) -> Unit, private val action: (GUIClickEvent<T>) -> Unit,
) : GUIElement<T>() { ) : GUIElement<T>() {
final override fun getItemStack(slot: Int) = icon final override fun getItemStack(slot: Int) = icon
override fun onClickElement(clickEvent: GUIClickEvent<T>) { override fun onClickElement(clickEvent: GUIClickEvent<T>) {
clickEvent.bukkitEvent.isCancelled = true clickEvent.bukkitEvent.isCancelled = true
action(clickEvent) action(clickEvent)
} }
} }

View File

@@ -7,14 +7,11 @@ class GUIButtonInventoryChange<T : ForInventory>(
icon: ItemStack, icon: ItemStack,
changeToGUICallback: () -> GUI<*>, changeToGUICallback: () -> GUI<*>,
changeToPageInt: Int?, changeToPageInt: Int?,
onChange: ((GUIClickEvent<T>) -> Unit)? onChange: ((GUIClickEvent<T>) -> Unit)?,
) : GUIButton<T>(icon, { ) : GUIButton<T>(icon, {
val changeToGUI = changeToGUICallback.invoke().getInstance(it.player) val changeToGUI = changeToGUICallback.invoke().getInstance(it.player)
val effect = (changeToGUI.gui.data.transitionTo ?: it.guiInstance.gui.data.transitionFrom) val effect = (changeToGUI.gui.data.transitionTo ?: it.guiInstance.gui.data.transitionFrom)
?: InventoryChangeEffect.INSTANT ?: InventoryChangeEffect.INSTANT
val changeToPage = changeToGUI.getPage(changeToPageInt) ?: changeToGUI.currentPage val changeToPage = changeToGUI.getPage(changeToPageInt) ?: changeToGUI.currentPage
changeToGUI.changeGUI(effect, it.guiInstance.currentPage, changeToPage) changeToGUI.changeGUI(effect, it.guiInstance.currentPage, changeToPage)
@@ -22,5 +19,4 @@ class GUIButtonInventoryChange<T : ForInventory>(
it.player.openGUIInstance(changeToGUI) it.player.openGUIInstance(changeToGUI)
onChange?.invoke(it) onChange?.invoke(it)
}) })

View File

@@ -7,9 +7,8 @@ class GUIButtonPageChange<T : ForInventory>(
icon: ItemStack, icon: ItemStack,
calculator: GUIPageChangeCalculator, calculator: GUIPageChangeCalculator,
shouldChange: ((GUIClickEvent<T>) -> Boolean)?, shouldChange: ((GUIClickEvent<T>) -> Boolean)?,
onChange: ((GUIClickEvent<T>) -> Unit)? onChange: ((GUIClickEvent<T>) -> Unit)?,
) : GUIButton<T>(icon, { ) : GUIButton<T>(icon, {
val currentPage = it.guiInstance.currentPage val currentPage = it.guiInstance.currentPage
val newPage = it.guiInstance.getPage( val newPage = it.guiInstance.getPage(
calculator.calculateNewPage( calculator.calculateNewPage(
@@ -18,7 +17,6 @@ class GUIButtonPageChange<T : ForInventory>(
) )
) )
if (newPage != null) { if (newPage != null) {
val changePage = shouldChange?.invoke(it) ?: true val changePage = shouldChange?.invoke(it) ?: true
if (changePage) { if (changePage) {
@@ -29,5 +27,4 @@ class GUIButtonPageChange<T : ForInventory>(
onChange?.invoke(it) onChange?.invoke(it)
} }
} }
}) })

View File

@@ -6,13 +6,10 @@ import net.axay.kspigot.gui.GUIElement
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class GUIPlaceholder<T : ForInventory>( class GUIPlaceholder<T : ForInventory>(
private val icon: ItemStack private val icon: ItemStack,
) : GUIElement<T>() { ) : GUIElement<T>() {
override fun getItemStack(slot: Int) = icon override fun getItemStack(slot: Int) = icon
override fun onClickElement(clickEvent: GUIClickEvent<T>) { override fun onClickElement(clickEvent: GUIClickEvent<T>) {
clickEvent.bukkitEvent.isCancelled = true clickEvent.bukkitEvent.isCancelled = true
} }
} }

View File

@@ -7,78 +7,58 @@ import org.bukkit.Material
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class GUISpaceCompoundElement<T : ForInventory, E> internal constructor( class GUISpaceCompoundElement<T : ForInventory, E> internal constructor(
private val compound: AbstractGUISpaceCompound<T, E> private val compound: AbstractGUISpaceCompound<T, E>,
) : GUIElement<T>() { ) : GUIElement<T>() {
override fun getItemStack(slot: Int) = compound.getItemStack(slot) override fun getItemStack(slot: Int) = compound.getItemStack(slot)
override fun onClickElement(clickEvent: GUIClickEvent<T>) { override fun onClickElement(clickEvent: GUIClickEvent<T>) {
compound.onClickElement(clickEvent) compound.onClickElement(clickEvent)
} }
// the following two methods register and unregister the instance // the following two methods register and unregister the instance
// for each compound element, but that is ok because it gets // for each compound element, but that is ok because it gets
// added/removed to/from a HashSet // added/removed to/from a HashSet
override fun startUsing(gui: GUIInstance<*>) = compound.registerGUI(gui) override fun startUsing(gui: GUIInstance<*>) = compound.registerGUI(gui)
override fun stopUsing(gui: GUIInstance<*>) = compound.unregisterGUI(gui) override fun stopUsing(gui: GUIInstance<*>) = compound.unregisterGUI(gui)
} }
class GUIRectSpaceCompound<T : ForInventory, E>( class GUIRectSpaceCompound<T : ForInventory, E>(
invType: GUIType<T>, invType: GUIType<T>,
iconGenerator: (E) -> ItemStack, iconGenerator: (E) -> ItemStack,
onClick: ((GUIClickEvent<T>, E) -> Unit)?, onClick: ((GUIClickEvent<T>, E) -> Unit)?,
internal val compoundWidth: Int internal val compoundWidth: Int,
) : AbstractGUISpaceCompound<T, E>(invType, iconGenerator, onClick) { ) : AbstractGUISpaceCompound<T, E>(invType, iconGenerator, onClick) {
override fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int) = override fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int) =
(internalSlotsSize + newProgress <= contentSize + (compoundWidth - (contentSize % compoundWidth))) (internalSlotsSize + newProgress <= contentSize + (compoundWidth - (contentSize % compoundWidth)))
} }
class GUISpaceCompound<T : ForInventory, E>( class GUISpaceCompound<T : ForInventory, E>(
invType: GUIType<T>, invType: GUIType<T>,
iconGenerator: (E) -> ItemStack, iconGenerator: (E) -> ItemStack,
onClick: ((GUIClickEvent<T>, E) -> Unit)? onClick: ((GUIClickEvent<T>, E) -> Unit)?,
) : AbstractGUISpaceCompound<T, E>(invType, iconGenerator, onClick) { ) : AbstractGUISpaceCompound<T, E>(invType, iconGenerator, onClick) {
override fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int) = false override fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int) = false
} }
abstract class AbstractGUISpaceCompound<T : ForInventory, E> internal constructor( abstract class AbstractGUISpaceCompound<T : ForInventory, E> internal constructor(
val guiType: GUIType<T>, val guiType: GUIType<T>,
private val iconGenerator: (E) -> ItemStack, private val iconGenerator: (E) -> ItemStack,
private val onClick: ((GUIClickEvent<T>, E) -> Unit)? private val onClick: ((GUIClickEvent<T>, E) -> Unit)?,
) { ) {
private val content = ArrayList<E>() private val content = ArrayList<E>()
private var currentContent: List<E> = emptyList() private var currentContent: List<E> = emptyList()
private val internalSlots: MutableList<Int> = ArrayList() private val internalSlots: MutableList<Int> = ArrayList()
private var scrollProgress: Int = 0 private var scrollProgress: Int = 0
private var contentSort: () -> Unit = { } private var contentSort: () -> Unit = { }
private val registeredGUIs = HashSet<GUIInstance<*>>() private val registeredGUIs = HashSet<GUIInstance<*>>()
private fun contentAtSlot(slot: Int) = currentContent.getOrNull(internalSlots.indexOf(slot)) private fun contentAtSlot(slot: Int) = currentContent.getOrNull(internalSlots.indexOf(slot))
private fun recalculateCurrentContent() { private fun recalculateCurrentContent() {
if (scrollProgress > content.size) if (scrollProgress > content.size)
throw IllegalStateException("The scrollProgress is greater than the content size.") throw IllegalStateException("The scrollProgress is greater than the content size.")
// avoid IndexOutOfBoundsException // avoid IndexOutOfBoundsException
var sliceUntil = internalSlots.size + scrollProgress var sliceUntil = internalSlots.size + scrollProgress
if (sliceUntil > content.lastIndex) if (sliceUntil > content.lastIndex)
sliceUntil = content.size sliceUntil = content.size
currentContent = content.slice(scrollProgress until sliceUntil) currentContent = content.slice(scrollProgress until sliceUntil)
} }
private fun updateOpenGUIs() { private fun updateOpenGUIs() {
@@ -88,7 +68,6 @@ abstract class AbstractGUISpaceCompound<T : ForInventory, E> internal constructo
internal fun scroll(distance: Int): Boolean { internal fun scroll(distance: Int): Boolean {
val value = scrollProgress + distance val value = scrollProgress + distance
return if (value >= 0) { return if (value >= 0) {
// always scroll if the end of the content is not reached // always scroll if the end of the content is not reached
val ifScroll = if (internalSlots.size + value <= content.size) true val ifScroll = if (internalSlots.size + value <= content.size) true
// scroll further if the width of the compound is defined and the last line can be filled up // scroll further if the width of the compound is defined and the last line can be filled up
@@ -100,12 +79,10 @@ abstract class AbstractGUISpaceCompound<T : ForInventory, E> internal constructo
updateOpenGUIs() updateOpenGUIs()
true true
} else false } else false
} else false } else false
} }
internal abstract fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int): Boolean internal abstract fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int): Boolean
internal fun getItemStack(slot: Int): ItemStack { internal fun getItemStack(slot: Int): ItemStack {
return contentAtSlot(slot)?.let { return@let iconGenerator.invoke(it) } return contentAtSlot(slot)?.let { return@let iconGenerator.invoke(it) }
?: ItemStack(Material.AIR) ?: ItemStack(Material.AIR)
@@ -191,7 +168,6 @@ abstract class AbstractGUISpaceCompound<T : ForInventory, E> internal constructo
recalculateCurrentContent() recalculateCurrentContent()
updateOpenGUIs() updateOpenGUIs()
} }
} }
/** /**
@@ -203,5 +179,5 @@ abstract class AbstractGUISpaceCompound<T : ForInventory, E> internal constructo
*/ */
open class GUICompoundElement<T : ForInventory>( open class GUICompoundElement<T : ForInventory>(
internal val icon: ItemStack, internal val icon: ItemStack,
internal val onClick: ((GUIClickEvent<T>) -> Unit)? = null internal val onClick: ((GUIClickEvent<T>) -> Unit)? = null,
) )

View File

@@ -5,16 +5,12 @@ import net.axay.kspigot.runnables.task
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class GUISpaceCompoundScrollButton<T : ForInventory>( class GUISpaceCompoundScrollButton<T : ForInventory>(
icon: ItemStack, icon: ItemStack,
private val compound: AbstractGUISpaceCompound<T, *>, private val compound: AbstractGUISpaceCompound<T, *>,
private val scrollDistance: Int, private val scrollDistance: Int,
private val scrollTimes: Int, private val scrollTimes: Int,
private val reverse: Boolean = false private val reverse: Boolean = false,
) : GUIButton<T>(icon, { ) : GUIButton<T>(icon, {
if (scrollTimes > 1) { if (scrollTimes > 1) {
task( task(
period = 1, period = 1,
@@ -25,14 +21,11 @@ class GUISpaceCompoundScrollButton<T : ForInventory>(
} }
} else if (scrollTimes == 1) } else if (scrollTimes == 1)
if (reverse) compound.scroll(-scrollDistance) else compound.scroll(scrollDistance) if (reverse) compound.scroll(-scrollDistance) else compound.scroll(scrollDistance)
}) { }) {
constructor( constructor(
icon: ItemStack, icon: ItemStack,
compound: GUIRectSpaceCompound<T, *>, compound: GUIRectSpaceCompound<T, *>,
scrollTimes: Int = 1, scrollTimes: Int = 1,
reverse: Boolean = false reverse: Boolean = false,
) : this(icon, compound, compound.compoundWidth, scrollTimes, reverse) ) : this(icon, compound, compound.compoundWidth, scrollTimes, reverse)
} }

View File

@@ -30,7 +30,7 @@ fun Player.hasBadIP(detector: BadIPDetector = BadIPDetector.DEFAULT) =
*/ */
fun Player.checkIP( fun Player.checkIP(
detector: BadIPDetector = BadIPDetector.DEFAULT, detector: BadIPDetector = BadIPDetector.DEFAULT,
breakOnHit: Boolean = true breakOnHit: Boolean = true,
): Map<BadIPDetectionService, BadIPDetectionResult> { ): Map<BadIPDetectionService, BadIPDetectionResult> {
val ip = address?.hostString ?: return emptyMap() val ip = address?.hostString ?: return emptyMap()
return detector.checkIP(ip, breakOnHit) return detector.checkIP(ip, breakOnHit)
@@ -47,9 +47,8 @@ fun Player.checkIP(
* - [net.axay.kspigot.ipaddress.badipdetectionservices.VPNBlocker] * - [net.axay.kspigot.ipaddress.badipdetectionservices.VPNBlocker]
*/ */
class BadIPDetector( class BadIPDetector(
val services: List<BadIPDetectionService> val services: List<BadIPDetectionService>,
) { ) {
/** /**
* Alternative constructor. * Alternative constructor.
* @see BadIPDetector * @see BadIPDetector
@@ -65,46 +64,35 @@ class BadIPDetector(
fun checkIP(ip: String, breakOnHit: Boolean = true) = fun checkIP(ip: String, breakOnHit: Boolean = true) =
HashMap<BadIPDetectionService, BadIPDetectionResult>().apply { HashMap<BadIPDetectionService, BadIPDetectionResult>().apply {
for (it in services) { for (it in services) {
val curResult = it.isBad(ip) val curResult = it.isBad(ip)
this[it] = curResult this[it] = curResult
if (curResult.isBad && breakOnHit) break if (curResult.isBad && breakOnHit) break
} }
} }
} }
enum class BadIPDetectionResult( enum class BadIPDetectionResult(
val isBad: Boolean, val isBad: Boolean,
val typeName: String val typeName: String,
) { ) {
GENERAL_BAD(true, "bad ip"), GENERAL_BAD(true, "bad ip"),
VPN(true, "vpn"), VPN(true, "vpn"),
PROXY(true, "proxy"), PROXY(true, "proxy"),
TOR(true, "tor network"), TOR(true, "tor network"),
HOSTING(true, "hosting"), HOSTING(true, "hosting"),
GOOD(false, "valid ip"), GOOD(false, "valid ip"),
ERROR(false, "error"), ERROR(false, "error"),
LIMIT(false, "limit"); LIMIT(false, "limit");
} }
abstract class BadIPDetectionService( abstract class BadIPDetectionService(
val name: String val name: String,
) { ) {
protected abstract fun requestString(ip: String): String protected abstract fun requestString(ip: String): String
protected open fun requestHeaders() = emptyMap<String, String>() protected open fun requestHeaders() = emptyMap<String, String>()
protected abstract fun interpreteResult(result: JSONObject): BadIPDetectionResult protected abstract fun interpreteResult(result: JSONObject): BadIPDetectionResult
fun isBad(ip: String): BadIPDetectionResult { fun isBad(ip: String): BadIPDetectionResult {
val con = URL(requestString(ip)).openConnection() as HttpURLConnection val con = URL(requestString(ip)).openConnection() as HttpURLConnection
con.requestMethod = "GET" con.requestMethod = "GET"
requestHeaders().forEach { (field, value) -> con.setRequestProperty(field, value) } requestHeaders().forEach { (field, value) -> con.setRequestProperty(field, value) }
@@ -113,7 +101,6 @@ abstract class BadIPDetectionService(
if (con.responseCode == 429) if (con.responseCode == 429)
return BadIPDetectionResult.LIMIT return BadIPDetectionResult.LIMIT
else { else {
val result = try { val result = try {
con.inputStream.use { JSONObject(it.readAllBytes().decodeToString()) } con.inputStream.use { JSONObject(it.readAllBytes().decodeToString()) }
} catch (exc: JSONException) { } catch (exc: JSONException) {
@@ -125,9 +112,6 @@ abstract class BadIPDetectionService(
} catch (exc: Exception) { } catch (exc: Exception) {
return BadIPDetectionResult.ERROR return BadIPDetectionResult.ERROR
} }
} }
} }
} }

View File

@@ -28,11 +28,8 @@ val Player.ipAddressData get() = ipAddressData()
* be found out about the IP address of the player. * be found out about the IP address of the player.
*/ */
fun Player.ipAddressData(language: IPAddressDataLanguage = IPAddressDataLanguage.ENGLISH): IPAddressData? { fun Player.ipAddressData(language: IPAddressDataLanguage = IPAddressDataLanguage.ENGLISH): IPAddressData? {
return try { return try {
val hostString = address?.hostString ?: return null val hostString = address?.hostString ?: return null
val jsonObject = ValueHolder.getGson().fromUrlJson( val jsonObject = ValueHolder.getGson().fromUrlJson(
"$IP_API${hostString}?fields=${IP_API_FIELDS}?lang=${language.code}" "$IP_API${hostString}?fields=${IP_API_FIELDS}?lang=${language.code}"
) ?: return null ) ?: return null
@@ -40,11 +37,9 @@ fun Player.ipAddressData(language: IPAddressDataLanguage = IPAddressDataLanguage
if (jsonObject["status"].toString() == "fail") return null if (jsonObject["status"].toString() == "fail") return null
IPAddressData(jsonObject) IPAddressData(jsonObject)
} catch (exc: Exception) { } catch (exc: Exception) {
null null
} }
} }
enum class IPAddressDataLanguage(val code: String) { enum class IPAddressDataLanguage(val code: String) {
@@ -59,7 +54,6 @@ enum class IPAddressDataLanguage(val code: String) {
} }
class IPAddressData(private val json: JsonObject) { class IPAddressData(private val json: JsonObject) {
val ip get() = json.getStringOrNull("query") val ip get() = json.getStringOrNull("query")
// region // region
@@ -81,5 +75,4 @@ class IPAddressData(private val json: JsonObject) {
// information // information
val internetServiceProvider get() = json.getStringOrNull("isp") val internetServiceProvider get() = json.getStringOrNull("isp")
val organisation get() = json.getStringOrNull("org") val organisation get() = json.getStringOrNull("org")
} }

View File

@@ -9,15 +9,14 @@ import org.json.JSONObject
class GetIPIntel( class GetIPIntel(
private val intensity: Float = 0.99f, private val intensity: Float = 0.99f,
private val contactEmail: String = "foo@bar.com" private val contactEmail: String = "foo@bar.com",
) : BadIPDetectionService("getipintel.net") { ) : BadIPDetectionService("getipintel.net") {
override fun requestString(ip: String) =
override fun requestString(ip: String) = "http://check.getipintel.net/check.php?ip=$ip&contact=$contactEmail&format=json" "http://check.getipintel.net/check.php?ip=$ip&contact=$contactEmail&format=json"
override fun interpreteResult(result: JSONObject): BadIPDetectionResult { override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
val probability = result.getStringOrNull("result")?.toFloatOrNull() val probability = result.getStringOrNull("result")?.toFloatOrNull()
?: return BadIPDetectionResult.ERROR ?: return BadIPDetectionResult.ERROR
return if (probability >= intensity) BadIPDetectionResult.GENERAL_BAD else BadIPDetectionResult.GOOD return if (probability >= intensity) BadIPDetectionResult.GENERAL_BAD else BadIPDetectionResult.GOOD
} }
} }

View File

@@ -9,15 +9,12 @@ import org.json.JSONObject
class IPHub( class IPHub(
private val apiKey: String, private val apiKey: String,
private val ifStrict: Boolean = false private val ifStrict: Boolean = false,
) : BadIPDetectionService("iphub.info") { ) : BadIPDetectionService("iphub.info") {
override fun requestString(ip: String) = "http://v2.api.iphub.info/ip/$ip" override fun requestString(ip: String) = "http://v2.api.iphub.info/ip/$ip"
override fun requestHeaders() = mapOf("X-Key" to apiKey) override fun requestHeaders() = mapOf("X-Key" to apiKey)
override fun interpreteResult(result: JSONObject): BadIPDetectionResult { override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
val ifBlock = result.getStringOrNull("block")?.toInt() ?: return BadIPDetectionResult.ERROR val ifBlock = result.getStringOrNull("block")?.toInt() ?: return BadIPDetectionResult.ERROR
return if (ifBlock == 1 || (ifStrict && ifBlock == 2)) BadIPDetectionResult.GENERAL_BAD else BadIPDetectionResult.GOOD return if (ifBlock == 1 || (ifStrict && ifBlock == 2)) BadIPDetectionResult.GENERAL_BAD else BadIPDetectionResult.GOOD
} }
} }

View File

@@ -6,11 +6,9 @@ import net.axay.kspigot.languageextensions.getStringOrNull
import org.json.JSONObject import org.json.JSONObject
class IPInfo( class IPInfo(
private val token: String private val token: String,
) : BadIPDetectionService("ipinfo.io") { ) : BadIPDetectionService("ipinfo.io") {
override fun requestString(ip: String) = "https://ipinfo.io/$ip/privacy?token=$token" override fun requestString(ip: String) = "https://ipinfo.io/$ip/privacy?token=$token"
override fun interpreteResult(result: JSONObject): BadIPDetectionResult { override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
return when { return when {
result.getStringOrNull("vpn").toBoolean() -> BadIPDetectionResult.VPN result.getStringOrNull("vpn").toBoolean() -> BadIPDetectionResult.VPN
@@ -20,5 +18,4 @@ class IPInfo(
else -> BadIPDetectionResult.GOOD else -> BadIPDetectionResult.GOOD
} }
} }
} }

View File

@@ -6,9 +6,7 @@ import net.axay.kspigot.languageextensions.getStringOrNull
import org.json.JSONObject import org.json.JSONObject
class VPNBlocker : BadIPDetectionService("vpnblocker.net") { class VPNBlocker : BadIPDetectionService("vpnblocker.net") {
override fun requestString(ip: String) = "http://api.vpnblocker.net/v2/json/$ip" override fun requestString(ip: String) = "http://api.vpnblocker.net/v2/json/$ip"
override fun interpreteResult(result: JSONObject): BadIPDetectionResult { override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
val isBad = result.getStringOrNull("host-ip") val isBad = result.getStringOrNull("host-ip")
return when { return when {
@@ -20,5 +18,4 @@ class VPNBlocker : BadIPDetectionService("vpnblocker.net") {
} }
} }
} }
} }

View File

@@ -15,7 +15,6 @@ import org.bukkit.inventory.meta.ItemMeta
* aswell. * aswell.
*/ */
data class CustomItemIdentifier(val customModelData: Int, val placeHolderMaterial: Material) { data class CustomItemIdentifier(val customModelData: Int, val placeHolderMaterial: Material) {
constructor(itemStack: ItemStack) : constructor(itemStack: ItemStack) :
this( this(
kotlin.run { kotlin.run {
@@ -38,5 +37,4 @@ data class CustomItemIdentifier(val customModelData: Int, val placeHolderMateria
itemStack itemStack
} else null } else null
} }
} }

View File

@@ -8,20 +8,15 @@ import net.md_5.bungee.api.ChatColor
* can be used for minecraft lorelists. * can be used for minecraft lorelists.
*/ */
fun String.toLoreList(vararg lineColors: ChatColor = arrayOf(KColors.RESET), lineLength: Int = 40): List<String> { fun String.toLoreList(vararg lineColors: ChatColor = arrayOf(KColors.RESET), lineLength: Int = 40): List<String> {
val lineColor = lineColors.joinToString(separator = "") val lineColor = lineColors.joinToString(separator = "")
val loreList = ArrayList<String>() val loreList = ArrayList<String>()
val lineBuilder = StringBuilder() val lineBuilder = StringBuilder()
fun submitLine() { fun submitLine() {
loreList += "$lineColor$lineBuilder" loreList += "$lineColor$lineBuilder"
lineBuilder.clear() lineBuilder.clear()
} }
fun addWord(word: String) { fun addWord(word: String) {
if (lineBuilder.lengthWithoutMinecraftColour + word.lengthWithoutMinecraftColour > lineLength) if (lineBuilder.lengthWithoutMinecraftColour + word.lengthWithoutMinecraftColour > lineLength)
submitLine() submitLine()
@@ -29,7 +24,6 @@ fun String.toLoreList(vararg lineColors: ChatColor = arrayOf(KColors.RESET), lin
lineBuilder.append(" ") lineBuilder.append(" ")
lineBuilder.append(word) lineBuilder.append(word)
} }
split(" ").forEach { addWord(it) } split(" ").forEach { addWord(it) }
@@ -38,38 +32,33 @@ fun String.toLoreList(vararg lineColors: ChatColor = arrayOf(KColors.RESET), lin
submitLine() submitLine()
return loreList return loreList
} }
/** /**
* Returns the length of this sequence, ignoring * Returns the length of this sequence, ignoring
* all minecraft colour codes. * all minecraft colour codes.
*/ */
val CharSequence.lengthWithoutMinecraftColour: Int get() { val CharSequence.lengthWithoutMinecraftColour: Int
get() {
var count = 0
var isPreviousColourCode = false
var count = 0 this.forEachIndexed { index, char ->
if (isPreviousColourCode) {
isPreviousColourCode = false
return@forEachIndexed
}
var isPreviousColourCode = false if (char == '§') {
if (lastIndex >= index + 1) {
this.forEachIndexed { index, char -> val nextChar = this[index + 1]
if (nextChar.isLetter() || nextChar.isDigit())
if (isPreviousColourCode) { isPreviousColourCode = true
isPreviousColourCode = false else
return@forEachIndexed count++
}
} else count++
} }
if (char == '§') { return count
if (lastIndex >= index + 1) {
val nextChar = this[index + 1]
if (nextChar.isLetter() || nextChar.isDigit())
isPreviousColourCode = true
else
count++
}
} else count++
} }
return count
}

View File

@@ -9,16 +9,12 @@ import org.bukkit.inventory.meta.ItemMeta
/* /*
ITEM STACK ITEM STACK
*/ */
// creation // creation
/** /**
* Creates a new [ItemStack] and opens a builder for it. * Creates a new [ItemStack] and opens a builder for it.
*/ */
inline fun itemStack(material: Material, builder: ItemStack.() -> Unit) = ItemStack(material).apply(builder) inline fun itemStack(material: Material, builder: ItemStack.() -> Unit) = ItemStack(material).apply(builder)
// extensions // extensions
/** /**
* Opens a builder with the current meta. * Opens a builder with the current meta.
* @param T the specific type of the meta * @param T the specific type of the meta
@@ -48,13 +44,10 @@ inline fun <reified T : ItemMeta> ItemStack.setMeta(builder: T.() -> Unit) {
/** @see setMeta */ /** @see setMeta */
@JvmName("simpleSetMeta") @JvmName("simpleSetMeta")
inline fun ItemStack.setMeta(builder: ItemMeta.() -> Unit) = setMeta<ItemMeta>(builder) inline fun ItemStack.setMeta(builder: ItemMeta.() -> Unit) = setMeta<ItemMeta>(builder)
/* /*
ITEM META ITEM META
*/ */
// creation // creation
/** /**
* Creates new a [ItemMeta] instance of the given material and opens a builder for it. * Creates new a [ItemMeta] instance of the given material and opens a builder for it.
* @param T the specific type of the meta * @param T the specific type of the meta
@@ -67,9 +60,7 @@ inline fun <reified T : ItemMeta> itemMeta(material: Material, builder: T.() ->
/** @see itemMeta */ /** @see itemMeta */
@JvmName("simpleItemMeta") @JvmName("simpleItemMeta")
inline fun itemMeta(material: Material, builder: ItemMeta.() -> Unit) = itemMeta<ItemMeta>(material, builder) inline fun itemMeta(material: Material, builder: ItemMeta.() -> Unit) = itemMeta<ItemMeta>(material, builder)
// extensions // extensions
/** /**
* Sets the lore (description) of the item. * Sets the lore (description) of the item.
*/ */

View File

@@ -1,7 +1,5 @@
package net.axay.kspigot.languageextensions.kotlinextensions package net.axay.kspigot.languageextensions.kotlinextensions
internal inline fun <T, R> Lazy<T>.ifInitialized(block: (T) -> R) = if (isInitialized()) block(value) else null internal inline fun <T, R> Lazy<T>.ifInitialized(block: (T) -> R) = if (isInitialized()) block(value) else null
internal val <T> Lazy<T>.valueIfInitialized get() = ifInitialized { value } internal val <T> Lazy<T>.valueIfInitialized get() = ifInitialized { value }
internal fun Lazy<AutoCloseable>.closeIfInitialized() = ifInitialized { value.close() } internal fun Lazy<AutoCloseable>.closeIfInitialized() = ifInitialized { value.close() }

View File

@@ -3,7 +3,6 @@
package net.axay.kspigot.languageextensions.kotlinextensions package net.axay.kspigot.languageextensions.kotlinextensions
internal class MinMaxPair<T : Comparable<T>>(a: T, b: T) { internal class MinMaxPair<T : Comparable<T>>(a: T, b: T) {
val min: T; val min: T;
val max: T val max: T
@@ -14,5 +13,4 @@ internal class MinMaxPair<T : Comparable<T>>(a: T, b: T) {
min = a; max = b min = a; max = b
} }
} }
} }

View File

@@ -1,17 +1,12 @@
package net.axay.kspigot.languageextensions.kotlinextensions package net.axay.kspigot.languageextensions.kotlinextensions
internal fun stringBuilder(builder: StringBuilder.() -> Unit) = StringBuilder().apply(builder).toString() internal fun stringBuilder(builder: StringBuilder.() -> Unit) = StringBuilder().apply(builder).toString()
inline fun multiLine(builder: MultiLineBuilder.() -> Unit) = MultiLineBuilder().apply(builder).build() inline fun multiLine(builder: MultiLineBuilder.() -> Unit) = MultiLineBuilder().apply(builder).build()
class MultiLineBuilder { class MultiLineBuilder {
private val stringBuilder = StringBuilder() private val stringBuilder = StringBuilder()
operator fun String.unaryPlus() { operator fun String.unaryPlus() {
stringBuilder.appendLine(this) stringBuilder.appendLine(this)
} }
fun build() = stringBuilder.toString() fun build() = stringBuilder.toString()
} }

View File

@@ -5,7 +5,6 @@ import org.bukkit.entity.Player
import java.io.InputStreamReader import java.io.InputStreamReader
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.util.* import java.util.*
import kotlin.collections.HashMap
/** /**
* Handles localization of strings using java [ResourceBundle]s. * Handles localization of strings using java [ResourceBundle]s.
@@ -23,7 +22,6 @@ object Localization {
* is advisable in many cases. * is advisable in many cases.
*/ */
var localeProvider: (Player) -> Locale = { Locale.US } var localeProvider: (Player) -> Locale = { Locale.US }
private val bundles: MutableMap<Locale, ResourceBundle> = HashMap() private val bundles: MutableMap<Locale, ResourceBundle> = HashMap()
/** /**

View File

@@ -19,11 +19,9 @@ import org.bukkit.plugin.java.JavaPlugin
* - [shutdown()] (called in the "end") * - [shutdown()] (called in the "end")
*/ */
abstract class KSpigot : JavaPlugin() { abstract class KSpigot : JavaPlugin() {
// lazy properties // lazy properties
private val kRunnableHolderProperty = lazy { KRunnableHolder } private val kRunnableHolderProperty = lazy { KRunnableHolder }
private val guiHolderProperty = lazy { GUIHolder } private val guiHolderProperty = lazy { GUIHolder }
internal val kRunnableHolder by kRunnableHolderProperty internal val kRunnableHolder by kRunnableHolderProperty
internal val guiHolder by guiHolderProperty internal val guiHolder by guiHolderProperty
@@ -41,7 +39,6 @@ abstract class KSpigot : JavaPlugin() {
* Called when the plugin gets disabled * Called when the plugin gets disabled
*/ */
open fun shutdown() {} open fun shutdown() {}
final override fun onLoad() { final override fun onLoad() {
KSpigotMainInstance = this KSpigotMainInstance = this
load() load()
@@ -52,15 +49,11 @@ abstract class KSpigot : JavaPlugin() {
} }
final override fun onDisable() { final override fun onDisable() {
shutdown() shutdown()
// avoid unnecessary load of lazy properties // avoid unnecessary load of lazy properties
kRunnableHolderProperty.closeIfInitialized() kRunnableHolderProperty.closeIfInitialized()
guiHolderProperty.closeIfInitialized() guiHolderProperty.closeIfInitialized()
} }
} }
lateinit var KSpigotMainInstance: KSpigot private set lateinit var KSpigotMainInstance: KSpigot private set

View File

@@ -4,14 +4,10 @@ import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
object ValueHolder { object ValueHolder {
private val gsonBuilder by lazy { private val gsonBuilder by lazy {
GsonBuilder() GsonBuilder()
} }
private val gson: Gson by lazy { gsonBuilder.create() } private val gson: Gson by lazy { gsonBuilder.create() }
private val gsonPretty: Gson by lazy { gsonBuilder.setPrettyPrinting().create() } private val gsonPretty: Gson by lazy { gsonBuilder.setPrettyPrinting().create() }
fun getGson(pretty: Boolean = false) = if (pretty) gsonPretty else gson fun getGson(pretty: Boolean = false) = if (pretty) gsonPretty else gson
} }

View File

@@ -21,9 +21,8 @@ data class KSpigotParticle(
var offset: Vector? = null, var offset: Vector? = null,
var extra: Number = 1.0, var extra: Number = 1.0,
var data: Any? = null, var data: Any? = null,
var force: Boolean = false var force: Boolean = false,
) { ) {
/** /**
* Spawns the particle at the location. It * Spawns the particle at the location. It
* will be visible for everyone near it. * will be visible for everyone near it.
@@ -58,7 +57,6 @@ data class KSpigotParticle(
data data
) )
} }
} }
/** /**

View File

@@ -9,40 +9,29 @@ import java.io.DataInputStream
internal class BungeePluginMessageResponseCallback( internal class BungeePluginMessageResponseCallback(
val subChannel: String, val subChannel: String,
val timeoutSeconds: Int, val timeoutSeconds: Int,
val onResponse: (message: DataInputStream) -> Unit val onResponse: (message: DataInputStream) -> Unit,
) { ) {
init { init {
BungeePluginMessageReceiver.registered += this BungeePluginMessageReceiver.registered += this
taskRunLater(20L * timeoutSeconds) { taskRunLater(20L * timeoutSeconds) {
BungeePluginMessageReceiver.registered -= this BungeePluginMessageReceiver.registered -= this
} }
} }
} }
private object BungeePluginMessageReceiver : PluginMessageListener { private object BungeePluginMessageReceiver : PluginMessageListener {
val registered = ArrayList<BungeePluginMessageResponseCallback>() val registered = ArrayList<BungeePluginMessageResponseCallback>()
override fun onPluginMessageReceived(channel: String, player: Player, message: ByteArray) { override fun onPluginMessageReceived(channel: String, player: Player, message: ByteArray) {
if (channel != "BungeeCord") return if (channel != "BungeeCord") return
val msgbytes = ByteArrayInputStream(message) val msgbytes = ByteArrayInputStream(message)
val msgin = DataInputStream(msgbytes) val msgin = DataInputStream(msgbytes)
val subChannel = msgin.readUTF() val subChannel = msgin.readUTF()
val callback = registered.find { it.subChannel == subChannel } val callback = registered.find { it.subChannel == subChannel }
if (callback != null) { if (callback != null) {
registered -= callback registered -= callback
callback.onResponse.invoke(msgin) callback.onResponse.invoke(msgin)
} }
} }
} }

View File

@@ -8,7 +8,7 @@ import org.bukkit.entity.Player
* Sends the sending player to the given server * Sends the sending player to the given server
*/ */
class PluginMessageConnect( class PluginMessageConnect(
val servername: String val servername: String,
) : BungeePluginMessagePlayerSpecific { ) : BungeePluginMessagePlayerSpecific {
override fun sendWithPlayer(player: Player) = sendPluginMessageToBungeeCord( override fun sendWithPlayer(player: Player) = sendPluginMessageToBungeeCord(
player, "Connect", listOf(servername) player, "Connect", listOf(servername)
@@ -21,7 +21,7 @@ class PluginMessageConnect(
*/ */
class PluginMessagePlayerCount( class PluginMessagePlayerCount(
val servername: String, val servername: String,
private val response: (Int) -> Unit private val response: (Int) -> Unit,
) : BungeePluginMessageRandomPlayer { ) : BungeePluginMessageRandomPlayer {
override fun send() = sendPluginMessageToBungeeCordRandomPlayer( override fun send() = sendPluginMessageToBungeeCordRandomPlayer(
"PlayerCount", listOf(servername) "PlayerCount", listOf(servername)
@@ -35,7 +35,7 @@ class PluginMessagePlayerCount(
* on all servers. * on all servers.
*/ */
class PluginMessagePlayerCountAllServers( class PluginMessagePlayerCountAllServers(
private val response: (Int) -> Unit private val response: (Int) -> Unit,
) : BungeePluginMessageRandomPlayer { ) : BungeePluginMessageRandomPlayer {
override fun send() = sendPluginMessageToBungeeCordRandomPlayer( override fun send() = sendPluginMessageToBungeeCordRandomPlayer(
"PlayerCount", listOf("ALL") "PlayerCount", listOf("ALL")
@@ -50,7 +50,7 @@ class PluginMessagePlayerCountAllServers(
*/ */
class PluginMessagePlayerList( class PluginMessagePlayerList(
val servername: String, val servername: String,
private val response: (List<String>) -> Unit private val response: (List<String>) -> Unit,
) : BungeePluginMessageRandomPlayer { ) : BungeePluginMessageRandomPlayer {
override fun send() = sendPluginMessageToBungeeCordRandomPlayer( override fun send() = sendPluginMessageToBungeeCordRandomPlayer(
"PlayerList", listOf(servername) "PlayerList", listOf(servername)
@@ -65,7 +65,7 @@ class PluginMessagePlayerList(
*/ */
class PluginMessagePlayerListAllServers( class PluginMessagePlayerListAllServers(
val servername: String, val servername: String,
private val response: (List<String>) -> Unit private val response: (List<String>) -> Unit,
) : BungeePluginMessageRandomPlayer { ) : BungeePluginMessageRandomPlayer {
override fun send() = sendPluginMessageToBungeeCordRandomPlayer( override fun send() = sendPluginMessageToBungeeCordRandomPlayer(
"PlayerList", listOf("ALL") "PlayerList", listOf("ALL")
@@ -79,7 +79,7 @@ class PluginMessagePlayerListAllServers(
* BungeeCord network. * BungeeCord network.
*/ */
class PluginMessageGetServers( class PluginMessageGetServers(
private val response: (List<String>) -> Unit private val response: (List<String>) -> Unit,
) : BungeePluginMessageRandomPlayer { ) : BungeePluginMessageRandomPlayer {
override fun send() = sendPluginMessageToBungeeCordRandomPlayer( override fun send() = sendPluginMessageToBungeeCordRandomPlayer(
"GetServers" "GetServers"

View File

@@ -19,7 +19,7 @@ fun sendPluginMessageToBungeeCordRandomPlayer(
subChannel: String, subChannel: String,
content: List<String>? = null, content: List<String>? = null,
responseTimeout: Int = 20, responseTimeout: Int = 20,
onResponse: ((message: DataInputStream) -> Unit)? = null onResponse: ((message: DataInputStream) -> Unit)? = null,
): Boolean { ): Boolean {
val randomPlayer = onlinePlayers.randomOrNull() val randomPlayer = onlinePlayers.randomOrNull()
return if (randomPlayer != null) { return if (randomPlayer != null) {
@@ -43,20 +43,17 @@ fun sendPluginMessageToBungeeCord(
subChannel: String, subChannel: String,
content: List<String>? = null, content: List<String>? = null,
responseTimeout: Int = 20, responseTimeout: Int = 20,
onResponse: ((message: DataInputStream) -> Unit)? = null onResponse: ((message: DataInputStream) -> Unit)? = null,
) { ) {
val msgbytes = ByteArrayOutputStream() val msgbytes = ByteArrayOutputStream()
val msgout = DataOutputStream(msgbytes) val msgout = DataOutputStream(msgbytes)
try { try {
msgout.writeUTF(subChannel) msgout.writeUTF(subChannel)
if (content != null) if (content != null)
for (messagePart in content) for (messagePart in content)
msgout.writeUTF(messagePart) msgout.writeUTF(messagePart)
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
} }
@@ -65,5 +62,4 @@ fun sendPluginMessageToBungeeCord(
BungeePluginMessageResponseCallback(subChannel, responseTimeout, onResponse) BungeePluginMessageResponseCallback(subChannel, responseTimeout, onResponse)
player.sendPluginMessage(KSpigotMainInstance, "BungeeCord", msgbytes.toByteArray()) player.sendPluginMessage(KSpigotMainInstance, "BungeeCord", msgbytes.toByteArray())
} }

View File

@@ -5,11 +5,9 @@ package net.axay.kspigot.runnables
import kotlin.reflect.KClass import kotlin.reflect.KClass
abstract class ChainedRunnablePart<T, R>( abstract class ChainedRunnablePart<T, R>(
val sync: Boolean val sync: Boolean,
) { ) {
var next: ChainedRunnablePart<R, *>? = null var next: ChainedRunnablePart<R, *>? = null
protected abstract fun invoke(data: T): R protected abstract fun invoke(data: T): R
/** /**
@@ -27,7 +25,7 @@ abstract class ChainedRunnablePart<T, R>(
*/ */
inline fun <reified E : Exception> executeCatching( inline fun <reified E : Exception> executeCatching(
exceptionSync: Boolean = true, exceptionSync: Boolean = true,
noinline exceptionHandler: ((E) -> Unit)? = null noinline exceptionHandler: ((E) -> Unit)? = null,
) { ) {
executeCatchingImpl(E::class, exceptionSync, exceptionHandler) executeCatchingImpl(E::class, exceptionSync, exceptionHandler)
} }
@@ -74,42 +72,35 @@ abstract class ChainedRunnablePart<T, R>(
next?.startCatching(result, exceptionClass, exceptionSync, exceptionHandler) next?.startCatching(result, exceptionClass, exceptionSync, exceptionHandler)
} }
} }
} }
class ChainedRunnablePartFirst<R>( class ChainedRunnablePartFirst<R>(
val runnable: () -> R, val runnable: () -> R,
sync: Boolean sync: Boolean,
) : ChainedRunnablePart<Unit, R>(sync) { ) : ChainedRunnablePart<Unit, R>(sync) {
override fun execute() = start(Unit) override fun execute() = start(Unit)
override fun <E : Exception> executeCatchingImpl( override fun <E : Exception> executeCatchingImpl(
exceptionClass: KClass<E>, exceptionClass: KClass<E>,
exceptionSync: Boolean, exceptionSync: Boolean,
exceptionHandler: ((E) -> Unit)? exceptionHandler: ((E) -> Unit)?,
) = startCatching(Unit, exceptionClass, exceptionSync, exceptionHandler) ) = startCatching(Unit, exceptionClass, exceptionSync, exceptionHandler)
override fun invoke(data: Unit) = runnable.invoke() override fun invoke(data: Unit) = runnable.invoke()
} }
class ChainedRunnablePartThen<T, R>( class ChainedRunnablePartThen<T, R>(
val runnable: (T) -> R, val runnable: (T) -> R,
sync: Boolean, sync: Boolean,
val previous: ChainedRunnablePart<*, T> val previous: ChainedRunnablePart<*, T>,
) : ChainedRunnablePart<T, R>(sync) { ) : ChainedRunnablePart<T, R>(sync) {
override fun execute() = previous.execute() override fun execute() = previous.execute()
override fun <E : Exception> executeCatchingImpl( override fun <E : Exception> executeCatchingImpl(
exceptionClass: KClass<E>, exceptionClass: KClass<E>,
exceptionSync: Boolean, exceptionSync: Boolean,
exceptionHandler: ((E) -> Unit)? exceptionHandler: ((E) -> Unit)?,
) = previous.executeCatchingImpl(exceptionClass, exceptionSync, exceptionHandler) ) = previous.executeCatchingImpl(exceptionClass, exceptionSync, exceptionHandler)
override fun invoke(data: T) = runnable.invoke(data) override fun invoke(data: T) = runnable.invoke(data)
} }
// FIRST // FIRST

View File

@@ -7,7 +7,6 @@ import org.bukkit.Bukkit
import org.bukkit.scheduler.BukkitRunnable import org.bukkit.scheduler.BukkitRunnable
internal object KRunnableHolder : AutoCloseable { internal object KRunnableHolder : AutoCloseable {
/** /**
* [BukkitRunnable] for tracking the responsible runnable. * [BukkitRunnable] for tracking the responsible runnable.
* [Pair] of callback for the endCallback code and [Boolean] * [Pair] of callback for the endCallback code and [Boolean]
@@ -15,7 +14,6 @@ internal object KRunnableHolder : AutoCloseable {
* or not. * or not.
*/ */
private val runnableEndCallbacks = HashMap<BukkitRunnable, Pair<() -> Unit, Boolean>>() private val runnableEndCallbacks = HashMap<BukkitRunnable, Pair<() -> Unit, Boolean>>()
override fun close() { override fun close() {
runnableEndCallbacks.values.forEach { if (it.second) it.first.invoke() } runnableEndCallbacks.values.forEach { if (it.second) it.first.invoke() }
runnableEndCallbacks.clear() runnableEndCallbacks.clear()
@@ -26,13 +24,12 @@ internal object KRunnableHolder : AutoCloseable {
fun remove(runnable: BukkitRunnable) = runnableEndCallbacks.remove(runnable) fun remove(runnable: BukkitRunnable) = runnableEndCallbacks.remove(runnable)
fun activate(runnable: BukkitRunnable) = runnableEndCallbacks.remove(runnable)?.first?.invoke() fun activate(runnable: BukkitRunnable) = runnableEndCallbacks.remove(runnable)?.first?.invoke()
} }
abstract class KSpigotRunnable( abstract class KSpigotRunnable(
var counterUp: Long? = null, var counterUp: Long? = null,
var counterDownToOne: Long? = null, var counterDownToOne: Long? = null,
var counterDownToZero: Long? = null var counterDownToZero: Long? = null,
) : BukkitRunnable() ) : BukkitRunnable()
/** /**
@@ -56,20 +53,14 @@ fun task(
howOften: Long? = null, howOften: Long? = null,
safe: Boolean = false, safe: Boolean = false,
endCallback: (() -> Unit)? = null, endCallback: (() -> Unit)? = null,
runnable: ((KSpigotRunnable) -> Unit)? = null runnable: ((KSpigotRunnable) -> Unit)? = null,
): KSpigotRunnable? { ): KSpigotRunnable? {
if (howOften != null && howOften == 0L) return null if (howOften != null && howOften == 0L) return null
val bukkitRunnable = object : KSpigotRunnable() { val bukkitRunnable = object : KSpigotRunnable() {
private var curCounter = 0L private var curCounter = 0L
override fun run() { override fun run() {
var ranOut = false var ranOut = false
if (howOften != null) { if (howOften != null) {
counterDownToOne = howOften - curCounter counterDownToOne = howOften - curCounter
counterDownToZero = counterDownToOne?.minus(1) counterDownToZero = counterDownToOne?.minus(1)
@@ -78,7 +69,6 @@ fun task(
ranOut = true ranOut = true
counterUp = curCounter counterUp = curCounter
} }
runnable?.invoke(this) runnable?.invoke(this)
@@ -91,9 +81,7 @@ fun task(
else else
KRunnableHolder.remove(this) KRunnableHolder.remove(this)
} }
} }
} }
if (endCallback != null) KRunnableHolder.add(bukkitRunnable, endCallback, safe) if (endCallback != null) KRunnableHolder.add(bukkitRunnable, endCallback, safe)
@@ -106,7 +94,6 @@ fun task(
else bukkitRunnable.runTaskLaterAsynchronously(KSpigotMainInstance, delay) else bukkitRunnable.runTaskLaterAsynchronously(KSpigotMainInstance, delay)
return bukkitRunnable return bukkitRunnable
} }
/** /**

View File

@@ -24,13 +24,10 @@ object ItemMetaSerializer : KSerializerForBukkit<ItemMeta>(ItemMeta::class)
object ItemStackSerializer : KSerializerForBukkit<ItemStack>(ItemStack::class) object ItemStackSerializer : KSerializerForBukkit<ItemStack>(ItemStack::class)
object LocationSerializer : KSerializerForBukkit<Location>(Location::class) object LocationSerializer : KSerializerForBukkit<Location>(Location::class)
object VectorSerializer : KSerializerForBukkit<Vector>(Vector::class) object VectorSerializer : KSerializerForBukkit<Vector>(Vector::class)
open class KSerializerForBukkit<T : ConfigurationSerializable>( open class KSerializerForBukkit<T : ConfigurationSerializable>(
private val kClass: KClass<T> private val kClass: KClass<T>,
) : KSerializer<T> { ) : KSerializer<T> {
override val descriptor = ByteArraySerializer().descriptor override val descriptor = ByteArraySerializer().descriptor
override fun serialize(encoder: Encoder, value: T) { override fun serialize(encoder: Encoder, value: T) {
val bytes = ByteArrayOutputStream() val bytes = ByteArrayOutputStream()
BukkitObjectOutputStream(bytes).use { BukkitObjectOutputStream(bytes).use {
@@ -48,5 +45,4 @@ open class KSerializerForBukkit<T : ConfigurationSerializable>(
?: throw IllegalStateException("The object can not be deserialized to an object of the type ${kClass.simpleName}") ?: throw IllegalStateException("The object can not be deserialized to an object of the type ${kClass.simpleName}")
} }
} }
} }

View File

@@ -11,14 +11,16 @@ data class SerializableLocation(
val x: Double, val x: Double,
val y: Double, val y: Double,
val z: Double, val z: Double,
val direction: SerializableVector val direction: SerializableVector,
) : SpigotSerializable<Location> { ) : SpigotSerializable<Location> {
companion object : SpigotSerializableCompanion<SerializableLocation> companion object : SpigotSerializableCompanion<SerializableLocation>
constructor(loc: Location) : this(loc.world?.let { SerializableWorld(it) }, loc.x, loc.y, loc.z, SerializableVector(loc.direction)) constructor(loc: Location) : this(loc.world?.let { SerializableWorld(it) },
loc.x,
loc.y,
loc.z,
SerializableVector(loc.direction))
override fun toSpigot() = Location(world?.toSpigot(), x, y, z) override fun toSpigot() = Location(world?.toSpigot(), x, y, z)
.apply { direction = this@SerializableLocation.direction.toSpigot() } .apply { direction = this@SerializableLocation.direction.toSpigot() }
} }

View File

@@ -9,13 +9,11 @@ import org.bukkit.util.Vector
data class SerializableVector( data class SerializableVector(
val x: Double, val x: Double,
val y: Double, val y: Double,
val z: Double val z: Double,
) : SpigotSerializable<Vector> { ) : SpigotSerializable<Vector> {
companion object : SpigotSerializableCompanion<SerializableVector> companion object : SpigotSerializableCompanion<SerializableVector>
constructor(vec: Vector) : this(vec.x, vec.y, vec.z) constructor(vec: Vector) : this(vec.x, vec.y, vec.z)
override fun toSpigot() = Vector(x, y, z) override fun toSpigot() = Vector(x, y, z)
} }

View File

@@ -8,14 +8,12 @@ import org.bukkit.Bukkit
import org.bukkit.World import org.bukkit.World
class SerializableWorld( class SerializableWorld(
val name: String val name: String,
) : SpigotSerializable<World> { ) : SpigotSerializable<World> {
companion object : SpigotSerializableCompanion<World> companion object : SpigotSerializableCompanion<World>
constructor(world: World) : this(world.name) constructor(world: World) : this(world.name)
override fun toSpigot() = Bukkit.getWorld(name) override fun toSpigot() = Bukkit.getWorld(name)
?: throw NullPointerException("The world \"$name\" does not exist") ?: throw NullPointerException("The world \"$name\" does not exist")
} }

View File

@@ -11,9 +11,8 @@ data class KSpigotSound(
val sound: Sound, val sound: Sound,
var volume: Float = 1f, var volume: Float = 1f,
var pitch: Float = 1f, var pitch: Float = 1f,
var category: SoundCategory? = null var category: SoundCategory? = null,
) { ) {
/** /**
* Plays the sound at the location. It * Plays the sound at the location. It
* will be audible for everyone near it. * will be audible for everyone near it.
@@ -37,7 +36,6 @@ data class KSpigotSound(
else else
player.playSound(player.location, sound, volume, pitch) player.playSound(player.location, sound, volume, pitch)
} }
} }
/** /**

View File

@@ -9,15 +9,12 @@ import org.bukkit.Material
import org.bukkit.entity.EntityType import org.bukkit.entity.EntityType
private fun circleEdgeLocations(radius: Number) = HashSet<SimpleLocation2D>().apply { private fun circleEdgeLocations(radius: Number) = HashSet<SimpleLocation2D>().apply {
val currentRadius = radius.toDouble() val currentRadius = radius.toDouble()
var d = -currentRadius var d = -currentRadius
var x = currentRadius var x = currentRadius
var y = 0 var y = 0
while (y <= x) { while (y <= x) {
addSimpleLoc2D(x, y) addSimpleLoc2D(x, y)
addSimpleLoc2D(x, -y) addSimpleLoc2D(x, -y)
addSimpleLoc2D(-x, y) addSimpleLoc2D(-x, y)
@@ -34,9 +31,7 @@ private fun circleEdgeLocations(radius: Number) = HashSet<SimpleLocation2D>().ap
d += -2 * x + 2 d += -2 * x + 2
x-- x--
} }
} }
} }
private fun MutableSet<SimpleLocation2D>.addSimpleLoc2D(first: Number, second: Number) { private fun MutableSet<SimpleLocation2D>.addSimpleLoc2D(first: Number, second: Number) {
@@ -44,11 +39,8 @@ private fun MutableSet<SimpleLocation2D>.addSimpleLoc2D(first: Number, second: N
} }
abstract class Circle(val radius: Number) { abstract class Circle(val radius: Number) {
protected abstract val data: StructureData protected abstract val data: StructureData
val fillLocations by lazy { val fillLocations by lazy {
var currentRadius = radius.toDouble() var currentRadius = radius.toDouble()
HashSet<SimpleLocation2D>().apply { HashSet<SimpleLocation2D>().apply {
@@ -70,17 +62,12 @@ abstract class Circle(val radius: Number) {
currentRadius-- currentRadius--
} }
} }
} }
val edgeLocations by lazy { val edgeLocations by lazy {
circleEdgeLocations(radius) circleEdgeLocations(radius)
} }
val filledStructure by lazy { structure(true) } val filledStructure by lazy { structure(true) }
val edgeStructure by lazy { structure(false) } val edgeStructure by lazy { structure(false) }
fun structure(filled: Boolean) = Structure( fun structure(filled: Boolean) = Structure(
HashSet<SingleStructureData>().apply { HashSet<SingleStructureData>().apply {
val locations = if (filled) fillLocations else edgeLocations val locations = if (filled) fillLocations else edgeLocations
@@ -88,7 +75,6 @@ abstract class Circle(val radius: Number) {
this += SingleStructureData(SimpleLocation3D(it.x, 0, it.y), data) this += SingleStructureData(SimpleLocation3D(it.x, 0, it.y), data)
} }
) )
} }
class MaterialCircle(radius: Number, material: Material) : Circle(radius) { class MaterialCircle(radius: Number, material: Material) : Circle(radius) {

View File

@@ -19,35 +19,31 @@ interface StructureData {
class SingleStructureData( class SingleStructureData(
val location: SimpleLocation3D, val location: SimpleLocation3D,
val structureData: StructureData val structureData: StructureData,
) )
data class Structure( data class Structure(
val structureData: Set<SingleStructureData> val structureData: Set<SingleStructureData>,
) { ) {
constructor(vararg structureDataSets: Set<SingleStructureData>) constructor(vararg structureDataSets: Set<SingleStructureData>)
: this(structureDataSets.flatMapTo(HashSet()) { it }) : this(structureDataSets.flatMapTo(HashSet()) { it })
} }
/* /*
* Structure data implementations. * Structure data implementations.
*/ */
data class StructureDataMaterial( data class StructureDataMaterial(
val material: Material val material: Material,
) : StructureData { ) : StructureData {
override fun createAt(loc: Location) { override fun createAt(loc: Location) {
loc.block.type = material loc.block.type = material
} }
} }
data class StructureDataBlock( data class StructureDataBlock(
val material: Material, val material: Material,
val blockData: BlockData val blockData: BlockData,
) : StructureData { ) : StructureData {
constructor(block: Block) : this(block.type, block.blockData) constructor(block: Block) : this(block.type, block.blockData)
override fun createAt(loc: Location) { override fun createAt(loc: Location) {
@@ -56,30 +52,25 @@ data class StructureDataBlock(
it.blockData = blockData it.blockData = blockData
} }
} }
} }
@NMS_General @NMS_General
data class StructureDataEntity( data class StructureDataEntity(
val entityType: EntityType, val entityType: EntityType,
val nbtData: NBTData val nbtData: NBTData,
) : StructureData { ) : StructureData {
constructor(entity: Entity) : this(entity.type, entity.nbtData) constructor(entity: Entity) : this(entity.type, entity.nbtData)
constructor(entityType: EntityType) : this(entityType, NBTData()) constructor(entityType: EntityType) : this(entityType, NBTData())
override fun createAt(loc: Location) { override fun createAt(loc: Location) {
loc.spawnCleanEntity(entityType)?.nbtData = nbtData loc.spawnCleanEntity(entityType)?.nbtData = nbtData
} }
} }
data class StructureDataParticle( data class StructureDataParticle(
val particle: KSpigotParticle val particle: KSpigotParticle,
) : StructureData { ) : StructureData {
override fun createAt(loc: Location) { override fun createAt(loc: Location) {
particle.spawnAt(loc) particle.spawnAt(loc)
} }
} }

View File

@@ -9,14 +9,12 @@ import org.bukkit.block.BlockFace
* vertical directions (pitch). * vertical directions (pitch).
*/ */
enum class VerticalDirection { enum class VerticalDirection {
UP, DOWN, STRAIGHT; UP, DOWN, STRAIGHT;
val facing: BlockFace? val facing: BlockFace?
get() = Enums.getIfPresent(BlockFace::class.java, this.name).orNull() get() = Enums.getIfPresent(BlockFace::class.java, this.name).orNull()
companion object { companion object {
fun fromLocation(location: Location): VerticalDirection { fun fromLocation(location: Location): VerticalDirection {
val pitch: Float = location.pitch val pitch: Float = location.pitch
return when { return when {
@@ -25,9 +23,7 @@ enum class VerticalDirection {
else -> STRAIGHT else -> STRAIGHT
} }
} }
} }
} }
/** /**
@@ -35,14 +31,12 @@ enum class VerticalDirection {
* cardinal directions (yaw). * cardinal directions (yaw).
*/ */
enum class CardinalDirection { enum class CardinalDirection {
NORTH, EAST, SOUTH, WEST; NORTH, EAST, SOUTH, WEST;
val facing: BlockFace? val facing: BlockFace?
get() = Enums.getIfPresent(BlockFace::class.java, this.name).orNull() get() = Enums.getIfPresent(BlockFace::class.java, this.name).orNull()
companion object { companion object {
fun fromLocation(location: Location): CardinalDirection { fun fromLocation(location: Location): CardinalDirection {
var yaw: Float = location.yaw var yaw: Float = location.yaw
if (yaw < 0) yaw += 360f if (yaw < 0) yaw += 360f
@@ -54,7 +48,5 @@ enum class CardinalDirection {
else -> NORTH else -> NORTH
} }
} }
} }
} }

View File

@@ -7,44 +7,34 @@ import org.bukkit.FireworkEffect
import org.bukkit.inventory.meta.FireworkMeta import org.bukkit.inventory.meta.FireworkMeta
object KSpigotFirework { object KSpigotFirework {
inline fun buildFireworkMeta(fireworkMeta: FireworkMeta, builder: KSpigotFireworkBuilder.() -> Unit): FireworkMeta { inline fun buildFireworkMeta(fireworkMeta: FireworkMeta, builder: KSpigotFireworkBuilder.() -> Unit): FireworkMeta {
return KSpigotFireworkBuilder().apply(builder).applyTo(fireworkMeta) return KSpigotFireworkBuilder().apply(builder).applyTo(fireworkMeta)
} }
fun FireworkMeta.build(builder: KSpigotFireworkBuilder.() -> Unit) = buildFireworkMeta(this, builder) fun FireworkMeta.build(builder: KSpigotFireworkBuilder.() -> Unit) = buildFireworkMeta(this, builder)
} }
class KSpigotFireworkBuilder { class KSpigotFireworkBuilder {
val effects = ArrayList<FireworkEffect>() val effects = ArrayList<FireworkEffect>()
var power: Int? = null var power: Int? = null
inline fun effect(builder: FireworkEffectBuilder.() -> Unit) { inline fun effect(builder: FireworkEffectBuilder.() -> Unit) {
effects += FireworkEffectBuilder().apply(builder).fireworkEffect effects += FireworkEffectBuilder().apply(builder).fireworkEffect
} }
fun applyTo(fireworkMeta: FireworkMeta): FireworkMeta { fun applyTo(fireworkMeta: FireworkMeta): FireworkMeta {
fireworkMeta.addEffects(effects) fireworkMeta.addEffects(effects)
power?.let { fireworkMeta.power = it } power?.let { fireworkMeta.power = it }
return fireworkMeta return fireworkMeta
} }
} }
class FireworkEffectBuilder { class FireworkEffectBuilder {
private val fireworkBuilder = FireworkEffect.builder() private val fireworkBuilder = FireworkEffect.builder()
var type: FireworkEffect.Type? = null var type: FireworkEffect.Type? = null
var trail: Boolean? = null var trail: Boolean? = null
var flicker: Boolean? = null var flicker: Boolean? = null
fun fade(vararg colors: Color) { fun fade(vararg colors: Color) {
fireworkBuilder.withFade(*colors) fireworkBuilder.withFade(*colors)
} }
@@ -55,13 +45,10 @@ class FireworkEffectBuilder {
val fireworkEffect: FireworkEffect val fireworkEffect: FireworkEffect
get() { get() {
type?.let { fireworkBuilder.with(it) } type?.let { fireworkBuilder.with(it) }
trail?.let { fireworkBuilder.trail(it) } trail?.let { fireworkBuilder.trail(it) }
flicker?.let { fireworkBuilder.flicker(it) } flicker?.let { fireworkBuilder.flicker(it) }
return fireworkBuilder.build() return fireworkBuilder.build()
} }
} }

View File

@@ -33,9 +33,7 @@ fun PersistentDataHolder.unmark(key: String) {
* this objects' markings. * this objects' markings.
*/ */
fun PersistentDataHolder.hasMark(key: String) = persistentDataContainer.has(markerKey(key), PersistentDataType.BYTE) fun PersistentDataHolder.hasMark(key: String) = persistentDataContainer.has(markerKey(key), PersistentDataType.BYTE)
// quick access for ItemStacks // quick access for ItemStacks
/** @see PersistentDataHolder.mark */ /** @see PersistentDataHolder.mark */
fun ItemStack.mark(key: String) = meta { mark(key) } fun ItemStack.mark(key: String) = meta { mark(key) }