From ec7bd6a7c6ce2e2ed308f054ea4d2c7f7725df8e Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Thu, 25 Jun 2020 16:38:24 -0700 Subject: [PATCH] even even even even more work --- SHIT_TO_CHECK.md | 2 + .../Add-effect-to-block-break-naturally.patch | 2 +- ...to-allow-iron-golems-to-spawn-in-air.patch | 2 +- ...d-option-to-disable-pillager-patrols.patch | 4 +- ...n-to-nerf-pigmen-from-nether-portals.patch | 4 +- Spigot-Server-Patches/Anti-Xray.patch | 60 ++-- .../Asynchronous-chunk-IO-and-loading.patch | 320 ++++++++---------- .../Backport-fix-for-MC-167561.patch | 41 --- ...-more-tolerant-of-invalid-attributes.patch | 29 -- ...get-gravity-in-void.-Fixes-MC-167279.patch | 4 +- ...-chance-of-villager-zombie-infection.patch | 11 +- ...gurable-projectile-relative-velocity.patch | 27 +- ...if-we-have-a-custom-Bukkit-generator.patch | 52 ++- ...low-bees-to-load-chunks-for-beehives.patch | 10 +- ...Chunks-from-Hoppers-and-other-things.patch | 7 +- ...re-Entity-is-never-double-registered.patch | 18 +- .../Entity-Activation-Range-2.0.patch | 89 +++-- Spigot-Server-Patches/Entity-Jump-API.patch | 8 +- ...or-when-player-hand-set-to-empty-typ.patch | 20 +- .../Fix-World-isChunkGenerated-calls.patch | 29 +- ...ator-behavior-for-EntityPhanton-goal.patch | 19 -- ...x-items-vanishing-through-end-portal.patch | 8 +- ...k-in-stack-not-having-effects-when-d.patch | 8 +- .../Fix-spawn-radius-being-treated-as-0.patch | 19 -- ...ering-entities-from-unloading-chunks.patch | 2 +- .../Generator-Settings.patch | 82 +++-- ...rializing-mismatching-chunk-coordina.patch | 8 +- ...lement-alternative-item-despawn-rate.patch | 2 +- .../Lag-compensate-eating.patch | 36 +- .../Make-the-GUI-graph-fancier.patch | 8 +- ...-being-ticked-when-notifying-navigat.patch | 4 +- ...al-Spawned-mobs-towards-natural-spaw.patch | 22 +- ...timise-IEntityAccess-getPlayerByUUID.patch | 10 +- ...imise-TickListServer-by-rewriting-it.patch | 76 ++--- .../Optimise-random-block-ticking.patch | 181 +++------- Spigot-Server-Patches/Optimize-Hoppers.patch | 32 +- ...mize-call-to-getFluid-for-explosions.patch | 4 +- ...spawn-settings-and-per-player-option.patch | 5 +- ...layerDeathEvent-shouldDropExperience.patch | 4 +- .../PlayerLaunchProjectileEvent.patch | 58 ++-- ...-PlayerChunkMap-adds-crashing-server.patch | 8 +- ...oading-chunks-checking-hive-position.patch | 2 +- ...revent-consuming-the-wrong-itemstack.patch | 8 +- ...nk-loads-when-villagers-try-to-find-.patch | 16 +- Spigot-Server-Patches/Reduce-sync-loads.patch | 10 +- .../Seed-based-feature-search.patch | 110 ------ ...PaletteBlock-instead-of-ReentrantLoc.patch | 2 +- ...Status-cache-when-saving-protochunks.patch | 25 -- ...etChunkIfLoadedImmediately-in-places.patch | 37 +- ...ement-optional-per-player-mob-spawns.patch | 304 +++++++++-------- .../incremental-chunk-saving.patch | 319 +++++++++++++++++ scripts/importmcdev.sh | 2 +- 52 files changed, 1064 insertions(+), 1106 deletions(-) delete mode 100644 Spigot-Server-Patches/Backport-fix-for-MC-167561.patch delete mode 100644 Spigot-Server-Patches/Be-more-tolerant-of-invalid-attributes.patch delete mode 100644 Spigot-Server-Patches/Fix-comparator-behavior-for-EntityPhanton-goal.patch delete mode 100644 Spigot-Server-Patches/Fix-spawn-radius-being-treated-as-0.patch delete mode 100644 Spigot-Server-Patches/Seed-based-feature-search.patch delete mode 100644 Spigot-Server-Patches/Use-ChunkStatus-cache-when-saving-protochunks.patch create mode 100644 Spigot-Server-Patches/incremental-chunk-saving.patch diff --git a/SHIT_TO_CHECK.md b/SHIT_TO_CHECK.md index 6077d66cd2..024d8cc9af 100644 --- a/SHIT_TO_CHECK.md +++ b/SHIT_TO_CHECK.md @@ -4,3 +4,5 @@ * Mini: "Optimize World Server Map": Figure out how to fill PaperWorldMap, it needs a dim key which doesnt exist anymore? * Mini: "MC-50319": fix if still works * Mini: I definetly dropped a patch I didnt want to drop, we need to go thru in the end and see if all patches are still in, lol +* Make sure the flat bedrock setting doesn't do anything stupid +* Check DataBits foreach \ No newline at end of file diff --git a/Spigot-Server-Patches/Add-effect-to-block-break-naturally.patch b/Spigot-Server-Patches/Add-effect-to-block-break-naturally.patch index cf767a46d0..7fbb466ce8 100644 --- a/Spigot-Server-Patches/Add-effect-to-block-break-naturally.patch +++ b/Spigot-Server-Patches/Add-effect-to-block-break-naturally.patch @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 net.minecraft.server.Block block = iblockdata.getBlock(); @@ -0,0 +0,0 @@ public class CraftBlock implements Block { // Modelled off EntityHuman#hasBlock - if (block != Blocks.AIR && (item == null || iblockdata.getMaterial().isAlwaysDestroyable() || nmsItem.canDestroySpecialBlock(iblockdata))) { + if (block != Blocks.AIR && (item == null || !iblockdata.isAlwaysDestroyable() || nmsItem.canDestroySpecialBlock(iblockdata))) { net.minecraft.server.Block.dropItems(iblockdata, world.getMinecraftWorld(), position, world.getTileEntity(position), null, nmsItem); + if (triggerEffect) world.triggerEffect(org.bukkit.Effect.STEP_SOUND.getId(), position, net.minecraft.server.Block.getCombinedId(block.getBlockData())); // Paper result = true; diff --git a/Spigot-Server-Patches/Add-option-to-allow-iron-golems-to-spawn-in-air.patch b/Spigot-Server-Patches/Add-option-to-allow-iron-golems-to-spawn-in-air.patch index 053bce4c02..c03f830711 100644 --- a/Spigot-Server-Patches/Add-option-to-allow-iron-golems-to-spawn-in-air.patch +++ b/Spigot-Server-Patches/Add-option-to-allow-iron-golems-to-spawn-in-air.patch @@ -24,7 +24,7 @@ diff --git a/src/main/java/net/minecraft/server/EntityIronGolem.java b/src/main/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/EntityIronGolem.java +++ b/src/main/java/net/minecraft/server/EntityIronGolem.java -@@ -0,0 +0,0 @@ public class EntityIronGolem extends EntityGolem { +@@ -0,0 +0,0 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { BlockPosition blockposition1 = blockposition.down(); IBlockData iblockdata = iworldreader.getType(blockposition1); diff --git a/Spigot-Server-Patches/Add-option-to-disable-pillager-patrols.patch b/Spigot-Server-Patches/Add-option-to-disable-pillager-patrols.patch index f4a942a6aa..221bf805c6 100644 --- a/Spigot-Server-Patches/Add-option-to-disable-pillager-patrols.patch +++ b/Spigot-Server-Patches/Add-option-to-disable-pillager-patrols.patch @@ -22,9 +22,9 @@ diff --git a/src/main/java/net/minecraft/server/MobSpawnerPatrol.java b/src/main index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MobSpawnerPatrol.java +++ b/src/main/java/net/minecraft/server/MobSpawnerPatrol.java -@@ -0,0 +0,0 @@ public class MobSpawnerPatrol { - public MobSpawnerPatrol() {} +@@ -0,0 +0,0 @@ public class MobSpawnerPatrol implements MobSpawner { + @Override public int a(WorldServer worldserver, boolean flag, boolean flag1) { + if (worldserver.paperConfig.disablePillagerPatrols) return 0; // Paper if (!flag) { diff --git a/Spigot-Server-Patches/Add-option-to-nerf-pigmen-from-nether-portals.patch b/Spigot-Server-Patches/Add-option-to-nerf-pigmen-from-nether-portals.patch index e3b65d58fe..f41a39e283 100644 --- a/Spigot-Server-Patches/Add-option-to-nerf-pigmen-from-nether-portals.patch +++ b/Spigot-Server-Patches/Add-option-to-nerf-pigmen-from-nether-portals.patch @@ -23,14 +23,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/BlockPortal.java +++ b/src/main/java/net/minecraft/server/BlockPortal.java @@ -0,0 +0,0 @@ public class BlockPortal extends Block { - Entity entity = EntityTypes.ZOMBIE_PIGMAN.spawnCreature(worldserver, (NBTTagCompound) null, (IChatBaseComponent) null, (EntityHuman) null, blockposition.up(), EnumMobSpawn.STRUCTURE, false, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NETHER_PORTAL); if (entity != null) { + entity.portalCooldown = entity.getDefaultPortalCooldown(); + entity.fromNetherPortal = true; // Paper + if (worldserver.paperConfig.nerfNetherPortalPigmen) ((EntityInsentient) entity).aware = false; // Paper - entity.portalCooldown = entity.ba(); } } + } diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/Entity.java diff --git a/Spigot-Server-Patches/Anti-Xray.patch b/Spigot-Server-Patches/Anti-Xray.patch index 319edc40a0..73bde20765 100644 --- a/Spigot-Server-Patches/Anti-Xray.patch +++ b/Spigot-Server-Patches/Anti-Xray.patch @@ -1039,6 +1039,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ package net.minecraft.server; + import java.util.function.Predicate; +import com.destroystokyo.paper.antixray.ChunkPacketInfo; // Paper - Anti-Xray - Add chunk packet info import javax.annotation.Nullable; @@ -1065,8 +1066,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.nonEmptyBlockCount = short0; this.tickingBlockCount = short1; this.e = short2; -- this.blockIds = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::d, GameProfileSerializer::a, Blocks.AIR.getBlockData()); -+ this.blockIds = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::d, GameProfileSerializer::a, Blocks.AIR.getBlockData(), world == null ? null : world.chunkPacketBlockController.getPredefinedBlockData(world, chunk, this, initializeBlocks), initializeBlocks); // Paper - Anti-Xray - Add predefined block data +- this.blockIds = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData()); ++ this.blockIds = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData(), world == null ? null : world.chunkPacketBlockController.getPredefinedBlockData(world, chunk, this, initializeBlocks), initializeBlocks); // Paper - Anti-Xray - Add predefined block data } public final IBlockData getType(int i, int j, int k) { // Paper @@ -1092,10 +1093,10 @@ diff --git a/src/main/java/net/minecraft/server/DataPaletteBlock.java b/src/main index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/DataPaletteBlock.java +++ b/src/main/java/net/minecraft/server/DataPaletteBlock.java -@@ -0,0 +0,0 @@ package net.minecraft.server; - import it.unimi.dsi.fastutil.ints.Int2IntMap; +@@ -0,0 +0,0 @@ + package net.minecraft.server; + import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; - import it.unimi.dsi.fastutil.ints.Int2IntMap.Entry; +import com.destroystokyo.paper.antixray.ChunkPacketInfo; // Paper - Anti-Xray - Add chunk packet info import java.util.Arrays; import java.util.Objects; @@ -1195,9 +1196,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public synchronized void a(NBTTagList nbttaglist, long[] along) { // Paper - synchronize this.a(); -- int i = Math.max(4, MathHelper.d(nbttaglist.size())); +- int i = Math.max(4, MathHelper.e(nbttaglist.size())); + // Paper - Anti-Xray - TODO: Should this.predefinedObjects.length just be added here (faster) or should the contents be compared to calculate the size (less RAM)? -+ int i = Math.max(4, MathHelper.d(nbttaglist.size() + (this.predefinedObjects == null ? 0 : this.predefinedObjects.length))); // Paper - Anti-Xray - Calculate the size with predefined objects ++ int i = Math.max(4, MathHelper.e(nbttaglist.size() + (this.predefinedObjects == null ? 0 : this.predefinedObjects.length))); // Paper - Anti-Xray - Calculate the size with predefined objects - if (i != this.i) { + if (true || i != this.i) { // Paper - Anti-Xray - Not initialized yet @@ -1221,13 +1222,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -0,0 +0,0 @@ public class PacketPlayOutMapChunk implements Packet { - private byte[] f; private byte[] getData() { return this.f; } // Paper - OBFHELPER - private List g; private boolean h; -+ private volatile boolean ready; // Paper - Async-Anti-Xray - Ready flag for the network manager + private boolean i; - public PacketPlayOutMapChunk() {} + // Paper start - Async-Anti-Xray - Set the ready flag to true ++ private volatile boolean ready; // Paper - Async-Anti-Xray - Ready flag for the network manager + public PacketPlayOutMapChunk() { + this.ready = true; + } @@ -1238,7 +1238,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class PacketPlayOutMapChunk implements Packet { } // Paper end - public PacketPlayOutMapChunk(Chunk chunk, int i) { + public PacketPlayOutMapChunk(Chunk chunk, int i, boolean flag) { + ChunkPacketInfo chunkPacketInfo = chunk.world.chunkPacketBlockController.getChunkPacketInfo(this, chunk, i); // Paper - Anti-Xray - Add chunk packet info ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); @@ -1247,12 +1247,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } this.f = new byte[this.a(chunk, i)]; -- this.c = this.a(new PacketDataSerializer(this.j()), chunk, i); +- this.c = this.a(new PacketDataSerializer(this.k()), chunk, i); + // Paper start - Anti-Xray - Add chunk packet info + if (chunkPacketInfo != null) { + chunkPacketInfo.setData(this.getData()); + } -+ this.c = this.writeChunk(new PacketDataSerializer(this.j()), chunk, i, chunkPacketInfo); ++ this.c = this.writeChunk(new PacketDataSerializer(this.k()), chunk, i, chunkPacketInfo); + // Paper end this.g = Lists.newArrayList(); iterator = chunk.getTileEntities().entrySet().iterator(); @@ -1306,9 +1306,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { - PlayerChunkMap.LOGGER.error("Couldn't load chunk {}", chunkcoordintpair, exception); } + this.g(chunkcoordintpair); - return Either.left(new ProtoChunk(chunkcoordintpair, ChunkConverter.a)); + return Either.left(new ProtoChunk(chunkcoordintpair, ChunkConverter.a, this.world)); // Paper - Anti-Xray - Add parameter }, this.executor); @@ -1403,17 +1403,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public final co.aikar.timings.WorldTimingsHandler timings; // Paper public static BlockPosition lastPhysicsProblem; // Spigot @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, AutoCloseable { - return ((ChunkProviderServer) this.chunkProvider).getChunkAt(x, z, false); + return (CraftServer) Bukkit.getServer(); } -- protected World(WorldData worlddata, DimensionManager dimensionmanager, BiFunction bifunction, GameProfilerFiller gameprofilerfiller, boolean flag, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) { -+ protected World(WorldData worlddata, DimensionManager dimensionmanager, java.util.concurrent.Executor executor, BiFunction bifunction, GameProfilerFiller gameprofilerfiller, boolean flag, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) { // Paper - executor - this.spigotConfig = new org.spigotmc.SpigotWorldConfig( worlddata.getName() ); // Spigot - this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(worlddata.getName(), this.spigotConfig); // Paper +- protected World(WorldDataMutable worlddatamutable, ResourceKey resourcekey, ResourceKey resourcekey1, DimensionManager dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) { ++ protected World(WorldDataMutable worlddatamutable, ResourceKey resourcekey, ResourceKey resourcekey1, DimensionManager dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((WorldDataServer) worlddatamutable).getName()); // Spigot + this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig((((WorldDataServer)worlddatamutable).getName()), this.spigotConfig); // Paper + this.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this.paperConfig, executor) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray this.generator = gen; - if (dimensionmanager.world == null) dimensionmanager.world = (WorldServer) this; // Paper this.world = new CraftWorld((WorldServer) this, gen, env); + this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, AutoCloseable { // CraftBukkit end @@ -1426,15 +1426,15 @@ diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { - - // Add env and gen to constructor - public WorldServer(MinecraftServer minecraftserver, Executor executor, WorldNBTStorage worldnbtstorage, WorldData worlddata, DimensionManager dimensionmanager, GameProfilerFiller gameprofilerfiller, WorldLoadListener worldloadlistener, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { -- super(worlddata, dimensionmanager, (world, worldprovider) -> { -+ super(worlddata, dimensionmanager, executor, (world, worldprovider) -> { // Paper - pass executor down - // CraftBukkit start - ChunkGenerator chunkGenerator; +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { + // Add env and gen to constructor, WorldData -> WorldDataServer + public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey resourcekey, ResourceKey resourcekey1, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { +- super(iworlddataserver, resourcekey, resourcekey1, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env); ++ super(iworlddataserver, resourcekey, resourcekey1, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env, executor); // Paper pass executor + this.pvpMode = minecraftserver.getPVP(); + convertable = convertable_conversionsession; + uuid = WorldUUID.getUUID(convertable_conversionsession.folder.toFile()); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -1452,8 +1452,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 NBTTagCompound data = new NBTTagCompound(); cs[i].getBlocks().a(data, "Palette", "BlockStates"); -- DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, net.minecraft.server.Block.REGISTRY_ID, GameProfileSerializer::d, GameProfileSerializer::a, Blocks.AIR.getBlockData()); // TODO: snapshot whole ChunkSection -+ DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, net.minecraft.server.Block.REGISTRY_ID, GameProfileSerializer::d, GameProfileSerializer::a, Blocks.AIR.getBlockData(), null, false); // TODO: snapshot whole ChunkSection // Paper - Anti-Xray - Add no predefined block data and don't initialize because it's done in the line below internally +- DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, net.minecraft.server.Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData()); // TODO: snapshot whole ChunkSection ++ DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, net.minecraft.server.Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData(), null, false); // TODO: snapshot whole ChunkSection // Paper - Anti-Xray - Add no predefined block data and don't initialize because it's done in the line below internally blockids.a(data.getList("Palette", CraftMagicNumbers.NBT.TAG_COMPOUND), data.getLongArray("BlockStates")); sectionBlockIDs[i] = blockids; diff --git a/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch b/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch index da0da43621..a1099c9e45 100644 --- a/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch +++ b/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch @@ -2534,7 +2534,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static InProgressChunkHolder loadChunk(WorldServer worldserver, DefinedStructureManager definedstructuremanager, VillagePlace villageplace, ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound, boolean distinguish) { + ArrayDeque tasksToExecuteOnMain = new ArrayDeque<>(); + // Paper end - ChunkGenerator chunkgenerator = worldserver.getChunkProvider().getChunkGenerator(); + ChunkGenerator chunkgenerator = worldserver.getChunkProvider().getChunkGenerator(); WorldChunkManager worldchunkmanager = chunkgenerator.getWorldChunkManager(); NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("Level"); @@ -0,0 +0,0 @@ public class ChunkRegionLoader { @@ -2560,25 +2560,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (flag) { if (nbttagcompound2.hasKeyOfType("BlockLight", 7)) { -- lightengine.a(EnumSkyBlock.BLOCK, SectionPosition.a(chunkcoordintpair, b0), new NibbleArray(nbttagcompound2.getByteArray("BlockLight"))); +- lightengine.a(EnumSkyBlock.BLOCK, SectionPosition.a(chunkcoordintpair, b0), new NibbleArray(nbttagcompound2.getByteArray("BlockLight")), true); + // Paper start - delay this task since we're executing off-main + NibbleArray blockLight = new NibbleArray(nbttagcompound2.getByteArray("BlockLight")); -+ // Note: We move the block light nibble array creation here for perf & in case the compound is modified + tasksToExecuteOnMain.add(() -> { -+ lightengine.a(EnumSkyBlock.BLOCK, SectionPosition.a(chunkcoordintpair, b0), blockLight); ++ lightengine.a(EnumSkyBlock.BLOCK, SectionPosition.a(chunkcoordintpair, b0), blockLight, true); + }); -+ // Paper end ++ // Paper end - delay this task since we're executing off-main } if (flag2 && nbttagcompound2.hasKeyOfType("SkyLight", 7)) { -- lightengine.a(EnumSkyBlock.SKY, SectionPosition.a(chunkcoordintpair, b0), new NibbleArray(nbttagcompound2.getByteArray("SkyLight"))); +- lightengine.a(EnumSkyBlock.SKY, SectionPosition.a(chunkcoordintpair, b0), new NibbleArray(nbttagcompound2.getByteArray("SkyLight")), true); + // Paper start - delay this task since we're executing off-main + NibbleArray skyLight = new NibbleArray(nbttagcompound2.getByteArray("SkyLight")); -+ // Note: We move the block light nibble array creation here for perf & in case the compound is modified + tasksToExecuteOnMain.add(() -> { -+ lightengine.a(EnumSkyBlock.SKY, SectionPosition.a(chunkcoordintpair, b0), skyLight); ++ lightengine.a(EnumSkyBlock.SKY, SectionPosition.a(chunkcoordintpair, b0), skyLight, true); + }); -+ // Paper end ++ // Paper end - delay this task since we're executing off-main } } } @@ -2597,9 +2595,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return protochunk1; + return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading - } - } - ++ } ++ } ++ + // Paper start - async chunk save for unload + public static final class AsyncSaveData { + public final NibbleArray[] blockLight; // null or size of 17 (for indices -1 through 15) @@ -2617,9 +2615,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.blockTickList = blockTickList; + this.fluidTickList = fluidTickList; + this.worldTime = worldTime; -+ } -+ } -+ + } + } + + // must be called sync + public static AsyncSaveData getAsyncSaveData(WorldServer world, IChunkAccess chunk) { + org.spigotmc.AsyncCatcher.catchOp("preparation of chunk data for async save"); @@ -2731,8 +2729,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (ticklist instanceof ProtoChunkTickList) { nbttagcompound1.set("ToBeTicked", ((ProtoChunkTickList) ticklist).b()); } else if (ticklist instanceof TickListChunk) { -- nbttagcompound1.set("TileTicks", ((TickListChunk) ticklist).a(worldserver.getTime())); -+ nbttagcompound1.set("TileTicks", ((TickListChunk) ticklist).a(asyncsavedata != null ? asyncsavedata.worldTime : worldserver.getTime())); // Paper - async chunk unloading + nbttagcompound1.set("TileTicks", ((TickListChunk) ticklist).b()); + // Paper start - async chunk save for unload + } else if (asyncsavedata != null) { + nbttagcompound1.set("TileTicks", asyncsavedata.blockTickList); @@ -2748,15 +2745,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (ticklist1 instanceof ProtoChunkTickList) { nbttagcompound1.set("LiquidsToBeTicked", ((ProtoChunkTickList) ticklist1).b()); } else if (ticklist1 instanceof TickListChunk) { -- nbttagcompound1.set("LiquidTicks", ((TickListChunk) ticklist1).a(worldserver.getTime())); -+ nbttagcompound1.set("LiquidTicks", ((TickListChunk) ticklist1).a(asyncsavedata != null ? asyncsavedata.worldTime : worldserver.getTime())); // Paper - async chunk unloading + nbttagcompound1.set("LiquidTicks", ((TickListChunk) ticklist1).b()); + // Paper start - async chunk save for unload + } else if (asyncsavedata != null) { + nbttagcompound1.set("LiquidTicks", asyncsavedata.fluidTickList); + // Paper end } else { - nbttagcompound1.set("LiquidTicks", worldserver.getFluidTickList().a(chunkcoordintpair)); -+ nbttagcompound1.set("LiquidTicks", worldserver.getFluidTickList().a(chunkcoordintpair)); // Paper - diff on method change (see getAsyncSaveData) ++ nbttagcompound1.set("LiquidTicks", worldserver.getFluidTickList().a(chunkcoordintpair)); // Paper - diff on method change (see getAsyncSaveData) } nbttagcompound1.set("PostProcessing", a(ichunkaccess.l())); @@ -2824,23 +2820,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import java.util.function.Supplier; import javax.annotation.Nullable; --public class IChunkLoader implements AutoCloseable { -+public class IChunkLoader extends RegionFileCache implements AutoCloseable { + public class IChunkLoader implements AutoCloseable { - private final IOWorker a; public IOWorker getIOWorker() { return a; } // Paper - OBFHELPER -+// private final IOWorker a; public IOWorker getIOWorker() { return a; } // Paper - OBFHELPER - nuke IOWorker ++ // Paper - OBFHELPER - nuke IOWorker protected final DataFixer b; @Nullable - private PersistentStructureLegacy c; + private volatile PersistentStructureLegacy c; // Paper - async chunk loading + + private final Object persistentDataLock = new Object(); // Paper ++ protected final RegionFileCache regionFileCache; - public IChunkLoader(File file, DataFixer datafixer) { -+ super(file); + public IChunkLoader(File file, DataFixer datafixer, boolean flag) { ++ this.regionFileCache = new RegionFileCache(file, flag); // Paper - nuke IOWorker this.b = datafixer; -- this.a = new IOWorker(new RegionFileCache(file), "chunk"); -+// this.a = new IOWorker(new RegionFileCache(file), "chunk"); // Paper - nuke IOWorker +- this.a = new IOWorker(file, flag, "chunk"); ++ // Paper - nuke IOWorker } // CraftBukkit start @@ -2881,7 +2877,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) { + synchronized (this.persistentDataLock) { // Paper - Async chunk loading if (this.c == null) { - this.c = PersistentStructureLegacy.a(dimensionmanager.getType(), (WorldPersistentData) supplier.get()); // CraftBukkit - getType + this.c = PersistentStructureLegacy.a(resourcekey, (WorldPersistentData) supplier.get()); } nbttagcompound = this.c.a(nbttagcompound); @@ -2890,49 +2886,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } @@ -0,0 +0,0 @@ public class IChunkLoader implements AutoCloseable { - return nbttagcompound.hasKeyOfType("DataVersion", 99) ? nbttagcompound.getInt("DataVersion") : -1; + + @Nullable + public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException { +- return this.a.a(chunkcoordintpair); ++ return this.regionFileCache.read(chunkcoordintpair); } -- @Nullable -- public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException { -- return this.a.a(chunkcoordintpair); -- } -- - public void a(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) { - this.a.a(chunkcoordintpair, nbttagcompound); -+// Paper start - nuke IOWorker -+// @Nullable -+// public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException { -+// return this.a.a(chunkcoordintpair); -+// } -+// + public void a(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException { write(chunkcoordintpair, nbttagcompound); } // Paper OBFHELPER + public void write(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException { // Paper - OBFHELPER - (Switched around for safety) -+ super.write(chunkcoordintpair, nbttagcompound); ++ this.regionFileCache.write(chunkcoordintpair, nbttagcompound); if (this.c != null) { -- this.c.a(chunkcoordintpair.pair()); + synchronized (this.persistentDataLock) { // Paper - Async chunk loading -+ this.c.a(chunkcoordintpair.pair()); } // Paper - Async chunk loading} + this.c.a(chunkcoordintpair.pair()); ++ } // Paper - Async chunk loading} } - - } +- +- } - - public void i() { - this.a.a().join(); -- } -- -- public void close() throws IOException { + } + + public void close() throws IOException { - this.a.close(); -- } -+// -+// public void i() { -+// this.a.a().join(); -+// } -+// -+// public void close() throws IOException { -+// this.a.close(); -+// } -+// Paper end ++ this.regionFileCache.close(); + } } diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -2948,6 +2929,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return 33 + ChunkStatus.getTicketLevelOffset(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 ++++ b/src/main/java/net/minecraft/server/Main.java +@@ -0,0 +0,0 @@ public class Main { + + convertable_conversionsession.a((IRegistryCustom) iregistrycustom_dimension, (SaveData) object); + */ ++ Class.forName("net.minecraft.server.VillagerTrades");// Paper - load this sync so it won't fail later async + final DedicatedServer dedicatedserver = (DedicatedServer) MinecraftServer.a((thread) -> { + DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, datapackconfiguration1, thread, iregistrycustom_dimension, convertable_conversionsession, resourcepackrepository, datapackresources, null, dedicatedserversettings, DataConverterRegistry.a(), minecraftsessionservice, gameprofilerepository, usercache, WorldLoadListenerLogger::new); + 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 @@ -2956,18 +2949,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.getUserCache().c(false); // Paper } // Spigot end +- + com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true, true); // Paper } public String getServerIp() { -@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant executor; - public final ChunkGenerator chunkGenerator; + public final ChunkGenerator chunkGenerator; - private final Supplier l; + private final Supplier l; public final Supplier getWorldPersistentDataSupplier() { return this.l; } // Paper - OBFHELPER private final VillagePlace m; @@ -3083,11 +3069,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final PlayerMap playerMap; public final Int2ObjectMap trackedEntities; @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { - this.lightEngine = new LightEngineThreaded(ilightaccess, this, this.world.getWorldProvider().f(), threadedmailbox1, this.p.a(threadedmailbox1, false)); + this.lightEngine = new LightEngineThreaded(ilightaccess, this, this.world.getDimensionManager().hasSkyLight(), threadedmailbox1, this.p.a(threadedmailbox1, false)); this.chunkDistanceManager = new PlayerChunkMap.a(executor, iasynctaskhandler); this.l = supplier; -- this.m = new VillagePlace(new File(this.w, "poi"), datafixer); -+ this.m = new VillagePlace(new File(this.w, "poi"), datafixer, this.world); // Paper +- this.m = new VillagePlace(new File(this.w, "poi"), datafixer, flag); ++ this.m = new VillagePlace(new File(this.w, "poi"), datafixer, flag, this.world); // Paper this.setViewDistance(i); } @@ -3240,15 +3226,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.lightEngine.queueUpdate(); this.worldLoadListener.a(ichunkaccess.getPos(), (ChunkStatus) null); @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { - } } -+ // Paper start - Async chunk io -+ public NBTTagCompound completeChunkData(NBTTagCompound compound, ChunkCoordIntPair chunkcoordintpair) throws IOException { -+ return compound == null ? null : this.getChunkData(this.world.getWorldProvider().getDimensionManager(), this.getWorldPersistentDataSupplier(), compound, chunkcoordintpair, this.world); -+ } -+ // Paper end -+ private CompletableFuture> f(ChunkCoordIntPair chunkcoordintpair) { - return CompletableFuture.supplyAsync(() -> { + // Paper start - Async chunk io @@ -3259,38 +3238,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - try (Timing ignored2 = this.world.timings.chunkIO.startTimingIfSync()) { // Paper start - timings - nbttagcompound = this.readChunkData(chunkcoordintpair); - } // Paper end -- ++ // Paper start ++ if (ioThrowable != null) { ++ com.destroystokyo.paper.util.SneakyThrow.sneaky(ioThrowable); ++ } ++ // Paper end + - if (nbttagcompound != null) {try (Timing ignored2 = this.world.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings - boolean flag = nbttagcompound.hasKeyOfType("Level", 10) && nbttagcompound.getCompound("Level").hasKeyOfType("Status", 8); -+ if (ioThrowable != null) { -+ com.destroystokyo.paper.io.IOUtil.rethrow(ioThrowable); -+ } ++ if (chunkHolder.protoChunk != null) {try (Timing ignored2 = this.world.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings // Paper - chunk is created async - if (flag) { - ProtoChunk protochunk = ChunkRegionLoader.loadChunk(this.world, this.definedStructureManager, this.m, chunkcoordintpair, nbttagcompound); -+ this.getVillagePlace().loadInData(chunkcoordintpair, chunkHolder.poiData); -+ chunkHolder.tasks.forEach(Runnable::run); -+ // Paper - async load completes this -+ // Paper end - -- protochunk.setLastSaved(this.world.getTime()); -- return Either.left(protochunk); -- } -- -- PlayerChunkMap.LOGGER.error("Chunk file at {} is missing level data, skipping", chunkcoordintpair); -- }} // Paper -+ // Paper start - This is done async -+ if (chunkHolder.protoChunk != null) { -+ chunkHolder.protoChunk.setLastSaved(this.world.getTime()); -+ return Either.left(chunkHolder.protoChunk); -+ } -+ // Paper end - } catch (ReportedException reportedexception) { - Throwable throwable = reportedexception.getCause(); ++ if (true) { ++ ProtoChunk protochunk = chunkHolder.protoChunk; + protochunk.setLastSaved(this.world.getTime()); + this.a(chunkcoordintpair, protochunk.getChunkStatus().getType()); @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { - } + this.g(chunkcoordintpair); return Either.left(new ProtoChunk(chunkcoordintpair, ChunkConverter.a, this.world)); // Paper - Anti-Xray - Add parameter - }, this.executor); + // Paper start - Async chunk io @@ -3321,7 +3288,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end } - private CompletableFuture> b(PlayerChunk playerchunk, ChunkStatus chunkstatus) { + private void g(ChunkCoordIntPair chunkcoordintpair) { @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } @@ -3330,43 +3297,37 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.m.a(ichunkaccess.getPos()); if (!ichunkaccess.isNeedsSaving()) { return false; - } else { -- try { -- this.world.checkSession(); -- } catch (ExceptionWorldConflict exceptionworldconflict) { -- PlayerChunkMap.LOGGER.error("Couldn't save chunk; already in use by another instance of Minecraft?", exceptionworldconflict); -- com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exceptionworldconflict); // Paper -- return false; -- } -+ // Paper - The save session check is performed on the IO thread - - ichunkaccess.setLastSaved(this.world.getTime()); - ichunkaccess.setNeedsSaving(false); @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { - NBTTagCompound nbttagcompound; + ChunkStatus chunkstatus = ichunkaccess.getChunkStatus(); if (chunkstatus.getType() != ChunkStatus.Type.LEVELCHUNK) { + try (co.aikar.timings.Timing ignored1 = this.world.timings.chunkSaveOverwriteCheck.startTiming()) { // Paper - // Paper start - Optimize save by using status cache - ChunkStatus statusOnDisk = this.getChunkStatusOnDisk(chunkcoordintpair); - if (statusOnDisk != null && statusOnDisk.getType() == ChunkStatus.Type.LEVELCHUNK) { -@@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + if (this.h(chunkcoordintpair)) { + return false; } +@@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + if (chunkstatus == ChunkStatus.EMPTY && ichunkaccess.h().values().stream().noneMatch(StructureStart::e)) { + return false; + } ++ } // Paper } -+ } // Paper this.world.getMethodProfiler().c("chunkSave"); +- NBTTagCompound nbttagcompound = ChunkRegionLoader.saveChunk(this.world, ichunkaccess); ++ NBTTagCompound nbttagcompound; + try (co.aikar.timings.Timing ignored1 = this.world.timings.chunkSaveDataSerialization.startTiming()) { // Paper - nbttagcompound = ChunkRegionLoader.saveChunk(this.world, ichunkaccess); -- this.a(chunkcoordintpair, nbttagcompound); ++ nbttagcompound = ChunkRegionLoader.saveChunk(this.world, ichunkaccess); + } // Paper ++ + +- this.a(chunkcoordintpair, nbttagcompound); + // Paper start - async chunk io + com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(this.world, chunkcoordintpair.x, chunkcoordintpair.z, + null, nbttagcompound, com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); + // Paper end - async chunk io + this.a(chunkcoordintpair, chunkstatus.getType()); return true; } catch (Exception exception) { - PlayerChunkMap.LOGGER.error("Failed to save chunk {},{}", chunkcoordintpair.x, chunkcoordintpair.z, exception); @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { return false; } @@ -3374,7 +3335,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } // Paper } - protected void setViewDistance(int i) { + private boolean h(ChunkCoordIntPair chunkcoordintpair) { @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } } @@ -3417,14 +3378,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public ChunkStatus getChunkStatusOnDiskIfCached(ChunkCoordIntPair chunkPos) { - RegionFile regionFile = this.getIOWorker().getRegionFileCache().getRegionFileIfLoaded(chunkPos); + synchronized (this) { // Paper -+ RegionFile regionFile = this.getRegionFileIfLoaded(chunkPos); ++ RegionFile regionFile = this.regionFileCache.getRegionFileIfLoaded(chunkPos); return regionFile == null ? null : regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); + } // Paper } public ChunkStatus getChunkStatusOnDisk(ChunkCoordIntPair chunkPos) throws IOException { -- RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, false); +- RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, true); + // Paper start - async chunk save for unload + IChunkAccess unloadingChunk = this.world.asyncChunkTaskManager.getChunkInSaveProgress(chunkPos.x, chunkPos.z); + if (unloadingChunk != null) { @@ -3435,20 +3396,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + NBTTagCompound inProgressWrite = com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE + .getPendingWrite(this.world, chunkPos.x, chunkPos.z, false); -- if (!regionFile.chunkExists(chunkPos)) { +- if (regionFile == null || !regionFile.chunkExists(chunkPos)) { - return null; + if (inProgressWrite != null) { + return ChunkRegionLoader.getStatus(inProgressWrite); } + // Paper end + synchronized (this) { // Paper - async io -+ RegionFile regionFile = this.getFile(chunkPos, false); -+ -+ if (!regionFile.chunkExists(chunkPos)) { -+ return null; -+ } ++ RegionFile regionFile = this.regionFileCache.getFile(chunkPos, true); - ChunkStatus status = regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); ++ if (regionFile == null || !regionFile.chunkExists(chunkPos)) { ++ return null; ++ } ++ + ChunkStatus status = regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); - if (status != null) { @@ -3470,7 +3431,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void updateChunkStatusOnDisk(ChunkCoordIntPair chunkPos, @Nullable NBTTagCompound compound) throws IOException { - RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, false); + synchronized (this) { -+ RegionFile regionFile = this.getFile(chunkPos, false); ++ RegionFile regionFile = this.regionFileCache.getFile(chunkPos, false); - regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkRegionLoader.getStatus(compound)); + regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkRegionLoader.getStatus(compound)); @@ -3506,7 +3467,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + synchronized (world.getChunkProvider().playerChunkMap) { + net.minecraft.server.RegionFile file; + try { -+ file = world.getChunkProvider().playerChunkMap.getFile(chunkPos, false); ++ file = world.getChunkProvider().playerChunkMap.regionFileCache.getFile(chunkPos, false); + } catch (IOException ex) { + throw new RuntimeException(ex); + } @@ -3577,9 +3538,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end this.closed = true; // Paper try { - this.c(); + this.d(); @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - } + this.dataFile.close(); } } + } finally { // Paper start - Prevent regionfiles from being closed during use @@ -3633,7 +3594,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { if (this.cache.size() >= com.destroystokyo.paper.PaperConfig.regionFileCacheSize) { // Paper - configurable @@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable { - RegionFile regionfile1 = new RegionFile(file, this.b); + RegionFile regionfile1 = new RegionFile(file, this.b, this.c); this.cache.putAndMoveToFirst(i, regionfile1); + // Paper start @@ -3686,9 +3647,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - public void close() throws IOException { + public synchronized void close() throws IOException { // Paper -> synchronized + ExceptionSuppressor exceptionsuppressor = new ExceptionSuppressor<>(); ObjectIterator objectiterator = this.cache.values().iterator(); - while (objectiterator.hasNext()) { @@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable { } @@ -3710,39 +3671,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; --public class RegionFileSection implements AutoCloseable { -+public class RegionFileSection extends RegionFileCache implements AutoCloseable { // Paper - nuke IOWorker +-public class RegionFileSection implements AutoCloseable { ++public class RegionFileSection extends RegionFileCache implements AutoCloseable { // Paper - nuke IOWorker private static final Logger LOGGER = LogManager.getLogger(); - private final IOWorker b; -+// private final IOWorker b; ++ // Paper - nuke IOWorker private final Long2ObjectMap> c = new Long2ObjectOpenHashMap(); - private final LongLinkedOpenHashSet d = new LongLinkedOpenHashSet(); + protected final LongLinkedOpenHashSet d = new LongLinkedOpenHashSet(); // Paper - private -> protected - private final BiFunction, R> e; + private final Function> e; private final Function f; private final DataFixer g; private final DataFixTypes h; - public RegionFileSection(File file, BiFunction, R> bifunction, Function function, DataFixer datafixer, DataFixTypes datafixtypes) { -+ super(file); // Paper - nuke IOWorker - this.e = bifunction; - this.f = function; + public RegionFileSection(File file, Function> function, Function function1, DataFixer datafixer, DataFixTypes datafixtypes, boolean flag) { ++ super(file, flag); // Paper - nuke IOWorker + this.e = function; + this.f = function1; this.g = datafixer; this.h = datafixtypes; -- this.b = new IOWorker(new RegionFileCache(file), file.getName()); -+// this.b = new IOWorker(new RegionFileCache(file), file.getName()); // Paper - nuke IOWorker +- this.b = new IOWorker(file, flag, file.getName()); ++ //this.b = new IOWorker(file, flag, file.getName()); // Paper - nuke IOWorker } protected void a(BooleanSupplier booleansupplier) { -- while (!this.d.isEmpty() && booleansupplier.getAsBoolean()) { -- ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(this.d.firstLong()).u(); -+ while (!this.d.isEmpty() && booleansupplier.getAsBoolean()) { // Paper - conflict here to avoid obfhelpers -+ ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(this.d.firstLong()).u(); // Paper - conflict here to avoid obfhelpers + while (!this.d.isEmpty() && booleansupplier.getAsBoolean()) { +- ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(this.d.firstLong()).r(); ++ ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(this.d.firstLong()).r(); // Paper - conflict here to avoid obfhelpers this.d(chunkcoordintpair); } -@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC +@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoCloseable { } private void b(ChunkCoordIntPair chunkcoordintpair) { @@ -3763,7 +3723,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } catch (IOException ioexception) { RegionFileSection.LOGGER.error("Error reading chunk {} data from disk", chunkcoordintpair, ioexception); return null; -@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC +@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoCloseable { } private void d(ChunkCoordIntPair chunkcoordintpair) { @@ -3797,19 +3757,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private Dynamic a(ChunkCoordIntPair chunkcoordintpair, DynamicOps dynamicops) { Map map = Maps.newHashMap(); -@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC +@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoCloseable { public void a(ChunkCoordIntPair chunkcoordintpair) { if (!this.d.isEmpty()) { for (int i = 0; i < 16; ++i) { -- long j = SectionPosition.a(chunkcoordintpair, i).v(); -+ long j = SectionPosition.a(chunkcoordintpair, i).v(); // Paper - conflict here to avoid obfhelpers +- long j = SectionPosition.a(chunkcoordintpair, i).s(); ++ long j = SectionPosition.a(chunkcoordintpair, i).s(); // Paper - conflict here to avoid obfhelpers - if (this.d.contains(j)) { + if (this.d.contains(j)) { // Paper - conflict here to avoid obfhelpers this.d(chunkcoordintpair); return; } -@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoC +@@ -0,0 +0,0 @@ public class RegionFileSection implements AutoCloseable { } @@ -3827,7 +3787,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // This is checking if the data exists, then it builds it later in getDataInternal(ChunkCoordIntPair) + if (!this.d.isEmpty()) { + for (int i = 0; i < 16; ++i) { -+ long j = SectionPosition.a(chunkcoordintpair, i).v(); ++ long j = SectionPosition.a(chunkcoordintpair, i).s(); + + if (this.d.contains(j)) { + return this.getDataInternal(chunkcoordintpair); @@ -3860,14 +3820,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private final WorldServer world; // Paper + - public VillagePlace(File file, DataFixer datafixer) { -+ // Paper start -+ this(file, datafixer, null); + public VillagePlace(File file, DataFixer datafixer, boolean flag) { ++ // Paper start - add world parameter ++ this(file, datafixer, flag, null); + } -+ public VillagePlace(File file, DataFixer datafixer, WorldServer world) { -+ // Paper end - super(file, VillagePlaceSection::new, VillagePlaceSection::new, datafixer, DataFixTypes.POI_CHUNK); -+ this.world = world; // Paper ++ public VillagePlace(File file, DataFixer datafixer, boolean flag, WorldServer world) { + super(file, VillagePlaceSection::a, VillagePlaceSection::new, datafixer, DataFixTypes.POI_CHUNK, flag); ++ this.world = world; ++ // Paper end - add world parameter } public void a(BlockPosition blockposition, VillagePlaceType villageplacetype) { @@ -3882,7 +3842,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } else { + //super.a(booleansupplier); // re-implement below + while (!((RegionFileSection)this).d.isEmpty() && booleansupplier.getAsBoolean()) { -+ ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(((RegionFileSection)this).d.firstLong()).u(); ++ ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(((RegionFileSection)this).d.firstLong()).r(); + + NBTTagCompound data; + try (co.aikar.timings.Timing ignored1 = this.world.timings.poiSaveDataSerialization.startTiming()) { @@ -3936,8 +3896,8 @@ diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { - return new Throwable(entity + " Added to world at " + new java.util.Date()); +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { + return this.chunkProvider.getChunkAt(x, z, false); } + // Paper start - Asynchronous IO @@ -3993,7 +3953,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + RegionFile file; + + try { -+ file = WorldServer.this.getChunkProvider().playerChunkMap.getFile(new ChunkCoordIntPair(chunkX, chunkZ), false); ++ file = WorldServer.this.getChunkProvider().playerChunkMap.regionFileCache.getFile(new ChunkCoordIntPair(chunkX, chunkZ), false); + } catch (java.io.IOException ex) { + throw new RuntimeException(ex); + } @@ -4005,7 +3965,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @Override + public T computeForRegionFileIfLoaded(int chunkX, int chunkZ, java.util.function.Function function) { + synchronized (WorldServer.this.getChunkProvider().playerChunkMap) { -+ RegionFile file = WorldServer.this.getChunkProvider().playerChunkMap.getRegionFileIfLoaded(new ChunkCoordIntPair(chunkX, chunkZ)); ++ RegionFile file = WorldServer.this.getChunkProvider().playerChunkMap.regionFileCache.getRegionFileIfLoaded(new ChunkCoordIntPair(chunkX, chunkZ)); + return function.apply(file); + } + } @@ -4013,19 +3973,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public final com.destroystokyo.paper.io.chunk.ChunkTaskManager asyncChunkTaskManager; + // Paper end + - // Add env and gen to constructor - public WorldServer(MinecraftServer minecraftserver, Executor executor, WorldNBTStorage worldnbtstorage, WorldData worlddata, DimensionManager dimensionmanager, GameProfilerFiller gameprofilerfiller, WorldLoadListener worldloadlistener, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { - super(worlddata, dimensionmanager, executor, (world, worldprovider) -> { // Paper - pass executor down -@@ -0,0 +0,0 @@ public class WorldServer extends World { - - this.mobSpawnerTrader = this.worldProvider.getDimensionManager().getType() == DimensionManager.OVERWORLD ? new MobSpawnerTrader(this) : null; // CraftBukkit - getType() + // Add env and gen to constructor, WorldData -> WorldDataServer + public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey resourcekey, ResourceKey resourcekey1, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { + super(iworlddataserver, resourcekey, resourcekey1, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env, executor); // Paper pass executor +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { + this.dragonBattle = null; + } this.getServer().addWorld(this.getWorld()); // CraftBukkit + + this.asyncChunkTaskManager = new com.destroystokyo.paper.io.chunk.ChunkTaskManager(this); // Paper } // CraftBukkit start -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { } MCUtil.getSpiralOutChunks(spawn, radiusInBlocks >> 4).forEach(pair -> { @@ -4082,8 +4042,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // fall through to load // we do this so we do not re-read the chunk data on disk @@ -0,0 +0,0 @@ public class CraftWorld implements World { - - return new CraftDragonBattle(worldProvider.o()); // PAIL rename getDragonBattle + public DragonBattle getEnderDragonBattle() { + return (getHandle().getDragonBattle() == null) ? null : new CraftDragonBattle(getHandle().getDragonBattle()); } + // Paper start + @Override diff --git a/Spigot-Server-Patches/Backport-fix-for-MC-167561.patch b/Spigot-Server-Patches/Backport-fix-for-MC-167561.patch deleted file mode 100644 index ead80ed47a..0000000000 --- a/Spigot-Server-Patches/Backport-fix-for-MC-167561.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Fri, 21 Feb 2020 18:44:28 +0000 -Subject: [PATCH] Backport fix for MC-167561 - - -diff --git a/src/main/java/net/minecraft/server/EntityWolf.java b/src/main/java/net/minecraft/server/EntityWolf.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/EntityWolf.java -+++ b/src/main/java/net/minecraft/server/EntityWolf.java -@@ -0,0 +0,0 @@ public class EntityWolf extends EntityTameableAnimal { - boolean flag = super.a(entityhuman, enumhand); - - if (!flag || this.isBaby()) { -- this.goalSit.setSitting(!this.isSitting()); -+ //this.goalSit.setSitting(!this.isSitting()); // Paper start - copied from below -+ if (this.i((EntityLiving) entityhuman) && !this.i(itemstack)) { -+ this.goalSit.setSitting(!this.isSitting()); -+ this.jumping = false; -+ this.navigation.o(); -+ this.setGoalTarget((EntityLiving) null, TargetReason.FORGOT_TARGET, true); // CraftBukkit - reason -+ } -+ // Paper end - copied from below - } - - return flag; -@@ -0,0 +0,0 @@ public class EntityWolf extends EntityTameableAnimal { - return true; - } - -+ /* Paper start - Move into above - if (this.i((EntityLiving) entityhuman) && !this.i(itemstack)) { - this.goalSit.setSitting(!this.isSitting()); - this.jumping = false; - this.navigation.o(); - this.setGoalTarget((EntityLiving) null, TargetReason.FORGOT_TARGET, true); // CraftBukkit - reason - } -+ */ // Paper end - } else if (item == Items.BONE && !this.isAngry()) { - if (!entityhuman.abilities.canInstantlyBuild) { - itemstack.subtract(1); diff --git a/Spigot-Server-Patches/Be-more-tolerant-of-invalid-attributes.patch b/Spigot-Server-Patches/Be-more-tolerant-of-invalid-attributes.patch deleted file mode 100644 index abd4ca0d76..0000000000 --- a/Spigot-Server-Patches/Be-more-tolerant-of-invalid-attributes.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown <1254957+zachbr@users.noreply.github.com> -Date: Thu, 6 Feb 2020 19:20:27 -0600 -Subject: [PATCH] Be more tolerant of invalid attributes - -Prior to this commit, the player would be disconnected if they ever encountered an attribute with a name that did -not match Bukkit's expected vanilla scheme. It appears that datapacks can set whatever attribute name they want, -ignoring vanilla's typical scheme. - -In a more perfect world the API would expose some way to interact with these attributes, however Bukkit is not -particularly flexible in this area. Perhaps this is an area for future expansion at a later time. - -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -@@ -0,0 +0,0 @@ public class CraftAttributeMap implements Attributable { - public static Attribute fromMinecraft(String nms) { - String[] split = nms.split("\\.", 2); - -+ // Paper start - Datapacks can set their own attributes that may not match our expectations, ignore them -+ if (split.length != 2) { -+ return null; -+ } -+ // Paper end -+ - String generic = split[0]; - String descriptor = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, split[1]); // movementSpeed -> MOVEMENT_SPEED - String fin = generic + "_" + descriptor; diff --git a/Spigot-Server-Patches/Bees-get-gravity-in-void.-Fixes-MC-167279.patch b/Spigot-Server-Patches/Bees-get-gravity-in-void.-Fixes-MC-167279.patch index 20495b198f..8044f1f126 100644 --- a/Spigot-Server-Patches/Bees-get-gravity-in-void.-Fixes-MC-167279.patch +++ b/Spigot-Server-Patches/Bees-get-gravity-in-void.-Fixes-MC-167279.patch @@ -34,7 +34,7 @@ diff --git a/src/main/java/net/minecraft/server/EntityBee.java b/src/main/java/n index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/EntityBee.java +++ b/src/main/java/net/minecraft/server/EntityBee.java -@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements EntityBird { +@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB public EntityBee(EntityTypes entitytypes, World world) { super(entitytypes, world); @@ -51,5 +51,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + }; + // Paper end this.lookController = new EntityBee.j(this); + this.a(PathType.DANGER_FIRE, -1.0F); this.a(PathType.WATER, -1.0F); - this.a(PathType.COCOA, -1.0F); diff --git a/Spigot-Server-Patches/Configurable-chance-of-villager-zombie-infection.patch b/Spigot-Server-Patches/Configurable-chance-of-villager-zombie-infection.patch index 582937fb04..c816903f2b 100644 --- a/Spigot-Server-Patches/Configurable-chance-of-villager-zombie-infection.patch +++ b/Spigot-Server-Patches/Configurable-chance-of-villager-zombie-infection.patch @@ -27,18 +27,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/EntityZombie.java @@ -0,0 +0,0 @@ public class EntityZombie extends EntityMonster { @Override - public void b(EntityLiving entityliving) { - super.b(entityliving); + public void a_(EntityLiving entityliving) { + super.a_(entityliving); - if ((this.world.getDifficulty() == EnumDifficulty.NORMAL || this.world.getDifficulty() == EnumDifficulty.HARD) && entityliving instanceof EntityVillager) { - if (this.world.getDifficulty() != EnumDifficulty.HARD && this.random.nextBoolean()) { + // Paper start + if (world.paperConfig.zombieVillagerInfectionChance != 0.0 && (world.paperConfig.zombieVillagerInfectionChance != -1.0 || this.world.getDifficulty() == EnumDifficulty.NORMAL || this.world.getDifficulty() == EnumDifficulty.HARD) && entityliving instanceof EntityVillager) { + if (world.paperConfig.zombieVillagerInfectionChance == -1.0 && this.world.getDifficulty() != EnumDifficulty.HARD && this.random.nextBoolean()) { -+ return; -+ } -+ if (world.paperConfig.zombieVillagerInfectionChance != -1.0 && (this.random.nextDouble() * 100.0) > world.paperConfig.zombieVillagerInfectionChance) { return; -- } + } ++ if (world.paperConfig.zombieVillagerInfectionChance != -1.0 && (this.random.nextDouble() * 100.0) > world.paperConfig.zombieVillagerInfectionChance) { ++ return; + } // Paper end EntityVillager entityvillager = (EntityVillager) entityliving; diff --git a/Spigot-Server-Patches/Configurable-projectile-relative-velocity.patch b/Spigot-Server-Patches/Configurable-projectile-relative-velocity.patch index 6b7741d337..fdef2c3315 100644 --- a/Spigot-Server-Patches/Configurable-projectile-relative-velocity.patch +++ b/Spigot-Server-Patches/Configurable-projectile-relative-velocity.patch @@ -38,29 +38,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + disableRelativeProjectileVelocity = getBoolean("game-mechanics.disable-relative-projectile-velocity", false); + } } -diff --git a/src/main/java/net/minecraft/server/EntityArrow.java b/src/main/java/net/minecraft/server/EntityArrow.java +diff --git a/src/main/java/net/minecraft/server/IProjectile.java b/src/main/java/net/minecraft/server/IProjectile.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/EntityArrow.java -+++ b/src/main/java/net/minecraft/server/EntityArrow.java -@@ -0,0 +0,0 @@ public abstract class EntityArrow extends Entity implements IProjectile { - float f7 = MathHelper.cos(f1 * 0.017453292F) * MathHelper.cos(f * 0.017453292F); - - this.shoot((double) f5, (double) f6, (double) f7, f3, f4); -- this.setMot(this.getMot().add(entity.getMot().x, entity.onGround ? 0.0D : entity.getMot().y, entity.getMot().z)); -+ if (!entity.world.paperConfig.disableRelativeProjectileVelocity) this.setMot(this.getMot().add(entity.getMot().x, entity.onGround ? 0.0D : entity.getMot().y, entity.getMot().z)); // Paper - allow disabling relative velocity - } - - @Override -diff --git a/src/main/java/net/minecraft/server/EntityProjectile.java b/src/main/java/net/minecraft/server/EntityProjectile.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/EntityProjectile.java -+++ b/src/main/java/net/minecraft/server/EntityProjectile.java -@@ -0,0 +0,0 @@ public abstract class EntityProjectile extends Entity implements IProjectile { +--- a/src/main/java/net/minecraft/server/IProjectile.java ++++ b/src/main/java/net/minecraft/server/IProjectile.java +@@ -0,0 +0,0 @@ public abstract class IProjectile extends Entity { this.shoot((double) f5, (double) f6, (double) f7, f3, f4); Vec3D vec3d = entity.getMot(); -- this.setMot(this.getMot().add(vec3d.x, entity.onGround ? 0.0D : vec3d.y, vec3d.z)); -+ if (!entity.world.paperConfig.disableRelativeProjectileVelocity) this.setMot(this.getMot().add(vec3d.x, entity.onGround ? 0.0D : vec3d.y, vec3d.z)); // Paper - allow disabling relative velocity +- this.setMot(this.getMot().add(vec3d.x, entity.isOnGround() ? 0.0D : vec3d.y, vec3d.z)); ++ if (!entity.world.paperConfig.disableRelativeProjectileVelocity) this.setMot(this.getMot().add(vec3d.x, entity.isOnGround() ? 0.0D : vec3d.y, vec3d.z)); // Paper - allow disabling relative velocity } - @Override + protected void a(MovingObjectPosition movingobjectposition) { diff --git a/Spigot-Server-Patches/Do-less-work-if-we-have-a-custom-Bukkit-generator.patch b/Spigot-Server-Patches/Do-less-work-if-we-have-a-custom-Bukkit-generator.patch index 1f4ea0475e..6fd63597f2 100644 --- a/Spigot-Server-Patches/Do-less-work-if-we-have-a-custom-Bukkit-generator.patch +++ b/Spigot-Server-Patches/Do-less-work-if-we-have-a-custom-Bukkit-generator.patch @@ -6,41 +6,35 @@ Subject: [PATCH] Do less work if we have a custom Bukkit generator If the Bukkit generator already has a spawn, use it immediately instead of spending time generating one that we won't use -diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java +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/WorldServer.java -+++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { - } else if (this.worldData.getType() == WorldType.DEBUG_ALL_BLOCK_STATES) { - this.worldData.setSpawn(BlockPosition.ZERO.up()); +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant list = worldchunkmanager.a(); -- Random random = new Random(this.getSeed()); -- BlockPosition blockposition = worldchunkmanager.a(0, this.getSeaLevel(), 0, 256, list, random); +- WorldChunkManager worldchunkmanager = chunkgenerator.getWorldChunkManager(); +- List list = worldchunkmanager.b(); +- Random random = new Random(worldserver.getSeed()); +- BlockPosition blockposition = worldchunkmanager.a(0, worldserver.getSeaLevel(), 0, 256, list, random); - ChunkCoordIntPair chunkcoordintpair = blockposition == null ? new ChunkCoordIntPair(0, 0) : new ChunkCoordIntPair(blockposition); -- -+// Paper start - moved down -+// WorldChunkManager worldchunkmanager = this.getChunkProvider().getChunkGenerator().getWorldChunkManager(); -+// List list = worldchunkmanager.a(); -+// Random random = new Random(this.getSeed()); -+// BlockPosition blockposition = worldchunkmanager.a(0, this.getSeaLevel(), 0, 256, list, random); -+// ChunkCoordIntPair chunkcoordintpair = blockposition == null ? new ChunkCoordIntPair(0, 0) : new ChunkCoordIntPair(blockposition); -+// Paper end ++ // Paper start - moved down // CraftBukkit start - if (this.generator != null) { - Random rand = new Random(this.getSeed()); -@@ -0,0 +0,0 @@ public class WorldServer extends World { + if (worldserver.generator != null) { + Random rand = new Random(worldserver.getSeed()); +@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant list = worldchunkmanager.a(); -+ Random random = new Random(this.getSeed()); -+ BlockPosition blockposition = worldchunkmanager.a(0, this.getSeaLevel(), 0, 256, list, random); ++ // Paper start - if the generator created a spawn for us, then there is no need for us to also create a spawn - ++ // only do it if the generator did not ++ WorldChunkManager worldchunkmanager = chunkgenerator.getWorldChunkManager(); ++ List list = worldchunkmanager.b(); ++ Random random = new Random(worldserver.getSeed()); ++ BlockPosition blockposition = worldchunkmanager.a(0, worldserver.getSeaLevel(), 0, 256, list, random); + ChunkCoordIntPair chunkcoordintpair = blockposition == null ? new ChunkCoordIntPair(0, 0) : new ChunkCoordIntPair(blockposition); + // Paper end + if (blockposition == null) { - WorldServer.LOGGER.warn("Unable to find spawn biome"); - } + MinecraftServer.LOGGER.warn("Unable to find spawn biome"); diff --git a/Spigot-Server-Patches/Do-not-allow-bees-to-load-chunks-for-beehives.patch b/Spigot-Server-Patches/Do-not-allow-bees-to-load-chunks-for-beehives.patch index 0073903ee7..521514d73d 100644 --- a/Spigot-Server-Patches/Do-not-allow-bees-to-load-chunks-for-beehives.patch +++ b/Spigot-Server-Patches/Do-not-allow-bees-to-load-chunks-for-beehives.patch @@ -8,7 +8,7 @@ diff --git a/src/main/java/net/minecraft/server/EntityBee.java b/src/main/java/n index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/EntityBee.java +++ b/src/main/java/net/minecraft/server/EntityBee.java -@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements EntityBird { +@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB if (this.hivePos == null) { return false; } else { @@ -16,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 TileEntity tileentity = this.world.getTileEntity(this.hivePos); return tileentity instanceof TileEntityBeehive && ((TileEntityBeehive) tileentity).d(); -@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements EntityBird { +@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB } private boolean i(BlockPosition blockposition) { @@ -24,15 +24,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 TileEntity tileentity = this.world.getTileEntity(blockposition); return tileentity instanceof TileEntityBeehive ? !((TileEntityBeehive) tileentity).isFull() : false; -@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements EntityBird { +@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB @Override public boolean g() { - if (EntityBee.this.hasHivePos() && EntityBee.this.eI() && EntityBee.this.hivePos.a((IPosition) EntityBee.this.getPositionVector(), 2.0D)) { + if (EntityBee.this.hasHivePos() && EntityBee.this.fe() && EntityBee.this.hivePos.a((IPosition) EntityBee.this.getPositionVector(), 2.0D)) { + if (!EntityBee.this.world.isLoadedAndInBounds(EntityBee.this.hivePos)) return false; // Paper TileEntity tileentity = EntityBee.this.world.getTileEntity(EntityBee.this.hivePos); if (tileentity instanceof TileEntityBeehive) { -@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements EntityBird { +@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB @Override public void c() { diff --git a/Spigot-Server-Patches/Don-t-load-Chunks-from-Hoppers-and-other-things.patch b/Spigot-Server-Patches/Don-t-load-Chunks-from-Hoppers-and-other-things.patch index 9e65c17c06..f9461e3223 100644 --- a/Spigot-Server-Patches/Don-t-load-Chunks-from-Hoppers-and-other-things.patch +++ b/Spigot-Server-Patches/Don-t-load-Chunks-from-Hoppers-and-other-things.patch @@ -21,13 +21,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { BlockPosition blockposition1 = blockposition.shift((EnumDirection) function1.apply(iblockdata)); - IBlockData iblockdata1 = generatoraccess.getType(blockposition1); -- -+ // Paper start - don't load chunks if the other side of the chest is in unloaded chunk ++ // Paper start + IBlockData iblockdata1 = generatoraccess.getTypeIfLoaded(blockposition1); + if (iblockdata1 == null) { + return new DoubleBlockFinder.Result.Single<>(s0); + } + // Paper end - if (iblockdata1.getBlock() == iblockdata.getBlock()) { - DoubleBlockFinder.BlockType doubleblockfinder_blocktype1 = (DoubleBlockFinder.BlockType) function.apply(iblockdata1); + if (iblockdata1.a(iblockdata.getBlock())) { + DoubleBlockFinder.BlockType doubleblockfinder_blocktype1 = (DoubleBlockFinder.BlockType) function.apply(iblockdata1); diff --git a/Spigot-Server-Patches/Ensure-Entity-is-never-double-registered.patch b/Spigot-Server-Patches/Ensure-Entity-is-never-double-registered.patch index b524f88631..5247e488c2 100644 --- a/Spigot-Server-Patches/Ensure-Entity-is-never-double-registered.patch +++ b/Spigot-Server-Patches/Ensure-Entity-is-never-double-registered.patch @@ -26,15 +26,15 @@ diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { + Entity entity2; - try (co.aikar.timings.Timing ignored = this.timings.newEntities.startTiming()) { // Paper - timings - while ((entity = (Entity) this.entitiesToAdd.poll()) != null) { -+ if (!entity.isQueuedForRegister) continue; // Paper - ignore cancelled registers - this.registerEntity(entity); + while ((entity2 = (Entity) this.entitiesToAdd.poll()) != null) { ++ if (!entity2.isQueuedForRegister) continue; // Paper - ignore cancelled registers + this.registerEntity(entity2); } - } // Paper - timings -@@ -0,0 +0,0 @@ public class WorldServer extends World { + +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { public void unregisterEntity(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot @@ -54,7 +54,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Spigot start if ( entity instanceof EntityHuman ) { -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { private void registerEntity(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot @@ -76,4 +76,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + entity.isQueuedForRegister = false; // Paper this.entitiesById.put(entity.getId(), entity); if (entity instanceof EntityEnderDragon) { - EntityComplexPart[] aentitycomplexpart = ((EntityEnderDragon) entity).eo(); + EntityComplexPart[] aentitycomplexpart = ((EntityEnderDragon) entity).eK(); diff --git a/Spigot-Server-Patches/Entity-Activation-Range-2.0.patch b/Spigot-Server-Patches/Entity-Activation-Range-2.0.patch index f1dee1b612..b854d7156d 100644 --- a/Spigot-Server-Patches/Entity-Activation-Range-2.0.patch +++ b/Spigot-Server-Patches/Entity-Activation-Range-2.0.patch @@ -17,13 +17,13 @@ diff --git a/src/main/java/net/minecraft/server/BehaviorController.java b/src/ma index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/BehaviorController.java +++ b/src/main/java/net/minecraft/server/BehaviorController.java -@@ -0,0 +0,0 @@ public class BehaviorController implements MinecraftSeri - }); +@@ -0,0 +0,0 @@ public class BehaviorController { + } + public boolean hasActivity(Activity activity) { return c(activity); } // Paper - OBFHELPER public boolean c(Activity activity) { - return this.g.contains(activity); + return this.j.contains(activity); } diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -46,7 +46,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (vec3d.equals(Vec3D.a)) { return; @@ -0,0 +0,0 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke - this.y = Vec3D.a; + this.x = Vec3D.a; this.setMot(Vec3D.a); } + // Paper start - ignore movement changes while inactive. @@ -58,13 +58,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end vec3d = this.a(vec3d, enummovetype); - Vec3D vec3d1 = this.e(vec3d); + Vec3D vec3d1 = this.f(vec3d); @@ -0,0 +0,0 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke - return this.am; + return this.al; } -+ public boolean isPushedByWater() { return this.bM(); } // Paper - OBFHELPER - the below is not an obfhelper, don't use it! - public boolean bM() { ++ public boolean isPushedByWater() { return this.bU(); } // Paper - OBFHELPER - the below is not an obfhelper, don't use it! + public boolean bU() { // Paper start return this.pushedByWater(); diff --git a/src/main/java/net/minecraft/server/EntityCreature.java b/src/main/java/net/minecraft/server/EntityCreature.java @@ -88,10 +88,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public long lootTableSeed; @Nullable - private Entity leashHolder; -+ public Entity leashHolder; // Paper - private int bF; ++ public Entity leashHolder; // Paper - private -> public + private int bE; @Nullable - private NBTTagCompound bG; + private NBTTagCompound bF; @@ -0,0 +0,0 @@ public abstract class EntityInsentient extends EntityLiving { return this.lookController; } @@ -115,25 +115,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { - protected float aV; - protected int aW; protected int getKillCount() { return this.aW; } // Paper - OBFHELPER + protected float aU; + protected int aV; protected int getKillCount() { return this.aV; } // Paper - OBFHELPER public float lastDamage; - protected boolean jumping; -+ public boolean jumping; // Paper ++ public boolean jumping; // Paper protected -> public + public float aY; public float aZ; public float ba; - public float bb; diff --git a/src/main/java/net/minecraft/server/EntityLlama.java b/src/main/java/net/minecraft/server/EntityLlama.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/EntityLlama.java +++ b/src/main/java/net/minecraft/server/EntityLlama.java @@ -0,0 +0,0 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn - return this.bK != null; + return this.bJ != null; } -+ public boolean inCaravan() { return this.fd(); } // Paper - OBFHELPER - public boolean fd() { - return this.bJ != null; ++ public final boolean inCaravan() { return this.fD(); } // Paper - OBFHELPER + public boolean fD() { + return this.bI != null; } diff --git a/src/main/java/net/minecraft/server/EntityVillager.java b/src/main/java/net/minecraft/server/EntityVillager.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -148,14 +148,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + if (this.getUnhappy() > 0) { + this.setUnhappy(this.getUnhappy() - 1); -+ } + } + if (this.doAITick()) { + if (world.spigotConfig.tickInactiveVillagers) { + this.mobTick(); + } else { + this.mobTick(true); + } - } ++ } + doReputationTick(); + // Paper end + @@ -163,30 +163,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Spigot End -- @Override + @Override - protected void mobTick() { -+ @Override // Paper start - tick trades while inactive + protected void mobTick() { mobTick(false); } + protected void mobTick(boolean inactive) { -+ // Paper end - this.world.getMethodProfiler().enter("brain"); + this.world.getMethodProfiler().enter("villagerBrain"); - this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error +- this.world.getMethodProfiler().exit(); + if (!inactive) this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper - this.world.getMethodProfiler().exit(); - if (!this.et() && this.bB > 0) { - --this.bB; + if (this.bM) { + this.bM = false; + } @@ -0,0 +0,0 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation - this.bD = null; + this.bC = null; } - if (!this.isNoAI() && this.random.nextInt(100) == 0) { + if (!inactive && !this.isNoAI() && this.random.nextInt(100) == 0) { // Paper - Raid raid = ((WorldServer) this.world).c_(new BlockPosition(this)); + Raid raid = ((WorldServer) this.world).c_(this.getChunkCoordinates()); if (raid != null && raid.v() && !raid.a()) { @@ -0,0 +0,0 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation - if (this.getVillagerData().getProfession() == VillagerProfession.NONE && this.et()) { - this.ey(); + if (this.getVillagerData().getProfession() == VillagerProfession.NONE && this.eO()) { + this.eT(); } + if (inactive) return; // Paper @@ -196,8 +195,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -+ private void doReputationTick() { fa(); } // Paper - OBFHELPER - private void fa() { ++ private void doReputationTick() { fv(); } // Paper - OBFHELPER + private void fv() { long i = this.world.getTime(); diff --git a/src/main/java/net/minecraft/server/EntityVillagerAbstract.java b/src/main/java/net/minecraft/server/EntityVillagerAbstract.java @@ -208,14 +207,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return super.prepare(generatoraccess, difficultydamagescaler, enummobspawn, (GroupDataEntity) groupdataentity, nbttagcompound); } -+ public final int getUnhappy() { return eq(); } // Paper - OBFHELPER - public int eq() { - return (Integer) this.datawatcher.get(EntityVillagerAbstract.bx); ++ public final int getUnhappy() { return eL(); } // Paper - OBFHELPER + public int eL() { + return (Integer) this.datawatcher.get(EntityVillagerAbstract.bw); } + public final void setUnhappy(int i) { s(i); } // Paper - OBFHELPER public void s(int i) { - this.datawatcher.set(EntityVillagerAbstract.bx, i); + this.datawatcher.set(EntityVillagerAbstract.bw, i); } diff --git a/src/main/java/net/minecraft/server/PathfinderGoal.java b/src/main/java/net/minecraft/server/PathfinderGoal.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -267,7 +266,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public PathfinderGoalGotoTarget(EntityCreature entitycreature, double d0, int i, int j) { this.e = BlockPosition.ZERO; @@ -0,0 +0,0 @@ public abstract class PathfinderGoalGotoTarget extends PathfinderGoal { - blockposition_mutableblockposition.g(blockposition).e(i1, k - 1, j1); + blockposition_mutableblockposition.a((BaseBlockPosition) blockposition, i1, k - 1, j1); if (this.a.a((BlockPosition) blockposition_mutableblockposition) && this.a(this.a.world, blockposition_mutableblockposition)) { this.e = blockposition_mutableblockposition; + setTarget(blockposition_mutableblockposition.immutableCopy()); // Paper @@ -283,15 +282,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }; private final Map c = new EnumMap(PathfinderGoal.Type.class); - private final Set d = Sets.newLinkedHashSet(); -+ private final Set d = Sets.newLinkedHashSet();private Set getTasks() { return d; }// Paper - OBFHELPER - private final GameProfilerFiller e; ++ private final Set d = Sets.newLinkedHashSet(); private Set getTasks() { return d; }// Paper - OBFHELPER + private final Supplier e; private final EnumSet f = EnumSet.noneOf(PathfinderGoal.Type.class); - private int g = 3; + private int g = 3;private int getTickRate() { return g; } // Paper - OBFHELPER + private int curRate;private int getCurRate() { return curRate; } private void incRate() { this.curRate++; } // Paper TODO - public PathfinderGoalSelector(GameProfilerFiller gameprofilerfiller) { - this.e = gameprofilerfiller; + public PathfinderGoalSelector(Supplier supplier) { + this.e = supplier; @@ -0,0 +0,0 @@ public class PathfinderGoalSelector { this.d.add(new PathfinderGoalWrapped(i, pathfindergoal)); } @@ -593,8 +592,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } if ( !( entity instanceof EntityArrow ) ) { -- if ( !entity.onGround || !entity.passengers.isEmpty() || entity.isPassenger() ) -+ if ( (!entity.onGround && !(entity instanceof EntityFlying)) || !entity.passengers.isEmpty() || entity.isPassenger() ) // Paper +- if ( !entity.isOnGround() || !entity.passengers.isEmpty() || entity.isPassenger() ) ++ if ( (!entity.isOnGround() && !(entity instanceof EntityFlying)) || !entity.passengers.isEmpty() || entity.isPassenger() ) { - return true; + return 10; // Paper diff --git a/Spigot-Server-Patches/Entity-Jump-API.patch b/Spigot-Server-Patches/Entity-Jump-API.patch index ff7424a411..da44758b6a 100644 --- a/Spigot-Server-Patches/Entity-Jump-API.patch +++ b/Spigot-Server-Patches/Entity-Jump-API.patch @@ -9,9 +9,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { - } else if (this.aH()) { - this.c(TagsFluid.LAVA); - } else if ((this.onGround || this.N > 0.0D && this.N <= 0.4D) && this.jumpTicks == 0) { + } else if (this.aN() && (!this.onGround || d7 > d8)) { + this.c((Tag) TagsFluid.LAVA); + } else if ((this.onGround || flag && d7 <= d8) && this.jumpTicks == 0) { + if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper this.jump(); this.jumpTicks = 10; @@ -26,7 +26,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class EntityPanda extends EntityAnimal { EntityPanda entitypanda = (EntityPanda) iterator.next(); - if (!entitypanda.isBaby() && entitypanda.onGround && !entitypanda.isInWater() && entitypanda.eL()) { + if (!entitypanda.isBaby() && entitypanda.onGround && !entitypanda.isInWater() && entitypanda.fi()) { + if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper entitypanda.jump(); + } else { this.setJumping(false); } // Paper - setJumping(false) stops a potential loop diff --git a/Spigot-Server-Patches/Fix-AssertionError-when-player-hand-set-to-empty-typ.patch b/Spigot-Server-Patches/Fix-AssertionError-when-player-hand-set-to-empty-typ.patch index 2fc174550e..4422b90b90 100644 --- a/Spigot-Server-Patches/Fix-AssertionError-when-player-hand-set-to-empty-typ.patch +++ b/Spigot-Server-Patches/Fix-AssertionError-when-player-hand-set-to-empty-typ.patch @@ -11,10 +11,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { - return this.getEquipment(EnumItemSlot.OFFHAND); + return predicate.test(this.getItemInMainHand().getItem()) || predicate.test(this.getItemInOffHand().getItem()); } -+ public ItemStack getItemInHand(EnumHand enumhand) { return this.b(enumhand); } // Paper - OBFHELPER ++ public final ItemStack getItemInHand(EnumHand enumhand) { return this.b(enumhand); } // Paper - OBFHELPER public ItemStack b(EnumHand enumhand) { if (enumhand == EnumHand.MAIN_HAND) { return this.getEquipment(EnumItemSlot.MAINHAND); @@ -23,13 +23,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/PlayerConnection.java +++ b/src/main/java/net/minecraft/server/PlayerConnection.java @@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn { - if (cancelled) { this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524 - } else { -+ // Paper start -+ itemstack = this.player.getItemInHand(enumhand); -+ if (itemstack.isEmpty()) return; -+ // Paper end - this.player.playerInteractManager.a(this.player, worldserver, itemstack, enumhand); + return; } - // CraftBukkit end ++ // Paper start ++ itemstack = this.player.getItemInHand(enumhand); ++ if (itemstack.isEmpty()) return; ++ // Paper end + EnumInteractionResult enuminteractionresult = this.player.playerInteractManager.a(this.player, worldserver, itemstack, enumhand); + + if (enuminteractionresult.b()) { diff --git a/Spigot-Server-Patches/Fix-World-isChunkGenerated-calls.patch b/Spigot-Server-Patches/Fix-World-isChunkGenerated-calls.patch index f0403a6f11..e4af25853b 100644 --- a/Spigot-Server-Patches/Fix-World-isChunkGenerated-calls.patch +++ b/Spigot-Server-Patches/Fix-World-isChunkGenerated-calls.patch @@ -142,14 +142,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - private NBTTagCompound readChunkData(ChunkCoordIntPair chunkcoordintpair) throws IOException { + public NBTTagCompound readChunkData(ChunkCoordIntPair chunkcoordintpair) throws IOException { // Paper - private -> public NBTTagCompound nbttagcompound = this.read(chunkcoordintpair); - -- return nbttagcompound == null ? null : this.getChunkData(this.world.getWorldProvider().getDimensionManager(), this.l, nbttagcompound, chunkcoordintpair, world); // CraftBukkit + // Paper start - Cache chunk status on disk + if (nbttagcompound == null) { + return null; + } + -+ nbttagcompound = this.getChunkData(this.world.getWorldProvider().getDimensionManager(), this.l, nbttagcompound, chunkcoordintpair, world); // CraftBukkit ++ nbttagcompound = this.getChunkData(this.world.getTypeKey(), this.l, nbttagcompound, chunkcoordintpair, world); // CraftBukkit + if (nbttagcompound == null) { + return null; + } @@ -165,12 +163,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + RegionFile regionFile = this.getIOWorker().getRegionFileCache().getRegionFileIfLoaded(chunkPos); + + return regionFile == null ? null : regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); - } - -+ public ChunkStatus getChunkStatusOnDisk(ChunkCoordIntPair chunkPos) throws IOException { -+ RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, false); ++ } + -+ if (!regionFile.chunkExists(chunkPos)) { ++ public ChunkStatus getChunkStatusOnDisk(ChunkCoordIntPair chunkPos) throws IOException { ++ RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, true); ++ ++ if (regionFile == null || !regionFile.chunkExists(chunkPos)) { + return null; + } + @@ -181,10 +179,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + this.readChunkData(chunkPos); -+ + +- return nbttagcompound == null ? null : this.getChunkData(this.world.getTypeKey(), this.l, nbttagcompound, chunkcoordintpair, world); // CraftBukkit + return regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); -+ } -+ + } + + public void updateChunkStatusOnDisk(ChunkCoordIntPair chunkPos, @Nullable NBTTagCompound compound) throws IOException { + RegionFile regionFile = this.getIOWorker().getRegionFileCache().getFile(chunkPos, false); + @@ -232,8 +231,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end + - public RegionFile(File file, File file1) throws IOException { - this(file.toPath(), file1.toPath(), RegionFileCompression.b); + public RegionFile(File file, File file1, boolean flag) throws IOException { + this(file.toPath(), file1.toPath(), RegionFileCompression.b, flag); } @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { return this.getOffset(chunkcoordintpair) != 0; @@ -247,14 +246,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void close() throws IOException { + this.closed = true; // Paper try { - this.c(); + this.d(); } finally { diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/RegionFileCache.java +++ b/src/main/java/net/minecraft/server/RegionFileCache.java @@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable { - this.b = file; + this.c = flag; } - private RegionFile getFile(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit diff --git a/Spigot-Server-Patches/Fix-comparator-behavior-for-EntityPhanton-goal.patch b/Spigot-Server-Patches/Fix-comparator-behavior-for-EntityPhanton-goal.patch deleted file mode 100644 index 012659b1c0..0000000000 --- a/Spigot-Server-Patches/Fix-comparator-behavior-for-EntityPhanton-goal.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Wed, 22 Jan 2020 21:00:21 +0000 -Subject: [PATCH] Fix comparator behavior for EntityPhanton goal - - -diff --git a/src/main/java/net/minecraft/server/EntityPhantom.java b/src/main/java/net/minecraft/server/EntityPhantom.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/EntityPhantom.java -+++ b/src/main/java/net/minecraft/server/EntityPhantom.java -@@ -0,0 +0,0 @@ public class EntityPhantom extends EntityFlying implements IMonster { - - if (!list.isEmpty()) { - list.sort((entityhuman, entityhuman1) -> { -- return entityhuman.locY() > entityhuman1.locY() ? -1 : 1; -+ return Double.compare(entityhuman1.locY(), entityhuman.locY()); // Paper - }); - Iterator iterator = list.iterator(); - diff --git a/Spigot-Server-Patches/Fix-items-vanishing-through-end-portal.patch b/Spigot-Server-Patches/Fix-items-vanishing-through-end-portal.patch index 66c5006093..2892b633b8 100644 --- a/Spigot-Server-Patches/Fix-items-vanishing-through-end-portal.patch +++ b/Spigot-Server-Patches/Fix-items-vanishing-through-end-portal.patch @@ -19,12 +19,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke if (blockposition == null) { // CraftBukkit - if (dimensionmanager1.getType() == DimensionManager.THE_END && dimensionmanager == DimensionManager.OVERWORLD) { // CraftBukkit + if (this.world.getDimensionKey() == World.THE_END && worldserver.getDimensionKey() == World.OVERWORLD) { + // Paper start - Ensure spawn chunk is always loaded before calculating Y coordinate -+ if (!worldserver1.isLoaded(worldserver1.getSpawn())) { -+ worldserver1.getChunkAtWorldCoords(worldserver1.getSpawn()); -+ } ++ this.world.getChunkAtWorldCoords(this.world.getSpawn()); + // Paper end // CraftBukkit start - EntityPortalEvent event = CraftEventFactory.callEntityPortalEvent(this, worldserver1, worldserver1.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES, worldserver1.getSpawn()), 0); + EntityPortalEvent event = CraftEventFactory.callEntityPortalEvent(this, worldserver, worldserver.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES, worldserver.getSpawn()), 0); if (event == null) { diff --git a/Spigot-Server-Patches/Fix-last-firework-in-stack-not-having-effects-when-d.patch b/Spigot-Server-Patches/Fix-last-firework-in-stack-not-having-effects-when-d.patch index 892826de01..43ba0c661f 100644 --- a/Spigot-Server-Patches/Fix-last-firework-in-stack-not-having-effects-when-d.patch +++ b/Spigot-Server-Patches/Fix-last-firework-in-stack-not-having-effects-when-d.patch @@ -16,8 +16,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } itemstack1 = CraftItemStack.asNMSCopy(event.getItem()); -- EntityFireworks entityfireworks = new EntityFireworks(isourceblock.getWorld(), itemstack, d3, d4, d5, true); -+ EntityFireworks entityfireworks = new EntityFireworks(isourceblock.getWorld(), itemstack1, d3, d4, d5, true); // Paper - GH-2871 - fix last firework in stack having no effects when dispensed +- EntityFireworks entityfireworks = new EntityFireworks(isourceblock.getWorld(), itemstack, isourceblock.getX(), isourceblock.getY(), isourceblock.getX(), true); ++ EntityFireworks entityfireworks = new EntityFireworks(isourceblock.getWorld(), itemstack1, isourceblock.getX(), isourceblock.getY(), isourceblock.getX(), true); // Paper - GH-2871 - fix last firework in stack having no effects when dispensed - entityfireworks.shoot(d0, d1, d2, 0.5F, 1.0F); - isourceblock.getWorld().addEntity(entityfireworks); + IDispenseBehavior.a(isourceblock, entityfireworks, enumdirection); + entityfireworks.shoot((double) enumdirection.getAdjacentX(), (double) enumdirection.getAdjacentY(), (double) enumdirection.getAdjacentZ(), 0.5F, 1.0F); diff --git a/Spigot-Server-Patches/Fix-spawn-radius-being-treated-as-0.patch b/Spigot-Server-Patches/Fix-spawn-radius-being-treated-as-0.patch deleted file mode 100644 index eb029b9908..0000000000 --- a/Spigot-Server-Patches/Fix-spawn-radius-being-treated-as-0.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sun, 15 Dec 2019 19:41:28 +0000 -Subject: [PATCH] Fix spawn radius being treated as 0 - - -diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/EntityPlayer.java -+++ b/src/main/java/net/minecraft/server/EntityPlayer.java -@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting { - public final BlockPosition getSpawnPoint(WorldServer worldserver) { - BlockPosition blockposition = worldserver.getSpawn(); - -- if (worldserver.worldProvider.g() && worldserver.getWorldData().getGameType() != EnumGamemode.ADVENTURE) { -+ if (worldserver.worldProvider.f() && worldserver.getWorldData().getGameType() != EnumGamemode.ADVENTURE) { // Paper - int i = Math.max(0, this.server.a(worldserver)); - int j = MathHelper.floor(worldserver.getWorldBorder().b((double) blockposition.getX(), (double) blockposition.getZ())); - diff --git a/Spigot-Server-Patches/Fix-unregistering-entities-from-unloading-chunks.patch b/Spigot-Server-Patches/Fix-unregistering-entities-from-unloading-chunks.patch index 2134d29148..e753c5fa81 100644 --- a/Spigot-Server-Patches/Fix-unregistering-entities-from-unloading-chunks.patch +++ b/Spigot-Server-Patches/Fix-unregistering-entities-from-unloading-chunks.patch @@ -18,7 +18,7 @@ diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { } private void removeEntityFromChunk(Entity entity) { diff --git a/Spigot-Server-Patches/Generator-Settings.patch b/Spigot-Server-Patches/Generator-Settings.patch index 596865d130..f4cda5030d 100644 --- a/Spigot-Server-Patches/Generator-Settings.patch +++ b/Spigot-Server-Patches/Generator-Settings.patch @@ -22,32 +22,68 @@ diff --git a/src/main/java/net/minecraft/server/ChunkGeneratorAbstract.java b/sr index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/ChunkGeneratorAbstract.java +++ b/src/main/java/net/minecraft/server/ChunkGeneratorAbstract.java -@@ -0,0 +0,0 @@ public abstract class ChunkGeneratorAbstract +@@ -0,0 +0,0 @@ public final class ChunkGeneratorAbstract extends ChunkGenerator { + BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition(); int i = ichunkaccess.getPos().d(); int j = ichunkaccess.getPos().e(); - T t0 = this.getSettings(); -- int k = t0.u(); -- int l = t0.t(); -+ int k = t0.u(); final int floorHeight = k; // Paper -+ int l = t0.t(); final int roofHeight = l; // Paper - Iterator iterator = BlockPosition.b(i, 0, j, i + 15, 0, j + 15).iterator(); +- int k = this.h.f(); +- int l = this.x - 1 - this.h.e(); ++ int k = this.h.f(); final int floorHeight = k; // Paper ++ int l = this.x - 1 - this.h.e(); final int roofHeight = l; // Paper + boolean flag = true; + boolean flag1 = l + 4 >= 0 && l < this.x; + boolean flag2 = k + 4 >= 0 && k < this.x; +@@ -0,0 +0,0 @@ public final class ChunkGeneratorAbstract extends ChunkGenerator { - while (iterator.hasNext()) { -@@ -0,0 +0,0 @@ public abstract class ChunkGeneratorAbstract - - if (l > 0) { - for (i1 = l; i1 >= l - 4; --i1) { -- if (i1 >= l - random.nextInt(5)) { -+ if (i1 >= (getWorld().paperConfig.generateFlatBedrock ? roofHeight : l - random.nextInt(5))) { // Paper - Configurable flat bedrock roof - ichunkaccess.setType(blockposition_mutableblockposition.d(blockposition.getX(), i1, blockposition.getZ()), Blocks.BEDROCK.getBlockData(), false); + if (flag1) { + for (i1 = 0; i1 < 5; ++i1) { +- if (i1 <= random.nextInt(5)) { ++ if (i1 <= (ichunkaccess.generateFlatBedrock() ? roofHeight : random.nextInt(5))) { // Paper - Configurable flat bedrock roof + ichunkaccess.setType(blockposition_mutableblockposition.d(blockposition.getX(), l - i1, blockposition.getZ()), Blocks.BEDROCK.getBlockData(), false); + } } - } -@@ -0,0 +0,0 @@ public abstract class ChunkGeneratorAbstract +@@ -0,0 +0,0 @@ public final class ChunkGeneratorAbstract extends ChunkGenerator { - if (k < 256) { - for (i1 = k + 4; i1 >= k; --i1) { -- if (i1 <= k + random.nextInt(5)) { -+ if (i1 <= (getWorld().paperConfig.generateFlatBedrock ? floorHeight : k + random.nextInt(5))) { // Paper - Configurable flat bedrock floor - ichunkaccess.setType(blockposition_mutableblockposition.d(blockposition.getX(), i1, blockposition.getZ()), Blocks.BEDROCK.getBlockData(), false); + if (flag2) { + for (i1 = 4; i1 >= 0; --i1) { +- if (i1 <= random.nextInt(5)) { ++ if (i1 <= (ichunkaccess.generateFlatBedrock() ? floorHeight : random.nextInt(5))) { // Paper - Configurable flat bedrock floor + ichunkaccess.setType(blockposition_mutableblockposition.d(blockposition.getX(), k + i1, blockposition.getZ()), Blocks.BEDROCK.getBlockData(), false); + } } - } +diff --git a/src/main/java/net/minecraft/server/IChunkAccess.java b/src/main/java/net/minecraft/server/IChunkAccess.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/IChunkAccess.java ++++ b/src/main/java/net/minecraft/server/IChunkAccess.java +@@ -0,0 +0,0 @@ import org.apache.logging.log4j.LogManager; + + public interface IChunkAccess extends IBlockAccess, IStructureAccess { + ++ // Paper start ++ default boolean generateFlatBedrock() { ++ if (this instanceof ProtoChunk) { ++ return ((ProtoChunk)this).world.paperConfig.generateFlatBedrock; ++ } else if (this instanceof Chunk) { ++ return ((Chunk)this).world.paperConfig.generateFlatBedrock; ++ } else { ++ return false; ++ } ++ } ++ // Paper end ++ + IBlockData getType(final int x, final int y, final int z); // Paper + @Nullable + IBlockData setType(BlockPosition blockposition, IBlockData iblockdata, boolean flag); +diff --git a/src/main/java/net/minecraft/server/ProtoChunk.java b/src/main/java/net/minecraft/server/ProtoChunk.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/ProtoChunk.java ++++ b/src/main/java/net/minecraft/server/ProtoChunk.java +@@ -0,0 +0,0 @@ public class ProtoChunk implements IChunkAccess { + private long s; + private final Map t; + private volatile boolean u; +- private final World world; // Paper - Anti-Xray - Add world ++ final World world; // Paper - Anti-Xray - Add world // Paper - private -> default + + // Paper start - Anti-Xray - Add world + @Deprecated public ProtoChunk(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter) { this(chunkcoordintpair, chunkconverter, null); } // Notice for updates: Please make sure this constructor isn't used anywhere diff --git a/Spigot-Server-Patches/Guard-against-serializing-mismatching-chunk-coordina.patch b/Spigot-Server-Patches/Guard-against-serializing-mismatching-chunk-coordina.patch index fe3aa5408a..26c0d59940 100644 --- a/Spigot-Server-Patches/Guard-against-serializing-mismatching-chunk-coordina.patch +++ b/Spigot-Server-Patches/Guard-against-serializing-mismatching-chunk-coordina.patch @@ -25,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ChunkRegionLoader { // Paper end - ChunkGenerator chunkgenerator = worldserver.getChunkProvider().getChunkGenerator(); + ChunkGenerator chunkgenerator = worldserver.getChunkProvider().getChunkGenerator(); WorldChunkManager worldchunkmanager = chunkgenerator.getWorldChunkManager(); - NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("Level"); - ChunkCoordIntPair chunkcoordintpair1 = new ChunkCoordIntPair(nbttagcompound1.getInt("xPos"), nbttagcompound1.getInt("zPos")); @@ -38,8 +38,8 @@ diff --git a/src/main/java/net/minecraft/server/IChunkLoader.java b/src/main/jav index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/IChunkLoader.java +++ b/src/main/java/net/minecraft/server/IChunkLoader.java -@@ -0,0 +0,0 @@ public class IChunkLoader extends RegionFileCache implements AutoCloseable { - // +@@ -0,0 +0,0 @@ public class IChunkLoader implements AutoCloseable { + public void a(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException { write(chunkcoordintpair, nbttagcompound); } // Paper OBFHELPER public void write(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException { // Paper - OBFHELPER - (Switched around for safety) + // Paper start @@ -49,6 +49,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + " but compound says coordinate is " + ChunkRegionLoader.getChunkCoordinate(nbttagcompound).toString() + (world == null ? " for an unknown world" : (" for world: " + world))); + } + // Paper end - super.write(chunkcoordintpair, nbttagcompound); + this.regionFileCache.write(chunkcoordintpair, nbttagcompound); if (this.c != null) { synchronized (this.persistentDataLock) { // Paper - Async chunk loading diff --git a/Spigot-Server-Patches/Implement-alternative-item-despawn-rate.patch b/Spigot-Server-Patches/Implement-alternative-item-despawn-rate.patch index 1e55afffde..37a7771eb3 100644 --- a/Spigot-Server-Patches/Implement-alternative-item-despawn-rate.patch +++ b/Spigot-Server-Patches/Implement-alternative-item-despawn-rate.patch @@ -123,5 +123,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end + @Override - public Packet L() { + public Packet O() { return new PacketPlayOutSpawnEntity(this); diff --git a/Spigot-Server-Patches/Lag-compensate-eating.patch b/Spigot-Server-Patches/Lag-compensate-eating.patch index 3ad9bccb61..7d85ea46e9 100644 --- a/Spigot-Server-Patches/Lag-compensate-eating.patch +++ b/Spigot-Server-Patches/Lag-compensate-eating.patch @@ -14,45 +14,45 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private int jumpTicks; private float bD; public ItemStack activeItem; // Paper - public -- protected int bl; -+ protected int bl; protected final int getEatTimeTicks() { return this.bl; } protected final void setEatTimeTicks(int value) { this.bl = value; } // Paper - OBFHELPER - protected int bm; +- protected int bk; ++ protected int bk; protected final int getEatTimeTicks() { return this.bk; } protected final void setEatTimeTicks(int value) { this.bk = value; } // Paper - OBFHELPER + protected int bl; private BlockPosition bE; - private DamageSource bF; + private Optional bF; @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { - return ((Byte) this.datawatcher.get(EntityLiving.ao) & 2) > 0 ? EnumHand.OFF_HAND : EnumHand.MAIN_HAND; + return ((Byte) this.datawatcher.get(EntityLiving.an) & 2) > 0 ? EnumHand.OFF_HAND : EnumHand.MAIN_HAND; } + // Paper start - lag compensate eating + protected long eatStartTime; + protected int totalEatTimeTicks; + // Paper end - private void o() { ++ + private void u() { if (this.isHandRaised()) { if (ItemStack.d(this.b(this.getRaisedHand()), this.activeItem)) { @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { this.b(this.activeItem, 5); } -- if (--this.bl == 0 && !this.world.isClientSide && !this.activeItem.m()) { -+ +- if (--this.bk == 0 && !this.world.isClientSide && !this.activeItem.m()) { + // Paper start - lag compensate eating + // we add 1 to the expected time to avoid lag compensating when we should not + boolean shouldLagCompensate + = this.activeItem.getItem().isFood() && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1 + this.totalEatTimeTicks) * 50 * (1000 * 1000)); -+ if ((--this.bl == 0 || shouldLagCompensate) && !this.world.isClientSide && !this.activeItem.m()) { ++ if ((--this.bk == 0 || shouldLagCompensate) && !this.world.isClientSide && !this.activeItem.m()) { + this.setEatTimeTicks(0); + // Paper end - this.q(); + this.s(); } } else { @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { if (!itemstack.isEmpty() && !this.isHandRaised() || forceUpdate) { // Paper use override flag this.activeItem = itemstack; -- this.bl = itemstack.k(); +- this.bk = itemstack.k(); + // Paper start - lag compensate eating -+ this.bl = this.totalEatTimeTicks = itemstack.k(); ++ this.bk = this.totalEatTimeTicks = itemstack.k(); + this.eatStartTime = System.nanoTime(); + // Paper end if (!this.world.isClientSide) { @@ -61,10 +61,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { } } else if (!this.isHandRaised() && !this.activeItem.isEmpty()) { - this.activeItem = ItemStack.a; -- this.bl = 0; + this.activeItem = ItemStack.b; +- this.bk = 0; + // Paper start - lag compensate eating -+ this.bl = this.totalEatTimeTicks = 0; ++ this.bk = this.totalEatTimeTicks = 0; + this.eatStartTime = -1L; + // Paper end } @@ -73,10 +73,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { } - this.activeItem = ItemStack.a; -- this.bl = 0; + this.activeItem = ItemStack.b; +- this.bk = 0; + // Paper start - lag compensate eating -+ this.bl = this.totalEatTimeTicks = 0; ++ this.bk = this.totalEatTimeTicks = 0; + this.eatStartTime = -1L; + // Paper end } diff --git a/Spigot-Server-Patches/Make-the-GUI-graph-fancier.patch b/Spigot-Server-Patches/Make-the-GUI-graph-fancier.patch index acbd7a72f7..10da4ae409 100644 --- a/Spigot-Server-Patches/Make-the-GUI-graph-fancier.patch +++ b/Spigot-Server-Patches/Make-the-GUI-graph-fancier.patch @@ -403,12 +403,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant> 4, blockposition.getZ() >> 4); + diff --git a/Spigot-Server-Patches/Optimise-IEntityAccess-getPlayerByUUID.patch b/Spigot-Server-Patches/Optimise-IEntityAccess-getPlayerByUUID.patch index 2479f49a74..bc43aa1dc9 100644 --- a/Spigot-Server-Patches/Optimise-IEntityAccess-getPlayerByUUID.patch +++ b/Spigot-Server-Patches/Optimise-IEntityAccess-getPlayerByUUID.patch @@ -26,9 +26,9 @@ diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { - return new Throwable(entity + " Added to world at " + new java.util.Date()); +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { } + // Paper end + // Paper start - optimise getPlayerByUUID + @Nullable @@ -39,6 +39,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end + - // Paper start - Asynchronous IO - public final com.destroystokyo.paper.io.PaperFileIOThread.ChunkDataController poiDataController = new com.destroystokyo.paper.io.PaperFileIOThread.ChunkDataController() { - @Override + // Add env and gen to constructor, WorldData -> WorldDataServer + public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey resourcekey, ResourceKey resourcekey1, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { + super(iworlddataserver, resourcekey, resourcekey1, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env, executor); // Paper pass executor diff --git a/Spigot-Server-Patches/Optimise-TickListServer-by-rewriting-it.patch b/Spigot-Server-Patches/Optimise-TickListServer-by-rewriting-it.patch index 18a7ee2092..6b665f255b 100644 --- a/Spigot-Server-Patches/Optimise-TickListServer-by-rewriting-it.patch +++ b/Spigot-Server-Patches/Optimise-TickListServer-by-rewriting-it.patch @@ -113,7 +113,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private final WorldServer world; + private final Predicate excludeFromScheduling; + private final Function getMinecraftKeyFrom; -+ private final Function getObjectFronMinecraftKey; ++ //private final Function getObjectFronMinecraftKey; + private final Consumer> tickFunction; + + private final co.aikar.timings.Timing timingCleanup; // Paper @@ -156,12 +156,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public PaperTickList(final WorldServer world, final Predicate excludeFromScheduling, final Function getMinecraftKeyFrom, -+ final Function getObjectFronMinecraftKey, final Consumer> tickFunction, final String timingsType) { -+ super(world, excludeFromScheduling, getMinecraftKeyFrom, getObjectFronMinecraftKey, tickFunction, timingsType); ++ final Consumer> tickFunction, final String timingsType) { ++ super(world, excludeFromScheduling, getMinecraftKeyFrom, tickFunction, timingsType); + this.world = world; + this.excludeFromScheduling = excludeFromScheduling; + this.getMinecraftKeyFrom = getMinecraftKeyFrom; -+ this.getObjectFronMinecraftKey = getObjectFronMinecraftKey; + this.tickFunction = tickFunction; + this.timingCleanup = co.aikar.timings.WorldTimingsHandler.getTickList(world, timingsType + " - Cleanup"); // Paper + this.timingTicking = co.aikar.timings.WorldTimingsHandler.getTickList(world, timingsType + " - Ticking"); // Paper @@ -521,10 +520,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.addToSchedule(entry); + } + -+ @Override -+ public void scheduleAll(final Stream> stream) { -+ this.scheduleAll(stream.iterator()); -+ } + public void scheduleAll(final Iterator> iterator) { + while (iterator.hasNext()) { + this.schedule(iterator.next()); @@ -886,7 +881,7 @@ diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/ja index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/BlockPosition.java +++ b/src/main/java/net/minecraft/server/BlockPosition.java -@@ -0,0 +0,0 @@ public class BlockPosition extends BaseBlockPosition implements MinecraftSeriali +@@ -0,0 +0,0 @@ public class BlockPosition extends BaseBlockPosition { return i == 0 && j == 0 && k == 0 ? this : new BlockPosition(this.getX() + i, this.getY() + j, this.getZ() + k); } @@ -909,9 +904,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - rewrite ticklistserver + - - public ChunkProviderServer(WorldServer worldserver, File file, DataFixer datafixer, DefinedStructureManager definedstructuremanager, Executor executor, ChunkGenerator chunkgenerator, int i, WorldLoadListener worldloadlistener, Supplier supplier) { + public ChunkProviderServer(WorldServer worldserver, Convertable.ConversionSession convertable_conversionsession, DataFixer datafixer, DefinedStructureManager definedstructuremanager, Executor executor, ChunkGenerator chunkgenerator, int i, boolean flag, WorldLoadListener worldloadlistener, Supplier supplier) { this.world = worldserver; + this.serverThreadQueue = new ChunkProviderServer.a(worldserver); diff --git a/src/main/java/net/minecraft/server/NextTickListEntry.java b/src/main/java/net/minecraft/server/NextTickListEntry.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/NextTickListEntry.java @@ -1030,7 +1025,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return this.d >= structureboundingbox.a && this.a <= structureboundingbox.d && this.f >= structureboundingbox.c && this.c <= structureboundingbox.f && this.e >= structureboundingbox.b && this.b <= structureboundingbox.e; } @@ -0,0 +0,0 @@ public class StructureBoundingBox { - return new StructureBoundingBox(this.a + i, this.b + j, this.c + k, this.d + i, this.e + j, this.f + k); + this.a(baseblockposition.getX(), baseblockposition.getY(), baseblockposition.getZ()); } + public final boolean hasPoint(BaseBlockPosition baseblockposition) { return this.b(baseblockposition); } // Paper - OBFHELPER @@ -1062,17 +1057,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + public boolean isPendingTickThisTick(BlockPosition blockposition, T t0) { + // Paper end - return this.g.contains(new NextTickListEntry<>(blockposition, t0)); - } - - @Override - public void a(Stream> stream) { -+ // Paper start - allow overriding -+ this.scheduleAll(stream); -+ } -+ public void scheduleAll(Stream> stream) { -+ // Paper end - stream.forEach(this::a); + return this.f.contains(new NextTickListEntry<>(blockposition, t0)); } public List> a(ChunkCoordIntPair chunkcoordintpair, boolean flag, boolean flag1) { @@ -1119,11 +1104,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end List> list = this.a(chunkcoordintpair, false, true); - return a(this.b, list, this.f.getTime()); + return a(this.b, list, this.e.getTime()); } + public static NBTTagList serialize(Function function, Iterable> iterable, long i) { return TickListServer.a(function, iterable, i); } // Paper - OBFHELPER - public static NBTTagList a(Function function, Iterable> iterable, long i) { + private static NBTTagList a(Function function, Iterable> iterable, long i) { NBTTagList nbttaglist = new NBTTagList(); Iterator iterator = iterable.iterator(); @@ -0,0 +0,0 @@ public class TickListServer implements TickList { @@ -1146,7 +1131,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void schedule(BlockPosition blockposition, T t0, int i, TickListPriority ticklistpriority) { + // Paper end if (!this.a.test(t0)) { - this.a(new NextTickListEntry<>(blockposition, t0, (long) i + this.f.getTime(), ticklistpriority)); + this.a(new NextTickListEntry<>(blockposition, t0, (long) i + this.e.getTime(), ticklistpriority)); } @@ -0,0 +0,0 @@ public class TickListServer implements TickList { } @@ -1164,7 +1149,7 @@ diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { } // Paper end @@ -1177,35 +1162,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - rewrite ticklistserver + - // Add env and gen to constructor - public WorldServer(MinecraftServer minecraftserver, Executor executor, WorldNBTStorage worldnbtstorage, WorldData worlddata, DimensionManager dimensionmanager, GameProfilerFiller gameprofilerfiller, WorldLoadListener worldloadlistener, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { - super(worlddata, dimensionmanager, executor, (world, worldprovider) -> { // Paper - pass executor down -@@ -0,0 +0,0 @@ public class WorldServer extends World { - this.pvpMode = minecraftserver.getPVP(); - worlddata.world = this; + // Add env and gen to constructor, WorldData -> WorldDataServer + public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey resourcekey, ResourceKey resourcekey1, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { + super(iworlddataserver, resourcekey, resourcekey1, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env, executor); // Paper pass executor +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { + convertable = convertable_conversionsession; + uuid = WorldUUID.getUUID(convertable_conversionsession.folder.toFile()); // CraftBukkit end - this.nextTickListBlock = new TickListServer<>(this, (block) -> { - return block == null || block.getBlockData().isAir(); -- }, IRegistry.BLOCK::getKey, IRegistry.BLOCK::get, this::b, "Blocks"); // Paper - Timings +- }, IRegistry.BLOCK::getKey, this::b, "Blocks"); // Paper - Timings - this.nextTickListFluid = new TickListServer<>(this, (fluidtype) -> { - return fluidtype == null || fluidtype == FluidTypes.EMPTY; -- }, IRegistry.FLUID::getKey, IRegistry.FLUID::get, this::a, "Fluids"); // Paper - Timings +- }, IRegistry.FLUID::getKey, this::a, "Fluids"); // Paper - Timings + if (com.destroystokyo.paper.PaperConfig.useOptimizedTickList) { -+ this.nextTickListBlock = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (block) -> { // Paper - optimise TickListServer ++ this.nextTickListBlock = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (block) -> { + return block == null || block.getBlockData().isAir(); -+ }, IRegistry.BLOCK::getKey, IRegistry.BLOCK::get, this::b, "Blocks"); // Paper - Timings -+ this.nextTickListFluid = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (fluidtype) -> { // Paper - optimise TickListServer ++ }, IRegistry.BLOCK::getKey, this::b, "Blocks"); // Paper - Timings ++ this.nextTickListFluid = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (fluidtype) -> { + return fluidtype == null || fluidtype == FluidTypes.EMPTY; -+ }, IRegistry.FLUID::getKey, IRegistry.FLUID::get, this::a, "Fluids"); // Paper - Timings ++ }, IRegistry.FLUID::getKey, this::a, "Fluids"); // Paper - Timings + } else { -+ this.nextTickListBlock = new TickListServer<>(this, (block) -> { // Paper - optimise TickListServer ++ this.nextTickListBlock = new TickListServer<>(this, (block) -> { + return block == null || block.getBlockData().isAir(); -+ }, IRegistry.BLOCK::getKey, IRegistry.BLOCK::get, this::b, "Blocks"); // Paper - Timings -+ this.nextTickListFluid = new TickListServer<>(this, (fluidtype) -> { // Paper - optimise TickListServer ++ }, IRegistry.BLOCK::getKey, this::b, "Blocks"); // Paper - Timings ++ this.nextTickListFluid = new TickListServer<>(this, (fluidtype) -> { + return fluidtype == null || fluidtype == FluidTypes.EMPTY; -+ }, IRegistry.FLUID::getKey, IRegistry.FLUID::get, this::a, "Fluids"); // Paper - Timings ++ }, IRegistry.FLUID::getKey, this::a, "Fluids"); // Paper - Timings + } -+ this.navigators = Sets.newHashSet(); - this.I = new ObjectLinkedOpenHashSet(); - this.dataManager = worldnbtstorage; + this.L = new ObjectLinkedOpenHashSet(); + this.Q = flag1; diff --git a/Spigot-Server-Patches/Optimise-random-block-ticking.patch b/Spigot-Server-Patches/Optimise-random-block-ticking.patch index 28e598f7b2..23a930b1be 100644 --- a/Spigot-Server-Patches/Optimise-random-block-ticking.patch +++ b/Spigot-Server-Patches/Optimise-random-block-ticking.patch @@ -70,39 +70,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return fastRandomBounded(this.next(32) & 0xFFFFFFFFL, bound); + } +} -diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/Block.java -+++ b/src/main/java/net/minecraft/server/Block.java -@@ -0,0 +0,0 @@ public class Block implements IMaterial { - return iblockdata.d(iblockaccess, blockposition, EnumDirection.UP) && this.n < 14; - } - -- @Deprecated -- public boolean d(IBlockData iblockdata) { -+ public final boolean isAir(IBlockData iblockdata) { return this.d(iblockdata); } // Paper - OBFHELPER -+ @Deprecated public boolean d(IBlockData iblockdata) { // Paper - OBFHELPER - return false; - } - -diff --git a/src/main/java/net/minecraft/server/BlockFluids.java b/src/main/java/net/minecraft/server/BlockFluids.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/BlockFluids.java -+++ b/src/main/java/net/minecraft/server/BlockFluids.java -@@ -0,0 +0,0 @@ public class BlockFluids extends Block implements IFluidSource { - - @Override - public void b(IBlockData iblockdata, WorldServer worldserver, BlockPosition blockposition, Random random) { -- worldserver.getFluid(blockposition).b(worldserver, blockposition, random); -+ iblockdata.getFluid().b(worldserver, blockposition, random); // Paper - avoid getType call - } - - @Override diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/BlockPosition.java +++ b/src/main/java/net/minecraft/server/BlockPosition.java -@@ -0,0 +0,0 @@ public class BlockPosition extends BaseBlockPosition implements MinecraftSeriali +@@ -0,0 +0,0 @@ public class BlockPosition extends BaseBlockPosition { return this.d(MathHelper.floor(d0), MathHelper.floor(d1), MathHelper.floor(d2)); } @@ -119,9 +91,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - @Override -- public int a(HeightMap.Type heightmap_type, int i, int j) { -+ public int getHighestBlockY(HeightMap.Type heightmap_type, int i, int j) { return this.a(heightmap_type, i, j) + 1; } // Paper - sort of an obfhelper, but without -1 -+ @Override public int a(HeightMap.Type heightmap_type, int i, int j) { // Paper +- public int getHighestBlock(HeightMap.Type heightmap_type, int i, int j) { ++ public final int getHighestBlockY(HeightMap.Type heightmap_type, int i, int j) { return this.getHighestBlock(heightmap_type, i, j) + 1; } // Paper - sort of an obfhelper, but without -1 ++ @Override public int getHighestBlock(HeightMap.Type heightmap_type, int i, int j) { // Paper return ((HeightMap) this.heightMap.get(heightmap_type)).a(i & 15, j & 15) - 1; } @@ -148,7 +120,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public ChunkSection(int i, IChunkAccess chunk, World world, boolean initializeBlocks) { @@ -0,0 +0,0 @@ public class ChunkSection { --this.nonEmptyBlockCount; - if (iblockdata1.q()) { + if (iblockdata1.isTicking()) { --this.tickingBlockCount; + // Paper start + this.tickingList.remove(i, j, k); @@ -158,7 +130,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ChunkSection { ++this.nonEmptyBlockCount; - if (iblockdata.q()) { + if (iblockdata.isTicking()) { ++this.tickingBlockCount; + // Paper start + this.tickingList.add(i, j, k, iblockdata); @@ -182,10 +154,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!iblockdata.isAir()) { - this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + i); -+ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); // Paper - if (iblockdata.q()) { ++ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); + if (iblockdata.isTicking()) { - this.tickingBlockCount = (short) (this.tickingBlockCount + i); -+ this.tickingBlockCount = (short) (this.tickingBlockCount + 1); // Paper ++ this.tickingBlockCount = (short) (this.tickingBlockCount + 1); + // Paper start + this.tickingList.add(location, iblockdata); + // Paper end @@ -194,10 +166,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!fluid.isEmpty()) { - this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + i); -+ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); // Paper - if (fluid.h()) { ++ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); + if (fluid.f()) { - this.e = (short) (this.e + i); -+ this.e = (short) (this.e + 1); // Paper ++ this.e = (short) (this.e + 1); } } @@ -206,41 +178,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/DataBits.java +++ b/src/main/java/net/minecraft/server/DataBits.java @@ -0,0 +0,0 @@ public class DataBits { - } + } + + // Paper start + public final void forEach(DataBitConsumer consumer) { -+ // Note: copied from above -+ int i = this.a.length; ++ int i = 0; ++ long[] along = this.b; ++ int j = along.length; + -+ if (i != 0) { -+ int j = 0; -+ long k = this.a[0]; -+ long l = i > 1 ? this.a[1] : 0L; ++ for (int k = 0; k < j; ++k) { ++ long l = along[k]; + -+ for (int i1 = 0; i1 < this.d; ++i1) { -+ int j1 = i1 * this.b; -+ int k1 = j1 >> 6; -+ int l1 = (i1 + 1) * this.b - 1 >> 6; -+ int i2 = j1 ^ k1 << 6; -+ -+ if (k1 != j) { -+ k = l; -+ l = k1 + 1 < i ? this.a[k1 + 1] : 0L; -+ j = k1; -+ } -+ -+ if (k1 == l1) { -+ consumer.accept(i1, (int) (k >>> i2 & this.c)); -+ } else { -+ int j2 = 64 - i2; -+ -+ consumer.accept(i1, (int) ((k >>> i2 | l << j2) & this.c)); ++ for (int i1 = 0; i1 < this.f; ++i1) { ++ consumer.accept(i, (int) (l & this.d)); ++ l >>= this.c; ++ ++i; ++ if (i >= this.e) { ++ return; + } + } -+ + } + } + @@ -277,72 +235,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/EntityTurtle.java @@ -0,0 +0,0 @@ public class EntityTurtle extends EntityAnimal { - public final void setHome(BlockPosition pos) { g(pos); } // Paper - OBFHELPER - public void g(BlockPosition blockposition) { -- this.datawatcher.set(EntityTurtle.bx, blockposition); -+ this.datawatcher.set(EntityTurtle.bx, blockposition.immutableCopy()); // Paper - make sure home position can't change + public final void setHome(BlockPosition pos) { setHomePos(pos); } // Paper - OBFHELPER + public void setHomePos(BlockPosition blockposition) { +- this.datawatcher.set(EntityTurtle.bw, blockposition); ++ this.datawatcher.set(EntityTurtle.bw, blockposition.immutableCopy()); // Paper - called with mutablepos... } - - public final BlockPosition getHome() { return this.es(); } // Paper - OBFHELPER -diff --git a/src/main/java/net/minecraft/server/IBlockData.java b/src/main/java/net/minecraft/server/IBlockData.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/IBlockData.java -+++ b/src/main/java/net/minecraft/server/IBlockData.java -@@ -0,0 +0,0 @@ public class IBlockData extends BlockDataAbstract implements - private IBlockData.a c; - private final int d; - private final boolean e; -+ private final boolean isAir; // Paper -+ private final boolean isTicking; // Paper - - public IBlockData(Block block, ImmutableMap, Comparable> immutablemap) { - super(block, immutablemap); - this.d = block.a(this); - this.e = block.o(this); -+ this.isAir = this.getBlock().isAir(this); // Paper -+ this.isTicking = this.getBlock().isTicking(this); // Paper - } - - public void c() { -@@ -0,0 +0,0 @@ public class IBlockData extends BlockDataAbstract implements - return this.d; - } - -- public boolean isAir() { -- return this.getBlock().d(this); -+ public final boolean isAir() { // Paper - compile fail if the impl changes -+ return this.isAir; // Paper - improve inlining of isAir - } - - public MaterialMapColor c(IBlockAccess iblockaccess, BlockPosition blockposition) { -@@ -0,0 +0,0 @@ public class IBlockData extends BlockDataAbstract implements - return this.getBlock().a(tag); - } - -+ private Fluid fluidData; // Paper - cache result - public Fluid getFluid() { -- return this.getBlock().a_(this); -+ // Paper start -+ // This can't be done during the constructor, order issues -+ if (this.fluidData != null) { -+ return this.fluidData; -+ } -+ return this.fluidData = this.getBlock().a_(this); -+ // Paper end - } - - public boolean q() { -- return this.getBlock().isTicking(this); -+ return this.isTicking; // Paper - } - - public final SoundEffectType getStepSound() { return this.r(); } // Paper - OBFHELPER + // TODO Paper: Obf helpers here can prolly be removed? check that no newer patches use them + public final BlockPosition getHome() { return this.getHomePos(); } // Paper - OBFHELPER diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, AutoCloseable { - public abstract TagRegistry t(); + public abstract TagRegistry p(); public BlockPosition a(int i, int j, int k, int l) { + // Paper start - allow use of mutable pos @@ -350,11 +255,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.getRandomBlockPosition(i, j, k, l, ret); + return ret.immutableCopy(); + } -+ + public final BlockPosition.MutableBlockPosition getRandomBlockPosition(int i, int j, int k, int l, BlockPosition.MutableBlockPosition out) { + // Paper end - this.i = this.i * 3 + 1013904223; - int i1 = this.i >> 2; + this.n = this.n * 3 + 1013904223; + int i1 = this.n >> 2; - return new BlockPosition(i + (i1 & 15), j + (i1 >> 16 & l), k + (i1 >> 8 & 15)); + out.setValues(i + (i1 & 15), j + (i1 >> 16 & l), k + (i1 >> 8 & 15)); // Paper - change to setValues call @@ -366,7 +270,7 @@ diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { }); } @@ -380,21 +284,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); boolean flag = this.isRaining(); int j = chunkcoordintpair.d(); -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { GameProfilerFiller gameprofilerfiller = this.getMethodProfiler(); gameprofilerfiller.enter("thunder"); - BlockPosition blockposition; + final BlockPosition.MutableBlockPosition blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change -- if (!this.paperConfig.disableThunder && flag && this.U() && this.random.nextInt(100000) == 0) { // Paper - Disable thunder + if (!this.paperConfig.disableThunder && flag && this.T() && this.random.nextInt(100000) == 0) { // Paper - Disable thunder - blockposition = this.a(this.a(j, 0, k, 15)); -+ if (!this.paperConfig.disableThunder && flag && this.U() && this.randomTickRandom.nextInt(100000) == 0) { // Paper - Disable thunder // Paper - optimise random ticking -+ blockposition.setValues(this.a(this.getRandomBlockPosition(j, 0, k, 15, blockposition))); // Paper ++ blockposition.setValues(this.a(this.a(j, 0, k, 15))); // Paper if (this.isRainingAt(blockposition)) { DifficultyDamageScaler difficultydamagescaler = this.getDamageScaler(blockposition); boolean flag1 = this.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.b() * paperConfig.skeleHorseSpawnChance; // Paper -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { } gameprofilerfiller.exitEnter("iceandsnow"); @@ -469,10 +372,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + continue; + } -- if (iblockdata.q()) { -- iblockdata.getBlock().randomTick = true; // Paper - fix MC-113809 +- if (iblockdata.isTicking()) { - iblockdata.b(this, blockposition2, this.random); -- iblockdata.getBlock().randomTick = false; // Paper - fix MC-113809 - } + long raw = section.tickingList.getRaw(index); + int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); @@ -484,12 +385,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + BlockPosition blockposition2 = blockposition.setValues(j + randomX, randomY, k + randomZ); + IBlockData iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); -- if (fluid.h()) { +- if (fluid.f()) { - fluid.b(this, blockposition2, this.random); - } -+ iblockdata.getBlock().randomTick = true; // Paper - fix MC-113809 + iblockdata.b(this, blockposition2, this.randomTickRandom); -+ iblockdata.getBlock().randomTick = false; // Paper - fix MC-113809 - gameprofilerfiller.exit(); - } diff --git a/Spigot-Server-Patches/Optimize-Hoppers.patch b/Spigot-Server-Patches/Optimize-Hoppers.patch index 9bed81874a..47ee597893 100644 --- a/Spigot-Server-Patches/Optimize-Hoppers.patch +++ b/Spigot-Server-Patches/Optimize-Hoppers.patch @@ -43,14 +43,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 World getWorld(); + default BlockPosition getBlockPosition() { return new BlockPosition(getX(), getY(), getZ()); } // Paper +- double x(); ++ double x(); default double getX() { return this.x(); } // Paper - OBFHELPER + - double z(); -+ double z();default double getX() { return z(); } // Paper - OBFHELPER ++ double z(); default double getY() { return this.z(); } // Paper - OBFHELPER - double A(); -+ double A();default double getY() { return A(); } // Paper - OBFHELPER - -- double B(); -+ double B();default double getZ() { return B(); } // Paper - OBFHELPER ++ double A(); default double getZ() { return this.A(); } // Paper - OBFHELPER } diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -65,25 +65,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public ItemStack cloneItemStack() { return cloneItemStack(false); } // Paper + public ItemStack cloneItemStack(boolean origItem) { // Paper + if (!origItem && this.isEmpty()) { // Paper - return ItemStack.a; + return ItemStack.b; } else { - ItemStack itemstack = new ItemStack(this.getItem(), this.count); + ItemStack itemstack = new ItemStack(origItem ? this.item : this.getItem(), this.count); // Paper - itemstack.d(this.C()); + itemstack.d(this.D()); if (this.tag != null) { 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 +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 0; // Paper + TileEntityHopper.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - if (true || worldserver.worldProvider.getDimensionManager() == DimensionManager.OVERWORLD || this.getAllowNether()) { // CraftBukkit - this.methodProfiler.a(() -> { - return worldserver.getWorldData().getName() + " " + IRegistry.DIMENSION_TYPE.getKey(worldserver.worldProvider.getDimensionManager()); + + this.methodProfiler.a(() -> { + return worldserver + " " + worldserver.getDimensionKey().a(); diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/TileEntity.java @@ -266,8 +266,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end + - private boolean j() { - IInventory iinventory = this.k(); + private boolean k() { + IInventory iinventory = this.l(); @@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi if (this.b(iinventory, enumdirection)) { @@ -412,15 +412,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + IGNORE_TILE_UPDATES = true; // Paper iinventory1.setItem(i, itemstack); + IGNORE_TILE_UPDATES = false; // Paper - itemstack = ItemStack.a; + itemstack = ItemStack.b; flag = true; } else if (a(itemstack1, itemstack)) { @@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi } public static List c(IHopper ihopper) { -- return (List) ihopper.P_().d().stream().flatMap((axisalignedbb) -> { -- return ihopper.getWorld().a(EntityItem.class, axisalignedbb.d(ihopper.z() - 0.5D, ihopper.A() - 0.5D, ihopper.B() - 0.5D), IEntitySelector.a).stream(); +- return (List) ihopper.ac_().d().stream().flatMap((axisalignedbb) -> { +- return ihopper.getWorld().a(EntityItem.class, axisalignedbb.d(ihopper.x() - 0.5D, ihopper.z() - 0.5D, ihopper.A() - 0.5D), IEntitySelector.a).stream(); - }).collect(Collectors.toList()); + // Paper start - Optimize item suck in. remove streams, restore 1.12 checks. Seriously checking the bowl?! + World world = ihopper.getWorld(); diff --git a/Spigot-Server-Patches/Optimize-call-to-getFluid-for-explosions.patch b/Spigot-Server-Patches/Optimize-call-to-getFluid-for-explosions.patch index 72644f1c98..5e9e7cb003 100644 --- a/Spigot-Server-Patches/Optimize-call-to-getFluid-for-explosions.patch +++ b/Spigot-Server-Patches/Optimize-call-to-getFluid-for-explosions.patch @@ -14,6 +14,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 IBlockData iblockdata = this.world.getType(blockposition); - Fluid fluid = this.world.getFluid(blockposition); + Fluid fluid = iblockdata.getFluid(); // Paper + Optional optional = this.k.a(this, this.world, blockposition, iblockdata, fluid); - if (!iblockdata.isAir() || !fluid.isEmpty()) { - float f2 = Math.max(iblockdata.getBlock().getDurability(), fluid.k()); + if (optional.isPresent()) { diff --git a/Spigot-Server-Patches/Pillager-patrol-spawn-settings-and-per-player-option.patch b/Spigot-Server-Patches/Pillager-patrol-spawn-settings-and-per-player-option.patch index b3a0997d20..bad4373f6b 100644 --- a/Spigot-Server-Patches/Pillager-patrol-spawn-settings-and-per-player-option.patch +++ b/Spigot-Server-Patches/Pillager-patrol-spawn-settings-and-per-player-option.patch @@ -53,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/MobSpawnerPatrol.java @@ -0,0 +0,0 @@ import java.util.Random; - public class MobSpawnerPatrol { + public class MobSpawnerPatrol implements MobSpawner { + private int getSpawnDelay() { return a; } // Paper - OBFHELPER + private void setSpawnDelay(int spawnDelay) { this.a = spawnDelay; } // Paper - OBFHELPER @@ -61,13 +61,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public MobSpawnerPatrol() {} + @Override public int a(WorldServer worldserver, boolean flag, boolean flag1) { - if (worldserver.paperConfig.disablePillagerPatrols) return 0; // Paper + if (worldserver.paperConfig.disablePillagerPatrols || worldserver.paperConfig.patrolSpawnChance == 0) return 0; // Paper if (!flag) { return 0; } else if (!worldserver.getGameRules().getBoolean(GameRules.DO_PATROL_SPAWNING)) { -@@ -0,0 +0,0 @@ public class MobSpawnerPatrol { +@@ -0,0 +0,0 @@ public class MobSpawnerPatrol implements MobSpawner { } else { Random random = worldserver.random; diff --git a/Spigot-Server-Patches/PlayerDeathEvent-shouldDropExperience.patch b/Spigot-Server-Patches/PlayerDeathEvent-shouldDropExperience.patch index 0c8021baf9..dc279458f3 100644 --- a/Spigot-Server-Patches/PlayerDeathEvent-shouldDropExperience.patch +++ b/Spigot-Server-Patches/PlayerDeathEvent-shouldDropExperience.patch @@ -9,8 +9,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/EntityPlayer.java @@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting { - - this.releaseShoulderEntities(); + this.eW(); + } // SPIGOT-5478 must be called manually now - this.dropExperience(); + if (event.shouldDropExperience()) this.dropExperience(); // Paper - tie to event diff --git a/Spigot-Server-Patches/PlayerLaunchProjectileEvent.patch b/Spigot-Server-Patches/PlayerLaunchProjectileEvent.patch index 8f81dd5b77..0e9d0ac723 100644 --- a/Spigot-Server-Patches/PlayerLaunchProjectileEvent.patch +++ b/Spigot-Server-Patches/PlayerLaunchProjectileEvent.patch @@ -49,7 +49,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + } - world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_EGG_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemEgg.i.nextFloat() * 0.4F + 0.8F)); // CraftBukkit - from above + world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_EGG_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemEgg.RANDOM.nextFloat() * 0.4F + 0.8F)); // CraftBukkit - from above + /* // Paper start - moved up entityhuman.b(StatisticList.ITEM_USED.b(this)); @@ -58,7 +58,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + */ // Paper end - return InteractionResultWrapper.success(itemstack); + return InteractionResultWrapper.a(itemstack, world.s_()); } diff --git a/src/main/java/net/minecraft/server/ItemEnderPearl.java b/src/main/java/net/minecraft/server/ItemEnderPearl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -91,7 +91,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -- world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemEnderPearl.i.nextFloat() * 0.4F + 0.8F)); +- world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemEnderPearl.RANDOM.nextFloat() * 0.4F + 0.8F)); - entityhuman.getCooldownTracker().setCooldown(this, 20); - // CraftBukkit end - @@ -100,7 +100,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - itemstack.subtract(1); - } + // Paper start - moved up -+// world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemEnderPearl.i.nextFloat() * 0.4F + 0.8F)); ++// world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemEnderPearl.RANDOM.nextFloat() * 0.4F + 0.8F)); +// entityhuman.getCooldownTracker().setCooldown(this, 20); +// // CraftBukkit end +// @@ -108,9 +108,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +// if (!entityhuman.abilities.canInstantlyBuild) { +// itemstack.subtract(1); +// } -+ // Paper end ++ // Paper end - moved up - return InteractionResultWrapper.success(itemstack); + return InteractionResultWrapper.a(itemstack, world.s_()); } diff --git a/src/main/java/net/minecraft/server/ItemExpBottle.java b/src/main/java/net/minecraft/server/ItemExpBottle.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -120,8 +120,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public InteractionResultWrapper a(World world, EntityHuman entityhuman, EnumHand enumhand) { ItemStack itemstack = entityhuman.b(enumhand); -- world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_EXPERIENCE_BOTTLE_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemExpBottle.i.nextFloat() * 0.4F + 0.8F)); -+// world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_EXPERIENCE_BOTTLE_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemExpBottle.i.nextFloat() * 0.4F + 0.8F)); // Paper - moved down +- world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_EXPERIENCE_BOTTLE_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemExpBottle.RANDOM.nextFloat() * 0.4F + 0.8F)); ++ //world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_EXPERIENCE_BOTTLE_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemExpBottle.RANDOM.nextFloat() * 0.4F + 0.8F)); // Paper - moved down if (!world.isClientSide) { EntityThrownExpBottle entitythrownexpbottle = new EntityThrownExpBottle(world, entityhuman); @@ -155,7 +155,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + */ // Paper end - return InteractionResultWrapper.success(itemstack); + return InteractionResultWrapper.a(itemstack, world.s_()); } diff --git a/src/main/java/net/minecraft/server/ItemLingeringPotion.java b/src/main/java/net/minecraft/server/ItemLingeringPotion.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -165,12 +165,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public InteractionResultWrapper a(World world, EntityHuman entityhuman, EnumHand enumhand) { -- world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_LINGERING_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemLingeringPotion.i.nextFloat() * 0.4F + 0.8F)); +- world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_LINGERING_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemLingeringPotion.RANDOM.nextFloat() * 0.4F + 0.8F)); - return super.a(world, entityhuman, enumhand); + // Paper start + InteractionResultWrapper wrapper = super.a(world, entityhuman, enumhand); -+ if (wrapper.getResult() != EnumInteractionResult.FAIL) -+ world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_LINGERING_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemLingeringPotion.i.nextFloat() * 0.4F + 0.8F)); ++ if (wrapper.getResult() != EnumInteractionResult.FAIL) { ++ world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_LINGERING_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemLingeringPotion.RANDOM.nextFloat() * 0.4F + 0.8F)); ++ } + return wrapper; + // Paper end } @@ -210,7 +211,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + */ // Paper end - return InteractionResultWrapper.success(itemstack); + return InteractionResultWrapper.a(itemstack, world.s_()); } diff --git a/src/main/java/net/minecraft/server/ItemSnowball.java b/src/main/java/net/minecraft/server/ItemSnowball.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -226,30 +227,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitysnowball.getBukkitEntity()); + if (event.callEvent() && world.addEntity(entitysnowball)) { + if (event.shouldConsume() && !entityhuman.abilities.canInstantlyBuild) { ++ // Paper end itemstack.subtract(1); -+ } else if (entityhuman instanceof EntityPlayer) { -+ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } else if (entityhuman instanceof EntityPlayer) { // Paper ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); // Paper } -- world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemSnowball.i.nextFloat() * 0.4F + 0.8F)); + world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemSnowball.RANDOM.nextFloat() * 0.4F + 0.8F)); - } else if (entityhuman instanceof EntityPlayer) { - ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); -+ world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (Entity.SHARED_RANDOM.nextFloat() * 0.4F + 0.8F)); -+ entityhuman.b(StatisticList.ITEM_USED.b(this)); -+ } else { -+ if (entityhuman instanceof EntityPlayer) { -+ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); -+ } -+ return new InteractionResultWrapper(EnumInteractionResult.FAIL, itemstack); ++ } else { // Paper ++ if (entityhuman instanceof EntityPlayer) ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); // Paper ++ return new InteractionResultWrapper(EnumInteractionResult.FAIL, itemstack); // Paper } } // CraftBukkit end - -- entityhuman.b(StatisticList.ITEM_USED.b(this)); -+// entityhuman.b(StatisticList.ITEM_USED.b(this)); // Paper - moved up - // CraftBukkit start - moved up - /* - if (!entityhuman.abilities.canInstantlyBuild) { diff --git a/src/main/java/net/minecraft/server/ItemSplashPotion.java b/src/main/java/net/minecraft/server/ItemSplashPotion.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/ItemSplashPotion.java @@ -258,12 +250,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public InteractionResultWrapper a(World world, EntityHuman entityhuman, EnumHand enumhand) { -- world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_SPLASH_POTION_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemSplashPotion.i.nextFloat() * 0.4F + 0.8F)); -- return super.a(world, entityhuman, enumhand); + // Paper start + InteractionResultWrapper wrapper = super.a(world, entityhuman, enumhand); -+ if (wrapper.getResult() != EnumInteractionResult.FAIL) -+ world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_SPLASH_POTION_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemSplashPotion.i.nextFloat() * 0.4F + 0.8F)); ++ if (wrapper.getResult() != EnumInteractionResult.FAIL) { + world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_SPLASH_POTION_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemSplashPotion.RANDOM.nextFloat() * 0.4F + 0.8F)); +- return super.a(world, entityhuman, enumhand); ++ } + return wrapper; + // Paper end } diff --git a/Spigot-Server-Patches/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/Spigot-Server-Patches/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch index 3a3cd7a3c4..9b69cf36ed 100644 --- a/Spigot-Server-Patches/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch +++ b/Spigot-Server-Patches/Prevent-Double-PlayerChunkMap-adds-crashing-server.patch @@ -23,13 +23,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end if (!(entity instanceof EntityComplexPart)) { - if (!(entity instanceof EntityLightning)) { - EntityTypes entitytypes = entity.getEntityType(); + EntityTypes entitytypes = entity.getEntityType(); + int i = entitytypes.getChunkRange() * 16; diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { } } @@ -38,7 +38,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - SPIGOT-5278 if (entity instanceof EntityDrowned) { this.navigators.add(((EntityDrowned) entity).navigationWater); -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { this.navigators.add(((EntityInsentient) entity).getNavigation()); } entity.valid = true; // CraftBukkit diff --git a/Spigot-Server-Patches/Prevent-bees-loading-chunks-checking-hive-position.patch b/Spigot-Server-Patches/Prevent-bees-loading-chunks-checking-hive-position.patch index 82bb02aa0d..98f76a5752 100644 --- a/Spigot-Server-Patches/Prevent-bees-loading-chunks-checking-hive-position.patch +++ b/Spigot-Server-Patches/Prevent-bees-loading-chunks-checking-hive-position.patch @@ -8,7 +8,7 @@ diff --git a/src/main/java/net/minecraft/server/EntityBee.java b/src/main/java/n index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/EntityBee.java +++ b/src/main/java/net/minecraft/server/EntityBee.java -@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements EntityBird { +@@ -0,0 +0,0 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB if (!this.hasHivePos()) { return false; } else { diff --git a/Spigot-Server-Patches/Prevent-consuming-the-wrong-itemstack.patch b/Spigot-Server-Patches/Prevent-consuming-the-wrong-itemstack.patch index f93da9e66e..1104879e50 100644 --- a/Spigot-Server-Patches/Prevent-consuming-the-wrong-itemstack.patch +++ b/Spigot-Server-Patches/Prevent-consuming-the-wrong-itemstack.patch @@ -9,7 +9,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { - this.datawatcher.set(EntityLiving.ao, (byte) j); + this.datawatcher.set(EntityLiving.an, (byte) j); } - public void c(EnumHand enumhand) { @@ -22,10 +22,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (!itemstack.isEmpty() && !this.isHandRaised()) { + if (!itemstack.isEmpty() && !this.isHandRaised() || forceUpdate) { // Paper use override flag this.activeItem = itemstack; - this.bl = itemstack.k(); + this.bk = itemstack.k(); if (!this.world.isClientSide) { @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { - this.clearActiveItem(); + this.releaseActiveItem(); } else { if (!this.activeItem.isEmpty() && this.isHandRaised()) { + this.updateActiveItem(this.getRaisedHand(), true); // Paper @@ -35,7 +35,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity { this.a(this.getRaisedHand(), itemstack); // CraftBukkit end - this.dH(); + this.clearActiveItem(); - // Paper start - if the replacement is anything but the default, update the client inventory - if (this instanceof EntityPlayer && !com.google.common.base.Objects.equal(defaultReplacement, itemstack)) { + // Paper start diff --git a/Spigot-Server-Patches/Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch b/Spigot-Server-Patches/Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch index 18f6d0f99b..78f68b2fd3 100644 --- a/Spigot-Server-Patches/Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch +++ b/Spigot-Server-Patches/Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch @@ -9,12 +9,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/BehaviorSleep.java +++ b/src/main/java/net/minecraft/server/BehaviorSleep.java @@ -0,0 +0,0 @@ public class BehaviorSleep extends Behavior { - if (optional.isPresent() && worldserver.getTime() - ((MinecraftSerializableLong) optional.get()).a() < 100L) { - return false; - } else { -- IBlockData iblockdata = worldserver.getType(globalpos.getBlockPosition()); -+ IBlockData iblockdata = worldserver.getTypeIfLoaded(globalpos.getBlockPosition()); // Paper -+ if(iblockdata == null) return false; // Paper - - return globalpos.getBlockPosition().a((IPosition) entityliving.getPositionVector(), 2.0D) && iblockdata.getBlock().a(TagsBlock.BEDS) && !(Boolean) iblockdata.get(BlockBed.OCCUPIED); + } } + +- IBlockData iblockdata = worldserver.getType(globalpos.getBlockPosition()); ++ IBlockData iblockdata = worldserver.getTypeIfLoaded(globalpos.getBlockPosition()); // Paper ++ if (iblockdata == null) { return false; } // Paper + + return globalpos.getBlockPosition().a((IPosition) entityliving.getPositionVector(), 2.0D) && iblockdata.getBlock().a((Tag) TagsBlock.BEDS) && !(Boolean) iblockdata.get(BlockBed.OCCUPIED); + } diff --git a/Spigot-Server-Patches/Reduce-sync-loads.patch b/Spigot-Server-Patches/Reduce-sync-loads.patch index 6ba707db51..e2d7b7693f 100644 --- a/Spigot-Server-Patches/Reduce-sync-loads.patch +++ b/Spigot-Server-Patches/Reduce-sync-loads.patch @@ -267,7 +267,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final ThrowableWithEquals other = (ThrowableWithEquals)obj; + final StackTraceElement[] otherStackTrace = other.stacktrace; + -+ if (this.stacktrace.length != otherStackTrace.length) { ++ if (this.stacktrace.length != otherStackTrace.length || this.hash != other.hash) { + return false; + } + @@ -305,7 +305,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (int i1 = i; i1 <= j; ++i1) { for (int j1 = k; j1 <= l; ++j1) { -- Chunk chunk = this.getChunkProvider().getChunkAt(i1, j1, false); +- Chunk chunk = ichunkprovider.getChunkAt(i1, j1, false); + Chunk chunk = (Chunk)this.getChunkIfLoadedImmediately(i1, j1); // Paper if (chunk != null) { @@ -332,7 +332,7 @@ diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { }; public final com.destroystokyo.paper.io.chunk.ChunkTaskManager asyncChunkTaskManager; // Paper end @@ -343,5 +343,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - // Add env and gen to constructor - public WorldServer(MinecraftServer minecraftserver, Executor executor, WorldNBTStorage worldnbtstorage, WorldData worlddata, DimensionManager dimensionmanager, GameProfilerFiller gameprofilerfiller, WorldLoadListener worldloadlistener, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { + // Add env and gen to constructor, WorldData -> WorldDataServer + public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey resourcekey, ResourceKey resourcekey1, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { diff --git a/Spigot-Server-Patches/Seed-based-feature-search.patch b/Spigot-Server-Patches/Seed-based-feature-search.patch deleted file mode 100644 index 30c0ee0347..0000000000 --- a/Spigot-Server-Patches/Seed-based-feature-search.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Mon, 13 Jan 2020 15:40:32 +0100 -Subject: [PATCH] Seed based feature search - -This fixes the issue where the server will load surrounding chunks up to -a radius of 100 chunks in order to search for features e.g. when running -the /locate command or for treasure maps (issue #2312). -This is done by using the same seed checking functionality that is used -by the server when generating these features before actually attempting -to load the chunk to check if a feature is available in it. - -The only downside of this is that it breaks once the seed or generator -changes but this should usually not happen. A config option to disable -this improvement is added though in case that should ever be necessary. - -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - -+ public boolean seedBasedFeatureSearch = true; -+ private void seedBasedFeatureSearch() { -+ seedBasedFeatureSearch = getBoolean("seed-based-feature-search", seedBasedFeatureSearch); -+ log("Feature search is based on seed: " + seedBasedFeatureSearch); -+ } -+ - public int maxCollisionsPerEntity; - private void maxEntityCollision() { - maxCollisionsPerEntity = getInt( "max-entity-collisions", this.spigotConfig.getInt("max-entity-collisions", 8) ); -diff --git a/src/main/java/net/minecraft/server/BiomeManager.java b/src/main/java/net/minecraft/server/BiomeManager.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/BiomeManager.java -+++ b/src/main/java/net/minecraft/server/BiomeManager.java -@@ -0,0 +0,0 @@ public class BiomeManager { - this.c = genlayerzoomer; - } - -+ public BiomeManager withProvider(WorldChunkManager worldchunkmanager) { return a(worldchunkmanager); } // Paper - OBFHELPER - public BiomeManager a(WorldChunkManager worldchunkmanager) { - return new BiomeManager(worldchunkmanager, this.b, this.c); - } - -+ public BiomeBase getBiome(BlockPosition blockposition) { return a(blockposition); } // Paper - OBFHELPER - public BiomeBase a(BlockPosition blockposition) { - return this.c.a(this.b, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.a); - } -diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java -+++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java -@@ -0,0 +0,0 @@ public class ChunkCoordIntPair { - } - } - -+ public int getBlockX() { return d(); } // Paper - OBFHELPER - public int d() { - return this.x << 4; - } - -+ public int getBlockZ() { return e(); } // Paper - OBFHELPER - public int e() { - return this.z << 4; - } -diff --git a/src/main/java/net/minecraft/server/StructureGenerator.java b/src/main/java/net/minecraft/server/StructureGenerator.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/StructureGenerator.java -+++ b/src/main/java/net/minecraft/server/StructureGenerator.java -@@ -0,0 +0,0 @@ public abstract class StructureGenerator - if (flag1 || flag2) { - ChunkCoordIntPair chunkcoordintpair = this.a(chunkgenerator, seededrandom, j, k, i1, j1); - if (!world.getWorldBorder().isChunkInBounds(chunkcoordintpair.x, chunkcoordintpair.z)) { continue; } // Paper -+ // Paper start - seed based feature search -+ if (world.paperConfig.seedBasedFeatureSearch) { -+ BiomeManager biomeManager = world.getBiomeManager().withProvider(chunkgenerator.getWorldChunkManager()); -+ BiomeBase biomeBase = biomeManager.getBiome(new BlockPosition(chunkcoordintpair.getBlockX() + 9, 0, chunkcoordintpair.getBlockZ() + 9)); -+ if (!shouldGenerate(biomeManager, chunkgenerator, seededrandom, chunkcoordintpair.x, chunkcoordintpair.z, biomeBase)) { -+ continue; -+ } -+ } -+ // Paper end - StructureStart structurestart = world.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z, ChunkStatus.STRUCTURE_STARTS).a(this.b()); - - if (structurestart != null && structurestart.e()) { -@@ -0,0 +0,0 @@ public abstract class StructureGenerator - return new ChunkCoordIntPair(i + k, j + l); - } - -+ public boolean shouldGenerate(BiomeManager biomemanager, ChunkGenerator chunkgenerator, Random random, int chunkX, int chunkZ, BiomeBase biomebase) { return a(biomemanager, chunkgenerator, random, chunkX, chunkZ, biomebase); } // Paper - OBFHELPER - public abstract boolean a(BiomeManager biomemanager, ChunkGenerator chunkgenerator, Random random, int i, int j, BiomeBase biomebase); - - public abstract StructureGenerator.a a(); -diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/World.java -+++ b/src/main/java/net/minecraft/server/World.java -@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, AutoCloseable { - return this.methodProfiler; - } - -- @Override -- public BiomeManager d() { -+ public BiomeManager getBiomeManager() { return d(); } // Paper - OBFHELPER -+ @Override public BiomeManager d() { - return this.biomeManager; - } - } diff --git a/Spigot-Server-Patches/Synchronize-DataPaletteBlock-instead-of-ReentrantLoc.patch b/Spigot-Server-Patches/Synchronize-DataPaletteBlock-instead-of-ReentrantLoc.patch index 548f86bdf4..6599ac8f3e 100644 --- a/Spigot-Server-Patches/Synchronize-DataPaletteBlock-instead-of-ReentrantLoc.patch +++ b/Spigot-Server-Patches/Synchronize-DataPaletteBlock-instead-of-ReentrantLoc.patch @@ -88,7 +88,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - public void a(NBTTagList nbttaglist, long[] along) { + public synchronized void a(NBTTagList nbttaglist, long[] along) { // Paper - synchronize this.a(); - int i = Math.max(4, MathHelper.d(nbttaglist.size())); + int i = Math.max(4, MathHelper.e(nbttaglist.size())); @@ -0,0 +0,0 @@ public class DataPaletteBlock implements DataPaletteExpandable { this.b(); diff --git a/Spigot-Server-Patches/Use-ChunkStatus-cache-when-saving-protochunks.patch b/Spigot-Server-Patches/Use-ChunkStatus-cache-when-saving-protochunks.patch deleted file mode 100644 index 0b162327c6..0000000000 --- a/Spigot-Server-Patches/Use-ChunkStatus-cache-when-saving-protochunks.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 22 Jun 2019 04:20:47 -0700 -Subject: [PATCH] Use ChunkStatus cache when saving protochunks - -The cache should contain the chunk status when saving. If not it -will load it. - -diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/PlayerChunkMap.java -+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java -@@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { - NBTTagCompound nbttagcompound; - - if (chunkstatus.getType() != ChunkStatus.Type.LEVELCHUNK) { -- nbttagcompound = this.readChunkData(chunkcoordintpair); -- if (nbttagcompound != null && ChunkRegionLoader.a(nbttagcompound) == ChunkStatus.Type.LEVELCHUNK) { -+ // Paper start - Optimize save by using status cache -+ ChunkStatus statusOnDisk = this.getChunkStatusOnDisk(chunkcoordintpair); -+ if (statusOnDisk != null && statusOnDisk.getType() == ChunkStatus.Type.LEVELCHUNK) { -+ // Paper end - return false; - } - diff --git a/Spigot-Server-Patches/Use-getChunkIfLoadedImmediately-in-places.patch b/Spigot-Server-Patches/Use-getChunkIfLoadedImmediately-in-places.patch index 48fd517b67..553fb38569 100644 --- a/Spigot-Server-Patches/Use-getChunkIfLoadedImmediately-in-places.patch +++ b/Spigot-Server-Patches/Use-getChunkIfLoadedImmediately-in-places.patch @@ -25,39 +25,35 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + return (CraftServer) Bukkit.getServer(); } - public Chunk getChunkIfLoaded(int x, int z) { -- return ((ChunkProviderServer) this.chunkProvider).getChunkAt(x, z, false); -+ return ((ChunkProviderServer) this.chunkProvider).getChunkAtIfLoadedImmediately(x, z); // Paper - } + // Paper start + @Override + public boolean isChunkLoaded(int x, int z) { -+ return getChunkIfLoaded(x, z) != null; ++ return ((WorldServer)this).getChunkIfLoaded(x, z) != null; + } -+ -+ + // Paper end - - protected World(WorldData worlddata, DimensionManager dimensionmanager, java.util.concurrent.Executor executor, BiFunction bifunction, GameProfilerFiller gameprofilerfiller, boolean flag, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) { // Paper - executor - this.spigotConfig = new org.spigotmc.SpigotWorldConfig( worlddata.getName() ); // Spigot ++ + protected World(WorldDataMutable worlddatamutable, ResourceKey resourcekey, ResourceKey resourcekey1, DimensionManager dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((WorldDataServer) worlddatamutable).getName()); // Spigot + this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig((((WorldDataServer)worlddatamutable).getName()), this.spigotConfig); // Paper @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, AutoCloseable { } - public boolean n(BlockPosition blockposition) { -- return isOutsideWorld(blockposition) ? false : this.chunkProvider.b(blockposition.getX() >> 4, blockposition.getZ() >> 4); + public boolean p(BlockPosition blockposition) { +- return isOutsideWorld(blockposition) ? false : this.getChunkProvider().b(blockposition.getX() >> 4, blockposition.getZ() >> 4); + return isOutsideWorld(blockposition) ? false : isChunkLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4); // Paper } - public boolean a(BlockPosition blockposition, Entity entity) { + public boolean a(BlockPosition blockposition, Entity entity, EnumDirection enumdirection) { if (isOutsideWorld(blockposition)) { return false; } else { - IChunkAccess ichunkaccess = this.getChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4, ChunkStatus.FULL, false); + IChunkAccess ichunkaccess = this.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4); // Paper - return ichunkaccess == null ? false : ichunkaccess.getType(blockposition).a((IBlockAccess) this, blockposition, entity); + return ichunkaccess == null ? false : ichunkaccess.getType(blockposition).a((IBlockAccess) this, blockposition, entity, enumdirection); } @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, AutoCloseable { @@ -68,6 +64,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (chunk != null) { chunk.a(oclass, axisalignedbb, list, predicate); +diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/WorldServer.java ++++ b/src/main/java/net/minecraft/server/WorldServer.java +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { + } + + public Chunk getChunkIfLoaded(int x, int z) { +- return this.chunkProvider.getChunkAt(x, z, false); ++ return this.chunkProvider.getChunkAtIfLoadedImmediately(x, z); // Paper + } + + // Paper start - Asynchronous IO diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java diff --git a/Spigot-Server-Patches/implement-optional-per-player-mob-spawns.patch b/Spigot-Server-Patches/implement-optional-per-player-mob-spawns.patch index ba76ab638e..f3e456e258 100644 --- a/Spigot-Server-Patches/implement-optional-per-player-mob-spawns.patch +++ b/Spigot-Server-Patches/implement-optional-per-player-mob-spawns.patch @@ -549,12 +549,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -0,0 +0,0 @@ public class ChunkProviderServer extends IChunkProvider { + this.world.getMethodProfiler().enter("naturalSpawnCount"); this.world.timings.countNaturalMobs.startTiming(); // Paper - timings int l = this.chunkMapDistance.b(); - EnumCreatureType[] aenumcreaturetype = EnumCreatureType.values(); -- Object2IntMap object2intmap = this.world.l(); +- SpawnerCreature.d spawnercreature_d = SpawnerCreature.a(l, this.world.z(), this::a); + // Paper start - per player mob spawning -+ int[] worldMobCount; ++ SpawnerCreature.d spawnercreature_d; // moved down + if (this.playerChunkMap.playerMobDistanceMap != null) { + // update distance map + this.world.timings.playerMobDistanceMapUpdate.startTiming(); @@ -564,40 +564,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + for (EntityPlayer player : this.world.players) { + Arrays.fill(player.mobCounts, 0); + } -+ worldMobCount = this.world.countMobs(true); ++ spawnercreature_d = SpawnerCreature.countMobs(l, this.world.z(), this::a, true); + } else { -+ worldMobCount = this.world.countMobs(false); ++ spawnercreature_d = SpawnerCreature.countMobs(l, this.world.z(), this::a, false); + } + // Paper end - this.world.timings.countNaturalMobs.stopTiming(); // Paper - timings - this.world.getMethodProfiler().exit(); -@@ -0,0 +0,0 @@ public class ChunkProviderServer extends IChunkProvider { - if (enumcreaturetype != EnumCreatureType.MISC && (!enumcreaturetype.c() || this.allowAnimals) && (enumcreaturetype.c() || this.allowMonsters) && (!enumcreaturetype.d() || flag2)) { - int k1 = limit * l / ChunkProviderServer.b; // CraftBukkit - use per-world limits -- if (object2intmap.getInt(enumcreaturetype) <= k1) { -- SpawnerCreature.a(enumcreaturetype, this.world, chunk, blockposition); -+ // Paper start - only allow spawns upto the limit per chunk and update count afterwards -+ int currEntityCount = worldMobCount[enumcreaturetype.ordinal()]; -+ int difference = k1 - currEntityCount; -+ -+ if (this.world.paperConfig.perPlayerMobSpawns) { -+ int minDiff = Integer.MAX_VALUE; -+ for (EntityPlayer entityplayer : this.playerChunkMap.playerMobDistanceMap.getPlayersInRange(chunk.getPos())) { -+ minDiff = Math.min(limit - this.playerChunkMap.getMobCountNear(entityplayer, enumcreaturetype), minDiff); -+ } -+ difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff; -+ } -+ -+ if (difference > 0) { -+ int spawnCount = SpawnerCreature.spawnMobs(enumcreaturetype, this.world, chunk, blockposition, difference, -+ this.world.paperConfig.perPlayerMobSpawns ? this.playerChunkMap::updatePlayerMobTypeMap : null); -+ worldMobCount[enumcreaturetype.ordinal()] += spawnCount; -+ // Paper end - } - } - } + this.p = spawnercreature_d; diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/EntityPlayer.java @@ -626,30 +600,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } -+ public SectionPosition getPlayerMapSection() { return this.K(); } // Paper - OBFHELPER - public SectionPosition K() { - return this.cs; ++ public final SectionPosition getPlayerMapSection() { return this.N(); } // Paper - OBFHELPER + public SectionPosition N() { + return this.cq; } diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/EntityTypes.java +++ b/src/main/java/net/minecraft/server/EntityTypes.java @@ -0,0 +0,0 @@ public class EntityTypes { - return this.bf; + return this.bk; } -+ public EnumCreatureType getEnumCreatureType() { return this.e(); } // Paper - OBFHELPER ++ public final EnumCreatureType getEnumCreatureType() { return this.e(); } // Paper - OBFHELPER public EnumCreatureType e() { - return this.bb; + return this.bf; } diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { - private final PlayerMap playerMap; public final Int2ObjectMap trackedEntities; - private final Queue z; + private final Long2ByteMap z; + private final Queue A; private final Queue getUnloadQueueTasks() { return this.A; } // Paper - OBFHELPER - private int viewDistance; + int viewDistance; // Paper - private -> package private + public final com.destroystokyo.paper.util.PlayerMobDistanceMap playerMobDistanceMap; // Paper @@ -658,7 +632,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public final CallbackExecutor callbackExecutor = new CallbackExecutor(); @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { this.l = supplier; - this.m = new VillagePlace(new File(this.w, "poi"), datafixer, this.world); // Paper + this.m = new VillagePlace(new File(this.w, "poi"), datafixer, flag, this.world); // Paper this.setViewDistance(i); + this.playerMobDistanceMap = this.world.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.PlayerMobDistanceMap() : null; // Paper + } @@ -685,117 +659,167 @@ diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/SpawnerCreature.java +++ b/src/main/java/net/minecraft/server/SpawnerCreature.java -@@ -0,0 +0,0 @@ package net.minecraft.server; - import java.util.List; - import java.util.Objects; - import java.util.Random; -+import java.util.function.Consumer; // Paper - import javax.annotation.Nullable; - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; @@ -0,0 +0,0 @@ public final class SpawnerCreature { + }); - private static final Logger LOGGER = LogManager.getLogger(); - -+ // Paper start - add maxSpawns parameter and return spawned mobs - public static void a(EnumCreatureType enumcreaturetype, WorldServer worldserver, Chunk chunk, BlockPosition blockposition) { -+ spawnMobs(enumcreaturetype, worldserver, chunk, blockposition, Integer.MAX_VALUE, null); + public static SpawnerCreature.d a(int i, Iterable iterable, SpawnerCreature.b spawnercreature_b) { ++ // Paper start - add countMobs parameter ++ return countMobs(i, iterable, spawnercreature_b, false); + } -+ public static int spawnMobs(EnumCreatureType enumcreaturetype, WorldServer worldserver, Chunk chunk, BlockPosition blockposition, int maxSpawns, Consumer trackEntity) { -+ // Paper end - ChunkGenerator chunkgenerator = worldserver.getChunkProvider().getChunkGenerator(); -- int i = 0; -+ int i = 0; // Paper - force diff on name change - BlockPosition blockposition1 = getRandomPosition(worldserver, chunk); - int j = blockposition1.getX(); - int k = blockposition1.getY(); -@@ -0,0 +0,0 @@ public final class SpawnerCreature { - ); - if (!event.callEvent()) { - if (event.shouldAbortSpawn()) { -- return; -+ return i; // Paper - } - ++i2; - continue; -@@ -0,0 +0,0 @@ public final class SpawnerCreature { - } catch (Exception exception) { - SpawnerCreature.LOGGER.warn("Failed to create mob", exception); - ServerInternalException.reportInternalException(exception); // Paper -- return; -+ return i; // Paper - } - - entityinsentient.setPositionRotation((double) f, (double) k, (double) f1, worldserver.random.nextFloat() * 360.0F, 0.0F); -@@ -0,0 +0,0 @@ public final class SpawnerCreature { - groupdataentity = entityinsentient.prepare(worldserver, worldserver.getDamageScaler(new BlockPosition(entityinsentient)), EnumMobSpawn.NATURAL, groupdataentity, (NBTTagCompound) null); - // CraftBukkit start - if (worldserver.addEntity(entityinsentient, SpawnReason.NATURAL)) { -- ++i; -+ ++i; // Paper - force diff on name change - ++i2; -+ if (trackEntity != null) { -+ trackEntity.accept(entityinsentient); // Paper -+ } - } -+ if (i >= maxSpawns) { return i; } // Paper - // CraftBukkit end - if (i >= entityinsentient.getMaxSpawnGroup()) { -- return; -+ return i; // Paper - } - - if (entityinsentient.c(i2)) { ++ public static SpawnerCreature.d countMobs(int i, Iterable iterable, SpawnerCreature.b spawnercreature_b, boolean countMobs) { ++ // Paper end - add countMobs parameter + SpawnerCreatureProbabilities spawnercreatureprobabilities = new SpawnerCreatureProbabilities(); + Object2IntOpenHashMap object2intopenhashmap = new Object2IntOpenHashMap(); + Iterator iterator = iterable.iterator(); @@ -0,0 +0,0 @@ public final class SpawnerCreature { + } + object2intopenhashmap.addTo(enumcreaturetype, 1); ++ // Paper start ++ if (countMobs) { ++ ((WorldServer)chunk.world).getChunkProvider().playerChunkMap.updatePlayerMobTypeMap(entity); ++ } ++ // Paper end + }); } } -+ return i; // Paper - } +@@ -0,0 +0,0 @@ public final class SpawnerCreature { + continue; + } - @Nullable -diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/WorldServer.java -+++ b/src/main/java/net/minecraft/server/WorldServer.java -@@ -0,0 +0,0 @@ public class WorldServer extends World { - } - - public Object2IntMap l() { -- Object2IntMap object2intmap = new Object2IntOpenHashMap(); -+ // Paper start -+ int[] values = this.countMobs(false); -+ EnumCreatureType[] byId = EnumCreatureType.values(); -+ Object2IntMap ret = new Object2IntOpenHashMap<>(); ++ // Paper start - only allow spawns upto the limit per chunk and update count afterwards ++ int currEntityCount = spawnercreature_d.getEntityCountsByType().getInt(enumcreaturetype); ++ int k1 = limit * spawnercreature_d.getSpawnerChunks() / SpawnerCreature.b; ++ int difference = k1 - currEntityCount; + -+ for (int i = 0, len = values.length; i < len; ++i) { -+ ret.put(byId[i], values[i]); -+ } -+ -+ return ret; -+ } -+ public int[] countMobs(boolean updatePlayerCounts) { -+ int[] ret = new int[EntityPlayer.ENUMCREATURETYPE_TOTAL_ENUMS]; -+ // Paper end - ObjectIterator objectiterator = this.entitiesById.values().iterator(); - - while (objectiterator.hasNext()) { -@@ -0,0 +0,0 @@ public class WorldServer extends World { - continue; - } - // Paper end -- object2intmap.mergeInt(enumcreaturetype, 1, Integer::sum); -+ // Paper start - rework mob spawning -+ if (updatePlayerCounts) { -+ this.getChunkProvider().playerChunkMap.updatePlayerMobTypeMap(entity); ++ if (worldserver.paperConfig.perPlayerMobSpawns) { ++ int minDiff = Integer.MAX_VALUE; ++ for (EntityPlayer entityplayer : worldserver.getChunkProvider().playerChunkMap.playerMobDistanceMap.getPlayersInRange(chunk.getPos())) { ++ minDiff = Math.min(limit - worldserver.getChunkProvider().playerChunkMap.getMobCountNear(entityplayer, enumcreaturetype), minDiff); + } -+ ++ret[enumcreaturetype.ordinal()]; -+ // Paper end ++ difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff; ++ } ++ // Paper end ++ ++ if (difference > 0) { // Paper + if ((flag || !enumcreaturetype.d()) && (flag1 || enumcreaturetype.d()) && (flag2 || !enumcreaturetype.e()) && spawnercreature_d.a(enumcreaturetype, limit)) { + // CraftBukkit end +- a(enumcreaturetype, worldserver, chunk, (entitytypes, blockposition, ichunkaccess) -> { ++ int spawnCount = spawnMobs(enumcreaturetype, worldserver, chunk, (entitytypes, blockposition, ichunkaccess) -> { + return spawnercreature_d.a(entitytypes, blockposition, ichunkaccess); + }, (entityinsentient, ichunkaccess) -> { + spawnercreature_d.a(entityinsentient, ichunkaccess); ++ }, ++ limit, worldserver.paperConfig.perPlayerMobSpawns ? worldserver.getChunkProvider().playerChunkMap::updatePlayerMobTypeMap : null); ++ spawnercreature_d.getEntityCountsByType().mergeInt(enumcreaturetype, 0, (keyInMap, valueInMap) -> { ++ return Integer.valueOf(spawnCount + valueInMap.intValue()); + }); ++ } // Paper } } -- return object2intmap; -+ return ret; +@@ -0,0 +0,0 @@ public final class SpawnerCreature { } - @Override + public static void a(EnumCreatureType enumcreaturetype, WorldServer worldserver, Chunk chunk, SpawnerCreature.c spawnercreature_c, SpawnerCreature.a spawnercreature_a) { ++ // Paper start - add parameters and int ret type ++ spawnMobs(enumcreaturetype, worldserver, chunk, spawnercreature_c, spawnercreature_a, Integer.MAX_VALUE, null); ++ } ++ public static int spawnMobs(EnumCreatureType enumcreaturetype, WorldServer worldserver, Chunk chunk, SpawnerCreature.c spawnercreature_c, SpawnerCreature.a spawnercreature_a, int maxSpawns, Consumer trackEntity) { ++ // Paper end - add parameters and int ret type + BlockPosition blockposition = getRandomPosition(worldserver, chunk); + + if (blockposition.getY() >= 1) { +- a(enumcreaturetype, worldserver, (IChunkAccess) chunk, blockposition, spawnercreature_c, spawnercreature_a); ++ return spawnMobsInternal(enumcreaturetype, worldserver, (IChunkAccess) chunk, blockposition, spawnercreature_c, spawnercreature_a, maxSpawns, trackEntity); + } ++ return 0; // Paper + } + + public static void a(EnumCreatureType enumcreaturetype, WorldServer worldserver, IChunkAccess ichunkaccess, BlockPosition blockposition, SpawnerCreature.c spawnercreature_c, SpawnerCreature.a spawnercreature_a) { ++ // Paper start - add maxSpawns parameter and return spawned mobs ++ spawnMobsInternal(enumcreaturetype, worldserver, ichunkaccess, blockposition, spawnercreature_c, spawnercreature_a, Integer.MAX_VALUE, null); ++ } ++ public static int spawnMobsInternal(EnumCreatureType enumcreaturetype, WorldServer worldserver, IChunkAccess ichunkaccess, BlockPosition blockposition, SpawnerCreature.c spawnercreature_c, SpawnerCreature.a spawnercreature_a, int maxSpawns, Consumer trackEntity) { ++ // Paper end - add maxSpawns parameter and return spawned mobs + StructureManager structuremanager = worldserver.getStructureManager(); + ChunkGenerator chunkgenerator = worldserver.getChunkProvider().getChunkGenerator(); + int i = blockposition.getY(); + IBlockData iblockdata = worldserver.getTypeIfLoadedAndInBounds(blockposition); // Paper - don't load chunks for mob spawn ++ int j = 0; // Paper - moved up + + if (iblockdata != null && !iblockdata.isOccluding(ichunkaccess, blockposition)) { // Paper - don't load chunks for mob spawn + BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition(); +- int j = 0; ++ // Paper - moved up + int k = 0; + + while (k < 3) { +@@ -0,0 +0,0 @@ public final class SpawnerCreature { + // Paper start + Boolean doSpawning = a(worldserver, enumcreaturetype, structuremanager, chunkgenerator, biomebase_biomemeta, blockposition_mutableblockposition, d2); + if (doSpawning == null) { +- return; ++ return j; // Paper + } + if (doSpawning.booleanValue() && spawnercreature_c.test(biomebase_biomemeta.c, blockposition_mutableblockposition, ichunkaccess)) { // Paper end + EntityInsentient entityinsentient = a(worldserver, biomebase_biomemeta.c); + + if (entityinsentient == null) { +- return; ++ return j; // Paper + } + + entityinsentient.setPositionRotation(d0, (double) i, d1, worldserver.random.nextFloat() * 360.0F, 0.0F); +@@ -0,0 +0,0 @@ public final class SpawnerCreature { + groupdataentity = entityinsentient.prepare(worldserver, worldserver.getDamageScaler(entityinsentient.getChunkCoordinates()), EnumMobSpawn.NATURAL, groupdataentity, (NBTTagCompound) null); + // CraftBukkit start + if (worldserver.addEntity(entityinsentient, SpawnReason.NATURAL)) { +- ++j; ++ ++j; // Paper - force diff on name change - we expect this to be the total amount spawned + ++k1; + spawnercreature_a.run(entityinsentient, ichunkaccess); ++ // Paper start ++ if (trackEntity != null) { ++ trackEntity.accept(entityinsentient); ++ } ++ // Paper end + } + // CraftBukkit end +- if (j >= entityinsentient.getMaxSpawnGroup()) { +- return; ++ if (j >= entityinsentient.getMaxSpawnGroup() || j >= maxSpawns) { // Paper ++ return j; // Paper + } + + if (entityinsentient.c(k1)) { +@@ -0,0 +0,0 @@ public final class SpawnerCreature { + } + + } ++ return j; // Paper + } + + private static boolean a(WorldServer worldserver, IChunkAccess ichunkaccess, BlockPosition.MutableBlockPosition blockposition_mutableblockposition, double d0) { +@@ -0,0 +0,0 @@ public final class SpawnerCreature { + + public static class d { + +- private final int a; ++ private final int a; final int getSpawnerChunks() { return this.a; } // Paper - OBFHELPER + private final Object2IntOpenHashMap b; + private final SpawnerCreatureProbabilities c; +- private final Object2IntMap d; ++ private final Object2IntMap d; final Object2IntMap getEntityCountsByType() { return this.d; } // Paper - OBFHELPER + @Nullable + private BlockPosition e; + @Nullable +@@ -0,0 +0,0 @@ public final class SpawnerCreature { + + // CraftBukkit start + private boolean a(EnumCreatureType enumcreaturetype, int limit) { +- int i = limit * this.a / SpawnerCreature.b; ++ int i = limit * this.a / SpawnerCreature.b; // Paper - diff on change, needed in the spawn method + // CraftBukkit end + + return this.b.getInt(enumcreaturetype) < i; diff --git a/Spigot-Server-Patches/incremental-chunk-saving.patch b/Spigot-Server-Patches/incremental-chunk-saving.patch new file mode 100644 index 0000000000..56e383a305 --- /dev/null +++ b/Spigot-Server-Patches/incremental-chunk-saving.patch @@ -0,0 +1,319 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sun, 9 Jun 2019 03:53:22 +0100 +Subject: [PATCH] incremental chunk saving + + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -0,0 +0,0 @@ public class PaperWorldConfig { + keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); + log( "Keep Spawn Loaded Range: " + (keepLoadedRange/16)); + } ++ ++ public int autoSavePeriod = -1; ++ private void autoSavePeriod() { ++ autoSavePeriod = getInt("auto-save-interval", -1); ++ if (autoSavePeriod > 0) { ++ log("Auto Save Interval: " +autoSavePeriod + " (" + (autoSavePeriod / 20) + "s)"); ++ } else if (autoSavePeriod < 0) { ++ autoSavePeriod = net.minecraft.server.MinecraftServer.getServer().autosavePeriod; ++ } ++ } ++ ++ public int maxAutoSaveChunksPerTick = 24; ++ private void maxAutoSaveChunksPerTick() { ++ maxAutoSaveChunksPerTick = getInt("max-auto-save-chunks-per-tick", 24); ++ } + } +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -0,0 +0,0 @@ public class Chunk implements IChunkAccess { + private TickList o; + private TickList p; + private boolean q; +- private long lastSaved; ++ public long lastSaved; // Paper + private volatile boolean s; + private long inhabitedTime; + @Nullable +diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java ++++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +@@ -0,0 +0,0 @@ public class ChunkProviderServer extends IChunkProvider { + } // Paper - Timings + } + ++ // Paper start - duplicate save, but call incremental ++ public void saveIncrementally() { ++ this.tickDistanceManager(); ++ try (co.aikar.timings.Timing timed = world.timings.chunkSaveData.startTiming()) { // Paper - Timings ++ this.playerChunkMap.saveIncrementally(); ++ } // Paper - Timings ++ } ++ // Paper end ++ + @Override + public void close() throws IOException { + // CraftBukkit start +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 ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); + public int autosavePeriod; ++ public boolean serverAutoSave = false; // Paper + public File bukkitDataPackFolder; + public CommandDispatcher vanillaCommandDispatcher; + private boolean forceTicks; +@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit +- MinecraftServer.LOGGER.debug("Autosave started"); ++ //if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit // Paper - move down ++ //MinecraftServer.LOGGER.debug("Autosave started"); // Paper ++ serverAutoSave = (autosavePeriod > 0 && this.ticks % autosavePeriod == 0); // Paper + this.methodProfiler.enter("save"); ++ if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // Paper + this.playerList.savePlayers(); +- this.saveChunks(true, false, false); ++ }// Paper ++ // Paper start ++ for (WorldServer world : getWorlds()) { ++ if (world.paperConfig.autoSavePeriod > 0) { ++ try { ++ world.saveIncrementally(serverAutoSave); ++ } catch (ExceptionWorldConflict exceptionWorldConflict) { ++ MinecraftServer.LOGGER.warn(exceptionWorldConflict.getMessage()); ++ } ++ } ++ } ++ // Paper end ++ + this.methodProfiler.exit(); +- MinecraftServer.LOGGER.debug("Autosave finished"); +- } ++ //MinecraftServer.LOGGER.debug("Autosave finished"); // Paper ++ //} // Paper + + this.methodProfiler.enter("snooper"); + if (((DedicatedServer) this).getDedicatedServerProperties().snooperEnabled && !this.snooper.d() && this.ticks > 100) { // Spigot +diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunk.java ++++ b/src/main/java/net/minecraft/server/PlayerChunk.java +@@ -0,0 +0,0 @@ public class PlayerChunk { + + private final PlayerChunkMap chunkMap; // Paper + ++ long lastAutoSaveTime; // Paper - incremental autosave ++ long inactiveTimeStart; // Paper - incremental autosave ++ + public PlayerChunk(ChunkCoordIntPair chunkcoordintpair, int i, LightEngine lightengine, PlayerChunk.c playerchunk_c, PlayerChunk.d playerchunk_d) { + this.statusFutures = new AtomicReferenceArray(PlayerChunk.CHUNK_STATUSES.size()); + this.fullChunkFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE; +@@ -0,0 +0,0 @@ public class PlayerChunk { + boolean flag2 = playerchunk_state.isAtLeast(PlayerChunk.State.BORDER); + boolean flag3 = playerchunk_state1.isAtLeast(PlayerChunk.State.BORDER); + ++ boolean prevHasBeenLoaded = this.hasBeenLoaded; // Paper + this.hasBeenLoaded |= flag3; ++ // Paper start - incremental autosave ++ if (this.hasBeenLoaded & !prevHasBeenLoaded) { ++ long timeSinceAutoSave = this.inactiveTimeStart - this.lastAutoSaveTime; ++ if (timeSinceAutoSave < 0) { ++ // safest bet is to assume autosave is needed here ++ timeSinceAutoSave = this.chunkMap.world.paperConfig.autoSavePeriod; ++ } ++ this.lastAutoSaveTime = this.chunkMap.world.getTime() - timeSinceAutoSave; ++ this.chunkMap.autoSaveQueue.add(this); ++ } ++ // Paper end + if (!flag2 && flag3) { + // Paper start - cache ticking ready status + int expectCreateCount = ++this.fullChunkCreateCount; +@@ -0,0 +0,0 @@ public class PlayerChunk { + } + + public void m() { ++ boolean prev = this.hasBeenLoaded; // Paper ++ this.hasBeenLoaded = getChunkState(this.ticketLevel).isAtLeast(PlayerChunk.State.BORDER); ++ // Paper start - incremental autosave ++ if (prev != this.hasBeenLoaded) { ++ if (this.hasBeenLoaded) { ++ long timeSinceAutoSave = this.inactiveTimeStart - this.lastAutoSaveTime; ++ if (timeSinceAutoSave < 0) { ++ // safest bet is to assume autosave is needed here ++ timeSinceAutoSave = this.chunkMap.world.paperConfig.autoSavePeriod; ++ } ++ this.lastAutoSaveTime = this.chunkMap.world.getTime() - timeSinceAutoSave; ++ this.chunkMap.autoSaveQueue.add(this); ++ } else { ++ this.inactiveTimeStart = this.chunkMap.world.getTime(); ++ this.chunkMap.autoSaveQueue.remove(this); ++ } ++ } ++ // Paper end ++ } ++ ++ // Paper start - incremental autosave ++ public boolean setHasBeenLoaded() { + this.hasBeenLoaded = getChunkState(this.ticketLevel).isAtLeast(PlayerChunk.State.BORDER); ++ return this.hasBeenLoaded; + } ++ // Paper end + + public void a(ProtoChunkExtension protochunkextension) { + for (int i = 0; i < this.statusFutures.length(); ++i) { +diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java ++++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java +@@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + + } + ++ // Paper start - incremental autosave ++ final it.unimi.dsi.fastutil.objects.ObjectRBTreeSet autoSaveQueue = new it.unimi.dsi.fastutil.objects.ObjectRBTreeSet<>((playerchunk1, playerchunk2) -> { ++ int timeCompare = Long.compare(playerchunk1.lastAutoSaveTime, playerchunk2.lastAutoSaveTime); ++ if (timeCompare != 0) { ++ return timeCompare; ++ } ++ ++ return Long.compare(MCUtil.getCoordinateKey(playerchunk1.location), MCUtil.getCoordinateKey(playerchunk2.location)); ++ }); ++ ++ protected void saveIncrementally() { ++ int savedThisTick = 0; ++ // optimized since we search far less chunks to hit ones that need to be saved ++ List reschedule = new java.util.ArrayList<>(this.world.paperConfig.maxAutoSaveChunksPerTick); ++ long currentTick = this.world.getTime(); ++ long maxSaveTime = currentTick - this.world.paperConfig.autoSavePeriod; ++ ++ for (Iterator iterator = this.autoSaveQueue.iterator(); iterator.hasNext();) { ++ PlayerChunk playerchunk = iterator.next(); ++ if (playerchunk.lastAutoSaveTime > maxSaveTime) { ++ break; ++ } ++ ++ iterator.remove(); ++ ++ IChunkAccess ichunkaccess = playerchunk.getChunkSave().getNow(null); ++ if (ichunkaccess instanceof Chunk) { ++ boolean shouldSave = ((Chunk)ichunkaccess).lastSaved <= maxSaveTime; ++ ++ if (shouldSave && this.saveChunk(ichunkaccess)) { ++ ++savedThisTick; ++ ++ if (!playerchunk.setHasBeenLoaded()) { ++ // do not fall through to reschedule logic ++ playerchunk.inactiveTimeStart = currentTick; ++ if (savedThisTick >= this.world.paperConfig.maxAutoSaveChunksPerTick) { ++ break; ++ } ++ continue; ++ } ++ } ++ } ++ ++ reschedule.add(playerchunk); ++ ++ if (savedThisTick >= this.world.paperConfig.maxAutoSaveChunksPerTick) { ++ break; ++ } ++ } ++ ++ for (int i = 0, len = reschedule.size(); i < len; ++i) { ++ PlayerChunk playerchunk = reschedule.get(i); ++ playerchunk.lastAutoSaveTime = this.world.getTime(); ++ this.autoSaveQueue.add(playerchunk); ++ } ++ } ++ // Paper end ++ + protected void save(boolean flag) { + if (flag) { + List list = (List) this.visibleChunks.values().stream().filter(PlayerChunk::hasBeenLoaded).peek(PlayerChunk::m).collect(Collectors.toList()); +@@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + + this.world.unloadChunk(chunk); + } ++ this.autoSaveQueue.remove(playerchunk); // Paper + + this.lightEngine.a(ichunkaccess.getPos()); + this.lightEngine.queueUpdate(); +@@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + playerchunk.a(new ProtoChunkExtension(chunk)); + } + ++ chunk.setLastSaved(this.world.getTime() - 1); // Paper - avoid autosaving newly generated/loaded chunks ++ + chunk.a(() -> { + return PlayerChunk.getChunkState(playerchunk.getTicketLevel()); + }); +diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/WorldServer.java ++++ b/src/main/java/net/minecraft/server/WorldServer.java +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { + return !this.server.a(this, blockposition, entityhuman) && this.getWorldBorder().a(blockposition); + } + ++ // Paper start - derived from below ++ public void saveIncrementally(boolean doFull) { ++ ChunkProviderServer chunkproviderserver = this.getChunkProvider(); ++ ++ if (doFull) { ++ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); ++ } ++ ++ try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { ++ if (doFull) { ++ this.saveData(); ++ } ++ ++ timings.worldSaveChunks.startTiming(); // Paper ++ if (!this.isSavingDisabled()) chunkproviderserver.saveIncrementally(); ++ timings.worldSaveChunks.stopTiming(); // Paper ++ ++ ++ // Copied from save() ++ // CraftBukkit start - moved from MinecraftServer.saveChunks ++ if (doFull) { // Paper ++ WorldServer worldserver1 = this; ++ ++ worldDataServer.a(worldserver1.getWorldBorder().t()); ++ worldDataServer.setCustomBossEvents(this.server.getBossBattleCustomData().save()); ++ convertable.a(this.server.f, this.worldDataServer, this.server.getPlayerList().save()); ++ } ++ // CraftBukkit end ++ } ++ } ++ // Paper end ++ + public void save(@Nullable IProgressUpdate iprogressupdate, boolean flag, boolean flag1) { + ChunkProviderServer chunkproviderserver = this.getChunkProvider(); + + if (!flag1) { +- org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit ++ if (flag) org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit // Paper + try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { // Paper + if (iprogressupdate != null) { + iprogressupdate.a(new ChatMessage("menu.savingLevel")); +@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed { + // CraftBukkit end + } + ++ private void saveData() { this.ag(); } // Paper - OBFHELPER + private void ag() { + if (this.dragonBattle != null) { + this.server.getSaveData().a(this.dragonBattle.a()); diff --git a/scripts/importmcdev.sh b/scripts/importmcdev.sh index 6fd55da94e..06ad7ab9b9 100755 --- a/scripts/importmcdev.sh +++ b/scripts/importmcdev.sh @@ -94,7 +94,7 @@ done # import FileName - +import VoxelShapeSpliterator ######################################################## ########################################################