WorldRemoved class

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

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

extends: StoreSystem<ChunkStore>

Поля (3)

МодификаторыТипИмя
private final Set<Dependency<ChunkStore>> dependencies
World var2
ChunkSavingSystems.Data var3

Методы (3)

МодификаторыВозвратСигнатура
public Set<Dependency<ChunkStore>> getDependenciespublic Set<Dependency<ChunkStore>> getDependencies()
public void onSystemAddedToStorepublic void onSystemAddedToStore(@Nonnull Store<ChunkStore> var1)
public void onSystemRemovedFromStorepublic void onSystemRemovedFromStore(@Nonnull Store<ChunkStore> var1)

Исходный код

Показать/скрыть
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!");
         }
      }
   }
}