ChunkTracker class

Пакет: com.hypixel.hytale.server.core.modules.entity.player

Файл: com/hypixel/hytale/server/core/modules/entity/player/ChunkTracker.java

implements: Component<EntityStore>

Поля (252)

МодификаторыТипИмя
NONE, HOT, COLD
NONE, LOADING, READY
private int budget
private ChunkStore chunkStore
private CommandBuffer<EntityStore> commandBuffer
continue
private final IntSet loadedSections
private final IntSet loadingSections
private final IntSet pendingSections
private PlayerRef playerRef
return
return
return
private ChunkTracker.ColumnState state
private TransformComponent transform
long var1
long var1
long var1
var1
long var1
int[] var10
int var10
int var10
int var10
ObjectIterator var10
IntIterator var10
int var10
World var10
int var10
ChunkTracker.TrackedColumn var10
ObjectArrayList var10
ToClientPacket var10
double var10
int var11
int var11
int var11
int var11
Entry var11
int var11
PacketHandler var11
int var11
Vector3d var11
ChunkTracker.TrackedColumn var11
int var12
boolean var12
ChunkTracker.TrackedColumn var12
IntIterator var12
ChunkStore var12
int var12
int var12
double var12
int var13
int var13
boolean var13
int var13
int var13
Ref var13
boolean var13
int var13
int var14
int var14
World var14
Store var14
Ref var14
long var14
int var14
int var15
IntIterator var15
PacketHandler var15
ObjectArrayList var15
WorldChunk var15
ChunkTracker.TrackedColumn var15
int var15
long var15
int var16
ChunkStore var16
int var16
int var16
ChunkTracker.TrackedColumn var16
int var17
Ref var17
long var17
int var17
int var18
Store var18
boolean var18
int var19
ObjectArrayList var19
Ref var19
PacketHandler var2
PacketHandler var2
long var2
long var2
int var20
Store var20
long var20
boolean var21
IntIterator var21
int var21
ChunkTracker.TrackedColumn var21
long var22
IntIterator var22
Ref var23
SphereSpiralIterator var24
int var24
int var25
var25
int var25
boolean var26
var26
var26
var26
var26
Store var26
SpherePosition var27
long var28
SpherePosition var29
ObjectIterator var3
int var3
long var3
long var3
Vector3d var3
Vector3d var3
int var3
int var3
StringBuilder var3
int var3
ChunkTracker.TrackedColumn var30
int var31
int var32
long var33
ChunkTracker.TrackedColumn var35
Ref var36
Ref var37
WorldChunk var38
Entry var4
int[] var4
long var4
long var4
int var4
Vector3d var4
int var4
Vector3d var4
ObjectIterator var4
ObjectIterator var4
Vector3d var4
long var4
long var4
int var4
int var4
int var46
int var47
boolean var48
World var49
long var5
ChunkTracker.TrackedColumn var5
ChunkTracker.TrackedColumn var5
int var5
int var5
int var5
int var5
ChunkTracker.TrackedColumn var5
Entry var5
int var5
int var5
int var5
int var5
Vector3d var5
ChunkStore var50
ObjectIterator var51
ComponentType var52
ComponentType var54
Store var55
long var56
int var57
int var6
int var6
ChunkTracker.TrackedColumn var6
int var6
int var6
int var6
int var6
int var6
ChunkTracker.TrackedColumn var6
int var6
ObjectIterator var6
int var6
long var6
ChunkTracker.TrackedColumn var6
List var6
int var6
double var6
int var7
int var7
Vector3d var7
int var7
int var7
int var7
int var7
int var7
int var7
int var7
Entry var7
int var7
long var7
World var7
ObjectArrayList var7
Iterator var7
long var7
long var7
Vector3d var7
int var8
int var8
int var8
IntIterator var8
int var8
int var8
int var8
int var8
int var8
ChunkTracker.TrackedColumn var8
ChunkTracker.TrackedColumn var8
Ref var8
Vector3d var8
ChunkTracker.TrackedColumn var8
CompletableFuture var8
long var8
World var8
Iterator var8
double var8
double var8
IntArrayList var9
int[] var9
int var9
Integer var9
int var9
int var9
IntIterator var9
int var9
int var9
var9
var9
ChunkTracker.TrackedColumn var9
ChunkTracker.TrackedColumn var9
Store var9
int var9
ToClientPacket var9
long var9
long var9
ChunkTracker.TrackedColumn var9
List var9
CompletableFuture var9

Методы (87)

МодификаторыВозвратСигнатура
ChunkVisibility ChunkVisibility()
ColumnState ColumnState()
private ReloadContextprivate ReloadContext()
private TrackedColumnprivate TrackedColumn()
private void appendColumnGridvoid appendColumnGrid(@Nonnull StringBuilder var1, int var2, int var3, boolean var4)
public float calculateColumnPriorityfloat calculateColumnPriority(int var1, int var2)
public float calculateSectionPriorityfloat calculateSectionPriority(int var1, int var2, int var3)
public void clearvoid clear()
private void clearprivate void clear()
public void copyFromvoid copyFrom(@Nonnull ChunkTracker var1)
private void flushPendingAbsentvoid flushPendingAbsent(@Nonnull PlayerRef var1)
private void flushUnloadsvoid flushUnloads(@Nonnull PlayerRef var1)
for for(int var12 = 0; var12 < var11; var12 += 128)
for for(int var5 = 0; var5 < var3; var5 += 12288)
for for(int var10 = 0; var10 < var8; var10 += 8192)
for for(int var6 = var3 - var5; var6 <= var3 + var5; var6++)
for for(int var7 = var2 - var5; var7 <= var2 + var5; var7++)
abstract for for(int var20 = 0; var20 < var19.size()
abstract for for(int var16 = 0; var16 < var15.size()
abstract for for(int var10 = 0; var10 < var6.size()
abstract for for(int var11 = 0; var11 < var9.size()
public void forEachLoadedSectionvoid forEachLoadedSection(@Nonnull TriIntConsumer var1)
static ComponentType<EntityStore, ChunkTracker> getComponentTypeComponentType<EntityStore, ChunkTracker> getComponentType()
public int getLoadedSectionsCountint getLoadedSectionsCount()
public int getLoadingSectionsCountint getLoadingSectionsCount()
public int getMaxHotLoadedRadiusint getMaxHotLoadedRadius()
public int getMaxSectionsPerSecondint getMaxSectionsPerSecond()
public int getMaxSectionsPerTickint getMaxSectionsPerTick()
public int getMinLoadedRadiusint getMinLoadedRadius()
if if(var3 > 0)
if if(var8 > 0)
if if(var15 > 0)
if if(var48)
if if(this.hotRadiusSq > var47 + 1)
if if(this.sentViewRadiusSq <= var11)
if if(var21 || var27.y >= 0 && var27.y < 10)
if if(var30.state == ChunkTracker.ColumnState.NONE)
if if(var30.state == ChunkTracker.ColumnState.LOADING)
if if(var26)
if if(this.hotRadiusSq <= var47)
if if(this.sentViewRadiusSq > var11)
if if(var5 == null)
if if(this.transformComponent == null)
if if(this.transformComponent == null)
if if(this.transformComponent == null)
if if(var12)
if if(this.transformComponent == null)
if if(this.transformComponent == null)
if if(var8 == null)
if if(var4)
if if(var8.state == ChunkTracker.ColumnState.READY)
if if(var9.state != ChunkTracker.ColumnState.READY)
if if(var17 != null)
if if(var13 != null)
if if(var14 != null)
if if(var13)
if if(var8 != null)
if if(var6 != null)
if if(var9 != null)
if if(var15 != null)
if if(var7.budget <= 0)
if if(var10 == null)
if if(var18)
if if(var10 != null)
if if(this.transformComponent == null)
if if(this.transformComponent == null)
public boolean isLoadedboolean isLoaded(long var1)
public boolean isLoadedboolean isLoaded(int var1, int var2, int var3)
public boolean isReadyForChunksboolean isReadyForChunks()
static boolean reloadSectionboolean reloadSection(int var0, int var1, int var2, int var3, int var4, int var5, @Nonnull ChunkTracker var6, @Nonnull ChunkTracker.ReloadContext var7)
public void removeForReloadvoid removeForReload(int var1, int var2, int var3)
private void resetStatevoid resetState()
public void setDefaultMaxSectionsPerSecondvoid setDefaultMaxSectionsPerSecond(@Nonnull PlayerRef var1)
public void setMaxHotLoadedRadiusvoid setMaxHotLoadedRadius(int var1)
public void setMaxSectionsPerSecondvoid setMaxSectionsPerSecond(int var1)
public void setMaxSectionsPerTickvoid setMaxSectionsPerTick(int var1)
public void setMinLoadedRadiusvoid setMinLoadedRadius(int var1)
public void setReadyForChunksvoid setReadyForChunks(boolean var1)
public boolean shouldBeVisibleboolean shouldBeVisible(long var1)
public boolean shouldBeVisibleboolean shouldBeVisible(int var1, int var2, int var3)
static boolean shouldBeVisibleboolean shouldBeVisible(int var0, int var1, int var2, int var3, int var4)
abstract return shouldBeVisiblereturn shouldBeVisible(var8 * var8, var4, var5, var6, var7)
public void tickvoid tick(@Nonnull Player var1, @Nonnull PlayerRef var2, @Nonnull TransformComponent var3, float var4, @Nonnull CommandBuffer<EntityStore> var5)
public void tryLoadColumnAsyncvoid tryLoadColumnAsync(@Nonnull ChunkStore var1, @Nonnull PlayerRef var2, long var3, @Nonnull TransformComponent var5, @Nonnull ComponentAccessor<EntityStore> var6)
public void tryLoadSectionAsyncvoid tryLoadSectionAsync(@Nonnull ChunkStore var1, @Nonnull PlayerRef var2, int var3, int var4, int var5, @Nonnull TransformComponent var6, @Nonnull ComponentAccessor<EntityStore> var7)
private boolean tryUnloadColumnboolean tryUnloadColumn(Entry<ChunkTracker.TrackedColumn> var1, int var2, int var3, int var4, int var5, PlayerRef var6)
private boolean tryUnloadSectionboolean tryUnloadSection(int var1, int var2, int var3, int var4, int var5, int var6, @Nonnull PlayerRef var7)

Исходный код

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

class="kw">import com.hypixel.hytale.codec.Codec;
class="kw">import com.hypixel.hytale.component.CommandBuffer;
class="kw">import com.hypixel.hytale.component.Component;
class="kw">import com.hypixel.hytale.component.ComponentAccessor;
class="kw">import com.hypixel.hytale.component.ComponentType;
class="kw">import com.hypixel.hytale.component.NonTicking;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.component.Store;
class="kw">import com.hypixel.hytale.function.consumer.TriIntConsumer;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.math.data.Int3OpenHashSet;
class="kw">import com.hypixel.hytale.math.iterator.SphereOffsets;
class="kw">import com.hypixel.hytale.math.iterator.SpherePosition;
class="kw">import com.hypixel.hytale.math.iterator.SphereSpiralIterator;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.math.util.MathUtil;
class="kw">import com.hypixel.hytale.metrics.MetricsRegistry;
class="kw">import com.hypixel.hytale.protocol.NetworkChannel;
class="kw">import com.hypixel.hytale.protocol.ToClientPacket;
class="kw">import com.hypixel.hytale.protocol.packets.world.SetAbsentChunks;
class="kw">import com.hypixel.hytale.protocol.packets.world.UnloadChunks;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.entity.entities.Player;
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.TransformComponent;
class="kw">import com.hypixel.hytale.server.core.universe.PlayerRef;
class="kw">import com.hypixel.hytale.server.core.universe.world.World;
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.storage.ChunkStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
class="kw">import it.unimi.dsi.fastutil.ints.IntArrayList;
class="kw">import it.unimi.dsi.fastutil.ints.IntIterator;
class="kw">import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
class="kw">import it.unimi.dsi.fastutil.ints.IntSet;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectArrayList;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectIterator;
class="kw">import java.util.Arrays;
class="kw">import java.util.Collections;
class="kw">import java.util.Iterator;
class="kw">import java.util.List;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.TimeUnit;
class="kw">import java.util.concurrent.locks.StampedLock;
class="kw">import java.util.function.Supplier;
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 ChunkTracker class="kw">implements Component<EntityStore> {
   @Nonnull
   class="kw">public class="kw">static class="kw">final MetricsRegistry<ChunkTracker> METRICS_REGISTRY = new MetricsRegistry<ChunkTracker>()
      .register("ViewRadius", var0 -> var0.sectionViewRadius, Codec.INTEGER)
      .register("SentViewRadiusSq", var0 -> var0.sentViewRadiusSq, Codec.INTEGER)
      .register("HotRadiusSq", var0 -> var0.hotRadiusSq, Codec.INTEGER)
      .register("LoadedSectionsCount", ChunkTracker::getLoadedSectionsCount, Codec.INTEGER)
      .register("LoadingSectionsCount", ChunkTracker::getLoadingSectionsCount, Codec.INTEGER)
      .register("MaxSectionsPerSecond", ChunkTracker::getMaxSectionsPerSecond, Codec.INTEGER)
      .register("MaxSectionsPerTick", ChunkTracker::getMaxSectionsPerTick, Codec.INTEGER)
      .register("ReadyForChunks", ChunkTracker::isReadyForChunks, Codec.BOOLEAN)
      .register("LastChunkX", var0 -> var0.lastChunkX, Codec.INTEGER)
      .register("LastChunkY", var0 -> var0.lastChunkY, Codec.INTEGER)
      .register("LastChunkZ", var0 -> var0.lastChunkZ, Codec.INTEGER);
   class="kw">public class="kw">static class="kw">final int MAX_SECTIONS_PER_SECOND_LOCAL = 2560;
   class="kw">public class="kw">static class="kw">final int MAX_SECTIONS_PER_SECOND_LAN = 1280;
   class="kw">public class="kw">static class="kw">final int MAX_SECTIONS_PER_SECOND = 360;
   class="kw">public class="kw">static class="kw">final int MAX_SECTIONS_PER_TICK = 40;
   class="kw">public class="kw">static class="kw">final int MAX_UNLOAD_SECTION_INTS = 12288;
   class="kw">public class="kw">static class="kw">final int MAX_UNLOAD_COLUMN_INTS = 8192;
   class="kw">public class="kw">static class="kw">final int MAX_ABSENT_Y_INTS = 128;
   class="kw">public class="kw">static class="kw">final int MIN_LOADED_RADIUS = 2;
   class="kw">public class="kw">static class="kw">final int MAX_HOT_LOADED_RADIUS = 8;
   class="kw">public class="kw">static class="kw">final long MAX_FAILURE_BACKOFF_NANOS = TimeUnit.SECONDS.toNanos(10L);
   @Nullable
   class="kw">private TransformComponent transformComponent;
   class="kw">private int sectionViewRadius;
   @Nonnull
   class="kw">private class="kw">final Supplier<SphereOffsets> sphereOffsetsSupplier;
   @Nonnull
   class="kw">private class="kw">volatile SphereSpiralIterator spiralIterator;
   @Nonnull
   class="kw">private class="kw">final StampedLock lock = new StampedLock();
   class="kw">private class="kw">final Long2ObjectMap<ChunkTracker.TrackedColumn> trackedColumns = new Long2ObjectOpenHashMap();
   class="kw">private class="kw">final Long2ObjectMap<IntArrayList> pendingAbsentByColumn = new Long2ObjectOpenHashMap();
   class="kw">private class="kw">volatile boolean hasPendingAbsent;
   class="kw">private class="kw">final IntArrayList unloadSectionScratch = new IntArrayList();
   class="kw">private class="kw">final IntArrayList unloadColumnScratch = new IntArrayList();
   class="kw">private int loadingSections;
   class="kw">private class="kw">final Int3OpenHashSet reloadingSections = new Int3OpenHashSet();
   class="kw">private class="kw">final ChunkTracker.ReloadContext reloadContext = new ChunkTracker.ReloadContext();
   class="kw">private int maxSectionsPerSecond;
   class="kw">private float inverseMaxSectionsPerSecond;
   class="kw">private int maxSectionsPerTick;
   class="kw">private int minLoadedRadius;
   class="kw">private int maxHotLoadedRadius;
   class="kw">private int maxHotLoadedRadiusSq;
   class="kw">private float accumulatorSeconds;
   class="kw">private int sentViewRadiusSq;
   class="kw">private int hotRadiusSq;
   class="kw">private int lastChunkX;
   class="kw">private int lastChunkY;
   class="kw">private int lastChunkZ;
   class="kw">private boolean readyForChunks;

   class="kw">public class="kw">static ComponentType<EntityStore, ChunkTracker> getComponentType() {
      class="kw">return EntityModule.get().getChunkTrackerComponentType();
   }

   class="kw">public ChunkTracker() {
      this(() -> HytaleServer.get().getConfig().getMaxViewSphereOffsets());
   }

   class="kw">public ChunkTracker(@Nonnull Supplier<SphereOffsets> var1) {
      this.sphereOffsetsSupplier = var1;
      this.spiralIterator = new SphereSpiralIterator(var1.get());
      this.minLoadedRadius = 2;
      this.maxHotLoadedRadius = 8;
      this.maxHotLoadedRadiusSq = 64;
      this.maxSectionsPerTick = 40;
   }

   class="kw">private ChunkTracker(@Nonnull ChunkTracker var1) {
      this.sphereOffsetsSupplier = var1.sphereOffsetsSupplier;
      this.spiralIterator = new SphereSpiralIterator(this.sphereOffsetsSupplier.get());
      this.copyFrom(var1);
   }

   class="kw">public void clear() {
      long var1 = this.lock.writeLock();

      try {
         this.resetState();
      } class="kw">finally {
         this.lock.unlockWrite(var1);
      }
   }

   class="kw">private void resetState() {
      this.trackedColumns.clear();
      this.reloadingSections.clear();
      this.pendingAbsentByColumn.clear();
      this.hasPendingAbsent = false;
      this.loadingSections = 0;
      this.sentViewRadiusSq = 0;
      this.hotRadiusSq = 0;
   }

   class="kw">private void flushPendingAbsent(@Nonnull PlayerRef var1) {
      if (this.pendingAbsentByColumn.isEmpty()) {
         this.hasPendingAbsent = false;
      } else {
         PacketHandler var2 = var1.getPacketHandler();
         ObjectIterator var3 = Long2ObjectMaps.fastIterator(this.pendingAbsentByColumn);

         while (var3.hasNext()) {
            Entry var4 = (Entry<IntArrayList>)var3.next();
            long var5 = var4.getLongKey();
            if (this.trackedColumns.containsKey(var5)) {
               int var7 = ChunkUtil.xOfChunkIndex(var5);
               int var8 = ChunkUtil.zOfChunkIndex(var5);
               IntArrayList var9 = (IntArrayList)var4.getValue();
               int[] var10 = var9.elements();
               int var11 = var9.size();

               for (int var12 = 0; var12 < var11; var12 += 128) {
                  int var13 = Math.min(var12 + 128, var11);
                  var2.writeNoCache(new SetAbsentChunks(var7, var8, Arrays.copyOfRange(var10, var12, var13)));
               }
            }
         }

         this.pendingAbsentByColumn.clear();
         this.hasPendingAbsent = false;
      }
   }

   class="kw">private void flushUnloads(@Nonnull PlayerRef var1) {
      PacketHandler var2 = var1.getPacketHandler();
      int var3 = this.unloadSectionScratch.size();
      if (var3 > 0) {
         int[] var4 = this.unloadSectionScratch.elements();

         for (int var5 = 0; var5 < var3; var5 += 12288) {
            int var6 = Math.min(var5 + 12288, var3);
            var2.writeNoCache(new UnloadChunks(Arrays.copyOfRange(var4, var5, var6), null));
         }
      }

      int var8 = this.unloadColumnScratch.size();
      if (var8 > 0) {
         int[] var9 = this.unloadColumnScratch.elements();

         for (int var10 = 0; var10 < var8; var10 += 8192) {
            int var7 = Math.min(var10 + 8192, var8);
            var2.writeNoCache(new UnloadChunks(null, Arrays.copyOfRange(var9, var10, var7)));
         }
      }
   }

   class="kw">public void tick(@Nonnull Player var1, @Nonnull PlayerRef var2, @Nonnull TransformComponent var3, float var4, @Nonnull CommandBuffer<EntityStore> var5) {
      if (this.readyForChunks && var2.getPacketHandler().getChannel(NetworkChannel.Chunks).isWritable()) {
         this.transformComponent = var3;
         int var6 = this.sectionViewRadius = var1.getViewRadius();
         Vector3d var7 = var3.getPosition();
         int var8 = MathUtil.floor(var7.x()) >> 5;
         int var9 = MathUtil.floor(var7.y()) >> 5;
         int var10 = MathUtil.floor(var7.z()) >> 5;
         int var11 = var6 * var6;
         int var12 = this.lastChunkX - var8;
         int var13 = this.lastChunkY - var9;
         int var14 = this.lastChunkZ - var10;
         int var15 = (int)Math.ceil(Math.sqrt(var12 * var12 + var13 * var13 + var14 * var14));
         if (var15 > 0) {
            int var16 = Math.min((int)Math.sqrt(this.sentViewRadiusSq), var6);
            int var17 = Math.max(0, var16 - var15);
            this.sentViewRadiusSq = var17 * var17;
            int var18 = Math.min(this.maxHotLoadedRadius, var6);
            int var19 = Math.min((int)Math.sqrt(this.hotRadiusSq), var18);
            int var20 = Math.max(0, var19 - var15);
            this.hotRadiusSq = var20 * var20;
         }

         this.lastChunkX = var8;
         this.lastChunkY = var9;
         this.lastChunkZ = var10;
         int var46 = Math.min(this.maxHotLoadedRadius, var6);
         int var47 = var46 * var46;
         boolean var48 = this.sentViewRadiusSq > var11 + 1;
         if (var48) {
            this.sentViewRadiusSq = var11 + 1;
         }

         if (this.hotRadiusSq > var47 + 1) {
            this.hotRadiusSq = var47 + 1;
         }

         if (var48 || this.sentViewRadiusSq <= var11 || this.hotRadiusSq <= var47 || !this.reloadingSections.isEmpty() || this.hasPendingAbsent) {
            World var49 = var5.getExternalData().getWorld();
            ChunkStore var50 = var49.getChunkStore();
            boolean var21 = var50.supportsCubicSections();
            long var22 = this.lock.writeLock();

            try {
               if (var6 > this.spiralIterator.sharedOffsets().maxR) {
                  SphereSpiralIterator var24 = new SphereSpiralIterator(this.sphereOffsetsSupplier.get());
                  var24.configure(var6);
                  this.spiralIterator = var24;
               } else {
                  this.spiralIterator.configure(var6);
               }

               this.flushPendingAbsent(var2);
               this.unloadSectionScratch.clear();
               this.unloadColumnScratch.clear();
               ObjectIterator var51 = Long2ObjectMaps.fastIterator(this.trackedColumns);

               while (var51.hasNext()) {
                  if (this.tryUnloadColumn((Entry<ChunkTracker.TrackedColumn>)var51.next(), var11, var8, var9, var10, var2)) {
                     var51.remove();
                  }
               }

               this.flushUnloads(var2);
               this.accumulatorSeconds += var4;
               int var25 = Math.min((int)(this.maxSectionsPerSecond * this.accumulatorSeconds), this.maxSectionsPerTick);
               var25 -= this.loadingSections;
               if (var25 > 0 && !this.reloadingSections.isEmpty()) {
                  this.reloadContext.budget = var25;
                  this.reloadContext.chunkStore = var50;
                  this.reloadContext.playerRef = var2;
                  this.reloadContext.transform = var3;
                  this.reloadContext.commandBuffer = var5;
                  this.reloadingSections.removeIf(ChunkTracker::reloadSection, 0, 0, 0, this, this.reloadContext);
                  var25 = this.reloadContext.budget;
                  this.reloadContext.clear();
               }

               if (this.sentViewRadiusSq <= var11) {
                  boolean var26 = true;
                  this.spiralIterator.init(var8, var9, var10, this.sentViewRadiusSq, var11);

                  while (var25 > 0 && this.spiralIterator.advance()) {
                     SpherePosition var27 = this.spiralIterator.position();
                     if (var21 || var27.y >= 0 && var27.y < 10) {
                        long var28 = ChunkUtil.indexChunk(var27.x, var27.z);
                        ChunkTracker.TrackedColumn var30 = (ChunkTracker.TrackedColumn)this.trackedColumns
                           .computeIfAbsent(var28, var0 -> new ChunkTracker.TrackedColumn());
                        if (var30.state == ChunkTracker.ColumnState.NONE) {
                           if (var50.isChunkOnBackoff(var28, MAX_FAILURE_BACKOFF_NANOS)) {
                              var26 = false;
                              class="kw">continue;
                           }

                           this.tryLoadColumnAsync(var50, var2, var28, var3, var5);
                           var30.state = ChunkTracker.ColumnState.LOADING;
                        }

                        if (var30.state == ChunkTracker.ColumnState.LOADING) {
                           var26 = false;
                           if (var30.pendingSections.add(var27.y)) {
                              var25--;
                           }
                        } else if (!var30.loadedSections.contains(var27.y)) {
                           if (var50.isChunkSectionOnBackoff(var27.x, var27.y, var27.z, MAX_FAILURE_BACKOFF_NANOS)) {
                              var26 = false;
                           } else {
                              var26 = false;
                              var30.pendingSections.remove(var27.y);
                              if (var30.loadingSections.add(var27.y)) {
                                 this.loadingSections++;
                                 var25--;
                                 this.accumulatorSeconds = this.accumulatorSeconds - this.inverseMaxSectionsPerSecond;
                                 this.tryLoadSectionAsync(var50, var2, var27.x, var27.y, var27.z, var3, var5);
                              }
                           }
                        }
                     }
                  }

                  if (var26) {
                     this.sentViewRadiusSq = this.spiralIterator.getCompletedDistSq() + 1;
                  }
               }
            } class="kw">finally {
               this.lock.unlockWrite(var22);
            }

            if (this.hotRadiusSq <= var47) {
               ComponentType var52 = ChunkStore.REGISTRY.getNonTickingComponentType();
               ComponentType var54 = WorldChunk.getComponentType();
               Store var55 = var50.getStore();
               long var56 = this.lock.readLock();

               try {
                  this.spiralIterator.init(var8, var9, var10, this.hotRadiusSq, var47);

                  while (this.spiralIterator.advance()) {
                     SpherePosition var29 = this.spiralIterator.position();
                     int var57 = var29.x;
                     int var31 = var29.y;
                     int var32 = var29.z;
                     long var33 = ChunkUtil.indexChunk(var57, var32);
                     ChunkTracker.TrackedColumn var35 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var33);
                     if (var35 != null && var35.loadedSections.contains(var31)) {
                        Ref var36 = var50.getChunkSectionReference(var57, var31, var32);
                        if (var36 != null && var36.isValid()) {
                           if (var55.<NonTicking<ChunkStore>>getComponent(var36, var52) != null) {
                              var5.run(var3x -> var55.tryRemoveComponent(var36, var52));
                           }

                           Ref var37 = var50.getChunkReference(var33);
                           if (var37 != null && var37.isValid()) {
                              WorldChunk var38 = var55.getComponent(var37, var54);
                              if (var38 != null && !var38.is(ChunkFlag.TICKING)) {
                                 var5.run(var1x -> var38.setFlag(ChunkFlag.TICKING, true));
                              }
                           }
                        }
                     }
                  }
               } class="kw">finally {
                  this.lock.unlockRead(var56);
               }

               this.hotRadiusSq = var47 + 1;
            }

            if (this.sentViewRadiusSq > var11) {
               this.accumulatorSeconds = 0.0F;
            }
         }
      }
   }

   class="kw">public boolean isLoaded(long var1) {
      long var3 = this.lock.readLock();

      try {
         ChunkTracker.TrackedColumn var5 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var1);
         class="kw">return var5 != null && var5.state == ChunkTracker.ColumnState.READY;
      } class="kw">finally {
         this.lock.unlockRead(var3);
      }
   }

   class="kw">public boolean isLoaded(int var1, int var2, int var3) {
      long var4 = this.lock.readLock();

      try {
         ChunkTracker.TrackedColumn var6 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(ChunkUtil.indexChunk(var1, var3));
         class="kw">return var6 != null && var6.state == ChunkTracker.ColumnState.READY && var6.loadedSections.contains(var2);
      } class="kw">finally {
         this.lock.unlockRead(var4);
      }
   }

   @Deprecated(forRemoval = true)
   class="kw">public void removeForReload(long var1) {
      long var3 = this.lock.writeLock();

      try {
         ChunkTracker.TrackedColumn var5 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var1);
         if (var5 == null) {
            class="kw">return;
         }

         int var6 = ChunkUtil.xOfChunkIndex(var1);
         int var7 = ChunkUtil.zOfChunkIndex(var1);
         IntIterator var8 = var5.loadedSections.iterator();

         while (var8.hasNext()) {
            Integer var9 = (Integer)var8.next();
            this.reloadingSections.add(var6, var9, var7);
         }
      } class="kw">finally {
         this.lock.unlockWrite(var3);
      }
   }

   class="kw">public void removeForReload(int var1, int var2, int var3) {
      if (this.shouldBeVisible(var1, var2, var3)) {
         long var4 = this.lock.writeLock();

         try {
            this.reloadingSections.add(var1, var2, var3);
         } class="kw">finally {
            this.lock.unlockWrite(var4);
         }
      }
   }

   class="kw">public boolean shouldBeVisible(long var1) {
      if (this.transformComponent == null) {
         class="kw">return false;
      }

      Vector3d var3 = this.transformComponent.getPosition();
      int var4 = MathUtil.floor(var3.x()) >> 5;
      int var5 = MathUtil.floor(var3.z()) >> 5;
      int var6 = ChunkUtil.xOfChunkIndex(var1);
      int var7 = ChunkUtil.zOfChunkIndex(var1);
      int var8 = Math.max(this.minLoadedRadius, this.sectionViewRadius);
      class="kw">return shouldBeVisible(var8 * var8, var4, var5, var6, var7);
   }

   class="kw">public boolean shouldBeVisible(int var1, int var2, int var3) {
      if (this.transformComponent == null) {
         class="kw">return false;
      }

      Vector3d var4 = this.transformComponent.getPosition();
      int var5 = MathUtil.floor(var4.x()) >> 5;
      int var6 = MathUtil.floor(var4.y()) >> 5;
      int var7 = MathUtil.floor(var4.z()) >> 5;
      class="kw">return this.spiralIterator.containsOffset(var1 - var5, var2 - var6, var3 - var7);
   }

   @Nonnull
   class="kw">public ChunkTracker.ChunkVisibility getChunkVisibility(long var1) {
      if (this.transformComponent == null) {
         class="kw">return ChunkTracker.ChunkVisibility.NONE;
      } else {
         Vector3d var3 = this.transformComponent.getPosition();
         int var4 = MathUtil.floor(var3.x()) >> 5;
         int var5 = MathUtil.floor(var3.z()) >> 5;
         int var6 = ChunkUtil.xOfChunkIndex(var1);
         int var7 = ChunkUtil.zOfChunkIndex(var1);
         int var8 = Math.abs(var6 - var4);
         int var9 = Math.abs(var7 - var5);
         int var10 = var8 * var8 + var9 * var9;
         int var11 = Math.max(this.minLoadedRadius, this.sectionViewRadius);
         boolean var12 = var10 <= var11 * var11;
         if (var12) {
            boolean var13 = var10 <= this.maxHotLoadedRadiusSq;
            class="kw">return var13 ? ChunkTracker.ChunkVisibility.HOT : ChunkTracker.ChunkVisibility.COLD;
         } else {
            class="kw">return ChunkTracker.ChunkVisibility.NONE;
         }
      }
   }

   @Nonnull
   class="kw">public ChunkTracker.ChunkVisibility getSectionVisibility(int var1, int var2, int var3) {
      if (this.transformComponent == null) {
         class="kw">return ChunkTracker.ChunkVisibility.NONE;
      }

      Vector3d var4 = this.transformComponent.getPosition();
      int var5 = MathUtil.floor(var4.x()) >> 5;
      int var6 = MathUtil.floor(var4.y()) >> 5;
      int var7 = MathUtil.floor(var4.z()) >> 5;
      int var8 = var1 - var5;
      int var9 = var2 - var6;
      int var10 = var3 - var7;
      if (!this.spiralIterator.containsOffset(var8, var9, var10)) {
         class="kw">return ChunkTracker.ChunkVisibility.NONE;
      }

      int var11 = var8 * var8 + var9 * var9 + var10 * var10;
      class="kw">return var11 <= this.maxHotLoadedRadiusSq ? ChunkTracker.ChunkVisibility.HOT : ChunkTracker.ChunkVisibility.COLD;
   }

   class="kw">public int getMaxSectionsPerSecond() {
      class="kw">return this.maxSectionsPerSecond;
   }

   class="kw">public void setMaxSectionsPerSecond(int var1) {
      this.maxSectionsPerSecond = var1;
      this.inverseMaxSectionsPerSecond = 1.0F / var1;
   }

   class="kw">public void setDefaultMaxSectionsPerSecond(@Nonnull PlayerRef var1) {
      if (var1.getPacketHandler().isLocalConnection()) {
         this.maxSectionsPerSecond = 2560;
      } else if (var1.getPacketHandler().isLANConnection()) {
         this.maxSectionsPerSecond = 1280;
      } else {
         this.maxSectionsPerSecond = 360;
      }

      this.inverseMaxSectionsPerSecond = 1.0F / this.maxSectionsPerSecond;
   }

   class="kw">public int getMaxSectionsPerTick() {
      class="kw">return this.maxSectionsPerTick;
   }

   class="kw">public void setMaxSectionsPerTick(int var1) {
      this.maxSectionsPerTick = var1;
   }

   class="kw">public int getMinLoadedRadius() {
      class="kw">return this.minLoadedRadius;
   }

   class="kw">public void setMinLoadedRadius(int var1) {
      this.minLoadedRadius = var1;
   }

   class="kw">public int getMaxHotLoadedRadius() {
      class="kw">return this.maxHotLoadedRadius;
   }

   class="kw">public void setMaxHotLoadedRadius(int var1) {
      this.maxHotLoadedRadius = var1;
      this.maxHotLoadedRadiusSq = var1 * var1;
   }

   class="kw">public int getLoadedSectionsCount() {
      long var1 = this.lock.readLock();

      try {
         int var3 = 0;
         ObjectIterator var4 = this.trackedColumns.values().iterator();

         while (var4.hasNext()) {
            ChunkTracker.TrackedColumn var5 = (ChunkTracker.TrackedColumn)var4.next();
            var3 += var5.loadedSections.size();
         }

         class="kw">return var3;
      } class="kw">finally {
         this.lock.unlockRead(var1);
      }
   }

   class="kw">public void forEachLoadedSection(@Nonnull TriIntConsumer var1) {
      long var2 = this.lock.readLock();

      try {
         ObjectIterator var4 = Long2ObjectMaps.fastIterator(this.trackedColumns);

         while (var4.hasNext()) {
            Entry var5 = (Entry<ChunkTracker.TrackedColumn>)var4.next();
            ChunkTracker.TrackedColumn var6 = (ChunkTracker.TrackedColumn)var5.getValue();
            if (!var6.loadedSections.isEmpty()) {
               int var7 = ChunkUtil.xOfChunkIndex(var5.getLongKey());
               int var8 = ChunkUtil.zOfChunkIndex(var5.getLongKey());
               IntIterator var9 = var6.loadedSections.iterator();

               while (var9.hasNext()) {
                  var1.accept(var7, var9.nextInt(), var8);
               }
            }
         }
      } class="kw">finally {
         this.lock.unlockRead(var2);
      }
   }

   class="kw">public int getLoadingSectionsCount() {
      long var1 = this.lock.tryOptimisticRead();
      int var3 = this.loadingSections;
      if (this.lock.validate(var1)) {
         class="kw">return var3;
      }

      var1 = this.lock.readLock();

      try {
         class="kw">return this.loadingSections;
      } class="kw">finally {
         this.lock.unlockRead(var1);
      }
   }

   @Nonnull
   class="kw">public String getLoadedChunksDebug() {
      long var1 = this.lock.readLock();

      try {
         StringBuilder var3 = new StringBuilder();
         if (this.transformComponent == null) {
            var3.append("Tracker not yet ticked");
            class="kw">return var3.toString();
         }

         Vector3d var4 = this.transformComponent.getPosition();
         int var5 = MathUtil.floor(var4.x()) >> 5;
         int var6 = MathUtil.floor(var4.y()) >> 5;
         int var7 = MathUtil.floor(var4.z()) >> 5;
         int var8 = 0;
         int var9 = 0;
         ObjectIterator var10 = Long2ObjectMaps.fastIterator(this.trackedColumns);

         while (var10.hasNext()) {
            Entry var11 = (Entry<ChunkTracker.TrackedColumn>)var10.next();
            ChunkTracker.TrackedColumn var12 = (ChunkTracker.TrackedColumn)var11.getValue();
            var8 += var12.loadedSections.size();
            int var13 = ChunkUtil.xOfChunkIndex(var11.getLongKey());
            int var14 = ChunkUtil.zOfChunkIndex(var11.getLongKey());
            IntIterator var15 = var12.loadedSections.iterator();

            while (var15.hasNext()) {
               if (this.getSectionVisibility(var13, var15.nextInt(), var14) == ChunkTracker.ChunkVisibility.HOT) {
                  var9++;
               }
            }
         }

         var3.append("Player chunk: (").append(var5).append(", ").append(var6).append(", ").append(var7).append(")\n");
         var3.append("View radius: ").append(this.sectionViewRadius).append('\n');
         var3.append("Sent radius sq: ").append(this.sentViewRadiusSq).append('\n');
         var3.append("Hot radius sq: ").append(this.hotRadiusSq).append('\n');
         var3.append("Ready for chunks: ").append(this.readyForChunks).append('\n');
         var3.append("Tracked columns: ").append(this.trackedColumns.size()).append('\n');
         var3.append("Loaded sections: ").append(var8).append('\n');
         var3.append("Hot sections: ").append(var9).append('\n');
         var3.append("\nLoaded sections per column (top-down):\n");
         this.appendColumnGrid(var3, var5, var7, false);
         var3.append("\nHot sections per column (top-down):\n");
         this.appendColumnGrid(var3, var5, var7, true);
         class="kw">return var3.toString();
      } class="kw">finally {
         this.lock.unlockRead(var1);
      }
   }

   class="kw">private void appendColumnGrid(@Nonnull StringBuilder var1, int var2, int var3, boolean var4) {
      int var5 = this.sectionViewRadius;

      for (int var6 = var3 - var5; var6 <= var3 + var5; var6++) {
         for (int var7 = var2 - var5; var7 <= var2 + var5; var7++) {
            ChunkTracker.TrackedColumn var8 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(ChunkUtil.indexChunk(var7, var6));
            if (var8 == null) {
               var1.append(" . ");
            } else {
               int var9;
               if (var4) {
                  var9 = 0;
                  IntIterator var10 = var8.loadedSections.iterator();

                  while (var10.hasNext()) {
                     if (this.getSectionVisibility(var7, var10.nextInt(), var6) == ChunkTracker.ChunkVisibility.HOT) {
                        var9++;
                     }
                  }
               } else {
                  var9 = var8.loadedSections.size();
               }

               var1.append(String.format("%2d ", var9));
            }
         }

         var1.append('\n');
      }
   }

   class="kw">public void setReadyForChunks(boolean var1) {
      this.readyForChunks = var1;
   }

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

   class="kw">public void copyFrom(@Nonnull ChunkTracker var1) {
      long var2 = this.lock.writeLock();

      try {
         long var4 = var1.lock.readLock();

         try {
            this.resetState();
            ObjectIterator var6 = var1.trackedColumns.long2ObjectEntrySet().iterator();

            while (var6.hasNext()) {
               Entry var7 = (Entry<ChunkTracker.TrackedColumn>)var6.next();
               ChunkTracker.TrackedColumn var8 = (ChunkTracker.TrackedColumn)var7.getValue();
               if (var8.state == ChunkTracker.ColumnState.READY) {
                  ChunkTracker.TrackedColumn var9 = new ChunkTracker.TrackedColumn();
                  var9.state = ChunkTracker.ColumnState.READY;
                  var9.loadedSections.addAll(var8.loadedSections);
                  this.trackedColumns.put(var7.getLongKey(), var9);
               }
            }

            var1.reloadingSections.forEach((var1x, var2x, var3) -> this.reloadingSections.add(var1x, var2x, var3));
         } class="kw">finally {
            var1.lock.unlockRead(var4);
         }
      } class="kw">finally {
         this.lock.unlockWrite(var2);
      }
   }

   class="kw">private class="kw">static boolean shouldBeVisible(int var0, int var1, int var2, int var3, int var4) {
      int var5 = Math.abs(var3 - var1);
      int var6 = Math.abs(var4 - var2);
      int var7 = var5 * var5 + var6 * var6;
      class="kw">return var7 <= var0;
   }

   class="kw">private boolean tryUnloadColumn(Entry<ChunkTracker.TrackedColumn> var1, int var2, int var3, int var4, int var5, PlayerRef var6) {
      long var7 = var1.getLongKey();
      ChunkTracker.TrackedColumn var9 = (ChunkTracker.TrackedColumn)var1.getValue();
      int var10 = ChunkUtil.xOfChunkIndex(var7);
      int var11 = ChunkUtil.zOfChunkIndex(var7);
      if (!var9.pendingSections.isEmpty()) {
         IntIterator var12 = var9.pendingSections.iterator();

         while (var12.hasNext()) {
            int var13 = var12.nextInt();
            if (!this.spiralIterator.containsOffset(var10 - var3, var13 - var4, var11 - var5)) {
               var12.remove();
            }
         }
      }

      if (!var9.loadingSections.isEmpty()) {
         IntIterator var21 = var9.loadingSections.iterator();

         while (var21.hasNext()) {
            int var24 = var21.nextInt();
            if (!this.spiralIterator.containsOffset(var10 - var3, var24 - var4, var11 - var5)) {
               var21.remove();
               this.loadingSections--;
            }
         }
      }

      if (!var9.loadedSections.isEmpty()) {
         IntIterator var22 = var9.loadedSections.iterator();

         while (var22.hasNext()) {
            int var25 = var22.nextInt();
            if (this.tryUnloadSection(var10, var25, var11, var3, var4, var5, var6)) {
               var22.remove();
            }
         }
      }

      if (shouldBeVisible(var2, var10, var11, var3, var5)) {
         class="kw">return false;
      }

      if (!var9.pendingSections.isEmpty() || !var9.loadingSections.isEmpty() || !var9.loadedSections.isEmpty()) {
         class="kw">return false;
      }

      if (var9.state != ChunkTracker.ColumnState.READY) {
         class="kw">return true;
      }

      Ref var23 = var6.getReference();
      if (var23 != null && var23.isValid()) {
         Store var26 = var23.getStore();
         World var14 = var26.getExternalData().getWorld();
         PacketHandler var15 = var6.getPacketHandler();
         ChunkStore var16 = var14.getChunkStore();
         Ref var17 = var16.getChunkReference(var7);
         if (var17 != null) {
            Store var18 = var16.getStore();
            ObjectArrayList var19 = new ObjectArrayList();
            var18.fetch(Collections.singletonList(var17), ChunkStore.UNLOAD_PACKETS_DATA_QUERY_SYSTEM_TYPE, var6, var19);

            for (int var20 = 0; var20 < var19.size(); var20++) {
               var15.write((ToClientPacket)var19.get(var20));
            }
         }

         this.unloadColumnScratch.add(var10);
         this.unloadColumnScratch.add(var11);
         class="kw">return true;
      } else {
         class="kw">return true;
      }
   }

   class="kw">private boolean tryUnloadSection(int var1, int var2, int var3, int var4, int var5, int var6, @Nonnull PlayerRef var7) {
      if (this.spiralIterator.containsOffset(var1 - var4, var2 - var5, var3 - var6)) {
         class="kw">return false;
      }

      Ref var8 = var7.getReference();
      if (var8 != null && var8.isValid()) {
         Store var9 = var8.getStore();
         World var10 = var9.getExternalData().getWorld();
         PacketHandler var11 = var7.getPacketHandler();
         ChunkStore var12 = var10.getChunkStore();
         Ref var13 = var12.getChunkSectionReference(var1, var2, var3);
         if (var13 != null) {
            Store var14 = var12.getStore();
            ObjectArrayList var15 = new ObjectArrayList();
            var14.fetch(Collections.singletonList(var13), ChunkStore.UNLOAD_PACKETS_DATA_QUERY_SYSTEM_TYPE, var7, var15);

            for (int var16 = 0; var16 < var15.size(); var16++) {
               var11.write((ToClientPacket)var15.get(var16));
            }
         }

         this.unloadSectionScratch.add(var1);
         this.unloadSectionScratch.add(var2);
         this.unloadSectionScratch.add(var3);
         class="kw">return true;
      } else {
         class="kw">return true;
      }
   }

   class="kw">public void tryLoadColumnAsync(
      @Nonnull ChunkStore var1, @Nonnull PlayerRef var2, long var3, @Nonnull TransformComponent var5, @Nonnull ComponentAccessor<EntityStore> var6
   ) {
      World var7 = var6.getExternalData().getWorld();
      Vector3d var8 = var5.getPosition();
      int var9 = MathUtil.floor(var8.x()) >> 5;
      int var10 = MathUtil.floor(var8.z()) >> 5;
      int var11 = ChunkUtil.xOfChunkIndex(var3);
      int var12 = ChunkUtil.zOfChunkIndex(var3);
      boolean var13 = shouldBeVisible(this.maxHotLoadedRadiusSq, var9, var10, var11, var12);
      Ref var14 = var1.getChunkReference(var3);
      if (var14 != null) {
         WorldChunk var15 = var1.getStore().getComponent(var14, WorldChunk.getComponentType());
         assert var15 != null;
         if (var15.is(ChunkFlag.TICKING)) {
            this._loadChunkAsync(var3, var2, var14, var1).exceptionallyAsync(var3x -> this.columnLoadFailed(var3, var3x));
            class="kw">return;
         }
      }

      int var16 = -2147483632;
      if (var13) {
         var16 |= 4;
      }

      var1.getChunkReferenceAsync(var3, var16).thenComposeAsync(var5x -> {
         if (var5x != null && var5x.isValid()) {
            long var17 = this.lock.readLock();

            try {
               if (!this.trackedColumns.containsKey(var3)) {
                  class="kw">return CompletableFuture.completedFuture(null);
               }
            } class="kw">finally {
               this.lock.unlockRead(var17);
            }

            class="kw">return this._loadChunkAsync(var3, var2, (Ref<ChunkStore>)var5x, var1);
         } else {
            long var6 = this.lock.writeLock();

            try {
               ChunkTracker.TrackedColumn var8 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var3);
               if (var8 != null) {
                  var8.state = ChunkTracker.ColumnState.READY;
                  var8.pendingSections.clear();
               }
            } class="kw">finally {
               this.lock.unlockWrite(var6);
            }

            class="kw">return CompletableFuture.completedFuture(null);
         }
      }, var7).exceptionallyAsync(var3x -> this.columnLoadFailed(var3, var3x));
   }

   @Nullable
   class="kw">private Void columnLoadFailed(long var1, @Nonnull Throwable var3) {
      long var4 = this.lock.writeLock();

      try {
         ChunkTracker.TrackedColumn var6 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var1);
         if (var6 != null) {
            var6.state = ChunkTracker.ColumnState.NONE;
         }
      } class="kw">finally {
         this.lock.unlockWrite(var4);
      }

      ((HytaleLogger.Api)HytaleLogger.getLogger().at(Level.SEVERE).withCause(var3))
         .log("Failed to load chunk! %d, %d", ChunkUtil.xOfChunkIndex(var1), ChunkUtil.zOfChunkIndex(var1));
      class="kw">return null;
   }

   @Nonnull
   class="kw">private CompletableFuture<Void> _loadChunkAsync(long var1, @Nonnull PlayerRef var3, @Nonnull Ref<ChunkStore> var4, @Nonnull ChunkStore var5) {
      List var6 = new ObjectArrayList();
      var5.getStore().fetch(Collections.singletonList(var4), ChunkStore.LOAD_PACKETS_DATA_QUERY_SYSTEM_TYPE, var3, var6);
      ObjectArrayList var7 = new ObjectArrayList();
      var5.getStore().fetch(Collections.singletonList(var4), ChunkStore.LOAD_FUTURE_PACKETS_DATA_QUERY_SYSTEM_TYPE, var3, var7);
      class="kw">return CompletableFuture.allOf((CompletableFuture<?>[])var7.toArray(CompletableFuture[]::new)).thenAcceptAsync(var6x -> {
         Iterator var7 = var7.iterator();

         while (var7.hasNext()) {
            CompletableFuture var8 = (CompletableFuture<ToClientPacket>)var7.next();
            ToClientPacket var9 = var8.join();
            if (var9 != null) {
               var6.add(var9);
            }
         }

         long var14 = this.lock.writeLock();

         try {
            ChunkTracker.TrackedColumn var15 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var1);
            if (var15 != null) {
               for (int var10 = 0; var10 < var6.size(); var10++) {
                  var3.getPacketHandler().write(var6.get(var10));
               }

               var15.state = ChunkTracker.ColumnState.READY;
            }
         } class="kw">finally {
            this.lock.unlockWrite(var14);
         }
      });
   }

   class="kw">private class="kw">static boolean reloadSection(
      int var0, int var1, int var2, int var3, int var4, int var5, @Nonnull ChunkTracker var6, @Nonnull ChunkTracker.ReloadContext var7
   ) {
      if (var7.budget <= 0) {
         class="kw">return false;
      }

      long var8 = ChunkUtil.indexChunk(var0, var2);
      ChunkTracker.TrackedColumn var10 = (ChunkTracker.TrackedColumn)var6.trackedColumns.get(var8);
      if (var10 == null) {
         class="kw">return true;
      }

      if (var10.loadingSections.contains(var1) || var10.pendingSections.contains(var1)) {
         class="kw">return true;
      }

      if (!var10.loadedSections.contains(var1)) {
         class="kw">return true;
      }

      var10.loadedSections.remove(var1);
      var10.loadingSections.add(var1);
      var6.loadingSections++;
      var7.budget--;
      var6.accumulatorSeconds = var6.accumulatorSeconds - var6.inverseMaxSectionsPerSecond;
      var6.tryLoadSectionAsync(var7.chunkStore, var7.playerRef, var0, var1, var2, var7.transform, var7.commandBuffer);
      class="kw">return true;
   }

   class="kw">public void tryLoadSectionAsync(
      @Nonnull ChunkStore var1,
      @Nonnull PlayerRef var2,
      int var3,
      int var4,
      int var5,
      @Nonnull TransformComponent var6,
      @Nonnull ComponentAccessor<EntityStore> var7
   ) {
      World var8 = var7.getExternalData().getWorld();
      long var9 = ChunkUtil.indexChunk(var3, var5);
      Vector3d var11 = var6.getPosition();
      int var12 = MathUtil.floor(var11.x()) >> 5;
      int var13 = MathUtil.floor(var11.y()) >> 5;
      int var14 = MathUtil.floor(var11.z()) >> 5;
      int var15 = var3 - var12;
      int var16 = var4 - var13;
      int var17 = var5 - var14;
      boolean var18 = var15 * var15 + var16 * var16 + var17 * var17 <= this.maxHotLoadedRadiusSq;
      Ref var19 = var1.getChunkSectionReference(var3, var4, var5);
      if (var19 != null && var19.isValid()) {
         Store var20 = var1.getStore();
         if (var20.<NonTicking<ChunkStore>>getComponent(var19, ChunkStore.REGISTRY.getNonTickingComponentType()) == null) {
            this._loadSectionAsync(var3, var4, var5, var2, var19, var1).exceptionallyAsync(var6x -> this.sectionLoadFailed(var9, var3, var4, var5, var6x));
            class="kw">return;
         }
      }

      int var21 = -2147483632;
      if (var18) {
         var21 |= 4;
      }

      var1.getChunkSectionReferenceAsync(var3, var4, var5, var21).thenComposeAsync(var8x -> {
         if (var8x != null && var8x.isValid()) {
            long var20 = this.lock.readLock();

            try {
               ChunkTracker.TrackedColumn var21 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var9);
               if (var21 == null || !var21.loadingSections.contains(var4)) {
                  class="kw">return CompletableFuture.completedFuture(null);
               }
            } class="kw">finally {
               this.lock.unlockRead(var20);
            }

            class="kw">return this._loadSectionAsync(var3, var4, var5, var2, (Ref<ChunkStore>)var8x, var1);
         } else {
            long var9 = this.lock.writeLock();

            try {
               ChunkTracker.TrackedColumn var11 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var9);
               if (var11 != null && var11.loadingSections.remove(var4)) {
                  this.loadingSections--;
                  var11.loadedSections.add(var4);
                  ((IntArrayList)this.pendingAbsentByColumn.computeIfAbsent(var9, var0 -> new IntArrayList())).add(var4);
                  this.hasPendingAbsent = true;
               }
            } class="kw">finally {
               this.lock.unlockWrite(var9);
            }

            class="kw">return CompletableFuture.completedFuture(null);
         }
      }, var8).exceptionallyAsync(var6x -> this.sectionLoadFailed(var9, var3, var4, var5, var6x));
   }

   @Nullable
   class="kw">private Void sectionLoadFailed(long var1, int var3, int var4, int var5, @Nonnull Throwable var6) {
      long var7 = this.lock.writeLock();

      try {
         ChunkTracker.TrackedColumn var9 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var1);
         if (var9 != null && var9.loadingSections.remove(var4)) {
            this.loadingSections--;
         }
      } class="kw">finally {
         this.lock.unlockWrite(var7);
      }

      ((HytaleLogger.Api)HytaleLogger.getLogger().at(Level.SEVERE).withCause(var6)).log("Failed to load chunk section! %d, %d, %d", var3, var4, var5);
      class="kw">return null;
   }

   @Nonnull
   class="kw">private CompletableFuture<Void> _loadSectionAsync(
      int var1, int var2, int var3, @Nonnull PlayerRef var4, @Nonnull Ref<ChunkStore> var5, @Nonnull ChunkStore var6
   ) {
      long var7 = ChunkUtil.indexChunk(var1, var3);
      List var9 = new ObjectArrayList();
      var6.getStore().fetch(Collections.singletonList(var5), ChunkStore.LOAD_PACKETS_DATA_QUERY_SYSTEM_TYPE, var4, var9);
      ObjectArrayList var10 = new ObjectArrayList();
      var6.getStore().fetch(Collections.singletonList(var5), ChunkStore.LOAD_FUTURE_PACKETS_DATA_QUERY_SYSTEM_TYPE, var4, var10);
      class="kw">return CompletableFuture.allOf((CompletableFuture<?>[])var10.toArray(CompletableFuture[]::new)).thenAcceptAsync(var7x -> {
         Iterator var8 = var10.iterator();

         while (var8.hasNext()) {
            CompletableFuture var9 = (CompletableFuture<ToClientPacket>)var8.next();
            ToClientPacket var10 = var9.join();
            if (var10 != null) {
               var9.add(var10);
            }
         }

         long var15 = this.lock.writeLock();

         try {
            ChunkTracker.TrackedColumn var16 = (ChunkTracker.TrackedColumn)this.trackedColumns.get(var7);
            if (var16 != null && var16.loadingSections.remove(var2)) {
               this.loadingSections--;

               for (int var11 = 0; var11 < var9.size(); var11++) {
                  var4.getPacketHandler().write(var9.get(var11));
               }

               var16.loadedSections.add(var2);
            }
         } class="kw">finally {
            this.lock.unlockWrite(var15);
         }
      });
   }

   @Nonnull
   @Override
   class="kw">public Component<EntityStore> clone() {
      class="kw">return new ChunkTracker(this);
   }

   class="kw">public float calculateSectionPriority(int var1, int var2, int var3) {
      if (this.transformComponent == null) {
         class="kw">return Float.MAX_VALUE;
      }

      int var4 = ChunkUtil.minBlock(var1) + 16;
      int var5 = ChunkUtil.minBlock(var2) + 16;
      int var6 = ChunkUtil.minBlock(var3) + 16;
      Vector3d var7 = this.transformComponent.getPosition();
      double var8 = var4 - var7.x;
      double var10 = var5 - var7.y;
      double var12 = var6 - var7.z;
      class="kw">return (float)(var8 * var8 + var10 * var10 + var12 * var12);
   }

   class="kw">public float calculateColumnPriority(int var1, int var2) {
      if (this.transformComponent == null) {
         class="kw">return Float.MAX_VALUE;
      }

      int var3 = ChunkUtil.minBlock(var1) + 16;
      int var4 = ChunkUtil.minBlock(var2) + 16;
      Vector3d var5 = this.transformComponent.getPosition();
      double var6 = var3 - var5.x;
      double var8 = var4 - var5.z;
      class="kw">return (float)(var6 * var6 + var8 * var8);
   }

   class="kw">public enum ChunkVisibility {
      NONE,
      HOT,
      COLD;

      ChunkVisibility() {
      }
   }

   class="kw">private enum ColumnState {
      NONE,
      LOADING,
      READY;

      ColumnState() {
      }
   }

   class="kw">private class="kw">static class="kw">final class ReloadContext {
      class="kw">private int budget;
      @Nullable
      class="kw">private ChunkStore chunkStore;
      @Nullable
      class="kw">private PlayerRef playerRef;
      @Nullable
      class="kw">private TransformComponent transform;
      @Nullable
      class="kw">private CommandBuffer<EntityStore> commandBuffer;

      class="kw">private ReloadContext() {
      }

      class="kw">private void clear() {
         this.chunkStore = null;
         this.playerRef = null;
         this.transform = null;
         this.commandBuffer = null;
      }
   }

   class="kw">private class="kw">static class TrackedColumn {
      @Nonnull
      class="kw">private ChunkTracker.ColumnState state = ChunkTracker.ColumnState.NONE;
      @Nonnull
      class="kw">private class="kw">final IntSet pendingSections = new IntOpenHashSet();
      @Nonnull
      class="kw">private class="kw">final IntSet loadingSections = new IntOpenHashSet();
      @Nonnull
      class="kw">private class="kw">final IntSet loadedSections = new IntOpenHashSet();

      class="kw">private TrackedColumn() {
      }
   }
}