--- a/net/minecraft/world/level/World.java +++ b/net/minecraft/world/level/World.java @@ -77,6 +77,28 @@ import net.minecraft.world.phys.Vec3D; import net.minecraft.world.scores.Scoreboard; +// CraftBukkit start +import java.util.HashMap; +import java.util.Map; +import net.minecraft.network.protocol.game.ClientboundSetBorderCenterPacket; +import net.minecraft.network.protocol.game.ClientboundSetBorderLerpSizePacket; +import net.minecraft.network.protocol.game.ClientboundSetBorderSizePacket; +import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDelayPacket; +import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDistancePacket; +import net.minecraft.server.level.WorldServer; +import net.minecraft.world.entity.item.EntityItem; +import net.minecraft.world.level.border.IWorldBorderListener; +import net.minecraft.world.level.dimension.WorldDimension; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CapturedBlockState; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.util.CraftSpawnCategory; +import org.bukkit.entity.SpawnCategory; +import org.bukkit.event.block.BlockPhysicsEvent; +// CraftBukkit end + public abstract class World implements GeneratorAccess, AutoCloseable { public static final Codec> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION); @@ -118,7 +140,42 @@ private final DamageSources damageSources; private long subTickCount; - protected World(WorldDataMutable worlddatamutable, ResourceKey resourcekey, IRegistryCustom iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j) { + // CraftBukkit start Added the following + private final CraftWorld world; + public boolean pvpMode; + public org.bukkit.generator.ChunkGenerator generator; + + public boolean preventPoiUpdated = false; // CraftBukkit - SPIGOT-5710 + public boolean captureBlockStates = false; + public boolean captureTreeGeneration = false; + public Map capturedBlockStates = new java.util.LinkedHashMap<>(); + public Map capturedTileEntities = new HashMap<>(); + public List captureDrops; + public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); + public boolean populating; + + public CraftWorld getWorld() { + return this.world; + } + + public CraftServer getCraftServer() { + return (CraftServer) Bukkit.getServer(); + } + + public abstract ResourceKey getTypeKey(); + + protected World(WorldDataMutable worlddatamutable, ResourceKey resourcekey, IRegistryCustom iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env) { + this.generator = gen; + this.world = new CraftWorld((WorldServer) this, gen, biomeProvider, env); + + // CraftBukkit Ticks things + for (SpawnCategory spawnCategory : SpawnCategory.values()) { + if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { + this.ticksPerSpawnCategory.put(spawnCategory, (long) this.getCraftServer().getTicksPerSpawns(spawnCategory)); + } + } + + // CraftBukkit end this.profiler = supplier; this.levelData = worlddatamutable; this.dimensionTypeRegistration = holder; @@ -127,15 +184,15 @@ this.dimension = resourcekey; this.isClientSide = flag; if (dimensionmanager.coordinateScale() != 1.0D) { - this.worldBorder = new WorldBorder(this) { + this.worldBorder = new WorldBorder() { // CraftBukkit - decompile error @Override public double getCenterX() { - return super.getCenterX() / dimensionmanager.coordinateScale(); + return super.getCenterX(); // CraftBukkit } @Override public double getCenterZ() { - return super.getCenterZ() / dimensionmanager.coordinateScale(); + return super.getCenterZ(); // CraftBukkit } }; } else { @@ -148,6 +205,42 @@ this.neighborUpdater = new CollectingNeighborUpdater(this, j); this.registryAccess = iregistrycustom; this.damageSources = new DamageSources(iregistrycustom); + // CraftBukkit start + getWorldBorder().world = (WorldServer) this; + // From PlayerList.setPlayerFileData + getWorldBorder().addListener(new IWorldBorderListener() { + @Override + public void onBorderSizeSet(WorldBorder worldborder, double d0) { + getCraftServer().getHandle().broadcastAll(new ClientboundSetBorderSizePacket(worldborder), worldborder.world); + } + + @Override + public void onBorderSizeLerping(WorldBorder worldborder, double d0, double d1, long i) { + getCraftServer().getHandle().broadcastAll(new ClientboundSetBorderLerpSizePacket(worldborder), worldborder.world); + } + + @Override + public void onBorderCenterSet(WorldBorder worldborder, double d0, double d1) { + getCraftServer().getHandle().broadcastAll(new ClientboundSetBorderCenterPacket(worldborder), worldborder.world); + } + + @Override + public void onBorderSetWarningTime(WorldBorder worldborder, int i) { + getCraftServer().getHandle().broadcastAll(new ClientboundSetBorderWarningDelayPacket(worldborder), worldborder.world); + } + + @Override + public void onBorderSetWarningBlocks(WorldBorder worldborder, int i) { + getCraftServer().getHandle().broadcastAll(new ClientboundSetBorderWarningDistancePacket(worldborder), worldborder.world); + } + + @Override + public void onBorderSetDamagePerBlock(WorldBorder worldborder, double d0) {} + + @Override + public void onBorderSetDamageSafeZOne(WorldBorder worldborder, double d0) {} + }); + // CraftBukkit end } @Override @@ -205,6 +298,18 @@ @Override public boolean setBlock(BlockPosition blockposition, IBlockData iblockdata, int i, int j) { + // CraftBukkit start - tree generation + if (this.captureTreeGeneration) { + CapturedBlockState blockstate = capturedBlockStates.get(blockposition); + if (blockstate == null) { + blockstate = CapturedBlockState.getTreeBlockState(this, blockposition, i); + this.capturedBlockStates.put(blockposition.immutable(), blockstate); + } + blockstate.setData(iblockdata); + blockstate.setFlag(i); + return true; + } + // CraftBukkit end if (this.isOutsideBuildHeight(blockposition)) { return false; } else if (!this.isClientSide && this.isDebug()) { @@ -212,13 +317,29 @@ } else { Chunk chunk = this.getChunkAt(blockposition); Block block = iblockdata.getBlock(); - IBlockData iblockdata1 = chunk.setBlockState(blockposition, iblockdata, (i & 64) != 0); + + // CraftBukkit start - capture blockstates + boolean captured = false; + if (this.captureBlockStates && !this.capturedBlockStates.containsKey(blockposition)) { + CapturedBlockState blockstate = CapturedBlockState.getBlockState(this, blockposition, i); + this.capturedBlockStates.put(blockposition.immutable(), blockstate); + captured = true; + } + // CraftBukkit end + + IBlockData iblockdata1 = chunk.setBlockState(blockposition, iblockdata, (i & 64) != 0, (i & 1024) == 0); // CraftBukkit custom NO_PLACE flag if (iblockdata1 == null) { + // CraftBukkit start - remove blockstate if failed (or the same) + if (this.captureBlockStates && captured) { + this.capturedBlockStates.remove(blockposition); + } + // CraftBukkit end return false; } else { IBlockData iblockdata2 = this.getBlockState(blockposition); + /* if (iblockdata2 == iblockdata) { if (iblockdata1 != iblockdata2) { this.setBlocksDirty(blockposition, iblockdata1, iblockdata2); @@ -245,12 +366,69 @@ this.onBlockStateChange(blockposition, iblockdata1, iblockdata2); } + */ + + // CraftBukkit start + if (!this.captureBlockStates) { // Don't notify clients or update physics while capturing blockstates + // Modularize client and physic updates + notifyAndUpdatePhysics(blockposition, chunk, iblockdata1, iblockdata, iblockdata2, i, j); + } + // CraftBukkit end return true; } } } + // CraftBukkit start - Split off from above in order to directly send client and physic updates + public void notifyAndUpdatePhysics(BlockPosition blockposition, Chunk chunk, IBlockData oldBlock, IBlockData newBlock, IBlockData actualBlock, int i, int j) { + IBlockData iblockdata = newBlock; + IBlockData iblockdata1 = oldBlock; + IBlockData iblockdata2 = actualBlock; + if (iblockdata2 == iblockdata) { + if (iblockdata1 != iblockdata2) { + this.setBlocksDirty(blockposition, iblockdata1, iblockdata2); + } + + if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || (chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement + this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i); + } + + if ((i & 1) != 0) { + this.blockUpdated(blockposition, iblockdata1.getBlock()); + if (!this.isClientSide && iblockdata.hasAnalogOutputSignal()) { + this.updateNeighbourForOutputSignal(blockposition, newBlock.getBlock()); + } + } + + if ((i & 16) == 0 && j > 0) { + int k = i & -34; + + // CraftBukkit start + iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam + CraftWorld world = ((WorldServer) this).getWorld(); + if (world != null) { + BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata)); + this.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + } + // CraftBukkit end + iblockdata.updateNeighbourShapes(this, blockposition, k, j - 1); + iblockdata.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); + } + + // CraftBukkit start - SPIGOT-5710 + if (!preventPoiUpdated) { + this.onBlockStateChange(blockposition, iblockdata1, iblockdata2); + } + // CraftBukkit end + } + } + // CraftBukkit end + public void onBlockStateChange(BlockPosition blockposition, IBlockData iblockdata, IBlockData iblockdata1) {} @Override @@ -336,6 +514,14 @@ @Override public IBlockData getBlockState(BlockPosition blockposition) { + // CraftBukkit start - tree generation + if (captureTreeGeneration) { + CapturedBlockState previous = capturedBlockStates.get(blockposition); + if (previous != null) { + return previous.getHandle(); + } + } + // CraftBukkit end if (this.isOutsideBuildHeight(blockposition)) { return Blocks.VOID_AIR.defaultBlockState(); } else { @@ -518,6 +704,11 @@ case 4: explosion_effect = Explosion.Effect.TRIGGER_BLOCK; break; + // CraftBukkit start - handle custom explosion type + case 5: + explosion_effect = Explosion.Effect.DESTROY; + break; + // CraftBukkit end default: throw new MatchException((String) null, (Throwable) null); } @@ -539,6 +730,16 @@ @Nullable @Override public TileEntity getBlockEntity(BlockPosition blockposition) { + // CraftBukkit start + return getBlockEntity(blockposition, true); + } + + @Nullable + public TileEntity getBlockEntity(BlockPosition blockposition, boolean validate) { + if (capturedTileEntities.containsKey(blockposition)) { + return capturedTileEntities.get(blockposition); + } + // CraftBukkit end return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, Chunk.EnumTileEntityState.IMMEDIATE)); } @@ -546,6 +747,12 @@ BlockPosition blockposition = tileentity.getBlockPos(); if (!this.isOutsideBuildHeight(blockposition)) { + // CraftBukkit start + if (captureBlockStates) { + capturedTileEntities.put(blockposition.immutable(), tileentity); + return; + } + // CraftBukkit end this.getChunkAt(blockposition).addAndRegisterBlockEntity(tileentity); } } @@ -675,7 +882,7 @@ for (int k = 0; k < j; ++k) { EntityComplexPart entitycomplexpart = aentitycomplexpart[k]; - T t0 = (Entity) entitytypetest.tryCast(entitycomplexpart); + T t0 = entitytypetest.tryCast(entitycomplexpart); // CraftBukkit - decompile error if (t0 != null && predicate.test(t0)) { list.add(t0); @@ -953,7 +1160,7 @@ public static enum a { - NONE, BLOCK, MOB, TNT, BLOW; + NONE, BLOCK, MOB, TNT, BLOW, STANDARD; // CraftBukkit - Add STANDARD which will always use Explosion.Effect.DESTROY private a() {} }