Ticking class

Пакет: com.hypixel.hytale.server.core.universe.world.storage.component

Файл: com/hypixel/hytale/server/core/universe/world/storage/component/ChunkSavingSystems.java

extends: TickingSystem<ChunkStore>

implements: RunWhenPausedSystem<ChunkStore>

Поля (40)

МодификаторыТипИмя
break
break
WorldChunk var10
EntitySection var10
boolean var11
BlockComponentSection var11
var11
boolean var12
var12
ReferenceArrayList var13
var13
ReferenceArrayList var14
var14
ReferenceArrayList var15
var15
ChunkColumn var16
var16
var16
CompletableFuture var17
ChunkSection var22
EntitySection var23
BlockComponentSection var24
ObjectListIterator var26
ChunkSection var27
ReferenceArrayList var30
ReferenceArrayList var31
ReferenceArrayList var32
ObjectListIterator var33
ObjectListIterator var34
EntitySection var35
BlockComponentSection var36
ChunkSavingSystems.Data var4
World var5
IChunkSaver var6
Iterator var6
int var7
ChunkSection var7
Iterator var8
Ref var9
Iterator var9

Методы (14)

МодификаторыВозвратСигнатура
for for(int var8 = 0; var8 < var7; var8++)
public Set<Dependency<ChunkStore>> getDependenciespublic Set<Dependency<ChunkStore>> getDependencies()
if if(var9 == null)
if if(var16 != null)
if if(var5x != null)
if if(var30 != null)
if if(var31 != null)
if if(var32 != null)
if if(!var11)
if if(var13 != null)
if if(var14 != null)
if if(var15 != null)
if if(!var12)
public void tickpublic void tick(float var1, int var2, @Nonnull Store<ChunkStore> var3)

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.server.core.universe.world.storage.component;

class="kw">import com.hypixel.hytale.codec.Codec;
class="kw">import com.hypixel.hytale.component.ArchetypeChunk;
class="kw">import com.hypixel.hytale.component.CommandBuffer;
class="kw">import com.hypixel.hytale.component.ComponentAccessor;
class="kw">import com.hypixel.hytale.component.ComponentType;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.component.Resource;
class="kw">import com.hypixel.hytale.component.Store;
class="kw">import com.hypixel.hytale.component.dependency.Dependency;
class="kw">import com.hypixel.hytale.component.dependency.Order;
class="kw">import com.hypixel.hytale.component.dependency.RootDependency;
class="kw">import com.hypixel.hytale.component.dependency.SystemDependency;
class="kw">import com.hypixel.hytale.component.query.Query;
class="kw">import com.hypixel.hytale.component.system.StoreSystem;
class="kw">import com.hypixel.hytale.component.system.tick.RunWhenPausedSystem;
class="kw">import com.hypixel.hytale.component.system.tick.TickingSystem;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.metrics.MetricsRegistry;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.entity.EntitySavingSystem;
class="kw">import com.hypixel.hytale.server.core.universe.world.World;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.ChunkColumn;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.ChunkFlag;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockComponentSection;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.section.EntitySection;
class="kw">import com.hypixel.hytale.server.core.universe.world.events.ecs.ChunkSaveEvent;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.IChunkSaver;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectArrayList;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectListIterator;
class="kw">import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
class="kw">import java.util.Deque;
class="kw">import java.util.Iterator;
class="kw">import java.util.List;
class="kw">import java.util.Set;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.ConcurrentHashMap;
class="kw">import java.util.concurrent.ConcurrentLinkedDeque;
class="kw">import java.util.concurrent.Executor;
class="kw">import java.util.concurrent.ForkJoinPool;
class="kw">import java.util.concurrent.Semaphore;
class="kw">import java.util.concurrent.atomic.AtomicInteger;
class="kw">import java.util.concurrent.atomic.AtomicLong;
class="kw">import java.util.function.BiConsumer;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">public class ChunkSavingSystems {
   @Nonnull
   class="kw">public class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   @Nonnull
   class="kw">private class="kw">static class="kw">final ComponentType<ChunkStore, WorldChunk> WORLD_CHUNK_COMPONENT_TYPE = WorldChunk.getComponentType();
   @Nonnull
   class="kw">public class="kw">static class="kw">final Query<ChunkStore> QUERY = Query.and(WORLD_CHUNK_COMPONENT_TYPE, Query.not(ChunkStore.REGISTRY.getNonSerializedComponentType()));

   class="kw">public ChunkSavingSystems() {
   }

   @Nonnull
   class="kw">public class="kw">static CompletableFuture<Void> saveChunksInWorld(@Nonnull Store<ChunkStore> var0, @Nullable Executor var1) {
      World var2 = var0.getExternalData().getWorld();
      HytaleLogger var3 = var2.getLogger();
      ChunkSavingSystems.Data var4 = var0.getResource(ChunkStore.SAVE_RESOURCE);
      IChunkSaver var5 = var0.getExternalData().getSaver();
      var3.at(Level.INFO).log("Queuing Chunks...");
      var0.forEachChunk(QUERY, (var0x, var1x) -> {
         for (int var2 = 0; var2 < var0x.size(); var2++) {
            tryQueue(var2, var0x, var1x.getStore());
         }
      });
      var3.at(Level.INFO).log("Saving All Chunks...");

      Ref var6;
      while ((var6 = var4.poll()) != null) {
         saveChunk(var6, var4, true, var0, var1);
      }

      if (var5 class="kw">instanceof IChunkSaver.Cubic var7) {
         var3.at(Level.INFO).log("Flushing Dirty Sections...");
         SectionSavingSystem.flushAllDirty(var0, var7, var4, var1);
         var3.at(Level.INFO).log("Flushing Dirty Entities...");
         EntitySavingSystem.flushAllDirty(var2, var7, var4, var1);
      }

      var3.at(Level.INFO).log("Waiting for Saving Chunks...");
      class="kw">return var4.waitForSavingChunks();
   }

   class="kw">public class="kw">static void tryQueue(int var0, @Nonnull ArchetypeChunk<ChunkStore> var1, @Nonnull Store<ChunkStore> var2) {
      WorldChunk var3 = var1.getComponent(var0, WORLD_CHUNK_COMPONENT_TYPE);
      assert var3 != null;
      boolean var4 = var3.getNeedsSaving();
      IChunkSaver var5 = var2.getExternalData().getSaver();
      if (!(var5 class="kw">instanceof IChunkSaver.Cubic) && !var4) {
         var4 = collectSectionDirtiness(var1.getComponent(var0, ChunkColumn.getComponentType()), var2, false);
      }

      if (var4 && !var3.isSaving()) {
         Ref var6 = var1.getReferenceTo(var0);
         ChunkSaveEvent var7 = new ChunkSaveEvent(var3);
         var2.invoke(var6, var7);
         if (!var7.isCancelled()) {
            var2.getResource(ChunkStore.SAVE_RESOURCE).push(var6);
         }
      }
   }

   class="kw">public class="kw">static void tryQueueSync(@Nonnull ArchetypeChunk<ChunkStore> var0, @Nonnull CommandBuffer<ChunkStore> var1) {
      Store var2 = var1.getStore();
      ChunkSavingSystems.Data var3 = var2.getResource(ChunkStore.SAVE_RESOURCE);
      IChunkSaver var4 = var2.getExternalData().getSaver();

      for (int var5 = 0; var5 < var0.size(); var5++) {
         WorldChunk var6 = var0.getComponent(var5, WORLD_CHUNK_COMPONENT_TYPE);
         assert var6 != null;
         boolean var7 = var6.getNeedsSaving();
         if (!(var4 class="kw">instanceof IChunkSaver.Cubic) && !var7) {
            var7 = collectSectionDirtiness(var0.getComponent(var5, ChunkColumn.getComponentType()), var2, false);
         }

         if (var7 && !var6.isSaving()) {
            Ref var8 = var0.getReferenceTo(var5);
            ChunkSaveEvent var9 = new ChunkSaveEvent(var6);
            var2.invoke(var8, var9);
            if (!var9.isCancelled()) {
               var3.push(var8);
            }
         }
      }
   }

   class="kw">static boolean collectSectionDirtiness(@Nullable ChunkColumn var0, @Nonnull ComponentAccessor<ChunkStore> var1, boolean var2) {
      if (var0 == null) {
         class="kw">return false;
      }

      for (Ref var6 : var0.getSections()) {
         if (var6 != null && var6.isValid()) {
            ChunkSection var7 = var1.getComponent(var6, ChunkSection.getComponentType());
            if (var7 != null && (var7.needsSaving() || var2 && var7.isSaving())) {
               class="kw">return true;
            }

            EntitySection var8 = var1.getComponent(var6, EntitySection.getComponentType());
            if (var8 != null && (var8.needsSaving() || var2 && var8.isSaving())) {
               class="kw">return true;
            }

            BlockComponentSection var9 = var1.getComponent(var6, BlockComponentSection.getComponentType());
            if (var9 != null && (var9.needsSaving() || var2 && var9.isSaving())) {
               class="kw">return true;
            }
         }
      }

      class="kw">return false;
   }

   class="kw">public class="kw">static void saveChunk(
      @Nonnull Ref<ChunkStore> var0, @Nonnull ChunkSavingSystems.Data var1, boolean var2, @Nonnull Store<ChunkStore> var3, @Nullable Executor var4
   ) {
      if (!var0.isValid()) {
         LOGGER.at(Level.FINEST).log("Chunk reference in queue is for a chunk that has been removed!");
      } else {
         var1.awaitInFlightCapacity();
         WorldChunk var5 = var3.getComponent(var0, WORLD_CHUNK_COMPONENT_TYPE);
         assert var5 != null;
         boolean var6 = false;
         boolean var7 = false;

         try {
            var1.toSaveTotal.getAndIncrement();
            ChunkStore var8 = var3.getExternalData();
            World var9 = var8.getWorld();
            IChunkSaver var10 = var8.getSaver();
            CompletableFuture var11 = var10.saveChunkColumn(var5.getX(), var5.getZ(), var3, var0, var4, var1::releaseInFlight);
            var7 = true;
            var5.consumeNeedsSaving();
            var1.chunkSavingFutures.add(var11);
            BiConsumer var12 = (var1x, var2x) -> {
               if (var2x != null) {
                  ((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var2x)).log("Failed to save chunk (%d, %d):", var5.getX(), var5.getZ());
                  var5.markNeedsSaving();
               } else {
                  var5.setFlag(ChunkFlag.ON_DISK, true);
                  LOGGER.at(Level.FINEST).log("Finished saving chunk (%d, %d)", var5.getX(), var5.getZ());
               }
            };
            if (var4 != null) {
               var11.whenCompleteAsync(var12, var4);
            } else {
               var11.whenComplete(var12);
            }

            var6 = true;
            if (var2) {
               var11.thenRunAsync(
                  () -> HytaleServer.get().reportSaveProgress(var9, var1.savedCount.incrementAndGet(), var1.toSaveTotal.get() + var1.queue.size())
               );
            }
         } class="kw">finally {
            if (!var6) {
               var5.markNeedsSaving();
               if (!var7) {
                  var1.releaseInFlight();
               }
            }
         }
      }
   }

   class="kw">public class="kw">static class Data class="kw">implements Resource<ChunkStore> {
      class="kw">public class="kw">static class="kw">final float QUEUE_UPDATE_INTERVAL = 0.5F;
      class="kw">public class="kw">static class="kw">final int DEFAULT_MAX_IN_FLIGHT_SAVES = Math.max(ForkJoinPool.getCommonPoolParallelism(), 8);
      @Nonnull
      class="kw">public class="kw">static class="kw">final MetricsRegistry<ChunkSavingSystems.Data> METRICS_REGISTRY = new MetricsRegistry<ChunkSavingSystems.Data>()
         .register("ColumnQueueDepth", var0 -> (long)var0.queue.size(), Codec.LONG)
         .register("DirtySectionsBacklog", var0 -> (long)var0.dirtySectionsBacklog.get(), Codec.LONG)
         .register("DirtyEntitySectionsBacklog", var0 -> (long)var0.dirtyEntitySectionsBacklog.get(), Codec.LONG)
         .register("DirtyBlockComponentSectionsBacklog", var0 -> (long)var0.dirtyBlockComponentSectionsBacklog.get(), Codec.LONG)
         .register("DirtyEntitiesBacklog", var0 -> (long)var0.dirtyEntitiesBacklog.get(), Codec.LONG)
         .register("InFlightSaves", var0 -> (long)var0.getInFlightSaveCount(), Codec.LONG)
         .register("MaxInFlightSaves", var0 -> (long)var0.maxInFlightSaves, Codec.LONG)
         .register("PendingFutures", var0 -> (long)var0.chunkSavingFutures.size(), Codec.LONG)
         .register("TotalSaveStarts", var0 -> var0.totalSaveStarts.get(), Codec.LONG)
         .register("TotalSaveCompletions", var0 -> var0.totalSaveCompletions.get(), Codec.LONG);
      @Nonnull
      class="kw">private class="kw">final Set<Ref<ChunkStore>> set = ConcurrentHashMap.newKeySet();
      @Nonnull
      class="kw">private class="kw">final Deque<Ref<ChunkStore>> queue = new ConcurrentLinkedDeque<>();
      @Nonnull
      class="kw">private class="kw">final List<CompletableFuture<Void>> chunkSavingFutures = new ObjectArrayList();
      class="kw">private class="kw">final int maxInFlightSaves = DEFAULT_MAX_IN_FLIGHT_SAVES;
      @Nonnull
      class="kw">private class="kw">final Semaphore inFlightPermits = new Semaphore(this.maxInFlightSaves);
      @Nonnull
      class="kw">private class="kw">final AtomicLong totalSaveStarts = new AtomicLong();
      @Nonnull
      class="kw">private class="kw">final AtomicLong totalSaveCompletions = new AtomicLong();
      @Nonnull
      class="kw">private class="kw">final AtomicInteger dirtySectionsBacklog = new AtomicInteger();
      @Nonnull
      class="kw">private class="kw">final AtomicInteger dirtyEntitySectionsBacklog = new AtomicInteger();
      @Nonnull
      class="kw">private class="kw">final AtomicInteger dirtyBlockComponentSectionsBacklog = new AtomicInteger();
      @Nonnull
      class="kw">private class="kw">final AtomicInteger dirtyEntitiesBacklog = new AtomicInteger();
      class="kw">private float time;
      @Nonnull
      class="kw">private class="kw">final AtomicInteger savedCount = new AtomicInteger();
      @Nonnull
      class="kw">private class="kw">final AtomicInteger toSaveTotal = new AtomicInteger();

      class="kw">public Data() {
         this.time = 0.5F;
      }

      class="kw">public Data(float var1) {
         this.time = var1;
      }

      @Nonnull
      @Override
      class="kw">public Resource<ChunkStore> clone() {
         class="kw">return new ChunkSavingSystems.Data(this.time);
      }

      class="kw">public void clearSaveQueue() {
         this.queue.clear();
         this.set.clear();
      }

      class="kw">public void push(@Nonnull Ref<ChunkStore> var1) {
         if (this.set.add(var1)) {
            this.queue.push(var1);
         }
      }

      @Nullable
      class="kw">public Ref<ChunkStore> poll() {
         Ref var1 = this.queue.poll();
         if (var1 == null) {
            class="kw">return null;
         }

         this.set.remove(var1);
         class="kw">return var1;
      }

      class="kw">public boolean checkTimer(float var1) {
         this.time -= var1;
         if (this.time <= 0.0F) {
            this.time += 0.5F;
            class="kw">return true;
         } else {
            class="kw">return false;
         }
      }

      class="kw">public void pushSavingFuture(@Nonnull CompletableFuture<Void> var1) {
         this.chunkSavingFutures.add(var1);
      }

      class="kw">public boolean tryReserveInFlight() {
         if (!this.inFlightPermits.tryAcquire()) {
            class="kw">return false;
         }

         this.totalSaveStarts.incrementAndGet();
         class="kw">return true;
      }

      class="kw">public void awaitInFlightCapacity() {
         this.inFlightPermits.acquireUninterruptibly();
         this.totalSaveStarts.incrementAndGet();
      }

      class="kw">public void releaseInFlight() {
         this.inFlightPermits.release();
         this.totalSaveCompletions.incrementAndGet();
      }

      class="kw">public int getQueueDepth() {
         class="kw">return this.queue.size();
      }

      class="kw">public int getInFlightSaveCount() {
         class="kw">return this.maxInFlightSaves - this.inFlightPermits.availablePermits();
      }

      class="kw">public int getMaxInFlightSaves() {
         class="kw">return this.maxInFlightSaves;
      }

      class="kw">public int getPendingFutureCount() {
         class="kw">return this.chunkSavingFutures.size();
      }

      class="kw">public long getTotalSaveStarts() {
         class="kw">return this.totalSaveStarts.get();
      }

      class="kw">public long getTotalSaveCompletions() {
         class="kw">return this.totalSaveCompletions.get();
      }

      class="kw">public int getDirtySectionsBacklog() {
         class="kw">return this.dirtySectionsBacklog.get();
      }

      class="kw">public void setDirtySectionsBacklog(int var1) {
         this.dirtySectionsBacklog.set(var1);
      }

      class="kw">public int getDirtyEntitySectionsBacklog() {
         class="kw">return this.dirtyEntitySectionsBacklog.get();
      }

      class="kw">public void setDirtyEntitySectionsBacklog(int var1) {
         this.dirtyEntitySectionsBacklog.set(var1);
      }

      class="kw">public int getDirtyBlockComponentSectionsBacklog() {
         class="kw">return this.dirtyBlockComponentSectionsBacklog.get();
      }

      class="kw">public void setDirtyBlockComponentSectionsBacklog(int var1) {
         this.dirtyBlockComponentSectionsBacklog.set(var1);
      }

      class="kw">public int getDirtyEntitiesBacklog() {
         class="kw">return this.dirtyEntitiesBacklog.get();
      }

      class="kw">public void setDirtyEntitiesBacklog(int var1) {
         this.dirtyEntitiesBacklog.set(var1);
      }

      @Nonnull
      class="kw">public CompletableFuture<Void> waitForSavingChunks() {
         class="kw">return CompletableFuture.allOf(this.chunkSavingFutures.toArray(CompletableFuture[]::new));
      }
   }

   class="kw">public class="kw">static class Ticking class="kw">extends TickingSystem<ChunkStore> class="kw">implements RunWhenPausedSystem<ChunkStore> {
      class="kw">public Ticking() {
      }

      @Nonnull
      @Override
      class="kw">public Set<Dependency<ChunkStore>> getDependencies() {
         class="kw">return RootDependency.lastSet();
      }

      @Override
      class="kw">public void tick(float var1, int var2, @Nonnull Store<ChunkStore> var3) {
         ChunkSavingSystems.Data var4 = var3.getResource(ChunkStore.SAVE_RESOURCE);
         if (!var3.getExternalData().getWorld().isSavingLocked() && var3.getExternalData().getWorld().getWorldConfig().canSaveChunks()) {
            var4.chunkSavingFutures.removeIf(CompletableFuture::isDone);
            if (var4.checkTimer(var1)) {
               var3.forEachChunk(ChunkSavingSystems.QUERY, ChunkSavingSystems::tryQueueSync);
            }

            World var5 = var3.getExternalData().getWorld();
            IChunkSaver var6 = var3.getExternalData().getSaver();
            int var7 = ForkJoinPool.commonPool().getParallelism();

            for (int var8 = 0; var8 < var7; var8++) {
               Ref var9 = var4.poll();
               if (var9 == null) {
                  break;
               }

               if (!var4.tryReserveInFlight()) {
                  var4.push(var9);
                  break;
               }

               if (!var9.isValid()) {
                  var4.releaseInFlight();
                  ChunkSavingSystems.LOGGER.at(Level.FINEST).log("Chunk reference in queue is for a chunk that has been removed!");
               } else {
                  WorldChunk var10 = var3.getComponent(var9, ChunkSavingSystems.WORLD_CHUNK_COMPONENT_TYPE);
                  var10.setSaving(true);
                  boolean var11 = false;
                  boolean var12 = false;
                  ReferenceArrayList var13 = null;
                  ReferenceArrayList var14 = null;
                  ReferenceArrayList var15 = null;

                  try {
                     ChunkColumn var16;
                     if (!(var6 class="kw">instanceof IChunkSaver.Cubic)) {
                        var16 = var3.getComponent(var9, ChunkColumn.getComponentType());
                     } else {
                        var16 = null;
                     }

                     var4.toSaveTotal.getAndIncrement();
                     var13 = var16 != null ? new ReferenceArrayList() : null;
                     var14 = var16 != null ? new ReferenceArrayList() : null;
                     var15 = var16 != null ? new ReferenceArrayList() : null;
                     CompletableFuture var17 = var6.saveChunkColumn(var10.getX(), var10.getZ(), var3, var9, var5, var4::releaseInFlight);
                     var12 = true;
                     var10.consumeNeedsSaving();
                     if (var16 != null) {
                        for (Ref var21 : var16.getSections()) {
                           if (var21 != null && var21.isValid()) {
                              ChunkSection var22 = var3.getComponent(var21, ChunkSection.getComponentType());
                              if (var22 != null && var22.consumeNeedsSaving()) {
                                 var13.add(var22);
                              }

                              EntitySection var23 = var3.getComponent(var21, EntitySection.getComponentType());
                              if (var23 != null && var23.consumeNeedsSaving()) {
                                 var14.add(var23);
                              }

                              BlockComponentSection var24 = var3.getComponent(var21, BlockComponentSection.getComponentType());
                              if (var24 != null && var24.consumeNeedsSaving()) {
                                 var15.add(var24);
                                 var24.takeDirtyBlocks();
                                 var24.takeRemovedBlocks();
                              }
                           }
                        }
                     }

                     var4.chunkSavingFutures.add(var17);
                     ReferenceArrayList var30 = var13;
                     ReferenceArrayList var31 = var14;
                     ReferenceArrayList var32 = var15;
                     var17.whenCompleteAsync(
                        (var4x, var5x) -> {
                           if (var5x != null) {
                              ((HytaleLogger.Api)ChunkSavingSystems.LOGGER.at(Level.SEVERE).withCause(var5x))
                                 .log("Failed to save chunk (%d, %d):", var10.getX(), var10.getZ());
                              var10.markNeedsSaving();
                              if (var30 != null) {
                                 Iterator var6 = var30.iterator();

                                 while (var6.hasNext()) {
                                    ChunkSection var7 = (ChunkSection)var6.next();
                                    var7.markNeedsSaving();
                                 }
                              }

                              if (var31 != null) {
                                 Iterator var8 = var31.iterator();

                                 while (var8.hasNext()) {
                                    EntitySection var10 = (EntitySection)var8.next();
                                    var10.markNeedsSaving();
                                 }
                              }

                              if (var32 != null) {
                                 Iterator var9 = var32.iterator();

                                 while (var9.hasNext()) {
                                    BlockComponentSection var11 = (BlockComponentSection)var9.next();
                                    var11.markNeedsSaving();
                                 }
                              }
                           } else {
                              var10.setFlag(ChunkFlag.ON_DISK, true);
                              ChunkSavingSystems.LOGGER.at(Level.FINEST).log("Finished saving chunk (%d, %d)", var10.getX(), var10.getZ());
                           }

                           var10.setSaving(false);
                        },
                        var5
                     );
                     var11 = true;
                  } class="kw">finally {
                     if (!var11) {
                        var10.setSaving(false);
                        var10.markNeedsSaving();
                        if (var13 != null) {
                           ObjectListIterator var26 = var13.iterator();

                           while (var26.hasNext()) {
                              ChunkSection var27 = (ChunkSection)var26.next();
                              var27.markNeedsSaving();
                           }
                        }

                        if (var14 != null) {
                           ObjectListIterator var33 = var14.iterator();

                           while (var33.hasNext()) {
                              EntitySection var35 = (EntitySection)var33.next();
                              var35.markNeedsSaving();
                           }
                        }

                        if (var15 != null) {
                           ObjectListIterator var34 = var15.iterator();

                           while (var34.hasNext()) {
                              BlockComponentSection var36 = (BlockComponentSection)var34.next();
                              var36.markNeedsSaving();
                           }
                        }

                        if (!var12) {
                           var4.releaseInFlight();
                        }
                     }
                  }
               }
            }
         }
      }
   }

   class="kw">public class="kw">static class WorldRemoved class="kw">extends StoreSystem<ChunkStore> {
      @Nonnull
      class="kw">private class="kw">final Set<Dependency<ChunkStore>> dependencies = Set.of(new SystemDependency<>(Order.AFTER, ChunkStore.ChunkLoaderSaverSetupSystem.class));

      class="kw">public WorldRemoved() {
      }

      @Nonnull
      @Override
      class="kw">public Set<Dependency<ChunkStore>> getDependencies() {
         class="kw">return this.dependencies;
      }

      @Override
      class="kw">public void onSystemAddedToStore(@Nonnull Store<ChunkStore> var1) {
      }

      @Override
      class="kw">public void onSystemRemovedFromStore(@Nonnull Store<ChunkStore> var1) {
         World var2 = var1.getExternalData().getWorld();
         var2.getLogger().at(Level.INFO).log("Shutting down chunk generator...");
         var2.getChunkStore().shutdownGenerator();
         if (!var2.getWorldConfig().canSaveChunks()) {
            var2.getLogger().at(Level.INFO).log("This world has opted to disable chunk saving so it will not be saved on shutdown");
         } else {
            var2.getLogger().at(Level.INFO).log("Saving Chunks...");
            ChunkSavingSystems.Data var3 = var1.getResource(ChunkStore.SAVE_RESOURCE);
            var3.savedCount.set(0);
            var3.toSaveTotal.set(0);
            ChunkSavingSystems.saveChunksInWorld(var1, null).join();
            var2.getLogger().at(Level.INFO).log("Done Saving Chunks!");
         }
      }
   }
}