From 86ae8cb90165a0507528fa66f399875245141612 Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Sat, 6 Sep 2025 22:14:45 +0200 Subject: [PATCH] better windcharge counter --- .../org/rattatwinko/mace/BossBarManager.java | 2 +- .../rattatwinko/mace/MaceEventListener.java | 149 ++++++++---------- .../rattatwinko/mace/PlayerGlowManager.java | 147 +++++++++-------- 3 files changed, 155 insertions(+), 143 deletions(-) diff --git a/src/main/java/org/rattatwinko/mace/BossBarManager.java b/src/main/java/org/rattatwinko/mace/BossBarManager.java index 4453e7b..fbae43e 100644 --- a/src/main/java/org/rattatwinko/mace/BossBarManager.java +++ b/src/main/java/org/rattatwinko/mace/BossBarManager.java @@ -19,7 +19,7 @@ public class BossBarManager { private final Map playerBossBars = new HashMap<>(); private final Map activeTasks = new HashMap<>(); - public void startCooldown(Player player) { + public void startCooldown(Player player, int oneshotCooldown) { UUID playerId = player.getUniqueId(); // Remove existing boss bar and task if present diff --git a/src/main/java/org/rattatwinko/mace/MaceEventListener.java b/src/main/java/org/rattatwinko/mace/MaceEventListener.java index 332531d..3e14db9 100644 --- a/src/main/java/org/rattatwinko/mace/MaceEventListener.java +++ b/src/main/java/org/rattatwinko/mace/MaceEventListener.java @@ -1,9 +1,12 @@ // src/main/java/org.rattatwinko.mace/MaceEventListener.java // © rattatwinko 2025 + package org.rattatwinko.mace; +import net.kyori.adventure.text.Component; import org.bukkit.*; +import org.bukkit.boss.BossBar; import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -11,8 +14,10 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; +import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -20,11 +25,14 @@ public class MaceEventListener implements Listener { private final Mace plugin; private final Map oneshotCooldowns; + private final Map windChargeCooldowns = new HashMap<>(); private final BossBarManager bossBarManager; private final PlayerGlowManager glowManager; + private final int windCooldown = 3; // seconds + private final int oneshotCooldown = 60; // seconds public MaceEventListener(Mace plugin, Map oneshotCooldowns, - BossBarManager bossBarManager, PlayerGlowManager glowManager) { + BossBarManager bossBarManager, PlayerGlowManager glowManager) { this.plugin = plugin; this.oneshotCooldowns = oneshotCooldowns; this.bossBarManager = bossBarManager; @@ -33,47 +41,27 @@ public class MaceEventListener implements Listener { @EventHandler public void onEntityDamage(EntityDamageByEntityEvent event) { - if (!(event.getDamager() instanceof Player)) return; - - Player attacker = (Player) event.getDamager(); - ItemStack weapon = attacker.getInventory().getItemInMainHand(); + if (!(event.getDamager() instanceof Player player)) return; + ItemStack weapon = player.getInventory().getItemInMainHand(); if (!plugin.isMaceItem(weapon)) return; - // Play attack sound and particles - playAttackEffects(attacker); + playAttackEffects(player); - // Check for one-shot capability - UUID playerId = attacker.getUniqueId(); - long currentTime = System.currentTimeMillis(); + UUID playerId = player.getUniqueId(); + long now = System.currentTimeMillis(); if (oneshotCooldowns.containsKey(playerId)) { long lastUse = oneshotCooldowns.get(playerId); - long cooldownTime = 60000; // 1 minute in milliseconds - - if (currentTime - lastUse < cooldownTime) { - // Still on cooldown, deal normal damage - return; - } + if ((now - lastUse) < oneshotCooldown * 1000L) return; // still on cooldown } - // One-shot is available - if (event.getEntity() instanceof LivingEntity) { - LivingEntity target = (LivingEntity) event.getEntity(); + if (event.getEntity() instanceof LivingEntity target) { + event.setDamage(target.getMaxHealth() + 100); // one-shot kill + oneshotCooldowns.put(playerId, now); - // Set damage to target's max health to ensure one-shot - event.setDamage(target.getMaxHealth() + 100); - - // Update cooldown - oneshotCooldowns.put(playerId, currentTime); - - // Start boss bar cooldown display - bossBarManager.startCooldown(attacker); - - // Play one-shot effects - playOneshotEffects(attacker, target); - - attacker.sendMessage("§6§lONE-SHOT KILL! §7Cooldown started"); + bossBarManager.startCooldown(player, oneshotCooldown); // display bossbar cooldown + playOneshotEffects(player, target); } } @@ -83,16 +71,11 @@ public class MaceEventListener implements Listener { Player player = event.getPlayer(); ItemStack item = player.getInventory().getItemInMainHand(); - if (!plugin.isMaceItem(item)) return; event.setCancelled(true); - - // Create wind charge effect - createWindCharge(player); - - // Play wind charge effects - playWindChargeEffects(player); + // remove if does not work + attemptWindCharge(player); } @EventHandler @@ -101,86 +84,96 @@ public class MaceEventListener implements Listener { ItemStack newItem = player.getInventory().getItem(event.getNewSlot()); ItemStack oldItem = player.getInventory().getItem(event.getPreviousSlot()); - // Check if switching to mace if (plugin.isMaceItem(newItem)) { glowManager.addPlayer(player); playEquipEffects(player); } - // Check if switching away from mace if (plugin.isMaceItem(oldItem)) { glowManager.removePlayer(player); } } - private void createWindCharge(Player player) { - Location eyeLocation = player.getEyeLocation(); - Vector direction = eyeLocation.getDirection(); + private void attemptWindCharge(Player player) { + UUID playerId = player.getUniqueId(); + long now = System.currentTimeMillis(); + + // Strict cooldown check + Long lastUse = windChargeCooldowns.get(playerId); + if (lastUse != null && (now - lastUse) < windCooldown * 1000L) { + int remaining = (int) ((windCooldown * 1000L - (now - lastUse)) / 1000L); + player.sendActionBar(Component.text("§cWind Charge cooldown: " + remaining + "s")); + player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 0.5f, 1.2f); + return; // Block spawn completely + } + + // Immediately mark the cooldown to prevent spamming + windChargeCooldowns.put(playerId, now); + + // Launch Wind Charge + Location loc = player.getEyeLocation(); + Vector dir = loc.getDirection(); - // Spawn wind charge WindCharge windCharge = (WindCharge) player.getWorld().spawnEntity( - eyeLocation.add(direction.multiply(1.5)), EntityType.WIND_CHARGE + loc.add(dir.multiply(1.5)), EntityType.WIND_CHARGE ); - - windCharge.setVelocity(direction.multiply(2.0)); + windCharge.setVelocity(dir.multiply(2.0)); windCharge.setShooter(player); - // Add knockback to nearby entities - for (Entity entity : player.getNearbyEntities(5, 5, 5)) { - if (entity instanceof LivingEntity && !entity.equals(player)) { - Vector knockback = entity.getLocation().toVector() - .subtract(player.getLocation().toVector()) - .normalize() - .multiply(1.5) - .setY(0.8); + // Action bar cooldown display + new BukkitRunnable() { + int secondsLeft = windCooldown; - entity.setVelocity(knockback); + @Override + public void run() { + if (secondsLeft <= 0) { + windChargeCooldowns.remove(playerId); + cancel(); + return; + } + player.sendActionBar(Component.text("§aWind Charge cooldown: " + secondsLeft + "s")); + secondsLeft--; } - } + }.runTaskTimer(plugin, 0L, 20L); + + // Play Wind Charge effects + playWindChargeEffects(player); } + + private void playAttackEffects(Player player) { Location loc = player.getLocation(); World world = player.getWorld(); - // Lightning particle effect world.spawnParticle(Particle.ELECTRIC_SPARK, loc.add(0, 1, 0), 20, 0.5, 0.5, 0.5, 0.1); world.spawnParticle(Particle.CRIT, loc, 15, 0.3, 0.3, 0.3, 0.1); - // Sound effects world.playSound(loc, Sound.ENTITY_LIGHTNING_BOLT_THUNDER, 0.3f, 1.5f); world.playSound(loc, Sound.ENTITY_PLAYER_ATTACK_CRIT, 1.0f, 0.8f); } private void playOneshotEffects(Player attacker, LivingEntity target) { - Location attackerLoc = attacker.getLocation(); - Location targetLoc = target.getLocation(); + Location loc = target.getLocation(); World world = attacker.getWorld(); - // Massive particle explosion at target - world.spawnParticle(Particle.EXPLOSION, targetLoc.add(0, 1, 0), 5, 1, 1, 1, 0); - world.spawnParticle(Particle.ELECTRIC_SPARK, targetLoc, 50, 2, 2, 2, 0.3); - world.spawnParticle(Particle.ENCHANT, targetLoc, 30, 1.5, 1.5, 1.5, 0.1); + world.spawnParticle(Particle.EXPLOSION, loc.add(0, 1, 0), 5, 1, 1, 1, 0); + world.spawnParticle(Particle.ELECTRIC_SPARK, loc, 50, 2, 2, 2, 0.3); + world.spawnParticle(Particle.ENCHANT, loc, 30, 1.5, 1.5, 1.5, 0.1); - // Lightning strike effect (visual only) - world.spawnParticle(Particle.ELECTRIC_SPARK, targetLoc.add(0, 10, 0), 100, 0, 10, 0, 0.1); - - // Epic sound effects - world.playSound(attackerLoc, Sound.ENTITY_LIGHTNING_BOLT_THUNDER, 1.0f, 1.0f); - world.playSound(targetLoc, Sound.ENTITY_GENERIC_EXPLODE, 1.0f, 0.5f); - world.playSound(targetLoc, Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 2.0f); + world.playSound(attacker.getLocation(), Sound.ENTITY_LIGHTNING_BOLT_THUNDER, 1.0f, 1.0f); + world.playSound(loc, Sound.ENTITY_GENERIC_EXPLODE, 1.0f, 0.5f); + world.playSound(loc, Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 2.0f); } private void playWindChargeEffects(Player player) { Location loc = player.getLocation(); World world = player.getWorld(); - // Wind particles world.spawnParticle(Particle.CLOUD, loc.add(0, 1, 0), 20, 1, 1, 1, 0.1); world.spawnParticle(Particle.SWEEP_ATTACK, loc, 3, 0.5, 0.5, 0.5, 0); - // Wind sound - world.playSound(loc, Sound.ENTITY_BREEZE_SHOOT, 1.0f, 1.2f); + world.playSound(loc, Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1f, 1.2f); world.playSound(loc, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 0.8f, 1.5f); } @@ -188,12 +181,10 @@ public class MaceEventListener implements Listener { Location loc = player.getLocation(); World world = player.getWorld(); - // Enchantment particles world.spawnParticle(Particle.ENCHANT, loc.add(0, 1, 0), 30, 0.5, 1, 0.5, 0.1); world.spawnParticle(Particle.ELECTRIC_SPARK, loc, 10, 0.3, 0.5, 0.3, 0.05); - // Epic equip sound world.playSound(loc, Sound.BLOCK_ANVIL_PLACE, 0.5f, 1.5f); world.playSound(loc, Sound.ENTITY_PLAYER_LEVELUP, 0.3f, 2.0f); } -} \ No newline at end of file +} diff --git a/src/main/java/org/rattatwinko/mace/PlayerGlowManager.java b/src/main/java/org/rattatwinko/mace/PlayerGlowManager.java index 8df6168..bc1718e 100644 --- a/src/main/java/org/rattatwinko/mace/PlayerGlowManager.java +++ b/src/main/java/org/rattatwinko/mace/PlayerGlowManager.java @@ -6,14 +6,14 @@ package org.rattatwinko.mace; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Team; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.UUID; @@ -21,40 +21,67 @@ public class PlayerGlowManager { private final Mace plugin; private final Set activePlayers = new HashSet<>(); + private final Map playerScoreboards = new HashMap<>(); + private final Map playerGlowTeams = new HashMap<>(); + private final Map> glowingTargets = new HashMap<>(); private BukkitTask glowTask; - private Scoreboard scoreboard; - private Team glowTeam; public PlayerGlowManager(Mace plugin) { this.plugin = plugin; - setupScoreboard(); } - private void setupScoreboard() { - scoreboard = Bukkit.getScoreboardManager().getMainScoreboard(); - - // Try to get existing team or create new one - glowTeam = scoreboard.getTeam("mace_glow"); - if (glowTeam == null) { - glowTeam = scoreboard.registerNewTeam("mace_glow"); - } + private void setupPlayerScoreboard(Player player) { + // Create a unique scoreboard for this player + Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + // Create a unique team for this player's glow effects + Team glowTeam = scoreboard.registerNewTeam("mace_glow_" + player.getName()); glowTeam.setColor(ChatColor.RED); glowTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER); + + // Set the custom scoreboard for this player + player.setScoreboard(scoreboard); + + // Store references + playerScoreboards.put(player.getUniqueId(), scoreboard); + playerGlowTeams.put(player.getUniqueId(), glowTeam); + glowingTargets.put(player.getUniqueId(), new HashSet<>()); } public void addPlayer(Player player) { activePlayers.add(player.getUniqueId()); + setupPlayerScoreboard(player); } public void removePlayer(Player player) { - activePlayers.remove(player.getUniqueId()); + UUID playerId = player.getUniqueId(); + activePlayers.remove(playerId); - // Remove glow effect from all players for this viewer - for (Player target : Bukkit.getOnlinePlayers()) { - if (!target.equals(player)) { - removeGlowEffect(target, player); + // Clean up this player's custom scoreboard and reset to main + cleanupPlayerScoreboard(player); + + // Reset player to main scoreboard + player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard()); + + // Remove stored data + playerScoreboards.remove(playerId); + playerGlowTeams.remove(playerId); + glowingTargets.remove(playerId); + } + + private void cleanupPlayerScoreboard(Player player) { + UUID playerId = player.getUniqueId(); + Team glowTeam = playerGlowTeams.get(playerId); + Set targets = glowingTargets.get(playerId); + + if (glowTeam != null && targets != null) { + // Remove all entries from the team + for (String targetName : targets) { + if (glowTeam.hasEntry(targetName)) { + glowTeam.removeEntry(targetName); + } } + targets.clear(); } } @@ -66,6 +93,10 @@ public class PlayerGlowManager { Player player = Bukkit.getPlayer(playerId); if (player == null || !player.isOnline()) { activePlayers.remove(playerId); + // Clean up stored data for offline player + playerScoreboards.remove(playerId); + playerGlowTeams.remove(playerId); + glowingTargets.remove(playerId); continue; } @@ -82,7 +113,15 @@ public class PlayerGlowManager { } private void updateGlowEffects(Player maceHolder) { - Set nearbyPlayers = new HashSet<>(); + UUID holderId = maceHolder.getUniqueId(); + Team glowTeam = playerGlowTeams.get(holderId); + Set currentTargets = glowingTargets.get(holderId); + + if (glowTeam == null || currentTargets == null) { + return; + } + + Set nearbyPlayerNames = new HashSet<>(); // Find players within 20 block radius for (Player target : Bukkit.getOnlinePlayers()) { @@ -91,49 +130,27 @@ public class PlayerGlowManager { double distance = target.getLocation().distance(maceHolder.getLocation()); if (distance <= 20.0) { - nearbyPlayers.add(target); - applyGlowEffect(target, maceHolder); - } else { - removeGlowEffect(target, maceHolder); - } - } - } - - private void applyGlowEffect(Player target, Player viewer) { - // Add target to glow team (makes them glow for everyone) - if (!glowTeam.hasEntry(target.getName())) { - glowTeam.addEntry(target.getName()); - } - - // Apply glowing potion effect specifically for the viewer - target.addPotionEffect(new PotionEffect( - PotionEffectType.GLOWING, - 25, // 1.25 seconds (will be refreshed) - 0, - false, - false, - false - )); - } - - private void removeGlowEffect(Player target, Player viewer) { - // Only remove from team if no other mace holders are near - boolean shouldKeepGlow = false; - for (UUID otherId : activePlayers) { - Player other = Bukkit.getPlayer(otherId); - if (other != null && !other.equals(viewer) && other.isOnline()) { - if (other.getWorld().equals(target.getWorld()) && - other.getLocation().distance(target.getLocation()) <= 20.0) { - shouldKeepGlow = true; - break; - } + nearbyPlayerNames.add(target.getName()); } } - if (!shouldKeepGlow && glowTeam.hasEntry(target.getName())) { - glowTeam.removeEntry(target.getName()); - target.removePotionEffect(PotionEffectType.GLOWING); + // Add new targets to glow team + for (String targetName : nearbyPlayerNames) { + if (!currentTargets.contains(targetName)) { + glowTeam.addEntry(targetName); + currentTargets.add(targetName); + } } + + // Remove targets that are no longer nearby + Set toRemove = new HashSet<>(); + for (String targetName : currentTargets) { + if (!nearbyPlayerNames.contains(targetName)) { + glowTeam.removeEntry(targetName); + toRemove.add(targetName); + } + } + currentTargets.removeAll(toRemove); } public void cleanup() { @@ -141,14 +158,18 @@ public class PlayerGlowManager { glowTask.cancel(); } - // Remove glow effects from all players - for (Player player : Bukkit.getOnlinePlayers()) { - if (glowTeam.hasEntry(player.getName())) { - glowTeam.removeEntry(player.getName()); - player.removePotionEffect(PotionEffectType.GLOWING); + // Clean up all player scoreboards and reset to main + for (UUID playerId : new HashSet<>(activePlayers)) { + Player player = Bukkit.getPlayer(playerId); + if (player != null && player.isOnline()) { + cleanupPlayerScoreboard(player); + player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard()); } } activePlayers.clear(); + playerScoreboards.clear(); + playerGlowTeams.clear(); + glowingTargets.clear(); } } \ No newline at end of file