The chunk view distance can now be dynamically modified both by the client or with the server using MinecraftServer#setChunkViewDistance, also added UpdateViewDistancePacket

This commit is contained in:
themode 2020-10-31 19:44:22 +01:00
parent 6e36f3242d
commit b74d85eca8
4 changed files with 61 additions and 6 deletions

View File

@ -13,12 +13,14 @@ import net.minestom.server.data.DataType;
import net.minestom.server.data.SerializableData;
import net.minestom.server.entity.EntityManager;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player;
import net.minestom.server.extensions.Extension;
import net.minestom.server.extensions.ExtensionManager;
import net.minestom.server.extras.mojangAuth.MojangCrypt;
import net.minestom.server.fluids.Fluid;
import net.minestom.server.gamedata.loottables.LootTableManager;
import net.minestom.server.gamedata.tags.TagManager;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockManager;
@ -33,6 +35,7 @@ import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.netty.NettyServer;
import net.minestom.server.network.packet.server.play.PluginMessagePacket;
import net.minestom.server.network.packet.server.play.ServerDifficultyPacket;
import net.minestom.server.network.packet.server.play.UpdateViewDistancePacket;
import net.minestom.server.particle.Particle;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.potion.PotionEffect;
@ -45,6 +48,7 @@ import net.minestom.server.stat.StatisticType;
import net.minestom.server.storage.StorageLocation;
import net.minestom.server.storage.StorageManager;
import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.thread.MinestomThread;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.Difficulty;
@ -57,6 +61,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.Proxy;
import java.security.KeyPair;
import java.util.Collection;
/**
* The main server class used to start the server and retrieve all the managers.
@ -432,15 +437,28 @@ public class MinecraftServer {
/**
* Changes the chunk view distance of the server.
* <p>
* WARNING: this need to be called before {@link #start(String, int, ResponseDataConsumer)}.
*
* @param chunkViewDistance the new chunk view distance
* @throws IllegalStateException if this is called after the server started
*/
public static void setChunkViewDistance(int chunkViewDistance) {
Check.stateCondition(started, "The chunk view distance cannot be changed after the server has been started.");
Check.argCondition(!MathUtils.isBetween(chunkViewDistance, 2, 32), "The chunk view distance needs to be between 2 and 32");
MinecraftServer.chunkViewDistance = chunkViewDistance;
if (started) {
UpdateViewDistancePacket updateViewDistancePacket = new UpdateViewDistancePacket();
updateViewDistancePacket.viewDistance = chunkViewDistance;
final Collection<Player> players = connectionManager.getOnlinePlayers();
PacketWriterUtils.writeAndSend(players, updateViewDistancePacket);
connectionManager.getOnlinePlayers().forEach(player -> {
final Chunk playerChunk = player.getChunk();
if (playerChunk != null) {
player.refreshVisibleChunks(playerChunk);
}
});
}
}
/**

View File

@ -1032,7 +1032,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
final boolean isPlayer = this instanceof Player;
if (isPlayer)
((Player) this).onChunkChange(newChunk); // Refresh loaded chunk
((Player) this).refreshVisibleChunks(newChunk); // Refresh loaded chunk
// Refresh entity viewable list
final int entityViewDistance = MinecraftServer.getEntityViewDistance();

View File

@ -1327,7 +1327,7 @@ public class Player extends LivingEntity implements CommandSender {
final BlockPosition pos = position.toBlockPosition();
final Chunk chunk = instance.getChunk(pos.getX() >> 4, pos.getZ() >> 4);
Check.notNull(chunk, "Tried to interact with an unloaded chunk.");
onChunkChange(chunk);
refreshVisibleChunks(chunk);
}
}
@ -1406,13 +1406,14 @@ public class Player extends LivingEntity implements CommandSender {
/**
* Called when the player changes chunk (move from one to another).
* Can also be used to refresh the list of chunks that the client should see.
* <p>
* It does remove and add the player from the chunks viewers list when removed or added.
* It also calls the events {@link PlayerChunkUnloadEvent} and {@link PlayerChunkLoadEvent}.
*
* @param newChunk the current/new player chunk
*/
protected void onChunkChange(@NotNull Chunk newChunk) {
public void refreshVisibleChunks(@NotNull Chunk newChunk) {
// Previous chunks indexes
final long[] lastVisibleChunks = viewableChunks.stream().mapToLong(viewableChunks ->
ChunkUtils.getChunkIndex(viewableChunks.getChunkX(), viewableChunks.getChunkZ())
@ -2389,6 +2390,8 @@ public class Player extends LivingEntity implements CommandSender {
private byte displayedSkinParts;
private MainHand mainHand;
private boolean firstRefresh = true;
/**
* The player game language.
*
@ -2451,6 +2454,9 @@ public class Player extends LivingEntity implements CommandSender {
* @param mainHand the player main hand
*/
public void refresh(String locale, byte viewDistance, ChatMode chatMode, boolean chatColors, byte displayedSkinParts, MainHand mainHand) {
final boolean viewDistanceChanged = !firstRefresh && this.viewDistance != viewDistance;
this.locale = locale;
this.viewDistance = viewDistance;
this.chatMode = chatMode;
@ -2458,6 +2464,16 @@ public class Player extends LivingEntity implements CommandSender {
this.displayedSkinParts = displayedSkinParts;
this.mainHand = mainHand;
sendMetadataIndex(16);
this.firstRefresh = false;
// Client changed his view distance in the settings
if (viewDistanceChanged) {
final Chunk playerChunk = getChunk();
if (playerChunk != null) {
refreshVisibleChunks(playerChunk);
}
}
}
}

View File

@ -0,0 +1,21 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
public class UpdateViewDistancePacket implements ServerPacket {
public int viewDistance;
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeVarInt(viewDistance);
}
@Override
public int getId() {
return ServerPacketIdentifier.UPDATE_VIEW_DISTANCE;
}
}