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
|
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -70,9 +73,9 @@
return "<null>";
}
};
- private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel = Maps.newHashMap();
- private boolean loaded;
- final Level level;
+ private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel;
+ public boolean loaded;
+ public final ServerLevel level; // CraftBukkit - type
@Nullable
private Supplier<FullChunkStatus> fullStatus;
@Nullable
@@ -85,20 +88,13 @@
this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null);
}
- public LevelChunk(
- Level level,
- ChunkPos pos,
- UpgradeData data,
- LevelChunkTicks<Block> blockTicks,
- LevelChunkTicks<Fluid> fluidTicks,
- long inhabitedTime,
- @Nullable LevelChunkSection[] sections,
- @Nullable LevelChunk.PostLoadProcessor postLoad,
- @Nullable BlendingData blendingData
- ) {
- super(pos, data, level, level.registryAccess().registryOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData);
- this.level = level;
- this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>();
+ public LevelChunk(Level level, ChunkPos pos, UpgradeData data, LevelChunkTicks<Block> blockTicks, LevelChunkTicks<Fluid> fluidTicks, long inhabitedTime, @Nullable LevelChunkSection[] achunksection, @Nullable LevelChunk.PostLoadProcessor sections, @Nullable BlendingData postLoad) {
+ super(pos, data, level, level.registryAccess().registryOrThrow(Registries.BIOME), inhabitedTime, achunksection, postLoad);
+ this.tickersInLevel = Maps.newHashMap();
+ this.level = (ServerLevel) level; // CraftBukkit - type
+ this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap();
+ Heightmap.Types[] aheightmap_type = Heightmap.Types.values();
+ int j = aheightmap_type.length;
for (Heightmap.Types types : Heightmap.Types.values()) {
if (ChunkStatus.FULL.heightmapsAfter().contains(types)) {
@@ -111,6 +109,11 @@
this.fluidTicks = fluidTicks;
}
+ // CraftBukkit start
+ public boolean mustNotSave;
+ public boolean needsDecoration;
+ // CraftBukkit end
+
public LevelChunk(ServerLevel level, ProtoChunk chunk, @Nullable LevelChunk.PostLoadProcessor postLoad) {
this(
level,
@@ -146,6 +145,10 @@
this.skyLightSources = chunk.skyLightSources;
this.setLightCorrect(chunk.isLightCorrect());
this.unsaved = true;
+ this.needsDecoration = true; // CraftBukkit
+ // CraftBukkit start
+ this.persistentDataContainer = chunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading.
+ // CraftBukkit end
}
@Override
@@ -231,13 +253,21 @@
}
}
+ // CraftBukkit start
@Nullable
@Override
- public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving) {
- int y = pos.getY();
- LevelChunkSection section = this.getSection(this.getSectionIndex(y));
- boolean hasOnlyAir = section.hasOnlyAir();
- if (hasOnlyAir && state.isAir()) {
+ public IBlockData setBlockState(BlockPos pos, IBlockData state, boolean isMoving) {
+ return this.setBlockState(pos, state, isMoving, true);
+ }
+
+ @Nullable
+ public IBlockData setBlockState(BlockPos blockposition, IBlockData iblockdata, boolean flag, boolean doPlace) {
+ // CraftBukkit end
+ int i = blockposition.getY();
+ LevelChunkSection chunksection = this.getSection(this.getSectionIndex(i));
+ boolean flag1 = chunksection.hasOnlyAir();
+
+ if (flag1 && iblockdata.isAir()) {
return null;
} else {
int i = pos.getX() & 15;
@@ -276,8 +311,9 @@
if (!section.getBlockState(i, i1, i2).is(block)) {
return null;
} else {
- if (!this.level.isClientSide) {
- state.onPlace(this.level, pos, blockState, isMoving);
+ // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
+ if (!this.level.isClientSide && doPlace && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) {
+ iblockdata.onPlace(this.level, blockposition, iblockdata1, flag);
}
if (state.hasBlockEntity()) {
@@ -318,14 +356,22 @@
}
@Nullable
- public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) {
- BlockEntity blockEntity = this.blockEntities.get(pos);
- if (blockEntity == null) {
- CompoundTag compoundTag = this.pendingBlockEntities.remove(pos);
- if (compoundTag != null) {
- BlockEntity blockEntity1 = this.promotePendingBlockEntity(pos, compoundTag);
- if (blockEntity1 != null) {
- return blockEntity1;
+ public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EnumTileEntityState creationType) {
+ // CraftBukkit start
+ BlockEntity tileentity = level.capturedTileEntities.get(pos);
+ if (tileentity == null) {
+ tileentity = (BlockEntity) this.blockEntities.get(pos);
+ }
+ // CraftBukkit end
+
+ if (tileentity == null) {
+ CompoundTag nbttagcompound = (CompoundTag) this.pendingBlockEntities.remove(pos);
+
+ if (nbttagcompound != null) {
+ BlockEntity tileentity1 = this.promotePendingBlockEntity(pos, nbttagcompound);
+
+ if (tileentity1 != null) {
+ return tileentity1;
}
}
}
@@ -378,6 +439,14 @@
if (blockEntity1 != null && blockEntity1 != blockEntity) {
blockEntity1.setRemoved();
}
+
+ // CraftBukkit start
+ } else {
+ System.out.println("Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + "," + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
+ + " (" + getBlockState(blockposition) + ") where there was no entity tile!");
+ System.out.println("Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
+ new Exception().printStackTrace();
+ // CraftBukkit end
}
}
@@ -403,10 +474,21 @@
@Override
public void removeBlockEntity(BlockPos pos) {
if (this.isInLevel()) {
- BlockEntity blockEntity = this.blockEntities.remove(pos);
- if (blockEntity != null) {
- if (this.level instanceof ServerLevel serverLevel) {
- this.removeGameEventListener(blockEntity, serverLevel);
+ BlockEntity tileentity = (BlockEntity) this.blockEntities.remove(pos);
+
+ // CraftBukkit start - SPIGOT-5561: Also remove from pending map
+ if (!pendingBlockEntities.isEmpty()) {
+ pendingBlockEntities.remove(pos);
+ }
+ // CraftBukkit end
+
+ if (tileentity != null) {
+ Level world = this.level;
+
+ if (world instanceof ServerLevel) {
+ ServerLevel worldserver = (ServerLevel) world;
+
+ this.removeGameEventListener(tileentity, worldserver);
}
blockEntity.setRemoved();
@@ -446,6 +535,57 @@
}
}
+ // CraftBukkit start
+ public void loadCallback() {
+ org.bukkit.Server server = this.level.getCraftServer();
+ if (server != null) {
+ /*
+ * If it's a new world, the first few chunks are generated inside
+ * the World constructor. We can't reliably alter that, so we have
+ * no way of creating a CraftWorld/CraftServer at that point.
+ */
+ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration));
+
+ if (this.needsDecoration) {
+ this.needsDecoration = false;
+ java.util.Random random = new java.util.Random();
+ random.setSeed(level.getSeed());
+ long xRand = random.nextLong() / 2L * 2L + 1L;
+ long zRand = random.nextLong() / 2L * 2L + 1L;
+ random.setSeed((long) this.chunkPos.x * xRand + (long) this.chunkPos.z * zRand ^ level.getSeed());
+
+ org.bukkit.World world = this.level.getWorld();
+ if (world != null) {
+ this.level.populating = true;
+ try {
+ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
+ populator.populate(world, random, bukkitChunk);
+ }
+ } finally {
+ this.level.populating = false;
+ }
+ }
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk));
+ }
+ }
+ }
+
+ public void unloadCallback() {
+ org.bukkit.Server server = this.level.getCraftServer();
+ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
+ org.bukkit.event.world.ChunkUnloadEvent unloadEvent = new org.bukkit.event.world.ChunkUnloadEvent(bukkitChunk, this.isUnsaved());
+ server.getPluginManager().callEvent(unloadEvent);
+ // note: saving can be prevented, but not forced if no saving is actually required
+ this.mustNotSave = !unloadEvent.isSaveChunk();
+ }
+
+ @Override
+ public boolean isUnsaved() {
+ return super.isUnsaved() && !this.mustNotSave;
+ }
+ // CraftBukkit end
+
public boolean isEmpty() {
return false;
}
|