diff --git a/.idea/gradle.xml b/.idea/gradle.xml index b01719d..544d142 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -10,6 +10,8 @@ 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 3fa7321..59f6b36 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 @@ -12,6 +12,7 @@ import java.io.InputStream class Config(file: File, stream: InputStream) { companion object { + private var debug: Boolean? = null @JvmStatic fun AUTO_SAVE_MINUTES() = AxMinionsAPI.INSTANCE.getConfig().get("autosave-minutes", 3L) @JvmStatic @@ -39,7 +40,13 @@ class Config(file: File, stream: InputStream) { @JvmStatic fun GUI_SIZE() = AxMinionsAPI.INSTANCE.getConfig().get("gui.size") @JvmStatic - fun DEBUG() = AxMinionsAPI.INSTANCE.getConfig().get("debug") + fun DEBUG(): Boolean { + if (debug === null) { + debug = AxMinionsAPI.INSTANCE.getConfig().get("debug", false) + } + + return debug ?: false + } } private val config = Config( diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/config/Messages.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/config/Messages.kt index ca4079e..352089f 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/config/Messages.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/config/Messages.kt @@ -47,6 +47,14 @@ class Messages(file: File, stream: InputStream) { fun WRONG_TOOL() = AxMinionsAPI.INSTANCE.getMessages().get("tools.wrong-tool") @JvmStatic fun ERROR_INVENTORY_FULL() = AxMinionsAPI.INSTANCE.getMessages().get("errors.inventory-full") + @JvmStatic + fun LINK_SUCCESS() = AxMinionsAPI.INSTANCE.getMessages().get("link.success") + @JvmStatic + fun LINK_UNLINK() = AxMinionsAPI.INSTANCE.getMessages().get("link.unlink") + @JvmStatic + fun LINK_FAIL() = AxMinionsAPI.INSTANCE.getMessages().get("link.fail") + @JvmStatic + fun LINK_START() = AxMinionsAPI.INSTANCE.getMessages().get("link.start") } private val config = Config( diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/events/MinionDamageEntityEvent.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/events/MinionDamageEntityEvent.kt new file mode 100644 index 0000000..1fd552a --- /dev/null +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/events/MinionDamageEntityEvent.kt @@ -0,0 +1,30 @@ +package com.artillexstudios.axminions.api.events + +import com.artillexstudios.axminions.api.minions.Minion +import org.bukkit.entity.LivingEntity +import org.bukkit.event.Cancellable +import org.bukkit.event.HandlerList + +class MinionDamageEntityEvent(minion: Minion, val target: LivingEntity, val damage: Double) : MinionEvent(minion), Cancellable { + companion object { + private val handlerList = HandlerList() + + @JvmStatic + fun getHandlerList(): HandlerList = handlerList + } + + private var isCancelled = false + + + override fun getHandlers(): HandlerList { + return handlerList + } + + override fun isCancelled(): Boolean { + return isCancelled + } + + override fun setCancelled(cancelled: Boolean) { + isCancelled = cancelled + } +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/events/MinionEvent.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/events/MinionEvent.kt new file mode 100644 index 0000000..ed718c3 --- /dev/null +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/events/MinionEvent.kt @@ -0,0 +1,6 @@ +package com.artillexstudios.axminions.api.events + +import com.artillexstudios.axminions.api.minions.Minion +import org.bukkit.event.Event + +abstract class MinionEvent(val minion: Minion) : Event() \ No newline at end of file diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/integrations/Integrations.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/integrations/Integrations.kt index 42e3a22..0c63866 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/integrations/Integrations.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/integrations/Integrations.kt @@ -9,9 +9,9 @@ interface Integrations { fun getStackerIntegration(): StackerIntegration - fun getPricesIntegration(): PricesIntegration + fun getPricesIntegration(): PricesIntegration? - fun getEconomyIntegration(): EconomyIntegration + fun getEconomyIntegration(): EconomyIntegration? fun getProtectionIntegration(): ProtectionIntegrations diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/Minion.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/Minion.kt index 5d3e07b..db57df2 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/Minion.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/minions/Minion.kt @@ -24,8 +24,6 @@ interface Minion : InventoryHolder { fun updateInventories() - fun updateInventory(inventory: Inventory) - fun openInventory(player: Player) fun getAsItem(): ItemStack diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/utils/Collections.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/utils/Collections.kt index c9c31c1..8739e34 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/utils/Collections.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/utils/Collections.kt @@ -8,6 +8,7 @@ inline fun Array.fastFor(action: (T) -> Unit) { } inline fun List.fastFor(action: (T) -> Unit) { + if (isEmpty()) return val indices = indices for (i in indices) { action(get(i)) diff --git a/api/src/main/kotlin/com/artillexstudios/axminions/api/warnings/Warnings.kt b/api/src/main/kotlin/com/artillexstudios/axminions/api/warnings/Warnings.kt index a1c4875..5044edd 100644 --- a/api/src/main/kotlin/com/artillexstudios/axminions/api/warnings/Warnings.kt +++ b/api/src/main/kotlin/com/artillexstudios/axminions/api/warnings/Warnings.kt @@ -29,9 +29,11 @@ object Warnings { } @JvmStatic - fun remove(minion: Minion) { - minion.getWarningHologram()?.remove() - minion.setWarningHologram(null) - minion.setWarning(null) + fun remove(minion: Minion, warning: Warning) { + if (minion.getWarning() == warning) { + minion.getWarningHologram()?.remove() + minion.setWarningHologram(null) + minion.setWarning(null) + } } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index f7d9569..37e8cac 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,7 @@ repositories { dependencies { implementation project(path: ":api") implementation project(path: ":common") + implementation project(path: ":nms:v1_20_R1", configuration: "reobf") } allprojects { @@ -110,6 +111,9 @@ allprojects { compileOnly 'com.intellectualsites.plotsquared:plotsquared-bukkit:7.0.0-rc.4' implementation platform('com.intellectualsites.bom:bom-newest:1.35') implementation files('../libs/AxAPI-1.0-SNAPSHOT.jar') +// compileOnly files('../libs/CMI-API9.5.0.8.jar') +// compileOnly files('../libs/IridiumSkyblock-3.2.12.jar') +// compileOnly files('../libs/KingdomsX-1.16.12.jar') } shadowJar { diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt b/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt index a0a9709..6f0711a 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt @@ -17,13 +17,17 @@ import com.artillexstudios.axminions.data.H2DataHandler import com.artillexstudios.axminions.integrations.Integrations import com.artillexstudios.axminions.listeners.ChunkListener import com.artillexstudios.axminions.listeners.LinkingListener +import com.artillexstudios.axminions.listeners.MinionDamageListener import com.artillexstudios.axminions.listeners.MinionInventoryListener import com.artillexstudios.axminions.listeners.MinionPlaceListener import com.artillexstudios.axminions.minions.MinionTicker import com.artillexstudios.axminions.minions.miniontype.CollectorMinionType import com.artillexstudios.axminions.minions.miniontype.FarmerMinionType +import com.artillexstudios.axminions.minions.miniontype.FisherMinionType import com.artillexstudios.axminions.minions.miniontype.LumberMinionType import com.artillexstudios.axminions.minions.miniontype.MinerMinionType +import com.artillexstudios.axminions.minions.miniontype.SellerMinionType +import com.artillexstudios.axminions.minions.miniontype.SlayerMinionType import org.bukkit.Bukkit import java.io.File @@ -65,6 +69,9 @@ class AxMinionsPlugin : AxPlugin() { it.register(FarmerMinionType()) it.register(MinerMinionType()) it.register(LumberMinionType()) + it.register(SellerMinionType()) + it.register(FisherMinionType()) + it.register(SlayerMinionType()) } val handler = BukkitCommandHandler.create(this) @@ -84,12 +91,15 @@ class AxMinionsPlugin : AxPlugin() { handler.register(AxMinionsCommand()) - handler.registerBrigadier() + if (handler.isBrigadierSupported) { + handler.registerBrigadier() + } Bukkit.getPluginManager().registerEvents(MinionPlaceListener(), this) Bukkit.getPluginManager().registerEvents(LinkingListener(), this) Bukkit.getPluginManager().registerEvents(MinionInventoryListener(), this) Bukkit.getPluginManager().registerEvents(ChunkListener(), this) + Bukkit.getPluginManager().registerEvents(MinionDamageListener(), this) MinionTicker.startTicking() } @@ -102,8 +112,6 @@ class AxMinionsPlugin : AxPlugin() { if (Config.DATABASE_TYPE().equals("H2", true)) { dataHandler = H2DataHandler() dataHandler.setup() - } else { - } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/converter/Converter.kt b/common/src/main/kotlin/com/artillexstudios/axminions/converter/Converter.kt new file mode 100644 index 0000000..b77b570 --- /dev/null +++ b/common/src/main/kotlin/com/artillexstudios/axminions/converter/Converter.kt @@ -0,0 +1,6 @@ +package com.artillexstudios.axminions.converter + +interface Converter { + + fun convert(); +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/converter/JetsMinionsConverter.kt b/common/src/main/kotlin/com/artillexstudios/axminions/converter/JetsMinionsConverter.kt new file mode 100644 index 0000000..3fe5877 --- /dev/null +++ b/common/src/main/kotlin/com/artillexstudios/axminions/converter/JetsMinionsConverter.kt @@ -0,0 +1,8 @@ +package com.artillexstudios.axminions.converter + +class JetsMinionsConverter : Converter { + + override fun convert() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/converter/LitMinionsConverter.kt b/common/src/main/kotlin/com/artillexstudios/axminions/converter/LitMinionsConverter.kt new file mode 100644 index 0000000..6402bcd --- /dev/null +++ b/common/src/main/kotlin/com/artillexstudios/axminions/converter/LitMinionsConverter.kt @@ -0,0 +1,79 @@ +package com.artillexstudios.axminions.converter + +import com.artillexstudios.axapi.serializers.Serializers +import com.artillexstudios.axapi.utils.StringUtils +import com.artillexstudios.axminions.api.minions.Direction +import java.sql.Connection +import java.sql.DriverManager +import java.util.Locale +import org.bukkit.Bukkit +import org.bukkit.Location +import org.bukkit.Material +import org.bukkit.inventory.ItemStack + + +class LitMinionsConverter : Converter { + private lateinit var connection: Connection + + override fun convert() { + Bukkit.getConsoleSender() + .sendMessage(StringUtils.formatToString("<#33FF33>[AxMinions-Converter] Converting from LitMinions...")) + val url = "jdbc:sqlite:" + "plugins/LitMinions/minions.db" + try { + connection = DriverManager.getConnection(url) ?: return + } catch (exception: Exception) { + Bukkit.getConsoleSender() + .sendMessage(StringUtils.formatToString("<#33FF33>[AxMinions-Converter] <#FF0000>FAILED! Database not found, or corrupted!")) + return + } + + connection.use { + connection.prepareStatement("SELECT * FROM `minions_data`").use { preparedStatement -> + preparedStatement.executeQuery().use { resultSet -> + while (resultSet.next()) { +// Bukkit.getConsoleSender().sendMessage( +// StringUtils.formatToString( +//// "&#DDDDDD[AxMinions-Converter] Converting: " + resultSet.getString("minionworld") + ";" + rs.getDouble( +// "minionx" +// ) + ";" + resultSet.getDouble("miniony") + ";" + resultSet.getDouble("minionz") +// ) +// ) + +/* val location = + resultSet.getString("minionworld") + ";" + resultSet.getDouble("minionx") + ";" + resultSet.getDouble( + "miniony"*//**//* +// ) + ";" + rs.getDouble( + "minionz" + )*/ + val direction: Direction = + Direction.valueOf(resultSet.getString("minionface").uppercase(Locale.ENGLISH)) + val level = resultSet.getInt("level") + val type = resultSet.getString("miniontype").uppercase(Locale.getDefault()) + val owner = resultSet.getString("owner") + + val storage = resultSet.getDouble("exp") + + val statistic = resultSet.getLong("stat") + val linkedChest = "${resultSet.getString("chestworld")};${resultSet.getDouble("chestx")};${ + resultSet.getDouble("chesty") + };${resultSet.getDouble("chestz")};0;0" + + var linkedChestLoc: Location? = null + + if (resultSet.getString("chestworld") != null) { + linkedChestLoc = Serializers.LOCATION.deserialize(linkedChest) + } + + val it = ItemStack(Material.AIR) + +// val locationId = AxMinionsPlugin.dataHandler.getLocationID(location) +// val minion = Minion(location, owner, Bukkit.getOfflinePlayer(owner), minionType, 1, ItemStack(Material.AIR), null, Direction.NORTH, 0, 0.0, locationId, 0) +// minion.setLevel(level) +// minion.setActions(stats) +// minion.setTicking(true) + } + } + } + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/integrations/Integrations.kt b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/Integrations.kt index c97f267..5aaefb7 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/integrations/Integrations.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/Integrations.kt @@ -18,6 +18,8 @@ import com.artillexstudios.axminions.integrations.prices.EssentialsIntegration import com.artillexstudios.axminions.integrations.prices.ShopGUIPlusIntegration import com.artillexstudios.axminions.integrations.protection.BentoBoxIntegration import com.artillexstudios.axminions.integrations.protection.GriefPreventionIntegration +import com.artillexstudios.axminions.integrations.protection.IridiumSkyBlockIntegration +import com.artillexstudios.axminions.integrations.protection.KingdomsXIntegration import com.artillexstudios.axminions.integrations.protection.LandsIntegration import com.artillexstudios.axminions.integrations.protection.SuperiorSkyBlock2Integration import com.artillexstudios.axminions.integrations.protection.WorldGuardIntegration @@ -29,19 +31,19 @@ import org.bukkit.Bukkit class Integrations : Integrations { private lateinit var stackerIntegration: StackerIntegration - private lateinit var pricesIntegration: PricesIntegration - private lateinit var economyIntegration: EconomyIntegration + private var pricesIntegration: PricesIntegration? = null + private var economyIntegration: EconomyIntegration? = null private val protectionIntegrations = com.artillexstudios.axminions.integrations.protection.ProtectionIntegrations() override fun getStackerIntegration(): StackerIntegration { return stackerIntegration } - override fun getPricesIntegration(): PricesIntegration { + override fun getPricesIntegration(): PricesIntegration? { return pricesIntegration } - override fun getEconomyIntegration(): EconomyIntegration { + override fun getEconomyIntegration(): EconomyIntegration? { return economyIntegration } @@ -133,6 +135,14 @@ class Integrations : Integrations { if (Bukkit.getPluginManager().getPlugin("Lands") != null) { register(LandsIntegration()) } + + if (Bukkit.getPluginManager().getPlugin("IridiumSkyBlock") != null) { + register(IridiumSkyBlockIntegration()) + } + + if (Bukkit.getPluginManager().getPlugin("KingdomsX") != null) { + register(KingdomsXIntegration()) + } } override fun register(integration: Integration) { diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/integrations/prices/CMIIntegration.kt b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/prices/CMIIntegration.kt index 5670160..62752a5 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/integrations/prices/CMIIntegration.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/prices/CMIIntegration.kt @@ -1,15 +1,21 @@ package com.artillexstudios.axminions.integrations.prices +import com.Zrips.CMI.CMI import com.artillexstudios.axminions.api.integrations.types.PricesIntegration import org.bukkit.inventory.ItemStack + class CMIIntegration : PricesIntegration { + private lateinit var manager: CMI + override fun getPrice(itemStack: ItemStack): Double { - TODO("Not yet implemented") + val worth = manager.worthManager.getWorth(itemStack) ?: return -1.0 + + return if (worth.sellPrice == 0.0) -1.0 else worth.sellPrice } override fun register() { - TODO("Not yet implemented") + manager = CMI.getInstance(); } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/integrations/protection/IridiumSkyBlockIntegration.kt b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/protection/IridiumSkyBlockIntegration.kt new file mode 100644 index 0000000..e1d23e7 --- /dev/null +++ b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/protection/IridiumSkyBlockIntegration.kt @@ -0,0 +1,19 @@ +package com.artillexstudios.axminions.integrations.protection + +import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration +import com.iridium.iridiumskyblock.api.IridiumSkyblockAPI +import org.bukkit.Location +import org.bukkit.entity.Player + +class IridiumSkyBlockIntegration : ProtectionIntegration { + + override fun canBuildAt(player: Player, location: Location): Boolean { + val island = IridiumSkyblockAPI.getInstance().getIslandViaLocation(location) + + return island.map { IridiumSkyblockAPI.getInstance().getUser(player) in it.members }.orElse(true) + } + + override fun register() { + + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/integrations/protection/KingdomsXIntegration.kt b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/protection/KingdomsXIntegration.kt new file mode 100644 index 0000000..40639ce --- /dev/null +++ b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/protection/KingdomsXIntegration.kt @@ -0,0 +1,21 @@ +package com.artillexstudios.axminions.integrations.protection + +import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration +import org.bukkit.Location +import org.bukkit.entity.Player +import org.kingdoms.constants.land.Land +import org.kingdoms.constants.player.KingdomPlayer + +class KingdomsXIntegration : ProtectionIntegration { + + override fun canBuildAt(player: Player, location: Location): Boolean { + val localPlayer = KingdomPlayer.getKingdomPlayer(player.uniqueId); + val land = Land.getLand(location) ?: return true + + return land.kingdom.isMember(localPlayer); + } + + override fun register() { + + } +} \ No newline at end of file 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 c85aa50..24ae158 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/LinkingListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/LinkingListener.kt @@ -1,6 +1,9 @@ package com.artillexstudios.axminions.listeners +import com.artillexstudios.axapi.utils.StringUtils +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 org.bukkit.Material @@ -19,17 +22,18 @@ class LinkingListener : Listener { if (event.player.uniqueId !in linking) return if (event.clickedBlock == null) return if (event.clickedBlock!!.type !in CONTAINERS) return - // TODO Check if player can build at location + if (!AxMinionsPlugin.integrations.getProtectionIntegration().canBuildAt(event.player, event.clickedBlock!!.location)) return val minion = linking.remove(event.player.uniqueId) ?: return event.isCancelled = true if (minion.getLocation() .distanceSquared(event.clickedBlock!!.location) > Config.MAX_LINKING_DISTANCE() * Config.MAX_LINKING_DISTANCE() ) { - // TODO Send too far message + event.player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_FAIL())) return } + event.player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_SUCCESS())) minion.setLinkedChest(event.clickedBlock!!.location) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionDamageListener.kt b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionDamageListener.kt new file mode 100644 index 0000000..dcf4d2b --- /dev/null +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionDamageListener.kt @@ -0,0 +1,19 @@ +package com.artillexstudios.axminions.listeners + +import com.artillexstudios.axminions.AxMinionsPlugin +import com.artillexstudios.axminions.api.events.MinionDamageEntityEvent +import java.util.concurrent.ThreadLocalRandom +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener + +class MinionDamageListener : Listener { + + @EventHandler + fun onMinionDamageEntityEvent(event: MinionDamageEntityEvent) { + if (event.damage < event.target.health) return + + val entitySize = AxMinionsPlugin.integrations.getStackerIntegration().getStackSize(event.target) + + event.minion.setStorage(event.minion.getStorage() + ThreadLocalRandom.current().nextInt(1, 4) * entitySize) + } +} \ No newline at end of file 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 2eefbda..d407656 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt @@ -66,7 +66,7 @@ class MinionInventoryListener : Listener { event.currentItem!!.amount = 0 } - minion.updateInventory(event.inventory) + minion.updateInventories() return } @@ -85,7 +85,7 @@ class MinionInventoryListener : Listener { tool.setItemMeta(toolMeta) player.inventory.addItem(tool) - minion.updateInventory(event.inventory) + minion.updateInventories() return } @@ -110,15 +110,16 @@ class MinionInventoryListener : Listener { "link" -> { if (minion.getLinkedChest() != null) { minion.setLinkedChest(null) - // TODO Unlink message + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_UNLINK())) return } + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_START())) LinkingListener.linking[player.uniqueId] = minion } } - minion.updateInventory(event.inventory) + minion.updateInventories() } @EventHandler 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 7ed99b9..d80a5b5 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionPlaceListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionPlaceListener.kt @@ -5,6 +5,7 @@ import com.artillexstudios.axapi.scheduler.Scheduler 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.miniontype.MinionTypes @@ -53,15 +54,16 @@ class MinionPlaceListener : Listener { } val locationId = AxMinionsPlugin.dataHandler.getLocationID(location) - Scheduler.get().run { - val minion = Minion(location, event.player.uniqueId, event.player, minionType, 1, ItemStack(Material.AIR), null, Direction.NORTH, 0, 0.0, locationId, 0) - minion.setLevel(level) - minion.setActions(stats) - minion.setTicking(true) + val minion = Minion(location, event.player.uniqueId, event.player, minionType, 1, ItemStack(Material.AIR), null, Direction.NORTH, 0, 0.0, locationId, 0) + minion.setLevel(level) + minion.setActions(stats) + minion.setTicking(true) + if (Config.DEBUG()) { event.player.sendMessage("Placed minion $minion. Ticking? ${minion.isTicking()} Is chunk ticking? ${Minions.isTicking(location.chunk)}") - AxMinionsPlugin.dataHandler.saveMinion(minion) } + AxMinionsPlugin.dataHandler.saveMinion(minion) + event.player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.PLACE_SUCCESS(), Placeholder.unparsed("type", minionType.getName()), Placeholder.unparsed("placed", (placed + 1).toString()), Placeholder.unparsed("max", (maxMinions).toString()))) } } 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 b9b38f1..1f64270 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minion.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minion.kt @@ -3,6 +3,7 @@ package com.artillexstudios.axminions.minions import com.artillexstudios.axapi.entity.PacketEntityFactory import com.artillexstudios.axapi.entity.impl.PacketArmorStand import com.artillexstudios.axapi.entity.impl.PacketEntity +import com.artillexstudios.axapi.events.PacketEntityInteractEvent import com.artillexstudios.axapi.hologram.Hologram import com.artillexstudios.axapi.hologram.HologramFactory import com.artillexstudios.axapi.libs.kyori.adventure.text.minimessage.tag.resolver.Placeholder @@ -99,8 +100,16 @@ class Minion( updateArmour() entity.onClick { event -> if (event.isAttack) { - println("LEFT CLICKED!") +// if (ownerUUID == event.player.uniqueId && Config.ONLY_OWNER_BREAK()) { +// breakMinion(event) +// } else if (AxMinionsPlugin.integrations.getProtectionIntegration().canBuildAt(event.player, event.packetEntity.location)) { + breakMinion(event) +// } } else { +/* if (ownerUUID == event.player.uniqueId || AxMinionsPlugin.integrations.getProtectionIntegration().canBuildAt(event.player, event.packetEntity.location)) { + + }*/ + Scheduler.get().run { openInventory(event.player) } @@ -108,6 +117,18 @@ class Minion( } } + private fun breakMinion(event: PacketEntityInteractEvent) { + setTicking(false) + val tool = getTool() + val asItem = getAsItem() + val remaining = event.player.inventory.addItem(tool, asItem) + remove() + + remaining.forEach { (_, i) -> + AxMinionsPlugin.integrations.getStackerIntegration().dropItemAt(i, i.amount, location) + } + } + override fun tick() { if (dirty) { dirty = false @@ -132,7 +153,7 @@ class Minion( } } - override fun updateInventory(inventory: Inventory) { + private fun updateInventory(inventory: Inventory) { AxMinionsAPI.INSTANCE.getConfig().getConfig().getSection("gui.items").getRoutesAsStrings(false).forEach { if (it.equals("filler")) return@forEach val item: ItemStack @@ -284,6 +305,8 @@ class Minion( override fun setLevel(level: Int) { this.level = level + updateArmour() + updateInventories() entity.name = StringUtils.format( type.getConfig().get("entity.name"), @@ -361,9 +384,13 @@ class Minion( } override fun remove() { - Warnings.remove(this) + Warnings.remove(this, warning ?: Warnings.NO_CONTAINER) Minions.remove(this) entity.remove() + + AxMinionsPlugin.dataQueue.submit { + AxMinionsPlugin.dataHandler.deleteMinion(this) + } } override fun getLinkedInventory(): Inventory? { @@ -457,6 +484,7 @@ class Minion( } else { meta.damage += amount tool?.itemMeta = meta + updateInventories() } } diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CollectorMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CollectorMinionType.kt index c4d9635..9e3ec15 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CollectorMinionType.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CollectorMinionType.kt @@ -42,14 +42,14 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get return } - Warnings.remove(minion) + Warnings.remove(minion, Warnings.NO_CONTAINER) if (!minion.canUseTool()) { Warnings.NO_TOOL.display(minion) return } - Warnings.remove(minion) + Warnings.remove(minion, Warnings.NO_TOOL) val entities = minion.getLocation().world?.getNearbyEntities( minion.getLocation(), 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 55e25d5..c94232f 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 @@ -44,7 +44,7 @@ class FarmerMinionType : MinionType("farmer", AxMinionsPlugin.INSTANCE.getResour return } - Warnings.remove(minion) + Warnings.remove(minion, Warnings.NO_TOOL) LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location -> val block = location.block diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/FisherMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/FisherMinionType.kt index fccee2b..5b7d9f6 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/FisherMinionType.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/FisherMinionType.kt @@ -3,11 +3,68 @@ package com.artillexstudios.axminions.minions.miniontype import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.miniontype.MinionType -import org.bukkit.loot.LootTables +import com.artillexstudios.axminions.api.utils.LocationUtils +import com.artillexstudios.axminions.api.utils.fastFor +import com.artillexstudios.axminions.api.warnings.Warnings +import com.artillexstudios.axminions.minions.MinionTicker +import com.artillexstudios.axminions.nms.NMSHandler +import java.util.concurrent.ThreadLocalRandom +import kotlin.math.roundToInt +import org.bukkit.Material +import org.bukkit.enchantments.Enchantment class FisherMinionType : MinionType("fisher", AxMinionsPlugin.INSTANCE.getResource("minions/fisher.yml")!!) { - override fun run(minion: Minion) { + override fun shouldRun(minion: Minion): Boolean { + return MinionTicker.getTick() % minion.getNextAction() == 0L + } + override fun onToolDirty(minion: Minion) { + val minionImpl = minion as com.artillexstudios.axminions.minions.Minion + minionImpl.setRange(getDouble("range", minion.getLevel())) + val efficiency = 1.0 - (minion.getTool()?.getEnchantmentLevel(Enchantment.LURE)?.div(10.0) ?: 0.1) + minionImpl.setNextAction((getLong("speed", minion.getLevel()) * efficiency).roundToInt()) + } + + override fun run(minion: Minion) { + if (minion.getLinkedChest() != null) { + val type = minion.getLinkedChest()!!.block.type + if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) { + minion.setLinkedChest(null) + } + } + + if (minion.getLinkedInventory() == null) { + minion.setLinkedChest(null) + } + + var hasWater = false + run breaking@{ + LocationUtils.getAllBlocksInRadius(minion.getLocation(), 2.0, false).fastFor { + if (it.block.type != Material.WATER) return@fastFor + + hasWater = true + return@breaking + } + } + + if (!hasWater) { + Warnings.NO_WATER_NEARBY.display(minion) + return + } + Warnings.remove(minion, Warnings.NO_WATER_NEARBY) + + if (!minion.canUseTool()) { + Warnings.NO_TOOL.display(minion) + return + } + + Warnings.remove(minion, Warnings.NO_TOOL) + + val loot = NMSHandler.get().generateRandomFishingLoot(minion) + val xp = ThreadLocalRandom.current().nextInt(6) + 1 + + minion.addToContainerOrDrop(loot) + minion.setStorage(minion.getStorage() + xp) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/LumberMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/LumberMinionType.kt index ca460d8..6fec6ae 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/LumberMinionType.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/LumberMinionType.kt @@ -44,7 +44,7 @@ class LumberMinionType : MinionType("lumber", AxMinionsPlugin.INSTANCE.getResour return } - Warnings.remove(minion) + Warnings.remove(minion, Warnings.NO_TOOL) val loot = ArrayList() LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location -> diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/MinerMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/MinerMinionType.kt index d8fa215..bdc89fe 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/MinerMinionType.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/MinerMinionType.kt @@ -49,7 +49,7 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource return } - Warnings.remove(minion) + Warnings.remove(minion, Warnings.NO_TOOL) when (getConfig().getString("mode").lowercase(Locale.ENGLISH)) { "sphere" -> { diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/SellerMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/SellerMinionType.kt index ab6189b..53ae8dc 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/SellerMinionType.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/SellerMinionType.kt @@ -3,10 +3,81 @@ package com.artillexstudios.axminions.minions.miniontype import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.miniontype.MinionType +import com.artillexstudios.axminions.api.warnings.Warnings +import com.artillexstudios.axminions.minions.MinionTicker +import kotlin.math.roundToInt +import org.bukkit.Material +import org.bukkit.enchantments.Enchantment class SellerMinionType : MinionType("seller", AxMinionsPlugin.INSTANCE.getResource("minions/seller.yml")!!) { - override fun run(minion: Minion) { + override fun shouldRun(minion: Minion): Boolean { + return MinionTicker.getTick() % minion.getNextAction() == 0L + } + override fun onToolDirty(minion: Minion) { + val minionImpl = minion as com.artillexstudios.axminions.minions.Minion + minionImpl.setRange(getDouble("range", minion.getLevel())) + val efficiency = 1.0 - (minion.getTool()?.getEnchantmentLevel(Enchantment.DIG_SPEED)?.div(10.0) ?: 0.1) + minionImpl.setNextAction((getLong("speed", minion.getLevel()) * efficiency).roundToInt()) + } + + override fun run(minion: Minion) { + if (minion.getLinkedChest() == null) { + Warnings.NO_CONTAINER.display(minion) + return + } + + val type = minion.getLinkedChest()!!.block.type + if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) { + Warnings.NO_CONTAINER.display(minion) + minion.setLinkedChest(null) + return + } + + if (minion.getLinkedInventory() == null) { + Warnings.NO_CONTAINER.display(minion) + minion.setLinkedChest(null) + return + } + + Warnings.remove(minion, Warnings.NO_CONTAINER) + + if (!minion.canUseTool()) { + Warnings.NO_TOOL.display(minion) + return + } + + Warnings.remove(minion, Warnings.NO_TOOL) + + if (AxMinionsPlugin.integrations.getPricesIntegration() === null) { + return + } + + for (it in minion.getLinkedInventory()!!.contents) { + if (it == null || it.type == Material.AIR) { + continue + } + + var price = AxMinionsPlugin.integrations.getPricesIntegration()!!.getPrice(it) + + if (price == -1.0) { + if (getConfig().get("delete-unsellable")) { + it.amount = 0 + } + continue + } + + price *= getDouble("multiplier", minion.getLevel()) + + if (minion.getStorage() + price > getDouble("storage", minion.getLevel())) { + continue + } + + minion.setActions(minion.getActionAmount() + it.amount) + minion.damageTool() + minion.setStorage(minion.getStorage() + price) + it.amount = 0 + } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/SlayerMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/SlayerMinionType.kt index d1486a0..4ba15d8 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/SlayerMinionType.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/SlayerMinionType.kt @@ -3,10 +3,79 @@ package com.artillexstudios.axminions.minions.miniontype import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.miniontype.MinionType +import com.artillexstudios.axminions.api.utils.fastFor +import com.artillexstudios.axminions.api.warnings.Warnings +import com.artillexstudios.axminions.minions.MinionTicker +import com.artillexstudios.axminions.nms.NMSHandler +import kotlin.math.roundToInt +import org.bukkit.Material +import org.bukkit.enchantments.Enchantment +import org.bukkit.entity.Item +import org.bukkit.entity.LivingEntity +import org.bukkit.entity.Player +import org.bukkit.entity.Tameable class SlayerMinionType : MinionType("slayer", AxMinionsPlugin.INSTANCE.getResource("minions/slayer.yml")!!) { - override fun run(minion: Minion) { + override fun shouldRun(minion: Minion): Boolean { + return MinionTicker.getTick() % minion.getNextAction() == 0L + } + override fun onToolDirty(minion: Minion) { + val minionImpl = minion as com.artillexstudios.axminions.minions.Minion + minionImpl.setRange(getDouble("range", minion.getLevel())) + val efficiency = 1.0 - (minion.getTool()?.getEnchantmentLevel(Enchantment.DIG_SPEED)?.div(10.0) ?: 0.1) + minionImpl.setNextAction((getLong("speed", minion.getLevel()) * efficiency).roundToInt()) + } + + override fun run(minion: Minion) { + if (minion.getLinkedChest() != null) { + val type = minion.getLinkedChest()!!.block.type + if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) { + minion.setLinkedChest(null) + } + } + + if (minion.getLinkedInventory() == null) { + minion.setLinkedChest(null) + } + + if (!minion.canUseTool()) { + Warnings.NO_TOOL.display(minion) + return + } + + Warnings.remove(minion, Warnings.NO_TOOL) + + minion.getLocation().world!!.getNearbyEntities(minion.getLocation(), minion.getRange(), minion.getRange(), minion.getRange()).filterIsInstance().fastFor { + if (it is Player) return@fastFor + + if (!getConfig().getBoolean("damage-animals") && NMSHandler.get().isAnimal(it)) { + return@fastFor + } + + if (!getConfig().getBoolean("damage-renamed") && it.customName != null) { + return@fastFor + } + + if (!getConfig().getBoolean("damage-tamed") && it is Tameable && it.isTamed) { + return@fastFor + } + + NMSHandler.get().attack(minion, it) + it.location.world!!.getNearbyEntities(it.location, 2.0, 2.0, 2.0).filterIsInstance().fastFor { item -> + if (minion.getLinkedInventory()?.firstEmpty() == -1) { + Warnings.CONTAINER_FULL.display(minion) + return + } + + val amount = AxMinionsPlugin.integrations.getStackerIntegration().getStackSize(item) + val stack = item.itemStack + stack.amount = amount.toInt() + + minion.addToContainerOrDrop(stack) + item.remove() + } + } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/nms/NMSHandler.kt b/common/src/main/kotlin/com/artillexstudios/axminions/nms/NMSHandler.kt new file mode 100644 index 0000000..d57d9e1 --- /dev/null +++ b/common/src/main/kotlin/com/artillexstudios/axminions/nms/NMSHandler.kt @@ -0,0 +1,23 @@ +package com.artillexstudios.axminions.nms + +import com.artillexstudios.axapi.utils.Version +import com.artillexstudios.axminions.api.minions.Minion +import org.bukkit.entity.Entity +import org.bukkit.inventory.ItemStack + +interface NMSHandler { + companion object { + private val handler: NMSHandler = + Class.forName("com.artillexstudios.axminions.nms.${Version.getServerVersion().nmsVersion}.NMSHandler").getConstructor().newInstance() as NMSHandler + + fun get(): NMSHandler { + return handler + } + } + + fun attack(source: Minion, target: Entity) + + fun generateRandomFishingLoot(minion: Minion): List + + fun isAnimal(entity: Entity): Boolean +} \ No newline at end of file diff --git a/common/src/main/resources/messages.yml b/common/src/main/resources/messages.yml index 090c97f..4f11515 100644 --- a/common/src/main/resources/messages.yml +++ b/common/src/main/resources/messages.yml @@ -32,6 +32,12 @@ upgrades: upgraded: "Successfully upgraded the minion to level: !" limit-reached: "You have maxed this minion!" +link: + success: "Successfully linked the minion to a container!" + unlink: "You have unliked the minion." + fail: "You can't link to that block! It's either too far away, or not a container!" + start: "Started linking! Click on a container!" + levels: 1: "<#33FF33>" 2: "<#66FF00>" diff --git a/common/src/main/resources/minions/fisher.yml b/common/src/main/resources/minions/fisher.yml new file mode 100644 index 0000000..4334745 --- /dev/null +++ b/common/src/main/resources/minions/fisher.yml @@ -0,0 +1,133 @@ +name: "<#00EEFF>Fisher Minion" + +entity: + name: "[] <#00EEFF>Fisher Minion []" + +tool: + material: + - "FISHING_ROD" + +item: + type: "player_head" + texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWMxNWU1ZmI1NmZhMTZiMDc0N2IxYmNiMDUzMzVmNTVkMWZhMzE1NjFjMDgyYjVlMzY0M2RiNTU2NTQxMDg1MiJ9fX0=" + name: "<#00EEFF>Fisher Minion" + lore: + - "" + - " - It catches fish." + - "" + - "<#00EEFF>Statistics" + - " <#00EEFF>❙ Level: <#FFEEAA>" + - " <#00EEFF>❙ Fish caught: <#FFEEAA>" + - "" + - "<#00EEFF>(!) Place the minion and give it a fishing rod!" + +gui: + upgrade: + type: "gold_ingot" + name: "<#00CCFF>Upgrade minion" + lore: + - "" + - " - Level: » " + - " - Range: » " + - " - Speed: » " + - "" + - "<#00CCFF>Requirements:" + - " - Money: <#33FF33>$" + - " - Fish caught: <#33FF33>" + - "" + - "<#00CCFF>(!) Click here to upgrade your minion!" + statistics: + type: "paper" + name: "<#00EEFF>Statistics" + lore: + - "" + - " - Killed mobs: <#00EEFF>" + - "" + +upgrades: + 1: + range: 3 + speed: 200 + items: + helmet: + type: "player_head" + texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWMxNWU1ZmI1NmZhMTZiMDc0N2IxYmNiMDUzMzVmNTVkMWZhMzE1NjFjMDgyYjVlMzY0M2RiNTU2NTQxMDg1MiJ9fX0=" + chestplate: + type: "leather_chestplate" + color: "0, 150, 255" + glow: false + leggings: + type: "leather_leggings" + color: "0, 150, 255" + glow: false + boots: + type: "leather_boots" + color: "0, 150, 255" + glow: false + 2: + range: 4 + speed: 190 + requirements: + money: 1000 + actions: 100 + 3: + range: 4 + speed: 175 + requirements: + money: 3000 + actions: 300 + 4: + range: 5 + speed: 160 + requirements: + money: 10000 + actions: 1000 + 5: + range: 5 + speed: 150 + requirements: + money: 20000 + actions: 3000 + 6: + range: 6 + speed: 130 + requirements: + money: 50000 + actions: 6000 + 7: + range: 6 + speed: 115 + requirements: + money: 150000 + actions: 10000 + 8: + range: 7 + speed: 100 + requirements: + money: 500000 + actions: 17500 + 9: + range: 8 + speed: 85 + requirements: + money: 1000000 + actions: 25000 + 10: + range: 8 + speed: 60 + requirements: + money: 5000000 + actions: 50000 + items: + chestplate: + type: LEATHER_CHESTPLATE + color: "255, 200, 0" + glow: true + leggings: + type: LEATHER_LEGGINGS + color: "255, 200, 0" + glow: true + boots: + type: LEATHER_BOOTS + color: "255, 200, 0" + glow: true \ No newline at end of file diff --git a/common/src/main/resources/minions/lumber.yml b/common/src/main/resources/minions/lumber.yml index 3b87bd0..693d4f2 100644 --- a/common/src/main/resources/minions/lumber.yml +++ b/common/src/main/resources/minions/lumber.yml @@ -76,49 +76,49 @@ upgrades: money: 1000 actions: 100 3: - range: 5 + range: 4 speed: 175 requirements: money: 3000 actions: 300 4: - range: 6 + range: 5 speed: 160 requirements: money: 10000 actions: 1000 5: - range: 7 + range: 5 speed: 150 requirements: money: 20000 actions: 3000 6: - range: 8 + range: 6 speed: 130 requirements: money: 50000 actions: 6000 7: - range: 9 + range: 6 speed: 115 requirements: money: 150000 actions: 10000 8: - range: 10 + range: 7 speed: 100 requirements: money: 500000 actions: 17500 9: - range: 11 + range: 8 speed: 85 requirements: money: 1000000 actions: 25000 10: - range: 12 + range: 8 speed: 60 requirements: money: 5000000 diff --git a/common/src/main/resources/minions/miner.yml b/common/src/main/resources/minions/miner.yml index e66fb50..e71bd92 100644 --- a/common/src/main/resources/minions/miner.yml +++ b/common/src/main/resources/minions/miner.yml @@ -14,7 +14,7 @@ tool: # Can be: sphere, line, face, asphere # If set to sphere: checks blocks in a sphere with the range of the minion as radius (Most resource intensive, the larger the radius, the worse) -# If set to line: checks blocks in all 4 directions from the minion in the range of the minion +# If set to line: checks blocks in all 4 directions from the minion in the range of the minion (Best performance to blocks broken ratio) # If set to face: checks blocks only in the facing of the minion (Least resource intensive) # If set to asphere: checks blocks in a sphere with the range of the minion as the radius, around the minion # Only switch to asphere mode, if you know what you're doing, @@ -79,55 +79,55 @@ upgrades: color: "0, 150, 255" glow: false 2: - range: 4 - speed: 190 + range: 3 + speed: 185 requirements: money: 1000 actions: 100 3: - range: 5 + range: 3 speed: 175 requirements: money: 3000 actions: 300 4: - range: 6 + range: 4 speed: 160 requirements: money: 10000 actions: 1000 5: - range: 7 + range: 4 speed: 150 requirements: money: 20000 actions: 3000 6: - range: 8 + range: 5 speed: 130 requirements: money: 50000 actions: 6000 7: - range: 9 + range: 5 speed: 115 requirements: money: 150000 actions: 10000 8: - range: 10 + range: 6 speed: 100 requirements: money: 500000 actions: 17500 9: - range: 11 + range: 6 speed: 85 requirements: money: 1000000 actions: 25000 10: - range: 12 + range: 7 speed: 60 requirements: money: 5000000 diff --git a/common/src/main/resources/minions/seller.yml b/common/src/main/resources/minions/seller.yml new file mode 100644 index 0000000..7742044 --- /dev/null +++ b/common/src/main/resources/minions/seller.yml @@ -0,0 +1,148 @@ +name: "<#CC00FF>Seller Minion" + +entity: + name: "[] <#CC00FF>Seller Minion []" + +tool: + material: + - "BOW" + - "CROSSBOW" + +delete-unsellable: true + +item: + type: "player_head" + texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDI0YmE3NjBhNjFkZDI1NmM1MmIzMjUxMjlmNDYwMTZhZTg5MjIzMmEwZGVhMTcxNWY5OTdmN2M0ZDYyMmJlZiJ9fX0=" + name: "<#CC00FF>Seller Minion" + lore: + - "" + - " - Sells all items from it's container." + - "" + - "<#CC00FF>Statistics" + - " <#CC00FF>❙ Level: <#FFEEAA>" + - " <#CC00FF>❙ Sold items: <#FFEEAA>" + - "" + - "<#CC00FF>(!) Place the minion and give it a bow!" + +gui: + upgrade: + type: "gold_ingot" + name: "<#00CCFF>Upgrade minion" + lore: + - "" + - " - Level: » " + - " - Range: » " + - " - Speed: » " + - "" + - "<#00CCFF>Requirements:" + - " - Money: <#33FF33>$" + - " - Collected items: <#33FF33>" + - "" + - "<#00CCFF>(!) Click here to upgrade your minion!" + statistics: + type: "paper" + name: "<#CC00FF>Statistics" + lore: + - "" + - " - Collected items: <#CC00FF>" + - " - Stored coins: <#CC00FF>" + - "" + - "<#CC00FF>(!) Click here to collect the stored coins!" + +upgrades: + 1: + multiplier: 1 + speed: 600 + storage: 100000 + items: + helmet: + type: "player_head" + texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDI0YmE3NjBhNjFkZDI1NmM1MmIzMjUxMjlmNDYwMTZhZTg5MjIzMmEwZGVhMTcxNWY5OTdmN2M0ZDYyMmJlZiJ9fX0=" + chestplate: + type: "leather_chestplate" + color: "200, 0, 255" + glow: false + leggings: + type: "leather_leggings" + color: "255, 230, 0" + glow: false + boots: + type: "leather_boots" + color: "255, 230, 0" + glow: false + 2: + multiplier: 1.05 + speed: 500 + storage: 500000 + requirements: + money: 1000 + actions: 100 + 3: + multiplier: 1.1 + speed: 450 + storage: 1000000 + requirements: + money: 3000 + actions: 300 + 4: + multiplier: 1.15 + speed: 400 + storage: 4000000 + requirements: + money: 10000 + actions: 1000 + 5: + multiplier: 1.2 + speed: 350 + storage: 7000000 + requirements: + money: 20000 + actions: 3000 + 6: + multiplier: 1.25 + speed: 300 + storage: 10000000 + requirements: + money: 50000 + actions: 6000 + 7: + multiplier: 1.3 + speed: 250 + storage: 30000000 + requirements: + money: 150000 + actions: 10000 + 8: + multiplier: 1.35 + speed: 200 + storage: 50000000 + requirements: + money: 500000 + actions: 17500 + 9: + multiplier: 1.4 + speed: 150 + storage: 80000000 + requirements: + money: 1000000 + actions: 25000 + 10: + multiplier: 1.5 + speed: 100 + storage: 100000000 + requirements: + money: 5000000 + actions: 50000 + items: + chestplate: + type: LEATHER_CHESTPLATE + color: "255, 200, 0" + glow: true + leggings: + type: LEATHER_LEGGINGS + color: "255, 200, 0" + glow: true + boots: + type: LEATHER_BOOTS + color: "255, 200, 0" + glow: true \ No newline at end of file diff --git a/common/src/main/resources/minions/slayer.yml b/common/src/main/resources/minions/slayer.yml new file mode 100644 index 0000000..1f5da8b --- /dev/null +++ b/common/src/main/resources/minions/slayer.yml @@ -0,0 +1,142 @@ +name: "<#FF3333>Slayer Minion" + +entity: + name: "[] <#FF3333>Slayer Minion []" + +tool: + material: + - "WOODEN_SWORD" + - "STONE_SWORD" + - "GOLDEN_SWORD" + - "IRON_SWORD" + - "DIAMOND_SWORD" + - "NETHERITE_SWORD" + +damage-animals: false +damage-tamed: false +damage-renamed: false + +item: + type: "player_head" + texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTc1MzJlOTBjNTczYTM5NGM3ODAyYWE0MTU4MzA1ODAyYjU5ZTY3ZjJhMmI3ZTNmZDAzNjNhYTZlYTQyYjg0MSJ9fX0=" + name: "<#FF3333>Slayer Minion" + lore: + - "" + - " - Kills mobs around itself." + - "" + - "<#FF3333>Statistics" + - " <#FF3333>❙ Level: <#FFEEAA>" + - " <#FF3333>❙ Mobs killed: <#FFEEAA>" + - "" + - "<#FF3333>(!) Place the minion and give it a sword!" + +gui: + upgrade: + type: "gold_ingot" + name: "<#00CCFF>Upgrade minion" + lore: + - "" + - " - Level: » " + - " - Range: » " + - " - Speed: » " + - "" + - "<#00CCFF>Requirements:" + - " - Money: <#33FF33>$" + - " - Killed mobs: <#33FF33>" + - "" + - "<#00CCFF>(!) Click here to upgrade your minion!" + statistics: + type: "paper" + name: "<#FF3333>Statistics" + lore: + - "" + - " - Killed mobs: <#FF3333>" + - "" + +upgrades: + 1: + range: 3 + speed: 200 + items: + helmet: + type: "player_head" + texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTc1MzJlOTBjNTczYTM5NGM3ODAyYWE0MTU4MzA1ODAyYjU5ZTY3ZjJhMmI3ZTNmZDAzNjNhYTZlYTQyYjg0MSJ9fX0=" + chestplate: + type: "leather_chestplate" + color: "0, 150, 255" + glow: false + leggings: + type: "leather_leggings" + color: "0, 150, 255" + glow: false + boots: + type: "leather_boots" + color: "0, 150, 255" + glow: false + 2: + range: 4 + speed: 190 + requirements: + money: 1000 + actions: 100 + 3: + range: 4 + speed: 175 + requirements: + money: 3000 + actions: 300 + 4: + range: 5 + speed: 160 + requirements: + money: 10000 + actions: 1000 + 5: + range: 5 + speed: 150 + requirements: + money: 20000 + actions: 3000 + 6: + range: 6 + speed: 130 + requirements: + money: 50000 + actions: 6000 + 7: + range: 6 + speed: 115 + requirements: + money: 150000 + actions: 10000 + 8: + range: 7 + speed: 100 + requirements: + money: 500000 + actions: 17500 + 9: + range: 8 + speed: 85 + requirements: + money: 1000000 + actions: 25000 + 10: + range: 8 + speed: 60 + requirements: + money: 5000000 + actions: 50000 + items: + chestplate: + type: LEATHER_CHESTPLATE + color: "255, 200, 0" + glow: true + leggings: + type: LEATHER_LEGGINGS + color: "255, 200, 0" + glow: true + boots: + type: LEATHER_BOOTS + color: "255, 200, 0" + glow: true \ No newline at end of file diff --git a/nms/build.gradle b/nms/build.gradle new file mode 100644 index 0000000..6d99e85 --- /dev/null +++ b/nms/build.gradle @@ -0,0 +1,13 @@ +plugins { + id("io.papermc.paperweight.userdev") version "1.5.4" apply false +} + +group = "com.artillexstudios.axminions" +version = rootProject.version + +subprojects { + dependencies { + compileOnly project(":common") + compileOnly project(":api") + } +} \ No newline at end of file diff --git a/nms/v1_20_R1/build.gradle b/nms/v1_20_R1/build.gradle new file mode 100644 index 0000000..5c7d254 --- /dev/null +++ b/nms/v1_20_R1/build.gradle @@ -0,0 +1,20 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +group = 'com.artillexstudios.axminions.nms' +version = '1.0-SNAPSHOT' + +dependencies { + paperweight.paperDevBundle("1.20-R0.1-SNAPSHOT") +} + +tasks { + build { + dependsOn(reobfJar) + } + + reobfJar { + mustRunAfter(shadowJar) + } +} \ No newline at end of file diff --git a/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/DamageHandler.kt b/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/DamageHandler.kt new file mode 100644 index 0000000..6af656c --- /dev/null +++ b/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/DamageHandler.kt @@ -0,0 +1,205 @@ +package com.artillexstudios.axminions.nms.v1_20_R1 + +import com.artillexstudios.axminions.api.events.MinionDamageEntityEvent +import com.artillexstudios.axminions.api.minions.Minion +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.server.level.ServerLevel +import net.minecraft.util.Mth +import net.minecraft.world.effect.MobEffectInstance +import net.minecraft.world.effect.MobEffects +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.MobType +import net.minecraft.world.entity.decoration.ArmorStand +import net.minecraft.world.item.AxeItem +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.SwordItem +import net.minecraft.world.item.TridentItem +import net.minecraft.world.item.enchantment.EnchantmentHelper +import net.minecraft.world.item.enchantment.SweepingEdgeEnchantment +import org.bukkit.Bukkit +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity +import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack +import org.bukkit.enchantments.Enchantment +import org.bukkit.entity.Entity +import org.bukkit.event.entity.EntityPotionEffectEvent + +object DamageHandler { + + fun damage(source: Minion, entity: Entity) { + val nmsEntity = (entity as CraftEntity).handle + var f = 1 + + val nmsItem: ItemStack + if (source.getTool() == null) { + nmsItem = ItemStack.EMPTY + } else { + nmsItem = CraftItemStack.asNMSCopy(source.getTool()) + + if (nmsItem.item is SwordItem) { + f = (f + (nmsItem.item as SwordItem).damage).toInt() + } + + if (nmsItem.item is AxeItem) { + f = (f + (nmsItem.item as AxeItem).attackDamage).toInt() + } + + if (nmsItem.item is TridentItem) { + f = (f + TridentItem.BASE_DAMAGE).toInt() + } + } + + if (!nmsEntity.isAttackable) return + val f2 = 1.0f + + var f1 = if (nmsEntity is LivingEntity) { + EnchantmentHelper.getDamageBonus(nmsItem, (nmsEntity).mobType) + } else { + EnchantmentHelper.getDamageBonus(nmsItem, MobType.UNDEFINED) + } + + f = (f * (0.2f + f2 * f2 * 0.8f)).toInt() + f1 *= f2 + + if (f > 0.0f || f1 > 0.0f) { + var flag3 = false + val b0: Byte = 0 + val i = b0 + (source.getTool()?.getEnchantmentLevel(Enchantment.KNOCKBACK) ?: 0) + + f = (f * 1.5f).toInt() + f = (f + f1).toInt() + + if (nmsItem.item is SwordItem) { + flag3 = true + } + + var f3 = 0.0f + var flag4 = false + val j = (source.getTool()?.getEnchantmentLevel(Enchantment.FIRE_ASPECT) ?: 0) + + if (nmsEntity is LivingEntity) { + f3 = nmsEntity.health + if (j > 0 && !nmsEntity.isOnFire()) { + flag4 = true + nmsEntity.setSecondsOnFire(1, false) + } + } + + val event = MinionDamageEntityEvent(source, entity as org.bukkit.entity.LivingEntity, f.toDouble()) + Bukkit.getPluginManager().callEvent(event) + if (event.isCancelled) { + return + } + + val flag5 = nmsEntity.hurt(nmsEntity.damageSources().magic(), f.toFloat()) + + if (flag5) { + if (i > 0) { + if (nmsEntity is LivingEntity) { + (nmsEntity).knockback( + (i.toFloat() * 0.5f).toDouble(), + Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble(), + (-Mth.cos(source.getLocation().yaw * 0.017453292f)).toDouble() + ) + } else { + nmsEntity.push( + (-Mth.sin(source.getLocation().yaw * 0.017453292f) * i.toFloat() * 0.5f).toDouble(), + 0.1, + (Mth.cos(source.getLocation().yaw * 0.017453292f) * i.toFloat() * 0.5f).toDouble() + ) + } + } + + if (flag3) { + val sweep = source.getTool()?.getEnchantmentLevel(Enchantment.SWEEPING_EDGE) ?: 0 + val f4 = 1.0f + if (sweep > 0) SweepingEdgeEnchantment.getSweepingDamageRatio(sweep) else 0.0f * f + val list: List = (source.getLocation().world as CraftWorld).handle + .getEntitiesOfClass(LivingEntity::class.java, nmsEntity.boundingBox.inflate(1.0, 0.25, 1.0)) + val iterator: Iterator<*> = list.iterator() + + while (iterator.hasNext()) { + val entityliving: LivingEntity = iterator.next() as LivingEntity + + if ((entityliving !is ArmorStand || !(entityliving).isMarker) && source.getLocation().distanceSquared( + (entity as Entity).location + ) < 9.0 + ) { + val damageEvent = MinionDamageEntityEvent(source, entityliving.bukkitEntity as org.bukkit.entity.LivingEntity, f4.toDouble()) + Bukkit.getPluginManager().callEvent(damageEvent) + if (event.isCancelled) { + return + } + + // CraftBukkit start - Only apply knockback if the damage hits + if (entityliving.hurt(nmsEntity.damageSources().magic(), f4)) { + entityliving.knockback( + 0.4000000059604645, + Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble(), + (-Mth.cos(source.getLocation().yaw * 0.017453292f)).toDouble() + ) + } + // CraftBukkit end + } + } + + val d0 = -Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble() + val d1 = Mth.cos(source.getLocation().yaw * 0.017453292f).toDouble() + + if ((source.getLocation().world as CraftWorld).handle is ServerLevel) { + ((source.getLocation().world as CraftWorld).handle as ServerLevel).sendParticles( + ParticleTypes.SWEEP_ATTACK, + source.getLocation().x + d0, + source.getLocation().y + 0.5, + source.getLocation().z + d1, + 0, + d0, + 0.0, + d1, + 0.0 + ) + } + } + + + val baneOfArthropods = source.getTool()?.getEnchantmentLevel(Enchantment.DAMAGE_ARTHROPODS) ?: 0 + if (nmsEntity is LivingEntity) { + if (baneOfArthropods > 0 && (nmsEntity.mobType === MobType.ARTHROPOD)) { + val p: Int = 20 + nmsEntity.random.nextInt(10 * baneOfArthropods) + nmsEntity.addEffect( + MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, p, 3), + EntityPotionEffectEvent.Cause.ATTACK + ) + } + } + + if (nmsEntity is LivingEntity) { + val f5: Float = f3 - nmsEntity.health + + if (j > 0) { + nmsEntity.setSecondsOnFire(j * 4, false) + } + + if ((source.getLocation().world as CraftWorld).handle is ServerLevel && f5 > 2.0f) { + val k = (f5.toDouble() * 0.5).toInt() + + ((source.getLocation().world as CraftWorld).handle).sendParticles( + ParticleTypes.DAMAGE_INDICATOR, + nmsEntity.getX(), + nmsEntity.getY(0.5), + nmsEntity.getZ(), + k, + 0.1, + 0.0, + 0.1, + 0.2 + ) + } + } + } else { + if (flag4) { + nmsEntity.clearFire() + } + } + } + } +} \ No newline at end of file diff --git a/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/LootHandler.kt b/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/LootHandler.kt new file mode 100644 index 0000000..14adb67 --- /dev/null +++ b/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/LootHandler.kt @@ -0,0 +1,38 @@ +package com.artillexstudios.axminions.nms.v1_20_R1 + +import com.artillexstudios.axminions.api.minions.Minion +import net.minecraft.server.MinecraftServer +import net.minecraft.world.level.storage.loot.BuiltInLootTables +import net.minecraft.world.level.storage.loot.LootParams +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets +import net.minecraft.world.level.storage.loot.parameters.LootContextParams +import net.minecraft.world.phys.Vec3 +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld +import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack +import org.bukkit.inventory.ItemStack + +object LootHandler { + + fun generateFishingLoot(minion: Minion): List { + val nmsItem: net.minecraft.world.item.ItemStack = if (minion.getTool() == null) { + net.minecraft.world.item.ItemStack.EMPTY + } else { + CraftItemStack.asNMSCopy(minion.getTool()) + } + + val level = (minion.getLocation().world as CraftWorld).handle + + val lootparams = LootParams.Builder(level).withParameter( + LootContextParams.ORIGIN, Vec3(minion.getLocation().x, minion.getLocation().y, minion.getLocation().z) + ).withParameter(LootContextParams.TOOL, nmsItem).withOptionalParameter(LootContextParams.THIS_ENTITY, null) + .create(LootContextParamSets.FISHING) + + val lootTable = MinecraftServer.getServer().lootData.getLootTable(BuiltInLootTables.FISHING) + + return lootTable.getRandomItems(lootparams).stream().map { original: net.minecraft.world.item.ItemStack? -> + CraftItemStack.asBukkitCopy( + original + ) + }.toList() + } +} \ No newline at end of file diff --git a/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/NMSHandler.kt b/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/NMSHandler.kt new file mode 100644 index 0000000..783c502 --- /dev/null +++ b/nms/v1_20_R1/src/main/kotlin/com/artillexstudios/axminions/nms/v1_20_R1/NMSHandler.kt @@ -0,0 +1,23 @@ +package com.artillexstudios.axminions.nms.v1_20_R1 + +import com.artillexstudios.axminions.api.minions.Minion +import com.artillexstudios.axminions.nms.NMSHandler +import net.minecraft.world.entity.MobCategory +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity +import org.bukkit.entity.Entity +import org.bukkit.inventory.ItemStack + +class NMSHandler : NMSHandler { + + override fun attack(source: Minion, target: Entity) { + DamageHandler.damage(source, target) + } + + override fun generateRandomFishingLoot(minion: Minion): List { + return LootHandler.generateFishingLoot(minion) + } + + override fun isAnimal(entity: Entity): Boolean { + return (entity as CraftEntity).handle.type.category == MobCategory.CREATURE + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 9793353..eaae46a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,4 +12,6 @@ plugins { rootProject.name = 'AxMinions' include 'api' include 'common' +include 'nms' +include 'nms:v1_20_R1'