PaperMC/Spigot-Server-Patches/0490-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
Aikar 4793f774c8
Move bedrock config under unsupported, add comments to these configs
Hopefully help 'technical minecrafters' find and understand these configs
by adding notes to them, and fixing the incorrect config placement on the
bedrock config.
2020-07-05 02:12:14 -04:00

168 lines
10 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 13 May 2020 23:01:26 -0400
Subject: [PATCH] Protect Bedrock and End Portal/Frames from being destroyed
This fixes exploits that let players destroy bedrock by Pistons, explosions
and Mushrooom/Tree generation.
These blocks are designed to not be broken except by creative players/commands.
So protect them from a multitude of methods of destroying them.
A config is provided if you rather let players use these exploits, and let
them destroy the worlds End Portals and get on top of the nether easy.
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index ac01d492872fde6df2b7113005457c714b91fe44..754e2f84526ce9d9eab1a5a4180be643d030b70a 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -411,4 +411,17 @@ public class PaperConfig {
private static void midTickChunkTasks() {
midTickChunkTasks = getInt("settings.chunk-tasks-per-tick", midTickChunkTasks);
}
+
+ public static boolean allowBlockPermanentBreakingExploits = false;
+ private static void allowBlockPermanentBreakingExploits() {
+ if (config.contains("allow-perm-block-break-exploits")) {
+ allowBlockPermanentBreakingExploits = config.getBoolean("allow-perm-block-break-exploits", false);
+ config.set("allow-perm-block-break-exploits", null);
+ }
+
+ config.set("settings.unsupported-settings.allow-permanent-block-break-exploits-readme", "This setting controls if players should be able to break bedrock, end portals and other intended to be permanent blocks.");
+ allowBlockPermanentBreakingExploits = getBoolean("settings.unsupported-settings.allow-permanent-block-break-exploits", allowBlockPermanentBreakingExploits);
+
+ }
+
}
diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java
index 4f9c6b25f152b348a00dadf4b8f58ec3adc3476e..81725611d5b8c10c05d561984f92dc67349900ec 100644
--- a/src/main/java/net/minecraft/server/Block.java
+++ b/src/main/java/net/minecraft/server/Block.java
@@ -25,6 +25,14 @@ public class Block extends BlockBase implements IMaterial {
protected final BlockStateList<Block, IBlockData> blockStateList;
private IBlockData blockData;
// Paper start
+ public final boolean isDestroyable() {
+ return com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits ||
+ this != Blocks.BEDROCK &&
+ this != Blocks.END_PORTAL_FRAME &&
+ this != Blocks.END_PORTAL &&
+ this != Blocks.END_GATEWAY &&
+ this != Blocks.MOVING_PISTON; // try to prevent creation of headless pistons
+ }
public co.aikar.timings.Timing timing;
public co.aikar.timings.Timing getTiming() {
if (timing == null) {
diff --git a/src/main/java/net/minecraft/server/BlockBase.java b/src/main/java/net/minecraft/server/BlockBase.java
index aa4bfc9fe8e917c1c19838b0a7b045a11fc9300b..ff770a3b0e5c4fcccc498ecca51dad9863b0fe0e 100644
--- a/src/main/java/net/minecraft/server/BlockBase.java
+++ b/src/main/java/net/minecraft/server/BlockBase.java
@@ -138,7 +138,7 @@ public abstract class BlockBase {
@Deprecated
public boolean a(IBlockData iblockdata, BlockActionContext blockactioncontext) {
- return this.material.isReplaceable() && (blockactioncontext.getItemStack().isEmpty() || blockactioncontext.getItemStack().getItem() != this.getItem());
+ return this.material.isReplaceable() && (blockactioncontext.getItemStack().isEmpty() || blockactioncontext.getItemStack().getItem() != this.getItem()) && (iblockdata.isDestroyable() || (blockactioncontext.getEntity() != null && blockactioncontext.getEntity().abilities.canInstantlyBuild)); // Paper
}
@Deprecated
@@ -342,7 +342,11 @@ public abstract class BlockBase {
public Block getBlock() {
return (Block) this.c;
}
-
+ // Paper start
+ public final boolean isDestroyable() {
+ return getBlock().isDestroyable();
+ }
+ // Paper end
public Material getMaterial() {
return this.g;
}
@@ -432,7 +436,7 @@ public abstract class BlockBase {
}
public EnumPistonReaction getPushReaction() {
- return this.getBlock().getPushReaction(this.p());
+ return !isDestroyable() ? EnumPistonReaction.BLOCK : this.getBlock().getPushReaction(this.p()); // Paper
}
public boolean i(IBlockAccess iblockaccess, BlockPosition blockposition) {
diff --git a/src/main/java/net/minecraft/server/BlockPiston.java b/src/main/java/net/minecraft/server/BlockPiston.java
index c068a4115e3b82f4886d822d2472e8b522946674..6b1253fe7e8d4bb71d4d19c063d3e84c167c4d7b 100644
--- a/src/main/java/net/minecraft/server/BlockPiston.java
+++ b/src/main/java/net/minecraft/server/BlockPiston.java
@@ -165,6 +165,12 @@ public class BlockPiston extends BlockDirectional {
@Override
public boolean a(IBlockData iblockdata, World world, BlockPosition blockposition, int i, int j) {
EnumDirection enumdirection = (EnumDirection) iblockdata.get(BlockPiston.FACING);
+ // Paper start - prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
+ EnumDirection directionQueuedAs = EnumDirection.fromType1(j & 7); // Paper - copied from below
+ if (!com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits && enumdirection != directionQueuedAs) {
+ return false;
+ }
+ // Paper end - prevent retracting when we're facing the wrong way
if (!world.isClientSide) {
boolean flag = this.a(world, blockposition, enumdirection);
@@ -196,7 +202,7 @@ public class BlockPiston extends BlockDirectional {
IBlockData iblockdata1 = (IBlockData) ((IBlockData) Blocks.MOVING_PISTON.getBlockData().set(BlockPistonMoving.a, enumdirection)).set(BlockPistonMoving.b, this.sticky ? BlockPropertyPistonType.STICKY : BlockPropertyPistonType.DEFAULT);
world.setTypeAndData(blockposition, iblockdata1, 20);
- world.setTileEntity(blockposition, BlockPistonMoving.a((IBlockData) this.getBlockData().set(BlockPiston.FACING, EnumDirection.fromType1(j & 7)), enumdirection, false, true));
+ world.setTileEntity(blockposition, BlockPistonMoving.a((IBlockData) this.getBlockData().set(BlockPiston.FACING, EnumDirection.fromType1(j & 7)), enumdirection, false, true)); // Paper - diff on change, j is facing direction - copy this above
world.update(blockposition, iblockdata1.getBlock());
iblockdata1.a(world, blockposition, 2);
if (this.sticky) {
@@ -225,7 +231,14 @@ public class BlockPiston extends BlockDirectional {
}
}
} else {
- world.a(blockposition.shift(enumdirection), false);
+ // Paper start - fix headless pistons breaking blocks
+ BlockPosition headPos = blockposition.shift(enumdirection);
+ if (com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits || world.getType(headPos) == Blocks.PISTON_HEAD.getBlockData().set(FACING, enumdirection)) { // double check to make sure we're not a headless piston.
+ world.setAir(headPos, false);
+ } else {
+ ((WorldServer)world).getChunkProvider().flagDirty(headPos); // ... fix client desync
+ }
+ // Paper end - fix headless pistons breaking blocks
}
world.playSound((EntityHuman) null, blockposition, SoundEffects.BLOCK_PISTON_CONTRACT, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F);
diff --git a/src/main/java/net/minecraft/server/Explosion.java b/src/main/java/net/minecraft/server/Explosion.java
index 22a19e761fdec68cc9405988b977021a8b6398eb..e408ec8c645e9ceb278a13a5b0de8ecf57f3929e 100644
--- a/src/main/java/net/minecraft/server/Explosion.java
+++ b/src/main/java/net/minecraft/server/Explosion.java
@@ -124,6 +124,7 @@ public class Explosion {
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
BlockPosition blockposition = new BlockPosition(d4, d5, d6);
IBlockData iblockdata = this.world.getType(blockposition);
+ if (!iblockdata.isDestroyable()) continue; // Paper
Fluid fluid = iblockdata.getFluid(); // Paper
Optional<Float> optional = this.k.a(this, this.world, blockposition, iblockdata, fluid);
@@ -277,7 +278,7 @@ public class Explosion {
IBlockData iblockdata = this.world.getType(blockposition);
Block block = iblockdata.getBlock();
- if (!iblockdata.isAir()) {
+ if (!iblockdata.isAir() && iblockdata.isDestroyable()) { // Paper
BlockPosition blockposition1 = blockposition.immutableCopy();
this.world.getMethodProfiler().enter("explosion_blocks");
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index ba50189b10b54f5b35448c898f8c3495ddf8e112..b598c48692ff340a081995384aeecf9a2266d10f 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -406,6 +406,10 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
public boolean a(BlockPosition blockposition, IBlockData iblockdata, int i, int j) {
// CraftBukkit start - tree generation
if (this.captureTreeGeneration) {
+ // Paper start
+ IBlockData type = getType(blockposition);
+ if (!type.isDestroyable()) return false;
+ // Paper end
CraftBlockState blockstate = capturedBlockStates.get(blockposition);
if (blockstate == null) {
blockstate = CapturedBlockState.getTreeBlockState(this, blockposition, i);