From baff0de0bacd06bd2ec5137ddd7fcadb9e49c3a4 Mon Sep 17 00:00:00 2001 From: Denis Istratov Date: Mon, 21 Aug 2023 13:00:30 +0300 Subject: [PATCH] Added extensions module --- .../kotlinbukkitkit/extensions/ExBlock.kt | 33 ++ .../kotlinbukkitkit/extensions/ExBukkit.kt | 72 ++++ .../kotlinbukkitkit/extensions/ExCommand.kt | 49 +++ .../extensions/ExConfiguration.kt | 47 +++ .../kotlinbukkitkit/extensions/ExEntity.kt | 41 ++ .../kotlinbukkitkit/extensions/ExEvent.kt | 79 ++++ .../kotlinbukkitkit/extensions/ExInventory.kt | 33 ++ .../kotlinbukkitkit/extensions/ExItemStack.kt | 95 +++++ .../kotlinbukkitkit/extensions/ExLocation.kt | 57 +++ .../extensions/ExPermission.kt | 17 + .../kotlinbukkitkit/extensions/ExPlayer.kt | 44 +++ .../kotlinbukkitkit/extensions/ExPlugin.kt | 34 ++ .../kotlinbukkitkit/extensions/ExScheduler.kt | 70 ++++ .../kotlinbukkitkit/extensions/ExServer.kt | 90 +++++ .../kotlinbukkitkit/extensions/ExText.kt | 374 ++++++++++++++++++ .../kotlinbukkitkit/extensions/ExWorld.kt | 55 +++ settings.gradle.kts | 1 + 17 files changed, 1191 insertions(+) create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExBlock.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExBukkit.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExCommand.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExConfiguration.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExEntity.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExEvent.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExInventory.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExItemStack.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExLocation.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPermission.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPlayer.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPlugin.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExScheduler.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExServer.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExText.kt create mode 100644 extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExWorld.kt diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExBlock.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExBlock.kt new file mode 100644 index 0000000..9af4403 --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExBlock.kt @@ -0,0 +1,33 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.Material +import org.bukkit.block.Block +import org.bukkit.entity.Player +import org.bukkit.material.MaterialData + +public infix fun Block.eqType(block: Block): Boolean = type == block.type && data == block.data +public infix fun Block.eqType(data: MaterialData): Boolean = type == data.itemType && this.data == data.data +public infix fun Block.eqType(material: Material): Boolean = type == material + +public fun Block.sendBlockChange( + materialData: MaterialData, + players: List, +): Unit = sendBlockChange(materialData.itemType, materialData.data, players) + +public fun Block.sendBlockChange( + material: Material, + data: Byte = 0, + players: List, +) { + players.filter { it.world.name == world.name }.forEach { + it.sendBlockChange(location, material, data) + } +} diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExBukkit.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExBukkit.kt new file mode 100644 index 0000000..c2f6581 --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExBukkit.kt @@ -0,0 +1,72 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import net.md_5.bungee.api.chat.BaseComponent +import net.md_5.bungee.api.chat.TextComponent +import org.bukkit.Bukkit +import org.bukkit.Server +import org.bukkit.command.ConsoleCommandSender +import org.bukkit.entity.Player + +public val server: Server get() = Bukkit.getServer() + +public object Console : ConsoleCommandSender by Bukkit.getConsoleSender() { + public fun command(command: String): Boolean = Bukkit.dispatchCommand(this, command) +} + +// logger +// todo: remove and use standard logging library, maybe extensions for it +public object Log { + public fun info(message: String): Unit = Bukkit.getLogger().info(message) + public fun warn(message: String): Unit = Bukkit.getLogger().warning(message) + public fun severe(message: String): Unit = Bukkit.getLogger().severe(message) + public fun fine(message: String): Unit = Bukkit.getLogger().fine(message) +} + +public fun broadcast(message: String) { + Bukkit.broadcastMessage(message) +} + +public inline fun broadcast( + players: Iterable = Bukkit.getOnlinePlayers(), + message: Player.() -> String, +) { + for (player in players) + player.msg(message.invoke(player)) +} + +public fun Collection.broadcast( + message: Player.() -> String, +): Unit = broadcast(this, message) + +public fun Array.broadcast( + message: Player.() -> String, +): Unit = broadcast(this.toList(), message) + +// BaseComponent + +public fun broadcast(message: BaseComponent) { + broadcastComponent { arrayOf(message) } + Bukkit.getConsoleSender().msg(TextComponent.toLegacyText(message)) +} + +public fun broadcast(message: Array) { + broadcastComponent { message } + Bukkit.getConsoleSender().msg(TextComponent.toLegacyText(*message)) +} + +public inline fun broadcastComponent( + players: Iterable = Bukkit.getOnlinePlayers(), + message: Player.() -> Array, +) { + for (player in players) { + player.msg(message.invoke(player)) + } +} diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExCommand.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExCommand.kt new file mode 100644 index 0000000..6691415 --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExCommand.kt @@ -0,0 +1,49 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.Bukkit +import org.bukkit.command.Command +import org.bukkit.command.SimpleCommandMap +import org.bukkit.plugin.Plugin +import java.lang.reflect.Field + +private val serverCommands: SimpleCommandMap by lazy { + val server = Bukkit.getServer() + server::class.java.getDeclaredField("commandMap").apply { + isAccessible = true + }.get(server) as SimpleCommandMap +} + +private val knownCommandsField: Field by lazy { + SimpleCommandMap::class.java.getDeclaredField("knownCommands").apply { + isAccessible = true + } +} + +public fun Command.register(plugin: Plugin) { + serverCommands.register(plugin.name, this) +} + +public fun Command.unregister() { + try { + val knownCommands = knownCommandsField.get(serverCommands) as MutableMap + val toRemove = ArrayList() + for ((key, value) in knownCommands) { + if (value === this) { + toRemove.add(key) + } + } + for (str in toRemove) { + knownCommands.remove(str) + } + } catch (e: Exception) { + e.printStackTrace() + } +} diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExConfiguration.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExConfiguration.kt new file mode 100644 index 0000000..d0eefde --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExConfiguration.kt @@ -0,0 +1,47 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.configuration.ConfigurationSection + +public fun ConfigurationSection.putAll(map: Map) { + for ((key, value) in map) { + if (value is Map<*, *>) { + set(key, null) + (getConfigurationSection(key) ?: createSection(key)).putAll(value as Map) + } else { + set(key, value) + } + } +} + +/** + * @returns the count of absent values that was set, if returns 0, no values was set to the Configuration + */ +public fun ConfigurationSection.putAllIfAbsent(map: Map): Int { + var missing = 0 + for ((key, value) in map) { + if (value is Map<*, *>) { + missing += (getConfigurationSection(key) ?: createSection(key)).putAllIfAbsent(value as Map) + } else if (!contains(key)) { + missing++ + } + } + return missing +} + +public fun ConfigurationSection.toMap(): Map { + return getValues(false).apply { + forEach { k, v -> + if (v is ConfigurationSection) { + set(k, v.toMap()) + } + } + } +} diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExEntity.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExEntity.kt new file mode 100644 index 0000000..ccacc2a --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExEntity.kt @@ -0,0 +1,41 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.Location +import org.bukkit.entity.Entity +import org.bukkit.entity.EntityType +import org.bukkit.entity.Firework +import org.bukkit.entity.Player +import org.bukkit.entity.Projectile +import org.bukkit.inventory.meta.FireworkMeta +import org.bukkit.projectiles.ProjectileSource +import org.bukkit.util.Vector +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +public fun Entity.isPlayer(): Boolean { + contract { returns(true) implies (this@isPlayer is Player) } + + return type == EntityType.PLAYER +} + +// firework + +public inline fun firework(location: Location, block: FireworkMeta.() -> Unit): Firework { + return location.spawn().apply { meta(block) } +} + +public inline fun Firework.meta(block: FireworkMeta.() -> Unit): Firework = apply { + fireworkMeta = fireworkMeta.apply(block) +} + +public inline fun ProjectileSource.launchProjectile(): T = launchProjectile(T::class.java) +public inline fun ProjectileSource.launchProjectile(vector: Vector): T = launchProjectile(T::class.java, vector) diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExEvent.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExEvent.kt new file mode 100644 index 0000000..3e1197a --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExEvent.kt @@ -0,0 +1,79 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import me.redtea.kotlinbukkitkit.architecture.extensions.WithPlugin +import org.bukkit.Bukkit +import org.bukkit.event.Event +import org.bukkit.event.EventPriority +import org.bukkit.event.HandlerList +import org.bukkit.event.Listener +import org.bukkit.event.player.PlayerMoveEvent +import org.bukkit.plugin.Plugin +import kotlin.reflect.KClass + +public inline fun KListener<*>.event( + priority: EventPriority = EventPriority.NORMAL, + ignoreCancelled: Boolean = false, + noinline block: T.() -> Unit, +): Unit = event(plugin, priority, ignoreCancelled, block) + +public fun KListener<*>.event( + type: KClass, + priority: EventPriority = EventPriority.NORMAL, + ignoreCancelled: Boolean = false, + block: T.() -> Unit, +): Unit = event(plugin, type, priority, ignoreCancelled, block) + +public inline fun Listener.event( + plugin: Plugin, + priority: EventPriority = EventPriority.NORMAL, + ignoreCancelled: Boolean = false, + noinline block: T.() -> Unit, +) { + event(plugin, T::class, priority, ignoreCancelled, block) +} + +public fun Listener.event( + plugin: Plugin, + type: KClass, + priority: EventPriority = EventPriority.NORMAL, + ignoreCancelled: Boolean = false, + block: T.() -> Unit, +) { + Bukkit.getServer().pluginManager.registerEvent( + type.java, + this, + priority, + { _, event -> + if (type.isInstance(event)) { + (event as? T)?.block() + } + }, + plugin, + ignoreCancelled, + ) +} + +public inline fun WithPlugin<*>.events(block: KListener<*>.() -> Unit): SimpleKListener = plugin.events(block) +public inline fun Plugin.events(block: KListener<*>.() -> Unit): SimpleKListener = SimpleKListener(this).apply(block) + +public fun Listener.registerEvents(plugin: Plugin): Unit = plugin.server.pluginManager.registerEvents(this, plugin) + +public fun Listener.unregisterListener(): Unit = HandlerList.unregisterAll(this) + +public fun Event.callEvent(): Unit = Bukkit.getServer().pluginManager.callEvent(this) + +public val PlayerMoveEvent.displaced: Boolean + get() = this.from.x != this.to?.x || this.from.y != this.to?.y || this.from.z != this.to?.z + +// TODO: remove KListener and move to Context Receivers +public interface KListener : Listener, WithPlugin + +public class SimpleKListener(override val plugin: Plugin) : KListener diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExInventory.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExInventory.kt new file mode 100644 index 0000000..891e8b5 --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExInventory.kt @@ -0,0 +1,33 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.Material +import org.bukkit.inventory.Inventory +import org.bukkit.inventory.ItemStack + +public val Inventory.hasSpace: Boolean + get() = contents.any { it == null || it.type == Material.AIR } + +public fun Inventory.hasSpace( + item: ItemStack, + amount: Int = item.amount, +): Boolean = spaceOf(item) >= amount + +public fun Inventory.spaceOf( + item: ItemStack, +): Int { + return contents.filterNotNull().map { + if (it.amount < it.maxStackSize && it.isSimilar(item)) { + it.maxStackSize - it.amount + } else { + 0 + } + }.count() +} diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExItemStack.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExItemStack.kt new file mode 100644 index 0000000..1def11d --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExItemStack.kt @@ -0,0 +1,95 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import com.google.common.collect.Multimap +import org.bukkit.Material +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.ItemMeta +import org.bukkit.inventory.meta.SkullMeta +import org.bukkit.material.MaterialData +import java.util.* + +public inline fun item( + material: Material, + amount: Int = 1, + data: Short = 0, + meta: ItemMeta.() -> Unit = {}, +): ItemStack = ItemStack(material, amount, data).meta(meta) + +public inline fun metadataItem( + material: Material, + amount: Int = 1, + data: Short = 0, + meta: T.() -> Unit, +): ItemStack = ItemStack(material, amount, data).meta(meta) + +public inline fun ItemStack.meta( + block: T.() -> Unit, +): ItemStack = apply { + itemMeta = (itemMeta as? T)?.apply(block) ?: itemMeta +} + +public fun ItemStack.displayName(displayName: String?): ItemStack = meta { + this.setDisplayName(displayName) +} + +public fun ItemStack.lore(lore: List): ItemStack = meta { + this.lore = lore +} + +public inline fun Material.asItemStack( + amount: Int = 1, + data: Short = 0, + meta: ItemMeta.() -> Unit = {}, +): ItemStack = item(this, amount, data, meta) + +public fun Material.asMaterialData( + data: Byte = 0, +): MaterialData = MaterialData(this, data) + +public fun MaterialData.toItemStack( + amount: Int = 1, + meta: ItemMeta.() -> Unit = {}, +): ItemStack = toItemStack(amount).meta(meta) + +/** + * get head from base64 + */ +private val gameProfileClass by lazy { Class.forName("com.mojang.authlib.GameProfile") } +private val propertyClass by lazy { Class.forName("com.mojang.authlib.properties.Property") } +private val getPropertiesMethod by lazy { gameProfileClass.getMethod("getProperties") } +private val gameProfileConstructor by lazy { gameProfileClass.getConstructor(UUID::class.java, String::class.java) } +private val propertyConstructor by lazy { propertyClass.getConstructor(String::class.java, String::class.java) } + +public fun headFromBase64(base64: String): ItemStack { + val item = ItemStack(Material.LEGACY_SKULL_ITEM, 1, 3) + val meta = item.itemMeta as SkullMeta + + val profile = gameProfileConstructor.newInstance(UUID.randomUUID(), null as String?) + val properties = getPropertiesMethod.invoke(profile) as Multimap + properties.put("textures", propertyConstructor.newInstance("textures", base64)) + + val profileField = meta.javaClass.getDeclaredField("profile").apply { isAccessible = true } + profileField.set(meta, profile) + + return item.apply { itemMeta = meta } +} + +public inline val Material.isPickaxe: Boolean get() = name.endsWith("PICKAXE") +public inline val Material.isSword: Boolean get() = name.endsWith("SWORD") +public inline val Material.isAxe: Boolean get() = name.endsWith("_AXE") +public inline val Material.isSpade: Boolean get() = name.endsWith("SPADE") +public inline val Material.isHoe: Boolean get() = name.endsWith("HOE") +public inline val Material.isOre: Boolean get() = name.endsWith("ORE") +public inline val Material.isIngot: Boolean get() = name.endsWith("INGOT") +public inline val Material.isDoor: Boolean get() = name.endsWith("DOOR") +public inline val Material.isMinecart: Boolean get() = name.endsWith("MINECART") +public inline val Material.isWater: Boolean get() = this == Material.WATER || this == Material.LEGACY_STATIONARY_WATER +public inline val Material.isLava: Boolean get() = this == Material.LAVA || this == Material.LEGACY_STATIONARY_LAVA diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExLocation.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExLocation.kt new file mode 100644 index 0000000..a89542d --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExLocation.kt @@ -0,0 +1,57 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.BlockChangeDelegate +import org.bukkit.Effect +import org.bukkit.Location +import org.bukkit.Sound +import org.bukkit.TreeType +import org.bukkit.block.Block +import org.bukkit.entity.Arrow +import org.bukkit.entity.Entity +import org.bukkit.entity.Item +import org.bukkit.entity.LightningStrike +import org.bukkit.inventory.ItemStack +import org.bukkit.util.Vector + +public operator fun Location.component1(): Double = x +public operator fun Location.component2(): Double = y +public operator fun Location.component3(): Double = z +public operator fun Location.component4(): Float = yaw +public operator fun Location.component5(): Float = pitch + +public operator fun Block.component1(): Int = x +public operator fun Block.component2(): Int = y +public operator fun Block.component3(): Int = z + +public fun Location.dropItem(item: ItemStack): Item = world!!.dropItem(this, item) +public fun Location.dropItemNaturally(item: ItemStack): Item = world!!.dropItemNaturally(this, item) + +public fun Location.spawnArrow(direction: Vector, speed: Float, spread: Float): Arrow = world!!.spawnArrow(this, direction, speed, spread) + +public fun Location.generateTree(type: TreeType): Boolean = world!!.generateTree(this, type) +public fun Location.generateTree(type: TreeType, delegate: BlockChangeDelegate): Boolean = world!!.generateTree(this, type, delegate) + +public fun Location.strikeLightning(): LightningStrike = world!!.strikeLightning(this) +public fun Location.strikeLightningEffect(): LightningStrike = world!!.strikeLightningEffect(this) + +public fun Location.getNearbyEntities(x: Double, y: Double, z: Double): MutableCollection = world!!.getNearbyEntities(this, x, y, z) + +public fun Location.createExplosion(power: Float): Boolean = world!!.createExplosion(this, power) +public fun Location.createExplosion(power: Float, setFire: Boolean): Boolean = world!!.createExplosion(this, power, setFire) + +public inline fun Location.spawn(): T = world!!.spawn(this) + +public fun Location.playEffect(effect: Effect, data: Int): Unit = world!!.playEffect(this, effect, data) +public fun Location.playEffect(effect: Effect, data: Int, radius: Int): Unit = world!!.playEffect(this, effect, data, radius) +public fun Location.playEffect(effect: Effect, data: T): Unit = world!!.playEffect(this, effect, data) +public fun Location.playEffect(effect: Effect, data: T, radius: Int): Unit = world!!.playEffect(this, effect, data, radius) + +public fun Location.playSound(sound: Sound, volume: Float, pitch: Float): Unit = world!!.playSound(this, sound, volume, pitch) diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPermission.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPermission.kt new file mode 100644 index 0000000..421031f --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPermission.kt @@ -0,0 +1,17 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.permissions.Permissible + +public fun Permissible.anyPermission(vararg permissions: String): Boolean = permissions.any { hasPermission(it) } + +public fun Permissible.allPermission(vararg permissions: String): Boolean = permissions.all { hasPermission(it) } + +public fun Permissible.hasPermissionOrStar(permission: String): Boolean = hasPermission(permission) || hasPermission(permission.replaceAfterLast('.', "*")) diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPlayer.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPlayer.kt new file mode 100644 index 0000000..dd0d568 --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPlayer.kt @@ -0,0 +1,44 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.Effect +import org.bukkit.Instrument +import org.bukkit.Material +import org.bukkit.Note +import org.bukkit.Sound +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.PlayerInventory + +public fun PlayerInventory.clearArmor() { + setArmorContents(arrayOf(null, null, null, null)) +} + +public fun PlayerInventory.clearAll() { + clear() + clearArmor() +} + +public val Player.hasItemInHand: Boolean get() = itemInHand != null && itemInHand.type != Material.AIR + +public fun Player.playSound(sound: Sound, volume: Float, pitch: Float): Unit = playSound(location, sound, volume, pitch) +public fun Player.playNote(instrument: Instrument, note: Note): Unit = playNote(location, instrument, note) +public fun Player.playEffect(effect: Effect, data: T? = null): Unit = playEffect(location, effect, data) + +public fun CommandSender.msg(message: List): Unit = message.forEach { msg(it) } + +public fun Player.resetWalkSpeed() { + walkSpeed = 0.2f +} + +public fun Player.resetFlySpeed() { + flySpeed = 0.1f +} diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPlugin.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPlugin.kt new file mode 100644 index 0000000..0ee3a43 --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExPlugin.kt @@ -0,0 +1,34 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import me.redtea.kotlinbukkitkit.architecture.extensions.WithPlugin +import org.bukkit.event.Listener +import org.bukkit.plugin.Plugin + +public fun Plugin.registerEvents( + vararg listeners: Listener, +): Unit = listeners.forEach { server.pluginManager.registerEvents(it, this) } + +public fun WithPlugin<*>.registerEvents( + vararg listeners: Listener, +): Unit = plugin.registerEvents(*listeners) + +// logger +public fun Plugin.info(message: String): Unit = logger.info(message) +public fun Plugin.warn(message: String): Unit = logger.warning(message) +public fun Plugin.severe(message: String): Unit = logger.severe(message) +public fun Plugin.debug(message: String): Unit = logger.config(message) +public fun Plugin.fine(message: String): Unit = logger.fine(message) + +public fun WithPlugin<*>.info(message: String): Unit = plugin.info(message) +public fun WithPlugin<*>.warn(message: String): Unit = plugin.warn(message) +public fun WithPlugin<*>.severe(message: String): Unit = plugin.severe(message) +public fun WithPlugin<*>.debug(message: String): Unit = plugin.debug(message) +public fun WithPlugin<*>.fine(message: String): Unit = plugin.fine(message) diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExScheduler.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExScheduler.kt new file mode 100644 index 0000000..b2c0e8b --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExScheduler.kt @@ -0,0 +1,70 @@ + +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ +package me.redtea.kotlinbukkitkit.extensions + +import me.redtea.kotlinbukkitkit.architecture.extensions.WithPlugin +import org.bukkit.plugin.Plugin +import org.bukkit.scheduler.BukkitRunnable +import org.bukkit.scheduler.BukkitTask + +public inline fun task( + delayToRun: Long = 0, + repeatDelay: Long = -1, + plugin: Plugin, + crossinline runnable: BukkitRunnable.() -> Unit, +): BukkitTask = task(delayToRun, repeatDelay, false, plugin, runnable) + +public inline fun Plugin.task( + delayToRun: Long = 0, + repeatDelay: Long = -1, + crossinline runnable: BukkitRunnable.() -> Unit, +): BukkitTask = task(delayToRun, repeatDelay, this, runnable) + +public inline fun WithPlugin<*>.task( + delayToRun: Long = 0, + repeatDelay: Long = -1, + crossinline runnable: BukkitRunnable.() -> Unit, +): BukkitTask = plugin.task(delayToRun, repeatDelay, runnable) + +public inline fun taskAsync( + delayToRun: Long = 0, + repeatDelay: Long = -1, + plugin: Plugin, + crossinline runnable: BukkitRunnable.() -> Unit, +): BukkitTask = task(delayToRun, repeatDelay, true, plugin, runnable) + +public inline fun Plugin.taskAsync( + delayToRun: Long = 0, + repeatDelay: Long = -1, + crossinline runnable: BukkitRunnable.() -> Unit, +): BukkitTask = taskAsync(delayToRun, repeatDelay, this, runnable) + +public inline fun WithPlugin<*>.taskAsync( + delayToRun: Long = 0, + repeatDelay: Long = -1, + crossinline runnable: BukkitRunnable.() -> Unit, +): BukkitTask = plugin.taskAsync(delayToRun, repeatDelay, runnable) + +public inline fun task( + delayToRun: Long, + repeatDelay: Long = -1, + async: Boolean, + plugin: Plugin, + crossinline runnable: BukkitRunnable.() -> Unit, +): BukkitTask = scheduler(runnable).run { + if (repeatDelay > -1) if (async) runTaskTimerAsynchronously(plugin, delayToRun, repeatDelay) else runTaskTimer(plugin, delayToRun, repeatDelay) + else if (delayToRun > 0) if (async) runTaskLaterAsynchronously(plugin, delayToRun) else runTaskLater(plugin, delayToRun) + else if (async) runTaskAsynchronously(plugin) else runTask(plugin) +} + +public inline fun scheduler(crossinline runnable: BukkitRunnable.() -> Unit): BukkitRunnable = object : BukkitRunnable() { + override fun run() { + this.runnable() + } +} diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExServer.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExServer.kt new file mode 100644 index 0000000..ee71ccc --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExServer.kt @@ -0,0 +1,90 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.GameMode +import org.bukkit.OfflinePlayer +import org.bukkit.World +import org.bukkit.WorldCreator +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.Recipe +import org.bukkit.plugin.PluginManager +import org.bukkit.plugin.ServicesManager +import org.bukkit.plugin.messaging.Messenger +import org.bukkit.scheduler.BukkitScheduler +import org.bukkit.scoreboard.ScoreboardManager +import java.io.File +import java.util.* + +public val isPrimaryThread: Boolean get() = server.isPrimaryThread + +public fun offlinePlayer(uuid: UUID): OfflinePlayer = server.getOfflinePlayer(uuid) +public fun offlinePlayer(name: String): OfflinePlayer = server.getOfflinePlayer(name) + +public fun player(uuid: UUID): Player? = server.getPlayer(uuid) +public fun player(name: String): Player? = server.getPlayer(name) +public fun playerExact(name: String): Player? = server.getPlayerExact(name) +public fun matchPlayer(name: String): List = server.matchPlayer(name) + +public fun onlinePlayer(uuid: UUID): Player? = server.getPlayer(uuid) +public fun onlinePlayer(name: String): Player? = server.getPlayerExact(name) + +public val onlinePlayers: Collection get() = server.onlinePlayers +public val worldType: String get() = server.worldType +public val generateStructures: Boolean get() = server.generateStructures +public val allowEnd: Boolean get() = server.allowEnd +public val allowNether: Boolean get() = server.allowNether +public val allowFlight: Boolean get() = server.allowFlight +public val whitelistedPlayers: MutableSet get() = server.whitelistedPlayers +public val updateFolder: String get() = server.updateFolder +public val updateFolderFile: File get() = server.updateFolderFile +public val connectionThrottle: Long get() = server.connectionThrottle +public val recipes: Iterator get() = server.recipeIterator() +public val ticksPerAnimalSpawns: Int get() = server.ticksPerAnimalSpawns +public val ticksPerMonsterSpawns: Int get() = server.ticksPerMonsterSpawns +public val pluginManager: PluginManager get() = server.pluginManager +public val scheduler: BukkitScheduler get() = server.scheduler +public val servicesManager: ServicesManager get() = server.servicesManager +public val worlds: List get() = server.worlds +public val onlineMode: Boolean get() = server.onlineMode +public val isHardcore: Boolean get() = server.isHardcore +public val bannedPlayers: Set get() = server.bannedPlayers +public val ipBans: Set get() = server.ipBans +public val operators: Set get() = server.operators +public val worldContainer: File get() = server.worldContainer +public val messenger: Messenger get() = server.messenger +public val monsterSpawnLimit: Int get() = server.monsterSpawnLimit +public val animalSpawnLimit: Int get() = server.animalSpawnLimit +public val ambientSpawnLimit: Int get() = server.ambientSpawnLimit +public val scoreboardManager: ScoreboardManager? get() = server.scoreboardManager + +public var idleTimeout: Int + get() = server.idleTimeout + set(value) { server.idleTimeout = value } + +public var defaultGameMode: GameMode + get() = server.defaultGameMode + set(value) { server.defaultGameMode = value } + +public var spawnRadius: Int + get() = server.spawnRadius + set(value) { server.spawnRadius = value } + +public var whitelist: Boolean + get() = server.hasWhitelist() + set(value) { server.setWhitelist(value) } + +public fun reloadWhitelist(): Unit = server.reloadWhitelist() + +public fun world(name: String): World? = server.getWorld(name) + +public fun addRecipe(recipe: Recipe): Boolean = server.addRecipe(recipe) +public fun recipesFor(item: ItemStack): List = server.getRecipesFor(item) + +public fun WorldCreator.create(): World? = server.createWorld(this) diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExText.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExText.kt new file mode 100644 index 0000000..820704f --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExText.kt @@ -0,0 +1,374 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import net.md_5.bungee.api.chat.BaseComponent +import net.md_5.bungee.api.chat.ClickEvent +import net.md_5.bungee.api.chat.HoverEvent +import net.md_5.bungee.api.chat.TextComponent +import net.md_5.bungee.chat.ComponentSerializer +import org.bukkit.ChatColor +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import kotlin.reflect.KProperty +import net.md_5.bungee.api.ChatColor as BungeeColor + +public fun CommandSender.msg(message: String): Unit = sendMessage(message) +public fun CommandSender.msg(message: Array): Unit = sendMessage(message) + +/** + * ONLY WITH SPIGOT + */ + +public fun textOf(text: String): TextComponent = text.asText() + +public fun String.translateColor(code: Char = '&'): String = ChatColor.translateAlternateColorCodes(code, this) +public fun Collection.translateColor(code: Char = '&'): List = map { it.translateColor(code) } +public fun Map.translateColorKeys(code: Char = '&'): Map = mapKeys { it.key.translateColor(code) } +public fun Map.translateColorValues(code: Char = '&'): Map = mapValues { it.value.translateColor(code) } + +public fun String.reverseTranslateColor(code: Char = '&'): String = replace('ยง', code) +public fun Collection.reverseTranslateColor(code: Char = '&'): List = map { it.reverseTranslateColor(code) } +public fun Map.reverseTranslateColorKeys(code: Char = '&'): Map = mapKeys { it.key.reverseTranslateColor(code) } +public fun Map.reverseTranslateColorValues(code: Char = '&'): Map = mapValues { it.value.reverseTranslateColor(code) } + +public operator fun ChatColor.plus(text: String): String = toString() + text +public operator fun ChatColor.plus(other: ChatColor): String = toString() + other.toString() + +public fun translateColor(default: String, colorChar: Char = '&'): TranslateChatColorDelegate = TranslateChatColorDelegate(default, colorChar) + +public class TranslateChatColorDelegate(public val realValue: String, public val colorChar: Char = '&') { + private var _value: String = ChatColor.translateAlternateColorCodes(colorChar, realValue) + + public operator fun getValue(thisRef: Any?, property: KProperty<*>): String = _value + + public operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { + _value = ChatColor.translateAlternateColorCodes(colorChar, value) + } +} + +public fun Player.sendMessage(text: BaseComponent): Unit = spigot().sendMessage(text) +public fun Player.sendMessage(text: Array): Unit = spigot().sendMessage(TextComponent(*text)) +public fun Player.sendMessage(text: List): Unit = sendMessage(text.toTypedArray()) +public fun CommandSender.sendMessage(text: BaseComponent): Unit = (this as? Player)?.let { it.sendMessage(text) } ?: sendMessage(TextComponent.toLegacyText(text)) +public fun CommandSender.sendMessage(text: Array): Unit = (this as? Player)?.let { it.sendMessage(text) } ?: sendMessage(TextComponent.toLegacyText(*text)) +public fun CommandSender.sendMessage(text: List): Unit = sendMessage(text.toTypedArray()) + +public fun Player.msg(text: BaseComponent): Unit = sendMessage(text) +public fun Player.msg(text: Array): Unit = sendMessage(text) +public fun Player.msg(text: List): Unit = sendMessage(text) +public fun CommandSender.msg(text: BaseComponent): Unit = sendMessage(text) +public fun CommandSender.msg(text: Array): Unit = sendMessage(text) +public fun CommandSender.msg(text: List): Unit = sendMessage(text) + +public fun String.asText(): TextComponent = TextComponent(*TextComponent.fromLegacyText(this)) +public fun List.asText(): TextComponent = TextComponent(*map { it.asText() }.toTypedArray()) + +// fun String.asText() = TextComponent(this) +public fun BaseComponent.toJson(): String = ComponentSerializer.toString(this) +public fun Array.toJson(): String = ComponentSerializer.toString(*this) + +public operator fun T.plus(component: BaseComponent): T = apply { addExtra(component) } +public operator fun T.plus(text: String): T = apply { addExtra(text) } + +public fun String.color(color: BungeeColor): TextComponent = asText().color(color) +public fun String.color(color: ChatColor): TextComponent = asText().color(BungeeColor.getByChar(color.char)) +public fun String.bold(): TextComponent = asText().bold() +public fun String.italic(): TextComponent = asText().italic() +public fun String.underline(): TextComponent = asText().underline() +public fun String.strikethrough(): TextComponent = asText().strikethrough() +public fun String.obfuscated(): TextComponent = asText().obfuscated() + +public fun String.click(clickEvent: ClickEvent): TextComponent = asText().click(clickEvent) +public fun String.openUrl(url: String): TextComponent = click(ClickEvent(ClickEvent.Action.OPEN_URL, url)) +public fun String.runCommand(command: String): TextComponent = click(ClickEvent(ClickEvent.Action.RUN_COMMAND, command)) +public fun String.suggestCommand(command: String): TextComponent = click(ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)) + +public fun String.hover(hoverEvent: HoverEvent): TextComponent = asText().hover(hoverEvent) +public fun String.showText(component: BaseComponent): TextComponent = hover(HoverEvent(HoverEvent.Action.SHOW_TEXT, arrayOf(component))) +public fun String.showText(vararg components: BaseComponent): TextComponent = hover(HoverEvent(HoverEvent.Action.SHOW_TEXT, components)) + +/** + * Chaining methods for TextComponent and BaseComponent + */ + +public fun TextComponent.append(text: String): TextComponent = apply { addExtra(text) } +public fun TextComponent.append(text: BaseComponent): TextComponent = apply { addExtra(text) } +public fun TextComponent.breakLine(): TextComponent = apply { addExtra("\\n") } + +public fun T.color(color: BungeeColor): T = apply { this.color = color } +public fun T.color(color: ChatColor): T = apply { this.color = BungeeColor.getByChar(color.char) } +public fun T.bold(): T = apply { isBold = true } +public fun T.italic(): T = apply { isItalic = true } +public fun T.underline(): T = apply { isUnderlined = true } +public fun T.strikethrough(): T = apply { isStrikethrough = true } +public fun T.obfuscated(): T = apply { isObfuscated = true } + +public fun T.click(clickEvent: ClickEvent): T = apply { this.clickEvent = clickEvent } +public fun T.openUrl(url: String): T = click(ClickEvent(ClickEvent.Action.OPEN_URL, url)) +public fun T.runCommand(command: String): T = click(ClickEvent(ClickEvent.Action.RUN_COMMAND, command)) +public fun T.suggestCommand(command: String): T = click(ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)) + +public fun T.hover(hoverEvent: HoverEvent): T = apply { this.hoverEvent = hoverEvent } +public fun T.showText(component: BaseComponent): T = hover(HoverEvent(HoverEvent.Action.SHOW_TEXT, arrayOf(component))) +public fun T.showText(vararg components: BaseComponent): T = hover(HoverEvent(HoverEvent.Action.SHOW_TEXT, components)) + +/** + * Replaces + */ + +/** + * Replace current [TextComponent.text], [BaseComponent.hover] text + * and [BaseComponent.click] text using [String.replace]. + */ +public fun T.replace( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + replaceOnHover(oldValue, newValue, ignoreCase) + replaceOnClick(oldValue, newValue, ignoreCase) + (this as? TextComponent)?.replaceOnText(oldValue, newValue, ignoreCase) +} + +/** + * Replace the current [BaseComponent] text, hover and click and all the [BaseComponent.extra] + * + * See [BaseComponent.replace]. + */ +public fun T.replaceAll( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + replaceOnAllHovers(oldValue, newValue, ignoreCase) + replaceOnAllClick(oldValue, newValue, ignoreCase) + (this as? TextComponent)?.replaceOnAllTexts(oldValue, newValue, ignoreCase) +} + +/** + * Replace the current [BaseComponent] hover [oldValue] to [newValue] with [String.replace] + */ +public fun T.replaceOnHover( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + if (hoverEvent != null) { + for (component in hoverEvent.value) + if (component is TextComponent) component.replaceOnAllTexts(oldValue, newValue, ignoreCase) + } +} + +/** + * Replace the current [BaseComponent] hover and all the [BaseComponent.extra] + * + * See [BaseComponent.replaceOnHover] + */ +public fun T.replaceOnAllHovers( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T { + return apply { + replaceOnHover(oldValue, newValue, ignoreCase) + if (extra != null) { + for (component in extra) + component.replaceOnAllHovers(oldValue, newValue, ignoreCase) + } + } +} + +public fun T.replaceOnShowText( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + if (hoverEvent != null) { + if (hoverEvent.action == HoverEvent.Action.SHOW_TEXT) { + for (component in hoverEvent.value) + if (component is TextComponent) { + component.replaceOnAllTexts(oldValue, newValue, ignoreCase) + } + } + } +} +public fun T.replaceOnAllShowText( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + replaceOnShowText(oldValue, newValue, ignoreCase) + if (extra != null) { + for (component in extra) component.replaceOnAllShowText(oldValue, newValue, ignoreCase) + } +} + +/** + * Replace the current [BaseComponent] click [oldValue] to [newValue] with [String.replace] + */ +public fun T.replaceOnClick( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + if (clickEvent != null) { + click(ClickEvent(clickEvent.action, clickEvent.value.replace(oldValue, newValue, ignoreCase))) + } +} + +/** + * Replace the current [BaseComponent] click and all [BaseComponent.extra] + * + * See [BaseComponent.replaceOnClick] + */ +public fun T.replaceOnAllClick( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + replaceOnClick(oldValue, newValue, ignoreCase) + if (extra != null) { + for (component in extra) + component.replaceOnAllClick(oldValue, newValue, ignoreCase) + } +} + +public fun T.replaceOnRunCommand( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + if (clickEvent != null && clickEvent.action == ClickEvent.Action.RUN_COMMAND) { + runCommand(clickEvent.value.replace(oldValue, newValue, ignoreCase)) + } +} +public fun T.replaceOnAllRunCommand( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): T = apply { + replaceOnRunCommand(oldValue, newValue, ignoreCase) + if (extra != null) { + for (component in extra) + component.replaceOnRunCommand(oldValue, newValue, ignoreCase) + } +} + +/** + * Replace the [TextComponent.text] with [String.replace] + */ +public fun TextComponent.replaceOnText( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): TextComponent = apply { + this.text = text.replace(oldValue, newValue, ignoreCase) +} + +/** + * Replace the current [TextComponent.text] and all the [TextComponent.extra]. + * + * See [TextComponent.replaceOnText] + */ +public fun TextComponent.replaceOnAllTexts( + oldValue: String, + newValue: String, + ignoreCase: Boolean = false, +): TextComponent = apply { + replaceOnText(oldValue, newValue, ignoreCase) + if (extra != null) { + for (component in extra) + if (component is TextComponent) { + component.replaceOnAllTexts(oldValue, newValue, ignoreCase) + } + } +} + +/** + * Replace the current [TextComponent.text] [oldValue] to [newValue]. + */ +public fun TextComponent.replace( + oldValue: String, + newValue: TextComponent, + ignoreCase: Boolean = false, +): TextComponent = split(oldValue, ignoreCase = ignoreCase, limit = 0).joinToText(newValue) + +/** + * Replace the current [TextComponent.text] and all the [TextComponent.extra] [oldValue] to [newValue]. + */ +public fun TextComponent.replaceAll( + oldValue: String, + newValue: TextComponent, + ignoreCase: Boolean = false, +): TextComponent = replace(oldValue, newValue, ignoreCase).apply { + if (extra != null) { + extra = extra.map { + if (it is TextComponent) { + it.replaceAll(oldValue, newValue, ignoreCase) + } else { + it + } + }.toMutableList() + } +} + +/** + * Splits this [TextComponent.text] into a list of [TextComponent] around occurrences of the specified [delimiters]. + * + * @param delimiters One or more characters to be used as delimiters. + * @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`. + * @param limit The maximum number of substrings to return. + */ +public fun TextComponent.split( + vararg delimiters: String, + ignoreCase: Boolean = false, + limit: Int = 0, +): List { + val copy = duplicate().apply { extra?.clear() } + val list = text.split(*delimiters, ignoreCase = ignoreCase, limit = limit).map { + (copy.duplicate() as TextComponent).apply { + text = it + } + } + if (list.isNotEmpty()) { + duplicate().also { if (it.extra != null) list.last().extra = it.extra } + } + return list +} + +/** + * Creates a [TextComponent] from all the elements separated using [separator] (none by default) + * and using the given [prefix] (none by default) and [postfix] (none by default). + * + * If the collection could be huge, you can specify a non-negative value of [limit], in which case only the first [limit] + * elements will be appended. + */ +public fun List.joinToText( + separator: TextComponent? = null, + prefix: TextComponent? = null, + suffix: TextComponent? = null, + limit: Int = -1, +): TextComponent { + if (isEmpty()) return TextComponent("") + + var component = prefix?.append(get(0)) ?: get(0) + + var count = 0 + for (element in this) { + if (++count > 1 && separator != null) component.append(separator) + if (limit < 0 || count <= limit) { + if (count > 1) component.append(element) + } else { + break + } + } + if (suffix != null) component.append(suffix) + return component +} diff --git a/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExWorld.kt b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExWorld.kt new file mode 100644 index 0000000..af0362e --- /dev/null +++ b/extensions/src/main/kotlin/me/redtea/kotlinbukkitkit/extensions/ExWorld.kt @@ -0,0 +1,55 @@ +/* +ORIGINAL PACKAGE: package br.com.devsrsouza.kotlinbukkitapi.extensions +ORIGINAL REPOSITORY: https://github.com/DevSrSouza/KotlinBukkitAPI +AUTHOR: https://github.com/DevSrSouza + +Thanks DevSrSouza for KotlinBukkitAPI + */ + +package me.redtea.kotlinbukkitkit.extensions + +import org.bukkit.Bukkit +import org.bukkit.Chunk +import org.bukkit.Location +import org.bukkit.Material +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.entity.Entity +import org.bukkit.entity.Item +import org.bukkit.material.MaterialData + +public fun mainWorld(): World = Bukkit.getWorlds()[0] +public fun chunk(world: World, x: Int, y: Int): Chunk = world.getChunkAt(x, y) +public fun chunk(block: Block): Chunk = chunk(block.world, block.x shr 4, block.z shr 4) + +public inline fun World.spawn(location: Location): T { + return spawn(location, T::class.java) +} + +public inline fun World.getEntitiesByClass(): Collection { + return getEntitiesByClass(T::class.java) +} + +public fun World.dropItem(location: Location, material: Material, data: Byte = 0): Item { + return dropItem(location, material.asMaterialData(data)) +} + +public fun World.dropItem(location: Location, materialData: MaterialData): Item { + return dropItem(location, materialData.toItemStack(1)) +} + +public fun World.dropItemNaturally(location: Location, material: Material, data: Byte = 0): Item { + return dropItemNaturally(location, material.asMaterialData(data)) +} + +public fun World.dropItemNaturally(location: Location, materialData: MaterialData): Item { + return dropItemNaturally(location, materialData.toItemStack(1)) +} + +public fun World.setSpawnLocation(location: Location): Boolean { + return setSpawnLocation(location.blockX, location.blockY, location.blockZ) +} + +public fun World.setSpawnLocation(block: Block): Boolean { + return setSpawnLocation(block.x, block.y, block.z) +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 45fa1ab..b6e7577 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,3 +2,4 @@ rootProject.name = "kotlinbukkitkit" include("architecture") include("messages") +include("extensions")