diff --git a/Spigot-Server-Patches/0548-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch b/Spigot-Server-Patches/0548-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch new file mode 100644 index 000000000..c8e5157a3 --- /dev/null +++ b/Spigot-Server-Patches/0548-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 13 Jul 2020 06:22:54 -0700 +Subject: [PATCH] Fix AdvancementDataPlayer leak due from quitting early in + login + +Move the criterion storage to the AdvancementDataPlayer object +itself, so the criterion object stores no references - and thus +needs no cleanup. + +diff --git a/src/main/java/net/minecraft/server/AdvancementDataPlayer.java b/src/main/java/net/minecraft/server/AdvancementDataPlayer.java +index d3387a4e16f81b820d40502d2c46ebb3db88f824..17789407b9e86896a963a305a13357286aa5f319 100644 +--- a/src/main/java/net/minecraft/server/AdvancementDataPlayer.java ++++ b/src/main/java/net/minecraft/server/AdvancementDataPlayer.java +@@ -51,6 +51,10 @@ public class AdvancementDataPlayer { + private Advancement l; + private boolean m = true; + ++ // Paper start - fix advancement data player leakage ++ final Map> criterionData = Maps.newIdentityHashMap(); ++ // Paper end - fix advancement data player leakage ++ + public AdvancementDataPlayer(DataFixer datafixer, PlayerList playerlist, AdvancementDataWorld advancementdataworld, File file, EntityPlayer entityplayer) { + this.d = datafixer; + this.e = playerlist; +diff --git a/src/main/java/net/minecraft/server/CriterionTriggerAbstract.java b/src/main/java/net/minecraft/server/CriterionTriggerAbstract.java +index 2419c57f90f40516cb4b4cedcda2c7d58523c3bc..d69ff9ca7a842cea715129f7f38972bed691a625 100644 +--- a/src/main/java/net/minecraft/server/CriterionTriggerAbstract.java ++++ b/src/main/java/net/minecraft/server/CriterionTriggerAbstract.java +@@ -12,25 +12,25 @@ import java.util.function.Predicate; + + public abstract class CriterionTriggerAbstract implements CriterionTrigger { + +- private final Map>> a = Maps.newIdentityHashMap(); ++ //private final Map>> a = Maps.newIdentityHashMap(); // Paper - moved into AdvancementDataPlayer to fix memory leak + + public CriterionTriggerAbstract() {} + + @Override + public final void a(AdvancementDataPlayer advancementdataplayer, CriterionTrigger.a criteriontrigger_a) { +- ((Set) this.a.computeIfAbsent(advancementdataplayer, (advancementdataplayer1) -> { ++ (advancementdataplayer.criterionData.computeIfAbsent(this, (advancementdataplayer1) -> { // Paper - fix AdvancementDataPlayer leak + return Sets.newHashSet(); + })).add(criteriontrigger_a); + } + + @Override + public final void b(AdvancementDataPlayer advancementdataplayer, CriterionTrigger.a criteriontrigger_a) { +- Set> set = (Set) this.a.get(advancementdataplayer); ++ Set> set = (Set) advancementdataplayer.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak + + if (set != null) { + set.remove(criteriontrigger_a); + if (set.isEmpty()) { +- this.a.remove(advancementdataplayer); ++ advancementdataplayer.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak + } + } + +@@ -38,7 +38,7 @@ public abstract class CriterionTriggerAbstract predicate) { + AdvancementDataPlayer advancementdataplayer = entityplayer.getAdvancementData(); +- Set> set = (Set) this.a.get(advancementdataplayer); ++ Set> set = (Set) advancementdataplayer.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak + + if (set != null && !set.isEmpty()) { + LootTableInfo loottableinfo = CriterionConditionEntity.b(entityplayer, entityplayer);