commit ed944e0d764e5fe5d44df3080e6e874287140925 Author: rattatwinko Date: Thu May 1 14:48:50 2025 +0200 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4788b4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +target/ + +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next + +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# Common working directory +run/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..40118ee --- /dev/null +++ b/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + org.AutoBow + AutoBow + 1.0-SNAPSHOT + jar + + AutoBow + + + 21 + 2.2.0-Beta2 + UTF-8 + + + + clean package + ${project.basedir}/src/main/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.3 + + + package + + shade + + + + + + + + src/main/resources + true + + + + + + + papermc-repo + https://repo.papermc.io/repository/maven-public/ + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + + + + io.papermc.paper + paper-api + 1.21.5-R0.1-SNAPSHOT + provided + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + diff --git a/src/main/kotlin/org/AutoBow/autoBow/AutoBow.kt b/src/main/kotlin/org/AutoBow/autoBow/AutoBow.kt new file mode 100644 index 0000000..d9a6c27 --- /dev/null +++ b/src/main/kotlin/org/AutoBow/autoBow/AutoBow.kt @@ -0,0 +1,220 @@ +package org.AutoBow.autoBow + +import org.bukkit.Bukkit +import org.bukkit.ChatColor +import org.bukkit.Material +import org.bukkit.NamespacedKey +import org.bukkit.Registry +import org.bukkit.Sound +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender +import org.bukkit.entity.Arrow +import org.bukkit.entity.Entity +import org.bukkit.entity.Player +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.entity.EntityShootBowEvent +import org.bukkit.event.entity.ProjectileHitEvent +import org.bukkit.inventory.ItemFlag +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.ItemMeta +import org.bukkit.plugin.java.JavaPlugin +import org.bukkit.scheduler.BukkitRunnable +import org.bukkit.util.Vector +import java.util.* + +class AutoBow : JavaPlugin(), Listener { + + companion object { + private const val POWER_LEVEL = 10 + private const val AUTO_AIM_DISTANCE = 100.0 // Maximum distance for auto-aim + private const val KNOCKBACK_MULTIPLIER = 5.0 + } + + override fun onEnable() { + logger.info("AutoBow plugin has been enabled!") + server.pluginManager.registerEvents(this, this) + getCommand("autobow")?.setExecutor(AutoBowCommand()) + + // Register for arrow hit events to handle knockback + server.pluginManager.registerEvents(object : Listener { + @EventHandler + fun onProjectileHit(event: ProjectileHitEvent) { + val arrow = event.entity + if (arrow is Arrow && arrow.scoreboardTags.contains("autobow-knockback")) { + // Apply knockback if our arrow hit an entity + val hitEntity = event.hitEntity + if (hitEntity is Player) { + // Play XP sound on hit + arrow.world.playSound(arrow.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 0.5f) + + // Apply custom knockback + val direction = arrow.velocity.normalize().multiply(KNOCKBACK_MULTIPLIER) + hitEntity.velocity = hitEntity.velocity.add(direction) + + // Additional effects + hitEntity.world.playSound(hitEntity.location, Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, 1.0f, 0.5f) + } + } + } + }, this) + } + + override fun onDisable() { + logger.info("AutoBow plugin has been disabled!") + } + + private inner class AutoBowCommand : CommandExecutor { + override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { + if (sender !is Player) { + sender.sendMessage("${ChatColor.RED}This command can only be used by players!") + return true + } + + val player = sender + + // Check if player is op + if (!player.isOp) { + player.sendMessage("${ChatColor.RED}You don't have permission to use this command!") + return true + } + + // Create the auto bow + val autoBow = createAutoBow() + + // Give the player the bow + player.inventory.addItem(autoBow) + player.sendMessage("${ChatColor.GREEN}You have received the ${ChatColor.GOLD}Auto Bow${ChatColor.GREEN}! It will auto-aim at the nearest player.") + + // Also give arrows if player doesn't have any + if (!player.inventory.contains(Material.ARROW)) { + player.inventory.addItem(ItemStack(Material.ARROW, 64)) + player.sendMessage("${ChatColor.GREEN}You have received some arrows!") + } + + return true + } + } + + private fun createAutoBow(): ItemStack { + val bow = ItemStack(Material.BOW) + val meta = bow.itemMeta ?: return bow + + // Set display name and lore + meta.setDisplayName("${ChatColor.GOLD}${ChatColor.BOLD}Auto-Aim Bow") + + val lore = ArrayList() + lore.add("${ChatColor.GRAY}This bow automatically aims at the nearest player.") + lore.add("${ChatColor.RED}Extreme Knockback") + lore.add("${ChatColor.RED}Power") + lore.add("${ChatColor.DARK_PURPLE}OP Only Weapon") + meta.lore = lore + + // Add generic enchantment level appearance + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS) + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES) + + // Set the item to be unbreakable + meta.isUnbreakable = true + + bow.itemMeta = meta + + // Enchant the bow - FIXED LINES (122-124) + val powerEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("power")) + val infinityEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("infinity")) + val unbreakingEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("unbreaking")) + val knockbackEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("knockback")) + + if (powerEnchant != null) bow.addUnsafeEnchantment(powerEnchant, POWER_LEVEL) + if (infinityEnchant != null) bow.addUnsafeEnchantment(infinityEnchant, 1) + if (unbreakingEnchant != null) bow.addUnsafeEnchantment(unbreakingEnchant, 10) + if (knockbackEnchant != null) bow.addUnsafeEnchantment(knockbackEnchant, 10) + + return bow + } + + @EventHandler + fun onBowShoot(event: EntityShootBowEvent) { + if (event.entity !is Player) { + return + } + + val shooter = event.entity as Player + val bow = event.bow ?: return + + // Check if it's our special bow + if (bow.hasItemMeta() && bow.itemMeta?.hasDisplayName() == true && + bow.itemMeta?.displayName == "${ChatColor.GOLD}${ChatColor.BOLD}Auto-Aim Bow") { + + // Cancel the original arrow + event.isCancelled = true + + // Find the nearest player + val nearestPlayer = Bukkit.getOnlinePlayers() + .filter { it != shooter } + .minByOrNull { it.location.distanceSquared(shooter.location) } + + if (nearestPlayer != null) { + val distance = shooter.location.distance(nearestPlayer.location) + + // Only auto-aim if within range + if (distance <= AUTO_AIM_DISTANCE) { + // Calculate the vector from the shooter to the target, accounting for movement and gravity + val direction = calculateInterceptVector(shooter, nearestPlayer) + + // Spawn a new arrow with the calculated direction + val arrow = shooter.launchProjectile(Arrow::class.java, direction) + arrow.velocity = direction.multiply(2.0) // Increase arrow speed + arrow.isCritical = true + arrow.fireTicks = 100 // Set arrow on fire for visual effect + + // Tag our arrow for custom knockback + arrow.addScoreboardTag("autobow-knockback") + + // Set shooter as the arrow's shooter for proper damage attribution + arrow.shooter = shooter + + // Play sound for feedback + shooter.playSound(shooter.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f) + + shooter.sendMessage("${ChatColor.GREEN}Auto-aiming at ${ChatColor.RED}${nearestPlayer.name}${ChatColor.GREEN} (${Math.round(distance)} blocks away)") + } else { + shooter.sendMessage("${ChatColor.RED}No players within range for auto-aim!") + + // Fire a normal arrow if no valid targets + val arrow = shooter.launchProjectile(Arrow::class.java) + arrow.velocity = shooter.location.direction.multiply(2.0) + arrow.isCritical = true + arrow.addScoreboardTag("autobow-knockback") + } + } else { + shooter.sendMessage("${ChatColor.RED}No players to auto-aim at!") + + // Fire a normal arrow if no valid targets + val arrow = shooter.launchProjectile(Arrow::class.java) + arrow.velocity = shooter.location.direction.multiply(2.0) + arrow.isCritical = true + arrow.addScoreboardTag("autobow-knockback") + } + } + } + + private fun calculateInterceptVector(shooter: Player, target: Player): Vector { + // Get positions + val shooterPos = shooter.location.toVector() + val targetPos = target.location.toVector().add(Vector(0, 1, 0)) // Aim for center mass + + // Get target velocity + val targetVel = target.velocity + + // Calculate direction vector + val direction = targetPos.subtract(shooterPos) + + // Add a small prediction based on target movement + direction.add(targetVel.multiply(5)) + + // Normalize and scale + return direction.normalize() + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..1f50d17 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,15 @@ +name: AutoBow +version: 1.0-SNAPSHOT +main: org.AutoBow.autoBow.AutoBow +api-version: 1.18 +description: Gives OP players an auto-aiming bow with knockback +commands: + autobow: + description: Gives you an auto-aiming bow with extreme knockback + usage: /autobow + permission: autobow.use + permission-message: You must be an operator to use this command! +permissions: + autobow.use: + description: Allows use of the AutoBow command + default: op \ No newline at end of file