ChunkVisibility enum
Пакет: com.hypixel.hytale.server.core.modules.entity.player
Файл: com/hypixel/hytale/server/core/modules/entity/player/ChunkTracker.java
Поля (1)
| Модификаторы | Тип | Имя |
|---|---|---|
|
NONE,
HOT, |
COLD |
Исходный код
Показать/скрыть
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() {
}
}
}