aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0411-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
blob: 7c01a4e8b6ecaeff6349ad098c44dd84aab24a85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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 38bb502e9f1272020a23a3ef8ebb0cb1a5a251ef..b18b0e1b5e059f08fd3117eaa0fb28a10fac6562 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -172,6 +172,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)) {
@@ -350,7 +351,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 426fe552d2444a4977a3e261d7e60fbda0893756..ea3b4c52769ff8112d865b226c8d3dcf48982787 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -429,6 +429,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 77125720fcbeb7bfc180effb27cfb78c74832ce5..cb11cef117fc896ddcb40993ddb852a2e717c2ad 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -92,6 +92,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 61a792c5ccf3688d4f78c6e7461090f63a0cc26a..b2ab7749e3ddf124d5ef97271a76dc875a650771 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 */
@@ -741,6 +741,12 @@ public abstract class BlockBehaviour {
             return ((Block) this.owner).builtInRegistryHolder();
         }
 
+        // Paper start
+        public final boolean isDestroyable() {
+            return getBlock().isDestroyable();
+        }
+        // Paper end
+
         public Material getMaterial() {
             return this.material;
         }
@@ -838,7 +844,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 7aa6181237eaec1df2ed2fdcd3b1137dfe89ce69..1311d69bb2fa7b3617936e6ad6eb5236fedc260d 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 (!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;
                 }