mirror of
https://github.com/PaperMC/Paper.git
synced 2025-07-26 09:42:06 -07:00
The ServerLevel#getAllEntities function only returns entities which are accessible. FeatureHooks#getAllEntities will return all entities, whether or not they are accessible. Use the new hook in the EntityCommand, which allows server admins to inspect entities in unloaded chunks. Use the hook as well for ticking the EntityScheduler. This fixes an issue whether unloaded entities did not have their scheduler ticked.
609 lines
39 KiB
Diff
609 lines
39 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: stonar96 <minecraft.stonar96@gmail.com>
|
|
Date: Thu, 25 Nov 2021 13:27:51 +0100
|
|
Subject: [PATCH] Anti-Xray
|
|
|
|
|
|
diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java
|
|
index 811a8e5141f2061a185b53b63d951646141c0c7d..33d3eb510c5844e72bbc382bd24641aae080962d 100644
|
|
--- a/io/papermc/paper/FeatureHooks.java
|
|
+++ b/io/papermc/paper/FeatureHooks.java
|
|
@@ -45,20 +45,25 @@ public final class FeatureHooks {
|
|
}
|
|
|
|
public static LevelChunkSection createSection(final Registry<Biome> biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) {
|
|
- return new LevelChunkSection(biomeRegistry);
|
|
+ return new LevelChunkSection(biomeRegistry, level, chunkPos, chunkSection); // Paper - Anti-Xray - Add parameters
|
|
}
|
|
|
|
public static void sendChunkRefreshPackets(final List<ServerPlayer> playersInRange, final LevelChunk chunk) {
|
|
- final ClientboundLevelChunkWithLightPacket refreshPacket = new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null);
|
|
+ // Paper start - Anti-Xray
|
|
+ final Map<Object, ClientboundLevelChunkWithLightPacket> refreshPackets = new HashMap<>();
|
|
for (final ServerPlayer player : playersInRange) {
|
|
if (player.connection == null) continue;
|
|
|
|
- player.connection.send(refreshPacket);
|
|
+ final Boolean shouldModify = chunk.getLevel().chunkPacketBlockController.shouldModify(player, chunk);
|
|
+ player.connection.send(refreshPackets.computeIfAbsent(shouldModify, s -> { // Use connection to prevent creating firing event
|
|
+ return new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null, (Boolean) s);
|
|
+ }));
|
|
}
|
|
+ // Paper end - Anti-Xray
|
|
}
|
|
|
|
public static PalettedContainer<BlockState> emptyPalettedBlockContainer() {
|
|
- return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
|
+ return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); // Paper - Anti-Xray - Add preset block states
|
|
}
|
|
|
|
public static Set<Long> getSentChunkKeys(final ServerPlayer player) {
|
|
diff --git a/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java b/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
|
|
index c9086bca5cbb780fd586f667e31a8fe1400ae58a..f828d07018d9a17aaa0142aac67ebed58dd84c3e 100644
|
|
--- a/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
|
|
+++ b/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
|
|
@@ -70,8 +70,10 @@ public record ClientboundChunksBiomesPacket(List<ClientboundChunksBiomesPacket.C
|
|
}
|
|
|
|
public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk) {
|
|
+ int chunkSectionIndex = 0; // Paper - Anti-Xray
|
|
for (LevelChunkSection levelChunkSection : chunk.getSections()) {
|
|
- levelChunkSection.getBiomes().write(buffer);
|
|
+ levelChunkSection.getBiomes().write(buffer, null, chunkSectionIndex); // Paper - Anti-Xray
|
|
+ chunkSectionIndex++; // Paper - Anti-Xray
|
|
}
|
|
|
|
if (buffer.writerIndex() != buffer.capacity()) {
|
|
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
|
index de234f220ba09ad9b5e0c8215b49d20ca51d0ac7..83c4b454472714de6ebf99cd4e50867920d07509 100644
|
|
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
|
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
|
@@ -33,13 +33,23 @@ public class ClientboundLevelChunkPacketData {
|
|
private final byte[] buffer;
|
|
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
|
|
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
public ClientboundLevelChunkPacketData(LevelChunk levelChunk) {
|
|
+ this(levelChunk, null);
|
|
+ }
|
|
+ public ClientboundLevelChunkPacketData(LevelChunk levelChunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo) {
|
|
+ // Paper end
|
|
this.heightmaps = levelChunk.getHeightmaps()
|
|
.stream()
|
|
.filter(entry1 -> entry1.getKey().sendToClient())
|
|
.collect(Collectors.toMap(Entry::getKey, entry1 -> (long[])entry1.getValue().getRawData().clone()));
|
|
this.buffer = new byte[calculateChunkSize(levelChunk)];
|
|
- extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk);
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ if (chunkPacketInfo != null) {
|
|
+ chunkPacketInfo.setBuffer(this.buffer);
|
|
+ }
|
|
+ extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk, chunkPacketInfo);
|
|
this.blockEntitiesData = Lists.newArrayList();
|
|
|
|
for (Entry<BlockPos, BlockEntity> entry : levelChunk.getBlockEntities().entrySet()) {
|
|
@@ -82,9 +92,17 @@ public class ClientboundLevelChunkPacketData {
|
|
return byteBuf;
|
|
}
|
|
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk) {
|
|
+ ClientboundLevelChunkPacketData.extractChunkData(buffer, chunk, null);
|
|
+ }
|
|
+ public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo) {
|
|
+ int chunkSectionIndex = 0;
|
|
for (LevelChunkSection levelChunkSection : chunk.getSections()) {
|
|
- levelChunkSection.write(buffer);
|
|
+ levelChunkSection.write(buffer, chunkPacketInfo, chunkSectionIndex);
|
|
+ chunkSectionIndex++;
|
|
+ // Paper end - Anti-Xray - Add chunk packet info
|
|
}
|
|
|
|
if (buffer.writerIndex() != buffer.capacity()) {
|
|
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
|
index 3a384175f8e7f204234bbaf3081bdc20c47a0d4b..5699bc15eba92e22433a20cb8326b59f2ebd3036 100644
|
|
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
|
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
|
@@ -18,18 +18,31 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
|
|
private final int z;
|
|
private final ClientboundLevelChunkPacketData chunkData;
|
|
private final ClientboundLightUpdatePacketData lightData;
|
|
- // Paper start - Anti-Xray
|
|
+ // Paper start - Async-Anti-Xray - Ready flag for the connection, add chunk packet info
|
|
+ private volatile boolean ready;
|
|
+
|
|
+ @Override
|
|
+ public boolean isReady() {
|
|
+ return this.ready;
|
|
+ }
|
|
+
|
|
public void setReady(final boolean ready) {
|
|
- // Empty hook, updated by feature patch
|
|
+ this.ready = ready;
|
|
}
|
|
- // Paper end - Anti-Xray
|
|
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight) {
|
|
+ this(chunk, lightEngine, skyLight, blockLight, true);
|
|
+ }
|
|
+ public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight, boolean modifyBlocks) {
|
|
+ // Paper end - Anti-Xray
|
|
ChunkPos pos = chunk.getPos();
|
|
this.x = pos.x;
|
|
this.z = pos.z;
|
|
- this.chunkData = new ClientboundLevelChunkPacketData(chunk);
|
|
+ io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo = modifyBlocks ? chunk.getLevel().chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null; // Paper - Ant-Xray
|
|
+ this.chunkData = new ClientboundLevelChunkPacketData(chunk, chunkPacketInfo); // Paper - Anti-Xray
|
|
this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight);
|
|
+ chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
|
}
|
|
|
|
private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) {
|
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
|
index e6f958b6128213fb9577406c6495148dccac40ca..49008b4cbaead8a66a93d2b0d4b50b335a6c3eed 100644
|
|
--- a/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
|
@@ -346,7 +346,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
org.bukkit.generator.BiomeProvider biomeProvider // CraftBukkit
|
|
) {
|
|
// CraftBukkit start
|
|
- super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.location(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules()))); // Paper - create paper world configs
|
|
+ super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.location(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), dispatcher); // Paper - create paper world configs; Async-Anti-Xray: Pass executor
|
|
this.pvpMode = server.isPvpAllowed();
|
|
this.levelStorageAccess = levelStorageAccess;
|
|
this.uuid = org.bukkit.craftbukkit.util.WorldUUID.getOrCreate(levelStorageAccess.levelDirectory.path().toFile());
|
|
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
|
|
index b29ecfcc07304c1ee3d77cd431db0889ebc7d6b1..6734756d7a51e635a50a47577f9e6b6f8111db51 100644
|
|
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
|
|
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
|
|
@@ -296,6 +296,7 @@ public class ServerPlayerGameMode {
|
|
org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDamageAbortEvent(this.player, pos, this.player.getInventory().getSelectedItem()); // CraftBukkit
|
|
}
|
|
}
|
|
+ this.level.chunkPacketBlockController.onPlayerLeftClickBlock(this, pos, action, face, maxBuildHeight, sequence); // Paper - Anti-Xray
|
|
}
|
|
|
|
public void destroyAndAck(BlockPos pos, int sequence, String message) {
|
|
diff --git a/net/minecraft/server/network/PlayerChunkSender.java b/net/minecraft/server/network/PlayerChunkSender.java
|
|
index 8cd7363704d4532c926dbf4778eb4dfec5fdf8bc..0376a10ee0544b13e8fd629a7b13f78811e57a30 100644
|
|
--- a/net/minecraft/server/network/PlayerChunkSender.java
|
|
+++ b/net/minecraft/server/network/PlayerChunkSender.java
|
|
@@ -78,8 +78,11 @@ public class PlayerChunkSender {
|
|
}
|
|
}
|
|
|
|
- private static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
|
|
- packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null));
|
|
+ // Paper start - Anti-Xray
|
|
+ public static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
|
|
+ final boolean shouldModify = level.chunkPacketBlockController.shouldModify(packetListener.player, chunk);
|
|
+ packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
|
|
+ // Paper end - Anti-Xray
|
|
// Paper start - PlayerChunkLoadEvent
|
|
if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
|
new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), packetListener.getPlayer().getBukkitEntity()).callEvent();
|
|
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
|
index b595fc3bd844eaf2a56f70f166523ee6254386b6..891d3e13057c6034c59a78e594935c433921de04 100644
|
|
--- a/net/minecraft/server/players/PlayerList.java
|
|
+++ b/net/minecraft/server/players/PlayerList.java
|
|
@@ -408,7 +408,7 @@ public abstract class PlayerList {
|
|
.getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
|
|
player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
|
|
new net.minecraft.world.level.chunk.EmptyLevelChunk(serverLevel, player.chunkPosition(), plains),
|
|
- serverLevel.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null)
|
|
+ serverLevel.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null, true) // Paper - Anti-Xray
|
|
);
|
|
}
|
|
// Paper end - Send empty chunk
|
|
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
|
index 980eaba27ce2616c1573a4760cf4acc2dd251190..1eb8cb187d33510a4e99d229e721a2e7db4012ad 100644
|
|
--- a/net/minecraft/world/level/Level.java
|
|
+++ b/net/minecraft/world/level/Level.java
|
|
@@ -132,6 +132,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
|
private long subTickCount;
|
|
|
|
// CraftBukkit start
|
|
+ public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
|
private final CraftWorld world;
|
|
public boolean pvpMode;
|
|
public @Nullable org.bukkit.generator.ChunkGenerator generator;
|
|
@@ -201,7 +202,8 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
|
@Nullable org.bukkit.generator.BiomeProvider biomeProvider, // Paper
|
|
org.bukkit.World.Environment environment, // Paper
|
|
java.util.function.Function<org.spigotmc.SpigotWorldConfig, // Spigot - create per world config
|
|
- io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator // Paper - create paper world config
|
|
+ io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, // Paper - create paper world config
|
|
+ java.util.concurrent.Executor executor // Paper - Anti-Xray
|
|
) {
|
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
|
|
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
|
@@ -278,6 +280,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
|
public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {}
|
|
});
|
|
// CraftBukkit end
|
|
+ this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new io.papermc.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : io.papermc.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
|
|
}
|
|
|
|
// Paper start - Cancel hit for vanished players
|
|
@@ -483,6 +486,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
|
snapshot.setFlags(flags); // Paper - always set the flag of the most recent call to mitigate issues with multiple update at the same pos with different flags
|
|
}
|
|
BlockState blockState = chunkAt.setBlockState(pos, state, flags);
|
|
+ this.chunkPacketBlockController.onBlockChange(this, pos, state, blockState, flags, recursionLeft); // Paper - Anti-Xray
|
|
// CraftBukkit end
|
|
if (blockState == null) {
|
|
// CraftBukkit start - remove blockstate if failed (or the same)
|
|
diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java
|
|
index f98ee299f5900b0a66c447d7970bd16a7ced1086..d1ae452f0aa96c36afe8b7ecddd3e06b06165878 100644
|
|
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
|
|
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
|
|
@@ -115,14 +115,14 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
|
|
}
|
|
}
|
|
|
|
- replaceMissingSections(biomeRegistry, this.sections);
|
|
+ this.replaceMissingSections(biomeRegistry, this.sections); // Paper - Anti-Xray - make it a non-static method
|
|
this.biomeRegistry = biomeRegistry; // CraftBukkit
|
|
}
|
|
|
|
- private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) {
|
|
+ private void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) { // Paper - Anti-Xray - make it a non-static method
|
|
for (int i = 0; i < sections.length; i++) {
|
|
if (sections[i] == null) {
|
|
- sections[i] = new LevelChunkSection(biomeRegistry);
|
|
+ sections[i] = new LevelChunkSection(biomeRegistry, this.levelHeightAccessor instanceof net.minecraft.world.level.Level ? (net.minecraft.world.level.Level) this.levelHeightAccessor : null, this.chunkPos, this.levelHeightAccessor.getSectionYFromSectionIndex(i)); // Paper - Anti-Xray - Add parameters
|
|
}
|
|
}
|
|
}
|
|
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
|
index 1e60b295f8fa672ecee96a71fd1fea14339b7054..6f19586b4a39541c0fb895a18a0a4fd9b5da504c 100644
|
|
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
|
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
|
@@ -112,7 +112,7 @@ public class LevelChunk extends ChunkAccess {
|
|
@Nullable LevelChunk.PostLoadProcessor postLoad,
|
|
@Nullable BlendingData blendingData
|
|
) {
|
|
- super(pos, data, level, level.registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData);
|
|
+ super(pos, data, level, net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData); // Paper - Anti-Xray - The world isn't ready yet, use server singleton for registry
|
|
this.level = (ServerLevel) level; // CraftBukkit - type
|
|
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>();
|
|
|
|
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
|
index 2399a0f8839c0925a9923bae87362c2c9a217197..1aa4e39431a93a7789b74a2e3476a3e47605e2cc 100644
|
|
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
|
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
|
@@ -38,9 +38,15 @@ public class LevelChunkSection {
|
|
this.recalcBlockCounts();
|
|
}
|
|
|
|
+ // Paper start - Anti-Xray - Add parameters
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
public LevelChunkSection(Registry<Biome> biomeRegistry) {
|
|
- this.states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
|
- this.biomes = new PalettedContainer<>(biomeRegistry.asHolderIdMap(), biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
|
+ this(biomeRegistry, null, null, 0);
|
|
+ }
|
|
+ public LevelChunkSection(Registry<Biome> biomeRegistry, net.minecraft.world.level.Level level, net.minecraft.world.level.ChunkPos chunkPos, int chunkSectionY) {
|
|
+ // Paper end - Anti-Xray
|
|
+ this.states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, level == null || level.chunkPacketBlockController == null ? null : level.chunkPacketBlockController.getPresetBlockStates(level, chunkPos, chunkSectionY)); // Paper - Anti-Xray - Add preset block states
|
|
+ this.biomes = new PalettedContainer<>(biomeRegistry.asHolderIdMap(), biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES, null); // Paper - Anti-Xray - Add preset biomes
|
|
}
|
|
|
|
public BlockState getBlockState(int x, int y, int z) {
|
|
@@ -168,10 +174,16 @@ public class LevelChunkSection {
|
|
this.biomes = palettedContainer;
|
|
}
|
|
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
public void write(FriendlyByteBuf buffer) {
|
|
+ this.write(buffer, null, 0);
|
|
+ }
|
|
+ public void write(FriendlyByteBuf buffer, io.papermc.paper.antixray.ChunkPacketInfo<BlockState> chunkPacketInfo, int chunkSectionIndex) {
|
|
buffer.writeShort(this.nonEmptyBlockCount);
|
|
- this.states.write(buffer);
|
|
- this.biomes.write(buffer);
|
|
+ this.states.write(buffer, chunkPacketInfo, chunkSectionIndex);
|
|
+ this.biomes.write(buffer, null, chunkSectionIndex);
|
|
+ // Paper end - Anti-Xray - Add chunk packet info
|
|
}
|
|
|
|
public int getSerializedSize() {
|
|
diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
index cd2b1240f13acaaecbb8e6d0f7f8b326ab24b5b0..9b0f17841230640f532ac33bb86e6585e88b5a57 100644
|
|
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
@@ -27,6 +27,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
private static final int MIN_PALETTE_BITS = 0;
|
|
private final PaletteResize<T> dummyPaletteResize = (bits, objectAdded) -> 0;
|
|
public final IdMap<T> registry;
|
|
+ private final T @org.jetbrains.annotations.Nullable [] presetValues; // Paper - Anti-Xray - Add preset values
|
|
private volatile PalettedContainer.Data<T> data;
|
|
private final PalettedContainer.Strategy strategy;
|
|
//private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
|
|
@@ -39,13 +40,21 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
// this.threadingDetector.checkAndUnlock(); // Paper - disable this - use proper synchronization
|
|
}
|
|
|
|
+ // Paper start - Anti-Xray - Add preset values
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value) {
|
|
- PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = PalettedContainer::unpack;
|
|
+ return PalettedContainer.codecRW(registry, codec, strategy, value, null);
|
|
+ }
|
|
+ public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value, T @org.jetbrains.annotations.Nullable [] presetValues) {
|
|
+ PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = (idListx, paletteProviderx, serialized) -> {
|
|
+ return unpack(idListx, paletteProviderx, serialized, value, presetValues);
|
|
+ };
|
|
+ // Paper end
|
|
return codec(registry, codec, strategy, value, unpacker);
|
|
}
|
|
|
|
public static <T> Codec<PalettedContainerRO<T>> codecRO(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value) {
|
|
- PalettedContainerRO.Unpacker<T, PalettedContainerRO<T>> unpacker = (registry1, strategy1, packedData) -> unpack(registry1, strategy1, packedData)
|
|
+ PalettedContainerRO.Unpacker<T, PalettedContainerRO<T>> unpacker = (registry1, strategy1, packedData) -> unpack(registry1, strategy1, packedData, value, null) // Paper - Anti-Xray - Add preset values
|
|
.map(container -> (PalettedContainerRO<T>)container);
|
|
return codec(registry, codec, strategy, value, unpacker);
|
|
}
|
|
@@ -65,27 +74,66 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
);
|
|
}
|
|
|
|
+ // Paper start - Anti-Xray - Add preset values
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
+ public PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values) {
|
|
+ this(registry, strategy, configuration, storage, values, null, null);
|
|
+ }
|
|
public PalettedContainer(
|
|
- IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values
|
|
+ IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues
|
|
) {
|
|
+ this.presetValues = presetValues;
|
|
this.registry = registry;
|
|
this.strategy = strategy;
|
|
this.data = new PalettedContainer.Data<>(configuration, storage, configuration.factory().create(configuration.bits(), registry, this, values));
|
|
+ if (presetValues != null && (configuration.factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY ? this.data.palette.valueFor(0) != defaultValue : configuration.factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY)) {
|
|
+ // In 1.18 Mojang unfortunately removed code that already handled possible resize operations on read from disk for us
|
|
+ // We readd this here but in a smarter way than it was before
|
|
+ int maxSize = 1 << configuration.bits();
|
|
+
|
|
+ for (T presetValue : presetValues) {
|
|
+ if (this.data.palette.getSize() >= maxSize) {
|
|
+ java.util.Set<T> allValues = new java.util.HashSet<>(values);
|
|
+ allValues.addAll(Arrays.asList(presetValues));
|
|
+ int newBits = Mth.ceillog2(allValues.size());
|
|
+
|
|
+ if (newBits > configuration.bits()) {
|
|
+ this.onResize(newBits, null);
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ this.data.palette.idFor(presetValue);
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
}
|
|
|
|
- private PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Data<T> data) {
|
|
+ // Paper start - Anti-Xray - Add preset values
|
|
+ private PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Data<T> data, T @org.jetbrains.annotations.Nullable [] presetValues) {
|
|
+ this.presetValues = presetValues;
|
|
+ // Paper end - Anti-Xray
|
|
this.registry = registry;
|
|
this.strategy = strategy;
|
|
this.data = data;
|
|
}
|
|
|
|
- private PalettedContainer(PalettedContainer<T> other) {
|
|
+ private PalettedContainer(PalettedContainer<T> other, T @org.jetbrains.annotations.Nullable [] presetValues) { // Paper - Anti-Xray - Add preset values
|
|
+ this.presetValues = presetValues; // Paper - Anti-Xray - Add preset values
|
|
this.registry = other.registry;
|
|
this.strategy = other.strategy;
|
|
this.data = other.data.copy(this);
|
|
}
|
|
|
|
+ // Paper start - Anti-Xray - Add preset values
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
public PalettedContainer(IdMap<T> registry, T palette, PalettedContainer.Strategy strategy) {
|
|
+ this(registry, palette, strategy, null);
|
|
+ }
|
|
+ public PalettedContainer(IdMap<T> registry, T palette, PalettedContainer.Strategy strategy, T @org.jetbrains.annotations.Nullable [] presetValues) {
|
|
+ this.presetValues = presetValues;
|
|
+ // Paper end - Anti-Xray
|
|
this.strategy = strategy;
|
|
this.registry = registry;
|
|
this.data = this.createOrReuseData(null, 0);
|
|
@@ -100,11 +148,30 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
@Override
|
|
public synchronized int onResize(int bits, T objectAdded) { // Paper - synchronize
|
|
PalettedContainer.Data<T> data = this.data;
|
|
+ // Paper start - Anti-Xray - Add preset values
|
|
+ if (this.presetValues != null && objectAdded != null && data.configuration().factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY) {
|
|
+ int duplicates = 0;
|
|
+ List<T> presetValues = Arrays.asList(this.presetValues);
|
|
+ duplicates += presetValues.contains(objectAdded) ? 1 : 0;
|
|
+ duplicates += presetValues.contains(data.palette.valueFor(0)) ? 1 : 0;
|
|
+ bits = Mth.ceillog2((1 << this.strategy.calculateBitsForSerialization(this.registry, 1 << bits)) + presetValues.size() - duplicates);
|
|
+ }
|
|
+ // Paper end - Anti-Xray
|
|
PalettedContainer.Data<T> data1 = this.createOrReuseData(data, bits);
|
|
data1.copyFrom(data.palette, data.storage);
|
|
this.data = data1;
|
|
- return data1.palette.idFor(objectAdded);
|
|
+ // Paper start - Anti-Xray
|
|
+ this.addPresetValues();
|
|
+ return objectAdded == null ? -1 : data1.palette.idFor(objectAdded);
|
|
+ }
|
|
+ private void addPresetValues() {
|
|
+ if (this.presetValues != null && this.data.configuration().factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY) {
|
|
+ for (T presetValue : this.presetValues) {
|
|
+ this.data.palette.idFor(presetValue);
|
|
+ }
|
|
+ }
|
|
}
|
|
+ // Paper end - Anti-Xray
|
|
|
|
public synchronized T getAndSet(int x, int y, int z, T state) { // Paper - synchronize
|
|
this.acquire();
|
|
@@ -171,24 +238,35 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
data.palette.read(buffer);
|
|
buffer.readFixedSizeLongArray(data.storage.getRaw());
|
|
this.data = data;
|
|
+ this.addPresetValues(); // Paper - Anti-Xray - Add preset values (inefficient, but this isn't used by the server)
|
|
} finally {
|
|
this.release();
|
|
}
|
|
}
|
|
|
|
+ // Paper start - Anti-Xray; Add chunk packet info
|
|
@Override
|
|
- public synchronized void write(FriendlyByteBuf buffer) { // Paper - synchronize
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
|
+ public void write(FriendlyByteBuf buffer) {
|
|
+ this.write(buffer, null, 0);
|
|
+ }
|
|
+ @Override
|
|
+ public synchronized void write(FriendlyByteBuf buffer, @Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) { // Paper - Synchronize
|
|
this.acquire();
|
|
|
|
try {
|
|
- this.data.write(buffer);
|
|
+ this.data.write(buffer, chunkPacketInfo, chunkSectionIndex);
|
|
+ if (chunkPacketInfo != null) {
|
|
+ chunkPacketInfo.setPresetValues(chunkSectionIndex, this.presetValues);
|
|
+ }
|
|
+ // Paper end - Anti-Xray
|
|
} finally {
|
|
this.release();
|
|
}
|
|
}
|
|
|
|
private static <T> DataResult<PalettedContainer<T>> unpack(
|
|
- IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainerRO.PackedData<T> packedData
|
|
+ IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainerRO.PackedData<T> packedData, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues // Paper - Anti-Xray - Add preset values
|
|
) {
|
|
List<T> list = packedData.paletteEntries();
|
|
int size = strategy.size();
|
|
@@ -221,7 +299,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
}
|
|
}
|
|
|
|
- return DataResult.success(new PalettedContainer<>(registry, strategy, configuration, bitStorage, list));
|
|
+ return DataResult.success(new PalettedContainer<>(registry, strategy, configuration, bitStorage, list, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values
|
|
}
|
|
|
|
@Override
|
|
@@ -279,12 +357,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
|
|
@Override
|
|
public PalettedContainer<T> copy() {
|
|
- return new PalettedContainer<>(this);
|
|
+ return new PalettedContainer<>(this, this.presetValues); // Paper - Anti-Xray - Add preset values
|
|
}
|
|
|
|
@Override
|
|
public PalettedContainer<T> recreate() {
|
|
- return new PalettedContainer<>(this.registry, this.data.palette.valueFor(0), this.strategy);
|
|
+ return new PalettedContainer<>(this.registry, this.data.palette.valueFor(0), this.strategy, this.presetValues); // Paper - Anti-Xray - Add preset values
|
|
}
|
|
|
|
@Override
|
|
@@ -323,9 +401,16 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
return 1 + this.palette.getSerializedSize() + this.storage.getRaw().length * 8;
|
|
}
|
|
|
|
- public void write(FriendlyByteBuf buffer) {
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ public void write(FriendlyByteBuf buffer, @Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) {
|
|
buffer.writeByte(this.storage.getBits());
|
|
this.palette.write(buffer);
|
|
+ if (chunkPacketInfo != null) {
|
|
+ chunkPacketInfo.setBits(chunkSectionIndex, this.configuration.bits());
|
|
+ chunkPacketInfo.setPalette(chunkSectionIndex, this.palette);
|
|
+ chunkPacketInfo.setIndex(chunkSectionIndex, buffer.writerIndex());
|
|
+ }
|
|
+ // Paper end - Anti-Xray - Add chunk packet info
|
|
buffer.writeFixedSizeLongArray(this.storage.getRaw());
|
|
}
|
|
|
|
diff --git a/net/minecraft/world/level/chunk/PalettedContainerRO.java b/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
|
index bfbb1a2bb4abbb369a24f2f01439e9ea3e16794b..8d6ed8be4d93f7d4e6ea80c351020d88ee98aa4d 100644
|
|
--- a/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
|
+++ b/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
|
@@ -14,7 +14,10 @@ public interface PalettedContainerRO<T> {
|
|
|
|
void getAll(Consumer<T> consumer);
|
|
|
|
- void write(FriendlyByteBuf buffer);
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ @Deprecated @io.papermc.paper.annotation.DoNotUse void write(FriendlyByteBuf buffer);
|
|
+ void write(FriendlyByteBuf buffer, @javax.annotation.Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex);
|
|
+ // Paper end
|
|
|
|
int getSerializedSize();
|
|
|
|
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
|
index e846bda9517f3325f0d343758d3235382bb8980d..15417fab103feec3c1f7d5bd5b332e89d3ace3f5 100644
|
|
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
|
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
|
@@ -96,7 +96,7 @@ public record SerializableChunkData(
|
|
, @Nullable net.minecraft.nbt.Tag persistentDataContainer // CraftBukkit - persistentDataContainer
|
|
) {
|
|
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(
|
|
- Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()
|
|
+ Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), null // Paper - Anti-Xray
|
|
);
|
|
private static final Codec<List<SavedTick<Block>>> BLOCK_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.BLOCK.byNameCodec()).listOf();
|
|
private static final Codec<List<SavedTick<Fluid>>> FLUID_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.FLUID.byNameCodec()).listOf();
|
|
@@ -132,6 +132,7 @@ public record SerializableChunkData(
|
|
|
|
@Nullable
|
|
public static SerializableChunkData parse(LevelHeightAccessor levelHeightAccessor, RegistryAccess registries, CompoundTag tag) {
|
|
+ net.minecraft.server.level.ServerLevel serverLevel = (net.minecraft.server.level.ServerLevel) levelHeightAccessor; // Paper - Anti-Xray This is is seemingly only called from ChunkMap, where, we have a server level. We'll fight this later if needed.
|
|
if (tag.getString("Status").isEmpty()) {
|
|
return null;
|
|
} else {
|
|
@@ -192,15 +193,17 @@ public record SerializableChunkData(
|
|
int byteOr = compoundTag.getByteOr("Y", (byte)0);
|
|
LevelChunkSection levelChunkSection;
|
|
if (byteOr >= levelHeightAccessor.getMinSectionY() && byteOr <= levelHeightAccessor.getMaxSectionY()) {
|
|
+ final BlockState[] presetBlockStates = serverLevel.chunkPacketBlockController.getPresetBlockStates(serverLevel, chunkPos, byteOr); // Paper - Anti-Xray - Add preset block states
|
|
+ final Codec<PalettedContainer<BlockState>> blockStateCodec = presetBlockStates == null ? BLOCK_STATE_CODEC : PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), presetBlockStates); // Paper - Anti-Xray
|
|
PalettedContainer<BlockState> palettedContainer = compoundTag.getCompound("block_states")
|
|
.map(
|
|
- compoundTag1 -> BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, compoundTag1)
|
|
+ compoundTag1 -> blockStateCodec.parse(NbtOps.INSTANCE, compoundTag1) // Paper - Anti-Xray
|
|
.promotePartial(string -> logErrors(chunkPos, byteOr, string))
|
|
.getOrThrow(SerializableChunkData.ChunkReadException::new)
|
|
)
|
|
.orElseGet(
|
|
() -> new PalettedContainer<>(
|
|
- Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES
|
|
+ Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, presetBlockStates // Paper - Anti-Xray - Add preset biomes
|
|
)
|
|
);
|
|
PalettedContainer<Holder<Biome>> palettedContainerRo = compoundTag.getCompound("biomes") // CraftBukkit - read/write
|
|
@@ -211,7 +214,7 @@ public record SerializableChunkData(
|
|
)
|
|
.orElseGet(
|
|
() -> new PalettedContainer<>(
|
|
- registry.asHolderIdMap(), registry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES
|
|
+ registry.asHolderIdMap(), registry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES, null // Paper - Anti-Xray - Add preset biomes
|
|
)
|
|
);
|
|
levelChunkSection = new LevelChunkSection(palettedContainer, palettedContainerRo);
|
|
@@ -384,7 +387,7 @@ public record SerializableChunkData(
|
|
|
|
// CraftBukkit start - read/write
|
|
private static Codec<PalettedContainer<Holder<Biome>>> makeBiomeCodecRW(Registry<Biome> biomeRegistry) {
|
|
- return PalettedContainer.codecRW(biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS));
|
|
+ return PalettedContainer.codecRW(biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS), null); // Paper - Anti-Xray - Add preset biomes
|
|
}
|
|
// CraftBukkit end
|
|
|