diff --git a/pom.xml b/pom.xml index 4e17394ce..a90f5c38f 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ UTF-8 chancesd https://sonarcloud.io - 4.0.9 + 4.0.10 diff --git a/pvpmanager/build.gradle b/pvpmanager/build.gradle index 3ae76f063..55b5c33f3 100644 --- a/pvpmanager/build.gradle +++ b/pvpmanager/build.gradle @@ -6,7 +6,7 @@ plugins { } group = 'me.chancesd.pvpmanager' -version = '4.0.3' +version = '4.0.10' description = 'A powerful plugin to manage various PvP combat features' dependencies { diff --git a/pvpmanager/src/main/java/me/chancesd/pvpmanager/command/Newbie.java b/pvpmanager/src/main/java/me/chancesd/pvpmanager/command/Newbie.java index b9b819c0a..d185cb890 100644 --- a/pvpmanager/src/main/java/me/chancesd/pvpmanager/command/Newbie.java +++ b/pvpmanager/src/main/java/me/chancesd/pvpmanager/command/Newbie.java @@ -126,6 +126,12 @@ public AddNewbieCommand(final PlayerManager ph) { public void execute(final CommandSender sender, final String label, final List args) { final Player targetPlayer = getArgument(args, ARG_PLAYER).getAsPlayer(); final CombatPlayer target = ph.get(targetPlayer); + // FIX: Prevent orphaned NewbieTask accumulation — skip if already protected. + if (target.isNewbie()) { + sender.sendMessage(ChatUtils.colorize( + Lang.PREFIX + " &#FFFF55" + target.getName() + " &#FFAAAAalready has newbie protection")); + return; + } target.setNewbie(true); sender.sendMessage(ChatUtils.colorize(Lang.PREFIX + " Added newbie protection to &#FFFF55" + target.getName())); } diff --git a/pvpmanager/src/main/java/me/chancesd/pvpmanager/player/CombatPlayer.java b/pvpmanager/src/main/java/me/chancesd/pvpmanager/player/CombatPlayer.java index 3794ffe6f..9a076c5dc 100644 --- a/pvpmanager/src/main/java/me/chancesd/pvpmanager/player/CombatPlayer.java +++ b/pvpmanager/src/main/java/me/chancesd/pvpmanager/player/CombatPlayer.java @@ -130,6 +130,14 @@ public final void setNewbie(final boolean newbie) { public final void setNewbie(final boolean newbie, final long time) { if (newbie) { + // FIX: Cancel existing newbieTask before overwriting the reference. + // Without this, the old task stays in the ScheduledThreadPoolExecutor queue + // (potentially for hours) while holding a strong CombatPlayer -> CraftPlayer + // reference, causing each orphaned task to retain ~4.85 GB of heap in aggregate. + // Triggered by repeated /newbie add on a player already under protection. + if (newbieTask != null) { + newbieTask.cancel(); + } this.newbieTask = new NewbieTask(this, time); } else if (this.newbie && newbieTask != null) { newbieTask.cancel(); @@ -480,6 +488,8 @@ public PlayerData exportPlayerData() { public final void cleanForRemoval() { if (newbieTask != null) { newbieTask.cancel(); + // FIX: Null out after cancel so the reference is released immediately. + newbieTask = null; } if (nametag != null) { nametag.cleanup();