ChunkMap#getPlayers(ChunkPos,boolean)
when passed in false
should return all players that are tracking the chunk, meaning the chunk’s data should already have been sent to the client. However, this is not currently the case. Specifically when a chunk has just loaded in on the server, this method can return players that do not have the chunk’s data yet.
This affects the Fabric API (seen here) and the Neoforge API (seen here) as they use this method to check if chunk packets should be sent to a client.
I understand that Mojang typically does not accept bug reports for issues relating to modloaders, but as will be detailed below, this is a vanilla bug, just that the bug is manifesting itself via the Fabric/Neoforge API.
Code Analysis
ChunkMap#getPlayers(ChunkPos,boolean)
relies on ChunkMap#isChunkTracked
to determine if a player is tracking a chunk.
boolean isChunkTracked(ServerPlayer player, int chunkX, int chunkZ) {
return player.getChunkTrackingView().contains(chunkX, chunkZ) && !player.connection.playerChunkSender.isPending(ChunkPos.toLong(chunkX, chunkZ));
}
ChunkMap#isChunkTracked
checks if the chunk’s data has already been sent to the client via the PlayerChunkSender
. If the PlayerChunkSender
still has the chunk in its pending chunks, then the chunk is considered to not be tracked by the player yet.
Looking at where pending chunks are added to PlayerChunkSender
, we see that ChunkMap#markChunkPendingToSend
adds new chunks to a player’s PlayerChunkSender
. There are two similar methods, one taking in a ChunkPos and one taking in a WorldChunk. The one we are interested in is the ChunkPos one.
private void markChunkPendingToSend(ServerPlayer player, ChunkPos pos) {
LevelChunk levelChunk = this.getChunkToSend(pos.toLong());
if (levelChunk != null) {
markChunkPendingToSend(player, levelChunk); // this then adds it to the PlayerChunkSender
}
}
If a chunk is “not ready” to be sent to the client yet, then it won’t get added to the player’sPlayerChunkSender
. While this may seem correct, it means that the assumption made by ChunkMap#isChunkTracked
as seen above is incorrect, as it will return true for chunks that are not ready to be sent but already within the client’s view distance. This usually happens when a chunk first loads in on the server.
Possible Solution
Change ChunkMap#markChunkPendingToSend
to always add the chunk to the player’s PlayerChunkSender
regardless of whether it is ready or not. PlayerChunkSender
actually already accounts for whether a chunk is ready to be sent. PlayerChunkSender#collectChunksToSend
will exclude chunks that are not ready yet (via the filter Objects::nonNull
), so unready chunks will just remain in the pending chunks queue until they are ready.
PlayerChunkSender#markChunkPendingToSend
currently takes in a LevelChunk, but if you look at its code it really only needs a ChunkPos or a long.
Comments 2
So far the only thing I could find is with the fillbiome command.
Steps to reproduce:
Create a new world with a datapack that has a
tick.mcfunction
with the following command:execute as @a at @s run fillbiome ~-10 ~-10 ~-10 ~10 ~10 ~10 minecraft:deep_dark
Teleport to a random completely unloaded location
e.g./tp 10000 100 10000
Observe the game’s log output to see a bunch of warnings
[19:01:09] [Render thread/WARN] (Minecraft) Ignoring chunk since it's not present: 624, 624
[19:01:09] [Render thread/WARN] (Minecraft) Ignoring chunk since it's not present: 625, 624
[19:01:09] [Render thread/WARN] (Minecraft) Ignoring chunk since it's not present: 624, 625
The fillbiome command sends a ClientboundChunksBiomesPacket
, so when that command starts executing in a chunk that is not ready to be sent to the client, the client receives packets for a chunk that doesn’t exist yet from its POV.
Now this isn’t really a big problem cause when the chunk’s data does get sent to the client, the biome data will still eventually be correct. So barely a “gameplay issue” but it’s all I could really find in a fully vanilla environment.
Is there any issue in vanilla gameplay caused by this?