mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-30 16:19:03 +01:00
87e443bf9a
This is an ode to all those times when you shoulda just gone to bed
189 lines
12 KiB
Diff
189 lines
12 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 6ee4d5377d3963c67c6da4e5b164e49949768f03..e849c9c9fccf928399478dc3727eba55ae5b40d4 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
|
@@ -435,4 +435,15 @@ public class PaperConfig {
|
|
private static void loggerSettings() {
|
|
deobfuscateStacktraces = getBoolean("settings.loggers.deobfuscate-stacktraces", deobfuscateStacktraces);
|
|
}
|
|
+
|
|
+ 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/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
|
index 548f103e648d9670d7434182c6598dc29ae77b57..f0c789d339fe8402c9c2a684d7e0415fa298b20e 100644
|
|
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
|
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
|
@@ -173,6 +173,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)) {
|
|
@@ -330,7 +331,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 634a858e4e03968ada7c13e26e151d8f05ad611c..ad9b48a0c89689a602c85f65e6cc68977af5ea29 100644
|
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
@@ -416,6 +416,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 b77eda6af8b430311e502465a2590d83555ff6cf..a37213bce34f45898f56a22196b0d5ef1470e812 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/Block.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
|
|
@@ -89,6 +89,19 @@ public class Block extends BlockBehaviour implements ItemLike {
|
|
protected final StateDefinition<Block, BlockState> stateDefinition;
|
|
private BlockState defaultBlockState;
|
|
// 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.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 aa4c582172221f7d48c9a64e91bdfb95a2453a6c..ebd8a234acf42f8d6ae0790bb6a60a214d22429f 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 (!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.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 (com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits || 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 3c6b1b92fedf9986ebb835170c070ebd461f5d25..9055a82e9c91ecb8fc2ef5ac58db043ffb759168 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
|
|
@@ -223,7 +223,7 @@ public abstract class BlockBehaviour {
|
|
/** @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 */
|
|
@@ -705,7 +705,11 @@ public abstract class BlockBehaviour {
|
|
public Block getBlock() {
|
|
return (Block) this.owner;
|
|
}
|
|
-
|
|
+ // Paper start
|
|
+ public final boolean isDestroyable() {
|
|
+ return getBlock().isDestroyable();
|
|
+ }
|
|
+ // Paper end
|
|
public Material getMaterial() {
|
|
return this.material;
|
|
}
|
|
@@ -803,7 +807,7 @@ public abstract class BlockBehaviour {
|
|
}
|
|
|
|
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 05150fbade1d5a9b3b6de8ad1f5e825f34d1037e..ed79058696eb26a89b9d4116821840dbad9ea449 100644
|
|
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
|
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
|
@@ -210,6 +210,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 (!com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits) {
|
|
+ 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;
|
|
}
|