From 15a243e93587c509ec4c955c148e54081524de4b Mon Sep 17 00:00:00 2001 From: JasperLorelai Date: Sun, 21 Jun 2026 23:35:48 +0200 Subject: [PATCH] fix: Charges shouldn't set true cooldown This reverts changes from d8c0381, as they have introduced a bug where once all charges are depleted, you have to wait for the full recharge duration instead of the short time until the next recharge. Combined with the fix this addresses the original issue of "-1" cooldown - "Spell#getCooldown" will now return the time of the next available recharge. --- .../java/com/nisovin/magicspells/Spell.java | 69 ++++++++++++++----- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/com/nisovin/magicspells/Spell.java b/core/src/main/java/com/nisovin/magicspells/Spell.java index f7db15374..5f831d565 100644 --- a/core/src/main/java/com/nisovin/magicspells/Spell.java +++ b/core/src/main/java/com/nisovin/magicspells/Spell.java @@ -88,7 +88,7 @@ public abstract class Spell implements Comparable, Listener { protected Multimap variableModsCasted; protected Multimap variableModsTarget; - protected IntMap chargesConsumed; + protected Map chargeStates; protected ListMultimap effects; @@ -375,7 +375,7 @@ public Spell(MagicConfig config, String spellName) { charges = config.getInt(internalKey + "charges", 0); rechargeSound = config.getString(internalKey + "recharge-sound", ""); nextCast = new HashMap<>(); - chargesConsumed = new IntMap<>(); + chargeStates = new HashMap<>(); nextCastServer = 0; // Modifiers @@ -1327,6 +1327,10 @@ public ConfigData getCooldown() { */ public boolean onCooldown(LivingEntity livingEntity) { if (Perm.NO_COOLDOWN.has(livingEntity)) return false; + + ChargeState state = chargeStates.get(livingEntity.getUniqueId()); + if (state != null && state.isDepleted()) return true; + if (serverCooldown > 0 && nextCastServer > System.currentTimeMillis()) return true; Long next = nextCast.get(livingEntity.getUniqueId()); @@ -1340,6 +1344,9 @@ public boolean onCooldown(LivingEntity livingEntity) { * @return The number of seconds remaining in the cooldown */ public float getCooldown(LivingEntity livingEntity) { + ChargeState state = chargeStates.get(livingEntity.getUniqueId()); + if (state != null && state.isDepleted()) return state.nextRechargeSeconds(); + float cd = 0; Long next = nextCast.get(livingEntity.getUniqueId()); @@ -1400,23 +1407,13 @@ public void setCooldown(LivingEntity livingEntity, float cooldown, SpellData dat if (cooldown > 0) { if (charges > 0) { - chargesConsumed.increment(uuid); - MagicSpells.scheduleDelayedTask(() -> { - chargesConsumed.decrement(uuid); - playSpellEffects(EffectPosition.CHARGE_USE, livingEntity, new SpellData(livingEntity)); - if (rechargeSound == null) return; - if (rechargeSound.isEmpty()) return; - if (livingEntity instanceof Player player) - player.playSound(livingEntity.getLocation(), rechargeSound, 1.0F, 1.0F); - }, Math.round(TimeUtil.TICKS_PER_SECOND * cooldown)); + ChargeState state = chargeStates.computeIfAbsent(uuid, _ -> new ChargeState()); + state.consume(livingEntity, cooldown); } - if (charges <= 0 || chargesConsumed.get(uuid) >= charges) { - nextCast.put(uuid, System.currentTimeMillis() + (long) (cooldown * TimeUtil.MILLISECONDS_PER_SECOND)); - } - + else nextCast.put(uuid, System.currentTimeMillis() + (long) (cooldown * TimeUtil.MILLISECONDS_PER_SECOND)); } else { nextCast.remove(uuid); - chargesConsumed.remove(uuid); + chargeStates.remove(uuid); } if (serverCooldown > 0) @@ -1507,7 +1504,8 @@ public int getCharges() { * @return The number of charges consumed */ public int getCharges(LivingEntity livingEntity) { - return chargesConsumed.get(livingEntity.getUniqueId()); + ChargeState state = chargeStates.get(livingEntity.getUniqueId()); + return state == null ? 0 : state.consumed(); } /** @@ -2930,6 +2928,43 @@ private void end() { } + protected class ChargeState { + + private final PriorityQueue rechargeTimes = new PriorityQueue<>(); + + private void consume(LivingEntity entity, double rechargeDelay) { + if (isDepleted()) return; + + long rechargeTime = System.currentTimeMillis() + (long) (rechargeDelay * TimeUtil.MILLISECONDS_PER_SECOND); + rechargeTimes.add(rechargeTime); + + MagicSpells.scheduleDelayedTask(() -> { + if (!rechargeTimes.remove(rechargeTime)) return; + + playSpellEffects(EffectPosition.CHARGE_USE, entity, new SpellData(entity)); + + if (rechargeSound.isEmpty() || !(entity instanceof Player player)) return; + player.playSound(entity, rechargeSound, 1, 1); + }, Math.round(TimeUtil.TICKS_PER_SECOND * rechargeDelay)); + } + + private boolean isDepleted() { + return rechargeTimes.size() >= charges; + } + + private int consumed() { + return rechargeTimes.size(); + } + + private float nextRechargeSeconds() { + Long next = rechargeTimes.peek(); + if (next == null) return 0; + + return Math.max(0, (next - System.currentTimeMillis()) / ((float) TimeUtil.MILLISECONDS_PER_SECOND)); + } + + } + protected record SharedCooldown(Collection spells, ConfigData cooldown) { }