Paper/patches/server/0407-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
Jake Potrebic 51cfcc88da
Updated Upstream (Bukkit/CraftBukkit) (#8740)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
d352d965 SPIGOT-7221: Add Enemy (Entity) interface

CraftBukkit Changes:
397c5557c SPIGOT-7221: Add Enemy (Entity) interface
a0d3dfaf2 PR-1129: Fix state corruption while handling explosion damage on EntityComplexPart
d67777f8b SPIGOT-7218: Player's outer layer of skin disappears after respawn
2023-01-01 12:17:40 -08:00

170 lines
11 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/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index cc8dcb77f2b6d447c0e8d769a3d233dc2eb64efa..0a2f5e929d34c933755e9bc4b205e1b2ad0ce3bc 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -168,6 +168,7 @@ public class Explosion {
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
BlockPos blockposition = new BlockPos(d4, d5, d6);
BlockState iblockdata = this.level.getBlockState(blockposition);
+ if (!iblockdata.isDestroyable()) continue; // Paper
FluidState fluid = iblockdata.getFluidState(); // Paper
if (!this.level.isInWorldBounds(blockposition)) {
@@ -347,7 +348,7 @@ public class Explosion {
BlockState iblockdata = this.level.getBlockState(blockposition);
Block block = iblockdata.getBlock();
- if (!iblockdata.isAir()) {
+ if (!iblockdata.isAir() && iblockdata.isDestroyable()) { // Paper
BlockPos blockposition1 = blockposition.immutable();
this.level.getProfiler().push("explosion_blocks");
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 6498a4073867fc2cb24e2d75776d2a84661846fb..44f0325e8762e1bc528ab22d56a71322dbc84bd6 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -428,6 +428,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
// CraftBukkit start - tree generation
if (this.captureTreeGeneration) {
+ // Paper start
+ BlockState type = getBlockState(pos);
+ if (!type.isDestroyable()) return false;
+ // Paper end
CraftBlockState blockstate = this.capturedBlockStates.get(pos);
if (blockstate == null) {
blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags);
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
index 11b0b1a217648496ccf08f09bb3aa53904ffa9cb..a9171ca47e836428e1b5c8366898a94702242e13 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -90,6 +90,19 @@ public class Block extends BlockBehaviour implements ItemLike {
protected final StateDefinition<Block, BlockState> stateDefinition;
private BlockState defaultBlockState;
// Paper start
+ public final boolean isDestroyable() {
+ return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
+ this != Blocks.BEDROCK &&
+ this != Blocks.END_PORTAL_FRAME &&
+ this != Blocks.END_PORTAL &&
+ this != Blocks.END_GATEWAY &&
+ this != Blocks.COMMAND_BLOCK &&
+ this != Blocks.REPEATING_COMMAND_BLOCK &&
+ this != Blocks.CHAIN_COMMAND_BLOCK &&
+ this != Blocks.BARRIER &&
+ this != Blocks.STRUCTURE_BLOCK &&
+ this != Blocks.JIGSAW;
+ }
public co.aikar.timings.Timing timing;
public co.aikar.timings.Timing getTiming() {
if (timing == null) {
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index 76720517cd2d82065eb8430cf854b536295341db..29755807fdb6c30e31c0ec2bbf33bed9afd5d478 100644
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -199,6 +199,12 @@ public class PistonBaseBlock extends DirectionalBlock {
@Override
public boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING);
+ // Paper start - prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
+ Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && enumdirection != directionQueuedAs) {
+ return false;
+ }
+ // Paper end - prevent retracting when we're facing the wrong way
if (!world.isClientSide) {
boolean flag = this.getNeighborSignal(world, pos, enumdirection);
@@ -231,7 +237,7 @@ public class PistonBaseBlock extends DirectionalBlock {
BlockState iblockdata1 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
world.setBlock(pos, iblockdata1, 20);
- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata1, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true));
+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata1, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change
world.blockUpdated(pos, iblockdata1.getBlock());
iblockdata1.updateNeighbourShapes(world, pos, 2);
if (this.isSticky) {
@@ -260,7 +266,14 @@ public class PistonBaseBlock extends DirectionalBlock {
}
}
} else {
- world.removeBlock(pos.relative(enumdirection), false);
+ // Paper start - fix headless pistons breaking blocks
+ BlockPos headPos = pos.relative(enumdirection);
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston.
+ world.removeBlock(headPos, false);
+ } else {
+ ((ServerLevel)world).getChunkSource().blockChanged(headPos); // ... fix client desync
+ }
+ // Paper end - fix headless pistons breaking blocks
}
world.playSound((Player) null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F);
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
index c53b80cba9ea658d20e527a9bfcd6b5d7d9f51fc..6a549229037c8b8c2093feb563780ef8565d709f 100644
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -234,7 +234,7 @@ public abstract class BlockBehaviour implements FeatureElement {
/** @deprecated */
@Deprecated
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
- return this.material.isReplaceable() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem()));
+ return this.material.isReplaceable() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper
}
/** @deprecated */
@@ -775,6 +775,12 @@ public abstract class BlockBehaviour implements FeatureElement {
return ((Block) this.owner).builtInRegistryHolder();
}
+ // Paper start
+ public final boolean isDestroyable() {
+ return getBlock().isDestroyable();
+ }
+ // Paper end
+
public Material getMaterial() {
return this.material;
}
@@ -872,7 +878,7 @@ public abstract class BlockBehaviour implements FeatureElement {
}
public PushReaction getPistonPushReaction() {
- return this.getBlock().getPistonPushReaction(this.asState());
+ return !isDestroyable() ? PushReaction.BLOCK : this.getBlock().getPistonPushReaction(this.asState()); // Paper
}
public boolean isSolidRender(BlockGetter world, BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
index d1c7eba29c64a6dbf55d3062ced9769eecb548ed..faaf50cb9bce254aef554ed8b402b145532e12a4 100644
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
@@ -221,6 +221,13 @@ public class PortalForcer {
for (int j = -1; j < 3; ++j) {
for (int k = -1; k < 4; ++k) {
temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal);
+ // Paper start - prevent destroying unbreakable blocks
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) {
+ if (!this.level.getBlockState(temp).isDestroyable()) {
+ return false;
+ }
+ }
+ // Paper end - prevent destroying unbreakable blocks
if (k < 0 && !this.level.getBlockState(temp).getMaterial().isSolid()) {
return false;
}