diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/config/Config.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/config/Config.kt index a21d532..48fdb67 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/config/Config.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/config/Config.kt @@ -9,6 +9,7 @@ import com.artillexstudios.axapi.libs.boostedyaml.boostedyaml.settings.updater.U import com.artillexstudios.axminions.api.AxMinionsAPI import java.io.File import java.io.InputStream +import java.util.Locale class Config(file: File, stream: InputStream) { companion object { @@ -42,6 +43,8 @@ class Config(file: File, stream: InputStream) { @JvmStatic fun PULL_FROM_CHEST() = AxMinionsAPI.INSTANCE.getConfig().get("pull-tools-from-chest", false) @JvmStatic + fun UPGRADE_FAIL() = AxMinionsAPI.INSTANCE.getConfig().get("upgrade-fail", "chat").lowercase(Locale.ENGLISH) + @JvmStatic fun PLACE_PERMISSION() = AxMinionsAPI.INSTANCE.getConfig().get("place-permissions", false) @JvmStatic fun DEBUG(): Boolean { diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/miniontype/MinionType.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/miniontype/MinionType.kt index 462ece9..1199a0f 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/miniontype/MinionType.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/miniontype/MinionType.kt @@ -7,7 +7,6 @@ import com.artillexstudios.axapi.utils.ItemBuilder import com.artillexstudios.axminions.api.AxMinionsAPI import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.utils.Keys -import com.artillexstudios.axminions.api.utils.fastFor import org.bukkit.inventory.ItemStack import org.bukkit.persistence.PersistentDataType import java.io.File @@ -33,12 +32,7 @@ abstract class MinionType(private val name: String, private val defaults: InputS return true } - fun isTicking(minion: Minion): Boolean { - return minion.isTicking() - } - fun tick(minion: Minion) { - if (!minion.isTicking()) return if (!shouldRun(minion)) return minion.resetAnimation() diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/utils/ChunkPos.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/utils/ChunkPos.kt index 599d03e..84ccdf9 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/utils/ChunkPos.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/utils/ChunkPos.kt @@ -1,10 +1,9 @@ package com.artillexstudios.axminions.api.minions.utils import com.artillexstudios.axminions.api.minions.Minion -import com.artillexstudios.axminions.api.utils.fastFor import org.bukkit.World -data class ChunkPos(val world: World, val x: Int, val z: Int) { +data class ChunkPos(val world: World, val x: Int, val z: Int, @Volatile var ticking: Boolean) { val minions = arrayListOf() val worldUUID = world.uid @@ -19,8 +18,10 @@ data class ChunkPos(val world: World, val x: Int, val z: Int) { } fun setTicking(ticking: Boolean) { - minions.fastFor { - it.setTicking(ticking) + this.ticking = ticking + + minions.forEach { + it.setTicking(true) } } diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/utils/CoolDown.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/utils/CoolDown.kt index 049ee10..edddb13 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/utils/CoolDown.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/utils/CoolDown.kt @@ -1,7 +1,9 @@ package com.artillexstudios.axminions.api.utils +import java.util.WeakHashMap + class CoolDown { - private val map = HashMap() + private val map = WeakHashMap() fun add(value: T, time: Long) { expire() diff --git a/build.gradle b/build.gradle index 8cfa6d5..c90f27f 100644 --- a/build.gradle +++ b/build.gradle @@ -123,7 +123,7 @@ allprojects { compileOnly 'com.intellectualsites.plotsquared:plotsquared-core:7.0.0-rc.4' compileOnly 'com.intellectualsites.plotsquared:plotsquared-bukkit:7.0.0-rc.4' implementation platform('com.intellectualsites.bom:bom-newest:1.35') - implementation("com.artillexstudios.axapi:axapi:1.4.22") + implementation("com.artillexstudios.axapi:axapi:1.4.23") implementation("net.byteflux:libby-bukkit:1.3.0") implementation("com.zaxxer:HikariCP:5.1.0") implementation("org.bstats:bstats-bukkit:3.0.2") diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/commands/AxMinionsCommand.kt b/common/src/main/kotlin/com/artillexstudios/axminions/commands/AxMinionsCommand.kt index 41b174d..ef0309b 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/commands/AxMinionsCommand.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/commands/AxMinionsCommand.kt @@ -82,7 +82,7 @@ class AxMinionsCommand { val total = minions.size minions.fastFor { - if (it.getType().isTicking(it)) { + if (it.isTicking()) { loaded++ } } diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/LinkingListener.kt b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/LinkingListener.kt index 24ae158..8fc721c 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/LinkingListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/LinkingListener.kt @@ -5,26 +5,27 @@ import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.api.config.Config import com.artillexstudios.axminions.api.config.Messages import com.artillexstudios.axminions.api.minions.Minion -import java.util.UUID +import java.util.WeakHashMap import org.bukkit.Material +import org.bukkit.entity.Player import org.bukkit.event.EventHandler import org.bukkit.event.Listener import org.bukkit.event.player.PlayerInteractEvent class LinkingListener : Listener { companion object { - val linking = hashMapOf() + val linking = WeakHashMap() private val CONTAINERS = listOf(Material.BARREL, Material.CHEST, Material.TRAPPED_CHEST) } @EventHandler fun onPlayerInteractEvent(event: PlayerInteractEvent) { - if (event.player.uniqueId !in linking) return if (event.clickedBlock == null) return + if (event.player !in linking) return if (event.clickedBlock!!.type !in CONTAINERS) return if (!AxMinionsPlugin.integrations.getProtectionIntegration().canBuildAt(event.player, event.clickedBlock!!.location)) return - val minion = linking.remove(event.player.uniqueId) ?: return + val minion = linking.remove(event.player) ?: return event.isCancelled = true if (minion.getLocation() .distanceSquared(event.clickedBlock!!.location) > Config.MAX_LINKING_DISTANCE() * Config.MAX_LINKING_DISTANCE() diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt index d16b25a..7c553b1 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt @@ -3,6 +3,7 @@ package com.artillexstudios.axminions.listeners import com.artillexstudios.axapi.utils.StringUtils import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.api.AxMinionsAPI +import com.artillexstudios.axminions.api.config.Config import com.artillexstudios.axminions.api.config.Messages import com.artillexstudios.axminions.api.minions.Direction import com.artillexstudios.axminions.api.minions.Minion @@ -10,7 +11,8 @@ import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes import com.artillexstudios.axminions.api.utils.CoolDown import com.artillexstudios.axminions.api.utils.Keys import com.artillexstudios.axminions.api.utils.fastFor -import java.util.UUID +import net.md_5.bungee.api.ChatMessageType +import net.md_5.bungee.api.chat.TextComponent import org.bukkit.Material import org.bukkit.entity.Player import org.bukkit.event.EventHandler @@ -22,7 +24,7 @@ import org.bukkit.inventory.ItemStack import org.bukkit.persistence.PersistentDataType class MinionInventoryListener : Listener { - private val coolDown = CoolDown() + private val coolDown = CoolDown() @EventHandler fun onInventoryDragEvent(event: InventoryDragEvent) { @@ -38,11 +40,11 @@ class MinionInventoryListener : Listener { event.isCancelled = true val player = event.whoClicked as Player - if (coolDown.contains(player.uniqueId)) { + if (coolDown.contains(player)) { return } - coolDown.add(player.uniqueId, 250) + coolDown.add(player, 250) val allowedTools = arrayListOf() minion.getType().getConfig().getStringList("tool.material").fastFor { @@ -116,7 +118,7 @@ class MinionInventoryListener : Listener { } player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_START())) - LinkingListener.linking[player.uniqueId] = minion + LinkingListener.linking[player] = minion player.closeInventory() } @@ -129,13 +131,13 @@ class MinionInventoryListener : Listener { } if (minion.getActionAmount() < actions) { - player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.UPGRADE_FAIL())) + sendFail(player) return } AxMinionsPlugin.integrations.getEconomyIntegration()?.let { if (it.getBalance(player) < money) { - player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.UPGRADE_FAIL())) + sendFail(player) return } @@ -154,8 +156,8 @@ class MinionInventoryListener : Listener { if (minion.getType() == MinionTypes.getMinionTypes()["seller"]) { AxMinionsPlugin.integrations.getEconomyIntegration()?.let { - minion.getOwner()?.let { - player -> it.giveBalance(player, stored) + minion.getOwner()?.let { player -> + it.giveBalance(player, stored) minion.setStorage(0.0) } } @@ -175,4 +177,30 @@ class MinionInventoryListener : Listener { holder.removeOpenInventory(event.inventory) } + + private fun sendFail(player: Player) { + when (Config.UPGRADE_FAIL()) { + "title" -> { + player.closeInventory() + player.sendTitle(StringUtils.formatToString(Messages.UPGRADE_FAIL()), "", 10, 70, 20) + } + + "subtitle" -> { + player.closeInventory() + player.sendTitle("", StringUtils.formatToString(Messages.UPGRADE_FAIL()), 10, 70, 20) + } + + "actionbar" -> { + player.closeInventory() + player.spigot().sendMessage( + ChatMessageType.ACTION_BAR, + *TextComponent.fromLegacyText(StringUtils.formatToString(Messages.UPGRADE_FAIL())) + ) + } + + else -> { + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.UPGRADE_FAIL())) + } + } + } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionPlaceListener.kt b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionPlaceListener.kt index 4fd0d0b..a351c6f 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionPlaceListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionPlaceListener.kt @@ -51,6 +51,7 @@ class MinionPlaceListener : Listener { val maxMinions = AxMinionsAPI.INSTANCE.getMinionLimit(event.player) + val chunk = location.chunk AxMinionsPlugin.dataQueue.submit { val placed = AxMinionsPlugin.dataHandler.getMinionAmount(event.player.uniqueId) @@ -85,7 +86,8 @@ class MinionPlaceListener : Listener { locationId, 0 ) - minion.setTicking(true) + Minions.addTicking(chunk) + Scheduler.get().run { task -> meta = item.itemMeta!! meta.persistentDataContainer.remove(Keys.PLACED) @@ -97,7 +99,7 @@ class MinionPlaceListener : Listener { event.player.sendMessage( "Placed minion $minion. Ticking? ${minion.isTicking()} Is chunk ticking? ${ Minions.isTicking( - location.chunk + chunk ) }" ) diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/WorldListener.kt b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/WorldListener.kt index 1cd76c4..0fe4aa3 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/WorldListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/WorldListener.kt @@ -1,6 +1,5 @@ package com.artillexstudios.axminions.listeners -import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes import org.bukkit.event.EventHandler import org.bukkit.event.Listener @@ -10,8 +9,6 @@ class WorldListener : Listener { @EventHandler fun onWorldLoadEvent(event: WorldLoadEvent) { - AxMinionsPlugin.dataQueue.submit { - MinionTypes.loadForWorld(event.world) - } + MinionTypes.loadForWorld(event.world) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minion.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minion.kt index c19dc10..a8c768e 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minion.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minion.kt @@ -67,6 +67,7 @@ class Minion( private val extraData = hashMapOf() private var linkedInventory: Inventory? = null internal val openInventories = mutableListOf() + @Volatile private var ticking = false private var debugHologram: Hologram? = null private var broken = false @@ -74,12 +75,6 @@ class Minion( init { spawn() Minions.load(this) - - if (linkedChest != null) { - Scheduler.get().runAt(linkedChest) { - linkedInventory = (linkedChest?.block?.state as? Container)?.inventory - } - } } override fun getType(): MinionType { @@ -149,7 +144,7 @@ class Minion( } private fun breakMinion(event: PacketEntityInteractEvent) { - LinkingListener.linking.remove(event.player.uniqueId) + LinkingListener.linking.remove(event.player) remove() setTicking(false) openInventories.fastFor { it.viewers.fastFor { viewer -> viewer.closeInventory() } } @@ -307,7 +302,7 @@ class Minion( } override fun openInventory(player: Player) { - LinkingListener.linking.remove(player.uniqueId) + LinkingListener.linking.remove(player) val inventory = Bukkit.createInventory( this, Config.GUI_SIZE(), @@ -565,10 +560,14 @@ class Minion( override fun setTicking(ticking: Boolean) { this.ticking = ticking - if (ticking && linkedChest != null) { + if (linkedChest == null) return + + if (ticking) { Scheduler.get().runAt(linkedChest) { linkedInventory = (linkedChest?.block?.state as? Container)?.inventory } + } else { + linkedInventory = null } } diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/MinionTicker.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/MinionTicker.kt index 58bb3e7..22bf37e 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/MinionTicker.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/MinionTicker.kt @@ -9,6 +9,7 @@ object MinionTicker { private inline fun tickAll() { Minions.get { minions -> minions.fastFor { pos -> + if (!pos.ticking) return@fastFor pos.minions.fastFor { it.tick() } diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minions.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minions.kt index 65c3640..6c351ee 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minions.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minions.kt @@ -37,7 +37,7 @@ object Minions { lock.read { minions.forEach { if (world.uid == it.worldUUID && it.x == chunkX && it.z == chunkZ) { - return true + return it.ticking } } } @@ -63,8 +63,8 @@ object Minions { } fun load(minion: Minion) { - val chunkX = round(minion.getLocation().x) shr 4 - val chunkZ = round(minion.getLocation().z) shr 4 + val chunkX = (Math.round(minion.getLocation().x) shr 4).toInt() + val chunkZ = (Math.round(minion.getLocation().z) shr 4).toInt() val world = minion.getLocation().world ?: return lock.write { @@ -79,7 +79,7 @@ object Minions { } if (pos === null) { - pos = ChunkPos(world, chunkX, chunkZ) + pos = ChunkPos(world, chunkX, chunkZ, false) minions.add(pos!!) } @@ -89,8 +89,8 @@ object Minions { } fun remove(minion: Minion) { - val chunkX = round(minion.getLocation().x) shr 4 - val chunkZ = round(minion.getLocation().z) shr 4 + val chunkX = (Math.round(minion.getLocation().x) shr 4).toInt() + val chunkZ = (Math.round(minion.getLocation().z) shr 4).toInt() val world = minion.getLocation().world ?: return lock.write { @@ -124,8 +124,4 @@ object Minions { minions(this.minions) } } - - private infix fun round(double: Double): Int { - return (double + 0.5).toInt() - } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/FarmerMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/FarmerMinionType.kt index 8ce2fd5..4329c60 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/FarmerMinionType.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/FarmerMinionType.kt @@ -52,9 +52,9 @@ class FarmerMinionType : MinionType("farmer", AxMinionsPlugin.INSTANCE.getResour Warnings.remove(minion, Warnings.NO_TOOL) var size = 0 + val drops = arrayListOf() LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location -> val block = location.block - val drops = arrayListOf() when (block.type) { Material.CACTUS, Material.SUGAR_CANE, Material.BAMBOO -> { @@ -95,10 +95,10 @@ class FarmerMinionType : MinionType("farmer", AxMinionsPlugin.INSTANCE.getResour else -> return@fastFor } - - minion.addToContainerOrDrop(drops) - minion.damageTool(size) - minion.setActions(minion.getActionAmount() + size) } + + minion.addToContainerOrDrop(drops) + minion.damageTool(size) + minion.setActions(minion.getActionAmount() + size) } } diff --git a/common/src/main/resources/config.yml b/common/src/main/resources/config.yml index 96824ef..3d18d0d 100644 --- a/common/src/main/resources/config.yml +++ b/common/src/main/resources/config.yml @@ -39,6 +39,11 @@ use-durability: true # If the minion should pull new tools from the chest it's connected to pull-tools-from-chest: false +# What type of message we should send when the upgrade fails +# due to insufficient funds +# Possible options: chat, title, subtitle, actionbar +upgrade-fail: "chat" + database: # Can be H2 (SqLite support is planned) type: "H2" @@ -90,4 +95,4 @@ gui: debug: false # Do not change! -config-version: 2 \ No newline at end of file +config-version: 3 \ No newline at end of file