diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java index f1af8a5b5c..ad8a529da7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java @@ -271,7 +271,7 @@ public abstract class CraftRegionAccessor implements RegionAccessor { @Override public void setBlockData(int x, int y, int z, BlockData blockData) { - getHandle().setTypeAndData(new BlockPosition(x, y, z), ((CraftBlockData) blockData).getState(), 3); + CraftBlock.at(getHandle(), new BlockPosition(x, y, z)).setTypeAndData(((CraftBlockData) blockData).getState(), true); } @Override @@ -295,6 +295,7 @@ public abstract class CraftRegionAccessor implements RegionAccessor { BlockPosition pos = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); BlockStateListPopulator populator = new BlockStateListPopulator(getHandle()); boolean result = generateTree(populator, getHandle().getMinecraftWorld().getChunkProvider().generator, pos, random, treeType); + populator.refreshTiles(); for (BlockState blockState : populator.getList()) { if (consumer != null) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java index 43d8c9787d..47243111b1 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java @@ -41,6 +41,10 @@ public class CraftBlockEntityState extends CraftBlockState this.load(snapshot); } + public void refreshSnapshot() { + this.load(tileEntity); + } + private T createSnapshot(T tileEntity) { if (tileEntity == null) { return null; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java index 153591593f..b4e94915e0 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java @@ -34,12 +34,7 @@ public class CraftBlockState implements BlockState { this.data = ((CraftBlock) block).getNMS(); this.flag = 3; - GeneratorAccess generatorAccess = ((CraftBlock) block).getHandle(); - if (generatorAccess instanceof net.minecraft.world.level.World) { - this.weakWorld = null; - } else { - this.weakWorld = new WeakReference<>(generatorAccess); - } + setWorldHandle(((CraftBlock) block).getHandle()); } public CraftBlockState(final Block block, int flag) { @@ -62,6 +57,14 @@ public class CraftBlockState implements BlockState { return new CraftBlockState(CraftBlock.at(world, pos), flag); } + public void setWorldHandle(GeneratorAccess generatorAccess) { + if (generatorAccess instanceof net.minecraft.world.level.World) { + this.weakWorld = null; + } else { + this.weakWorld = new WeakReference<>(generatorAccess); + } + } + public GeneratorAccess getWorldHandle() { if (weakWorld == null) { return world.getHandle(); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java index a5eeccb649..25c531ceb8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java @@ -1,55 +1,97 @@ package org.bukkit.craftbukkit.util; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Predicate; import net.minecraft.core.BlockPosition; +import net.minecraft.server.level.WorldServer; import net.minecraft.world.level.GeneratorAccess; +import net.minecraft.world.level.block.ITileEntity; +import net.minecraft.world.level.block.entity.TileEntity; import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.dimension.DimensionManager; import net.minecraft.world.level.material.Fluid; import org.bukkit.block.BlockState; import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockEntityState; import org.bukkit.craftbukkit.block.CraftBlockState; public class BlockStateListPopulator extends DummyGeneratorAccess { private final GeneratorAccess world; + private final Map dataMap = new HashMap<>(); + private final Map entityMap = new HashMap<>(); private final LinkedHashMap list; public BlockStateListPopulator(GeneratorAccess world) { this(world, new LinkedHashMap<>()); } - public BlockStateListPopulator(GeneratorAccess world, LinkedHashMap list) { + private BlockStateListPopulator(GeneratorAccess world, LinkedHashMap list) { this.world = world; this.list = list; } @Override public IBlockData getType(BlockPosition bp) { - CraftBlockState state = list.get(bp); - return (state != null) ? state.getHandle() : world.getType(bp); + IBlockData blockData = dataMap.get(bp); + return (blockData != null) ? blockData : world.getType(bp); } @Override public Fluid getFluid(BlockPosition bp) { - CraftBlockState state = list.get(bp); - return (state != null) ? state.getHandle().getFluid() : world.getFluid(bp); + IBlockData blockData = dataMap.get(bp); + return (blockData != null) ? blockData.getFluid() : world.getFluid(bp); + } + + @Override + public TileEntity getTileEntity(BlockPosition blockposition) { + // The contains is important to check for null values + if (entityMap.containsKey(blockposition)) { + return entityMap.get(blockposition); + } + + return world.getTileEntity(blockposition); } @Override public boolean setTypeAndData(BlockPosition position, IBlockData data, int flag) { - CraftBlockState state = (CraftBlockState) CraftBlock.at(world, position).getState(); - state.setFlag(flag); - state.setData(data); + position = position.immutableCopy(); // remove first to keep insertion order list.remove(position); - list.put(position.immutableCopy(), state); + + dataMap.put(position, data); + if (data.isTileEntity()) { + entityMap.put(position, ((ITileEntity) data.getBlock()).createTile(position, data)); + } else { + entityMap.put(position, null); + } + + // use 'this' to ensure that the block state is the correct TileState + CraftBlockState state = (CraftBlockState) CraftBlock.at(this, position).getState(); + state.setFlag(flag); + // set world handle to ensure that updated calls are done to the world and not to this populator + state.setWorldHandle(world); + list.put(position, state); return true; } + @Override + public WorldServer getMinecraftWorld() { + return world.getMinecraftWorld(); + } + + public void refreshTiles() { + for (CraftBlockState state : list.values()) { + if (state instanceof CraftBlockEntityState) { + ((CraftBlockEntityState) state).refreshSnapshot(); + } + } + } + public void updateList() { for (BlockState state : list.values()) { state.update(true);