Fix chunks not being refreshed when view distance updates (#2197)

* Fix chunks not being refreshed when view distance updates
This commit is contained in:
GreatWyrm 2024-09-05 20:22:24 -07:00 committed by GitHub
parent 3172039f39
commit 1b85254f91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 54 additions and 0 deletions

View File

@ -2469,6 +2469,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
byte displayedSkinParts, MainHand mainHand, boolean enableTextFiltering, boolean allowServerListings) {
this.locale = locale;
// Clamp viewDistance to valid bounds
byte previousViewDistance = this.viewDistance;
this.viewDistance = (byte) MathUtils.clamp(viewDistance, 2, 32);
this.chatMessageType = chatMessageType;
this.chatColors = chatColors;
@ -2477,6 +2478,27 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
this.enableTextFiltering = enableTextFiltering;
this.allowServerListings = allowServerListings;
// Check to see if we're in an instance first, as this method is called when first logging in since the client sends the Settings packet during configuration
if (instance != null) {
// Load/unload chunks if necessary due to view distance changes
if (previousViewDistance < this.viewDistance) {
// View distance expanded, send chunks
ChunkUtils.forChunksInRange(position.chunkX(), position.chunkZ(), this.viewDistance, (chunkX, chunkZ) -> {
if (Math.abs(chunkX - position.chunkX()) > previousViewDistance || Math.abs(chunkZ - position.chunkZ()) > previousViewDistance) {
chunkAdder.accept(chunkX, chunkZ);
}
});
} else if (previousViewDistance > this.viewDistance) {
// View distance shrunk, unload chunks
ChunkUtils.forChunksInRange(position.chunkX(), position.chunkZ(), previousViewDistance, (chunkX, chunkZ) -> {
if (Math.abs(chunkX - position.chunkX()) > this.viewDistance || Math.abs(chunkZ - position.chunkZ()) > this.viewDistance) {
chunkRemover.accept(chunkX, chunkZ);
}
});
}
// Else previous and current are equal, do nothing
}
boolean isInPlayState = getPlayerConnection().getConnectionState() == ConnectionState.PLAY;
PlayerMeta playerMeta = getPlayerMeta();
if (isInPlayState) playerMeta.setNotifyAboutChanges(false);

View File

@ -8,10 +8,12 @@ import net.minestom.server.entity.Player;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.message.ChatMessageType;
import net.minestom.server.network.packet.client.common.ClientSettingsPacket;
import net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket;
import net.minestom.server.network.packet.client.play.ClientTeleportConfirmPacket;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.EntityPositionPacket;
import net.minestom.server.network.packet.server.play.UnloadChunkPacket;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.testing.Collector;
@ -21,6 +23,8 @@ import net.minestom.testing.TestConnection;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@ -137,4 +141,32 @@ public class PlayerMovementIntegrationTest {
player.interpretPacketQueue();
chunkDataPacketCollector.assertCount(MathUtils.square(viewDistance * 2 + 1));
}
@Test
public void testSettingsViewDistanceExpansionAndShrink(Env env) {
int startingViewDistance = 8;
byte endViewDistance = 12;
byte finalViewDistance = 10;
var instance = env.createFlatInstance();
var connection = env.createConnection();
Pos startingPlayerPos = new Pos(0, 42, 0);
var player = connection.connect(instance, startingPlayerPos).join();
int chunkDifference = ChunkUtils.getChunkCount(endViewDistance) - ChunkUtils.getChunkCount(startingViewDistance);
// Preload chunks, otherwise our first tracker.assertCount call will fail randomly due to chunks being loaded off the main thread
ChunkUtils.forChunksInRange(0, 0, endViewDistance, instance::loadChunk);
var tracker = connection.trackIncoming(ChunkDataPacket.class);
player.addPacketToQueue(new ClientSettingsPacket("en_US", endViewDistance, ChatMessageType.FULL, false, (byte) 0, Player.MainHand.RIGHT, false, true));
player.interpretPacketQueue();
tracker.assertCount(chunkDifference);
var tracker1 = connection.trackIncoming(UnloadChunkPacket.class);
player.addPacketToQueue(new ClientSettingsPacket("en_US", finalViewDistance, ChatMessageType.FULL, false, (byte) 0, Player.MainHand.RIGHT, false, true));
player.interpretPacketQueue();
int chunkDifference1 = ChunkUtils.getChunkCount(endViewDistance) - ChunkUtils.getChunkCount(finalViewDistance);
tracker1.assertCount(chunkDifference1);
}
}