165 lines
5.5 KiB
Java
165 lines
5.5 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.mojang.logging.LogUtils
|
|
* org.jspecify.annotations.Nullable
|
|
* org.slf4j.Logger
|
|
*/
|
|
package net.minecraft.client.multiplayer;
|
|
|
|
import com.mojang.logging.LogUtils;
|
|
import java.util.concurrent.TimeUnit;
|
|
import net.minecraft.client.multiplayer.ClientLevel;
|
|
import net.minecraft.client.player.LocalPlayer;
|
|
import net.minecraft.client.renderer.LevelRenderer;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.resources.ResourceKey;
|
|
import net.minecraft.server.level.progress.ChunkLoadStatusView;
|
|
import net.minecraft.server.level.progress.LevelLoadListener;
|
|
import net.minecraft.server.level.progress.LevelLoadProgressTracker;
|
|
import net.minecraft.util.Util;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.world.level.Level;
|
|
import org.jspecify.annotations.Nullable;
|
|
import org.slf4j.Logger;
|
|
|
|
public class LevelLoadTracker
|
|
implements LevelLoadListener {
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private static final long CLIENT_WAIT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(30L);
|
|
public static final long LEVEL_LOAD_CLOSE_DELAY_MS = 500L;
|
|
private final LevelLoadProgressTracker serverProgressTracker = new LevelLoadProgressTracker(true);
|
|
private @Nullable ChunkLoadStatusView serverChunkStatusView;
|
|
private volatile @Nullable LevelLoadListener.Stage serverStage;
|
|
private @Nullable ClientState clientState;
|
|
private final long closeDelayMs;
|
|
|
|
public LevelLoadTracker() {
|
|
this(0L);
|
|
}
|
|
|
|
public LevelLoadTracker(long closeDelayMs) {
|
|
this.closeDelayMs = closeDelayMs;
|
|
}
|
|
|
|
public void setServerChunkStatusView(ChunkLoadStatusView serverChunkStatusView) {
|
|
this.serverChunkStatusView = serverChunkStatusView;
|
|
}
|
|
|
|
public void startClientLoad(LocalPlayer player, ClientLevel level, LevelRenderer levelRenderer) {
|
|
this.clientState = new WaitingForServer(player, level, levelRenderer, Util.getMillis() + CLIENT_WAIT_TIMEOUT_MS);
|
|
}
|
|
|
|
public void tickClientLoad() {
|
|
if (this.clientState != null) {
|
|
this.clientState = this.clientState.tick();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Enabled force condition propagation
|
|
* Lifted jumps to return sites
|
|
*/
|
|
public boolean isLevelReady() {
|
|
long readyAt;
|
|
ClientState clientState = this.clientState;
|
|
if (!(clientState instanceof ClientLevelReady)) return false;
|
|
ClientLevelReady clientLevelReady = (ClientLevelReady)clientState;
|
|
try {
|
|
long l;
|
|
readyAt = l = clientLevelReady.readyAt();
|
|
}
|
|
catch (Throwable throwable) {
|
|
throw new MatchException(throwable.toString(), throwable);
|
|
}
|
|
if (Util.getMillis() < readyAt + this.closeDelayMs) return false;
|
|
return true;
|
|
}
|
|
|
|
public void loadingPacketsReceived() {
|
|
if (this.clientState != null) {
|
|
this.clientState = this.clientState.loadingPacketsReceived();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void start(LevelLoadListener.Stage stage, int totalChunks) {
|
|
this.serverProgressTracker.start(stage, totalChunks);
|
|
this.serverStage = stage;
|
|
}
|
|
|
|
@Override
|
|
public void update(LevelLoadListener.Stage stage, int currentChunks, int totalChunks) {
|
|
this.serverProgressTracker.update(stage, currentChunks, totalChunks);
|
|
}
|
|
|
|
@Override
|
|
public void finish(LevelLoadListener.Stage stage) {
|
|
this.serverProgressTracker.finish(stage);
|
|
}
|
|
|
|
@Override
|
|
public void updateFocus(ResourceKey<Level> dimension, ChunkPos chunkPos) {
|
|
if (this.serverChunkStatusView != null) {
|
|
this.serverChunkStatusView.moveTo(dimension, chunkPos);
|
|
}
|
|
}
|
|
|
|
public @Nullable ChunkLoadStatusView statusView() {
|
|
return this.serverChunkStatusView;
|
|
}
|
|
|
|
public float serverProgress() {
|
|
return this.serverProgressTracker.get();
|
|
}
|
|
|
|
public boolean hasProgress() {
|
|
return this.serverStage != null;
|
|
}
|
|
|
|
private record WaitingForServer(LocalPlayer player, ClientLevel level, LevelRenderer levelRenderer, long timeoutAfter) implements ClientState
|
|
{
|
|
@Override
|
|
public ClientState loadingPacketsReceived() {
|
|
return new WaitingForPlayerChunk(this.player, this.level, this.levelRenderer, this.timeoutAfter);
|
|
}
|
|
}
|
|
|
|
private static sealed interface ClientState
|
|
permits WaitingForServer, WaitingForPlayerChunk, ClientLevelReady {
|
|
default public ClientState tick() {
|
|
return this;
|
|
}
|
|
|
|
default public ClientState loadingPacketsReceived() {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
private record ClientLevelReady(long readyAt) implements ClientState
|
|
{
|
|
}
|
|
|
|
private record WaitingForPlayerChunk(LocalPlayer player, ClientLevel level, LevelRenderer levelRenderer, long timeoutAfter) implements ClientState
|
|
{
|
|
@Override
|
|
public ClientState tick() {
|
|
return this.isReady() ? new ClientLevelReady(Util.getMillis()) : this;
|
|
}
|
|
|
|
private boolean isReady() {
|
|
if (Util.getMillis() > this.timeoutAfter) {
|
|
LOGGER.warn("Timed out while waiting for the client to load chunks, letting the player into the world anyway");
|
|
return true;
|
|
}
|
|
BlockPos playerPos = this.player.blockPosition();
|
|
if (this.level.isOutsideBuildHeight(playerPos.getY()) || this.player.isSpectator() || !this.player.isAlive()) {
|
|
return true;
|
|
}
|
|
return this.levelRenderer.isSectionCompiledAndVisible(playerPos);
|
|
}
|
|
}
|
|
}
|
|
|