diff --git a/.build.gradle.swp b/.build.gradle.swp new file mode 100644 index 0000000..ebdb209 Binary files /dev/null and b/.build.gradle.swp differ diff --git a/build.gradle b/build.gradle index acf573c..ea88daf 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { } group = 'com.artillexstudios.axminions' -version = '1.0.12' +version = '1.0.13' repositories { mavenCentral() @@ -29,6 +29,8 @@ dependencies { implementation project(path: ":nms:v1_20_R3", configuration: "reobf") implementation project(path: ":nms:v1_20_R4", configuration: "reobf") implementation project(path: ":nms:v1_21_R1", configuration: "reobf") + implementation project(path: ":nms:v1_21_R2", configuration: "reobf") +// implementation project(path: ":nms:v1_21_R3", configuration: "reobf") } allprojects { @@ -133,8 +135,11 @@ allprojects { compileOnly 'com.bgsoftware:WildStackerAPI:2023.2' compileOnly 'net.essentialsx:EssentialsX:2.19.0' compileOnly 'com.github.Gypopo:EconomyShopGUI-API:1.7.0' - compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0' - compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT' + compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0' + compileOnly('com.sk89q.worldguard:worldguard-bukkit:7.0.1') { + exclude module: "org.spigotmc" + exclude module: "org.bukkit" + } compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:2023.2' compileOnly 'world.bentobox:bentobox:1.24.0-SNAPSHOT' compileOnly 'com.github.TechFortress:GriefPrevention:16.18' @@ -144,11 +149,13 @@ allprojects { compileOnly 'com.github.LoneDev6:api-itemsadder:3.6.1' compileOnly 'com.palmergames.bukkit.towny:towny:0.100.1.0' implementation platform('com.intellectualsites.bom:bom-newest:1.35') - implementation("com.artillexstudios.axapi:axapi:1.4.322:all") + implementation("com.artillexstudios.axapi:axapi:1.4.507:all") implementation("com.zaxxer:HikariCP:5.1.0") implementation("org.bstats:bstats-bukkit:3.0.2") compileOnly 'org.black_ixx:playerpoints:3.2.6' - compileOnly 'com.github.Maxlego08:zShop-API:3.0.5' +// compileOnly('com.github.Maxlego08:zShop-API:3.0.5') { +// exclude module: "zMenu-API" +// } compileOnly 'me.clip:placeholderapi:2.11.5' } } diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt b/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt index 465d1e5..ca954f6 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt @@ -3,7 +3,7 @@ package com.artillexstudios.axminions import com.artillexstudios.axapi.AxPlugin import com.artillexstudios.axapi.data.ThreadedQueue import com.artillexstudios.axapi.scheduler.Scheduler -import com.artillexstudios.axapi.utils.FeatureFlags +import com.artillexstudios.axapi.utils.featureflags.FeatureFlags import com.artillexstudios.axminions.api.AxMinionsAPI import com.artillexstudios.axminions.api.AxMinionsAPIImpl import com.artillexstudios.axminions.api.config.Config @@ -62,9 +62,9 @@ class AxMinionsPlugin : AxPlugin() { manager.loadLibrary(h2) } - override fun updateFlags() { - FeatureFlags.PACKET_ENTITY_TRACKER_ENABLED.set(true) - FeatureFlags.USE_LEGACY_HEX_FORMATTER.set(true) + override fun updateFlags(flags: FeatureFlags) { + flags.PACKET_ENTITY_TRACKER_ENABLED.set(true) + flags.USE_LEGACY_HEX_FORMATTER.set(true) } override fun load() { @@ -74,6 +74,7 @@ class AxMinionsPlugin : AxPlugin() { override fun enable() { Metrics(this, 19043) + com.artillexstudios.axapi.metrics.AxMetrics(5).start() AxMinionsPlugin.config = Config(File(dataFolder, "config.yml"), getResource("config.yml")!!) messages = Messages(File(dataFolder, "messages.yml"), getResource("messages.yml")!!) 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 da87d51..205fb97 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/integrations/Integrations.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/Integrations.kt @@ -14,7 +14,7 @@ import com.artillexstudios.axminions.integrations.prices.CMIIntegration import com.artillexstudios.axminions.integrations.prices.EconomyShopGUIIntegration import com.artillexstudios.axminions.integrations.prices.EssentialsIntegration import com.artillexstudios.axminions.integrations.prices.ShopGUIPlusIntegration -import com.artillexstudios.axminions.integrations.prices.ZShopIntegration +//import com.artillexstudios.axminions.integrations.prices.ZShopIntegration import com.artillexstudios.axminions.integrations.protection.BentoBoxIntegration import com.artillexstudios.axminions.integrations.protection.GriefPreventionIntegration import com.artillexstudios.axminions.integrations.protection.IridiumSkyBlockIntegration @@ -108,11 +108,11 @@ class Integrations : Integrations { .sendMessage(StringUtils.formatToString("<#33FF33>[AxMinions] Hooked into EconomyShopGUI!"))} } - "zshop" -> { - if (isPluginLoaded("zShop")) { - register(ZShopIntegration()) - } - } +// "zshop" -> { +// if (isPluginLoaded("zShop")) { +// register(ZShopIntegration()) +// } +// } } when (Config.ECONOMY_HOOK().lowercase(Locale.ENGLISH)) { diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/integrations/prices/ZShopIntegration.kt b/common/src/main/kotlin/com/artillexstudios/axminions/integrations/prices/ZShopIntegration.-kt similarity index 100% rename from common/src/main/kotlin/com/artillexstudios/axminions/integrations/prices/ZShopIntegration.kt rename to common/src/main/kotlin/com/artillexstudios/axminions/integrations/prices/ZShopIntegration.-kt diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionDamageListener.kt b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionDamageListener.kt index 0ab679d..b2a9eca 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionDamageListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionDamageListener.kt @@ -7,25 +7,43 @@ import com.artillexstudios.axminions.api.events.MinionKillEntityEvent import com.artillexstudios.axminions.api.utils.fastFor import com.artillexstudios.axminions.api.warnings.Warnings import com.artillexstudios.axminions.nms.NMSHandler +import dev.rosewood.rosestacker.api.RoseStackerAPI +import com.artillexstudios.axminions.integrations.stacker.RoseStackerIntegration import org.bukkit.Bukkit import java.util.concurrent.ThreadLocalRandom +import java.util.Random import org.bukkit.entity.Item import org.bukkit.entity.LivingEntity import org.bukkit.entity.Player import org.bukkit.event.EventHandler +import org.bukkit.event.EventPriority import org.bukkit.event.Listener import org.bukkit.event.entity.EntityDamageByEntityEvent class MinionDamageListener : Listener { + private val random = Random() @EventHandler fun onMinionKillEntityEvent(event: MinionKillEntityEvent) { + val minion = event.minion val entitySize = AxMinionsPlugin.integrations.getStackerIntegration().getStackSize(event.target) + if (AxMinionsPlugin.integrations.getStackerIntegration() is RoseStackerIntegration && entitySize > 1) { + // chance can be 0.01 = 1% or 0.1 = 10% or 1 = 100% + val chance = minion.getType().getDouble("chance-kill-stacked-amount", minion.getLevel()) + val amount = minion.getType().getLong("stacked-amount", minion.getLevel()) + val stackedEntity = RoseStackerAPI.getInstance().getStackedEntity(event.target)!! + val amountToKill = (if (entitySize > amount) amount else entitySize) as Long + if (random.nextDouble() <= chance) { + stackedEntity.killPartialStack(null, (amountToKill as Number).toInt()) + minion.setActions((minion.getActionAmount() + (amountToKill - 1L) as Long) as Long) + } + } else { + event.minion.setActions(event.minion.getActionAmount() + entitySize) + } - event.minion.setActions(event.minion.getActionAmount() + entitySize) val coerced = (event.minion.getStorage() + ThreadLocalRandom.current().nextInt(1, 4) * entitySize).coerceIn( - 0.0, - event.minion.getType().getLong("storage", event.minion.getLevel()).toDouble() + 0.0, + event.minion.getType().getLong("storage", event.minion.getLevel()).toDouble() ) event.minion.setStorage(coerced) @@ -53,12 +71,6 @@ class MinionDamageListener : Listener { @EventHandler fun onEntityDamageByEntityEvent(event: EntityDamageByEntityEvent) { - if (event.damager.uniqueId == NMSHandler.get().getAnimalUUID() && event.entity is Player) { - event.isCancelled = true - event.damage = 0.0 - return - } - val entity = event.entity if (entity is LivingEntity) { if (event.damager.uniqueId == NMSHandler.get().getAnimalUUID() && event.finalDamage > entity.health) { @@ -66,4 +78,19 @@ class MinionDamageListener : Listener { } } } + + @EventHandler(priority = EventPriority.MONITOR) + fun onEntityDamageByEntityEvente(event: EntityDamageByEntityEvent) { + if (event.damager.uniqueId != NMSHandler.get().getAnimalUUID()) { + return + } + + if (event.entity is Player) { + event.isCancelled = true + event.damage = 0.0 + return + } + + event.isCancelled = false + } } \ 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 fb7aa6c..253744c 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt @@ -195,63 +195,128 @@ class MinionInventoryListener : Listener { player.giveExp(stored.toInt()) minion.setStorage(0.0) } + + AxMinionsPlugin.dataQueue.submit { + AxMinionsPlugin.dataHandler.saveMinion(minion) + } } "charge" -> { - val chargeSeconds = (minion.getCharge() - System.currentTimeMillis()) / 1000 - if ((Config.MAX_CHARGE() * 60) - chargeSeconds < Config.MINIMUM_CHARGE()) { - player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE_NOT_ENOUGH_TIME_PASSED())) - return - } + if (event.isShiftClick) { + while (true) { + val chargeSeconds = (minion.getCharge() - System.currentTimeMillis()) / 1000 - var chargeAmount = Config.CHARGE_AMOUNT() - var itemCharge = false - val section = Config.CHARGE_ITEMS() + if ((Config.MAX_CHARGE() * 60) - chargeSeconds < Config.MINIMUM_CHARGE()) { + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE_NOT_ENOUGH_TIME_PASSED())) + return + } - for (key in section.keys) { - val item = ItemBuilder(section.getSection(key.toString())).get() - if (player.inventory.containsAtLeast(item, 1)) { - itemCharge = true - chargeAmount = section.getSection(key.toString()).getInt("charge") - player.inventory.removeItem(item) - break + var chargeAmount = Config.CHARGE_AMOUNT() + var itemCharge = false + val section = Config.CHARGE_ITEMS() + + for (key in section.keys) { + val item = ItemBuilder(section.getSection(key.toString())).get() + if (player.inventory.containsAtLeast(item, 1)) { + itemCharge = true + chargeAmount = section.getSection(key.toString()).getInt("charge") + player.inventory.removeItem(item) + break + } + } + + if (Config.CHARGE_PRICE() <= 0 && !itemCharge) { + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE_FAIL())) + return + } + + if (!itemCharge) { + if ((AxMinionsPlugin.integrations.getEconomyIntegration()?.getBalance(player) + ?: return) < Config.CHARGE_PRICE() + ) { + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE_FAIL())) + return + } + + AxMinionsPlugin.integrations.getEconomyIntegration()?.let { + minion.getOwner()?.let { player -> + it.takeBalance(player, Config.CHARGE_PRICE()) + } + } + } + + if (chargeSeconds + chargeAmount > Config.MAX_CHARGE() * 60L) { + minion.setCharge(System.currentTimeMillis() + Config.MAX_CHARGE() * 60L * 1000L) + return + } + + if (minion.getCharge() < System.currentTimeMillis()) { + minion.setCharge(System.currentTimeMillis() + chargeAmount * 1000) + } else { + minion.setCharge(minion.getCharge() + chargeAmount * 1000) + } + + if (Messages.CHARGE().isNotBlank()) { + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE())) + } } - } + } else { + val chargeSeconds = (minion.getCharge() - System.currentTimeMillis()) / 1000 - if (Config.CHARGE_PRICE() <= 0 && !itemCharge) { - player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE_FAIL())) - return - } + if ((Config.MAX_CHARGE() * 60) - chargeSeconds < Config.MINIMUM_CHARGE()) { + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE_NOT_ENOUGH_TIME_PASSED())) + return + } - if (!itemCharge) { - if ((AxMinionsPlugin.integrations.getEconomyIntegration()?.getBalance(player) - ?: return) < Config.CHARGE_PRICE() - ) { + var chargeAmount = Config.CHARGE_AMOUNT() + var itemCharge = false + val section = Config.CHARGE_ITEMS() + + for (key in section.keys) { + val item = ItemBuilder(section.getSection(key.toString())).get() + if (player.inventory.containsAtLeast(item, 1)) { + itemCharge = true + chargeAmount = section.getSection(key.toString()).getInt("charge") + player.inventory.removeItem(item) + break + } + } + + if (Config.CHARGE_PRICE() <= 0 && !itemCharge) { player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE_FAIL())) return } - AxMinionsPlugin.integrations.getEconomyIntegration()?.let { - minion.getOwner()?.let { player -> - it.takeBalance(player, Config.CHARGE_PRICE()) + if (!itemCharge) { + if ((AxMinionsPlugin.integrations.getEconomyIntegration()?.getBalance(player) + ?: return) < Config.CHARGE_PRICE() + ) { + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE_FAIL())) + return + } + + AxMinionsPlugin.integrations.getEconomyIntegration()?.let { + minion.getOwner()?.let { player -> + it.takeBalance(player, Config.CHARGE_PRICE()) + } } } - } - if (chargeSeconds + chargeAmount > Config.MAX_CHARGE() * 60L) { - minion.setCharge(System.currentTimeMillis() + Config.MAX_CHARGE() * 60L * 1000L) - return - } + if (chargeSeconds + chargeAmount > Config.MAX_CHARGE() * 60L) { + minion.setCharge(System.currentTimeMillis() + Config.MAX_CHARGE() * 60L * 1000L) + return + } - if (minion.getCharge() < System.currentTimeMillis()) { - minion.setCharge(System.currentTimeMillis() + chargeAmount * 1000) - } else { - minion.setCharge(minion.getCharge() + chargeAmount * 1000) - } + if (minion.getCharge() < System.currentTimeMillis()) { + minion.setCharge(System.currentTimeMillis() + chargeAmount * 1000) + } else { + minion.setCharge(minion.getCharge() + chargeAmount * 1000) + } - if (Messages.CHARGE().isNotBlank()) { - player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE())) + if (Messages.CHARGE().isNotBlank()) { + player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.CHARGE())) + } } } } 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 da6a5d9..66025cc 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minion.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/Minion.kt @@ -133,12 +133,16 @@ class Minion( ) if (event.isAttack) { - if (ownerUUID == event.player.uniqueId) { - breakMinion(event) - } else if ((canBuildAt && !Config.ONLY_OWNER_BREAK()) || event.player.hasPermission("axminions.*")) { - breakMinion(event) - } else { + if (event.player.inventory.firstEmpty() == -1) { broken.set(false) + } else { + if (ownerUUID == event.player.uniqueId) { + breakMinion(event) + } else if ((canBuildAt && !Config.ONLY_OWNER_BREAK()) || event.player.hasPermission("axminions.*")) { + breakMinion(event) + } else { + broken.set(false) + } } } else { if (ownerUUID == event.player.uniqueId) { @@ -263,6 +267,22 @@ class Minion( this.level + 1 ).toString() ) + val chanceKillStackedAmount = Placeholder.parsed("chance_kill_stacked_amount", type.getDouble("chance-kill-stacked-amount", this.level).toString()) + val nextChanceKillStackedAmount = Placeholder.parsed( + "next_chance_kill_stacked_amount", + if (type.hasReachedMaxLevel(this)) Messages.UPGRADES_MAX_LEVEL_REACHED() else type.getDouble( + "chance-kill-stacked-amount", + this.level + 1 + ).toString() + ) + val stackedAmount = Placeholder.parsed("stacked_amount", type.getDouble("stacked-amount", this.level).toString()) + val nextStackedAmount = Placeholder.parsed( + "next_stacked_amount", + if (type.hasReachedMaxLevel(this)) Messages.UPGRADES_MAX_LEVEL_REACHED() else type.getDouble( + "stacked-amount", + this.level + 1 + ).toString() + ) val extra = Placeholder.parsed("extra", type.getDouble("extra", this.level).toString()) val nextExtra = Placeholder.parsed( "next_extra", @@ -321,7 +341,11 @@ class Minion( actions, multiplier, nextMultiplier, - nextStorage + nextStorage, + chanceKillStackedAmount, + nextChanceKillStackedAmount, + stackedAmount, + nextStackedAmount ).get() val meta = item.itemMeta!! diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CrafterMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CrafterMinionType.kt index 24f8c48..2e07db9 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CrafterMinionType.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CrafterMinionType.kt @@ -147,8 +147,10 @@ class CrafterMinionType : MinionType("crafter", AxMinionsPlugin.INSTANCE.getReso val amt = next.value - recipeChoice.itemStack.amount if (amt == 0) { iterator.remove() + } else if (amt > 0) { + next.setValue(amt) } else { - next.setValue(amount) + return false } } } @@ -178,8 +180,10 @@ class CrafterMinionType : MinionType("crafter", AxMinionsPlugin.INSTANCE.getReso val amt = next.value - recipeChoice.value.itemStack.amount if (amt == 0) { iterator.remove() + } else if (amt > 0) { + next.setValue(amt) } else { - next.setValue(amount) + return false } } } 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 8bdf991..8743b6d 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 @@ -110,7 +110,7 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource if (possible) { minion.addToContainerOrDrop( - gen.generator.drawGeneratedObject().customDrops?.item ?: return@fastFor + gen.lastGeneratedObject.customDrops?.item?.clone() ?: return@fastFor ) gen.scheduleGeneratorRegeneration() return@fastFor @@ -158,7 +158,7 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource if (possible) { minion.addToContainerOrDrop( - gen.generator.drawGeneratedObject().customDrops?.item ?: return@fastFor + gen.lastGeneratedObject.customDrops?.item?.clone() ?: return@fastFor ) gen.scheduleGeneratorRegeneration() return@fastFor @@ -192,7 +192,11 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource } } } else { - LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false) + val locCopy = minion.getLocation().clone() + locCopy.setX(locCopy.getBlockX().toDouble()) + locCopy.setY(locCopy.getBlockY().toDouble()) + locCopy.setZ(locCopy.getBlockZ().toDouble()) + LocationUtils.getAllBlocksInRadius(locCopy, minion.getRange(), false) .fastFor { location -> if (AxMinionsPlugin.integrations.kGeneratorsIntegration) { val gen = Main.getPlacedGenerators().getLoaded(location) @@ -201,7 +205,7 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource if (possible) { minion.addToContainerOrDrop( - gen.generator.drawGeneratedObject().customDrops?.item ?: return@fastFor + gen.lastGeneratedObject.customDrops?.item?.clone() ?: return@fastFor ) gen.scheduleGeneratorRegeneration() return@fastFor @@ -236,7 +240,11 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource "line" -> { faces.fastFor { - LocationUtils.getAllBlocksFacing(minion.getLocation(), minion.getRange(), it).fastFor { location -> + val locCopy = minion.getLocation().clone() + locCopy.setX(locCopy.getBlockX().toDouble()) + locCopy.setY(locCopy.getBlockY().toDouble()) + locCopy.setZ(locCopy.getBlockZ().toDouble()) + LocationUtils.getAllBlocksFacing(locCopy, minion.getRange(), it).fastFor { location -> if (AxMinionsPlugin.integrations.kGeneratorsIntegration) { if (Config.DEBUG()) { println("KGenerators integration!") @@ -253,7 +261,7 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource println("Not possible") } minion.addToContainerOrDrop( - gen.generator.drawGeneratedObject().customDrops?.item ?: return@fastFor + gen.lastGeneratedObject.customDrops?.item?.clone() ?: return@fastFor ) gen.scheduleGeneratorRegeneration() return@fastFor @@ -291,7 +299,11 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource } "face" -> { - LocationUtils.getAllBlocksFacing(minion.getLocation(), minion.getRange(), minion.getDirection().facing) + val locCopy = minion.getLocation().clone() + locCopy.setX(locCopy.getBlockX().toDouble()) + locCopy.setY(locCopy.getBlockY().toDouble()) + locCopy.setZ(locCopy.getBlockZ().toDouble()) + LocationUtils.getAllBlocksFacing(locCopy, minion.getRange(), minion.getDirection().facing) .fastFor { location -> if (AxMinionsPlugin.integrations.kGeneratorsIntegration) { val gen = Main.getPlacedGenerators().getLoaded(location) @@ -300,7 +312,7 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource if (possible) { minion.addToContainerOrDrop( - gen.generator.drawGeneratedObject().customDrops?.item ?: return@fastFor + gen.lastGeneratedObject.customDrops?.item?.clone() ?: return@fastFor ) gen.scheduleGeneratorRegeneration() return@fastFor diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c..e644113 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23..cea7a79 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index fcb6fca..1aa94a4 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -201,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 6689b85..7101f8e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/nms/build.gradle b/nms/build.gradle index c3a23da..a5b7d5b 100644 --- a/nms/build.gradle +++ b/nms/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" apply false + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" apply false } group = "com.artillexstudios.axminions" @@ -10,4 +10,4 @@ subprojects { compileOnly project(":common") compileOnly project(":api") } -} \ No newline at end of file +} diff --git a/nms/v1_20_R4/build.gradle b/nms/v1_20_R4/build.gradle index d7431ba..bd0301e 100644 --- a/nms/v1_20_R4/build.gradle +++ b/nms/v1_20_R4/build.gradle @@ -6,7 +6,7 @@ group = 'com.artillexstudios.axminions.nms' version = '1.0-SNAPSHOT' dependencies { - paperweight.paperDevBundle("1.20.5-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT") } kotlin { diff --git a/nms/v1_21_R2/build.gradle b/nms/v1_21_R2/build.gradle new file mode 100644 index 0000000..4461d1a --- /dev/null +++ b/nms/v1_21_R2/build.gradle @@ -0,0 +1,24 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +group = 'com.artillexstudios.axminions.nms' +version = '1.0-SNAPSHOT' + +dependencies { + paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT") +} + +kotlin { + jvmToolchain(21) +} + +tasks { + build { + dependsOn(reobfJar) + } + + reobfJar { + mustRunAfter(shadowJar) + } +} diff --git a/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/DamageHandler.kt b/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/DamageHandler.kt new file mode 100644 index 0000000..87742d3 --- /dev/null +++ b/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/DamageHandler.kt @@ -0,0 +1,224 @@ +package com.artillexstudios.axminions.nms.v1_21_R2 + +import com.artillexstudios.axminions.api.events.PreMinionDamageEntityEvent +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.entity.EntityType +import net.minecraft.world.entity.EquipmentSlot +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.animal.Fox +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 org.bukkit.Bukkit +import org.bukkit.craftbukkit.CraftWorld +import org.bukkit.craftbukkit.entity.CraftEntity +import org.bukkit.craftbukkit.inventory.CraftItemStack +import org.bukkit.enchantments.Enchantment +import org.bukkit.entity.Entity +import org.bukkit.entity.Player +import net.minecraft.world.entity.EquipmentSlotGroup +import net.minecraft.world.entity.ai.attributes.Attributes +import net.minecraft.core.component.DataComponents +import net.minecraft.core.Holder +import net.minecraft.resources.ResourceKey +import net.minecraft.world.entity.ai.attributes.Attribute +import java.util.* + +object DamageHandler { + private var DUMMY_ENTITY = Fox(EntityType.FOX, (Bukkit.getWorlds().get(0) as CraftWorld).handle) + private var minion: Minion? = null + + fun getUUID(): UUID { + return DUMMY_ENTITY.uuid + } + + fun getMinion(): Minion? { + return minion + } + + fun damage(source: Minion, entity: Entity) { + val nmsEntity = (entity as CraftEntity).handle + + synchronized(DUMMY_ENTITY) { + this.minion = source + var f = 1 + + val nmsItem: ItemStack + if (source.getTool() == null) { + nmsItem = ItemStack.EMPTY + } else { + nmsItem = CraftItemStack.asNMSCopy(source.getTool()) + + nmsItem.get(DataComponents.ATTRIBUTE_MODIFIERS)?.forEach(EquipmentSlotGroup.MAINHAND) { h: Holder, m -> + if (h.unwrapKey().orElseThrow() == Attributes.ATTACK_DAMAGE.unwrapKey().orElseThrow()) { + f += m.amount().toInt() + } + } + } + + DUMMY_ENTITY.setItemSlot(EquipmentSlot.MAINHAND, nmsItem) + + if (!nmsEntity.isAttackable || entity is Player) return + val f2 = 1.0f + + val damageSource = nmsEntity.damageSources().noAggroMobAttack(DUMMY_ENTITY) + var f1 = EnchantmentHelper.modifyDamage( + nmsEntity.level() as ServerLevel, + nmsItem, + nmsEntity, + damageSource, + f.toFloat() + ) + + 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.igniteForSeconds(1f, false) + } + } + + val event = PreMinionDamageEntityEvent(source, entity as org.bukkit.entity.LivingEntity, f.toDouble()) + Bukkit.getPluginManager().callEvent(event) + if (event.isCancelled) { + return + } + + val flag5 = nmsEntity.hurtServer((source.getLocation().world as CraftWorld).handle as ServerLevel, damageSource, 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) 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)) + .filter { it !is Player } + 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 = PreMinionDamageEntityEvent( + 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.hurtServer((source.getLocation().world as CraftWorld).handle as ServerLevel, nmsEntity.damageSources().noAggroMobAttack(DUMMY_ENTITY), 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 + ) + } + } + + if (nmsEntity is LivingEntity) { + val f5: Float = f3 - nmsEntity.health + + if (j > 0) { + nmsEntity.igniteForSeconds(j * 4f, 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() + } + } + } + this.minion = null + } + } + + fun getSweepingDamageRatio(level: Int): Float { + return 1.0f - 1.0f / (level + 1).toFloat() + } +} diff --git a/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/LootHandler.kt b/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/LootHandler.kt new file mode 100644 index 0000000..20eb0b1 --- /dev/null +++ b/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/LootHandler.kt @@ -0,0 +1,39 @@ +package com.artillexstudios.axminions.nms.v1_21_R2 + +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.Location +import org.bukkit.craftbukkit.CraftWorld +import org.bukkit.craftbukkit.inventory.CraftItemStack +import org.bukkit.inventory.ItemStack + +object LootHandler { + + fun generateFishingLoot(minion: Minion, waterLocation: Location): 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(waterLocation.x, waterLocation.y, waterLocation.z) + ).withParameter(LootContextParams.TOOL, nmsItem).withOptionalParameter(LootContextParams.THIS_ENTITY, null) + .create(LootContextParamSets.FISHING) + + val lootTable = MinecraftServer.getServer().reloadableRegistries().getLootTable(BuiltInLootTables.FISHING); + + return lootTable.getRandomItems(lootparams).stream().map { original: net.minecraft.world.item.ItemStack? -> + CraftItemStack.asBukkitCopy( + original + ) + }.toList() + } +} diff --git a/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/NMSHandler.kt b/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/NMSHandler.kt new file mode 100644 index 0000000..6d8cc2d --- /dev/null +++ b/nms/v1_21_R2/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R2/NMSHandler.kt @@ -0,0 +1,49 @@ +package com.artillexstudios.axminions.nms.v1_21_R2 + +import com.artillexstudios.axminions.api.minions.Minion +import com.artillexstudios.axminions.nms.NMSHandler +import net.minecraft.world.entity.MobCategory +import org.bukkit.Location +import org.bukkit.block.Block +import org.bukkit.craftbukkit.block.CraftBlock +import org.bukkit.craftbukkit.block.CraftBlockState +import org.bukkit.craftbukkit.entity.CraftEntity +import org.bukkit.craftbukkit.inventory.CraftItemStack +import org.bukkit.craftbukkit.util.CraftLocation +import org.bukkit.entity.Entity +import org.bukkit.inventory.ItemStack +import java.util.* + +class NMSHandler : NMSHandler { + + override fun attack(source: Minion, target: Entity) { + DamageHandler.damage(source, target) + } + + override fun generateRandomFishingLoot(minion: Minion, waterLocation: Location): List { + return LootHandler.generateFishingLoot(minion, waterLocation) + } + + override fun isAnimal(entity: Entity): Boolean { + return (entity as CraftEntity).handle.type.category == MobCategory.CREATURE + } + + override fun getAnimalUUID(): UUID { + return DamageHandler.getUUID() + } + + override fun getMinion(): Minion? { + return DamageHandler.getMinion() + } + + override fun getExp(block: Block, itemStack: ItemStack): Int { + val craftBlock = block as CraftBlock + return craftBlock.nms.block.getExpDrop( + (block.state as CraftBlockState).handle, + craftBlock.handle.minecraftWorld, + CraftLocation.toBlockPosition(block.location), + CraftItemStack.asNMSCopy(itemStack), + true + ) + } +} diff --git a/nms/v1_21_R3/build.gradle b/nms/v1_21_R3/build.gradle new file mode 100644 index 0000000..331d738 --- /dev/null +++ b/nms/v1_21_R3/build.gradle @@ -0,0 +1,26 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +group = 'com.artillexstudios.axminions.nms' +version = '1.0-SNAPSHOT' + +dependencies { + paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT") +} + +kotlin { + jvmToolchain(21) +} + + +configurations.all { resolutionStrategy { { details -> if (details.getSelected() != details.getRequested()) { details.useVersion(details.getSelected().toString()) } } } } +tasks { + build { + dependsOn(reobfJar) + } + + reobfJar { + mustRunAfter(shadowJar) + } +} diff --git a/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/DamageHandler.kt b/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/DamageHandler.kt new file mode 100644 index 0000000..47f46d1 --- /dev/null +++ b/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/DamageHandler.kt @@ -0,0 +1,224 @@ +package com.artillexstudios.axminions.nms.v1_21_R3 + +import com.artillexstudios.axminions.api.events.PreMinionDamageEntityEvent +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.entity.EntityType +import net.minecraft.world.entity.EquipmentSlot +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.animal.Fox +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 org.bukkit.Bukkit +import org.bukkit.craftbukkit.CraftWorld +import org.bukkit.craftbukkit.entity.CraftEntity +import org.bukkit.craftbukkit.inventory.CraftItemStack +import org.bukkit.enchantments.Enchantment +import org.bukkit.entity.Entity +import org.bukkit.entity.Player +import net.minecraft.world.entity.EquipmentSlotGroup +import net.minecraft.world.entity.ai.attributes.Attributes +import net.minecraft.core.component.DataComponents +import net.minecraft.core.Holder +import net.minecraft.resources.ResourceKey +import net.minecraft.world.entity.ai.attributes.Attribute +import java.util.* + +object DamageHandler { + private var DUMMY_ENTITY = Fox(EntityType.FOX, (Bukkit.getWorlds().get(0) as CraftWorld).handle) + private var minion: Minion? = null + + fun getUUID(): UUID { + return DUMMY_ENTITY.uuid + } + + fun getMinion(): Minion? { + return minion + } + + fun damage(source: Minion, entity: Entity) { + val nmsEntity = (entity as CraftEntity).handle + + synchronized(DUMMY_ENTITY) { + this.minion = source + var f = 1 + + val nmsItem: ItemStack + if (source.getTool() == null) { + nmsItem = ItemStack.EMPTY + } else { + nmsItem = CraftItemStack.asNMSCopy(source.getTool()) + + nmsItem.get(DataComponents.ATTRIBUTE_MODIFIERS)?.forEach(EquipmentSlotGroup.MAINHAND) { h: Holder, m -> + if (h.unwrapKey().orElseThrow() == Attributes.ATTACK_DAMAGE.unwrapKey().orElseThrow()) { + f += m.amount().toInt() + } + } + } + + DUMMY_ENTITY.setItemSlot(EquipmentSlot.MAINHAND, nmsItem) + + if (!nmsEntity.isAttackable || entity is Player) return + val f2 = 1.0f + + val damageSource = nmsEntity.damageSources().noAggroMobAttack(DUMMY_ENTITY) + var f1 = EnchantmentHelper.modifyDamage( + nmsEntity.level() as ServerLevel, + nmsItem, + nmsEntity, + damageSource, + f.toFloat() + ) + + 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.igniteForSeconds(1f, false) + } + } + + val event = PreMinionDamageEntityEvent(source, entity as org.bukkit.entity.LivingEntity, f.toDouble()) + Bukkit.getPluginManager().callEvent(event) + if (event.isCancelled) { + return + } + + val flag5 = nmsEntity.hurtServer((source.getLocation().world as CraftWorld).handle as ServerLevel, damageSource, 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) 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)) + .filter { it !is Player } + 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 = PreMinionDamageEntityEvent( + 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.hurtServer((source.getLocation().world as CraftWorld).handle as ServerLevel, nmsEntity.damageSources().noAggroMobAttack(DUMMY_ENTITY), 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 + ) + } + } + + if (nmsEntity is LivingEntity) { + val f5: Float = f3 - nmsEntity.health + + if (j > 0) { + nmsEntity.igniteForSeconds(j * 4f, 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() + } + } + } + this.minion = null + } + } + + fun getSweepingDamageRatio(level: Int): Float { + return 1.0f - 1.0f / (level + 1).toFloat() + } +} diff --git a/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/LootHandler.kt b/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/LootHandler.kt new file mode 100644 index 0000000..452048a --- /dev/null +++ b/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/LootHandler.kt @@ -0,0 +1,39 @@ +package com.artillexstudios.axminions.nms.v1_21_R3 + +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.Location +import org.bukkit.craftbukkit.CraftWorld +import org.bukkit.craftbukkit.inventory.CraftItemStack +import org.bukkit.inventory.ItemStack + +object LootHandler { + + fun generateFishingLoot(minion: Minion, waterLocation: Location): 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(waterLocation.x, waterLocation.y, waterLocation.z) + ).withParameter(LootContextParams.TOOL, nmsItem).withOptionalParameter(LootContextParams.THIS_ENTITY, null) + .create(LootContextParamSets.FISHING) + + val lootTable = MinecraftServer.getServer().reloadableRegistries().getLootTable(BuiltInLootTables.FISHING); + + return lootTable.getRandomItems(lootparams).stream().map { original: net.minecraft.world.item.ItemStack? -> + CraftItemStack.asBukkitCopy( + original + ) + }.toList() + } +} diff --git a/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/NMSHandler.kt b/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/NMSHandler.kt new file mode 100644 index 0000000..3234b20 --- /dev/null +++ b/nms/v1_21_R3/src/main/kotlin/com/artillexstudios/axminions/nms/v1_21_R3/NMSHandler.kt @@ -0,0 +1,49 @@ +package com.artillexstudios.axminions.nms.v1_21_R3 + +import com.artillexstudios.axminions.api.minions.Minion +import com.artillexstudios.axminions.nms.NMSHandler +import net.minecraft.world.entity.MobCategory +import org.bukkit.Location +import org.bukkit.block.Block +import org.bukkit.craftbukkit.block.CraftBlock +import org.bukkit.craftbukkit.block.CraftBlockState +import org.bukkit.craftbukkit.entity.CraftEntity +import org.bukkit.craftbukkit.inventory.CraftItemStack +import org.bukkit.craftbukkit.util.CraftLocation +import org.bukkit.entity.Entity +import org.bukkit.inventory.ItemStack +import java.util.* + +class NMSHandler : NMSHandler { + + override fun attack(source: Minion, target: Entity) { + DamageHandler.damage(source, target) + } + + override fun generateRandomFishingLoot(minion: Minion, waterLocation: Location): List { + return LootHandler.generateFishingLoot(minion, waterLocation) + } + + override fun isAnimal(entity: Entity): Boolean { + return (entity as CraftEntity).handle.type.category == MobCategory.CREATURE + } + + override fun getAnimalUUID(): UUID { + return DamageHandler.getUUID() + } + + override fun getMinion(): Minion? { + return DamageHandler.getMinion() + } + + override fun getExp(block: Block, itemStack: ItemStack): Int { + val craftBlock = block as CraftBlock + return craftBlock.nms.block.getExpDrop( + (block.state as CraftBlockState).handle, + craftBlock.handle.minecraftWorld, + CraftLocation.toBlockPosition(block.location), + CraftItemStack.asNMSCopy(itemStack), + true + ) + } +} diff --git a/settings.gradle b/settings.gradle index fd48435..a46f9aa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -22,5 +22,7 @@ include 'nms:v1_20_R3' include 'nms:v1_20_R4' include 'nms:v1_21_R1' include 'nms:v1_18_R2' +include 'nms:v1_21_R2' +//include 'nms:v1_21_R3' findProject(':nms:v1_18_R2')?.name = 'v1_18_R2'