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")
public class KColors {
// DEFAULT CODES
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>
*/
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 {
private val components = ArrayList<BaseComponent>()
// COMPONENTS
inline fun text(text: String, builder: TextComponent.() -> Unit = { }) {
this += TextComponent(text).apply(builder)
}
@@ -40,13 +37,11 @@ class KSpigotComponentBuilder {
inline fun translatable(
translatable: String,
with: Array<BaseComponent>,
builder: TranslatableComponent.() -> Unit = { }
builder: TranslatableComponent.() -> Unit = { },
) {
this += TranslatableComponent(translatable, with).apply(builder)
}
// SPECIAL
fun legacyText(text: String, color: ChatColor = ChatColor.WHITE, builder: BaseComponent.() -> Unit = { }) {
this += TextComponent.fromLegacyText(text, color).onEach { it.apply(builder) }
}
@@ -60,15 +55,11 @@ class KSpigotComponentBuilder {
}
fun create() = components.toTypedArray()
}
/*
* BASE COMPONENT
*/
// extensions
inline fun BaseComponent.hoverEventText(builder: KSpigotComponentBuilder.() -> Unit) {
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) {
clickEvent = ClickEvent(action, value)
}
/*
* GLOBAL SHORTCUTS
*/

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ internal class PlayerInputChat(
player: Player,
callback: (PlayerInputResult<String>) -> Unit,
timeoutSeconds: Int,
question: String
question: String,
) : PlayerInput<String>(player, callback, timeoutSeconds) {
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 file: File,
private val saveAfterLoad: Boolean,
private val defaultCallback: (() -> T)?
private val defaultCallback: (() -> T)?,
) {
private var internalConfig: T = loadIt()
var data: T
get() = internalConfig
set(value) {
@@ -55,7 +53,6 @@ class ConfigDelegate<T : Any>(
}
operator fun getValue(thisRef: Any?, property: KProperty<*>) = internalConfig
operator fun setValue(thisRef: Any?, property: KProperty<*>, config: T): Boolean {
internalConfig = config
return true
@@ -79,7 +76,6 @@ class ConfigDelegate<T : Any>(
}
private fun loadIt(): T {
val loaded = if (defaultCallback == null)
GsonConfigManager.loadConfig(file, configClass)
else
@@ -90,13 +86,10 @@ class ConfigDelegate<T : Any>(
saveIt(loaded)
return loaded
}
}
internal object GsonConfigManager {
fun <T : Any> loadConfig(file: File, configClass: KClass<T>): T =
FileReader(file).use { reader -> return getGson().fromJson(reader, configClass.java) }
@@ -111,7 +104,7 @@ internal object GsonConfigManager {
file: File,
configClass: KClass<T>,
pretty: Boolean = true,
default: () -> T
default: () -> T,
): T {
try {
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
class NBTData {
val nbtTagCompound: NBTTagCompound
constructor(nbtTagCompound: NBTTagCompound?) {
@@ -60,9 +59,6 @@ class NBTData {
operator fun minusAssign(key: String) = remove(key)
companion object {
fun deserialize(nbtString: String) = NBTData(nbtString)
}
}

View File

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

View File

@@ -28,7 +28,7 @@ fun Listener.unregister() = HandlerList.unregisterAll(this)
inline fun <reified T : Event> Listener.register(
priority: EventPriority = EventPriority.NORMAL,
ignoreCancelled: Boolean = false,
noinline executor: (Listener, Event) -> Unit
noinline executor: (Listener, Event) -> Unit,
) {
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(
priority: EventPriority = EventPriority.NORMAL,
ignoreCancelled: Boolean = false
ignoreCancelled: Boolean = false,
) {
register<T>(priority, ignoreCancelled) { _, event ->
(event as? T)?.let { this.onEvent(it) }
@@ -68,7 +68,7 @@ inline fun <reified T : Event> listen(
priority: EventPriority = EventPriority.NORMAL,
ignoreCancelled: Boolean = false,
register: Boolean = true,
crossinline onEvent: (event: T) -> Unit
crossinline onEvent: (event: T) -> Unit,
): SingleListener<T> {
val listener = object : SingleListener<T> {
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.NamespacedKey
import org.bukkit.command.CommandSender
import org.bukkit.entity.Entity
import org.bukkit.entity.Player
/**

View File

@@ -1,7 +1,5 @@
package net.axay.kspigot.extensions.bukkit
// FROM BUNGEE COLOR
/**
* 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
get() = color
// FROM BUKKIT COLOR
/**
* 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
get() = java.awt.Color(asRGB())
// FROM JAVA AWT COLOR
/**
* 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
get() = net.md_5.bungee.api.ChatColor.of(this)
// FROM BUKKIT CHAT COLOR
/**
* Returns the corresponding Bukkit Color object.
*/

View File

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

View File

@@ -15,7 +15,7 @@ fun Inventory.closeForViewers() = HashSet(viewers).forEach { it.closeInventory()
val InventoryAction.isSimple
get() = when (this) {
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
else -> false
}

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ import org.bukkit.util.Vector
data class SimpleLocation2D(
val x: Double,
val y: Double
val y: Double,
) {
constructor(x: Number, y: Number)
: this(x.toDouble(), y.toDouble())
@@ -19,30 +19,23 @@ data class SimpleLocation3D(
val x: Double,
val y: 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)
: this(x.toDouble(), y.toDouble(), z.toDouble())
val chunk: SimpleChunkLocation
get() = SimpleChunkLocation(x.toInt() shr 4, z.toInt() shr 4)
}
data class SimpleChunkLocation(
val x: Int,
val z: Int
val z: Int,
)
// CONVERTER
fun Location.toSimple() = SimpleLocation3D(x, y, z)
fun Chunk.toSimple() = SimpleChunkLocation(x, z)
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 Vector.toSimpleLoc() = SimpleLocation3D(x, y, z)
fun SimpleLocation3D.toVector() = Vector(x, y, z)

View File

@@ -10,21 +10,17 @@ import kotlin.math.max
import kotlin.math.min
class SimpleLocationPair(loc1: Location, loc2: Location) {
val world = loc1.worldOrException.let {
if (it == loc2.worldOrException) it
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 maxSimpleLoc = SimpleLocation3D(max(loc1.x, loc2.x), max(loc1.y, loc2.y), max(loc1.z, loc2.z))
fun isInArea(
loc: Location,
check3d: Boolean = true,
tolerance: Int = 0
tolerance: Int = 0,
): Boolean {
// checking world
if (loc.world != world) return false
@@ -37,11 +33,9 @@ class SimpleLocationPair(loc1: Location, loc2: Location) {
// checking y
if (check3d) loc.y >= minSimpleLoc.y - tolerance && loc.y <= maxSimpleLoc.y + tolerance else true
} else false
}
val touchedSimpleChunks: Set<SimpleChunkLocation> by lazy {
val foundChunks = HashSet<SimpleChunkLocation>()
(minSimpleLoc.chunk.x until maxSimpleLoc.chunk.x + 1).forEach { curX ->
@@ -51,13 +45,10 @@ class SimpleLocationPair(loc1: Location, loc2: Location) {
}
return@lazy foundChunks
}
}
class LocationArea(loc1: Location, loc2: Location) {
var loc1: Location = loc1
set(value) {
field = value
@@ -68,19 +59,14 @@ class LocationArea(loc1: Location, loc2: Location) {
field = value
simpleLocationPair = SimpleLocationPair(loc1, value)
}
var simpleLocationPair = SimpleLocationPair(loc1, loc2); private set
val world: World get() = simpleLocationPair.world
val minLoc: Location get() = simpleLocationPair.minSimpleLoc.withWorld(simpleLocationPair.world)
val maxLoc: Location get() = simpleLocationPair.maxSimpleLoc.withWorld(simpleLocationPair.world)
val touchedChunks: Set<Chunk> get() = simpleLocationPair.touchedSimpleChunks.mapTo(HashSet()) { it.withWorld(world) }
fun isInArea(
loc: Location,
check3d: Boolean = true,
tolerance: Int = 0
tolerance: Int = 0,
) = 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.reduceYZ(distance: Number) = subtract(0.0, distance, distance)
infix fun Location.reduceXZ(distance: Number) = subtract(distance, 0.0, distance)
// extensions
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())
val Location.blockLoc: Location get() = Location(world, blockX.toDouble(), blockY.toDouble(), blockZ.toDouble())
infix fun Location.relationTo(loc: Location) = this.subtract(loc).toSimple()
// 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.increase(loc: SimpleLocation3D) = add(loc.x, loc.y, loc.z)
infix fun Location.reduce(loc: SimpleLocation3D) = subtract(loc.x, loc.y, loc.z)
/*
* VECTOR
*/
val Vector.isFinite: Boolean get() = x.isFinite() && y.isFinite() && z.isFinite()
// fast construct

View File

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

View File

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

View File

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

View File

@@ -6,5 +6,5 @@ import org.bukkit.event.inventory.InventoryClickEvent
class GUIClickEvent<T : ForInventory>(
val bukkitEvent: InventoryClickEvent,
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>(
private val resetOnClose: Boolean = true,
private val resetOnQuit: Boolean = true
private val resetOnQuit: Boolean = true,
) : GUICreator<T>() {
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 fun onClick(clickEvent: GUIClickEvent<T>)
}
// ELEMENT
abstract class GUIElement<T : ForInventory> : GUISlot<T>() {
abstract fun getItemStack(slot: Int): ItemStack
final override fun onClick(clickEvent: GUIClickEvent<T>) {
clickEvent.guiInstance.gui.data.generalOnClick?.invoke(clickEvent)
onClickElement(clickEvent)
}
protected abstract fun onClickElement(clickEvent: GUIClickEvent<T>)
internal open fun startUsing(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? {
if (page != null)
guiInstance.loadPageUnsafe(page)
return openInventory(guiInstance.bukkitInventory)
}

View File

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

View File

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

View File

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

View File

@@ -9,11 +9,9 @@ import org.bukkit.inventory.InventoryHolder
class GUIType<in T : ForInventory>(
val dimensions: InventoryDimensions,
val bukkitType: InventoryType? = null
val bukkitType: InventoryType? = null,
) {
companion object {
val ONE_BY_NINE = GUIType<ForInventoryOneByNine>(InventoryDimensions(9, 1))
val TWO_BY_NINE = GUIType<ForInventoryTwoByNine>(InventoryDimensions(9, 2))
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)
val THREE_BY_THREE =
GUIType<ForInventoryThreeByThree>(InventoryDimensions(3, 3), bukkitType = InventoryType.DROPPER)
}
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)
}
}
}
// INVENTORY TYPE SAFETY
interface ForInventory
interface ForInventoryThreeByThree : ForInventoryThreeByNine
interface ForInventoryOneByFive : ForInventoryOneByNine
interface ForInventoryOneByNine : ForInventoryTwoByNine
@@ -49,7 +42,6 @@ interface ForInventoryThreeByNine : ForInventoryFourByNine
interface ForInventoryFourByNine : ForInventoryFiveByNine
interface ForInventoryFiveByNine : ForInventorySixByNine
interface ForInventorySixByNine : ForInventory
interface ForEveryInventory
: ForInventoryOneByNine, ForInventoryTwoByNine, ForInventoryThreeByNine,
ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,15 +9,12 @@ import org.json.JSONObject
class IPHub(
private val apiKey: String,
private val ifStrict: Boolean = false
private val ifStrict: Boolean = false,
) : BadIPDetectionService("iphub.info") {
override fun requestString(ip: String) = "http://v2.api.iphub.info/ip/$ip"
override fun requestHeaders() = mapOf("X-Key" to apiKey)
override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
val ifBlock = result.getStringOrNull("block")?.toInt() ?: return BadIPDetectionResult.ERROR
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
class IPInfo(
private val token: String
private val token: String,
) : BadIPDetectionService("ipinfo.io") {
override fun requestString(ip: String) = "https://ipinfo.io/$ip/privacy?token=$token"
override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
return when {
result.getStringOrNull("vpn").toBoolean() -> BadIPDetectionResult.VPN
@@ -20,5 +18,4 @@ class IPInfo(
else -> BadIPDetectionResult.GOOD
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,5 @@
package net.axay.kspigot.languageextensions.kotlinextensions
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 fun Lazy<AutoCloseable>.closeIfInitialized() = ifInitialized { value.close() }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,13 +24,10 @@ object ItemMetaSerializer : KSerializerForBukkit<ItemMeta>(ItemMeta::class)
object ItemStackSerializer : KSerializerForBukkit<ItemStack>(ItemStack::class)
object LocationSerializer : KSerializerForBukkit<Location>(Location::class)
object VectorSerializer : KSerializerForBukkit<Vector>(Vector::class)
open class KSerializerForBukkit<T : ConfigurationSerializable>(
private val kClass: KClass<T>
private val kClass: KClass<T>,
) : KSerializer<T> {
override val descriptor = ByteArraySerializer().descriptor
override fun serialize(encoder: Encoder, value: T) {
val bytes = ByteArrayOutputStream()
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}")
}
}
}

View File

@@ -11,14 +11,16 @@ data class SerializableLocation(
val x: Double,
val y: Double,
val z: Double,
val direction: SerializableVector
val direction: SerializableVector,
) : SpigotSerializable<Location> {
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)
.apply { direction = this@SerializableLocation.direction.toSpigot() }
}

View File

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

View File

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

View File

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

View File

@@ -9,15 +9,12 @@ import org.bukkit.Material
import org.bukkit.entity.EntityType
private fun circleEdgeLocations(radius: Number) = HashSet<SimpleLocation2D>().apply {
val currentRadius = radius.toDouble()
var d = -currentRadius
var x = currentRadius
var y = 0
while (y <= x) {
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
x--
}
}
}
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) {
protected abstract val data: StructureData
val fillLocations by lazy {
var currentRadius = radius.toDouble()
HashSet<SimpleLocation2D>().apply {
@@ -70,17 +62,12 @@ abstract class Circle(val radius: Number) {
currentRadius--
}
}
}
val edgeLocations by lazy {
circleEdgeLocations(radius)
}
val filledStructure by lazy { structure(true) }
val edgeStructure by lazy { structure(false) }
fun structure(filled: Boolean) = Structure(
HashSet<SingleStructureData>().apply {
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)
}
)
}
class MaterialCircle(radius: Number, material: Material) : Circle(radius) {

View File

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

View File

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

View File

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

View File

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