aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0706-Add-more-LimitedRegion-API.patch
blob: d8e81bbe730d11ea87959f94f2977b65783da277 (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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: dfsek <dfsek@protonmail.com>
Date: Sat, 19 Jun 2021 20:15:59 -0700
Subject: [PATCH] Add more LimitedRegion API


diff --git a/src/main/java/io/papermc/paper/world/generation/CraftProtoWorld.java b/src/main/java/io/papermc/paper/world/generation/CraftProtoWorld.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c6668c2b5e1816db7e0ebabc99af3586849e606
--- /dev/null
+++ b/src/main/java/io/papermc/paper/world/generation/CraftProtoWorld.java
@@ -0,0 +1,116 @@
+package io.papermc.paper.world.generation;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.world.entity.Mob;
+import net.minecraft.world.entity.MobSpawnType;
+import net.minecraft.world.entity.SpawnGroupData;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import org.bukkit.World;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.craftbukkit.block.CraftBlockEntityState;
+import org.bukkit.craftbukkit.block.CraftBlockState;
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
+import org.bukkit.craftbukkit.inventory.CraftMetaBlockState;
+import org.bukkit.entity.Entity;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+
+@Deprecated
+public class CraftProtoWorld implements ProtoWorld {
+    private WorldGenRegion region;
+
+    public CraftProtoWorld(WorldGenRegion region) {
+        this.region = region;
+    }
+
+    public void clearReference() {
+        region = null;
+    }
+
+    @Override
+    public void setBlockData(int x, int y, int z, @NotNull BlockData data) {
+        BlockPos position = new BlockPos(x, y, z);
+        getDelegate().setBlock(position, ((CraftBlockData) data).getState(), 3);
+    }
+
+    @Override
+    public void setBlockState(int x, int y, int z, @NotNull BlockState state) {
+        BlockPos pos = new BlockPos(x, y, z);
+        if(!state.getBlockData().matches(getDelegate().getBlockState(pos).createCraftBlockData())) {
+            throw new IllegalArgumentException("BlockData does not match! Expected " + state.getBlockData().getAsString(false) + ", got " + getDelegate().getBlockState(pos).createCraftBlockData().getAsString(false));
+        }
+        getDelegate().getBlockEntity(pos).load(((CraftBlockEntityState<?>) state).getSnapshotNBT());
+    }
+
+    @Override
+    public @NotNull BlockState getBlockState(int x, int y, int z) {
+        BlockEntity entity = getDelegate().getBlockEntity(new BlockPos(x, y, z));
+        return CraftMetaBlockState.createBlockState(entity.getBlockState().getBukkitMaterial(), entity.save(new CompoundTag()));
+    }
+
+    @Override
+    public void scheduleBlockUpdate(int x, int y, int z) {
+        BlockPos position = new BlockPos(x, y, z);
+        getDelegate().getBlockTicks().scheduleTick(position, getDelegate().getBlockIfLoaded(position), 0);
+    }
+
+    @Override
+    public void scheduleFluidUpdate(int x, int y, int z) {
+        BlockPos position = new BlockPos(x, y, z);
+        getDelegate().getLiquidTicks().scheduleTick(position, getDelegate().getFluidState(position).getType(), 0);
+    }
+
+    @Override
+    public @NotNull World getWorld() {
+        // reading/writing the returned Minecraft world causes a deadlock.
+        // By implementing this, and covering it in warnings, we're assuming people won't be stupid, and
+        // if they are stupid, they'll figure it out pretty fast.
+        return getDelegate().getMinecraftWorld().getWorld();
+    }
+
+    @Override
+    public @NotNull BlockData getBlockData(int x, int y, int z) {
+        return CraftBlockData.fromData(getDelegate().getBlockState(new BlockPos(x, y, z)));
+    }
+
+    @Override
+    public int getCenterChunkX() {
+        return getDelegate().getCenter().x;
+    }
+
+    @Override
+    public int getCenterChunkZ() {
+        return getDelegate().getCenter().z;
+    }
+
+    @SuppressWarnings({"unchecked", "deprecation"})
+    @Override
+    public <T extends Entity> @NotNull T spawn(@NotNull Vector location, @NotNull Class<T> clazz, @Nullable Consumer<T> function, CreatureSpawnEvent.@NotNull SpawnReason reason) throws IllegalArgumentException {
+        net.minecraft.world.entity.Entity entity = getDelegate().getMinecraftWorld().getWorld().createEntity(location.toLocation(getWorld()), clazz);
+        Objects.requireNonNull(entity, "Cannot spawn null entity");
+        if (entity instanceof Mob mob) {
+            mob.finalizeSpawn(getDelegate(), getDelegate().getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.COMMAND, (SpawnGroupData) null, null);
+        }
+
+        if (function != null) {
+            function.accept((T) entity.getBukkitEntity());
+        }
+
+        getDelegate().addEntity(entity, reason);
+        return (T) entity.getBukkitEntity();
+    }
+
+    @NotNull
+    private WorldGenRegion getDelegate() {
+        return Objects.requireNonNull(region, "Cannot access ProtoWorld after generation!");
+    }
+}
+
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
index d91c88d7bdfd954fa81fbf1c9ad92161d70993a6..f5ef7e026061351590f1ce77694e2d8fb8521048 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
@@ -151,7 +151,10 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe
     @Override
     public BlockState getBlockState(int x, int y, int z) {
         Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
-        return super.getBlockState(x, y, z);
+        // Paper start
+        net.minecraft.world.level.block.entity.BlockEntity entity = getHandle().getBlockEntity(new BlockPos(x, y, z));
+        return org.bukkit.craftbukkit.inventory.CraftMetaBlockState.createBlockState(entity.getBlockState().getBukkitMaterial(), entity.save(new CompoundTag()));
+        // Paper end
     }
 
     @Override
@@ -169,7 +172,7 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe
     @Override
     public void setBlockData(int x, int y, int z, BlockData blockData) {
         Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
-        super.setBlockData(x, y, z, blockData);
+        getHandle().setBlock(new BlockPos(x, y, z), ((org.bukkit.craftbukkit.block.data.CraftBlockData) blockData).getState(), 3); // Paper
     }
 
     @Override
@@ -199,4 +202,45 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe
     public void addEntityToWorld(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason) {
         this.entities.add(entity);
     }
+
+    // Paper start
+    @Override
+    public void setBlockState(int x, int y, int z, BlockState state) {
+        BlockPos pos = new BlockPos(x, y, z);
+        if (!state.getBlockData().matches(getHandle().getBlockState(pos).createCraftBlockData())) {
+            throw new IllegalArgumentException("BlockData does not match! Expected " + state.getBlockData().getAsString(false) + ", got " + getHandle().getBlockState(pos).createCraftBlockData().getAsString(false));
+        }
+        getHandle().getBlockEntity(pos).load(((org.bukkit.craftbukkit.block.CraftBlockEntityState<?>) state).getSnapshotNBT());
+    }
+
+    @Override
+    public void scheduleBlockUpdate(int x, int y, int z) {
+        BlockPos position = new BlockPos(x, y, z);
+        getHandle().getBlockTicks().scheduleTick(position, getHandle().getBlockIfLoaded(position), 0);
+    }
+
+    @Override
+    public void scheduleFluidUpdate(int x, int y, int z) {
+        BlockPos position = new BlockPos(x, y, z);
+        getHandle().getLiquidTicks().scheduleTick(position, getHandle().getFluidState(position).getType(), 0);
+    }
+
+    @Override
+    public World getWorld() {
+        // reading/writing the returned Minecraft world causes a deadlock.
+        // By implementing this, and covering it in warnings, we're assuming people won't be stupid, and
+        // if they are stupid, they'll figure it out pretty fast.
+        return getHandle().getMinecraftWorld().getWorld();
+    }
+
+    @Override
+    public int getCenterChunkX() {
+        return centerChunkX;
+    }
+
+    @Override
+    public int getCenterChunkZ() {
+        return centerChunkZ;
+    }
+    // Paper end
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
index eb82aaf9dcbc912d780a90842601da85497fa443..1b05bb78eaee548806df8ebfff1a1401e30d52e0 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
@@ -196,6 +196,12 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
         for (BlockPos lightPosition : craftData.getLights()) {
             ((ProtoChunk) chunk).addLight(new BlockPos((x << 4) + lightPosition.getX(), lightPosition.getY(), (z << 4) + lightPosition.getZ())); // PAIL rename addLightBlock
         }
+
+        // Paper start
+        io.papermc.paper.world.generation.CraftProtoWorld protoWorld = new io.papermc.paper.world.generation.CraftProtoWorld(region);
+        generator.generateDecorations(protoWorld);
+        protoWorld.clearReference(); // make sure people dont try to use the ProtoWorld after we're done with it.
+        // Paper end
     }
 
     @Override
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java
index 55dd618d8421271063843c6e65dbcaceba9a33de..56f65b49e0ce55ee5aa9d929a98ea055ce27a8a1 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java
@@ -214,11 +214,16 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
 
     @Override
     public BlockState getBlockState() {
-        Material stateMaterial = (this.material != Material.SHIELD) ? this.material : CraftMetaBlockState.shieldToBannerHack(this.blockEntityTag); // Only actually used for jigsaws
-        if (this.blockEntityTag != null) {
-            switch (this.material) {
+        // Paper start
+        return createBlockState(this.material, this.blockEntityTag);
+    }
+    public static BlockState createBlockState(Material material, CompoundTag blockEntityTag) {
+        Material stateMaterial = (material != Material.SHIELD) ? material : CraftMetaBlockState.shieldToBannerHack(blockEntityTag); // Only actually used for jigsaws
+        if (blockEntityTag != null) {
+            switch (material) {
+                // Paper end
                 case SHIELD:
-                    this.blockEntityTag.putString("id", "banner");
+                    blockEntityTag.putString("id", "banner"); // Paper
                     break;
                 case SHULKER_BOX:
                 case WHITE_SHULKER_BOX:
@@ -237,11 +242,11 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
                 case GREEN_SHULKER_BOX:
                 case RED_SHULKER_BOX:
                 case BLACK_SHULKER_BOX:
-                    this.blockEntityTag.putString("id", "shulker_box");
+                    blockEntityTag.putString("id", "shulker_box"); // Paper
                     break;
                 case BEE_NEST:
                 case BEEHIVE:
-                    this.blockEntityTag.putString("id", "beehive");
+                    blockEntityTag.putString("id", "beehive"); // Paper
                     break;
             }
         }