aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0955-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
blob: 3fdb9f8fe4c8beffc1e19fb51560b266f7585c5f (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
170
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 0add20466890db9d2af7c595806d5e767b7ee117..32651ed15e5961a8b27fc0dc8fb54ef05b6064fe 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -193,6 +193,7 @@ public class Explosion {
                         for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
                             BlockPos blockposition = BlockPos.containing(d4, d5, d6);
                             BlockState iblockdata = this.level.getBlockState(blockposition);
+                            if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed
                             FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions
 
                             if (!this.level.isInWorldBounds(blockposition)) {
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index b7bf7b3b91046c81467aeb483087e12b6d9191bf..a2877f3eb206ab9ccb93e3606f1c9b3401def5d6 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -447,6 +447,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 - Protect Bedrock and End Portal/Frames from being destroyed
+            BlockState type = getBlockState(pos);
+            if (!type.isDestroyable()) return false;
+            // Paper end - Protect Bedrock and End Portal/Frames from being destroyed
             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 bf52c36f31992a01a7403d8c85151327c9e944c4..d775ab8b0d37797f29e650842191d40691fb7afc 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,20 @@ 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.BARRIER &&
+            this != Blocks.LIGHT &&
+            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.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 e6bfbe2588e0c2a1be14e38d654e889d392ad4db..e0c62227b279a5fe0f3868fbf9ce8c78c515a09c 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
@@ -213,6 +213,12 @@ public class PistonBaseBlock extends DirectionalBlock {
     @Override
     protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
         Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING);
+        // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; 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 - Protect Bedrock and End Portal/Frames from being destroyed
         BlockState iblockdata1 = (BlockState) state.setValue(PistonBaseBlock.EXTENDED, true);
 
         if (!world.isClientSide) {
@@ -253,7 +259,7 @@ public class PistonBaseBlock extends DirectionalBlock {
             }
             // Paper end - Fix sticky pistons and BlockPistonRetractEvent
             world.setBlock(pos, iblockdata2, 20);
-            world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true));
+            world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed; diff on change
             world.blockUpdated(pos, iblockdata2.getBlock());
             iblockdata2.updateNeighbourShapes(world, pos, 2);
             if (this.isSticky) {
@@ -289,7 +295,14 @@ public class PistonBaseBlock extends DirectionalBlock {
                     }
                 }
             } else {
-                world.removeBlock(pos.relative(enumdirection), false);
+                // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; 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 - Protect Bedrock and End Portal/Frames from being destroyed
             }
 
             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 87289d8ab94705999c67457a28538e7a5576acc3..fe7dc02ea55c2bcd39d12bfd4d315f0b8c7014c3 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
@@ -173,7 +173,7 @@ public abstract class BlockBehaviour implements FeatureElement {
     }
 
     protected void onExplosionHit(BlockState state, Level world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stackMerger) {
-        if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK) {
+        if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK && state.isDestroyable()) { // Paper - Protect Bedrock and End Portal/Frames from being destroyed
             Block block = state.getBlock();
             boolean flag = explosion.getIndirectSourceEntity() instanceof Player;
 
@@ -253,7 +253,7 @@ public abstract class BlockBehaviour implements FeatureElement {
     }
 
     protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
-        return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem()));
+        return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed
     }
 
     protected boolean canBeReplaced(BlockState state, Fluid fluid) {
@@ -882,6 +882,12 @@ public abstract class BlockBehaviour implements FeatureElement {
             return this.legacySolid;
         }
 
+        // Paper start - Protect Bedrock and End Portal/Frames from being destroyed
+        public final boolean isDestroyable() {
+            return getBlock().isDestroyable();
+        }
+        // Paper end - Protect Bedrock and End Portal/Frames from being destroyed
+
         public boolean isValidSpawn(BlockGetter world, BlockPos pos, EntityType<?> type) {
             return this.getBlock().properties.isValidSpawn.test(this.asState(), world, pos, type);
         }
@@ -985,7 +991,7 @@ public abstract class BlockBehaviour implements FeatureElement {
         }
 
         public PushReaction getPistonPushReaction() {
-            return this.pushReaction;
+            return !this.isDestroyable() ? PushReaction.BLOCK : this.pushReaction; // Paper - Protect Bedrock and End Portal/Frames from being destroyed
         }
 
         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 5c4b2a33d4007c36aef68604bca40a4eba510b4e..fd04a50183ccb1f21fc6efa70256e1bb4db2d6d4 100644
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
@@ -207,6 +207,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 - Protect Bedrock and End Portal/Frames from being destroyed
+                if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) {
+                    if (!this.level.getBlockState(temp).isDestroyable()) {
+                        return false;
+                    }
+                }
+                // Paper end - Protect Bedrock and End Portal/Frames from being destroyed
                 if (k < 0 && !this.level.getBlockState(temp).isSolid()) {
                     return false;
                 }