diff --git a/patches/server/Add-BellRevealRaiderEvent.patch b/patches/server/Add-BellRevealRaiderEvent.patch index 06df17f771..40dcabe4a7 100644 --- a/patches/server/Add-BellRevealRaiderEvent.patch +++ b/patches/server/Add-BellRevealRaiderEvent.patch @@ -25,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + private static void glow(LivingEntity entity) { glow(entity, null); } + private static void glow(LivingEntity entity, @javax.annotation.Nullable BlockPos pos) { -+ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(entity.level.getWorld().getBlockAt(net.minecraft.server.MCUtil.toLocation(entity.level, pos)), entity.getBukkitEntity()).callEvent()) return; ++ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(entity.level.getWorld().getBlockAt(io.papermc.paper.util.MCUtil.toLocation(entity.level, pos)), entity.getBukkitEntity()).callEvent()) return; + // Paper end entity.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60)); } diff --git a/patches/server/Add-BellRingEvent.patch b/patches/server/Add-BellRingEvent.patch index ad51b0b6db..39e0a65831 100644 --- a/patches/server/Add-BellRingEvent.patch +++ b/patches/server/Add-BellRingEvent.patch @@ -14,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.stats.Stats; diff --git a/patches/server/Add-LivingEntity-getTargetEntity.patch b/patches/server/Add-LivingEntity-getTargetEntity.patch index 48df5ecfbd..f4f2b86695 100644 --- a/patches/server/Add-LivingEntity-getTargetEntity.patch +++ b/patches/server/Add-LivingEntity-getTargetEntity.patch @@ -68,7 +68,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import java.util.ArrayList; @@ -0,0 +0,0 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { new com.destroystokyo.paper.block.TargetBlockInfo(org.bukkit.craftbukkit.block.CraftBlock.at(getHandle().level, ((net.minecraft.world.phys.BlockHitResult)rayTrace).getBlockPos()), - net.minecraft.server.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection())); + io.papermc.paper.util.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection())); } + + public Entity getTargetEntity(int maxDistance, boolean ignoreBlocks) { diff --git a/patches/server/Add-PhantomPreSpawnEvent.patch b/patches/server/Add-PhantomPreSpawnEvent.patch index a08610b21f..8e2def97c9 100644 --- a/patches/server/Add-PhantomPreSpawnEvent.patch +++ b/patches/server/Add-PhantomPreSpawnEvent.patch @@ -55,7 +55,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import java.util.Iterator; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.stats.ServerStatsCounter; diff --git a/patches/server/Add-PlayerSetSpawnEvent.patch b/patches/server/Add-PlayerSetSpawnEvent.patch index 74a19688e3..9f288250c0 100644 --- a/patches/server/Add-PlayerSetSpawnEvent.patch +++ b/patches/server/Add-PlayerSetSpawnEvent.patch @@ -58,7 +58,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + boolean willNotify = false; if (pos != null) { boolean flag2 = pos.equals(this.respawnPosition) && dimension.equals(this.respawnDimension); -+ spawnLoc = net.minecraft.server.MCUtil.toLocation(this.getServer().getLevel(dimension), pos); ++ spawnLoc = io.papermc.paper.util.MCUtil.toLocation(this.getServer().getLevel(dimension), pos); + spawnLoc.setYaw(angle); + willNotify = sendMessage && !flag2; + } @@ -68,7 +68,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + if (event.getLocation() != null) { + dimension = event.getLocation().getWorld() != null ? ((CraftWorld) event.getLocation().getWorld()).getHandle().dimension() : dimension; -+ pos = net.minecraft.server.MCUtil.toBlockPosition(event.getLocation()); ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(event.getLocation()); + angle = (float) event.getLocation().getYaw(); + forced = event.isForced(); + // Paper end diff --git a/patches/server/Add-PlayerShearBlockEvent.patch b/patches/server/Add-PlayerShearBlockEvent.patch index cf67fece11..bdf1df8b3a 100644 --- a/patches/server/Add-PlayerShearBlockEvent.patch +++ b/patches/server/Add-PlayerShearBlockEvent.patch @@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (itemstack.is(Items.SHEARS)) { + // Paper start - Add PlayerShearBlockEvent -+ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), net.minecraft.server.MCUtil.toBukkitBlock(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (hand == InteractionHand.OFF_HAND ? org.bukkit.inventory.EquipmentSlot.OFF_HAND : org.bukkit.inventory.EquipmentSlot.HAND), new java.util.ArrayList<>()); ++ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (hand == InteractionHand.OFF_HAND ? org.bukkit.inventory.EquipmentSlot.OFF_HAND : org.bukkit.inventory.EquipmentSlot.HAND), new java.util.ArrayList<>()); + event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.HONEYCOMB, 3))); + if (!event.callEvent()) { + return InteractionResult.PASS; @@ -47,7 +47,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (itemStack.is(Items.SHEARS)) { if (!world.isClientSide) { + // Paper start - Add PlayerShearBlockEvent -+ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), net.minecraft.server.MCUtil.toBukkitBlock(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (hand == InteractionHand.OFF_HAND ? org.bukkit.inventory.EquipmentSlot.OFF_HAND : org.bukkit.inventory.EquipmentSlot.HAND), new java.util.ArrayList<>()); ++ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (hand == InteractionHand.OFF_HAND ? org.bukkit.inventory.EquipmentSlot.OFF_HAND : org.bukkit.inventory.EquipmentSlot.HAND), new java.util.ArrayList<>()); + event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.PUMPKIN_SEEDS, 4))); + if (!event.callEvent()) { + return InteractionResult.PASS; diff --git a/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch b/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch index 7c0ab821b6..cbb6022325 100644 --- a/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch +++ b/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch @@ -64,7 +64,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + // Paper start + private void addTicket(int x, int z) { -+ net.minecraft.server.MCUtil.MAIN_EXECUTOR.execute(() -> world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper ++ io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper } + // Paper end @@ -112,7 +112,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return true; // Paper end @@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World { - net.minecraft.server.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { + io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c; + if (chunk != null) addTicket(x, z); // Paper diff --git a/patches/server/Add-StructuresLocateEvent.patch b/patches/server/Add-StructuresLocateEvent.patch index 6627a735db..69dad626c0 100644 --- a/patches/server/Add-StructuresLocateEvent.patch +++ b/patches/server/Add-StructuresLocateEvent.patch @@ -81,7 +81,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public Pair> findNearestMapStructure(ServerLevel world, HolderSet structures, BlockPos center, int radius, boolean skipReferencedStructures) { + // Paper start - StructureLocateEvent + final org.bukkit.World bukkitWorld = world.getWorld(); -+ final org.bukkit.Location origin = net.minecraft.server.MCUtil.toLocation(world, center); ++ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(world, center); + final var paperRegistry = io.papermc.paper.registry.PaperRegistry.getRegistry(io.papermc.paper.registry.RegistryKey.CONFIGURED_STRUCTURE_REGISTRY); + final List configuredStructures = new ArrayList<>(); + paperRegistry.convertToApi(structures, configuredStructures::add, false); // gracefully handle missing api, use tests to check (or exclude) @@ -91,9 +91,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; + } + if (event.getResult() != null) { -+ return Pair.of(net.minecraft.server.MCUtil.toBlockPosition(event.getResult().position()), paperRegistry.getMinecraftHolder(event.getResult().configuredStructure())); ++ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPosition(event.getResult().position()), paperRegistry.getMinecraftHolder(event.getResult().configuredStructure())); + } -+ center = net.minecraft.server.MCUtil.toBlockPosition(event.getOrigin()); ++ center = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin()); + radius = event.getRadius(); + skipReferencedStructures = event.shouldFindUnexplored(); + structures = HolderSet.direct(paperRegistry::getMinecraftHolder, event.getConfiguredStructures()); diff --git a/patches/server/Add-TNTPrimeEvent.patch b/patches/server/Add-TNTPrimeEvent.patch index 74f5726e53..cee2094e47 100644 --- a/patches/server/Add-TNTPrimeEvent.patch +++ b/patches/server/Add-TNTPrimeEvent.patch @@ -36,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (block instanceof TntBlock) { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, blockposition); ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, blockposition); + if (!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.FIRE, null).callEvent()) { + return; + } @@ -54,7 +54,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!oldState.is(state.getBlock())) { if (world.hasNeighborSignal(pos)) { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, pos);; ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos);; + if(!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.REDSTONE, null).callEvent()) + return; + // Paper end @@ -66,7 +66,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { if (world.hasNeighborSignal(pos)) { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, pos);; ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos);; + if(!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.REDSTONE, null).callEvent()) + return; + // Paper end @@ -78,7 +78,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void wasExploded(Level world, BlockPos pos, Explosion explosion) { if (!world.isClientSide) { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, pos); ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos); + org.bukkit.entity.Entity source = explosion.source != null ? explosion.source.getBukkitEntity() : null; + if(!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.EXPLOSION, source).callEvent()) + return; @@ -91,7 +91,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return super.use(state, world, pos, player, hand, hit); } else { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, pos); ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos); + if(!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.ITEM, player.getBukkitEntity()).callEvent()) + return InteractionResult.FAIL; + // Paper end @@ -103,7 +103,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // CraftBukkit end + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, blockposition); ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, blockposition); + if (!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.PROJECTILE, projectile.getBukkitEntity()).callEvent()) { + return; + } diff --git a/patches/server/Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/server/Add-methods-to-find-targets-for-lightning-strikes.patch index 1cff673c74..dc11339610 100644 --- a/patches/server/Add-methods-to-find-targets-for-lightning-strikes.patch +++ b/patches/server/Add-methods-to-find-targets-for-lightning-strikes.patch @@ -39,8 +39,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + @Override + public Location findLightningRod(Location location) { -+ return this.world.findLightningRod(net.minecraft.server.MCUtil.toBlockPosition(location)) -+ .map(blockPos -> net.minecraft.server.MCUtil.toLocation(this.world, blockPos) ++ return this.world.findLightningRod(io.papermc.paper.util.MCUtil.toBlockPosition(location)) ++ .map(blockPos -> io.papermc.paper.util.MCUtil.toLocation(this.world, blockPos) + // get the actual rod pos + .subtract(0, 1, 0)) + .orElse(null); @@ -48,8 +48,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + public Location findLightningTarget(Location location) { -+ final BlockPos pos = this.world.findLightningTargetAround(net.minecraft.server.MCUtil.toBlockPosition(location), true); -+ return pos == null ? null : net.minecraft.server.MCUtil.toLocation(this.world, pos); ++ final BlockPos pos = this.world.findLightningTargetAround(io.papermc.paper.util.MCUtil.toBlockPosition(location), true); ++ return pos == null ? null : io.papermc.paper.util.MCUtil.toLocation(this.world, pos); + } + // Paper end + diff --git a/patches/server/Add-ray-tracing-methods-to-LivingEntity.patch b/patches/server/Add-ray-tracing-methods-to-LivingEntity.patch index 5f590ed01a..d6df104431 100644 --- a/patches/server/Add-ray-tracing-methods-to-LivingEntity.patch +++ b/patches/server/Add-ray-tracing-methods-to-LivingEntity.patch @@ -4,10 +4,10 @@ Date: Mon, 3 Sep 2018 18:20:03 -0500 Subject: [PATCH] Add ray tracing methods to LivingEntity -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java @@ -0,0 +0,0 @@ public final class MCUtil { return getNMSWorld(entity.getWorld()); } @@ -66,22 +66,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + @Override + public Block getTargetBlock(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) { -+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode)); ++ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, io.papermc.paper.util.MCUtil.getNMSFluidCollisionOption(fluidMode)); + return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : org.bukkit.craftbukkit.block.CraftBlock.at(getHandle().level, ((net.minecraft.world.phys.BlockHitResult)rayTrace).getBlockPos()); + } + + @Override + public org.bukkit.block.BlockFace getTargetBlockFace(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) { -+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode)); -+ return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : net.minecraft.server.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection()); ++ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, io.papermc.paper.util.MCUtil.getNMSFluidCollisionOption(fluidMode)); ++ return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : io.papermc.paper.util.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection()); + } + + @Override + public com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) { -+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode)); ++ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, io.papermc.paper.util.MCUtil.getNMSFluidCollisionOption(fluidMode)); + return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : + new com.destroystokyo.paper.block.TargetBlockInfo(org.bukkit.craftbukkit.block.CraftBlock.at(getHandle().level, ((net.minecraft.world.phys.BlockHitResult)rayTrace).getBlockPos()), -+ net.minecraft.server.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection())); ++ io.papermc.paper.util.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection())); + } + // Paper end + diff --git a/patches/server/Allow-controlled-flushing-for-network-manager.patch b/patches/server/Allow-controlled-flushing-for-network-manager.patch index 07cd0d19ef..c2c2a0c7bc 100644 --- a/patches/server/Allow-controlled-flushing-for-network-manager.patch +++ b/patches/server/Allow-controlled-flushing-for-network-manager.patch @@ -53,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.receiving = side; } @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { - net.minecraft.server.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && + io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) ))) { - this.sendPacket(packet, callbacks); diff --git a/patches/server/Async-GameProfileCache-saving.patch b/patches/server/Async-GameProfileCache-saving.patch index 2d278a5625..6c9a19c7ca 100644 --- a/patches/server/Async-GameProfileCache-saving.patch +++ b/patches/server/Async-GameProfileCache-saving.patch @@ -76,7 +76,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + }; + if (asyncSave) { -+ net.minecraft.server.MCUtil.scheduleAsyncTask(save); ++ io.papermc.paper.util.MCUtil.scheduleAsyncTask(save); + } else { + save.run(); + } diff --git a/patches/server/AsyncTabCompleteEvent.patch b/patches/server/AsyncTabCompleteEvent.patch index b1c26b4ea2..e5196c460a 100644 --- a/patches/server/AsyncTabCompleteEvent.patch +++ b/patches/server/AsyncTabCompleteEvent.patch @@ -97,7 +97,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers); -+ TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers, message.startsWith("/") || forceCommand, pos != null ? net.minecraft.server.MCUtil.toLocation(((CraftWorld) player.getWorld()).getHandle(), new BlockPos(pos)) : null); // Paper ++ TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers, message.startsWith("/") || forceCommand, pos != null ? io.papermc.paper.util.MCUtil.toLocation(((CraftWorld) player.getWorld()).getHandle(), new BlockPos(pos)) : null); // Paper this.getPluginManager().callEvent(tabEvent); return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions(); diff --git a/patches/server/Basic-PlayerProfile-API.patch b/patches/server/Basic-PlayerProfile-API.patch index a2a0f22dbb..de2172a165 100644 --- a/patches/server/Basic-PlayerProfile-API.patch +++ b/patches/server/Basic-PlayerProfile-API.patch @@ -554,12 +554,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @NotNull GameProfile buildGameProfile(); +} -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java @@ -0,0 +0,0 @@ - package net.minecraft.server; + package io.papermc.paper.util; +import com.destroystokyo.paper.profile.CraftPlayerProfile; +import com.destroystokyo.paper.profile.PlayerProfile; diff --git a/patches/server/BlockDestroyEvent.patch b/patches/server/BlockDestroyEvent.patch index 49d3d20865..c686087486 100644 --- a/patches/server/BlockDestroyEvent.patch +++ b/patches/server/BlockDestroyEvent.patch @@ -18,7 +18,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.network.protocol.Packet; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerLevel; diff --git a/patches/server/Catch-JsonParseException-in-Entity-and-TE-names.patch b/patches/server/Catch-JsonParseException-in-Entity-and-TE-names.patch index a623c58ad2..aa7f94642b 100644 --- a/patches/server/Catch-JsonParseException-in-Entity-and-TE-names.patch +++ b/patches/server/Catch-JsonParseException-in-Entity-and-TE-names.patch @@ -12,14 +12,14 @@ Shulkers) may need to be changed in order for it to re-save properly No more crashing though. -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -0,0 +0,0 @@ import java.lang.ref.Cleaner; - import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -0,0 +0,0 @@ import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; + import net.minecraft.server.MinecraftServer; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ChunkHolder; @@ -56,7 +56,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.successCount = nbt.getInt("SuccessCount"); if (nbt.contains("CustomName", 8)) { - this.setName(Component.Serializer.fromJson(nbt.getString("CustomName"))); -+ this.setName(net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt)); // Paper - Catch ParseException ++ this.setName(io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt)); // Paper - Catch ParseException } if (nbt.contains("TrackOutput", 1)) { @@ -69,7 +69,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super.load(nbt); if (nbt.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(nbt.getString("CustomName")); -+ this.name = net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException ++ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException } this.itemPatterns = nbt.getList("Patterns", 10); @@ -82,7 +82,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.lockKey = LockCode.fromTag(nbt); if (nbt.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(nbt.getString("CustomName")); -+ this.name = net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException ++ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException } } @@ -95,7 +95,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit end if (nbt.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(nbt.getString("CustomName")); -+ this.name = net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException ++ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException } this.lockKey = LockCode.fromTag(nbt); @@ -108,7 +108,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super.load(nbt); if (nbt.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(nbt.getString("CustomName")); -+ this.name = net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException ++ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException } } diff --git a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch index c326b54c7f..4482a894c8 100644 --- a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -71,7 +71,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.network.protocol.game.DebugPackets; import net.minecraft.resources.ResourceKey; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.MinecraftServer; import net.minecraft.server.ServerScoreboard; import net.minecraft.server.level.progress.ChunkProgressListener; diff --git a/patches/server/Dolphin-API.patch b/patches/server/Dolphin-API.patch index 63a4e39d3f..4917802d36 100644 --- a/patches/server/Dolphin-API.patch +++ b/patches/server/Dolphin-API.patch @@ -35,11 +35,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + public org.bukkit.Location getTreasureLocation() { -+ return net.minecraft.server.MCUtil.toLocation(this.getHandle().level, this.getHandle().getTreasurePos()); ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level, this.getHandle().getTreasurePos()); + } + + @Override + public void setTreasureLocation(org.bukkit.Location location) { -+ this.getHandle().setTreasurePos(net.minecraft.server.MCUtil.toBlockPosition(location)); ++ this.getHandle().setTreasurePos(io.papermc.paper.util.MCUtil.toBlockPosition(location)); + } } diff --git a/patches/server/Duplicate-UUID-Resolve-Option.patch b/patches/server/Duplicate-UUID-Resolve-Option.patch index be52b8a7e0..d1243bc9fd 100644 --- a/patches/server/Duplicate-UUID-Resolve-Option.patch +++ b/patches/server/Duplicate-UUID-Resolve-Option.patch @@ -32,10 +32,10 @@ But for those who are ok with leaving this inconsistent behavior, you may use WA It is recommended you regenerate the entities, as these were legit entities, and deserve your love. -diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java +diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/ChunkSystem.java -+++ b/src/main/java/net/minecraft/server/ChunkSystem.java +--- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java ++++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java @@ -0,0 +0,0 @@ public final class ChunkSystem { } diff --git a/patches/server/Enforce-Sync-Player-Saves.patch b/patches/server/Enforce-Sync-Player-Saves.patch index ce18c830ee..348efbfe81 100644 --- a/patches/server/Enforce-Sync-Player-Saves.patch +++ b/patches/server/Enforce-Sync-Player-Saves.patch @@ -14,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void saveAll() { -+ net.minecraft.server.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main ++ io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main MinecraftTimings.savePlayers.startTiming(); // Paper for (int i = 0; i < this.players.size(); ++i) { - this.save((ServerPlayer) this.players.get(i)); diff --git a/patches/server/EntityPathfindEvent.patch b/patches/server/EntityPathfindEvent.patch index 3c24b0cb7c..38706bf0da 100644 --- a/patches/server/EntityPathfindEvent.patch +++ b/patches/server/EntityPathfindEvent.patch @@ -115,7 +115,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + boolean copiedSet = false; + for (BlockPos possibleTarget : positions) { + if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(), -+ net.minecraft.server.MCUtil.toLocation(this.mob.level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) { ++ io.papermc.paper.util.MCUtil.toLocation(this.mob.level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) { + if (!copiedSet) { + copiedSet = true; + positions = new java.util.HashSet<>(positions); diff --git a/patches/server/Fix-World-isChunkGenerated-calls.patch b/patches/server/Fix-World-isChunkGenerated-calls.patch index 8f8480138b..6acf41e362 100644 --- a/patches/server/Fix-World-isChunkGenerated-calls.patch +++ b/patches/server/Fix-World-isChunkGenerated-calls.patch @@ -84,7 +84,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public ChunkAccess getUnloadingChunk(int chunkX, int chunkZ) { -+ ChunkHolder chunkHolder = net.minecraft.server.ChunkSystem.getUnloadingChunkHolder(this.level, chunkX, chunkZ); ++ ChunkHolder chunkHolder = io.papermc.paper.chunk.system.ChunkSystem.getUnloadingChunkHolder(this.level, chunkX, chunkZ); + return chunkHolder == null ? null : chunkHolder.getAvailableChunkNow(); + } + // Paper end diff --git a/patches/server/Fix-commands-from-signs-not-firing-command-events.patch b/patches/server/Fix-commands-from-signs-not-firing-command-events.patch index cb9ab59855..8bfe96ac69 100644 --- a/patches/server/Fix-commands-from-signs-not-firing-command-events.patch +++ b/patches/server/Fix-commands-from-signs-not-firing-command-events.patch @@ -79,7 +79,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (org.spigotmc.SpigotConfig.logCommands) { + LOGGER.info("{} issued server command: {}", player.getScoreboardName(), command); + } -+ io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent(player.getBukkitEntity(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(player.getServer()), (org.bukkit.block.Sign) net.minecraft.server.MCUtil.toBukkitBlock(this.level, this.worldPosition).getState()); ++ io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent(player.getBukkitEntity(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(player.getServer()), (org.bukkit.block.Sign) io.papermc.paper.util.MCUtil.toBukkitBlock(this.level, this.worldPosition).getState()); + if (!event.callEvent()) { + return false; + } diff --git a/patches/server/Improve-Server-Thread-Pool-and-Thread-Priorities.patch b/patches/server/Improve-Server-Thread-Pool-and-Thread-Priorities.patch index 038f2151c7..5689c2f461 100644 --- a/patches/server/Improve-Server-Thread-Pool-and-Thread-Priorities.patch +++ b/patches/server/Improve-Server-Thread-Pool-and-Thread-Priorities.patch @@ -11,6 +11,26 @@ server threads Allow usage of a single thread executor by not using ForkJoin so single core CPU's. +diff --git a/src/main/java/io/papermc/paper/util/ServerWorkerThread.java b/src/main/java/io/papermc/paper/util/ServerWorkerThread.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/ServerWorkerThread.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.util; ++ ++import java.util.concurrent.atomic.AtomicInteger; ++import net.minecraft.Util; ++ ++public class ServerWorkerThread extends Thread { ++ private static final AtomicInteger threadId = new AtomicInteger(1); ++ public ServerWorkerThread(Runnable target, String poolName, int prioritityModifier) { ++ super(target, "Worker-" + poolName + "-" + threadId.getAndIncrement()); ++ setPriority(Thread.NORM_PRIORITY+prioritityModifier); // Deprioritize over main ++ this.setDaemon(true); ++ this.setUncaughtExceptionHandler(Util::onThreadException); ++ } ++} diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/Util.java @@ -43,7 +63,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { - executorService = new ForkJoinPool(i, (forkJoinPool) -> { - ForkJoinWorkerThread forkJoinWorkerThread = new ForkJoinWorkerThread(forkJoinPool) { -+ executorService = new java.util.concurrent.ThreadPoolExecutor(i, i,0L, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue(), target -> new net.minecraft.server.ServerWorkerThread(target, s, priorityModifier)); ++ executorService = new java.util.concurrent.ThreadPoolExecutor(i, i,0L, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue(), target -> new io.papermc.paper.util.ServerWorkerThread(target, s, priorityModifier)); + } + /* @Override @@ -69,23 +89,3 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 thread.start(); return s0; } -diff --git a/src/main/java/net/minecraft/server/ServerWorkerThread.java b/src/main/java/net/minecraft/server/ServerWorkerThread.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/net/minecraft/server/ServerWorkerThread.java -@@ -0,0 +0,0 @@ -+package net.minecraft.server; -+ -+import java.util.concurrent.atomic.AtomicInteger; -+import net.minecraft.Util; -+ -+public class ServerWorkerThread extends Thread { -+ private static final AtomicInteger threadId = new AtomicInteger(1); -+ public ServerWorkerThread(Runnable target, String poolName, int prioritityModifier) { -+ super(target, "Worker-" + poolName + "-" + threadId.getAndIncrement()); -+ setPriority(Thread.NORM_PRIORITY+prioritityModifier); // Deprioritize over main -+ this.setDaemon(true); -+ this.setUncaughtExceptionHandler(Util::onThreadException); -+ } -+} diff --git a/patches/server/Load-Chunks-for-Login-Asynchronously.patch b/patches/server/Load-Chunks-for-Login-Asynchronously.patch index 926fc6e3f3..0cc13adf01 100644 --- a/patches/server/Load-Chunks-for-Login-Asynchronously.patch +++ b/patches/server/Load-Chunks-for-Login-Asynchronously.patch @@ -166,7 +166,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final net.minecraft.world.level.ChunkPos pos = new net.minecraft.world.level.ChunkPos(chunkX, chunkZ); + net.minecraft.server.level.ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap; + net.minecraft.server.level.DistanceManager distanceManager = playerChunkMap.distanceManager; -+ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState( + worldserver1, chunkX, chunkZ, net.minecraft.server.level.ChunkHolder.FullChunkStatus.ENTITY_TICKING, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHEST, + (chunk) -> { diff --git a/patches/server/LootTable-API-Replenishable-Lootables-Feature.patch b/patches/server/LootTable-API-Replenishable-Lootables-Feature.patch index 7016c023c1..8acfd439e3 100644 --- a/patches/server/LootTable-API-Replenishable-Lootables-Feature.patch +++ b/patches/server/LootTable-API-Replenishable-Lootables-Feature.patch @@ -421,7 +421,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package com.destroystokyo.paper.loottable; + -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import org.bukkit.Bukkit; diff --git a/patches/server/MC-Utils.patch b/patches/server/MC-Utils.patch index c8ba55fee7..039a524eb3 100644 --- a/patches/server/MC-Utils.patch +++ b/patches/server/MC-Utils.patch @@ -1000,7 +1000,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.ChunkPos; +import javax.annotation.Nullable; @@ -1456,7 +1456,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + +import io.papermc.paper.util.IntegerUtil; +import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.world.level.ChunkPos; + +/** @author Spottedleaf */ @@ -1996,7 +1996,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package com.destroystokyo.paper.util.pooled; + -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import org.apache.commons.lang3.mutable.MutableInt; + +import java.util.ArrayDeque; @@ -2182,7 +2182,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import java.util.ArrayList; @@ -2653,6 +2653,306 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + } +} +diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.chunk.system; ++ ++import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; ++import com.destroystokyo.paper.util.SneakyThrow; ++import com.mojang.datafixers.util.Either; ++import com.mojang.logging.LogUtils; ++import io.papermc.paper.util.CoordinateUtils; ++import net.minecraft.server.level.ChunkHolder; ++import net.minecraft.server.level.ChunkMap; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.server.level.TicketType; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.LevelChunk; ++import org.bukkit.Bukkit; ++import org.slf4j.Logger; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.concurrent.CompletableFuture; ++import java.util.function.Consumer; ++ ++public final class ChunkSystem { ++ ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ ++ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { ++ scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); ++ } ++ ++ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { ++ level.chunkSource.mainThreadProcessor.execute(run); ++ } ++ ++ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, ++ final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, ++ final Consumer onComplete) { ++ if (gen) { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ return; ++ } ++ scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { ++ if (chunk == null) { ++ onComplete.accept(null); ++ } else { ++ if (chunk.getStatus().isOrAfter(toStatus)) { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ } else { ++ onComplete.accept(null); ++ } ++ } ++ }); ++ } ++ ++ static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); ++ ++ private static long chunkLoadCounter = 0L; ++ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, ++ final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { ++ if (!Bukkit.isPrimaryThread()) { ++ scheduleChunkTask(level, chunkX, chunkZ, () -> { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ }, priority); ++ return; ++ } ++ ++ final int minLevel = 33 + ChunkStatus.getDistance(toStatus); ++ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; ++ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ++ ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ level.chunkSource.runDistanceManagerUpdates(); ++ ++ final Consumer loadCallback = (final ChunkAccess chunk) -> { ++ try { ++ if (onComplete != null) { ++ onComplete.accept(chunk); ++ } ++ } catch (final ThreadDeath death) { ++ throw death; ++ } catch (final Throwable thr) { ++ LOGGER.error("Exception handling chunk load callback", thr); ++ SneakyThrow.sneaky(thr); ++ } finally { ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); ++ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ } ++ }; ++ ++ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); ++ ++ if (holder == null || holder.getTicketLevel() > minLevel) { ++ loadCallback.accept(null); ++ return; ++ } ++ ++ final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); ++ ++ if (loadFuture.isDone()) { ++ loadCallback.accept(loadFuture.join().left().orElse(null)); ++ return; ++ } ++ ++ loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { ++ if (thr != null) { ++ loadCallback.accept(null); ++ return; ++ } ++ loadCallback.accept(either.left().orElse(null)); ++ }, (final Runnable r) -> { ++ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); ++ }); ++ } ++ ++ public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, ++ final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, ++ final PrioritisedExecutor.Priority priority, final Consumer onComplete) { ++ if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { ++ throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); ++ } ++ ++ if (!Bukkit.isPrimaryThread()) { ++ scheduleChunkTask(level, chunkX, chunkZ, () -> { ++ scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ }, priority); ++ return; ++ } ++ ++ final int minLevel = 33 - (toStatus.ordinal() - 1); ++ final int radius = toStatus.ordinal() - 1; ++ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; ++ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ++ ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ level.chunkSource.runDistanceManagerUpdates(); ++ ++ final Consumer loadCallback = (final LevelChunk chunk) -> { ++ try { ++ if (onComplete != null) { ++ onComplete.accept(chunk); ++ } ++ } catch (final ThreadDeath death) { ++ throw death; ++ } catch (final Throwable thr) { ++ LOGGER.error("Exception handling chunk load callback", thr); ++ SneakyThrow.sneaky(thr); ++ } finally { ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); ++ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ } ++ }; ++ ++ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); ++ ++ if (holder == null || holder.getTicketLevel() > minLevel) { ++ loadCallback.accept(null); ++ return; ++ } ++ ++ final CompletableFuture> tickingState; ++ switch (toStatus) { ++ case BORDER: { ++ tickingState = holder.getFullChunkFuture(); ++ break; ++ } ++ case TICKING: { ++ tickingState = holder.getTickingChunkFuture(); ++ break; ++ } ++ case ENTITY_TICKING: { ++ tickingState = holder.getEntityTickingChunkFuture(); ++ break; ++ } ++ default: { ++ throw new IllegalStateException("Cannot reach here"); ++ } ++ } ++ ++ if (tickingState.isDone()) { ++ loadCallback.accept(tickingState.join().left().orElse(null)); ++ return; ++ } ++ ++ tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { ++ if (thr != null) { ++ loadCallback.accept(null); ++ return; ++ } ++ loadCallback.accept(either.left().orElse(null)); ++ }, (final Runnable r) -> { ++ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); ++ }); ++ } ++ ++ public static List getVisibleChunkHolders(final ServerLevel level) { ++ return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); ++ } ++ ++ public static List getUpdatingChunkHolders(final ServerLevel level) { ++ return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); ++ } ++ ++ public static int getVisibleChunkHolderCount(final ServerLevel level) { ++ return level.chunkSource.chunkMap.visibleChunkMap.size(); ++ } ++ ++ public static int getUpdatingChunkHolderCount(final ServerLevel level) { ++ return level.chunkSource.chunkMap.updatingChunkMap.size(); ++ } ++ ++ public static boolean hasAnyChunkHolders(final ServerLevel level) { ++ return getUpdatingChunkHolderCount(level) != 0; ++ } ++ ++ public static void onEntityPreAdd(final ServerLevel level, final Entity entity) { ++ ++ } ++ ++ public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { ++ final ChunkMap chunkMap = level.chunkSource.chunkMap; ++ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { ++ chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); ++ } ++ } ++ ++ public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { ++ final ChunkMap chunkMap = level.chunkSource.chunkMap; ++ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { ++ chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); ++ } ++ } ++ ++ public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.playerChunk = holder; ++ } ++ ++ public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { ++ ++ } ++ ++ public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.level.getChunkSource().tickingChunks.add(chunk); ++ } ++ ++ public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.level.getChunkSource().tickingChunks.remove(chunk); ++ } ++ ++ public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.level.getChunkSource().entityTickingChunks.add(chunk); ++ } ++ ++ public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.level.getChunkSource().entityTickingChunks.remove(chunk); ++ } ++ ++ public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { ++ return level.chunkSource.chunkMap.getUnloadingChunkHolder(chunkX, chunkZ); ++ } ++ ++ public static int getSendViewDistance(final ServerPlayer player) { ++ return getLoadViewDistance(player); ++ } ++ ++ public static int getLoadViewDistance(final ServerPlayer player) { ++ final ServerLevel level = player.getLevel(); ++ if (level == null) { ++ return Bukkit.getViewDistance() + 1; ++ } ++ return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; ++ } ++ ++ public static int getTickViewDistance(final ServerPlayer player) { ++ final ServerLevel level = player.getLevel(); ++ if (level == null) { ++ return Bukkit.getSimulationDistance(); ++ } ++ return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); ++ } ++ ++ private ChunkSystem() { ++ throw new RuntimeException(); ++ } ++} diff --git a/src/main/java/io/papermc/paper/util/CachedLists.java b/src/main/java/io/papermc/paper/util/CachedLists.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -3154,6 +3454,524 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.sum; + } +} +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.util; ++ ++import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; ++import java.lang.ref.Cleaner; ++import net.minecraft.core.BlockPos; ++import net.minecraft.core.Direction; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.ClipContext; ++import net.minecraft.world.level.Level; ++import org.apache.commons.lang.exception.ExceptionUtils; ++import org.bukkit.Location; ++import org.bukkit.block.BlockFace; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.util.Waitable; ++import org.spigotmc.AsyncCatcher; ++ ++import javax.annotation.Nonnull; ++import javax.annotation.Nullable; ++import java.util.List; ++import java.util.Queue; ++import java.util.concurrent.CompletableFuture; ++import java.util.concurrent.ExecutionException; ++import java.util.concurrent.LinkedBlockingQueue; ++import java.util.concurrent.ThreadPoolExecutor; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.TimeoutException; ++import java.util.concurrent.atomic.AtomicBoolean; ++import java.util.function.BiConsumer; ++import java.util.function.Consumer; ++import java.util.function.Supplier; ++ ++public final class MCUtil { ++ public static final ThreadPoolExecutor asyncExecutor = new ThreadPoolExecutor( ++ 0, 2, 60L, TimeUnit.SECONDS, ++ new LinkedBlockingQueue<>(), ++ new ThreadFactoryBuilder() ++ .setNameFormat("Paper Async Task Handler Thread - %1$d") ++ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) ++ .build() ++ ); ++ public static final ThreadPoolExecutor cleanerExecutor = new ThreadPoolExecutor( ++ 1, 1, 0L, TimeUnit.SECONDS, ++ new LinkedBlockingQueue<>(), ++ new ThreadFactoryBuilder() ++ .setNameFormat("Paper Object Cleaner") ++ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) ++ .build() ++ ); ++ ++ public static final long INVALID_CHUNK_KEY = getCoordinateKey(Integer.MAX_VALUE, Integer.MAX_VALUE); ++ ++ ++ public static Runnable once(Runnable run) { ++ AtomicBoolean ran = new AtomicBoolean(false); ++ return () -> { ++ if (ran.compareAndSet(false, true)) { ++ run.run(); ++ } ++ }; ++ } ++ ++ public static Runnable once(List list, Consumer cb) { ++ return once(() -> { ++ list.forEach(cb); ++ }); ++ } ++ ++ private static Runnable makeCleanerCallback(Runnable run) { ++ return once(() -> cleanerExecutor.execute(run)); ++ } ++ ++ /** ++ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! ++ * @param obj ++ * @param run ++ * @return ++ */ ++ public static Runnable registerCleaner(Object obj, Runnable run) { ++ // Wrap callback in its own method above or the lambda will leak object ++ Runnable cleaner = makeCleanerCallback(run); ++ CleanerHolder.CLEANER.register(obj, cleaner); ++ return cleaner; ++ } ++ ++ private static final class CleanerHolder { ++ private static final Cleaner CLEANER = Cleaner.create(); ++ } ++ ++ /** ++ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! ++ * @param obj ++ * @param list ++ * @param cleaner ++ * @param ++ * @return ++ */ ++ public static Runnable registerListCleaner(Object obj, List list, Consumer cleaner) { ++ return registerCleaner(obj, () -> { ++ list.forEach(cleaner); ++ list.clear(); ++ }); ++ } ++ ++ /** ++ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! ++ * @param obj ++ * @param resource ++ * @param cleaner ++ * @param ++ * @return ++ */ ++ public static Runnable registerCleaner(Object obj, T resource, java.util.function.Consumer cleaner) { ++ return registerCleaner(obj, () -> cleaner.accept(resource)); ++ } ++ ++ public static List getSpiralOutChunks(BlockPos blockposition, int radius) { ++ List list = com.google.common.collect.Lists.newArrayList(); ++ ++ list.add(new ChunkPos(blockposition.getX() >> 4, blockposition.getZ() >> 4)); ++ for (int r = 1; r <= radius; r++) { ++ int x = -r; ++ int z = r; ++ ++ // Iterates the edge of half of the box; then negates for other half. ++ while (x <= r && z > -r) { ++ list.add(new ChunkPos((blockposition.getX() + (x << 4)) >> 4, (blockposition.getZ() + (z << 4)) >> 4)); ++ list.add(new ChunkPos((blockposition.getX() - (x << 4)) >> 4, (blockposition.getZ() - (z << 4)) >> 4)); ++ ++ if (x < r) { ++ x++; ++ } else { ++ z--; ++ } ++ } ++ } ++ return list; ++ } ++ ++ public static int fastFloor(double x) { ++ int truncated = (int)x; ++ return x < (double)truncated ? truncated - 1 : truncated; ++ } ++ ++ public static int fastFloor(float x) { ++ int truncated = (int)x; ++ return x < (double)truncated ? truncated - 1 : truncated; ++ } ++ ++ public static float normalizeYaw(float f) { ++ float f1 = f % 360.0F; ++ ++ if (f1 >= 180.0F) { ++ f1 -= 360.0F; ++ } ++ ++ if (f1 < -180.0F) { ++ f1 += 360.0F; ++ } ++ ++ return f1; ++ } ++ ++ /** ++ * Quickly generate a stack trace for current location ++ * ++ * @return Stacktrace ++ */ ++ public static String stack() { ++ return ExceptionUtils.getFullStackTrace(new Throwable()); ++ } ++ ++ /** ++ * Quickly generate a stack trace for current location with message ++ * ++ * @param str ++ * @return Stacktrace ++ */ ++ public static String stack(String str) { ++ return ExceptionUtils.getFullStackTrace(new Throwable(str)); ++ } ++ ++ public static long getCoordinateKey(final BlockPos blockPos) { ++ return ((long)(blockPos.getZ() >> 4) << 32) | ((blockPos.getX() >> 4) & 0xFFFFFFFFL); ++ } ++ ++ public static long getCoordinateKey(final Entity entity) { ++ return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); ++ } ++ ++ public static long getCoordinateKey(final ChunkPos pair) { ++ return ((long)pair.z << 32) | (pair.x & 0xFFFFFFFFL); ++ } ++ ++ public static long getCoordinateKey(final int x, final int z) { ++ return ((long)z << 32) | (x & 0xFFFFFFFFL); ++ } ++ ++ public static int getCoordinateX(final long key) { ++ return (int)key; ++ } ++ ++ public static int getCoordinateZ(final long key) { ++ return (int)(key >>> 32); ++ } ++ ++ public static int getChunkCoordinate(final double coordinate) { ++ return MCUtil.fastFloor(coordinate) >> 4; ++ } ++ ++ public static int getBlockCoordinate(final double coordinate) { ++ return MCUtil.fastFloor(coordinate); ++ } ++ ++ public static long getBlockKey(final int x, final int y, final int z) { ++ return ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54); ++ } ++ ++ public static long getBlockKey(final BlockPos pos) { ++ return ((long)pos.getX() & 0x7FFFFFF) | (((long)pos.getZ() & 0x7FFFFFF) << 27) | ((long)pos.getY() << 54); ++ } ++ ++ public static long getBlockKey(final Entity entity) { ++ return getBlockKey(getBlockCoordinate(entity.getX()), getBlockCoordinate(entity.getY()), getBlockCoordinate(entity.getZ())); ++ } ++ ++ // assumes the sets have the same comparator, and if this comparator is null then assume T is Comparable ++ public static void mergeSortedSets(final java.util.function.Consumer consumer, final java.util.Comparator comparator, final java.util.SortedSet...sets) { ++ final ObjectRBTreeSet all = new ObjectRBTreeSet<>(comparator); ++ // note: this is done in log(n!) ~ nlogn time. It could be improved if it were to mimic what mergesort does. ++ for (java.util.SortedSet set : sets) { ++ if (set != null) { ++ all.addAll(set); ++ } ++ } ++ all.forEach(consumer); ++ } ++ ++ private MCUtil() {} ++ ++ public static final java.util.concurrent.Executor MAIN_EXECUTOR = (run) -> { ++ if (!isMainThread()) { ++ MinecraftServer.getServer().execute(run); ++ } else { ++ run.run(); ++ } ++ }; ++ ++ public static CompletableFuture ensureMain(CompletableFuture future) { ++ return future.thenApplyAsync(r -> r, MAIN_EXECUTOR); ++ } ++ ++ public static void thenOnMain(CompletableFuture future, Consumer consumer) { ++ future.thenAcceptAsync(consumer, MAIN_EXECUTOR); ++ } ++ public static void thenOnMain(CompletableFuture future, BiConsumer consumer) { ++ future.whenCompleteAsync(consumer, MAIN_EXECUTOR); ++ } ++ ++ public static boolean isMainThread() { ++ return MinecraftServer.getServer().isSameThread(); ++ } ++ ++ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable) { ++ return scheduleTask(ticks, runnable, null); ++ } ++ ++ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable, String taskName) { ++ return MinecraftServer.getServer().server.getScheduler().scheduleInternalTask(runnable, ticks, taskName); ++ } ++ ++ public static void processQueue() { ++ Runnable runnable; ++ Queue processQueue = getProcessQueue(); ++ while ((runnable = processQueue.poll()) != null) { ++ try { ++ runnable.run(); ++ } catch (Exception e) { ++ MinecraftServer.LOGGER.error("Error executing task", e); ++ } ++ } ++ } ++ public static T processQueueWhileWaiting(CompletableFuture future) { ++ try { ++ if (isMainThread()) { ++ while (!future.isDone()) { ++ try { ++ return future.get(1, TimeUnit.MILLISECONDS); ++ } catch (TimeoutException ignored) { ++ processQueue(); ++ } ++ } ++ } ++ return future.get(); ++ } catch (Exception e) { ++ throw new RuntimeException(e); ++ } ++ } ++ ++ public static void ensureMain(Runnable run) { ++ ensureMain(null, run); ++ } ++ /** ++ * Ensures the target code is running on the main thread ++ * @param reason ++ * @param run ++ * @return ++ */ ++ public static void ensureMain(String reason, Runnable run) { ++ if (!isMainThread()) { ++ if (reason != null) { ++ MinecraftServer.LOGGER.warn("Asynchronous " + reason + "!", new IllegalStateException()); ++ } ++ getProcessQueue().add(run); ++ return; ++ } ++ run.run(); ++ } ++ ++ private static Queue getProcessQueue() { ++ return MinecraftServer.getServer().processQueue; ++ } ++ ++ public static T ensureMain(Supplier run) { ++ return ensureMain(null, run); ++ } ++ /** ++ * Ensures the target code is running on the main thread ++ * @param reason ++ * @param run ++ * @param ++ * @return ++ */ ++ public static T ensureMain(String reason, Supplier run) { ++ if (!isMainThread()) { ++ if (reason != null) { ++ MinecraftServer.LOGGER.warn("Asynchronous " + reason + "! Blocking thread until it returns ", new IllegalStateException()); ++ } ++ Waitable wait = new Waitable() { ++ @Override ++ protected T evaluate() { ++ return run.get(); ++ } ++ }; ++ getProcessQueue().add(wait); ++ try { ++ return wait.get(); ++ } catch (InterruptedException | ExecutionException e) { ++ MinecraftServer.LOGGER.warn("Encountered exception", e); ++ } ++ return null; ++ } ++ return run.get(); ++ } ++ ++ /** ++ * Calculates distance between 2 entities ++ * @param e1 ++ * @param e2 ++ * @return ++ */ ++ public static double distance(Entity e1, Entity e2) { ++ return Math.sqrt(distanceSq(e1, e2)); ++ } ++ ++ ++ /** ++ * Calculates distance between 2 block positions ++ * @param e1 ++ * @param e2 ++ * @return ++ */ ++ public static double distance(BlockPos e1, BlockPos e2) { ++ return Math.sqrt(distanceSq(e1, e2)); ++ } ++ ++ /** ++ * Gets the distance between 2 positions ++ * @param x1 ++ * @param y1 ++ * @param z1 ++ * @param x2 ++ * @param y2 ++ * @param z2 ++ * @return ++ */ ++ public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) { ++ return Math.sqrt(distanceSq(x1, y1, z1, x2, y2, z2)); ++ } ++ ++ /** ++ * Get's the distance squared between 2 entities ++ * @param e1 ++ * @param e2 ++ * @return ++ */ ++ public static double distanceSq(Entity e1, Entity e2) { ++ return distanceSq(e1.getX(),e1.getY(),e1.getZ(), e2.getX(),e2.getY(),e2.getZ()); ++ } ++ ++ /** ++ * Gets the distance sqaured between 2 block positions ++ * @param pos1 ++ * @param pos2 ++ * @return ++ */ ++ public static double distanceSq(BlockPos pos1, BlockPos pos2) { ++ return distanceSq(pos1.getX(), pos1.getY(), pos1.getZ(), pos2.getX(), pos2.getY(), pos2.getZ()); ++ } ++ ++ /** ++ * Gets the distance squared between 2 positions ++ * @param x1 ++ * @param y1 ++ * @param z1 ++ * @param x2 ++ * @param y2 ++ * @param z2 ++ * @return ++ */ ++ public static double distanceSq(double x1, double y1, double z1, double x2, double y2, double z2) { ++ return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2); ++ } ++ ++ /** ++ * Converts a NMS World/BlockPosition to Bukkit Location ++ * @param world ++ * @param x ++ * @param y ++ * @param z ++ * @return ++ */ ++ public static Location toLocation(Level world, double x, double y, double z) { ++ return new Location(world.getWorld(), x, y, z); ++ } ++ ++ /** ++ * Converts a NMS World/BlockPosition to Bukkit Location ++ * @param world ++ * @param pos ++ * @return ++ */ ++ public static Location toLocation(Level world, BlockPos pos) { ++ return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()); ++ } ++ ++ /** ++ * Converts an NMS entity's current location to a Bukkit Location ++ * @param entity ++ * @return ++ */ ++ public static Location toLocation(Entity entity) { ++ return new Location(entity.getCommandSenderWorld().getWorld(), entity.getX(), entity.getY(), entity.getZ()); ++ } ++ ++ public static org.bukkit.block.Block toBukkitBlock(Level world, BlockPos pos) { ++ return world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); ++ } ++ ++ public static BlockPos toBlockPosition(Location loc) { ++ return new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); ++ } ++ ++ public static boolean isEdgeOfChunk(BlockPos pos) { ++ final int modX = pos.getX() & 15; ++ final int modZ = pos.getZ() & 15; ++ return (modX == 0 || modX == 15 || modZ == 0 || modZ == 15); ++ } ++ ++ /** ++ * Posts a task to be executed asynchronously ++ * @param run ++ */ ++ public static void scheduleAsyncTask(Runnable run) { ++ asyncExecutor.execute(run); ++ } ++ ++ @Nonnull ++ public static ServerLevel getNMSWorld(@Nonnull org.bukkit.World world) { ++ return ((CraftWorld) world).getHandle(); ++ } ++ ++ public static ServerLevel getNMSWorld(@Nonnull org.bukkit.entity.Entity entity) { ++ return getNMSWorld(entity.getWorld()); ++ } ++ ++ public static BlockFace toBukkitBlockFace(Direction enumDirection) { ++ switch (enumDirection) { ++ case DOWN: ++ return BlockFace.DOWN; ++ case UP: ++ return BlockFace.UP; ++ case NORTH: ++ return BlockFace.NORTH; ++ case SOUTH: ++ return BlockFace.SOUTH; ++ case WEST: ++ return BlockFace.WEST; ++ case EAST: ++ return BlockFace.EAST; ++ default: ++ return null; ++ } ++ } ++ ++ public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { ++ return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); ++ } ++} diff --git a/src/main/java/io/papermc/paper/util/StackWalkerUtil.java b/src/main/java/io/papermc/paper/util/StackWalkerUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -3893,7 +4711,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; + +public final class Delayed8WayDistancePropagator2D { + @@ -4673,823 +5491,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (packet.isSkippable()) { throw new SkipPacketException(var10); } else { -diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/net/minecraft/server/ChunkSystem.java -@@ -0,0 +0,0 @@ -+package net.minecraft.server; -+ -+import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; -+import com.destroystokyo.paper.util.SneakyThrow; -+import com.mojang.datafixers.util.Either; -+import com.mojang.logging.LogUtils; -+import io.papermc.paper.util.CoordinateUtils; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.ChunkMap; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.level.TicketType; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; -+import net.minecraft.world.level.chunk.LevelChunk; -+import org.bukkit.Bukkit; -+import org.slf4j.Logger; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.concurrent.CompletableFuture; -+import java.util.function.Consumer; -+ -+public final class ChunkSystem { -+ -+ private static final Logger LOGGER = LogUtils.getLogger(); -+ -+ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { -+ scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); -+ } -+ -+ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { -+ level.chunkSource.mainThreadProcessor.execute(run); -+ } -+ -+ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, -+ final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, -+ final Consumer onComplete) { -+ if (gen) { -+ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ return; -+ } -+ scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { -+ if (chunk == null) { -+ onComplete.accept(null); -+ } else { -+ if (chunk.getStatus().isOrAfter(toStatus)) { -+ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ } else { -+ onComplete.accept(null); -+ } -+ } -+ }); -+ } -+ -+ static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); -+ -+ private static long chunkLoadCounter = 0L; -+ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, -+ final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { -+ if (!Bukkit.isPrimaryThread()) { -+ scheduleChunkTask(level, chunkX, chunkZ, () -> { -+ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ }, priority); -+ return; -+ } -+ -+ final int minLevel = 33 + ChunkStatus.getDistance(toStatus); -+ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -+ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -+ -+ if (addTicket) { -+ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -+ } -+ level.chunkSource.runDistanceManagerUpdates(); -+ -+ final Consumer loadCallback = (final ChunkAccess chunk) -> { -+ try { -+ if (onComplete != null) { -+ onComplete.accept(chunk); -+ } -+ } catch (final ThreadDeath death) { -+ throw death; -+ } catch (final Throwable thr) { -+ LOGGER.error("Exception handling chunk load callback", thr); -+ SneakyThrow.sneaky(thr); -+ } finally { -+ if (addTicket) { -+ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); -+ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -+ } -+ } -+ }; -+ -+ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ -+ if (holder == null || holder.getTicketLevel() > minLevel) { -+ loadCallback.accept(null); -+ return; -+ } -+ -+ final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); -+ -+ if (loadFuture.isDone()) { -+ loadCallback.accept(loadFuture.join().left().orElse(null)); -+ return; -+ } -+ -+ loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { -+ if (thr != null) { -+ loadCallback.accept(null); -+ return; -+ } -+ loadCallback.accept(either.left().orElse(null)); -+ }, (final Runnable r) -> { -+ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); -+ }); -+ } -+ -+ public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, -+ final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, -+ final PrioritisedExecutor.Priority priority, final Consumer onComplete) { -+ if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { -+ throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); -+ } -+ -+ if (!Bukkit.isPrimaryThread()) { -+ scheduleChunkTask(level, chunkX, chunkZ, () -> { -+ scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ }, priority); -+ return; -+ } -+ -+ final int minLevel = 33 - (toStatus.ordinal() - 1); -+ final int radius = toStatus.ordinal() - 1; -+ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -+ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -+ -+ if (addTicket) { -+ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -+ } -+ level.chunkSource.runDistanceManagerUpdates(); -+ -+ final Consumer loadCallback = (final LevelChunk chunk) -> { -+ try { -+ if (onComplete != null) { -+ onComplete.accept(chunk); -+ } -+ } catch (final ThreadDeath death) { -+ throw death; -+ } catch (final Throwable thr) { -+ LOGGER.error("Exception handling chunk load callback", thr); -+ SneakyThrow.sneaky(thr); -+ } finally { -+ if (addTicket) { -+ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); -+ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -+ } -+ } -+ }; -+ -+ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ -+ if (holder == null || holder.getTicketLevel() > minLevel) { -+ loadCallback.accept(null); -+ return; -+ } -+ -+ final CompletableFuture> tickingState; -+ switch (toStatus) { -+ case BORDER: { -+ tickingState = holder.getFullChunkFuture(); -+ break; -+ } -+ case TICKING: { -+ tickingState = holder.getTickingChunkFuture(); -+ break; -+ } -+ case ENTITY_TICKING: { -+ tickingState = holder.getEntityTickingChunkFuture(); -+ break; -+ } -+ default: { -+ throw new IllegalStateException("Cannot reach here"); -+ } -+ } -+ -+ if (tickingState.isDone()) { -+ loadCallback.accept(tickingState.join().left().orElse(null)); -+ return; -+ } -+ -+ tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { -+ if (thr != null) { -+ loadCallback.accept(null); -+ return; -+ } -+ loadCallback.accept(either.left().orElse(null)); -+ }, (final Runnable r) -> { -+ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); -+ }); -+ } -+ -+ public static List getVisibleChunkHolders(final ServerLevel level) { -+ return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); -+ } -+ -+ public static List getUpdatingChunkHolders(final ServerLevel level) { -+ return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); -+ } -+ -+ public static int getVisibleChunkHolderCount(final ServerLevel level) { -+ return level.chunkSource.chunkMap.visibleChunkMap.size(); -+ } -+ -+ public static int getUpdatingChunkHolderCount(final ServerLevel level) { -+ return level.chunkSource.chunkMap.updatingChunkMap.size(); -+ } -+ -+ public static boolean hasAnyChunkHolders(final ServerLevel level) { -+ return getUpdatingChunkHolderCount(level) != 0; -+ } -+ -+ public static void onEntityPreAdd(final ServerLevel level, final Entity entity) { -+ -+ } -+ -+ public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { -+ final ChunkMap chunkMap = level.chunkSource.chunkMap; -+ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { -+ chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); -+ } -+ } -+ -+ public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { -+ final ChunkMap chunkMap = level.chunkSource.chunkMap; -+ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { -+ chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); -+ } -+ } -+ -+ public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.playerChunk = holder; -+ } -+ -+ public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ -+ } -+ -+ public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.level.getChunkSource().tickingChunks.add(chunk); -+ } -+ -+ public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.level.getChunkSource().tickingChunks.remove(chunk); -+ } -+ -+ public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.level.getChunkSource().entityTickingChunks.add(chunk); -+ } -+ -+ public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.level.getChunkSource().entityTickingChunks.remove(chunk); -+ } -+ -+ public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { -+ return level.chunkSource.chunkMap.getUnloadingChunkHolder(chunkX, chunkZ); -+ } -+ -+ public static int getSendViewDistance(final ServerPlayer player) { -+ return getLoadViewDistance(player); -+ } -+ -+ public static int getLoadViewDistance(final ServerPlayer player) { -+ final ServerLevel level = player.getLevel(); -+ if (level == null) { -+ return Bukkit.getViewDistance() + 1; -+ } -+ return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; -+ } -+ -+ public static int getTickViewDistance(final ServerPlayer player) { -+ final ServerLevel level = player.getLevel(); -+ if (level == null) { -+ return Bukkit.getSimulationDistance(); -+ } -+ return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); -+ } -+ -+ private ChunkSystem() { -+ throw new RuntimeException(); -+ } -+} -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -0,0 +0,0 @@ -+package net.minecraft.server; -+ -+import com.google.common.util.concurrent.ThreadFactoryBuilder; -+import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; -+import java.lang.ref.Cleaner; -+import net.minecraft.core.BlockPos; -+import net.minecraft.core.Direction; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.ClipContext; -+import net.minecraft.world.level.Level; -+import org.apache.commons.lang.exception.ExceptionUtils; -+import org.bukkit.Location; -+import org.bukkit.block.BlockFace; -+import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.craftbukkit.util.Waitable; -+import org.spigotmc.AsyncCatcher; -+ -+import javax.annotation.Nonnull; -+import javax.annotation.Nullable; -+import java.util.List; -+import java.util.Queue; -+import java.util.concurrent.CompletableFuture; -+import java.util.concurrent.ExecutionException; -+import java.util.concurrent.LinkedBlockingQueue; -+import java.util.concurrent.ThreadPoolExecutor; -+import java.util.concurrent.TimeUnit; -+import java.util.concurrent.TimeoutException; -+import java.util.concurrent.atomic.AtomicBoolean; -+import java.util.function.BiConsumer; -+import java.util.function.Consumer; -+import java.util.function.Supplier; -+ -+public final class MCUtil { -+ public static final ThreadPoolExecutor asyncExecutor = new ThreadPoolExecutor( -+ 0, 2, 60L, TimeUnit.SECONDS, -+ new LinkedBlockingQueue<>(), -+ new ThreadFactoryBuilder() -+ .setNameFormat("Paper Async Task Handler Thread - %1$d") -+ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) -+ .build() -+ ); -+ public static final ThreadPoolExecutor cleanerExecutor = new ThreadPoolExecutor( -+ 1, 1, 0L, TimeUnit.SECONDS, -+ new LinkedBlockingQueue<>(), -+ new ThreadFactoryBuilder() -+ .setNameFormat("Paper Object Cleaner") -+ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) -+ .build() -+ ); -+ -+ public static final long INVALID_CHUNK_KEY = getCoordinateKey(Integer.MAX_VALUE, Integer.MAX_VALUE); -+ -+ -+ public static Runnable once(Runnable run) { -+ AtomicBoolean ran = new AtomicBoolean(false); -+ return () -> { -+ if (ran.compareAndSet(false, true)) { -+ run.run(); -+ } -+ }; -+ } -+ -+ public static Runnable once(List list, Consumer cb) { -+ return once(() -> { -+ list.forEach(cb); -+ }); -+ } -+ -+ private static Runnable makeCleanerCallback(Runnable run) { -+ return once(() -> cleanerExecutor.execute(run)); -+ } -+ -+ /** -+ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! -+ * @param obj -+ * @param run -+ * @return -+ */ -+ public static Runnable registerCleaner(Object obj, Runnable run) { -+ // Wrap callback in its own method above or the lambda will leak object -+ Runnable cleaner = makeCleanerCallback(run); -+ CleanerHolder.CLEANER.register(obj, cleaner); -+ return cleaner; -+ } -+ -+ private static final class CleanerHolder { -+ private static final Cleaner CLEANER = Cleaner.create(); -+ } -+ -+ /** -+ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! -+ * @param obj -+ * @param list -+ * @param cleaner -+ * @param -+ * @return -+ */ -+ public static Runnable registerListCleaner(Object obj, List list, Consumer cleaner) { -+ return registerCleaner(obj, () -> { -+ list.forEach(cleaner); -+ list.clear(); -+ }); -+ } -+ -+ /** -+ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! -+ * @param obj -+ * @param resource -+ * @param cleaner -+ * @param -+ * @return -+ */ -+ public static Runnable registerCleaner(Object obj, T resource, java.util.function.Consumer cleaner) { -+ return registerCleaner(obj, () -> cleaner.accept(resource)); -+ } -+ -+ public static List getSpiralOutChunks(BlockPos blockposition, int radius) { -+ List list = com.google.common.collect.Lists.newArrayList(); -+ -+ list.add(new ChunkPos(blockposition.getX() >> 4, blockposition.getZ() >> 4)); -+ for (int r = 1; r <= radius; r++) { -+ int x = -r; -+ int z = r; -+ -+ // Iterates the edge of half of the box; then negates for other half. -+ while (x <= r && z > -r) { -+ list.add(new ChunkPos((blockposition.getX() + (x << 4)) >> 4, (blockposition.getZ() + (z << 4)) >> 4)); -+ list.add(new ChunkPos((blockposition.getX() - (x << 4)) >> 4, (blockposition.getZ() - (z << 4)) >> 4)); -+ -+ if (x < r) { -+ x++; -+ } else { -+ z--; -+ } -+ } -+ } -+ return list; -+ } -+ -+ public static int fastFloor(double x) { -+ int truncated = (int)x; -+ return x < (double)truncated ? truncated - 1 : truncated; -+ } -+ -+ public static int fastFloor(float x) { -+ int truncated = (int)x; -+ return x < (double)truncated ? truncated - 1 : truncated; -+ } -+ -+ public static float normalizeYaw(float f) { -+ float f1 = f % 360.0F; -+ -+ if (f1 >= 180.0F) { -+ f1 -= 360.0F; -+ } -+ -+ if (f1 < -180.0F) { -+ f1 += 360.0F; -+ } -+ -+ return f1; -+ } -+ -+ /** -+ * Quickly generate a stack trace for current location -+ * -+ * @return Stacktrace -+ */ -+ public static String stack() { -+ return ExceptionUtils.getFullStackTrace(new Throwable()); -+ } -+ -+ /** -+ * Quickly generate a stack trace for current location with message -+ * -+ * @param str -+ * @return Stacktrace -+ */ -+ public static String stack(String str) { -+ return ExceptionUtils.getFullStackTrace(new Throwable(str)); -+ } -+ -+ public static long getCoordinateKey(final BlockPos blockPos) { -+ return ((long)(blockPos.getZ() >> 4) << 32) | ((blockPos.getX() >> 4) & 0xFFFFFFFFL); -+ } -+ -+ public static long getCoordinateKey(final Entity entity) { -+ return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); -+ } -+ -+ public static long getCoordinateKey(final ChunkPos pair) { -+ return ((long)pair.z << 32) | (pair.x & 0xFFFFFFFFL); -+ } -+ -+ public static long getCoordinateKey(final int x, final int z) { -+ return ((long)z << 32) | (x & 0xFFFFFFFFL); -+ } -+ -+ public static int getCoordinateX(final long key) { -+ return (int)key; -+ } -+ -+ public static int getCoordinateZ(final long key) { -+ return (int)(key >>> 32); -+ } -+ -+ public static int getChunkCoordinate(final double coordinate) { -+ return MCUtil.fastFloor(coordinate) >> 4; -+ } -+ -+ public static int getBlockCoordinate(final double coordinate) { -+ return MCUtil.fastFloor(coordinate); -+ } -+ -+ public static long getBlockKey(final int x, final int y, final int z) { -+ return ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54); -+ } -+ -+ public static long getBlockKey(final BlockPos pos) { -+ return ((long)pos.getX() & 0x7FFFFFF) | (((long)pos.getZ() & 0x7FFFFFF) << 27) | ((long)pos.getY() << 54); -+ } -+ -+ public static long getBlockKey(final Entity entity) { -+ return getBlockKey(getBlockCoordinate(entity.getX()), getBlockCoordinate(entity.getY()), getBlockCoordinate(entity.getZ())); -+ } -+ -+ // assumes the sets have the same comparator, and if this comparator is null then assume T is Comparable -+ public static void mergeSortedSets(final java.util.function.Consumer consumer, final java.util.Comparator comparator, final java.util.SortedSet...sets) { -+ final ObjectRBTreeSet all = new ObjectRBTreeSet<>(comparator); -+ // note: this is done in log(n!) ~ nlogn time. It could be improved if it were to mimic what mergesort does. -+ for (java.util.SortedSet set : sets) { -+ if (set != null) { -+ all.addAll(set); -+ } -+ } -+ all.forEach(consumer); -+ } -+ -+ private MCUtil() {} -+ -+ public static final java.util.concurrent.Executor MAIN_EXECUTOR = (run) -> { -+ if (!isMainThread()) { -+ MinecraftServer.getServer().execute(run); -+ } else { -+ run.run(); -+ } -+ }; -+ -+ public static CompletableFuture ensureMain(CompletableFuture future) { -+ return future.thenApplyAsync(r -> r, MAIN_EXECUTOR); -+ } -+ -+ public static void thenOnMain(CompletableFuture future, Consumer consumer) { -+ future.thenAcceptAsync(consumer, MAIN_EXECUTOR); -+ } -+ public static void thenOnMain(CompletableFuture future, BiConsumer consumer) { -+ future.whenCompleteAsync(consumer, MAIN_EXECUTOR); -+ } -+ -+ public static boolean isMainThread() { -+ return MinecraftServer.getServer().isSameThread(); -+ } -+ -+ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable) { -+ return scheduleTask(ticks, runnable, null); -+ } -+ -+ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable, String taskName) { -+ return MinecraftServer.getServer().server.getScheduler().scheduleInternalTask(runnable, ticks, taskName); -+ } -+ -+ public static void processQueue() { -+ Runnable runnable; -+ Queue processQueue = getProcessQueue(); -+ while ((runnable = processQueue.poll()) != null) { -+ try { -+ runnable.run(); -+ } catch (Exception e) { -+ MinecraftServer.LOGGER.error("Error executing task", e); -+ } -+ } -+ } -+ public static T processQueueWhileWaiting(CompletableFuture future) { -+ try { -+ if (isMainThread()) { -+ while (!future.isDone()) { -+ try { -+ return future.get(1, TimeUnit.MILLISECONDS); -+ } catch (TimeoutException ignored) { -+ processQueue(); -+ } -+ } -+ } -+ return future.get(); -+ } catch (Exception e) { -+ throw new RuntimeException(e); -+ } -+ } -+ -+ public static void ensureMain(Runnable run) { -+ ensureMain(null, run); -+ } -+ /** -+ * Ensures the target code is running on the main thread -+ * @param reason -+ * @param run -+ * @return -+ */ -+ public static void ensureMain(String reason, Runnable run) { -+ if (!isMainThread()) { -+ if (reason != null) { -+ MinecraftServer.LOGGER.warn("Asynchronous " + reason + "!", new IllegalStateException()); -+ } -+ getProcessQueue().add(run); -+ return; -+ } -+ run.run(); -+ } -+ -+ private static Queue getProcessQueue() { -+ return MinecraftServer.getServer().processQueue; -+ } -+ -+ public static T ensureMain(Supplier run) { -+ return ensureMain(null, run); -+ } -+ /** -+ * Ensures the target code is running on the main thread -+ * @param reason -+ * @param run -+ * @param -+ * @return -+ */ -+ public static T ensureMain(String reason, Supplier run) { -+ if (!isMainThread()) { -+ if (reason != null) { -+ MinecraftServer.LOGGER.warn("Asynchronous " + reason + "! Blocking thread until it returns ", new IllegalStateException()); -+ } -+ Waitable wait = new Waitable() { -+ @Override -+ protected T evaluate() { -+ return run.get(); -+ } -+ }; -+ getProcessQueue().add(wait); -+ try { -+ return wait.get(); -+ } catch (InterruptedException | ExecutionException e) { -+ MinecraftServer.LOGGER.warn("Encountered exception", e); -+ } -+ return null; -+ } -+ return run.get(); -+ } -+ -+ /** -+ * Calculates distance between 2 entities -+ * @param e1 -+ * @param e2 -+ * @return -+ */ -+ public static double distance(Entity e1, Entity e2) { -+ return Math.sqrt(distanceSq(e1, e2)); -+ } -+ -+ -+ /** -+ * Calculates distance between 2 block positions -+ * @param e1 -+ * @param e2 -+ * @return -+ */ -+ public static double distance(BlockPos e1, BlockPos e2) { -+ return Math.sqrt(distanceSq(e1, e2)); -+ } -+ -+ /** -+ * Gets the distance between 2 positions -+ * @param x1 -+ * @param y1 -+ * @param z1 -+ * @param x2 -+ * @param y2 -+ * @param z2 -+ * @return -+ */ -+ public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) { -+ return Math.sqrt(distanceSq(x1, y1, z1, x2, y2, z2)); -+ } -+ -+ /** -+ * Get's the distance squared between 2 entities -+ * @param e1 -+ * @param e2 -+ * @return -+ */ -+ public static double distanceSq(Entity e1, Entity e2) { -+ return distanceSq(e1.getX(),e1.getY(),e1.getZ(), e2.getX(),e2.getY(),e2.getZ()); -+ } -+ -+ /** -+ * Gets the distance sqaured between 2 block positions -+ * @param pos1 -+ * @param pos2 -+ * @return -+ */ -+ public static double distanceSq(BlockPos pos1, BlockPos pos2) { -+ return distanceSq(pos1.getX(), pos1.getY(), pos1.getZ(), pos2.getX(), pos2.getY(), pos2.getZ()); -+ } -+ -+ /** -+ * Gets the distance squared between 2 positions -+ * @param x1 -+ * @param y1 -+ * @param z1 -+ * @param x2 -+ * @param y2 -+ * @param z2 -+ * @return -+ */ -+ public static double distanceSq(double x1, double y1, double z1, double x2, double y2, double z2) { -+ return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2); -+ } -+ -+ /** -+ * Converts a NMS World/BlockPosition to Bukkit Location -+ * @param world -+ * @param x -+ * @param y -+ * @param z -+ * @return -+ */ -+ public static Location toLocation(Level world, double x, double y, double z) { -+ return new Location(world.getWorld(), x, y, z); -+ } -+ -+ /** -+ * Converts a NMS World/BlockPosition to Bukkit Location -+ * @param world -+ * @param pos -+ * @return -+ */ -+ public static Location toLocation(Level world, BlockPos pos) { -+ return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()); -+ } -+ -+ /** -+ * Converts an NMS entity's current location to a Bukkit Location -+ * @param entity -+ * @return -+ */ -+ public static Location toLocation(Entity entity) { -+ return new Location(entity.getCommandSenderWorld().getWorld(), entity.getX(), entity.getY(), entity.getZ()); -+ } -+ -+ public static org.bukkit.block.Block toBukkitBlock(Level world, BlockPos pos) { -+ return world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); -+ } -+ -+ public static BlockPos toBlockPosition(Location loc) { -+ return new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); -+ } -+ -+ public static boolean isEdgeOfChunk(BlockPos pos) { -+ final int modX = pos.getX() & 15; -+ final int modZ = pos.getZ() & 15; -+ return (modX == 0 || modX == 15 || modZ == 0 || modZ == 15); -+ } -+ -+ /** -+ * Posts a task to be executed asynchronously -+ * @param run -+ */ -+ public static void scheduleAsyncTask(Runnable run) { -+ asyncExecutor.execute(run); -+ } -+ -+ @Nonnull -+ public static ServerLevel getNMSWorld(@Nonnull org.bukkit.World world) { -+ return ((CraftWorld) world).getHandle(); -+ } -+ -+ public static ServerLevel getNMSWorld(@Nonnull org.bukkit.entity.Entity entity) { -+ return getNMSWorld(entity.getWorld()); -+ } -+ -+ public static BlockFace toBukkitBlockFace(Direction enumDirection) { -+ switch (enumDirection) { -+ case DOWN: -+ return BlockFace.DOWN; -+ case UP: -+ return BlockFace.UP; -+ case NORTH: -+ return BlockFace.NORTH; -+ case SOUTH: -+ return BlockFace.SOUTH; -+ case WEST: -+ return BlockFace.WEST; -+ case EAST: -+ return BlockFace.EAST; -+ default: -+ return null; -+ } -+ } -+ -+ public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { -+ return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); -+ } -+} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -5506,8 +5507,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 MinecraftServer.LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), ioexception1); } // Spigot start -+ MCUtil.asyncExecutor.shutdown(); // Paper -+ try { MCUtil.asyncExecutor.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS); // Paper ++ io.papermc.paper.util.MCUtil.asyncExecutor.shutdown(); // Paper ++ try { io.papermc.paper.util.MCUtil.asyncExecutor.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS); // Paper + } catch (java.lang.InterruptedException ignored) {} // Paper if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { MinecraftServer.LOGGER.info("Saving usercache.json"); @@ -5693,7 +5694,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (left.isPresent() && ChunkHolder.this.fullChunkCreateCount == expectCreateCount) { + LevelChunk fullChunk = either.left().get(); + ChunkHolder.this.isFullChunkReady = true; -+ net.minecraft.server.ChunkSystem.onChunkBorder(fullChunk, this); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkBorder(fullChunk, this); + } + }); this.updateChunkToSave(this.fullChunkFuture, "full"); @@ -5702,7 +5703,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (flag2 && !flag3) { + // Paper start + if (this.isFullChunkReady) { -+ net.minecraft.server.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().left().get(), this); // Paper ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().left().get(), this); // Paper + } + // Paper end this.fullChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); @@ -5721,7 +5722,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + either.ifLeft(chunk -> { + // note: Here is a very good place to add callbacks to logic waiting on this. + ChunkHolder.this.isTickingReady = true; -+ net.minecraft.server.ChunkSystem.onChunkTicking(chunk, this); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(chunk, this); + }); + }); + // Paper end @@ -5732,7 +5733,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); + // Paper start + if (this.isTickingReady) { -+ net.minecraft.server.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper + } + // Paper end + this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage @@ -5747,7 +5748,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.entityTickingChunkFuture.thenAccept(either -> { + either.ifLeft(chunk -> { + ChunkHolder.this.isEntityTickingReady = true; -+ net.minecraft.server.ChunkSystem.onChunkEntityTicking(chunk, this); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkEntityTicking(chunk, this); + }); + }); + // Paper end @@ -5758,7 +5759,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); + // Paper start + if (this.isEntityTickingReady) { -+ net.minecraft.server.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); + } + // Paper end + this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage @@ -5792,7 +5793,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.DebugPackets; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.util.CsvOutput; @@ -5884,10 +5885,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 stringbuilder.append("Updating:").append(System.lineSeparator()); - this.updatingChunkMap.values().forEach(consumer); -+ net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).forEach(consumer); // Paper ++ io.papermc.paper.chunk.system.ChunkSystem.getUpdatingChunkHolders(this.level).forEach(consumer); // Paper stringbuilder.append("Visible:").append(System.lineSeparator()); - this.visibleChunkMap.values().forEach(consumer); -+ net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(consumer); // Paper ++ io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).forEach(consumer); // Paper CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading"); @@ -5896,7 +5897,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); + // Paper start -+ net.minecraft.server.ChunkSystem.onChunkHolderCreate(this.level, holder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderCreate(this.level, holder); + // Paper end } @@ -5911,7 +5912,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void saveAllChunks(boolean flush) { if (flush) { - List list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); -+ List list = (List) net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper ++ List list = (List) io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper MutableBoolean mutableboolean = new MutableBoolean(); do { @@ -5920,7 +5921,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.flushWorker(); } else { - this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded); -+ net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); ++ io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); } } @@ -5929,7 +5930,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean hasWork() { - return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); -+ return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || net.minecraft.server.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper ++ return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || io.papermc.paper.chunk.system.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper } private void processUnloads(BooleanSupplier shouldKeepTicking) { @@ -5946,7 +5947,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int l = 0; - ObjectIterator objectiterator = this.visibleChunkMap.values().iterator(); -+ Iterator objectiterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper ++ Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { @@ -5958,7 +5959,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + boolean removed; + if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) { -+ net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(this.level, holder); + // Paper end if (ichunkaccess instanceof LevelChunk) { ((LevelChunk) ichunkaccess).setLoaded(false); @@ -5969,7 +5970,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong()); - } + } else if (removed) { // Paper start -+ net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(this.level, holder); + } // Paper end } @@ -5979,7 +5980,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.viewDistance = j; this.distanceManager.updatePlayerTickets(this.viewDistance + 1); - ObjectIterator objectiterator = this.updatingChunkMap.values().iterator(); -+ Iterator objectiterator = net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper ++ Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper while (objectiterator.hasNext()) { ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); @@ -5988,7 +5989,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public int size() { - return this.visibleChunkMap.size(); -+ return net.minecraft.server.ChunkSystem.getVisibleChunkHolderCount(this.level); // Paper ++ return io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolderCount(this.level); // Paper } public DistanceManager getDistanceManager() { @@ -5997,14 +5998,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected Iterable getChunks() { - return Iterables.unmodifiableIterable(this.visibleChunkMap.values()); -+ return Iterables.unmodifiableIterable(net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level)); // Paper ++ return Iterables.unmodifiableIterable(io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level)); // Paper } void dumpChunks(Writer writer) throws IOException { CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); TickingTracker tickingtracker = this.distanceManager.tickingTracker(); - ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator(); -+ Iterator objectbidirectionaliterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper ++ Iterator objectbidirectionaliterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper while (objectbidirectionaliterator.hasNext()) { - Entry entry = (Entry) objectbidirectionaliterator.next(); @@ -6186,21 +6187,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + long chunkFutureAwaitCounter; // Paper - private -> package private + + public void getEntityTickingChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState( + this.level, x, z, ChunkHolder.FullChunkStatus.ENTITY_TICKING, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad + ); + } + + public void getTickingChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState( + this.level, x, z, ChunkHolder.FullChunkStatus.TICKING, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad + ); + } + + public void getFullChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState( + this.level, x, z, ChunkHolder.FullChunkStatus.BORDER, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad + ); @@ -6224,7 +6225,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } + -+ net.minecraft.server.ChunkSystem.scheduleChunkLoad( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad( + this.level, chunkX, chunkZ, ChunkHolder.getStatus(ticketLevel), true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, consumer + ); @@ -6261,7 +6262,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } + -+ this.getChunkAtAsynchronously(chunkX, chunkZ, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.EMPTY), (ChunkAccess chunk) -> { ++ this.getChunkAtAsynchronously(chunkX, chunkZ, io.papermc.paper.util.MCUtil.getTicketLevelFor(ChunkStatus.EMPTY), (ChunkAccess chunk) -> { + if (chunk == null) { + throw new IllegalStateException("Chunk cannot be null"); + } @@ -6503,7 +6504,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + for (int cx = minChunkX; cx <= maxChunkX; ++cx) { + for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { -+ net.minecraft.server.ChunkSystem.scheduleChunkLoad( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad( + this, cx, cz, net.minecraft.world.level.chunk.ChunkStatus.FULL, true, priority, consumer + ); + } @@ -7277,7 +7278,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // I don't want to know why this is a generic type. + Entity entityCasted = (Entity)entity; + boolean wasRemoved = entityCasted.isRemoved(); -+ net.minecraft.server.ChunkSystem.onEntityPreAdd((net.minecraft.server.level.ServerLevel)entityCasted.level, entityCasted); ++ io.papermc.paper.chunk.system.ChunkSystem.onEntityPreAdd((net.minecraft.server.level.ServerLevel)entityCasted.level, entityCasted); + if (!wasRemoved && entityCasted.isRemoved()) { + // removed by callback + return false; @@ -7297,7 +7298,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public Chunk[] getLoadedChunks() { - Long2ObjectLinkedOpenHashMap chunks = this.world.getChunkSource().chunkMap.visibleChunkMap; - return chunks.values().stream().map(ChunkHolder::getFullChunkNow).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); -+ List chunks = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world); // Paper ++ List chunks = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.world); // Paper + return chunks.stream().map(ChunkHolder::getFullChunkNow).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); } @@ -7333,7 +7334,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); + -+ net.minecraft.server.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { + net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { + net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c; + ret.complete(chunk == null ? null : chunk.getBukkitChunk()); diff --git a/patches/server/Missing-Entity-Behavior-API.patch b/patches/server/Missing-Entity-Behavior-API.patch index fbd4c4f27f..51e53dcd87 100644 --- a/patches/server/Missing-Entity-Behavior-API.patch +++ b/patches/server/Missing-Entity-Behavior-API.patch @@ -240,14 +240,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; + } + -+ return net.minecraft.server.MCUtil.toLocation(this.getHandle().getLevel(), pos); ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().getLevel(), pos); + } + + @Override + public void setTargetLocation(org.bukkit.Location location) { + net.minecraft.core.BlockPos pos = null; + if (location != null) { -+ pos = net.minecraft.server.MCUtil.toBlockPosition(location); ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); + } + + this.getHandle().targetPosition = pos; @@ -678,14 +678,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; + } + -+ return net.minecraft.server.MCUtil.toLocation(this.getHandle().getLevel(), pos); ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().getLevel(), pos); + } + + @Override + public void setAnchorLocation(org.bukkit.Location location) { + net.minecraft.core.BlockPos pos = null; + if (location != null) { -+ pos = net.minecraft.server.MCUtil.toBlockPosition(location); ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); + } + + this.getHandle().anchorPoint = pos; @@ -899,14 +899,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; + } + -+ return net.minecraft.server.MCUtil.toLocation(this.getHandle().getLevel(), pos); ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().getLevel(), pos); + } + + @Override + public void setWanderingTowards(org.bukkit.Location location) { + net.minecraft.core.BlockPos pos = null; + if (location != null) { -+ pos = net.minecraft.server.MCUtil.toBlockPosition(location); ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); + } + + this.getHandle().wanderTarget = pos; diff --git a/patches/server/Optimise-nearby-player-lookups.patch b/patches/server/Optimise-nearby-player-lookups.patch index 44415c53e8..d304cf75d8 100644 --- a/patches/server/Optimise-nearby-player-lookups.patch +++ b/patches/server/Optimise-nearby-player-lookups.patch @@ -56,7 +56,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper start - distance maps private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player))); + trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); } // Paper end - use distance map to optimise entity tracker + this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn @@ -72,7 +72,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.playerMobDistanceMap != null) { this.playerMobDistanceMap.remove(player); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player))); + trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); } // Paper end - use distance map to optimise entity tracker + this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn diff --git a/patches/server/Optimize-Collision-to-not-load-chunks.patch b/patches/server/Optimize-Collision-to-not-load-chunks.patch index 2f6b252d65..e3259b5069 100644 --- a/patches/server/Optimize-Collision-to-not-load-chunks.patch +++ b/patches/server/Optimize-Collision-to-not-load-chunks.patch @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // Paper start - ensure we don't load chunks + final @Nullable Entity source = this.context instanceof net.minecraft.world.phys.shapes.EntityCollisionContext entityContext ? entityContext.getEntity() : null; -+ boolean far = source != null && net.minecraft.server.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14; ++ boolean far = source != null && io.papermc.paper.util.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14; + this.pos.set(x, y, z); - BlockGetter blockGetter = this.getChunk(i, k); diff --git a/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch b/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch index f6f8858407..5be635d606 100644 --- a/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch +++ b/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch @@ -115,7 +115,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + packet.onPacketDispatch(getPlayer()); + if (connected && (InnerUtil.canSendImmediate(this, packet) || ( -+ net.minecraft.server.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && ++ io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && + (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) + ))) { this.sendPacket(packet, callbacks); @@ -194,7 +194,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (!isConnected()) { + return true; + } -+ if (net.minecraft.server.MCUtil.isMainThread()) { ++ if (io.papermc.paper.util.MCUtil.isMainThread()) { + return processQueue(); + } else if (isPending) { + // Should only happen during login/status stages diff --git a/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch b/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch index baeefbd477..bc8dad0309 100644 --- a/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch +++ b/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch @@ -15,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void onChunkAdd() { - + // Paper start - optimise anyPlayerCloseEnoughForSpawning -+ long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos); ++ long key = io.papermc.paper.util.MCUtil.getCoordinateKey(this.pos); + this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key); + this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); + // Paper end - optimise anyPlayerCloseEnoughForSpawning @@ -69,7 +69,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning // Paper start - per player mob spawning if (this.playerMobDistanceMap != null) { - this.playerMobDistanceMap.add(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); + this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider void removePlayerFromDistanceMaps(ServerPlayer player) { this.playerChunkManager.removePlayer(player); // Paper - replace chunk loader @@ -88,7 +88,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning // Paper start - per player mob spawning if (this.playerMobDistanceMap != null) { - this.playerMobDistanceMap.update(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); + this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.regionManagers.add(this.dataRegionManager); // Paper end @@ -292,8 +292,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + int range = Math.min(event.getSpawnRadius(), 32); // limit to max view distance -+ int chunkX = net.minecraft.server.MCUtil.getChunkCoordinate(player.getX()); -+ int chunkZ = net.minecraft.server.MCUtil.getChunkCoordinate(player.getZ()); ++ int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); ++ int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); + + playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range); + player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in anyPlayerCloseEnoughForSpawning diff --git a/patches/server/PlayerTeleportEndGatewayEvent.patch b/patches/server/PlayerTeleportEndGatewayEvent.patch index 093e85d160..84616b9a91 100644 --- a/patches/server/PlayerTeleportEndGatewayEvent.patch +++ b/patches/server/PlayerTeleportEndGatewayEvent.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; diff --git a/patches/server/PreCreatureSpawnEvent.patch b/patches/server/PreCreatureSpawnEvent.patch index 1849dfa6a0..a660637e5f 100644 --- a/patches/server/PreCreatureSpawnEvent.patch +++ b/patches/server/PreCreatureSpawnEvent.patch @@ -41,7 +41,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ net.minecraft.server.MCUtil.toLocation(worldserver, blockposition), ++ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition), + type, + reason + ); @@ -71,7 +71,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (type != null) { + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ net.minecraft.server.MCUtil.toLocation(worldserver, blockposition), ++ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition), + type, + spawnReason + ); @@ -112,7 +112,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (type != null) { + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ net.minecraft.server.MCUtil.toLocation(world, d0, d1, d2), ++ io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2), + type, + org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER + ); @@ -160,7 +160,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(EntityType.getKey(entitytypes).getPath()); + if (type != null) { + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ net.minecraft.server.MCUtil.toLocation(world, pos), ++ io.papermc.paper.util.MCUtil.toLocation(world, pos), + type, SpawnReason.NATURAL + ); + if (!event.callEvent()) { diff --git a/patches/server/PreSpawnerSpawnEvent.patch b/patches/server/PreSpawnerSpawnEvent.patch index a31a073edb..60123ea19f 100644 --- a/patches/server/PreSpawnerSpawnEvent.patch +++ b/patches/server/PreSpawnerSpawnEvent.patch @@ -20,10 +20,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( + com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent( - net.minecraft.server.MCUtil.toLocation(world, d0, d1, d2), + io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2), type, - org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER -+ net.minecraft.server.MCUtil.toLocation(world, pos) ++ io.papermc.paper.util.MCUtil.toLocation(world, pos) ); if (!event.callEvent()) { flag = true; diff --git a/patches/server/Prevent-Pathfinding-out-of-World-Border.patch b/patches/server/Prevent-Pathfinding-out-of-World-Border.patch index 905dbe9fd7..44136693cd 100644 --- a/patches/server/Prevent-Pathfinding-out-of-World-Border.patch +++ b/patches/server/Prevent-Pathfinding-out-of-World-Border.patch @@ -22,6 +22,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (BlockPos possibleTarget : positions) { - if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(), + if (!this.mob.getCommandSenderWorld().getWorldBorder().isWithinBounds(possibleTarget) || !new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(), // Paper - don't path out of world border - net.minecraft.server.MCUtil.toLocation(this.mob.level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) { + io.papermc.paper.util.MCUtil.toLocation(this.mob.level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) { if (!copiedSet) { copiedSet = true; diff --git a/patches/server/ProfileWhitelistVerifyEvent.patch b/patches/server/ProfileWhitelistVerifyEvent.patch index b797a95db9..ff1a09cd42 100644 --- a/patches/server/ProfileWhitelistVerifyEvent.patch +++ b/patches/server/ProfileWhitelistVerifyEvent.patch @@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + boolean isOp = this.ops.contains(gameprofile); + boolean isWhitelisted = !this.doWhiteList || isOp || this.whitelist.contains(gameprofile); + final com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent event; -+ event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(net.minecraft.server.MCUtil.toBukkit(gameprofile), this.doWhiteList, isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage); ++ event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(io.papermc.paper.util.MCUtil.toBukkit(gameprofile), this.doWhiteList, isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage); + event.callEvent(); + if (!event.isWhitelisted()) { + if (loginEvent != null) { diff --git a/patches/server/Provide-E-TE-Chunk-count-stat-methods.patch b/patches/server/Provide-E-TE-Chunk-count-stat-methods.patch index 41970cac37..9e9f6e3920 100644 --- a/patches/server/Provide-E-TE-Chunk-count-stat-methods.patch +++ b/patches/server/Provide-E-TE-Chunk-count-stat-methods.patch @@ -43,7 +43,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public int getTileEntityCount() { + // We don't use the full world tile entity list, so we must iterate chunks + int size = 0; -+ for (ChunkHolder playerchunk : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world)) { ++ for (ChunkHolder playerchunk : io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.world)) { + net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk(); + if (chunk == null) { + continue; @@ -62,7 +62,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public int getChunkCount() { + int ret = 0; + -+ for (ChunkHolder chunkHolder : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world)) { ++ for (ChunkHolder chunkHolder : io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.world)) { + if (chunkHolder.getTickingChunk() != null) { + ++ret; + } diff --git a/patches/server/Rewrite-chunk-system.patch b/patches/server/Rewrite-chunk-system.patch index cc7a1e39db..29ca589211 100644 --- a/patches/server/Rewrite-chunk-system.patch +++ b/patches/server/Rewrite-chunk-system.patch @@ -1322,7 +1322,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; +import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket; +import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.*; +import net.minecraft.util.Mth; @@ -2435,6 +2435,238 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } +} +diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java ++++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +@@ -0,0 +0,0 @@ public final class ChunkSystem { + } + + public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { +- level.chunkSource.mainThreadProcessor.execute(run); ++ level.chunkTaskScheduler.scheduleChunkTask(chunkX, chunkZ, run, priority); // Paper - rewrite chunk system + } + + public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, + final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, + final Consumer onComplete) { +- if (gen) { +- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- return; +- } +- scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { +- if (chunk == null) { +- onComplete.accept(null); +- } else { +- if (chunk.getStatus().isOrAfter(toStatus)) { +- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- } else { +- onComplete.accept(null); +- } +- } +- }); ++ level.chunkTaskScheduler.scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system + } + +- static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); +- +- private static long chunkLoadCounter = 0L; ++ // Paper - rewrite chunk system + public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, + final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { +- if (!Bukkit.isPrimaryThread()) { +- scheduleChunkTask(level, chunkX, chunkZ, () -> { +- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- }, priority); +- return; +- } +- +- final int minLevel = 33 + ChunkStatus.getDistance(toStatus); +- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; +- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); +- +- if (addTicket) { +- level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); +- } +- level.chunkSource.runDistanceManagerUpdates(); +- +- final Consumer loadCallback = (final ChunkAccess chunk) -> { +- try { +- if (onComplete != null) { +- onComplete.accept(chunk); +- } +- } catch (final ThreadDeath death) { +- throw death; +- } catch (final Throwable thr) { +- LOGGER.error("Exception handling chunk load callback", thr); +- SneakyThrow.sneaky(thr); +- } finally { +- if (addTicket) { +- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); +- level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); +- } +- } +- }; +- +- final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); +- +- if (holder == null || holder.getTicketLevel() > minLevel) { +- loadCallback.accept(null); +- return; +- } +- +- final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); +- +- if (loadFuture.isDone()) { +- loadCallback.accept(loadFuture.join().left().orElse(null)); +- return; +- } +- +- loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { +- if (thr != null) { +- loadCallback.accept(null); +- return; +- } +- loadCallback.accept(either.left().orElse(null)); +- }, (final Runnable r) -> { +- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); +- }); ++ level.chunkTaskScheduler.scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system + } + + public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, + final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, + final PrioritisedExecutor.Priority priority, final Consumer onComplete) { +- if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { +- throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); +- } +- +- if (!Bukkit.isPrimaryThread()) { +- scheduleChunkTask(level, chunkX, chunkZ, () -> { +- scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- }, priority); +- return; +- } +- +- final int minLevel = 33 - (toStatus.ordinal() - 1); +- final int radius = toStatus.ordinal() - 1; +- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; +- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); +- +- if (addTicket) { +- level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); +- } +- level.chunkSource.runDistanceManagerUpdates(); +- +- final Consumer loadCallback = (final LevelChunk chunk) -> { +- try { +- if (onComplete != null) { +- onComplete.accept(chunk); +- } +- } catch (final ThreadDeath death) { +- throw death; +- } catch (final Throwable thr) { +- LOGGER.error("Exception handling chunk load callback", thr); +- SneakyThrow.sneaky(thr); +- } finally { +- if (addTicket) { +- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); +- level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); +- } +- } +- }; +- +- final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); +- +- if (holder == null || holder.getTicketLevel() > minLevel) { +- loadCallback.accept(null); +- return; +- } +- +- final CompletableFuture> tickingState; +- switch (toStatus) { +- case BORDER: { +- tickingState = holder.getFullChunkFuture(); +- break; +- } +- case TICKING: { +- tickingState = holder.getTickingChunkFuture(); +- break; +- } +- case ENTITY_TICKING: { +- tickingState = holder.getEntityTickingChunkFuture(); +- break; +- } +- default: { +- throw new IllegalStateException("Cannot reach here"); +- } +- } +- +- if (tickingState.isDone()) { +- loadCallback.accept(tickingState.join().left().orElse(null)); +- return; +- } +- +- tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { +- if (thr != null) { +- loadCallback.accept(null); +- return; +- } +- loadCallback.accept(either.left().orElse(null)); +- }, (final Runnable r) -> { +- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); +- }); ++ level.chunkTaskScheduler.scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system + } + + public static List getVisibleChunkHolders(final ServerLevel level) { +- return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); ++ return level.chunkTaskScheduler.chunkHolderManager.getOldChunkHolders(); // Paper - rewrite chunk system + } + + public static List getUpdatingChunkHolders(final ServerLevel level) { +- return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); ++ return level.chunkTaskScheduler.chunkHolderManager.getOldChunkHolders(); // Paper - rewrite chunk system + } + + public static int getVisibleChunkHolderCount(final ServerLevel level) { +- return level.chunkSource.chunkMap.visibleChunkMap.size(); ++ return level.chunkTaskScheduler.chunkHolderManager.size(); // Paper - rewrite chunk system + } + + public static int getUpdatingChunkHolderCount(final ServerLevel level) { +- return level.chunkSource.chunkMap.updatingChunkMap.size(); ++ return level.chunkTaskScheduler.chunkHolderManager.size(); // Paper - rewrite chunk system + } + + public static boolean hasAnyChunkHolders(final ServerLevel level) { +@@ -0,0 +0,0 @@ public final class ChunkSystem { + } + + public static int getSendViewDistance(final ServerPlayer player) { +- return getLoadViewDistance(player); ++ return io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player); + } + + public static int getLoadViewDistance(final ServerPlayer player) { +- final ServerLevel level = player.getLevel(); +- if (level == null) { +- return Bukkit.getViewDistance() + 1; +- } +- return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; ++ return io.papermc.paper.chunk.PlayerChunkLoader.getLoadViewDistance(player); + } + + public static int getTickViewDistance(final ServerPlayer player) { +- final ServerLevel level = player.getLevel(); +- if (level == null) { +- return Bukkit.getSimulationDistance(); +- } +- return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); ++ return io.papermc.paper.chunk.PlayerChunkLoader.getTickViewDistance(player); + } + + private ChunkSystem() { diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -2453,7 +2685,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import net.minecraft.core.BlockPos; -+import net.minecraft.server.ChunkSystem; ++import io.papermc.paper.chunk.system.ChunkSystem; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; @@ -5277,7 +5509,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; +import net.minecraft.nbt.CompoundTag; -+import net.minecraft.server.ChunkSystem; ++import io.papermc.paper.chunk.system.ChunkSystem; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; @@ -7264,7 +7496,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; @@ -11336,7 +11568,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import java.util.Collections; +import java.util.List; +import java.util.Locale; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; @@ -11432,7 +11664,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + int ticking = 0; + int entityTicking = 0; + -+ for (final ChunkHolder chunk : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(world)) { ++ for (final ChunkHolder chunk : io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(world)) { + if (chunk.getFullChunkNowUnchecked() == null) { + continue; + } @@ -11589,6 +11821,153 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + +} +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -0,0 +0,0 @@ + package io.papermc.paper.util; + + import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import com.google.gson.JsonArray; ++import com.google.gson.JsonObject; ++import com.google.gson.internal.Streams; ++import com.google.gson.stream.JsonWriter; ++import com.mojang.datafixers.util.Either; + import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; + import java.lang.ref.Cleaner; ++import it.unimi.dsi.fastutil.objects.ReferenceArrayList; + import net.minecraft.core.BlockPos; + import net.minecraft.core.Direction; + import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ChunkHolder; ++import net.minecraft.server.level.ChunkMap; ++import net.minecraft.server.level.DistanceManager; + import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.server.level.Ticket; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.level.ChunkPos; + import net.minecraft.world.level.ClipContext; + import net.minecraft.world.level.Level; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.ChunkStatus; + import org.apache.commons.lang.exception.ExceptionUtils; + import org.bukkit.Location; + import org.bukkit.block.BlockFace; +@@ -0,0 +0,0 @@ import org.spigotmc.AsyncCatcher; + + import javax.annotation.Nonnull; + import javax.annotation.Nullable; ++import java.io.*; ++import java.nio.charset.StandardCharsets; + import java.util.List; + import java.util.Queue; ++import java.util.Set; + import java.util.concurrent.CompletableFuture; + import java.util.concurrent.ExecutionException; + import java.util.concurrent.LinkedBlockingQueue; +@@ -0,0 +0,0 @@ public final class MCUtil { + } + } + ++ public static ChunkStatus getChunkStatus(ChunkHolder chunk) { ++ return chunk.getChunkHolderStatus(); ++ } ++ ++ public static void dumpChunks(File file, boolean watchdog) throws IOException { ++ file.getParentFile().mkdirs(); ++ file.createNewFile(); ++ ReferenceArrayList worlds = new ReferenceArrayList<>(org.bukkit.Bukkit.getWorlds()); ++ ReferenceArrayList loadedWorlds = new ReferenceArrayList<>(worlds); ++ JsonObject data = new JsonObject(); ++ ++ data.addProperty("server-version", org.bukkit.Bukkit.getVersion()); ++ data.addProperty("data-version", 1); ++ ++ { ++ JsonArray players = new JsonArray(); ++ data.add("all-players", players); ++ List playerList = MinecraftServer.getServer().getPlayerList().players; ++ for (ServerPlayer player : playerList) { ++ JsonObject playerData = new JsonObject(); ++ players.add(playerData); ++ ++ Level playerWorld = player.getLevel(); ++ org.bukkit.World craftWorld = playerWorld.getWorld(); ++ Entity.RemovalReason removalReason = player.getRemovalReason(); ++ ++ playerData.addProperty("name", player.getScoreboardName()); ++ playerData.addProperty("x", player.getX()); ++ playerData.addProperty("y", player.getY()); ++ playerData.addProperty("z", player.getZ()); ++ playerData.addProperty("world", playerWorld == null ? "null world" : craftWorld.getName()); ++ playerData.addProperty("removalReason", removalReason == null ? "null" : removalReason.name()); ++ ++ if (!worlds.contains(craftWorld)) { ++ worlds.add(craftWorld); ++ } ++ } ++ } ++ ++ JsonArray chunkWaitInformation = new JsonArray(); ++ data.add("chunk-wait-infos", chunkWaitInformation); ++ ++ for (io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.ChunkInfo chunkInfo : io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.getChunkInfos()) { ++ chunkWaitInformation.add(chunkInfo.toString()); ++ } ++ ++ JsonArray worldsData = new JsonArray(); ++ ++ for (org.bukkit.World bukkitWorld : worlds) { ++ JsonObject worldData = new JsonObject(); ++ ++ ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle(); ++ List players = world.players; ++ ++ worldData.addProperty("is-loaded", loadedWorlds.contains(bukkitWorld)); ++ worldData.addProperty("name", world.getWorld().getName()); ++ worldData.addProperty("view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()); // Paper - replace chunk loader system ++ worldData.addProperty("tick-view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()); // Paper - replace chunk loader system ++ worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); ++ worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); ++ ++ JsonArray playersData = new JsonArray(); ++ ++ for (ServerPlayer player : players) { ++ JsonObject playerData = new JsonObject(); ++ ++ playerData.addProperty("name", player.getScoreboardName()); ++ playerData.addProperty("x", player.getX()); ++ playerData.addProperty("y", player.getY()); ++ playerData.addProperty("z", player.getZ()); ++ ++ playersData.add(playerData); ++ } ++ ++ worldData.add("players", playersData); ++ worldData.add("chunk-data", watchdog ? world.chunkTaskScheduler.chunkHolderManager.getDebugJsonForWatchdog() : world.chunkTaskScheduler.chunkHolderManager.getDebugJson()); ++ worldsData.add(worldData); ++ } ++ ++ data.add("worlds", worldsData); ++ ++ StringWriter stringWriter = new StringWriter(); ++ JsonWriter jsonWriter = new JsonWriter(stringWriter); ++ jsonWriter.setIndent(" "); ++ jsonWriter.setLenient(false); ++ Streams.write(data, jsonWriter); ++ ++ String fileData = stringWriter.toString(); ++ ++ try (PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8)) { ++ out.print(fileData); ++ } ++ } ++ + public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { + return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); + } diff --git a/src/main/java/io/papermc/paper/util/TickThread.java b/src/main/java/io/papermc/paper/util/TickThread.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/io/papermc/paper/util/TickThread.java @@ -12316,384 +12695,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } @Override -diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/ChunkSystem.java -+++ b/src/main/java/net/minecraft/server/ChunkSystem.java -@@ -0,0 +0,0 @@ public final class ChunkSystem { - } - - public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { -- level.chunkSource.mainThreadProcessor.execute(run); -+ level.chunkTaskScheduler.scheduleChunkTask(chunkX, chunkZ, run, priority); // Paper - rewrite chunk system - } - - public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, - final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, - final Consumer onComplete) { -- if (gen) { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -- return; -- } -- scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { -- if (chunk == null) { -- onComplete.accept(null); -- } else { -- if (chunk.getStatus().isOrAfter(toStatus)) { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -- } else { -- onComplete.accept(null); -- } -- } -- }); -+ level.chunkTaskScheduler.scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system - } - -- static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); -- -- private static long chunkLoadCounter = 0L; -+ // Paper - rewrite chunk system - public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, - final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { -- if (!Bukkit.isPrimaryThread()) { -- scheduleChunkTask(level, chunkX, chunkZ, () -> { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -- }, priority); -- return; -- } -- -- final int minLevel = 33 + ChunkStatus.getDistance(toStatus); -- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -- -- if (addTicket) { -- level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -- } -- level.chunkSource.runDistanceManagerUpdates(); -- -- final Consumer loadCallback = (final ChunkAccess chunk) -> { -- try { -- if (onComplete != null) { -- onComplete.accept(chunk); -- } -- } catch (final ThreadDeath death) { -- throw death; -- } catch (final Throwable thr) { -- LOGGER.error("Exception handling chunk load callback", thr); -- SneakyThrow.sneaky(thr); -- } finally { -- if (addTicket) { -- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); -- level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -- } -- } -- }; -- -- final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -- -- if (holder == null || holder.getTicketLevel() > minLevel) { -- loadCallback.accept(null); -- return; -- } -- -- final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); -- -- if (loadFuture.isDone()) { -- loadCallback.accept(loadFuture.join().left().orElse(null)); -- return; -- } -- -- loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { -- if (thr != null) { -- loadCallback.accept(null); -- return; -- } -- loadCallback.accept(either.left().orElse(null)); -- }, (final Runnable r) -> { -- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); -- }); -+ level.chunkTaskScheduler.scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system - } - - public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, - final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, - final PrioritisedExecutor.Priority priority, final Consumer onComplete) { -- if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { -- throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); -- } -- -- if (!Bukkit.isPrimaryThread()) { -- scheduleChunkTask(level, chunkX, chunkZ, () -> { -- scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -- }, priority); -- return; -- } -- -- final int minLevel = 33 - (toStatus.ordinal() - 1); -- final int radius = toStatus.ordinal() - 1; -- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -- -- if (addTicket) { -- level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -- } -- level.chunkSource.runDistanceManagerUpdates(); -- -- final Consumer loadCallback = (final LevelChunk chunk) -> { -- try { -- if (onComplete != null) { -- onComplete.accept(chunk); -- } -- } catch (final ThreadDeath death) { -- throw death; -- } catch (final Throwable thr) { -- LOGGER.error("Exception handling chunk load callback", thr); -- SneakyThrow.sneaky(thr); -- } finally { -- if (addTicket) { -- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); -- level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -- } -- } -- }; -- -- final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -- -- if (holder == null || holder.getTicketLevel() > minLevel) { -- loadCallback.accept(null); -- return; -- } -- -- final CompletableFuture> tickingState; -- switch (toStatus) { -- case BORDER: { -- tickingState = holder.getFullChunkFuture(); -- break; -- } -- case TICKING: { -- tickingState = holder.getTickingChunkFuture(); -- break; -- } -- case ENTITY_TICKING: { -- tickingState = holder.getEntityTickingChunkFuture(); -- break; -- } -- default: { -- throw new IllegalStateException("Cannot reach here"); -- } -- } -- -- if (tickingState.isDone()) { -- loadCallback.accept(tickingState.join().left().orElse(null)); -- return; -- } -- -- tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { -- if (thr != null) { -- loadCallback.accept(null); -- return; -- } -- loadCallback.accept(either.left().orElse(null)); -- }, (final Runnable r) -> { -- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); -- }); -+ level.chunkTaskScheduler.scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system - } - - public static List getVisibleChunkHolders(final ServerLevel level) { -- return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); -+ return level.chunkTaskScheduler.chunkHolderManager.getOldChunkHolders(); // Paper - rewrite chunk system - } - - public static List getUpdatingChunkHolders(final ServerLevel level) { -- return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); -+ return level.chunkTaskScheduler.chunkHolderManager.getOldChunkHolders(); // Paper - rewrite chunk system - } - - public static int getVisibleChunkHolderCount(final ServerLevel level) { -- return level.chunkSource.chunkMap.visibleChunkMap.size(); -+ return level.chunkTaskScheduler.chunkHolderManager.size(); // Paper - rewrite chunk system - } - - public static int getUpdatingChunkHolderCount(final ServerLevel level) { -- return level.chunkSource.chunkMap.updatingChunkMap.size(); -+ return level.chunkTaskScheduler.chunkHolderManager.size(); // Paper - rewrite chunk system - } - - public static boolean hasAnyChunkHolders(final ServerLevel level) { -@@ -0,0 +0,0 @@ public final class ChunkSystem { - } - - public static int getSendViewDistance(final ServerPlayer player) { -- return getLoadViewDistance(player); -+ return io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player); - } - - public static int getLoadViewDistance(final ServerPlayer player) { -- final ServerLevel level = player.getLevel(); -- if (level == null) { -- return Bukkit.getViewDistance() + 1; -- } -- return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; -+ return io.papermc.paper.chunk.PlayerChunkLoader.getLoadViewDistance(player); - } - - public static int getTickViewDistance(final ServerPlayer player) { -- final ServerLevel level = player.getLevel(); -- if (level == null) { -- return Bukkit.getSimulationDistance(); -- } -- return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); -+ return io.papermc.paper.chunk.PlayerChunkLoader.getTickViewDistance(player); - } - - private ChunkSystem() { -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -0,0 +0,0 @@ - package net.minecraft.server; - - import com.google.common.util.concurrent.ThreadFactoryBuilder; -+import com.google.gson.JsonArray; -+import com.google.gson.JsonObject; -+import com.google.gson.internal.Streams; -+import com.google.gson.stream.JsonWriter; -+import com.mojang.datafixers.util.Either; - import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; - import java.lang.ref.Cleaner; -+import it.unimi.dsi.fastutil.objects.ReferenceArrayList; - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.ChunkMap; -+import net.minecraft.server.level.DistanceManager; - import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.level.Ticket; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.level.ChunkPos; - import net.minecraft.world.level.ClipContext; - import net.minecraft.world.level.Level; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; - import org.apache.commons.lang.exception.ExceptionUtils; - import org.bukkit.Location; - import org.bukkit.block.BlockFace; -@@ -0,0 +0,0 @@ import org.spigotmc.AsyncCatcher; - - import javax.annotation.Nonnull; - import javax.annotation.Nullable; -+import java.io.*; -+import java.nio.charset.StandardCharsets; - import java.util.List; - import java.util.Queue; -+import java.util.Set; - import java.util.concurrent.CompletableFuture; - import java.util.concurrent.ExecutionException; - import java.util.concurrent.LinkedBlockingQueue; -@@ -0,0 +0,0 @@ public final class MCUtil { - } - } - -+ public static ChunkStatus getChunkStatus(ChunkHolder chunk) { -+ return chunk.getChunkHolderStatus(); -+ } -+ -+ public static void dumpChunks(File file, boolean watchdog) throws IOException { -+ file.getParentFile().mkdirs(); -+ file.createNewFile(); -+ ReferenceArrayList worlds = new ReferenceArrayList<>(org.bukkit.Bukkit.getWorlds()); -+ ReferenceArrayList loadedWorlds = new ReferenceArrayList<>(worlds); -+ JsonObject data = new JsonObject(); -+ -+ data.addProperty("server-version", org.bukkit.Bukkit.getVersion()); -+ data.addProperty("data-version", 1); -+ -+ { -+ JsonArray players = new JsonArray(); -+ data.add("all-players", players); -+ List playerList = MinecraftServer.getServer().getPlayerList().players; -+ for (ServerPlayer player : playerList) { -+ JsonObject playerData = new JsonObject(); -+ players.add(playerData); -+ -+ Level playerWorld = player.getLevel(); -+ org.bukkit.World craftWorld = playerWorld.getWorld(); -+ Entity.RemovalReason removalReason = player.getRemovalReason(); -+ -+ playerData.addProperty("name", player.getScoreboardName()); -+ playerData.addProperty("x", player.getX()); -+ playerData.addProperty("y", player.getY()); -+ playerData.addProperty("z", player.getZ()); -+ playerData.addProperty("world", playerWorld == null ? "null world" : craftWorld.getName()); -+ playerData.addProperty("removalReason", removalReason == null ? "null" : removalReason.name()); -+ -+ if (!worlds.contains(craftWorld)) { -+ worlds.add(craftWorld); -+ } -+ } -+ } -+ -+ JsonArray chunkWaitInformation = new JsonArray(); -+ data.add("chunk-wait-infos", chunkWaitInformation); -+ -+ for (io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.ChunkInfo chunkInfo : io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.getChunkInfos()) { -+ chunkWaitInformation.add(chunkInfo.toString()); -+ } -+ -+ JsonArray worldsData = new JsonArray(); -+ -+ for (org.bukkit.World bukkitWorld : worlds) { -+ JsonObject worldData = new JsonObject(); -+ -+ ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle(); -+ List players = world.players; -+ -+ worldData.addProperty("is-loaded", loadedWorlds.contains(bukkitWorld)); -+ worldData.addProperty("name", world.getWorld().getName()); -+ worldData.addProperty("view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()); // Paper - replace chunk loader system -+ worldData.addProperty("tick-view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()); // Paper - replace chunk loader system -+ worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); -+ worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); -+ -+ JsonArray playersData = new JsonArray(); -+ -+ for (ServerPlayer player : players) { -+ JsonObject playerData = new JsonObject(); -+ -+ playerData.addProperty("name", player.getScoreboardName()); -+ playerData.addProperty("x", player.getX()); -+ playerData.addProperty("y", player.getY()); -+ playerData.addProperty("z", player.getZ()); -+ -+ playersData.add(playerData); -+ } -+ -+ worldData.add("players", playersData); -+ worldData.add("chunk-data", watchdog ? world.chunkTaskScheduler.chunkHolderManager.getDebugJsonForWatchdog() : world.chunkTaskScheduler.chunkHolderManager.getDebugJson()); -+ worldsData.add(worldData); -+ } -+ -+ data.add("worlds", worldsData); -+ -+ StringWriter stringWriter = new StringWriter(); -+ JsonWriter jsonWriter = new JsonWriter(stringWriter); -+ jsonWriter.setIndent(" "); -+ jsonWriter.setLenient(false); -+ Streams.write(data, jsonWriter); -+ -+ String fileData = stringWriter.toString(); -+ -+ try (PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8)) { -+ out.print(fileData); -+ } -+ } -+ - public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { - return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); - } diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/Main.java @@ -12877,7 +12878,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + "chunks-" + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(java.time.LocalDateTime.now()) + ".txt"); + sender.sendMessage(net.kyori.adventure.text.Component.text("Writing chunk information dump to " + file, net.kyori.adventure.text.format.NamedTextColor.GREEN)); + try { -+ net.minecraft.server.MCUtil.dumpChunks(file, true); ++ io.papermc.paper.util.MCUtil.dumpChunks(file, true); + sender.sendMessage(net.kyori.adventure.text.Component.text("Successfully written chunk information!", net.kyori.adventure.text.format.NamedTextColor.GREEN)); + } catch (Throwable thr) { + MinecraftServer.LOGGER.warn("Failed to dump chunk information to file " + file.toString(), thr); @@ -13339,7 +13340,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (left.isPresent() && ChunkHolder.this.fullChunkCreateCount == expectCreateCount) { - LevelChunk fullChunk = either.left().get(); - ChunkHolder.this.isFullChunkReady = true; -- net.minecraft.server.ChunkSystem.onChunkBorder(fullChunk, this); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkBorder(fullChunk, this); - } - }); - this.updateChunkToSave(this.fullChunkFuture, "full"); @@ -13348,7 +13349,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (flag2 && !flag3) { - // Paper start - if (this.isFullChunkReady) { -- net.minecraft.server.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().left().get(), this); // Paper +- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().left().get(), this); // Paper - } - // Paper end - this.fullChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); @@ -13368,7 +13369,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - either.ifLeft(chunk -> { - // note: Here is a very good place to add callbacks to logic waiting on this. - ChunkHolder.this.isTickingReady = true; -- net.minecraft.server.ChunkSystem.onChunkTicking(chunk, this); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(chunk, this); - }); - }); - // Paper end @@ -13378,7 +13379,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (flag4 && !flag5) { - // Paper start - if (this.isTickingReady) { -- net.minecraft.server.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper +- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper - } - // Paper end - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage @@ -13399,7 +13400,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.entityTickingChunkFuture.thenAccept(either -> { - either.ifLeft(chunk -> { - ChunkHolder.this.isEntityTickingReady = true; -- net.minecraft.server.ChunkSystem.onChunkEntityTicking(chunk, this); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkEntityTicking(chunk, this); - }); - }); - // Paper end @@ -13409,7 +13410,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (flag6 && !flag7) { - // Paper start - if (this.isEntityTickingReady) { -- net.minecraft.server.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); - } - // Paper end - this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage @@ -13783,7 +13784,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } else { - holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); - // Paper start -- net.minecraft.server.ChunkSystem.onChunkHolderCreate(this.level, holder); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderCreate(this.level, holder); - // Paper end - } - @@ -13818,7 +13819,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void saveAllChunks(boolean flush) { - if (flush) { -- List list = (List) net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper +- List list = (List) io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper - MutableBoolean mutableboolean = new MutableBoolean(); - - do { @@ -13847,7 +13848,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - }); - this.flushWorker(); - } else { -- net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); +- io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); - } - + this.level.chunkTaskScheduler.chunkHolderManager.saveAllChunks(flush, false, false); // Paper - rewrite chunk system @@ -13871,7 +13872,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public boolean hasWork() { -- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || net.minecraft.server.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper +- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || io.papermc.paper.chunk.system.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -13901,7 +13902,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - - int l = 0; -- Iterator objectiterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper +- Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper - - while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { - if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { @@ -13923,7 +13924,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - // Paper start - boolean removed; - if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) { -- net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(this.level, holder); - // Paper end - if (ichunkaccess instanceof LevelChunk) { - ((LevelChunk) ichunkaccess).setLoaded(false); @@ -13941,7 +13942,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null); - this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong()); - } else if (removed) { // Paper start -- net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(this.level, holder); - } // Paper end - - } @@ -14295,7 +14296,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.viewDistance = j; - this.distanceManager.updatePlayerTickets(this.viewDistance + 1); -- Iterator objectiterator = net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper +- Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper - - while (objectiterator.hasNext()) { - ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); @@ -14333,7 +14334,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 void dumpChunks(Writer writer) throws IOException { - CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); - TickingTracker tickingtracker = this.distanceManager.tickingTracker(); -- Iterator objectbidirectionaliterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper +- Iterator objectbidirectionaliterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper - - while (objectbidirectionaliterator.hasNext()) { - ChunkHolder playerchunk = objectbidirectionaliterator.next(); // Paper @@ -15017,7 +15018,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + priority = ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL; + } + -+ net.minecraft.server.ChunkSystem.scheduleChunkLoad(this.level, x, z, gen, ChunkStatus.FULL, true, priority, (chunk) -> { ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.level, x, z, gen, ChunkStatus.FULL, true, priority, (chunk) -> { + if (chunk == null) { + ret.complete(ChunkHolder.UNLOADED_CHUNK); + } else { @@ -16328,8 +16329,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public void onUnload(long coordinate) { // Paper - rewrite chunk system -+ int chunkX = net.minecraft.server.MCUtil.getCoordinateX(coordinate); -+ int chunkZ = net.minecraft.server.MCUtil.getCoordinateZ(coordinate); ++ int chunkX = io.papermc.paper.util.MCUtil.getCoordinateX(coordinate); ++ int chunkZ = io.papermc.paper.util.MCUtil.getCoordinateZ(coordinate); + io.papermc.paper.util.TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Unloading poi chunk off-main"); + for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) { + long sectionPos = SectionPos.asLong(chunkX, section, chunkZ); @@ -16764,7 +16765,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // the chunk load event // -> stays here + // any entity add to world events // -> in FULL status + this.loadCallback(); -+ net.minecraft.server.ChunkSystem.onChunkBorder(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkBorder(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkUnload(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { @@ -16774,25 +16775,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // any entity add to world events // -> goes into the unload logic, it will completely explode + // etc later + this.unloadCallback(); -+ net.minecraft.server.ChunkSystem.onChunkNotBorder(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotBorder(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { + this.postProcessGeneration(); + this.level.startTickingChunk(this); -+ net.minecraft.server.ChunkSystem.onChunkTicking(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkNotTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { -+ net.minecraft.server.ChunkSystem.onChunkNotTicking(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkEntityTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { -+ net.minecraft.server.ChunkSystem.onChunkEntityTicking(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkEntityTicking(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkNotEntityTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { -+ net.minecraft.server.ChunkSystem.onChunkNotEntityTicking(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotEntityTicking(this, chunkHolder.vanillaChunkHolder); + } + // Paper end - new load callbacks + diff --git a/patches/server/Starlight.patch b/patches/server/Starlight.patch index 72de283cb2..0284be6217 100644 --- a/patches/server/Starlight.patch +++ b/patches/server/Starlight.patch @@ -4357,7 +4357,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import io.papermc.paper.command.PaperSubcommand; +import java.util.ArrayDeque; +import java.util.Deque; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; @@ -4581,7 +4581,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + final Long id = Long.valueOf(this.relightCounter++); + -+ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().addTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), id); ++ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().addTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, io.papermc.paper.util.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), id); + ticketIds.put(chunkPos, id); + + ++totalChunks; @@ -4592,7 +4592,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + chunkLightCallback.accept(chunkPos); + ((java.util.concurrent.Executor)((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().mainThreadProcessor).execute(() -> { + ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong()).broadcast(new net.minecraft.network.protocol.game.ClientboundLightUpdatePacket(chunkPos, ThreadedLevelLightEngine.this, null, null, true), false); -+ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().removeTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), ticketIds.get(chunkPos)); ++ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().removeTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, io.papermc.paper.util.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), ticketIds.get(chunkPos)); + }); + }, onComplete); + }); diff --git a/patches/server/Turtle-API.patch b/patches/server/Turtle-API.patch index ea323f3f47..986d06a1ea 100644 --- a/patches/server/Turtle-API.patch +++ b/patches/server/Turtle-API.patch @@ -26,7 +26,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!this.turtle.isInWater() && this.isReachedTarget()) { if (this.turtle.layEggCounter < 1) { - this.turtle.setLayingEgg(true); -+ this.turtle.setLayingEgg(new com.destroystokyo.paper.event.entity.TurtleStartDiggingEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), net.minecraft.server.MCUtil.toLocation(this.turtle.level, this.getTargetPosition())).callEvent()); // Paper ++ this.turtle.setLayingEgg(new com.destroystokyo.paper.event.entity.TurtleStartDiggingEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level, this.getTargetPosition())).callEvent()); // Paper } else if (this.turtle.layEggCounter > this.adjustedTickDelay(200)) { Level world = this.turtle.level; @@ -34,7 +34,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1)).isCancelled()) { + // Paper start + int eggCount = this.turtle.random.nextInt(4) + 1; -+ com.destroystokyo.paper.event.entity.TurtleLayEggEvent layEggEvent = new com.destroystokyo.paper.event.entity.TurtleLayEggEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), net.minecraft.server.MCUtil.toLocation(this.turtle.level, this.blockPos.above()), eggCount); ++ com.destroystokyo.paper.event.entity.TurtleLayEggEvent layEggEvent = new com.destroystokyo.paper.event.entity.TurtleLayEggEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level, this.blockPos.above()), eggCount); + if (layEggEvent.callEvent() && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount())).isCancelled()) { world.playSound((Player) null, blockposition, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + world.random.nextFloat() * 0.2F); - world.setBlock(this.blockPos.above(), (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1), 3); @@ -63,12 +63,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + @Override + public org.bukkit.Location getHome() { -+ return net.minecraft.server.MCUtil.toLocation(getHandle().getLevel(), getHandle().getHomePos()); ++ return io.papermc.paper.util.MCUtil.toLocation(getHandle().getLevel(), getHandle().getHomePos()); + } + + @Override + public void setHome(org.bukkit.Location location) { -+ getHandle().setHomePos(net.minecraft.server.MCUtil.toBlockPosition(location)); ++ getHandle().setHomePos(io.papermc.paper.util.MCUtil.toBlockPosition(location)); + } + + @Override diff --git a/patches/server/Use-distance-map-to-optimise-entity-tracker.patch b/patches/server/Use-distance-map-to-optimise-entity-tracker.patch index 6b85b5fb6c..f38fab1a4c 100644 --- a/patches/server/Use-distance-map-to-optimise-entity-tracker.patch +++ b/patches/server/Use-distance-map-to-optimise-entity-tracker.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.DebugPackets; - import net.minecraft.server.MCUtil; + import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.network.ServerPlayerConnection; @@ -42,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 void addPlayerToDistanceMaps(ServerPlayer player) { this.playerChunkManager.addPlayer(player); // Paper - replace chunk loader @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerMobDistanceMap.add(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); + this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); } // Paper end - per player mob spawning + // Paper start - use distance map to optimise entity tracker @@ -50,7 +50,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i]; + int trackRange = this.entityTrackerTrackRanges[i]; + -+ trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player))); ++ trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); + } + // Paper end - use distance map to optimise entity tracker } @@ -69,7 +69,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 void updateMaps(ServerPlayer player) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerMobDistanceMap.update(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); + this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); } // Paper end - per player mob spawning + // Paper start - use distance map to optimise entity tracker @@ -77,7 +77,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i]; + int trackRange = this.entityTrackerTrackRanges[i]; + -+ trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player))); ++ trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); + } + // Paper end - use distance map to optimise entity tracker } @@ -294,7 +294,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; diff --git a/patches/server/implement-optional-per-player-mob-spawns.patch b/patches/server/implement-optional-per-player-mob-spawns.patch index e6eac3d384..829613e437 100644 --- a/patches/server/implement-optional-per-player-mob-spawns.patch +++ b/patches/server/implement-optional-per-player-mob-spawns.patch @@ -269,7 +269,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Note: players need to be explicitly added to distance maps before they can be updated + // Paper start - per player mob spawning + if (this.playerMobDistanceMap != null) { -+ this.playerMobDistanceMap.add(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); ++ this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); + } + // Paper end - per player mob spawning } @@ -291,7 +291,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.playerChunkManager.updatePlayer(player); // Paper - replace chunk loader + // Paper start - per player mob spawning + if (this.playerMobDistanceMap != null) { -+ this.playerMobDistanceMap.update(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); ++ this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); + } + // Paper end - per player mob spawning } diff --git a/patches/server/incremental-chunk-and-player-saving.patch b/patches/server/incremental-chunk-and-player-saving.patch index 80afeea9f5..2c93d1474d 100644 --- a/patches/server/incremental-chunk-and-player-saving.patch +++ b/patches/server/incremental-chunk-and-player-saving.patch @@ -147,7 +147,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public void saveAll(int interval) { - net.minecraft.server.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main + io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main MinecraftTimings.savePlayers.startTiming(); // Paper + int numSaved = 0; + long now = MinecraftServer.currentTick;