
A previous fix for SPIGOT-6814 implemented a callback function for the PDC implementation that could be set to actively define a chunk as unsaved, allowing chunks that have not been mutated through block changes to still require saving if the chunks pdc was mutated. This implementation however would pass a callback that references the chunk access internally, meaning the PDC now actively holds onto a callback that holds a reference to the entire chunk. Aditionally, this change also impacted the pdc for item metas and entities for really no reason whatsoever. This commit re-implements the fix by introducing a new child of the pdc implementation that the chunk now uses as its pdc. This specific implementation maintains a dirty flag that is set to `true` on any form of mutation and set back to false by the chunk that owns the PDC whenever the chunk itself is flag as no longer dirty.
204 lines
8.9 KiB
Diff
204 lines
8.9 KiB
Diff
--- a/net/minecraft/world/level/chunk/Chunk.java
|
|
+++ b/net/minecraft/world/level/chunk/Chunk.java
|
|
@@ -77,7 +77,7 @@
|
|
private final Map<BlockPosition, Chunk.d> tickersInLevel;
|
|
public boolean loaded;
|
|
private boolean clientLightReady;
|
|
- public final World level;
|
|
+ public final WorldServer level; // CraftBukkit - type
|
|
@Nullable
|
|
private Supplier<PlayerChunk.State> fullStatus;
|
|
@Nullable
|
|
@@ -94,7 +94,7 @@
|
|
super(chunkcoordintpair, chunkconverter, world, world.registryAccess().registryOrThrow(IRegistry.BIOME_REGISTRY), i, achunksection, blendingdata);
|
|
this.tickersInLevel = Maps.newHashMap();
|
|
this.clientLightReady = false;
|
|
- this.level = world;
|
|
+ this.level = (WorldServer) world; // CraftBukkit - type
|
|
this.gameEventDispatcherSections = new Int2ObjectOpenHashMap();
|
|
HeightMap.Type[] aheightmap_type = HeightMap.Type.values();
|
|
int j = aheightmap_type.length;
|
|
@@ -110,8 +110,20 @@
|
|
this.postLoad = chunk_c;
|
|
this.blockTicks = levelchunkticks;
|
|
this.fluidTicks = levelchunkticks1;
|
|
+ // CraftBukkit start
|
|
+ this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
|
|
}
|
|
|
|
+ public org.bukkit.Chunk bukkitChunk;
|
|
+ public org.bukkit.Chunk getBukkitChunk() {
|
|
+ return bukkitChunk;
|
|
+ }
|
|
+
|
|
+ public boolean mustNotSave;
|
|
+ public boolean needsDecoration;
|
|
+
|
|
+ // CraftBukkit end
|
|
+
|
|
public Chunk(WorldServer worldserver, ProtoChunk protochunk, @Nullable Chunk.c chunk_c) {
|
|
this(worldserver, protochunk.getPos(), protochunk.getUpgradeData(), protochunk.unpackBlockTicks(), protochunk.unpackFluidTicks(), protochunk.getInhabitedTime(), protochunk.getSections(), chunk_c, protochunk.getBlendingData());
|
|
Iterator iterator = protochunk.getBlockEntities().values().iterator();
|
|
@@ -142,6 +154,10 @@
|
|
|
|
this.setLightCorrect(protochunk.isLightCorrect());
|
|
this.unsaved = true;
|
|
+ this.needsDecoration = true; // CraftBukkit
|
|
+ // CraftBukkit start
|
|
+ this.persistentDataContainer = protochunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading.
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
@Override
|
|
@@ -238,9 +254,16 @@
|
|
}
|
|
}
|
|
|
|
+ // CraftBukkit start
|
|
@Nullable
|
|
@Override
|
|
public IBlockData setBlockState(BlockPosition blockposition, IBlockData iblockdata, boolean flag) {
|
|
+ return this.setBlockState(blockposition, iblockdata, flag, true);
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public IBlockData setBlockState(BlockPosition blockposition, IBlockData iblockdata, boolean flag, boolean doPlace) {
|
|
+ // CraftBukkit end
|
|
int i = blockposition.getY();
|
|
ChunkSection chunksection = this.getSection(this.getSectionIndex(i));
|
|
boolean flag1 = chunksection.hasOnlyAir();
|
|
@@ -279,7 +302,8 @@
|
|
if (!chunksection.getBlockState(j, k, l).is(block)) {
|
|
return null;
|
|
} else {
|
|
- if (!this.level.isClientSide) {
|
|
+ // 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.BlockTileEntity)) {
|
|
iblockdata.onPlace(this.level, blockposition, iblockdata1, flag);
|
|
}
|
|
|
|
@@ -324,7 +348,12 @@
|
|
|
|
@Nullable
|
|
public TileEntity getBlockEntity(BlockPosition blockposition, Chunk.EnumTileEntityState chunk_enumtileentitystate) {
|
|
- TileEntity tileentity = (TileEntity) this.blockEntities.get(blockposition);
|
|
+ // CraftBukkit start
|
|
+ TileEntity tileentity = level.capturedTileEntities.get(blockposition);
|
|
+ if (tileentity == null) {
|
|
+ tileentity = (TileEntity) this.blockEntities.get(blockposition);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
|
|
if (tileentity == null) {
|
|
NBTTagCompound nbttagcompound = (NBTTagCompound) this.pendingBlockEntities.remove(blockposition);
|
|
@@ -395,6 +424,13 @@
|
|
tileentity1.setRemoved();
|
|
}
|
|
|
|
+ // CraftBukkit start
|
|
+ } else {
|
|
+ System.out.println("Attempted to place a tile entity (" + tileentity + ") at " + tileentity.getBlockPos().getX() + "," + tileentity.getBlockPos().getY() + "," + tileentity.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
|
|
}
|
|
}
|
|
|
|
@@ -424,6 +460,12 @@
|
|
if (this.isInLevel()) {
|
|
TileEntity tileentity = (TileEntity) this.blockEntities.remove(blockposition);
|
|
|
|
+ // CraftBukkit start - SPIGOT-5561: Also remove from pending map
|
|
+ if (!pendingBlockEntities.isEmpty()) {
|
|
+ pendingBlockEntities.remove(blockposition);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
if (tileentity != null) {
|
|
this.removeGameEventListener(tileentity);
|
|
tileentity.setRemoved();
|
|
@@ -471,6 +513,55 @@
|
|
|
|
}
|
|
|
|
+ // 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.
|
|
+ */
|
|
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(this.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.event.world.ChunkUnloadEvent unloadEvent = new org.bukkit.event.world.ChunkUnloadEvent(this.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;
|
|
}
|
|
@@ -659,7 +750,7 @@
|
|
|
|
private <T extends TileEntity> void updateBlockEntityTicker(T t0) {
|
|
IBlockData iblockdata = t0.getBlockState();
|
|
- BlockEntityTicker<T> blockentityticker = iblockdata.getTicker(this.level, t0.getType());
|
|
+ BlockEntityTicker<T> blockentityticker = iblockdata.getTicker(this.level, (TileEntityTypes<T>) t0.getType()); // CraftBukkit - decompile error
|
|
|
|
if (blockentityticker == null) {
|
|
this.removeBlockEntityTicker(t0.getBlockPos());
|
|
@@ -752,7 +843,7 @@
|
|
private boolean loggedInvalidBlockState;
|
|
|
|
a(TileEntity tileentity, BlockEntityTicker blockentityticker) {
|
|
- this.blockEntity = tileentity;
|
|
+ this.blockEntity = (T) tileentity; // CraftBukkit - decompile error
|
|
this.ticker = blockentityticker;
|
|
}
|
|
|
|
@@ -775,7 +866,7 @@
|
|
this.loggedInvalidBlockState = true;
|
|
Chunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new org.apache.logging.log4j.util.Supplier[]{this::getType, this::getPos, () -> {
|
|
return iblockdata;
|
|
- }});
|
|
+ }}); // CraftBukkit - squelch checkstyle
|
|
}
|
|
|
|
gameprofilerfiller.pop();
|