--- a/net/minecraft/server/PlayerAdvancements.java
+++ b/net/minecraft/server/PlayerAdvancements.java
@@ -19,14 +19,14 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.StringReader;
-import java.io.Writer;
 import java.nio.charset.StandardCharsets;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -50,6 +50,7 @@
 import org.slf4j.Logger;
 
 public class PlayerAdvancements {
+
     private static final Logger LOGGER = LogUtils.getLogger();
     private static final int VISIBILITY_DEPTH = 2;
     private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(AdvancementProgress.class, new AdvancementProgress.Serializer()).registerTypeAdapter(ResourceLocation.class, new ResourceLocation.Serializer()).setPrettyPrinting().create();
@@ -67,6 +68,8 @@
     private Advancement lastSelectedTab;
     private boolean isFirstPacket = true;
 
+    public final Map<net.minecraft.advancements.critereon.SimpleCriterionTrigger, Set<CriterionTrigger.Listener>> criterionData = Maps.newIdentityHashMap(); // Paper - fix advancement data player leakage
+
     public PlayerAdvancements(DataFixer dataFixer, PlayerList playerManager, ServerAdvancementManager advancementLoader, File advancementFile, ServerPlayer owner) {
         this.dataFixer = dataFixer;
         this.playerList = playerManager;
@@ -80,8 +83,12 @@
     }
 
     public void stopListening() {
-        for(CriterionTrigger<?> criterionTrigger : CriteriaTriggers.all()) {
-            criterionTrigger.removePlayerListeners(this);
+        Iterator iterator = CriteriaTriggers.all().iterator();
+
+        while (iterator.hasNext()) {
+            CriterionTrigger<?> criteriontrigger = (CriterionTrigger) iterator.next();
+
+            criteriontrigger.removePlayerListeners(this);
         }
 
     }
@@ -98,7 +105,11 @@
     }
 
     private void registerListeners(ServerAdvancementManager advancementLoader) {
-        for(Advancement advancement : advancementLoader.getAllAdvancements()) {
+        Iterator iterator = advancementLoader.getAllAdvancements().iterator();
+
+        while (iterator.hasNext()) {
+            Advancement advancement = (Advancement) iterator.next();
+
             this.registerListeners(advancement);
         }
 
@@ -106,22 +117,33 @@
 
     private void ensureAllVisible() {
         List<Advancement> list = Lists.newArrayList();
+        Iterator iterator = this.advancements.entrySet().iterator();
 
-        for(Map.Entry<Advancement, AdvancementProgress> entry : this.advancements.entrySet()) {
-            if (entry.getValue().isDone()) {
-                list.add(entry.getKey());
-                this.progressChanged.add(entry.getKey());
+        while (iterator.hasNext()) {
+            Entry<Advancement, AdvancementProgress> entry = (Entry) iterator.next();
+
+            if (((AdvancementProgress) entry.getValue()).isDone()) {
+                list.add((Advancement) entry.getKey());
+                this.progressChanged.add((Advancement) entry.getKey());
             }
         }
 
-        for(Advancement advancement : list) {
+        iterator = list.iterator();
+
+        while (iterator.hasNext()) {
+            Advancement advancement = (Advancement) iterator.next();
+
             this.ensureVisibility(advancement);
         }
 
     }
 
     private void checkForAutomaticTriggers(ServerAdvancementManager advancementLoader) {
-        for(Advancement advancement : advancementLoader.getAllAdvancements()) {
+        Iterator iterator = advancementLoader.getAllAdvancements().iterator();
+
+        while (iterator.hasNext()) {
+            Advancement advancement = (Advancement) iterator.next();
+
             if (advancement.getCriteria().isEmpty()) {
                 this.award(advancement, "");
                 advancement.getRewards().grant(this.player);
@@ -133,47 +155,56 @@
     private void load(ServerAdvancementManager advancementLoader) {
         if (this.file.isFile()) {
             try {
-                JsonReader jsonReader = new JsonReader(new StringReader(Files.toString(this.file, StandardCharsets.UTF_8)));
+                JsonReader jsonreader = new JsonReader(new StringReader(Files.toString(this.file, StandardCharsets.UTF_8)));
 
                 try {
-                    jsonReader.setLenient(false);
-                    Dynamic<JsonElement> dynamic = new Dynamic<>(JsonOps.INSTANCE, Streams.parse(jsonReader));
+                    jsonreader.setLenient(false);
+                    Dynamic<JsonElement> dynamic = new Dynamic(JsonOps.INSTANCE, Streams.parse(jsonreader));
+
                     if (!dynamic.get("DataVersion").asNumber().result().isPresent()) {
                         dynamic = dynamic.set("DataVersion", dynamic.createInt(1343));
                     }
 
                     dynamic = this.dataFixer.update(DataFixTypes.ADVANCEMENTS.getType(), dynamic, dynamic.get("DataVersion").asInt(0), SharedConstants.getCurrentVersion().getWorldVersion());
                     dynamic = dynamic.remove("DataVersion");
-                    Map<ResourceLocation, AdvancementProgress> map = GSON.getAdapter(TYPE_TOKEN).fromJsonTree(dynamic.getValue());
+                    Map<ResourceLocation, AdvancementProgress> map = (Map) PlayerAdvancements.GSON.getAdapter(PlayerAdvancements.TYPE_TOKEN).fromJsonTree((JsonElement) dynamic.getValue());
+
                     if (map == null) {
                         throw new JsonParseException("Found null for advancements");
                     }
 
-                    Stream<Map.Entry<ResourceLocation, AdvancementProgress>> stream = map.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue));
+                    Stream<Entry<ResourceLocation, AdvancementProgress>> stream = map.entrySet().stream().sorted(Comparator.comparing(Entry::getValue));
+                    Iterator iterator = ((List) stream.collect(Collectors.toList())).iterator();
+
+                    while (iterator.hasNext()) {
+                        Entry<ResourceLocation, AdvancementProgress> entry = (Entry) iterator.next();
+                        Advancement advancement = advancementLoader.getAdvancement((ResourceLocation) entry.getKey());
 
-                    for(Map.Entry<ResourceLocation, AdvancementProgress> entry : stream.collect(Collectors.toList())) {
-                        Advancement advancement = advancementLoader.getAdvancement(entry.getKey());
                         if (advancement == null) {
-                            LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", entry.getKey(), this.file);
+                            // CraftBukkit start
+                            if (entry.getKey().getNamespace().equals("minecraft")) {
+                                PlayerAdvancements.LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", entry.getKey(), this.file);
+                            }
+                            // CraftBukkit end
                         } else {
-                            this.startProgress(advancement, entry.getValue());
+                            this.startProgress(advancement, (AdvancementProgress) entry.getValue());
                         }
                     }
-                } catch (Throwable var10) {
+                } catch (Throwable throwable) {
                     try {
-                        jsonReader.close();
-                    } catch (Throwable var9) {
-                        var10.addSuppressed(var9);
+                        jsonreader.close();
+                    } catch (Throwable throwable1) {
+                        throwable.addSuppressed(throwable1);
                     }
 
-                    throw var10;
+                    throw throwable;
                 }
 
-                jsonReader.close();
-            } catch (JsonParseException var11) {
-                LOGGER.error("Couldn't parse player advancements in {}", this.file, var11);
-            } catch (IOException var12) {
-                LOGGER.error("Couldn't access player advancements in {}", this.file, var12);
+                jsonreader.close();
+            } catch (JsonParseException jsonparseexception) {
+                PlayerAdvancements.LOGGER.error("Couldn't parse player advancements in {}", this.file, jsonparseexception);
+            } catch (IOException ioexception) {
+                PlayerAdvancements.LOGGER.error("Couldn't access player advancements in {}", this.file, ioexception);
             }
         }
 
@@ -183,12 +214,16 @@
     }
 
     public void save() {
+        if (org.spigotmc.SpigotConfig.disableAdvancementSaving) return; // Spigot
         Map<ResourceLocation, AdvancementProgress> map = Maps.newHashMap();
+        Iterator iterator = this.advancements.entrySet().iterator();
 
-        for(Map.Entry<Advancement, AdvancementProgress> entry : this.advancements.entrySet()) {
-            AdvancementProgress advancementProgress = entry.getValue();
-            if (advancementProgress.hasProgress()) {
-                map.put(entry.getKey().getId(), advancementProgress);
+        while (iterator.hasNext()) {
+            Entry<Advancement, AdvancementProgress> entry = (Entry) iterator.next();
+            AdvancementProgress advancementprogress = (AdvancementProgress) entry.getValue();
+
+            if (advancementprogress.hasProgress()) {
+                map.put(((Advancement) entry.getKey()).getId(), advancementprogress);
             }
         }
 
@@ -196,95 +231,120 @@
             this.file.getParentFile().mkdirs();
         }
 
-        JsonElement jsonElement = GSON.toJsonTree(map);
-        jsonElement.getAsJsonObject().addProperty("DataVersion", SharedConstants.getCurrentVersion().getWorldVersion());
+        JsonElement jsonelement = PlayerAdvancements.GSON.toJsonTree(map);
+
+        jsonelement.getAsJsonObject().addProperty("DataVersion", SharedConstants.getCurrentVersion().getWorldVersion());
 
         try {
-            OutputStream outputStream = new FileOutputStream(this.file);
+            FileOutputStream fileoutputstream = new FileOutputStream(this.file);
 
             try {
-                Writer writer = new OutputStreamWriter(outputStream, Charsets.UTF_8.newEncoder());
+                OutputStreamWriter outputstreamwriter = new OutputStreamWriter(fileoutputstream, Charsets.UTF_8.newEncoder());
 
                 try {
-                    GSON.toJson(jsonElement, writer);
-                } catch (Throwable var9) {
+                    PlayerAdvancements.GSON.toJson(jsonelement, outputstreamwriter);
+                } catch (Throwable throwable) {
                     try {
-                        writer.close();
-                    } catch (Throwable var8) {
-                        var9.addSuppressed(var8);
+                        outputstreamwriter.close();
+                    } catch (Throwable throwable1) {
+                        throwable.addSuppressed(throwable1);
                     }
 
-                    throw var9;
+                    throw throwable;
                 }
 
-                writer.close();
-            } catch (Throwable var10) {
+                outputstreamwriter.close();
+            } catch (Throwable throwable2) {
                 try {
-                    outputStream.close();
-                } catch (Throwable var7) {
-                    var10.addSuppressed(var7);
+                    fileoutputstream.close();
+                } catch (Throwable throwable3) {
+                    throwable2.addSuppressed(throwable3);
                 }
 
-                throw var10;
+                throw throwable2;
             }
 
-            outputStream.close();
-        } catch (IOException var11) {
-            LOGGER.error("Couldn't save player advancements to {}", this.file, var11);
+            fileoutputstream.close();
+        } catch (IOException ioexception) {
+            PlayerAdvancements.LOGGER.error("Couldn't save player advancements to {}", this.file, ioexception);
         }
 
     }
 
     public boolean award(Advancement advancement, String criterionName) {
-        boolean bl = false;
-        AdvancementProgress advancementProgress = this.getOrStartProgress(advancement);
-        boolean bl2 = advancementProgress.isDone();
-        if (advancementProgress.grantProgress(criterionName)) {
+        boolean flag = false;
+        AdvancementProgress advancementprogress = this.getOrStartProgress(advancement);
+        boolean flag1 = advancementprogress.isDone();
+
+        if (advancementprogress.grantProgress(criterionName)) {
+            // Paper start
+            if (!new com.destroystokyo.paper.event.player.PlayerAdvancementCriterionGrantEvent(this.player.getBukkitEntity(), advancement.bukkit, criterionName).callEvent()) {
+                advancementprogress.revokeProgress(criterionName);
+                return false;
+            }
+            // Paper end
             this.unregisterListeners(advancement);
             this.progressChanged.add(advancement);
-            bl = true;
-            if (!bl2 && advancementProgress.isDone()) {
+            flag = true;
+            if (!flag1 && advancementprogress.isDone()) {
+                // Paper start - Add Adventure message to PlayerAdvancementDoneEvent
+                boolean announceToChat = advancement.getDisplay() != null && advancement.getDisplay().shouldAnnounceChat();
+                net.kyori.adventure.text.Component message = announceToChat ? io.papermc.paper.adventure.PaperAdventure.asAdventure(Component.translatable("chat.type.advancement." + advancement.getDisplay().getFrame().getName(), this.player.getDisplayName(), advancement.getChatComponent())) : null;
+                org.bukkit.event.player.PlayerAdvancementDoneEvent event = new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.bukkit, message);
+                this.player.level.getCraftServer().getPluginManager().callEvent(event);
+                message = event.message();
+                // Paper end
                 advancement.getRewards().grant(this.player);
-                if (advancement.getDisplay() != null && advancement.getDisplay().shouldAnnounceChat() && this.player.level.getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) {
-                    this.playerList.broadcastSystemMessage(Component.translatable("chat.type.advancement." + advancement.getDisplay().getFrame().getName(), this.player.getDisplayName(), advancement.getChatComponent()), false);
+                // Paper start - Add Adventure message to PlayerAdvancementDoneEvent
+                if (message != null && this.player.level.getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) {
+                    this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), false);
+                    // Paper end
                 }
             }
         }
 
-        if (advancementProgress.isDone()) {
+        if (advancementprogress.isDone()) {
             this.ensureVisibility(advancement);
         }
 
-        return bl;
+        return flag;
     }
 
     public boolean revoke(Advancement advancement, String criterionName) {
-        boolean bl = false;
-        AdvancementProgress advancementProgress = this.getOrStartProgress(advancement);
-        if (advancementProgress.revokeProgress(criterionName)) {
+        boolean flag = false;
+        AdvancementProgress advancementprogress = this.getOrStartProgress(advancement);
+
+        if (advancementprogress.revokeProgress(criterionName)) {
             this.registerListeners(advancement);
             this.progressChanged.add(advancement);
-            bl = true;
+            flag = true;
         }
 
-        if (!advancementProgress.hasProgress()) {
+        if (!advancementprogress.hasProgress()) {
             this.ensureVisibility(advancement);
         }
 
-        return bl;
+        return flag;
     }
 
     private void registerListeners(Advancement advancement) {
-        AdvancementProgress advancementProgress = this.getOrStartProgress(advancement);
-        if (!advancementProgress.isDone()) {
-            for(Map.Entry<String, Criterion> entry : advancement.getCriteria().entrySet()) {
-                CriterionProgress criterionProgress = advancementProgress.getCriterion(entry.getKey());
-                if (criterionProgress != null && !criterionProgress.isDone()) {
-                    CriterionTriggerInstance criterionTriggerInstance = entry.getValue().getTrigger();
-                    if (criterionTriggerInstance != null) {
-                        CriterionTrigger<CriterionTriggerInstance> criterionTrigger = CriteriaTriggers.getCriterion(criterionTriggerInstance.getCriterion());
-                        if (criterionTrigger != null) {
-                            criterionTrigger.addPlayerListener(this, new CriterionTrigger.Listener<>(criterionTriggerInstance, advancement, entry.getKey()));
+        AdvancementProgress advancementprogress = this.getOrStartProgress(advancement);
+
+        if (!advancementprogress.isDone()) {
+            Iterator iterator = advancement.getCriteria().entrySet().iterator();
+
+            while (iterator.hasNext()) {
+                Entry<String, Criterion> entry = (Entry) iterator.next();
+                CriterionProgress criterionprogress = advancementprogress.getCriterion((String) entry.getKey());
+
+                if (criterionprogress != null && !criterionprogress.isDone()) {
+                    CriterionTriggerInstance criterioninstance = ((Criterion) entry.getValue()).getTrigger();
+
+                    if (criterioninstance != null) {
+                        CriterionTrigger<CriterionTriggerInstance> criteriontrigger = CriteriaTriggers.getCriterion(criterioninstance.getCriterion());
+
+                        if (criteriontrigger != null) {
+                            criteriontrigger.addPlayerListener(this, new CriterionTrigger.Listener<>(criterioninstance, advancement, (String) entry.getKey()));
                         }
                     }
                 }
@@ -294,16 +354,21 @@
     }
 
     private void unregisterListeners(Advancement advancement) {
-        AdvancementProgress advancementProgress = this.getOrStartProgress(advancement);
+        AdvancementProgress advancementprogress = this.getOrStartProgress(advancement);
+        Iterator iterator = advancement.getCriteria().entrySet().iterator();
 
-        for(Map.Entry<String, Criterion> entry : advancement.getCriteria().entrySet()) {
-            CriterionProgress criterionProgress = advancementProgress.getCriterion(entry.getKey());
-            if (criterionProgress != null && (criterionProgress.isDone() || advancementProgress.isDone())) {
-                CriterionTriggerInstance criterionTriggerInstance = entry.getValue().getTrigger();
-                if (criterionTriggerInstance != null) {
-                    CriterionTrigger<CriterionTriggerInstance> criterionTrigger = CriteriaTriggers.getCriterion(criterionTriggerInstance.getCriterion());
-                    if (criterionTrigger != null) {
-                        criterionTrigger.removePlayerListener(this, new CriterionTrigger.Listener<>(criterionTriggerInstance, advancement, entry.getKey()));
+        while (iterator.hasNext()) {
+            Entry<String, Criterion> entry = (Entry) iterator.next();
+            CriterionProgress criterionprogress = advancementprogress.getCriterion((String) entry.getKey());
+
+            if (criterionprogress != null && (criterionprogress.isDone() || advancementprogress.isDone())) {
+                CriterionTriggerInstance criterioninstance = ((Criterion) entry.getValue()).getTrigger();
+
+                if (criterioninstance != null) {
+                    CriterionTrigger<CriterionTriggerInstance> criteriontrigger = CriteriaTriggers.getCriterion(criterioninstance.getCriterion());
+
+                    if (criteriontrigger != null) {
+                        criteriontrigger.removePlayerListener(this, new CriterionTrigger.Listener<>(criterioninstance, advancement, (String) entry.getKey()));
                     }
                 }
             }
@@ -315,24 +380,31 @@
         if (this.isFirstPacket || !this.visibilityChanged.isEmpty() || !this.progressChanged.isEmpty()) {
             Map<ResourceLocation, AdvancementProgress> map = Maps.newHashMap();
             Set<Advancement> set = Sets.newLinkedHashSet();
-            Set<ResourceLocation> set2 = Sets.newLinkedHashSet();
+            Set<ResourceLocation> set1 = Sets.newLinkedHashSet();
+            Iterator iterator = this.progressChanged.iterator();
 
-            for(Advancement advancement : this.progressChanged) {
+            Advancement advancement;
+
+            while (iterator.hasNext()) {
+                advancement = (Advancement) iterator.next();
                 if (this.visible.contains(advancement)) {
-                    map.put(advancement.getId(), this.advancements.get(advancement));
+                    map.put(advancement.getId(), (AdvancementProgress) this.advancements.get(advancement));
                 }
             }
 
-            for(Advancement advancement2 : this.visibilityChanged) {
-                if (this.visible.contains(advancement2)) {
-                    set.add(advancement2);
+            iterator = this.visibilityChanged.iterator();
+
+            while (iterator.hasNext()) {
+                advancement = (Advancement) iterator.next();
+                if (this.visible.contains(advancement)) {
+                    set.add(advancement);
                 } else {
-                    set2.add(advancement2.getId());
+                    set1.add(advancement.getId());
                 }
             }
 
-            if (this.isFirstPacket || !map.isEmpty() || !set.isEmpty() || !set2.isEmpty()) {
-                player.connection.send(new ClientboundUpdateAdvancementsPacket(this.isFirstPacket, set, set2, map));
+            if (this.isFirstPacket || !map.isEmpty() || !set.isEmpty() || !set1.isEmpty()) {
+                player.connection.send(new ClientboundUpdateAdvancementsPacket(this.isFirstPacket, set, set1, map));
                 this.visibilityChanged.clear();
                 this.progressChanged.clear();
             }
@@ -342,27 +414,29 @@
     }
 
     public void setSelectedTab(@Nullable Advancement advancement) {
-        Advancement advancement2 = this.lastSelectedTab;
+        Advancement advancement1 = this.lastSelectedTab;
+
         if (advancement != null && advancement.getParent() == null && advancement.getDisplay() != null) {
             this.lastSelectedTab = advancement;
         } else {
             this.lastSelectedTab = null;
         }
 
-        if (advancement2 != this.lastSelectedTab) {
+        if (advancement1 != this.lastSelectedTab) {
             this.player.connection.send(new ClientboundSelectAdvancementsTabPacket(this.lastSelectedTab == null ? null : this.lastSelectedTab.getId()));
         }
 
     }
 
     public AdvancementProgress getOrStartProgress(Advancement advancement) {
-        AdvancementProgress advancementProgress = this.advancements.get(advancement);
-        if (advancementProgress == null) {
-            advancementProgress = new AdvancementProgress();
-            this.startProgress(advancement, advancementProgress);
+        AdvancementProgress advancementprogress = (AdvancementProgress) this.advancements.get(advancement);
+
+        if (advancementprogress == null) {
+            advancementprogress = new AdvancementProgress();
+            this.startProgress(advancement, advancementprogress);
         }
 
-        return advancementProgress;
+        return advancementprogress;
     }
 
     private void startProgress(Advancement advancement, AdvancementProgress progress) {
@@ -371,31 +445,54 @@
     }
 
     private void ensureVisibility(Advancement advancement) {
-        boolean bl = this.shouldBeVisible(advancement);
-        boolean bl2 = this.visible.contains(advancement);
-        if (bl && !bl2) {
+        // Paper start
+        ensureVisibility(advancement, IterationEntryPoint.ROOT);
+    }
+    private enum IterationEntryPoint {
+        ROOT,
+        ITERATOR,
+        PARENT_OF_ITERATOR
+    }
+    private void ensureVisibility(Advancement advancement, IterationEntryPoint entryPoint) {
+        // Paper end
+        boolean flag = this.shouldBeVisible(advancement);
+        boolean flag1 = this.visible.contains(advancement);
+
+        if (flag && !flag1) {
             this.visible.add(advancement);
             this.visibilityChanged.add(advancement);
             if (this.advancements.containsKey(advancement)) {
                 this.progressChanged.add(advancement);
             }
-        } else if (!bl && bl2) {
+        } else if (!flag && flag1) {
             this.visible.remove(advancement);
             this.visibilityChanged.add(advancement);
         }
 
-        if (bl != bl2 && advancement.getParent() != null) {
-            this.ensureVisibility(advancement.getParent());
+        if (flag != flag1 && advancement.getParent() != null) {
+            // Paper start - If we're not coming from an iterator consider this to be a root entry, otherwise
+            // market that we're entering from the parent of an iterator.
+            this.ensureVisibility(advancement.getParent(), entryPoint == IterationEntryPoint.ITERATOR ? IterationEntryPoint.PARENT_OF_ITERATOR : IterationEntryPoint.ROOT);
         }
 
-        for(Advancement advancement2 : advancement.getChildren()) {
-            this.ensureVisibility(advancement2);
+        // If this is true, we've went through a child iteration, entered the parent, processed the parent
+        // and are about to reprocess the children. Stop processing here to prevent O(N^2) processing.
+        if (entryPoint == IterationEntryPoint.PARENT_OF_ITERATOR) {
+            return;
+        } // Paper end
+
+        Iterator iterator = advancement.getChildren().iterator();
+
+        while (iterator.hasNext()) {
+            Advancement advancement1 = (Advancement) iterator.next();
+
+            this.ensureVisibility(advancement1, IterationEntryPoint.ITERATOR); // Paper - Mark this call as being from iteration
         }
 
     }
 
     private boolean shouldBeVisible(Advancement advancement) {
-        for(int i = 0; advancement != null && i <= 2; ++i) {
+        for (int i = 0; advancement != null && i <= 2; ++i) {
             if (i == 0 && this.hasCompletedChildrenOrSelf(advancement)) {
                 return true;
             }
@@ -404,8 +501,9 @@
                 return false;
             }
 
-            AdvancementProgress advancementProgress = this.getOrStartProgress(advancement);
-            if (advancementProgress.isDone()) {
+            AdvancementProgress advancementprogress = this.getOrStartProgress(advancement);
+
+            if (advancementprogress.isDone()) {
                 return true;
             }
 
@@ -420,17 +518,24 @@
     }
 
     private boolean hasCompletedChildrenOrSelf(Advancement advancement) {
-        AdvancementProgress advancementProgress = this.getOrStartProgress(advancement);
-        if (advancementProgress.isDone()) {
+        AdvancementProgress advancementprogress = this.getOrStartProgress(advancement);
+
+        if (advancementprogress.isDone()) {
             return true;
         } else {
-            for(Advancement advancement2 : advancement.getChildren()) {
-                if (this.hasCompletedChildrenOrSelf(advancement2)) {
-                    return true;
+            Iterator iterator = advancement.getChildren().iterator();
+
+            Advancement advancement1;
+
+            do {
+                if (!iterator.hasNext()) {
+                    return false;
                 }
-            }
 
-            return false;
+                advancement1 = (Advancement) iterator.next();
+            } while (!this.hasCompletedChildrenOrSelf(advancement1));
+
+            return true;
         }
     }
 }
