GenericBlockBulkUpdater interface

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

Файл: com/hypixel/hytale/server/core/universe/world/World.java

Методы (1)

МодификаторыВозвратСигнатура
abstract void applyvoid apply(World var1, T var2, long var3, WorldChunk var5, int var6, int var7, int var8, int var9, int var10, int var11)

Исходный код

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

class="kw">import com.hypixel.hytale.assetstore.AssetRegistry;
class="kw">import com.hypixel.hytale.codec.Codec;
class="kw">import com.hypixel.hytale.common.plugin.PluginIdentifier;
class="kw">import com.hypixel.hytale.common.util.FormatUtil;
class="kw">import com.hypixel.hytale.component.AddReason;
class="kw">import com.hypixel.hytale.component.ComponentAccessor;
class="kw">import com.hypixel.hytale.component.ComponentType;
class="kw">import com.hypixel.hytale.component.Holder;
class="kw">import com.hypixel.hytale.component.IResourceStorage;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.component.Store;
class="kw">import com.hypixel.hytale.component.data.unknown.UnknownComponents;
class="kw">import com.hypixel.hytale.event.EventRegistry;
class="kw">import com.hypixel.hytale.event.IEventDispatcher;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.logger.sentry.SkipSentryException;
class="kw">import com.hypixel.hytale.math.block.BlockUtil;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.math.vector.Rotation3f;
class="kw">import com.hypixel.hytale.math.vector.Transform;
class="kw">import com.hypixel.hytale.metrics.ExecutorMetricsRegistry;
class="kw">import com.hypixel.hytale.metrics.metric.HistoricMetric;
class="kw">import com.hypixel.hytale.protocol.packets.entities.SetEntitySeed;
class="kw">import com.hypixel.hytale.protocol.packets.player.JoinWorld;
class="kw">import com.hypixel.hytale.protocol.packets.player.SetClientId;
class="kw">import com.hypixel.hytale.protocol.packets.setup.ClientFeature;
class="kw">import com.hypixel.hytale.protocol.packets.setup.SetTimeDilation;
class="kw">import com.hypixel.hytale.protocol.packets.setup.SetUpdateRate;
class="kw">import com.hypixel.hytale.protocol.packets.setup.UpdateFeatures;
class="kw">import com.hypixel.hytale.protocol.packets.setup.ViewRadius;
class="kw">import com.hypixel.hytale.protocol.packets.world.ClearChunks;
class="kw">import com.hypixel.hytale.protocol.packets.world.ServerSetPaused;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.Message;
class="kw">import com.hypixel.hytale.server.core.ShutdownReason;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
class="kw">import com.hypixel.hytale.server.core.asset.type.gameplay.CombatConfig;
class="kw">import com.hypixel.hytale.server.core.asset.type.gameplay.DeathConfig;
class="kw">import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig;
class="kw">import com.hypixel.hytale.server.core.asset.type.gameplay.MutableDeathConfig;
class="kw">import com.hypixel.hytale.server.core.asset.type.gameplay.PlayerConfig;
class="kw">import com.hypixel.hytale.server.core.blocktype.component.BlockPhysics;
class="kw">import com.hypixel.hytale.server.core.console.ConsoleModule;
class="kw">import com.hypixel.hytale.server.core.entity.Entity;
class="kw">import com.hypixel.hytale.server.core.entity.EntityUtils;
class="kw">import com.hypixel.hytale.server.core.entity.UUIDComponent;
class="kw">import com.hypixel.hytale.server.core.entity.entities.Player;
class="kw">import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerConfigData;
class="kw">import com.hypixel.hytale.server.core.event.events.player.AddPlayerToWorldEvent;
class="kw">import com.hypixel.hytale.server.core.event.events.player.DrainPlayerFromWorldEvent;
class="kw">import com.hypixel.hytale.server.core.io.PacketHandler;
class="kw">import com.hypixel.hytale.server.core.modules.entity.EntityModule;
class="kw">import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
class="kw">import com.hypixel.hytale.server.core.modules.entity.component.Spectating;
class="kw">import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
class="kw">import com.hypixel.hytale.server.core.modules.entity.player.ChunkTracker;
class="kw">import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems;
class="kw">import com.hypixel.hytale.server.core.modules.time.TimeResource;
class="kw">import com.hypixel.hytale.server.core.modules.time.WorldTimeResource;
class="kw">import com.hypixel.hytale.server.core.prefab.selection.buffer.impl.IPrefabBuffer;
class="kw">import com.hypixel.hytale.server.core.receiver.IMessageReceiver;
class="kw">import com.hypixel.hytale.server.core.universe.PlayerRef;
class="kw">import com.hypixel.hytale.server.core.universe.Universe;
class="kw">import com.hypixel.hytale.server.core.universe.world.accessor.ChunkAccessor;
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.BlockSection;
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.StartWorldEvent;
class="kw">import com.hypixel.hytale.server.core.universe.world.lighting.ChunkLightingManager;
class="kw">import com.hypixel.hytale.server.core.universe.world.path.WorldPathConfig;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.resources.DiskResourceStorageProvider;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldgen.IWorldGen;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldgen.WorldGenLoadException;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.IWorldMap;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapLoadException;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager;
class="kw">import com.hypixel.hytale.server.core.util.FillerBlockUtil;
class="kw">import com.hypixel.hytale.server.core.util.MessageUtil;
class="kw">import com.hypixel.hytale.server.core.util.io.FileUtil;
class="kw">import com.hypixel.hytale.server.core.util.thread.TickingThread;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.longs.LongListIterator;
class="kw">import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectArrayList;
class="kw">import java.awt.Color;
class="kw">import java.io.IOException;
class="kw">import java.nio.file.Files;
class="kw">import java.nio.file.Path;
class="kw">import java.util.Collection;
class="kw">import java.util.Collections;
class="kw">import java.util.Deque;
class="kw">import java.util.EnumMap;
class="kw">import java.util.EnumSet;
class="kw">import java.util.List;
class="kw">import java.util.Map;
class="kw">import java.util.Random;
class="kw">import java.util.UUID;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.CompletionException;
class="kw">import java.util.concurrent.CompletionStage;
class="kw">import java.util.concurrent.ConcurrentHashMap;
class="kw">import java.util.concurrent.CopyOnWriteArrayList;
class="kw">import java.util.concurrent.Executor;
class="kw">import java.util.concurrent.LinkedBlockingDeque;
class="kw">import java.util.concurrent.ScheduledFuture;
class="kw">import java.util.concurrent.TimeUnit;
class="kw">import java.util.concurrent.atomic.AtomicBoolean;
class="kw">import java.util.concurrent.atomic.AtomicInteger;
class="kw">import java.util.function.IntUnaryOperator;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;
class="kw">import org.joml.Vector3d;

class="kw">public class World class="kw">extends TickingThread class="kw">implements Executor, ExecutorMetricsRegistry.ExecutorMetric, ChunkAccessor, IWorldChunks, IMessageReceiver {
   class="kw">public class="kw">static class="kw">final float SAVE_INTERVAL = 10.0F;
   class="kw">public class="kw">static class="kw">final String DEFAULT = "class="kw">default";
   @Nonnull
   class="kw">public class="kw">static class="kw">final ExecutorMetricsRegistry<World> METRICS_REGISTRY = new ExecutorMetricsRegistry<World>()
      .register("Name", var0 -> var0.name, Codec.STRING)
      .register("Alive", var0 -> var0.alive.get(), Codec.BOOLEAN)
      .register("TickLength", TickingThread::getBufferedTickLengthMetricSet, HistoricMetric.METRICS_CODEC)
      .register("EntityStore", World::getEntityStore, EntityStore.METRICS_REGISTRY)
      .register("ChunkStore", World::getChunkStore, ChunkStore.METRICS_REGISTRY);
   @Nonnull
   class="kw">private class="kw">final HytaleLogger logger;
   @Nonnull
   class="kw">private class="kw">final String name;
   @Nonnull
   class="kw">private class="kw">final Path savePath;
   @Nonnull
   class="kw">private class="kw">final WorldConfig worldConfig;
   @Nonnull
   class="kw">private class="kw">final ChunkStore chunkStore = new ChunkStore(this);
   @Nonnull
   class="kw">private class="kw">final EntityStore entityStore = new EntityStore(this);
   @Nonnull
   class="kw">private class="kw">final ChunkLightingManager chunkLighting;
   @Nonnull
   class="kw">private class="kw">final WorldMapManager worldMapManager;
   class="kw">private WorldPathConfig worldPathConfig;
   class="kw">private class="kw">final AtomicBoolean acceptingTasks = new AtomicBoolean(true);
   @Nonnull
   class="kw">private class="kw">final Deque<Runnable> taskQueue = new LinkedBlockingDeque<>();
   @Nonnull
   class="kw">private class="kw">final AtomicBoolean alive = new AtomicBoolean(true);
   @Nonnull
   class="kw">private class="kw">final EventRegistry eventRegistry = new EventRegistry(new CopyOnWriteArrayList<>(), () -> true, null, HytaleServer.get().getEventBus());
   @Nonnull
   class="kw">private class="kw">final WorldNotificationHandler notificationHandler = new WorldNotificationHandler(this);
   class="kw">private boolean isTicking;
   class="kw">private boolean isPaused;
   class="kw">private long tick;
   @Nonnull
   class="kw">private class="kw">final Random random = new Random();
   @Nonnull
   class="kw">private class="kw">final AtomicInteger entitySeed = new AtomicInteger();
   @Nonnull
   class="kw">private class="kw">final Map<UUID, PlayerRef> players = new ConcurrentHashMap<>();
   @Nonnull
   class="kw">private class="kw">final Collection<PlayerRef> playerRefs = Collections.unmodifiableCollection(this.players.values());
   @Nonnull
   class="kw">private class="kw">final Map<ClientFeature, Boolean> features = Collections.synchronizedMap(new EnumMap<>(ClientFeature.class));
   class="kw">private class="kw">volatile boolean gcHasRun;
   class="kw">private class="kw">final AtomicInteger savingLocks = new AtomicInteger(0);

   class="kw">public World(@Nonnull String var1, @Nonnull Path var2, @Nonnull WorldConfig var3) {
      super("WorldThread - " + var1);
      this.name = var1;
      this.logger = HytaleLogger.get("World|" + var1);
      this.savePath = var2;
      this.worldConfig = var3;
      this.logger
         .at(Level.INFO)
         .log("Loading world '%s' with generator type: '%s' and chunk storage: '%s'...", var1, var3.getWorldGenProvider(), var3.getChunkStorageProvider());
      this.worldMapManager = new WorldMapManager(this);
      this.chunkLighting = new ChunkLightingManager(this);
      this.isTicking = var3.isTicking();

      for (ClientFeature var7 : ClientFeature.VALUES) {
         this.features.put(var7, true);
      }

      GameplayConfig var8 = this.getGameplayConfig();
      CombatConfig var9 = var8.getCombatConfig();
      this.features.put(ClientFeature.DisplayHealthBars, var9.isDisplayHealthBars());
      this.features.put(ClientFeature.DisplayCombatText, var9.isDisplayCombatText());
      PlayerConfig.ArmorVisibilityOption var10 = var8.getPlayerConfig().getArmorVisibilityOption();
      this.features.put(ClientFeature.CanHideHelmet, var10.canHideHelmet());
      this.features.put(ClientFeature.CanHideCuirass, var10.canHideCuirass());
      this.features.put(ClientFeature.CanHideGauntlets, var10.canHideGauntlets());
      this.features.put(ClientFeature.CanHidePants, var10.canHidePants());
      this.logger.at(Level.INFO).log("Added world '%s' - Seed: %s, GameTime: %s", var1, Long.toString(var3.getSeed()), var3.getGameTime());
   }

   @Nonnull
   class="kw">public CompletableFuture<World> init() {
      CompletableFuture var1;
      if (this.worldConfig.isSavingConfig()) {
         var1 = Universe.get().getWorldConfigProvider().save(this.savePath, this.worldConfig, this);
      } else {
         var1 = CompletableFuture.completedFuture(null);
      }

      CompletableFuture var2 = CompletableFuture.<World>supplyAsync(() -> {
         try {
            IWorldGen var1 = this.worldConfig.getWorldGenProvider().getGenerator();
            this.chunkStore.setGenerator(var1);
            this.worldConfig.setDefaultSpawnProvider(var1);
            IWorldMap var6 = this.worldConfig.getWorldMapProvider().getGenerator(this);
            this.worldMapManager.setGenerator(var6);
            class="kw">return this;
         } catch (WorldGenLoadException var3) {
            if (this.name.equals(HytaleServer.get().getConfig().getDefaults().getWorld())) {
               Message var5 = Message.translation("client.disconnection.shutdownReason.worldGen.detail").param("detail", var3.getTraceMessage("\n"));
               HytaleServer.get().shutdownServer(ShutdownReason.WORLD_GEN.withMessage(var5));
            }

            throw new SkipSentryException("Failed to load WorldGen!", var3);
         } catch (WorldMapLoadException var4) {
            if (this.name.equals(HytaleServer.get().getConfig().getDefaults().getWorld())) {
               Message var2 = Message.translation("client.disconnection.shutdownReason.worldGen.detail").param("detail", var4.getTraceMessage("\n"));
               HytaleServer.get().shutdownServer(ShutdownReason.WORLD_GEN.withMessage(var2));
            }

            throw new SkipSentryException("Failed to load WorldGen!", var4);
         }
      }).whenComplete((var1x, var2x) -> {
         if (var2x != null) {
            ((HytaleLogger.Api)this.logger.at(Level.WARNING).withCause(var2x)).log("Failed to load WorldGen for world '%s'", this.name);
         }
      });
      CompletableFuture var3 = WorldPathConfig.load(this).thenAccept(var1x -> this.worldPathConfig = var1x);
      class="kw">return this.worldConfig.getSpawnProvider() != null
         ? CompletableFuture.allOf(var1, var3).thenApply(var1x -> this)
         : CompletableFuture.allOf(var1, var3).thenCompose(var1x -> var2);
   }

   @Override
   class="kw">protected void onStart() {
      DiskResourceStorageProvider.migrateFiles(this);
      IResourceStorage var1 = this.worldConfig.getResourceStorageProvider().getResourceStorage(this);
      this.chunkStore.start(var1);
      this.entityStore.start(var1);
      this.chunkLighting.start();
      this.worldMapManager.updateTickingState(this.worldMapManager.isStarted());
      Path var2 = this.savePath.resolve("rff");
      if (Files.exists(var2)) {
         throw new RuntimeException(var2 + " directory exists but this version of the server doesn't support migrating RFF worlds!");
      }

      IEventDispatcher var3 = HytaleServer.get().getEventBus().dispatchFor(StartWorldEvent.class, this.name);
      if (var3.hasListener()) {
         var3.dispatch(new StartWorldEvent(this));
      }
   }

   class="kw">public void stopIndividualWorld() {
      this.stopIndividualWorld(this.players);
   }

   class="kw">public void stopIndividualWorld(Map<UUID, PlayerRef> var1) {
      this.logger.at(Level.INFO).log("Removing individual world: %s", this.name);
      World var2 = Universe.get().getDefaultWorld();
      if (var2 != null && !var2.equals(this)) {
         Message var7;
         if (this.getFailureException() == null) {
            var7 = Message.translation("server.universe.worldRemoved");
         } else if (this.getPossibleFailureCause() == null) {
            var7 = Message.translation("server.universe.worldCrash.unknown");
         } else {
            var7 = Message.translation("server.universe.worldCrash.mod").param("mod", this.getPossibleFailureCause().toString());
         }

         var7.color(Color.RED);

         for (PlayerRef var9 : var1.values()) {
            var9.sendMessage(var7);
         }

         if (this.isInThread()) {
            this.drainPlayersTo(var2, var1.values()).join();
         } else {
            CompletableFuture.<CompletableFuture<Void>>supplyAsync(() -> this.drainPlayersTo(var2, var1.values()), this)
               .thenCompose(var0 -> (CompletionStage<Void>)var0)
               .join();
         }
      } else {
         Message var3;
         if (this.getFailureException() == null) {
            var3 = Message.translation("server.general.disconnect.worldRemoved");
         } else if (this.getPossibleFailureCause() == null) {
            var3 = Message.translation("server.general.disconnect.worldCrashed");
         } else {
            var3 = Message.translation("server.general.disconnect.worldCrashedCause").param("cause", this.getPossibleFailureCause().toString());
         }

         for (PlayerRef var5 : var1.values()) {
            var5.getPacketHandler().disconnect(var3);
         }
      }

      if (this.alive.getAndSet(false)) {
         try {
            super.stop();
         } catch (Throwable var6) {
            ((HytaleLogger.Api)this.logger.at(Level.SEVERE).withCause(var6)).log("Exception while shutting down world:");
         }
      }
   }

   class="kw">public void validateDeleteOnRemove() {
      if (this.worldConfig.isDeleteOnRemove()) {
         try {
            this.deleteWorldFromDisk();
         } catch (Throwable var2) {
            ((HytaleLogger.Api)this.logger.at(Level.SEVERE).withCause(var2)).log("Exception while deleting world on remove:");
         }
      }
   }

   class="kw">private void deleteWorldFromDisk() class="kw">throws IOException {
      Path var1 = this.savePath;
      Path var2 = var1.getFileName();
      String var3 = var2 + "_del" + UUID.randomUUID().toString().substring(0, 8);
      Path var4 = Universe.get().getWorldsDeletedPath().resolve(var3);
      Files.createDirectories(var4.getParent());
      FileUtil.atomicMove(var1, var4);
      FileUtil.deleteDirectory(var4);
   }

   @Override
   class="kw">protected boolean isIdle() {
      class="kw">return this.players.isEmpty();
   }

   @Override
   class="kw">protected void tick(float var1) {
      if (this.alive.get()) {
         TimeResource var2 = this.entityStore.getStore().getResource(TimeResource.getResourceType());
         var1 *= var2.getTimeDilationModifier();
         AssetRegistry.ASSET_LOCK.readLock().lock();

         try {
            this.consumeTaskQueue();
            if (!this.isPaused) {
               this.entityStore.getStore().tick(var1);
            } else {
               this.entityStore.getStore().pausedTick(var1);
            }

            if (this.isTicking && !this.isPaused) {
               this.chunkStore.getStore().tick(var1);
            } else {
               this.chunkStore.getStore().pausedTick(var1);
            }

            this.consumeTaskQueue();
         } class="kw">finally {
            AssetRegistry.ASSET_LOCK.readLock().unlock();
         }

         this.tick++;
      }
   }

   @Override
   class="kw">protected void onShutdown() {
      this.logger.at(Level.INFO).log("Stopping world %s...", this.name);
      this.logger.at(Level.INFO).log("Stopping background threads...");
      long var1 = System.nanoTime();

      while (this.chunkLighting.interrupt() || this.worldMapManager.interrupt()) {
         this.consumeTaskQueue();
         if (System.nanoTime() - var1 > 5000000000L) {
            break;
         }
      }

      this.chunkLighting.stop();
      this.worldMapManager.stop();
      this.logger.at(Level.INFO).log("Removing players...");
      Object2ObjectOpenHashMap var3 = new Object2ObjectOpenHashMap(this.players);

      for (PlayerRef var5 : this.playerRefs) {
         if (var5.getReference() != null) {
            var5.removeFromStore();
         }
      }

      this.consumeTaskQueue();
      this.logger.at(Level.INFO).log("Waiting for loading chunks...");
      this.chunkStore.waitForLoadingChunks();

      try {
         this.logger.at(Level.INFO).log("Shutting down stores...");
         HytaleServer.get().reportSingleplayerStatus(Message.translation("client.gameLoadingView.status.savingWorld").param("name", this.name));
         this.chunkStore.shutdown();
         this.consumeTaskQueue();
         this.entityStore.shutdown();
         this.consumeTaskQueue();
         this.eventRegistry.shutdownAndCleanup(true);
      } class="kw">finally {
         this.logger.at(Level.INFO).log("Saving Config...");
         if (this.worldConfig.isSavingConfig()) {
            Universe.get().getWorldConfigProvider().save(this.savePath, this.worldConfig, this).join();
         }
      }

      this.acceptingTasks.set(false);
      if (this.alive.getAndSet(false)) {
         this.stopIndividualWorld(var3);
         Universe.get().removeWorldExceptionally(this.name, var3);
      }

      HytaleServer.get().reportSingleplayerStatus(Message.translation("client.gameLoadingView.status.closingWorld").param("name", this.name));
   }

   @Override
   class="kw">public void setTps(int var1) {
      super.setTps(var1);
      SetUpdateRate var2 = new SetUpdateRate(var1);
      this.entityStore
         .getStore()
         .forEachEntityParallel(
            PlayerRef.getComponentType(), (var1x, var2x, var3) -> var2x.getComponent(var1x, PlayerRef.getComponentType()).getPacketHandler().writeNoCache(var2)
         );
   }

   class="kw">public class="kw">static void setTimeDilation(float var0, @Nonnull ComponentAccessor<EntityStore> var1) {
      World var2 = var1.getExternalData().getWorld();
      if (!(var0 <= 0.01) && !(var0 > 4.0F)) {
         TimeResource var3 = var1.getResource(TimeResource.getResourceType());
         var3.setTimeDilationModifier(var0);
         SetTimeDilation var4 = new SetTimeDilation(var0);

         for (PlayerRef var6 : var2.playerRefs) {
            var6.getPacketHandler().writeNoCache(var4);
         }
      } else {
         throw new IllegalArgumentException("TimeDilation is out of bounds (<=0.01 or >4)");
      }
   }

   @Nonnull
   class="kw">public String getName() {
      class="kw">return this.name;
   }

   class="kw">public boolean isAlive() {
      class="kw">return this.alive.get();
   }

   @Nonnull
   class="kw">public WorldConfig getWorldConfig() {
      class="kw">return this.worldConfig;
   }

   @Nonnull
   class="kw">public DeathConfig getDeathConfig() {
      MutableDeathConfig var1 = this.worldConfig.getDeathConfigOverride();
      class="kw">return var1 != null ? var1 : this.getGameplayConfig().getDeathConfig();
   }

   @Nullable
   class="kw">public String getGameModeTypeOnDeath() {
      String var1 = this.getDeathConfig().getGameModeTypeOnDeath();
      class="kw">return var1 != null ? var1 : HytaleServer.get().getConfig().getDefaults().getGameModeTypeOnDeath();
   }

   class="kw">public int getDaytimeDurationSeconds() {
      Integer var1 = this.worldConfig.getDaytimeDurationSecondsOverride();
      class="kw">return var1 != null ? var1 : this.getGameplayConfig().getWorldConfig().getDaytimeDurationSeconds();
   }

   class="kw">public int getNighttimeDurationSeconds() {
      Integer var1 = this.worldConfig.getNighttimeDurationSecondsOverride();
      class="kw">return var1 != null ? var1 : this.getGameplayConfig().getWorldConfig().getNighttimeDurationSeconds();
   }

   class="kw">public boolean isTicking() {
      class="kw">return this.isTicking;
   }

   class="kw">public void setTicking(boolean var1) {
      this.isTicking = var1;
      this.worldConfig.setTicking(var1);
      this.worldConfig.markChanged();
   }

   class="kw">public boolean isPaused() {
      class="kw">return this.isPaused;
   }

   class="kw">public void setPaused(boolean var1) {
      if (this.isPaused != var1) {
         this.isPaused = var1;
         ServerSetPaused var2 = new ServerSetPaused(var1);
         PlayerUtil.broadcastPacketToPlayersNoCache(this.entityStore.getStore(), var2);
      }
   }

   class="kw">public long getTick() {
      class="kw">return this.tick;
   }

   @Nonnull
   class="kw">public HytaleLogger getLogger() {
      class="kw">return this.logger;
   }

   class="kw">public boolean isCompassUpdating() {
      class="kw">return this.worldConfig.isCompassUpdating();
   }

   class="kw">public void setCompassUpdating(boolean var1) {
      boolean var2 = this.worldMapManager.shouldTick();
      this.worldConfig.setCompassUpdating(var1);
      this.worldConfig.markChanged();
      this.worldMapManager.updateTickingState(var2);
   }

   class="kw">public <T> void getBlockBulkRelative(
      @Nonnull Long2ObjectMap<T> var1,
      @Nonnull IntUnaryOperator var2,
      @Nonnull IntUnaryOperator var3,
      @Nonnull IntUnaryOperator var4,
      @Nonnull World.GenericBlockBulkUpdater<T> var5
   ) {
      Long2ObjectMap var6 = new Long2ObjectOpenHashMap();
      var1.forEach((var6x, var7) -> {
         int var8 = BlockUtil.unpackX(var6x);
         int var9 = BlockUtil.unpackY(var6x);
         int var10 = BlockUtil.unpackZ(var6x);
         int var11 = var2.applyAsInt(var8);
         int var12 = var3.applyAsInt(var9);
         int var13 = var4.applyAsInt(var10);
         long var14 = ChunkUtil.indexChunkFromBlock(var11, var13);
         WorldChunk var16 = (WorldChunk)var6.get(var14);
         if (var16 == null) {
            var16 = this.getNonTickingChunk(var14);
            var6.put(var14, var16);
         }

         var5.apply(this, (T)var7, var14, var16, var11, var12, var13, var8, var9, var10);
      });
   }

   @Nullable
   @Override
   class="kw">public WorldChunk loadChunkIfInMemory(long var1) {
      if (!this.isInThread()) {
         class="kw">return CompletableFuture.<WorldChunk>supplyAsync(() -> this.loadChunkIfInMemory(var1), this).join();
      }

      Ref var3 = this.chunkStore.getChunkReference(var1);
      if (var3 == null) {
         class="kw">return null;
      }

      WorldChunk var4 = this.chunkStore.getStore().getComponent(var3, WorldChunk.getComponentType());
      assert var4 != null;
      var4.setFlag(ChunkFlag.TICKING, true);
      class="kw">return var4;
   }

   @Nullable
   @Deprecated
   @Override
   class="kw">public WorldChunk getChunkIfInMemory(long var1) {
      Ref var3 = this.chunkStore.getChunkReference(var1);
      if (var3 == null) {
         class="kw">return null;
      } else {
         class="kw">return !this.isInThread()
            ? CompletableFuture.<WorldChunk>supplyAsync(() -> this.getChunkIfInMemory(var1), this).join()
            : this.chunkStore.getStore().getComponent(var3, WorldChunk.getComponentType());
      }
   }

   @Nullable
   @Deprecated
   @Override
   class="kw">public WorldChunk getChunkIfLoaded(long var1) {
      if (!this.isInThread()) {
         class="kw">return CompletableFuture.<WorldChunk>supplyAsync(() -> this.getChunkIfLoaded(var1), this).join();
      }

      Ref var3 = this.chunkStore.getChunkReference(var1);
      if (var3 == null) {
         class="kw">return null;
      }

      WorldChunk var4 = this.chunkStore.getStore().getComponent(var3, WorldChunk.getComponentType());
      assert var4 != null;
      class="kw">return var4.is(ChunkFlag.TICKING) ? var4 : null;
   }

   @Nullable
   @Deprecated
   @Override
   class="kw">public WorldChunk getChunkIfNonTicking(long var1) {
      if (!this.isInThread()) {
         class="kw">return CompletableFuture.<WorldChunk>supplyAsync(() -> this.getChunkIfNonTicking(var1), this).join();
      }

      Ref var3 = this.chunkStore.getChunkReference(var1);
      if (var3 == null) {
         class="kw">return null;
      }

      WorldChunk var4 = this.chunkStore.getStore().getComponent(var3, WorldChunk.getComponentType());
      assert var4 != null;
      class="kw">return var4.is(ChunkFlag.TICKING) ? null : var4;
   }

   @Nonnull
   @Deprecated
   @Override
   class="kw">public CompletableFuture<WorldChunk> getChunkAsync(long var1) {
      class="kw">return this.chunkStore
         .getChunkReferenceAsync(var1, 4)
         .thenApplyAsync(var1x -> var1x == null ? null : this.chunkStore.getStore().getComponent((Ref<ChunkStore>)var1x, WorldChunk.getComponentType()), this);
   }

   @Nonnull
   @Deprecated
   @Override
   class="kw">public CompletableFuture<WorldChunk> getNonTickingChunkAsync(long var1) {
      class="kw">return this.chunkStore
         .getChunkReferenceAsync(var1)
         .thenApplyAsync(var1x -> var1x == null ? null : this.chunkStore.getStore().getComponent((Ref<ChunkStore>)var1x, WorldChunk.getComponentType()), this);
   }

   @Deprecated(forRemoval = true)
   class="kw">public List<Player> getPlayers() {
      if (!this.isInThread()) {
         class="kw">return !this.isStarted() ? Collections.emptyList() : CompletableFuture.supplyAsync(this::getPlayers, this).join();
      }

      ObjectArrayList var1 = new ObjectArrayList(32);
      this.entityStore.getStore().forEachChunk(Player.getComponentType(), (var1x, var2) -> {
         var1.ensureCapacity(var1.size() + var1x.size());

         for (int var3 = 0; var3 < var1x.size(); var3++) {
            var1.add(var1x.getComponent(var3, Player.getComponentType()));
         }
      });
      class="kw">return var1;
   }

   @Nullable
   @Deprecated
   class="kw">public Entity getEntity(@Nonnull UUID var1) {
      if (!this.isInThread()) {
         class="kw">return CompletableFuture.<Entity>supplyAsync(() -> this.getEntity(var1), this).join();
      }

      Ref var2 = this.entityStore.getRefFromUUID(var1);
      class="kw">return EntityUtils.getEntity(var2, this.entityStore.getStore());
   }

   @Nullable
   class="kw">public Ref<EntityStore> getEntityRef(@Nonnull UUID var1) {
      class="kw">return !this.isInThread()
         ? CompletableFuture.<Ref<EntityStore>>supplyAsync(() -> this.getEntityRef(var1), this).join()
         : this.entityStore.getRefFromUUID(var1);
   }

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

   class="kw">public int getNonSpectatorPlayerCount() {
      int var1 = 0;

      for (PlayerRef var3 : this.playerRefs) {
         Ref var4 = var3.getReference();
         if (var4 == null || !var4.isValid() || !this.entityStore.getStore().getArchetype(var4).contains(Spectating.getComponentType())) {
            var1++;
         }
      }

      class="kw">return var1;
   }

   @Nonnull
   class="kw">public Collection<PlayerRef> getPlayerRefs() {
      class="kw">return this.playerRefs;
   }

   class="kw">public void trackPlayerRef(@Nonnull PlayerRef var1) {
      this.players.put(var1.getUuid(), var1);
   }

   class="kw">public void untrackPlayerRef(@Nonnull PlayerRef var1) {
      this.players.remove(var1.getUuid(), var1);
   }

   @Deprecated
   @Nullable
   class="kw">public <T class="kw">extends Entity> T spawnEntity(T var1, @Nonnull Vector3d var2, Rotation3f var3) {
      class="kw">return this.addEntity(var1, var2, var3, AddReason.SPAWN);
   }

   @Deprecated
   @Nullable
   class="kw">public <T class="kw">extends Entity> T addEntity(T var1, @Nonnull Vector3d var2, @Nullable Rotation3f var3, @Nonnull AddReason var4) {
      if (!EntityModule.get().isKnown(var1)) {
         throw new IllegalArgumentException("Unknown entity");
      }

      if (var1 class="kw">instanceof Player) {
         throw new IllegalArgumentException("Entity can't be a Player!");
      }

      if (var1.getNetworkId() == -1) {
         throw new IllegalArgumentException("Entity id can't be Entity.UNASSIGNED_ID (-1)!");
      }

      if (!this.equals(var1.getWorld())) {
         throw new IllegalStateException("Expected entity to already have its world set to " + this.name + " but it has " + var1.getWorld());
      }

      if (var1.getReference() != null && var1.getReference().isValid()) {
         throw new IllegalArgumentException("Entity already has a valid EntityReference: " + var1.getReference());
      }

      if (var2.y() < -32.0) {
         throw new IllegalArgumentException("Unable to spawn entity below the world! -32 < " + var2);
      }

      if (!this.isInThread()) {
         ((HytaleLogger.Api)this.logger.at(Level.WARNING).withCause(new SkipSentryException())).log("Warning addEntity was called off thread!");
         this.execute(() -> this.addEntity(var1, var2, var3, var4));
         class="kw">return var1;
      }

      var1.unloadFromWorld();
      Holder var5 = var1.toHolder();
      HeadRotation var6 = var5.ensureAndGetComponent(HeadRotation.getComponentType());
      if (var3 != null) {
         var6.teleportRotation(var3);
      }

      var5.addComponent(TransformComponent.getComponentType(), new TransformComponent(var2, var3));
      var5.ensureComponent(UUIDComponent.getComponentType());
      this.entityStore.getStore().addEntity(var5, var4);
      class="kw">return var1;
   }

   @Override
   class="kw">public void sendMessage(@Nonnull Message var1) {
      if (!this.isInThread()) {
         this.execute(() -> this.sendMessage(var1));
      } else {
         this.entityStore.getStore().forEachEntityParallel(PlayerRef.getComponentType(), (var1x, var2, var3) -> {
            PlayerRef var4 = var2.getComponent(var1x, PlayerRef.getComponentType());
            assert var4 != null;
            var4.sendMessage(var1);
         });
         this.logger.at(Level.INFO).log("[Broadcast] [Message] %s", MessageUtil.toAnsiString(var1).toAnsi(ConsoleModule.get().getTerminal()));
      }
   }

   @Override
   class="kw">public void execute(@Nonnull Runnable var1) {
      if (!this.acceptingTasks.get()) {
         throw new SkipSentryException(new IllegalThreadStateException("World thread is not accepting tasks: " + this.name + ", " + this.getThread()));
      }

      this.taskQueue.offer(var1);
   }

   class="kw">public ScheduledFuture<?> scheduleAfter(@Nonnull Runnable var1, long var2, @Nonnull TimeUnit var4) {
      class="kw">return HytaleServer.SCHEDULED_EXECUTOR.schedule(() -> {
         if (this.acceptingTasks.get()) {
            this.taskQueue.offer(var1);
         }
      }, var2, var4);
   }

   @Override
   class="kw">public void consumeTaskQueue() {
      this.debugAssertInTickingThread();
      int var1 = this.getTickStepNanos();

      Runnable var2;
      while ((var2 = this.taskQueue.poll()) != null) {
         try {
            long var3 = System.nanoTime();
            var2.run();
            long var5 = System.nanoTime();
            long var7 = var5 - var3;
            if (var7 > var1) {
               this.logger.at(Level.WARNING).log("Task took %s ns: %s", FormatUtil.nanosToString(var7), var2);
            }
         } catch (Exception var9) {
            ((HytaleLogger.Api)this.logger.at(Level.SEVERE).withCause(var9)).log("Failed to run task!");
         }
      }
   }

   @Nonnull
   class="kw">public ChunkStore getChunkStore() {
      class="kw">return this.chunkStore;
   }

   @Nonnull
   class="kw">public EntityStore getEntityStore() {
      class="kw">return this.entityStore;
   }

   @Nonnull
   class="kw">public ChunkLightingManager getChunkLighting() {
      class="kw">return this.chunkLighting;
   }

   @Nonnull
   class="kw">public WorldMapManager getWorldMapManager() {
      class="kw">return this.worldMapManager;
   }

   class="kw">public WorldPathConfig getWorldPathConfig() {
      class="kw">return this.worldPathConfig;
   }

   @Nonnull
   class="kw">public WorldNotificationHandler getNotificationHandler() {
      class="kw">return this.notificationHandler;
   }

   @Nonnull
   class="kw">public EventRegistry getEventRegistry() {
      class="kw">return this.eventRegistry;
   }

   @Nullable
   class="kw">public CompletableFuture<PlayerRef> addPlayer(@Nonnull PlayerRef var1) {
      class="kw">return this.addPlayer(var1, null);
   }

   @Nullable
   class="kw">public CompletableFuture<PlayerRef> addPlayer(@Nonnull PlayerRef var1, @Nullable Transform var2) {
      class="kw">return this.addPlayer(var1, var2, null, null);
   }

   @Nullable
   class="kw">public CompletableFuture<PlayerRef> addPlayer(@Nonnull PlayerRef var1, @Nullable Transform var2, @Nullable Boolean var3, @Nullable Boolean var4) {
      if (!this.alive.get()) {
         class="kw">return CompletableFuture.failedFuture(new SkipSentryException(new IllegalStateException("This world has already been shutdown!")));
      }

      if (var1.getReference() != null) {
         throw new IllegalStateException("Player is already in a world");
      }

      PacketHandler var5 = var1.getPacketHandler();
      if (!var5.stillActive()) {
         class="kw">return null;
      }

      Holder var6 = var1.getHolder();
      assert var6 != null;
      var1.setWorldUuid(this.worldConfig.getUuid());
      TransformComponent var7 = var6.getComponent(TransformComponent.getComponentType());
      if (var7 == null && var2 == null) {
         var7 = SpawnUtil.applyFirstSpawnTransform(var6, this, this.worldConfig, var1.getUuid());
         if (var7 == null) {
            class="kw">return CompletableFuture.failedFuture(new IllegalStateException("Spawn provider cannot be null for positioning new entities!"));
         }
      }

      assert var7 != null;
      Player var8 = var6.getComponent(Player.getComponentType());
      assert var8 != null;
      boolean var9 = !var8.getPlayerConfigData().getPerWorldData().containsKey(this.name);
      var8.setFirstSpawn(var9);
      if (var2 != null) {
         SpawnUtil.applyTransform(var6, var2);
      }

      Message var10 = Message.translation("server.general.playerJoinedWorld")
         .param("username", var1.getUsername())
         .param("world", this.worldConfig.getDisplayName() != null ? this.worldConfig.getDisplayName() : WorldConfig.formatDisplayName(this.name));
      AddPlayerToWorldEvent var11 = HytaleServer.get()
         .getEventBus()
         .dispatchFor(AddPlayerToWorldEvent.class, this.name)
         .dispatch(new AddPlayerToWorldEvent(var6, this, var10));
      ChunkTracker var12 = var6.getComponent(ChunkTracker.getComponentType());
      boolean var13 = var3 != null ? var3 : true;
      boolean var14 = var4 != null ? var4 : true;
      if (var12 != null && (var13 || var14)) {
         var12.setReadyForChunks(false);
      }

      Vector3d var15 = var7.getPosition();
      long var16 = ChunkUtil.indexChunkFromBlock(var15.x(), var15.z());
      CompletableFuture var18 = this.chunkStore.getChunkReferenceAsync(var16, 32).thenAccept(var1x -> var8.startClientReadyTimeout());
      CompletableFuture var19 = new CompletableFuture<>();
      var5.setClientReadyForChunksFuture(var19);
      CompletableFuture var20 = CompletableFuture.runAsync(() -> this.onSetupPlayerJoining(var6, var8, var1, var5, var2, var13, var14));
      CompletableFuture var21 = var19.orTimeout(30L, TimeUnit.SECONDS);
      class="kw">return CompletableFuture.allOf(var20, var21, var18)
         .thenApplyAsync(var5x -> this.onFinishPlayerJoining(var8, var1, var5, var11.getJoinMessage(), var11.shouldBroadcastJoinMessage()), this)
         .exceptionally(var2x -> {
            ((HytaleLogger.Api)this.logger.at(Level.WARNING).withCause(var2x)).log("Exception when adding player to world!");
            PluginIdentifier var3 = PluginIdentifier.identifyThirdPartyPlugin(var2x);
            if (var3 == null) {
               var1.getPacketHandler().disconnect(Message.translation("server.general.disconnect.exceptionJoiningWorld"));
            } else {
               var1.getPacketHandler().disconnect(Message.translation("server.general.disconnect.exceptionJoiningWorldCause").param("cause", var3.toString()));
            }

            throw new RuntimeException("Exception when adding player '" + var1.getUsername() + "' to world '" + this.name + "'", var2x);
         });
   }

   @Nonnull
   class="kw">private PlayerRef onFinishPlayerJoining(@Nonnull Player var1, @Nonnull PlayerRef var2, @Nonnull PacketHandler var3, @Nullable Message var4, boolean var5) {
      TimeResource var6 = this.entityStore.getStore().getResource(TimeResource.getResourceType());
      float var7 = var6.getTimeDilationModifier();
      int var8 = HytaleServer.get().getConfig().getMaxViewRadius();
      var3.write(new ViewRadius(var8 * 32));
      var3.write(new SetEntitySeed(this.entitySeed.get()), new SetClientId(var1.getNetworkId()), new SetTimeDilation(var7));
      var3.write(new UpdateFeatures(this.features));
      var3.write(this.worldConfig.getClientEffects().createSunSettingsPacket());
      var3.write(this.worldConfig.getClientEffects().createPostFxSettingsPacket());
      UUID var9 = var2.getUuid();
      Store var10 = this.entityStore.getStore();
      WorldTimeResource var11 = var10.getResource(WorldTimeResource.getResourceType());
      World var12 = var10.getExternalData().getWorld();
      var3.writeNoCache(new SetUpdateRate(this.getTps()));
      if (this.isPaused) {
         this.setPaused(false);
      }

      if (!var3.stillActive()) {
         throw new IllegalStateException("Connection of joining player closed before they could be added to the world store");
      }

      Ref var13 = var2.addToStore(var10);
      if (var13 != null && var13.isValid()) {
         var11.sendTimePackets(var2);
         WorldMapTracker var14 = var1.getWorldMapTracker();
         var14.clear();
         var14.sendSettings(var12);
         if (var5) {
            PlayerUtil.broadcastMessageToPlayers(var9, var4, var10);
         }

         TransformComponent var15 = var10.getComponent(var13, TransformComponent.getComponentType());
         assert var15 != null;
         String var16 = var15.getPosition().toString();
         this.logger.at(Level.INFO).log("Player '%s' joined world '%s' at location %s (%s)", var2.getUsername(), this.name, var16, var9);
         HeadRotation var17 = var10.getComponent(var13, HeadRotation.getComponentType());
         assert var17 != null;
         class="kw">return var2;
      } else {
         throw new IllegalStateException("Failed to add player ref of joining player to the world store");
      }
   }

   class="kw">private void onSetupPlayerJoining(
      @Nonnull Holder<EntityStore> var1,
      @Nonnull Player var2,
      @Nonnull PlayerRef var3,
      @Nonnull PacketHandler var4,
      @Nullable Transform var5,
      boolean var6,
      boolean var7
   ) {
      UUID var8 = var3.getUuid();
      this.logger.at(Level.INFO).log("Adding player '%s' to world '%s' at location %s (%s)", var3.getUsername(), this.name, var5, var8);
      int var9 = this.entityStore.takeNextNetworkId();
      var2.setNetworkId(var9);
      PlayerConfigData var10 = var2.getPlayerConfigData();
      var10.setWorld(this.name);
      if (var6) {
         EntityTrackerSystems.clear(var1);
         ChunkTracker var11 = var1.getComponent(ChunkTracker.getComponentType());
         if (var11 != null) {
            var11.clear();
            var4.writeNoCache(new ClearChunks());
         }
      }

      var2.getPageManager().clearCustomPageAcknowledgements();
      boolean var15 = this.chunkStore.supportsCubicSections();
      Integer var12 = var15 ? null : 0;
      Integer var13 = var15 ? null : 9;
      JoinWorld var14 = new JoinWorld(var6, var7, this.worldConfig.getUuid(), var12, var13);
      var4.write(var14);
      var4.tryFlush();
      HytaleLogger.getLogger().at(Level.INFO).log("%s: Sent %s", var4.getIdentifier(), var14);
      var4.setQueuePackets(true);
   }

   @Nonnull
   class="kw">public CompletableFuture<Void> drainPlayersTo(@Nonnull World var1, Collection<PlayerRef> var2) {
      ObjectArrayList var3 = new ObjectArrayList();

      for (PlayerRef var5 : var2) {
         Holder var6 = var5.getReference() != null ? var5.removeFromStore() : var5.getHolder();
         DrainPlayerFromWorldEvent var7 = HytaleServer.get()
            .getEventBus()
            .dispatchFor(DrainPlayerFromWorldEvent.class, this.name)
            .dispatch(new DrainPlayerFromWorldEvent(var6, var1, null));
         var3.add(var7.getWorld().addPlayer(var5, var7.getTransform()));
      }

      class="kw">return CompletableFuture.allOf((CompletableFuture<?>[])var3.toArray(CompletableFuture[]::new));
   }

   @Nonnull
   class="kw">public GameplayConfig getGameplayConfig() {
      String var1 = this.worldConfig.getGameplayConfig();
      GameplayConfig var2 = GameplayConfig.getAssetMap().getAsset(var1);
      if (var2 == null) {
         var2 = GameplayConfig.DEFAULT;
      }

      class="kw">return var2;
   }

   @Nonnull
   class="kw">public Map<ClientFeature, Boolean> getFeatures() {
      class="kw">return Collections.unmodifiableMap(this.features);
   }

   class="kw">public boolean isFeatureEnabled(@Nonnull ClientFeature var1) {
      class="kw">return this.features.getOrDefault(var1, false);
   }

   class="kw">public void registerFeature(@Nonnull ClientFeature var1, boolean var2) {
      this.features.put(var1, var2);
      this.broadcastFeatures();
   }

   class="kw">public void broadcastFeatures() {
      UpdateFeatures var1 = new UpdateFeatures(this.features);

      for (PlayerRef var3 : this.playerRefs) {
         var3.getPacketHandler().write(var1);
      }
   }

   @Nonnull
   class="kw">public Path getSavePath() {
      class="kw">return this.savePath;
   }

   class="kw">public void updateEntitySeed(@Nonnull Store<EntityStore> var1) {
      int var2 = this.random.nextInt();
      this.entitySeed.set(var2);
      PlayerUtil.broadcastPacketToPlayers(var1, new SetEntitySeed(var2));
   }

   class="kw">public void markGCHasRun() {
      this.gcHasRun = true;
   }

   class="kw">public boolean consumeGCHasRun() {
      boolean var1 = this.gcHasRun;
      this.gcHasRun = false;
      class="kw">return var1;
   }

   class="kw">public boolean isSavingLocked() {
      class="kw">return this.savingLocks.get() > 0;
   }

   class="kw">public void lockSaving() {
      this.savingLocks.incrementAndGet();
   }

   class="kw">public void unlockSaving() {
      int var1 = this.savingLocks.decrementAndGet();
      assert var1 >= 0 : "savingLocks underflow";
   }

   @Override
   class="kw">public int hashCode() {
      class="kw">return this.name != null ? this.name.hashCode() : 0;
   }

   @Override
   class="kw">public boolean equals(@Nullable Object var1) {
      if (this == var1) {
         class="kw">return true;
      } else if (var1 != null && this.getClass() == var1.getClass()) {
         World var2 = (World)var1;
         class="kw">return this.name.equals(var2.name);
      } else {
         class="kw">return false;
      }
   }

   @Nonnull
   @Override
   class="kw">public String toString() {
      class="kw">return "World{name='"
         + this.name
         + "', alive="
         + this.alive.get()
         + ", loadedChunksCount="
         + this.chunkStore.getLoadedChunksCount()
         + ", totalLoadedChunksCount="
         + this.chunkStore.getTotalLoadedChunksCount()
         + ", totalGeneratedChunksCount="
         + this.chunkStore.getTotalGeneratedChunksCount()
         + ", entityCount="
         + (this.entityStore.getStore() != null ? this.entityStore.getStore().getEntityCount() : 0)
         + "}";
   }

   class="kw">public void validate(@Nonnull StringBuilder var1, @Nonnull IPrefabBuffer.RawBlockConsumer<Void> var2, @Nonnull EnumSet<ValidationOption> var3) class="kw">throws IOException {
      this.setThread(Thread.currentThread());
      this.onStart();
      Store var4 = this.chunkStore.getStore();
      StringBuilder var5 = new StringBuilder();
      LongListIterator var6 = this.chunkStore.getLoader().getIndexes().iterator();

      while (var6.hasNext()) {
         long var7 = (Long)var6.next();
         int var9 = ChunkUtil.xOfChunkIndex(var7);
         int var10 = ChunkUtil.zOfChunkIndex(var7);

         try {
            CompletableFuture var11 = this.chunkStore.getChunkReferenceAsync(var7, 2);

            while (!var11.isDone()) {
               this.consumeTaskQueue();
            }

            Ref var12 = var11.join();
            if (var12 != null && var12.isValid()) {
               WorldChunk var13 = var4.getComponent(var12, WorldChunk.getComponentType());
               ChunkColumn var14 = var4.getComponent(var12, ChunkColumn.getComponentType());
               if (var14 != null) {
                  for (Ref var18 : var14.getSections()) {
                     class="kw">final ChunkSection var19 = var4.getComponent(var18, ChunkSection.getComponentType());
                     if (var3.contains(ValidationOption.ENTITIES)) {
                        ComponentType var20 = EntityStore.REGISTRY.getUnknownComponentType();
                        EntitySection var21 = var4.getComponent(var18, EntitySection.getComponentType());
                        if (var21 != null) {
                           for (Holder var23 : var21.getEntityHolders()) {
                              UnknownComponents var24 = var23.getComponent(var20);
                              if (var24 != null && !var24.getUnknownComponents().isEmpty()) {
                                 var1.append("\tUnknown Entity Components: ").append(var24.getUnknownComponents()).append("\n");
                              }
                           }
                        }
                     }

                     BlockSection var36 = var4.getComponent(var18, BlockSection.getComponentType());
                     if (var36 != null) {
                        BlockPhysics var37 = var4.getComponent(var18, BlockPhysics.getComponentType());

                        for (int var38 = 0; var38 < 32; var38++) {
                           int var39 = (var19.getY() << 5) + var38;

                           for (int var40 = 0; var40 < 32; var40++) {
                              for (int var25 = 0; var25 < 32; var25++) {
                                 int var26 = var36.get(var25, var38, var40);
                                 int var27 = var36.getFiller(var25, var38, var40);
                                 int var28 = var36.getRotationIndex(var25, var38, var40);
                                 Holder var29 = var13.getBlockComponentHolder(var25, var39, var40);
                                 int var30 = ChunkUtil.minBlock(var13.getX()) + var25;
                                 int var31 = ChunkUtil.minBlock(var13.getZ()) + var40;
                                 var2.accept(var30, var39, var31, var26, 0, 1.0F, var29, var37 != null ? var37.get(var25, var38, var40) : 0, var28, var27, null);
                                 if (var3.contains(ValidationOption.BLOCK_FILLER)) {
                                    var var32 = new FillerBlockUtil.FillerFetcher<BlockSection, ChunkStore>() {
                                       class="kw">public int getBlock(BlockSection var1, ChunkStore var2x, int var3x, int var4, int var5) {
                                          if (var3x >= 0 && var4 >= 0 && var5 >= 0 && var3x < 32 && var4 < 32 && var5 < 32) {
                                             class="kw">return var1.get(var3x, var4, var5);
                                          }

                                          int var6 = var19.getX() + ChunkUtil.chunkCoordinate(var3x);
                                          int var7 = var19.getY() + ChunkUtil.chunkCoordinate(var4);
                                          int var8 = var19.getZ() + ChunkUtil.chunkCoordinate(var5);
                                          CompletableFuture var9 = var2x.getChunkSectionReferenceAsync(var6, var7, var8);

                                          while (!var9.isDone()) {
                                             World.this.consumeTaskQueue();
                                          }

                                          Ref var10 = var9.join();
                                          BlockSection var11 = var2x.getStore().getComponent(var10, BlockSection.getComponentType());
                                          class="kw">return var11 == null ? Integer.MIN_VALUE : var11.get(var3x, var4, var5);
                                       }

                                       class="kw">public int getFiller(BlockSection var1, ChunkStore var2x, int var3x, int var4, int var5) {
                                          if (var3x >= 0 && var4 >= 0 && var5 >= 0 && var3x < 32 && var4 < 32 && var5 < 32) {
                                             class="kw">return var1.getFiller(var3x, var4, var5);
                                          }

                                          int var6 = var19.getX() + ChunkUtil.chunkCoordinate(var3x);
                                          int var7 = var19.getY() + ChunkUtil.chunkCoordinate(var4);
                                          int var8 = var19.getZ() + ChunkUtil.chunkCoordinate(var5);
                                          CompletableFuture var9 = var2x.getChunkSectionReferenceAsync(var6, var7, var8);

                                          while (!var9.isDone()) {
                                             World.this.consumeTaskQueue();
                                          }

                                          Ref var10 = var9.join();
                                          BlockSection var11 = var2x.getStore().getComponent(var10, BlockSection.getComponentType());
                                          class="kw">return var11 == null ? Integer.MIN_VALUE : var11.getFiller(var3x, var4, var5);
                                       }

                                       class="kw">public int getRotationIndex(BlockSection var1, ChunkStore var2x, int var3x, int var4, int var5) {
                                          if (var3x >= 0 && var4 >= 0 && var5 >= 0 && var3x < 32 && var4 < 32 && var5 < 32) {
                                             class="kw">return var1.getFiller(var3x, var4, var5);
                                          }

                                          int var6 = var19.getX() + ChunkUtil.chunkCoordinate(var3x);
                                          int var7 = var19.getY() + ChunkUtil.chunkCoordinate(var4);
                                          int var8 = var19.getZ() + ChunkUtil.chunkCoordinate(var5);
                                          CompletableFuture var9 = var2x.getChunkSectionReferenceAsync(var6, var7, var8);

                                          while (!var9.isDone()) {
                                             World.this.consumeTaskQueue();
                                          }

                                          Ref var10 = var9.join();
                                          BlockSection var11 = var2x.getStore().getComponent(var10, BlockSection.getComponentType());
                                          class="kw">return var11 == null ? Integer.MIN_VALUE : var11.getRotationIndex(var3x, var4, var5);
                                       }
                                    };
                                    FillerBlockUtil.ValidationResult var33 = FillerBlockUtil.validateBlock(
                                       var25, var38, var40, var26, var28, var27, var36, this.chunkStore, var32
                                    );
                                    class="kw">switch (var33) {
                                       case OK:
                                       class="kw">default:
                                          break;
                                       case INVALID_BLOCK: {
                                          BlockType var41 = BlockType.getAssetMap().getAsset(var26);
                                          var5.append("\tBlock ")
                                             .append(var41 != null ? var41.getId() : "<missing>")
                                             .append(" at ")
                                             .append(var25)
                                             .append(", ")
                                             .append(var38)
                                             .append(", ")
                                             .append(var40)
                                             .append(" is not valid filler")
                                             .append('\n');
                                          break;
                                       }
                                       case INVALID_FILLER: {
                                          BlockType var34 = BlockType.getAssetMap().getAsset(var26);
                                          var5.append("\tBlock ")
                                             .append(var34 != null ? var34.getId() : "<missing>")
                                             .append(" at ")
                                             .append(var25)
                                             .append(", ")
                                             .append(var38)
                                             .append(", ")
                                             .append(var40)
                                             .append(" has invalid/missing filler blocks")
                                             .append('\n');
                                       }
                                    }
                                 }
                              }
                           }
                        }

                        if (!var5.isEmpty()) {
                           var1.append("\tChunk ")
                              .append(var19.getX())
                              .append(", ")
                              .append(var19.getY())
                              .append(", ")
                              .append(var19.getZ())
                              .append(" validation errors:")
                              .append(var5);
                           var5.setLength(0);
                        }
                     }
                  }

                  var4.tick(1.0F);
               }
            }
         } catch (CompletionException var35) {
            ((HytaleLogger.Api)this.logger.at(Level.SEVERE).withCause(var35)).log("Failed to validate chunk: %d, %d", var9, var10);
            var1.append('\t')
               .append("Exception validating chunk: ")
               .append(var9)
               .append(", ")
               .append(var10)
               .append('\n')
               .append("\t\t")
               .append(var35.getCause().getMessage())
               .append('\n');
         }
      }

      if (this.alive.getAndSet(false)) {
         this.onShutdown();
      }

      this.setThread(null);
   }

   @FunctionalInterface
   class="kw">public class="kw">interface GenericBlockBulkUpdater<T> {
      void apply(World var1, T var2, long var3, WorldChunk var5, int var6, int var7, int var8, int var9, int var10, int var11);
   }
}