diff --git a/patches/api/Add-GameEvent-tags.patch b/patches/api/Add-GameEvent-tags.patch index 95aeca59d9..89c9c894f1 100644 --- a/patches/api/Add-GameEvent-tags.patch +++ b/patches/api/Add-GameEvent-tags.patch @@ -8,14 +8,6 @@ diff --git a/src/main/java/org/bukkit/Tag.java b/src/main/java/org/bukkit/Tag.ja index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/Tag.java +++ b/src/main/java/org/bukkit/Tag.java -@@ -0,0 +0,0 @@ public interface Tag extends Keyed { - * Vanilla tag representing entities which are dismounted when underwater. - */ - Tag ENTITY_TYPES_DISMOUNTS_UNDERWATER = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("dismounts_underwater"), EntityType.class); -+ - /** - * Vanilla tag representing entities which are not controlled by their mount. - */ @@ -0,0 +0,0 @@ public interface Tag extends Keyed { */ Tag ENTITY_TYPES_CAN_TURN_IN_BOATS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("can_turn_in_boats"), EntityType.class); diff --git a/patches/server/Actually-optimise-explosions.patch b/patches/server/Actually-optimise-explosions.patch index 758a26ff5e..6687aa49a3 100644 --- a/patches/server/Actually-optimise-explosions.patch +++ b/patches/server/Actually-optimise-explosions.patch @@ -371,7 +371,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - BlockPos blockposition = BlockPos.containing(d4, d5, d6); - BlockState iblockdata = this.level.getBlockState(blockposition); - if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed -- FluidState fluid = iblockdata.getFluidState(); // Paper +- FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions + // Paper start - optimise explosions + final int blockX = Mth.floor(d4); + final int blockY = Mth.floor(d5); diff --git a/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch b/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch index 4b5ec53d1f..9327db7125 100644 --- a/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch +++ b/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch @@ -115,7 +115,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true); return true; - // Paper end + // Paper end - Optimize this method @@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World { io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { diff --git a/patches/server/Add-ThrownEggHatchEvent.patch b/patches/server/Add-ThrownEggHatchEvent.patch index 72bc0bcd65..16db2e76a1 100644 --- a/patches/server/Add-ThrownEggHatchEvent.patch +++ b/patches/server/Add-ThrownEggHatchEvent.patch @@ -14,13 +14,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } // CraftBukkit end -+ // Paper start ++ // Paper start - Add ThrownEggHatchEvent + com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, b0, hatchingType); + event.callEvent(); + hatching = event.isHatching(); + b0 = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 + hatchingType = event.getHatchingType(); -+ // Paper end ++ // Paper end - Add ThrownEggHatchEvent for (int i = 0; i < b0; ++i) { Entity entitychicken = this.level().getWorld().makeEntity(new org.bukkit.Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass()); // CraftBukkit diff --git a/patches/server/Add-debug-for-sync-chunk-loads.patch b/patches/server/Add-debug-for-sync-chunk-loads.patch index 2c78c67e54..170cd5a535 100644 --- a/patches/server/Add-debug-for-sync-chunk-loads.patch +++ b/patches/server/Add-debug-for-sync-chunk-loads.patch @@ -307,7 +307,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper start - async chunk io/loading io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.pushChunkWait(this.level, x1, z1); // Paper - rewrite chunk system // Paper end -+ com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x1, z1); // Paper - sync load info ++ com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x1, z1); // Paper - Add debug for sync chunk loads this.level.timings.syncChunkLoad.startTiming(); // Paper chunkproviderserver_b.managedBlock(completablefuture::isDone); io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.popChunkWait(); // Paper - async chunk debug // Paper - rewrite chunk system diff --git a/patches/server/Add-option-to-allow-iron-golems-to-spawn-in-air.patch b/patches/server/Add-option-to-allow-iron-golems-to-spawn-in-air.patch index c479ddc589..01ff4dbb9f 100644 --- a/patches/server/Add-option-to-allow-iron-golems-to-spawn-in-air.patch +++ b/patches/server/Add-option-to-allow-iron-golems-to-spawn-in-air.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockState iblockdata = world.getBlockState(blockposition1); - if (!iblockdata.entityCanStandOn(world, blockposition1, this)) { -+ if (!iblockdata.entityCanStandOn(world, blockposition1, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper ++ if (!iblockdata.entityCanStandOn(world, blockposition1, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper - Add option to allow iron golems to spawn in air return false; } else { for (int i = 1; i < 3; ++i) { diff --git a/patches/server/Add-option-to-disable-pillager-patrols.patch b/patches/server/Add-option-to-disable-pillager-patrols.patch index 87f9f19b5d..59ab81e72c 100644 --- a/patches/server/Add-option-to-disable-pillager-patrols.patch +++ b/patches/server/Add-option-to-disable-pillager-patrols.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { -+ if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper ++ if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper - Add option to disable pillager patrols if (!spawnMonsters) { return 0; } else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) { diff --git a/patches/server/Add-option-to-nerf-pigmen-from-nether-portals.patch b/patches/server/Add-option-to-nerf-pigmen-from-nether-portals.patch index 971b8139d9..e101025b41 100644 --- a/patches/server/Add-option-to-nerf-pigmen-from-nether-portals.patch +++ b/patches/server/Add-option-to-nerf-pigmen-from-nether-portals.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper start public long activatedImmunityTick = Integer.MIN_VALUE; // Paper public boolean isTemporarilyActive = false; // Paper -+ public boolean fromNetherPortal; // Paper ++ public boolean fromNetherPortal; // Paper - Add option to nerf pigmen from nether portals protected int numCollisions = 0; // Paper public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one @javax.annotation.Nullable @@ -42,8 +42,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entity != null) { entity.setPortalCooldown(); -+ entity.fromNetherPortal = true; // Paper -+ if (world.paperConfig().entities.behavior.nerfPigmenFromNetherPortals) ((net.minecraft.world.entity.Mob) entity).aware = false; // Paper ++ entity.fromNetherPortal = true; // Paper - Add option to nerf pigmen from nether portals ++ if (world.paperConfig().entities.behavior.nerfPigmenFromNetherPortals) ((net.minecraft.world.entity.Mob) entity).aware = false; // Paper - Add option to nerf pigmen from nether portals } } } diff --git a/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch index 56f3f3be59..ea6a2a6a7d 100644 --- a/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch +++ b/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch @@ -275,7 +275,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - Add mobcaps commands + public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) { - // Paper start - add parameters and int ret type + // Paper start - Optional per player mob spawns spawnCategoryForChunk(group, world, chunk, checker, runner, Integer.MAX_VALUE, null); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Allow-Saving-of-Oversized-Chunks.patch b/patches/server/Allow-Saving-of-Oversized-Chunks.patch index d0c38cce8a..26f5a5a3eb 100644 --- a/patches/server/Allow-Saving-of-Oversized-Chunks.patch +++ b/patches/server/Allow-Saving-of-Oversized-Chunks.patch @@ -71,7 +71,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + private final byte[] oversized = new byte[1024]; -+ private int oversizedCount = 0; ++ private int oversizedCount; + + private synchronized void initOversizedState() throws IOException { + Path metaFile = getOversizedMetaFile(); @@ -153,22 +153,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); + } + -+ private static final int DEFAULT_SIZE_THRESHOLD = 1024 * 8; -+ private static final int OVERZEALOUS_TOTAL_THRESHOLD = 1024 * 64; -+ private static final int OVERZEALOUS_THRESHOLD = 1024; -+ private static int SIZE_THRESHOLD = DEFAULT_SIZE_THRESHOLD; -+ private static void resetFilterThresholds() { -+ SIZE_THRESHOLD = Math.max(1024 * 4, Integer.getInteger("Paper.FilterThreshhold", DEFAULT_SIZE_THRESHOLD)); -+ } -+ static { -+ resetFilterThresholds(); -+ } -+ -+ static boolean isOverzealous() { -+ return SIZE_THRESHOLD == OVERZEALOUS_THRESHOLD; -+ } -+ -+ + private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { + synchronized (regionfile) { + try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { @@ -199,18 +183,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + level.put(key, levelList); + } + } -+ -+ private static int getNBTSize(net.minecraft.nbt.Tag nbtBase) { -+ DataOutputStream test = new DataOutputStream(new org.apache.commons.io.output.NullOutputStream()); -+ try { -+ nbtBase.write(test); -+ return test.size(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return 0; -+ } -+ } -+ + // Paper end + @Nullable diff --git a/patches/server/Implement-alternative-item-despawn-rate.patch b/patches/server/Alternative-item-despawn-rate.patch similarity index 86% rename from patches/server/Implement-alternative-item-despawn-rate.patch rename to patches/server/Alternative-item-despawn-rate.patch index 3af4eeac5b..545d649253 100644 --- a/patches/server/Implement-alternative-item-despawn-rate.patch +++ b/patches/server/Alternative-item-despawn-rate.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: kickash32 Date: Mon, 3 Jun 2019 02:02:39 -0400 -Subject: [PATCH] Implement alternative item-despawn-rate +Subject: [PATCH] Alternative item-despawn-rate Co-authored-by: Noah van der Aa @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public final float bobOffs; private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit public boolean canMobPickup = true; // Paper -+ private int despawnRate = -1; // Paper ++ private int despawnRate = -1; // Paper - Alternative item-despawn-rate public ItemEntity(EntityType type, Level world) { super(type, world); @@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - if (!this.level().isClientSide && this.age >= this.level().spigotConfig.itemDespawnRate) { // Spigot -+ if (!this.level().isClientSide && this.age >= this.despawnRate) { // Spigot // Paper ++ if (!this.level().isClientSide && this.age >= this.despawnRate) { // Spigot // Paper - Alternative item-despawn-rate // CraftBukkit start - fire ItemDespawnEvent if (CraftEventFactory.callItemDespawnEvent(this).isCancelled()) { this.age = 0; @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit end - if (!this.level().isClientSide && this.age >= this.level().spigotConfig.itemDespawnRate) { // Spigot -+ if (!this.level().isClientSide && this.age >= this.despawnRate) { // Spigot // Paper ++ if (!this.level().isClientSide && this.age >= this.despawnRate) { // Spigot // Paper - Alternative item-despawn-rate // CraftBukkit start - fire ItemDespawnEvent if (org.bukkit.craftbukkit.event.CraftEventFactory.callItemDespawnEvent(this).isCancelled()) { this.age = 0; @@ -40,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ItemStack itemstack = this.getItem(); - return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < 6000 && itemstack.getCount() < itemstack.getMaxStackSize(); -+ return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && itemstack.getCount() < itemstack.getMaxStackSize(); // Paper - respect despawn rate in pickup check. ++ return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && itemstack.getCount() < itemstack.getMaxStackSize(); // Paper - Alternative item-despawn-rate } private void tryToMerge(ItemEntity other) { @@ -48,7 +48,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void setItem(ItemStack stack) { this.getEntityData().set(ItemEntity.DATA_ITEM, stack); -+ this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper ++ this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper - Alternative item-despawn-rate } @Override @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void makeFakeItem() { this.setNeverPickUp(); - this.age = this.level().spigotConfig.itemDespawnRate - 1; // Spigot -+ this.age = this.despawnRate - 1; // Spigot // Paper ++ this.age = this.despawnRate - 1; // Spigot // Paper - Alternative item-despawn-rate } public float getSpin(float tickDelta) { diff --git a/patches/server/Bees-get-gravity-in-void.-Fixes-MC-167279.patch b/patches/server/Bees-get-gravity-in-void.-Fixes-MC-167279.patch index daa911a823..c30c098291 100644 --- a/patches/server/Bees-get-gravity-in-void.-Fixes-MC-167279.patch +++ b/patches/server/Bees-get-gravity-in-void.-Fixes-MC-167279.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super(type, world); this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60); - this.moveControl = new FlyingMoveControl(this, 20, true); -+ // Paper start - apply gravity to bees when they get stuck in the void, fixes MC-167279 ++ // Paper start - Fix MC-167279 + class BeeFlyingMoveControl extends FlyingMoveControl { + public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) { + super(entity, maxPitchChange, noGravity); @@ -28,7 +28,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + this.moveControl = new BeeFlyingMoveControl(this, 20, true); -+ // Paper end ++ // Paper end - Fix MC-167279 this.lookControl = new Bee.BeeLookControl(this); this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F); this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); diff --git a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch index 27914e4950..0a2a41399b 100644 --- a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -13,43 +13,42 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start public void prepareLevels(ChunkProgressListener worldloadlistener, ServerLevel worldserver) { -+ ServerChunkCache chunkproviderserver = worldserver.getChunkSource(); // Paper ++ ServerChunkCache chunkproviderserver = worldserver.getChunkSource(); // Paper - Configurable Keep Spawn Loaded range per world // WorldServer worldserver = this.overworld(); this.forceTicks = true; // CraftBukkit end -+ if (worldserver.getWorld().getKeepSpawnInMemory()) { // Paper ++ if (worldserver.getWorld().getKeepSpawnInMemory()) { // Paper - Configurable Keep Spawn Loaded range per world MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.dimension().location()); BlockPos blockposition = worldserver.getSharedSpawnPos(); worldloadlistener.updateSpawnPos(new ChunkPos(blockposition)); - ServerChunkCache chunkproviderserver = worldserver.getChunkSource(); -+ //ChunkProviderServer chunkproviderserver = worldserver.getChunkProvider(); // Paper - move up ++ //ChunkProviderServer chunkproviderserver = worldserver.getChunkProvider(); // Paper - Configurable Keep Spawn Loaded range per world; move up this.nextTickTimeNanos = Util.getNanos(); - // CraftBukkit start - if (worldserver.getWorld().getKeepSpawnInMemory()) { - chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(blockposition), 11, Unit.INSTANCE); -- -- while (chunkproviderserver.getTickingGenerated() != 441) { -- // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS; -- this.executeModerately(); -- } -- } -+ // Paper start - configurable spawn reason ++ // Paper start - Configurable Keep Spawn Loaded range per world + int radiusBlocks = worldserver.paperConfig().spawn.keepSpawnLoadedRange * 16; + int radiusChunks = radiusBlocks / 16 + ((radiusBlocks & 15) != 0 ? 1 : 0); + int totalChunks = ((radiusChunks) * 2 + 1); + totalChunks *= totalChunks; + worldloadlistener.setChunkRadius(radiusBlocks / 16); -+ + +- while (chunkproviderserver.getTickingGenerated() != 441) { +- // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS; +- this.executeModerately(); +- } +- } + worldserver.addTicketsForSpawn(radiusBlocks, blockposition); -+ // Paper end ++ // Paper end - Configurable Keep Spawn Loaded range per world // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS; this.executeModerately(); // Iterator iterator = this.levels.values().iterator(); -+ } ++ } // Paper - Configurable Keep Spawn Loaded range per world if (true) { ServerLevel worldserver1 = worldserver; @@ -58,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.executeModerately(); // CraftBukkit end - worldloadlistener.stop(); -+ if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper ++ if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper - Configurable Keep Spawn Loaded range per world // CraftBukkit start // this.updateMobSpawningFlags(); worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals()); @@ -70,7 +69,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return ((MapIndex) this.getServer().overworld().getDataStorage().computeIfAbsent(MapIndex.factory(), "idcounts")).getFreeAuxValueForMap(); } -+ // Paper start - helper function for configurable spawn radius ++ // Paper start - Configurable Keep Spawn Loaded range per world + public void addTicketsForSpawn(int radiusInBlocks, BlockPos spawn) { + // In order to respect vanilla behavior, which is ensuring everything but the spawn border can tick, we add tickets + // with level 31 for the non-border spawn chunks @@ -135,11 +134,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32 + } + } -+ // Paper end ++ // Paper end - Configurable Keep Spawn Loaded range per world + public void setDefaultSpawnPos(BlockPos pos, float angle) { - ChunkPos chunkcoordintpair = new ChunkPos(new BlockPos(this.levelData.getXSpawn(), 0, this.levelData.getZSpawn())); -+ // Paper - configurable spawn radius ++ // Paper start - Configurable Keep Spawn Loaded range per world + BlockPos prevSpawn = this.getSharedSpawnPos(); + //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c())); @@ -163,7 +162,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 void stop(); + -+ void setChunkRadius(int radius); // Paper - allow changing chunk radius ++ void setChunkRadius(int radius); // Paper - Configurable Keep Spawn Loaded range per world } diff --git a/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java b/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -180,13 +179,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private long nextTickTime = Long.MAX_VALUE; public LoggerChunkProgressListener(int radius) { -+ // Paper start - Allow changing radius later for configurable spawn patch ++ // Paper start - Configurable Keep Spawn Loaded range per world + this.setChunkRadius(radius); // Move to method + } + + @Override + public void setChunkRadius(int radius) { -+ // Paper end ++ // Paper end - Configurable Keep Spawn Loaded range per world int i = radius * 2 + 1; this.maxCount = i * i; } diff --git a/patches/server/Configurable-Region-Compression-Format.patch b/patches/server/Configurable-Region-Compression-Format.patch index 7571cfbbc0..1b8c685454 100644 --- a/patches/server/Configurable-Region-Compression-Format.patch +++ b/patches/server/Configurable-Region-Compression-Format.patch @@ -9,7 +9,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - // Paper end + // Paper end - Cache chunk status public RegionFile(Path file, Path directory, boolean dsync) throws IOException { - this(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync); diff --git a/patches/server/Configurable-chance-of-villager-zombie-infection.patch b/patches/server/Configurable-chance-of-villager-zombie-infection.patch index f87edf06dc..22bca3d9aa 100644 --- a/patches/server/Configurable-chance-of-villager-zombie-infection.patch +++ b/patches/server/Configurable-chance-of-villager-zombie-infection.patch @@ -21,8 +21,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { - return flag; - } -+ final double fallbackChance = world.getDifficulty() == Difficulty.HARD ? 100d : world.getDifficulty() == Difficulty.NORMAL ? 50d : 0d; // Paper -+ if (this.random.nextDouble() * 100 < world.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && other instanceof Villager entityvillager) { // Paper ++ final double fallbackChance = world.getDifficulty() == Difficulty.HARD ? 100d : world.getDifficulty() == Difficulty.NORMAL ? 50d : 0d; // Paper - Configurable chance of villager zombie infection ++ if (this.random.nextDouble() * 100 < world.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && other instanceof Villager entityvillager) { // Paper - Configurable chance of villager zombie infection // CraftBukkit start flag = Zombie.zombifyVillager(world, entityvillager, this.blockPosition(), this.isSilent(), CreatureSpawnEvent.SpawnReason.INFECTION) == null; } diff --git a/patches/server/Do-not-let-the-server-load-chunks-from-newer-version.patch b/patches/server/Do-not-let-the-server-load-chunks-from-newer-version.patch index 12d524cb87..70c2e0cc2b 100644 --- a/patches/server/Do-not-let-the-server-load-chunks-from-newer-version.patch +++ b/patches/server/Do-not-let-the-server-load-chunks-from-newer-version.patch @@ -31,5 +31,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } // Paper end - ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate + ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate diff --git a/patches/server/Don-t-load-Chunks-from-Hoppers-and-other-things.patch b/patches/server/Don-t-load-Chunks-from-Hoppers-and-other-things.patch index 74a793ce71..ea635d04fc 100644 --- a/patches/server/Don-t-load-Chunks-from-Hoppers-and-other-things.patch +++ b/patches/server/Don-t-load-Chunks-from-Hoppers-and-other-things.patch @@ -21,12 +21,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { BlockPos blockPos = pos.relative(directionMapper.apply(state)); - BlockState blockState = world.getBlockState(blockPos); -+ // Paper start ++ // Paper start - Don't load Chunks from Hoppers and other things + BlockState blockState = world.getBlockStateIfLoaded(blockPos); + if (blockState == null) { + return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); + } -+ // Paper end ++ // Paper end - Don't load Chunks from Hoppers and other things if (blockState.is(state.getBlock())) { DoubleBlockCombiner.BlockType blockType2 = typeMapper.apply(blockState); if (blockType2 != DoubleBlockCombiner.BlockType.SINGLE && blockType != blockType2 && blockState.getValue(directionProperty) == state.getValue(directionProperty)) { diff --git a/patches/server/Dont-send-unnecessary-sign-update.patch b/patches/server/Dont-send-unnecessary-sign-update.patch index 5b5e0e46a9..d1bfb171b4 100644 --- a/patches/server/Dont-send-unnecessary-sign-update.patch +++ b/patches/server/Dont-send-unnecessary-sign-update.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3); } else { SignBlockEntity.LOGGER.warn("Player {} just tried to change non-editable sign", player.getName().getString()); -+ if (player.distanceToSqr(this.getBlockPos().getX(), this.getBlockPos().getY(), this.getBlockPos().getZ()) < 32 * 32) // Paper ++ if (player.distanceToSqr(this.getBlockPos().getX(), this.getBlockPos().getY(), this.getBlockPos().getZ()) < 32 * 32) // Paper - Dont send far away sign update ((ServerPlayer) player).connection.send(this.getUpdatePacket()); // CraftBukkit } } diff --git a/patches/server/Duplicate-UUID-Resolve-Option.patch b/patches/server/Duplicate-UUID-Resolve-Option.patch index b941148f60..9cbd1429e1 100644 --- a/patches/server/Duplicate-UUID-Resolve-Option.patch +++ b/patches/server/Duplicate-UUID-Resolve-Option.patch @@ -63,7 +63,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 entity.discard(); needsRemoval = true; } -+ checkDupeUUID(world, entity); // Paper ++ checkDupeUUID(world, entity); // Paper - duplicate uuid resolving return !needsRemoval; }), position); // Paper - rewrite chunk system // CraftBukkit end @@ -71,7 +71,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 throw new UnsupportedOperationException(); // Paper - rewrite chunk system } -+ // Paper start ++ // Paper start - duplicate uuid resolving + // rets true if to prevent the entity from being added + public static boolean checkDupeUUID(ServerLevel level, Entity entity) { + io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode mode = level.paperConfig().entities.spawning.duplicateUuid.mode; @@ -113,7 +113,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + return false; + } -+ // Paper end ++ // Paper end - duplicate uuid resolving public CompletableFuture> prepareTickingChunk(ChunkHolder holder) { throw new UnsupportedOperationException(); // Paper - rewrite chunk system } diff --git a/patches/server/Entity-Jump-API.patch b/patches/server/Entity-Jump-API.patch index 454edcc934..375aa48292 100644 --- a/patches/server/Entity-Jump-API.patch +++ b/patches/server/Entity-Jump-API.patch @@ -12,10 +12,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else if (this.isInLava() && (!this.onGround() || d3 > d4)) { this.jumpInLiquid(FluidTags.LAVA); } else if ((this.onGround() || flag && d3 <= d4) && this.noJumpDelay == 0) { -+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper ++ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API this.jumpFromGround(); this.noJumpDelay = 10; -+ } else { this.setJumping(false); } // Paper - setJumping(false) stops a potential loop ++ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop } } else { this.noJumpDelay = 0; @@ -27,9 +27,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Panda entitypanda = (Panda) iterator.next(); if (!entitypanda.isBaby() && entitypanda.onGround() && !entitypanda.isInWater() && entitypanda.canPerformAction()) { -+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper ++ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API entitypanda.jumpFromGround(); -+ } else { this.setJumping(false); } // Paper - setJumping(false) stops a potential loop ++ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop } } @@ -41,9 +41,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } if (!flag && this.onGround()) { -+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper ++ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API this.jumpFromGround(); -+ } else { this.setJumping(false); } // Paper - setJumping(false) stops a potential loop ++ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop } } diff --git a/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch index b03065ab36..0e3b24f03b 100644 --- a/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch +++ b/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 ReentrantBlockableEventLoop Date: Fri, 17 Jan 2020 18:44:55 -0800 Subject: [PATCH] Fix last firework in stack not having effects when dispensed - - #2871 CB used the resulting item in the dispenser rather than the item dispensed. The resulting item would have size == 0 and therefore diff --git a/patches/server/Fix-tripwire-state-inconsistency.patch b/patches/server/Fix-tripwire-state-inconsistency.patch index 92d01a9bf4..e244d24060 100644 --- a/patches/server/Fix-tripwire-state-inconsistency.patch +++ b/patches/server/Fix-tripwire-state-inconsistency.patch @@ -82,6 +82,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 TripWireHookBlock.emitState(world, pos, flag4, flag5, flag2, flag3); - if (!flag) { + if (!beingRemoved) { // Paper - fix tripwire state inconsistency - if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - validate + if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - Validate tripwire hook placement before update world.setBlock(pos, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection), 3); if (flag1) { diff --git a/patches/server/Flat-bedrock-generator-settings.patch b/patches/server/Flat-bedrock-generator-settings.patch index 1470fc995f..4be7662424 100644 --- a/patches/server/Flat-bedrock-generator-settings.patch +++ b/patches/server/Flat-bedrock-generator-settings.patch @@ -108,7 +108,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 CauldronInteraction.bootStrap(); // Paper start BuiltInRegistries.bootStrap(() -> { -+ io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - optional flat bedrock ++ io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - Flat bedrock generator settings io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping }); // Paper end @@ -121,7 +121,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void buildSurface(WorldGenRegion region, StructureManager structures, RandomState noiseConfig, ChunkAccess chunk) { if (!SharedConstants.debugVoidTerrain(chunk.getPos())) { - WorldGenerationContext worldgenerationcontext = new WorldGenerationContext(this, region); -+ WorldGenerationContext worldgenerationcontext = new WorldGenerationContext(this, region, region.getMinecraftWorld()); // Paper ++ WorldGenerationContext worldgenerationcontext = new WorldGenerationContext(this, region, region.getMinecraftWorld()); // Paper - Flat bedrock generator settings this.buildSurface(chunk, worldgenerationcontext, noiseConfig, structures, region.getBiomeManager(), region.registryAccess().registryOrThrow(Registries.BIOME), Blender.of(region)); } @@ -130,7 +130,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }); Aquifer aquifer = noisechunk.aquifer(); - CarvingContext carvingcontext = new CarvingContext(this, chunkRegion.registryAccess(), chunk.getHeightAccessorForGeneration(), noisechunk, noiseConfig, ((NoiseGeneratorSettings) this.settings.value()).surfaceRule()); -+ CarvingContext carvingcontext = new CarvingContext(this, chunkRegion.registryAccess(), chunk.getHeightAccessorForGeneration(), noisechunk, noiseConfig, ((NoiseGeneratorSettings) this.settings.value()).surfaceRule(), chunkRegion.getMinecraftWorld()); // Paper ++ CarvingContext carvingcontext = new CarvingContext(this, chunkRegion.registryAccess(), chunk.getHeightAccessorForGeneration(), noisechunk, noiseConfig, ((NoiseGeneratorSettings) this.settings.value()).surfaceRule(), chunkRegion.getMinecraftWorld()); // Paper - Flat bedrock generator settings CarvingMask carvingmask = ((ProtoChunk) chunk).getOrCreateCarvingMask(carverStep); for (int j = -8; j <= 8; ++j) { @@ -142,14 +142,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public class WorldGenerationContext { private final int minY; private final int height; -+ private final @javax.annotation.Nullable net.minecraft.world.level.Level level; // Paper ++ private final @javax.annotation.Nullable net.minecraft.world.level.Level level; // Paper - Flat bedrock generator settings - public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor world) { -+ public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor world) { this(generator, world, null); } // Paper -+ public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor world, @org.jetbrains.annotations.Nullable net.minecraft.world.level.Level level) { // Paper ++ public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor world) { this(generator, world, null); } // Paper - Flat bedrock generator settings ++ public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor world, @org.jetbrains.annotations.Nullable net.minecraft.world.level.Level level) { // Paper - Flat bedrock generator settings this.minY = Math.max(world.getMinBuildHeight(), generator.getMinY()); this.height = Math.min(world.getHeight(), generator.getGenDepth()); -+ this.level = level; // Paper ++ this.level = level; // Paper - Flat bedrock generator settings } public int getMinGenY() { @@ -158,14 +158,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return this.height; } + -+ // Paper start ++ // Paper start - Flat bedrock generator settings + public net.minecraft.world.level.Level getWorld() { + if (this.level == null) { + throw new NullPointerException("WorldGenerationContext was initialized without a Level, but WorldGenerationContext#getWorld was called"); + } + return this.level; + } -+ // Paper end ++ // Paper end - Flat bedrock generator settings } diff --git a/src/main/java/net/minecraft/world/level/levelgen/carver/CarvingContext.java b/src/main/java/net/minecraft/world/level/levelgen/carver/CarvingContext.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -177,8 +177,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - public CarvingContext(NoiseBasedChunkGenerator noiseChunkGenerator, RegistryAccess registryManager, LevelHeightAccessor heightLimitView, NoiseChunk chunkNoiseSampler, RandomState noiseConfig, SurfaceRules.RuleSource materialRule) { - super(noiseChunkGenerator, heightLimitView); -+ public CarvingContext(NoiseBasedChunkGenerator noiseChunkGenerator, RegistryAccess registryManager, LevelHeightAccessor heightLimitView, NoiseChunk chunkNoiseSampler, RandomState noiseConfig, SurfaceRules.RuleSource materialRule, @javax.annotation.Nullable net.minecraft.world.level.Level level) { // Paper -+ super(noiseChunkGenerator, heightLimitView, level); // Paper ++ public CarvingContext(NoiseBasedChunkGenerator noiseChunkGenerator, RegistryAccess registryManager, LevelHeightAccessor heightLimitView, NoiseChunk chunkNoiseSampler, RandomState noiseConfig, SurfaceRules.RuleSource materialRule, @javax.annotation.Nullable net.minecraft.world.level.Level level) { // Paper - Flat bedrock generator settings ++ super(noiseChunkGenerator, heightLimitView, level); // Paper - Flat bedrock generator settings this.registryAccess = registryManager; this.noiseChunk = chunkNoiseSampler; this.randomState = noiseConfig; @@ -191,7 +191,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public PlacementContext(WorldGenLevel world, ChunkGenerator generator, Optional placedFeature) { - super(generator, world); -+ super(generator, world, world.getLevel()); // Paper ++ super(generator, world, world.getLevel()); // Paper - Flat bedrock generator settings this.level = world; this.generator = generator; this.topFeature = placedFeature; diff --git a/patches/server/Friction-API.patch b/patches/server/Friction-API.patch index c86261f52c..598281fac4 100644 --- a/patches/server/Friction-API.patch +++ b/patches/server/Friction-API.patch @@ -61,7 +61,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ItemEntity extends Entity implements TraceableEntity { private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit public boolean canMobPickup = true; // Paper - private int despawnRate = -1; // Paper + private int despawnRate = -1; // Paper - Alternative item-despawn-rate + public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API public ItemEntity(EntityType type, Level world) { diff --git a/patches/server/Guard-against-serializing-mismatching-chunk-coordina.patch b/patches/server/Guard-against-serializing-mismatching-chunk-coordina.patch index 220b4c2e94..0e3ec75d56 100644 --- a/patches/server/Guard-against-serializing-mismatching-chunk-coordina.patch +++ b/patches/server/Guard-against-serializing-mismatching-chunk-coordina.patch @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return new ChunkPos(chunkData.getInt("xPos"), chunkData.getInt("zPos")); + } + } -+ // Paper end ++ // Paper end - guard against serializing mismatching coordinates // Paper start public static final class InProgressChunkHolder { @@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static InProgressChunkHolder loadChunk(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt, boolean distinguish) { // Paper end - ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); -+ ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate ++ ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate if (!Objects.equals(chunkPos, chunkcoordintpair1)) { ChunkSerializer.LOGGER.error("Chunk file at {} is in the wrong location; relocating. (Expected {}, got {})", new Object[]{chunkPos, chunkPos, chunkcoordintpair1}); @@ -45,13 +45,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper start - async chunk io public void write(ChunkPos chunkPos, CompoundTag nbt) throws IOException { -+ // Paper start ++ // Paper start - guard against serializing mismatching coordinates + if (nbt != null && !chunkPos.equals(ChunkSerializer.getChunkCoordinate(nbt))) { + String world = (this instanceof net.minecraft.server.level.ChunkMap) ? ((net.minecraft.server.level.ChunkMap)this).level.getWorld().getName() : null; + throw new IllegalArgumentException("Chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + chunkPos.toString() + + " but compound says coordinate is " + ChunkSerializer.getChunkCoordinate(nbt).toString() + (world == null ? " for an unknown world" : (" for world: " + world))); + } -+ // Paper end ++ // Paper end - guard against serializing mismatching coordinates this.regionFileCache.write(chunkPos, nbt); // Paper end - Async chunk loading if (this.legacyStructureHandler != null) { diff --git a/patches/server/Improve-Block-breakNaturally-API.patch b/patches/server/Improve-Block-breakNaturally-API.patch index 7e7f26c0b8..3317483d7a 100644 --- a/patches/server/Improve-Block-breakNaturally-API.patch +++ b/patches/server/Improve-Block-breakNaturally-API.patch @@ -25,11 +25,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { super.playerDestroy(world, player, pos, state, blockEntity, tool); -+ // Paper start ++ // Paper start - Improve Block#breakNaturally API + this.afterDestroy(world, pos, tool); + } + public void afterDestroy(Level world, BlockPos pos, ItemStack tool) { -+ // Paper end ++ // Paper end - Improve Block#breakNaturally API if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) == 0) { if (world.dimensionType().ultraWarm()) { world.removeBlock(pos, false); diff --git a/patches/server/Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch b/patches/server/Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch index 8f48530d30..ae1c5e5fdb 100644 --- a/patches/server/Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch +++ b/patches/server/Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch @@ -35,7 +35,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return entityPlayer.mobCounts[mobCategory.ordinal()]; + return entityPlayer.mobCounts[mobCategory.ordinal()] + entityPlayer.mobBackoffCounts[mobCategory.ordinal()]; // Paper - per player mob count backoff } - // Paper end + // Paper end - Optional per player mob spawns diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -67,7 +67,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerPlayer extends Player { public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length; public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper - // Paper end - mob spawning rework + // Paper end - Optional per player mob spawns + public final int[] mobBackoffCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper - per player mob count backoff // CraftBukkit start @@ -86,5 +86,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - per player mob count backoff if (doSpawning == PreSpawnStatus.ABORT) { - return j; // Paper + return j; // Paper - Optional per player mob spawns } diff --git a/patches/server/Improve-java-version-check.patch b/patches/server/Improve-java-version-check.patch index c448bf7035..46968649c4 100644 --- a/patches/server/Improve-java-version-check.patch +++ b/patches/server/Improve-java-version-check.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return; } -+ // Paper start - better java version checks ++ // Paper start - Improve java version check + boolean skip = Boolean.getBoolean("Paper.IgnoreJavaVersion"); float javaVersion = Float.parseFloat(System.getProperty("java.class.version")); - if (javaVersion < 61.0) { @@ -40,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (skip && (isOldVersion || isPreRelease)) { + System.err.println("Unsupported Java detected ("+ javaVersionName + "), but the check was skipped. Proceed with caution! "); + } -+ // Paper end - better java version checks ++ // Paper end - Improve java version check + try { // Paper start - Handled by TerminalConsoleAppender diff --git a/patches/server/Lag-compensation-ticks.patch b/patches/server/Lag-compensation-ticks.patch index 676cfe3680..cf9c4ab046 100644 --- a/patches/server/Lag-compensation-ticks.patch +++ b/patches/server/Lag-compensation-ticks.patch @@ -36,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { return player != null && player.level() == this ? player : null; } - // Paper end + // Paper end - optimise getPlayerByUUID + // Paper start - lag compensation + private long lagCompensationTick = net.minecraft.server.MinecraftServer.SERVER_INIT; + @@ -95,7 +95,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (!itemstack.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper use override flag + if (!itemstack.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper - Prevent consuming the wrong itemstack this.useItem = itemstack; - this.useItemRemaining = itemstack.getUseDuration(); + // Paper start - lag compensate eating diff --git a/patches/server/MC-145656-Fix-Follow-Range-Initial-Target.patch b/patches/server/MC-145656-Fix-Follow-Range-Initial-Target.patch index 7536365315..bc59e97648 100644 --- a/patches/server/MC-145656-Fix-Follow-Range-Initial-Target.patch +++ b/patches/server/MC-145656-Fix-Follow-Range-Initial-Target.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.randomInterval = reducedTickDelay(reciprocalChance); this.setFlags(EnumSet.of(Goal.Flag.TARGET)); this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(targetPredicate); -+ if (mob.level().paperConfig().entities.entitiesTargetWithFollowRange) this.targetConditions.useFollowRange(); // Paper ++ if (mob.level().paperConfig().entities.entitiesTargetWithFollowRange) this.targetConditions.useFollowRange(); // Paper - Fix MC-145656 } @Override @@ -25,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.range > 0.0D) { double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0D; - double e = Math.max(this.range * d, 2.0D); -+ double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0D); // Paper ++ double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0D); // Paper - Fix MC-145656 double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ()); if (f > e * e) { return false; @@ -34,7 +34,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } + -+ // Paper start ++ // Paper start - Fix MC-145656 + private boolean useFollowRange = false; + + public TargetingConditions useFollowRange() { @@ -46,5 +46,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + net.minecraft.world.entity.ai.attributes.AttributeInstance attributeinstance = entityliving.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.FOLLOW_RANGE); + return attributeinstance == null ? 16.0D : attributeinstance.getValue(); + } -+ // Paper end ++ // Paper end - Fix MC-145656 } diff --git a/patches/server/Make-the-GUI-graph-fancier.patch b/patches/server/Make-the-GUI-graph-fancier.patch index 677df0e8cf..542f3f7d54 100644 --- a/patches/server/Make-the-GUI-graph-fancier.patch +++ b/patches/server/Make-the-GUI-graph-fancier.patch @@ -392,7 +392,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private JComponent buildInfoPanel() { JPanel jpanel = new JPanel(new BorderLayout()); - StatsComponent guistatscomponent = new StatsComponent(this.server); -+ com.destroystokyo.paper.gui.GuiStatsComponent guistatscomponent = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper ++ com.destroystokyo.paper.gui.GuiStatsComponent guistatscomponent = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper - Make GUI graph fancier Collection collection = this.finalizers; // CraftBukkit - decompile error Objects.requireNonNull(guistatscomponent); diff --git a/patches/server/Mob-Spawner-API-Enhancements.patch b/patches/server/Mob-Spawner-API-Enhancements.patch index 0cb8e4be12..cf3acc18cc 100644 --- a/patches/server/Mob-Spawner-API-Enhancements.patch +++ b/patches/server/Mob-Spawner-API-Enhancements.patch @@ -64,7 +64,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + nbt.putShort("MinSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.minSpawnDelay)); + nbt.putShort("MaxSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.maxSpawnDelay)); -+ // Paper nbt ++ // Paper end nbt.putShort("SpawnCount", (short) this.spawnCount); nbt.putShort("MaxNearbyEntities", (short) this.maxNearbyEntities); nbt.putShort("RequiredPlayerRange", (short) this.requiredPlayerRange); diff --git a/patches/server/Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch b/patches/server/Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch index fc68fcfec7..1feab914ca 100644 --- a/patches/server/Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch +++ b/patches/server/Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch @@ -30,7 +30,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) { + continue; + } -+ // Paper end ++ // Paper end - Only count natural spawns BlockPos blockposition = entity.blockPosition(); chunkSource.query(ChunkPos.asLong(blockposition), (chunk) -> { diff --git a/patches/server/Only-write-chunk-data-to-disk-if-it-serializes-witho.patch b/patches/server/Only-write-chunk-data-to-disk-if-it-serializes-witho.patch index 389ec30dfd..6aaee02c2a 100644 --- a/patches/server/Only-write-chunk-data-to-disk-if-it-serializes-witho.patch +++ b/patches/server/Only-write-chunk-data-to-disk-if-it-serializes-witho.patch @@ -52,10 +52,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { NbtIo.write(nbt, (DataOutput) dataoutputstream); - regionfile.setStatus(pos.x, pos.z, ChunkSerializer.getStatus(nbt)); // Paper - cache status on disk + regionfile.setStatus(pos.x, pos.z, ChunkSerializer.getStatus(nbt)); // Paper - Cache chunk status regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone + dataoutputstream.close(); // Paper - only write if successful -+ // Paper start - don't write garbage data to disk if writing serialization fails ++ // Paper start - don't write garbage data to disk if writing serialization fails + } catch (RegionFileSizeException e) { + attempts = 5; // Don't retry + regionfile.clear(pos); diff --git a/patches/server/Optimise-Chunk-getFluid.patch b/patches/server/Optimise-Chunk-getFluid.patch index 9d3540074b..b7d1d2ecc3 100644 --- a/patches/server/Optimise-Chunk-getFluid.patch +++ b/patches/server/Optimise-Chunk-getFluid.patch @@ -20,8 +20,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - - if (l >= 0 && l < this.sections.length) { - LevelChunkSection chunksection = this.sections[l]; -+ // try { // Paper - remove try catch -+ // Paper start - reduce the number of ops in this call ++ // Paper start - Perf: Optimise Chunk#getFluid ++ // try { // Remove try catch + int index = this.getSectionIndex(y); + if (index >= 0 && index < this.sections.length) { + LevelChunkSection chunksection = this.sections[index]; @@ -29,12 +29,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!chunksection.hasOnlyAir()) { - return chunksection.getFluidState(x & 15, y & 15, z & 15); + return chunksection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState(); -+ // Paper end ++ // Paper end - Perf: Optimise Chunk#getFluid } } return Fluids.EMPTY.defaultFluidState(); -+ /* // Paper - remove try catch ++ /* // Paper - Perf: Optimise Chunk#getFluid } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got"); @@ -42,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }); throw new ReportedException(crashreport); } -+ */ // Paper - remove try catch ++ */ // Paper - Perf: Optimise Chunk#getFluid } // CraftBukkit start @@ -55,7 +55,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public FluidState getFluidState(int x, int y, int z) { - return ((BlockState) this.states.get(x, y, z)).getFluidState(); -+ return this.states.get(x, y, z).getFluidState(); // Paper - diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid. ++ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid; diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid. } public void acquire() { diff --git a/patches/server/Optimise-EntityGetter-getPlayerByUUID.patch b/patches/server/Optimise-EntityGetter-getPlayerByUUID.patch index 027d132cef..06f4450882 100644 --- a/patches/server/Optimise-EntityGetter-getPlayerByUUID.patch +++ b/patches/server/Optimise-EntityGetter-getPlayerByUUID.patch @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final Player player = this.getServer().getPlayerList().getPlayer(uuid); + return player != null && player.level() == this ? player : null; + } -+ // Paper end ++ // Paper end - optimise getPlayerByUUID + // Add env and gen to constructor, IWorldDataServer -> WorldDataServer public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { diff --git a/patches/server/Optimise-chunk-tick-iteration.patch b/patches/server/Optimise-chunk-tick-iteration.patch index e53d4070f2..65168afa41 100644 --- a/patches/server/Optimise-chunk-tick-iteration.patch +++ b/patches/server/Optimise-chunk-tick-iteration.patch @@ -132,7 +132,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - // Paper end + // Paper end - Optional per player mob spawns - private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) { + public static double euclideanDistanceSquared(ChunkPos pos, Entity entity) { // Paper - optimise chunk iteration; public diff --git a/patches/server/Optimise-getChunkAt-calls-for-loaded-chunks.patch b/patches/server/Optimise-getChunkAt-calls-for-loaded-chunks.patch index 3bd61b6429..aaf37435af 100644 --- a/patches/server/Optimise-getChunkAt-calls-for-loaded-chunks.patch +++ b/patches/server/Optimise-getChunkAt-calls-for-loaded-chunks.patch @@ -14,12 +14,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return this.getChunk(x, z, leastStatus, create); }, this.mainThreadProcessor).join(); } else { -+ // Paper start - optimise for loaded chunks ++ // Paper start - Perf: Optimise getChunkAt calls for loaded chunks + LevelChunk ifLoaded = this.getChunkAtIfLoadedMainThread(x, z); + if (ifLoaded != null) { + return ifLoaded; + } -+ // Paper end ++ // Paper end - Perf: Optimise getChunkAt calls for loaded chunks ProfilerFiller gameprofilerfiller = this.level.getProfiler(); gameprofilerfiller.incrementCounter("getChunk"); @@ -60,7 +60,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return null; - } - } -+ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - optimise for loaded chunks ++ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks } } diff --git a/patches/server/Optimize-Captured-TileEntity-Lookup.patch b/patches/server/Optimize-Captured-BlockEntity-Lookup.patch similarity index 89% rename from patches/server/Optimize-Captured-TileEntity-Lookup.patch rename to patches/server/Optimize-Captured-BlockEntity-Lookup.patch index d169847e04..5c6d361a54 100644 --- a/patches/server/Optimize-Captured-TileEntity-Lookup.patch +++ b/patches/server/Optimize-Captured-BlockEntity-Lookup.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sat, 6 Apr 2019 10:16:48 -0400 -Subject: [PATCH] Optimize Captured TileEntity Lookup +Subject: [PATCH] Optimize Captured BlockEntity Lookup upstream was doing a containsKey/get pattern, and always doing it at that. that scenario is only even valid if were in the middle of a block place. @@ -19,12 +19,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) { - if (this.capturedTileEntities.containsKey(blockposition)) { - return this.capturedTileEntities.get(blockposition); -+ // Paper start - Optimize capturedTileEntities lookup ++ // Paper start - Perf: Optimize capturedTileEntities lookup + net.minecraft.world.level.block.entity.BlockEntity blockEntity; + if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(blockposition)) != null) { + return blockEntity; } -+ // Paper end ++ // Paper end - Perf: Optimize capturedTileEntities lookup // CraftBukkit end return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system } diff --git a/patches/server/Optimize-call-to-getFluid-for-explosions.patch b/patches/server/Optimize-call-to-getFluid-for-explosions.patch index d5d64cc740..bd75e3a4a3 100644 --- a/patches/server/Optimize-call-to-getFluid-for-explosions.patch +++ b/patches/server/Optimize-call-to-getFluid-for-explosions.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockPos blockposition = BlockPos.containing(d4, d5, d6); BlockState iblockdata = this.level.getBlockState(blockposition); - FluidState fluid = this.level.getFluidState(blockposition); -+ FluidState fluid = iblockdata.getFluidState(); // Paper ++ FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions if (!this.level.isInWorldBounds(blockposition)) { break; diff --git a/patches/server/implement-optional-per-player-mob-spawns.patch b/patches/server/Optional-per-player-mob-spawns.patch similarity index 86% rename from patches/server/implement-optional-per-player-mob-spawns.patch rename to patches/server/Optional-per-player-mob-spawns.patch index 69b6a318b8..17e26788b3 100644 --- a/patches/server/implement-optional-per-player-mob-spawns.patch +++ b/patches/server/Optional-per-player-mob-spawns.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: kickash32 Date: Mon, 19 Aug 2019 01:27:58 +0500 -Subject: [PATCH] implement optional per player mob spawns +Subject: [PATCH] Optional per player mob spawns diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }); } -+ // Paper start ++ // Paper start - Optional per player mob spawns + public void updatePlayerMobTypeMap(Entity entity) { + if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { + return; @@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public int getMobCountNear(ServerPlayer entityPlayer, net.minecraft.world.entity.MobCategory mobCategory) { + return entityPlayer.mobCounts[mobCategory.ordinal()]; + } -+ // Paper end ++ // Paper end - Optional per player mob spawns + private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) { double d0 = (double) SectionPos.sectionToBlockCoord(pos.x, 8); @@ -47,7 +47,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.level.timings.countNaturalMobs.startTiming(); // Paper - timings int k = this.distanceManager.getNaturalSpawnChunkCount(); - NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(k, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap)); -+ // Paper start - per player mob spawning ++ // Paper start - Optional per player mob spawns + int naturalSpawnChunkCount = k; + NaturalSpawner.SpawnState spawnercreature_d; // moved down + if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled @@ -59,7 +59,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } else { + spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); + } -+ // Paper end ++ // Paper end - Optional per player mob spawns this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings this.lastSpawnState = spawnercreature_d; @@ -71,10 +71,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean queueHealthUpdatePacket = false; public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket; // Paper end -+ // Paper start - mob spawning rework ++ // Paper start - Optional per player mob spawns + public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length; + public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper -+ // Paper end - mob spawning rework ++ // Paper end - Optional per player mob spawns // CraftBukkit start public String displayName; @@ -86,12 +86,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private NaturalSpawner() {} public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper) { -+ // Paper start - add countMobs parameter ++ // Paper start - Optional per player mob spawns + return createState(spawningChunkCount, entities, chunkSource, densityCapper, false); + } + + public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper, boolean countMobs) { -+ // Paper end ++ // Paper end - Optional per player mob spawns PotentialCalculator spawnercreatureprobabilities = new PotentialCalculator(); Object2IntOpenHashMap object2intopenhashmap = new Object2IntOpenHashMap(); Iterator iterator = entities.iterator(); @@ -100,16 +100,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - if (entity instanceof Mob) { -+ if (densityCapper != null && entity instanceof Mob) { // Paper ++ if (densityCapper != null && entity instanceof Mob) { // Paper - Optional per player mob spawns densityCapper.addMob(chunk.getPos(), enumcreaturetype); } object2intopenhashmap.addTo(enumcreaturetype, 1); -+ // Paper start ++ // Paper start - Optional per player mob spawns + if (countMobs) { + chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity); + } -+ // Paper end ++ // Paper end - Optional per player mob spawns }); } } @@ -118,7 +118,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rareSpawn || !enumcreaturetype.isPersistent()) && info.canSpawnForCategory(enumcreaturetype, chunk.getPos(), limit)) { -+ // Paper start - only allow spawns upto the limit per chunk and update count afterwards ++ // Paper start - Optional per player mob spawns; only allow spawns upto the limit per chunk and update count afterwards + int currEntityCount = info.mobCategoryCounts.getInt(enumcreaturetype); + int k1 = limit * info.getSpawnableChunkCount() / NaturalSpawner.MAGIC_NUMBER; + int difference = k1 - currEntityCount; @@ -136,18 +136,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff; + } + if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rareSpawn || !enumcreaturetype.isPersistent()) && difference > 0) { -+ // Paper end ++ // Paper end - Optional per player mob spawns // CraftBukkit end Objects.requireNonNull(info); NaturalSpawner.SpawnPredicate spawnercreature_c = info::canSpawn; Objects.requireNonNull(info); - NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn); -+ // Paper start ++ // Paper start - Optional per player mob spawns + int spawnCount = NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn, + difference, world.paperConfig().entities.spawning.perPlayerMobSpawns ? world.getChunkSource().chunkMap::updatePlayerMobTypeMap : null); + info.mobCategoryCounts.mergeInt(enumcreaturetype, spawnCount, Integer::sum); -+ // Paper end ++ // Paper end - Optional per player mob spawns } } @@ -155,18 +155,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) { -+ // Paper start - add parameters and int ret type ++ // Paper start - Optional per player mob spawns + spawnCategoryForChunk(group, world, chunk, checker, runner, Integer.MAX_VALUE, null); + } + public static int spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer trackEntity) { -+ // Paper end - add parameters and int ret type ++ // Paper end - Optional per player mob spawns BlockPos blockposition = NaturalSpawner.getRandomPosWithin(world, chunk); if (blockposition.getY() >= world.getMinBuildHeight() + 1) { - NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner); -+ return NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner, maxSpawns, trackEntity); // Paper ++ return NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner, maxSpawns, trackEntity); // Paper - Optional per player mob spawns } -+ return 0; // Paper ++ return 0; // Paper - Optional per player mob spawns } @VisibleForDebug @@ -174,22 +174,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }); } -+ // Paper start - add maxSpawns parameter and return spawned mobs ++ // Paper start - Optional per player mob spawns public static void spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) { + spawnCategoryForPosition(group, world,chunk, pos, checker, runner, Integer.MAX_VALUE, null); + } + public static int spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer trackEntity) { -+ // Paper end - add maxSpawns parameter and return spawned mobs ++ // Paper end - Optional per player mob spawns StructureManager structuremanager = world.structureManager(); ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator(); int i = pos.getY(); BlockState iblockdata = world.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn -+ int j = 0; // Paper - moved up ++ int j = 0; // Paper - Optional per player mob spawns; moved up if (iblockdata != null && !iblockdata.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); - int j = 0; -+ //int j = 0; // Paper - moved up ++ //int j = 0; // Paper - Optional per player mob spawns; moved up int k = 0; while (k < 3) { @@ -198,7 +198,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2); if (doSpawning == PreSpawnStatus.ABORT) { - return; -+ return j; // Paper ++ return j; // Paper - Optional per player mob spawns } if (doSpawning == PreSpawnStatus.SUCCESS && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) { // Paper end @@ -206,7 +206,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entityinsentient == null) { - return; -+ return j; // Paper ++ return j; // Paper - Optional per player mob spawns } entityinsentient.moveTo(d0, (double) i, d1, world.random.nextFloat() * 360.0F, 0.0F); @@ -214,17 +214,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ++j; ++k1; runner.run(entityinsentient, chunk); -+ // Paper start ++ // Paper start - Optional per player mob spawns + if (trackEntity != null) { + trackEntity.accept(entityinsentient); + } -+ // Paper end ++ // Paper end - Optional per player mob spawns } // CraftBukkit end - if (j >= entityinsentient.getMaxSpawnClusterSize()) { - return; -+ if (j >= entityinsentient.getMaxSpawnClusterSize() || j >= maxSpawns) { // Paper -+ return j; // Paper ++ if (j >= entityinsentient.getMaxSpawnClusterSize() || j >= maxSpawns) { // Paper - Optional per player mob spawns ++ return j; // Paper - Optional per player mob spawns } if (entityinsentient.isMaxGroupSizeReached(k1)) { @@ -232,7 +232,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -+ return j; // Paper ++ return j; // Paper - Optional per player mob spawns } private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel world, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double squaredDistance) { @@ -241,7 +241,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.mobCategoryCounts.addTo(enumcreaturetype, 1); - this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype); -+ if (this.localMobCapCalculator != null) this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype); // Paper ++ if (this.localMobCapCalculator != null) this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype); // Paper - Optional per player mob spawns } public int getSpawnableChunkCount() { @@ -249,7 +249,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int i = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; // CraftBukkit end -+ if (this.localMobCapCalculator == null) return this.mobCategoryCounts.getInt(enumcreaturetype) < i; // Paper ++ if (this.localMobCapCalculator == null) return this.mobCategoryCounts.getInt(enumcreaturetype) < i; // Paper - Optional per player mob spawns return this.mobCategoryCounts.getInt(enumcreaturetype) >= i ? false : this.localMobCapCalculator.canSpawn(enumcreaturetype, chunkcoordintpair); } } diff --git a/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch index b63029fa43..dbad5a52e2 100644 --- a/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch +++ b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch @@ -29,8 +29,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { -- if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper -+ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper - Pillager patrol spawn settings and per player options +- if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper - Add option to disable pillager patrols ++ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper - Add option to disable pillager patrols & Pillager patrol spawn settings and per player options if (!spawnMonsters) { return 0; } else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) { diff --git a/patches/server/Prevent-consuming-the-wrong-itemstack.patch b/patches/server/Prevent-consuming-the-wrong-itemstack.patch index 4ce245dbc0..f7c02434df 100644 --- a/patches/server/Prevent-consuming-the-wrong-itemstack.patch +++ b/patches/server/Prevent-consuming-the-wrong-itemstack.patch @@ -12,15 +12,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void startUsingItem(InteractionHand hand) { -+ // Paper start - forwarder to method with forceUpdate parameter ++ // Paper start - Prevent consuming the wrong itemstack + this.startUsingItem(hand, false); + } + public void startUsingItem(InteractionHand hand, boolean forceUpdate) { -+ // Paper end ++ // Paper end - Prevent consuming the wrong itemstack ItemStack itemstack = this.getItemInHand(hand); - if (!itemstack.isEmpty() && !this.isUsingItem()) { -+ if (!itemstack.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper use override flag ++ if (!itemstack.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper - Prevent consuming the wrong itemstack this.useItem = itemstack; this.useItemRemaining = itemstack.getUseDuration(); if (!this.level().isClientSide) { @@ -28,7 +28,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.releaseUsingItem(); } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { -+ this.startUsingItem(this.getUsedItemHand(), true); // Paper ++ this.startUsingItem(this.getUsedItemHand(), true); // Paper - Prevent consuming the wrong itemstack this.triggerItemUseEffects(this.useItem, 16); // CraftBukkit start - fire PlayerItemConsumeEvent ItemStack itemstack; diff --git a/patches/server/Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch b/patches/server/Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch index 333f3f4150..89672d2f5f 100644 --- a/patches/server/Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch +++ b/patches/server/Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch @@ -13,8 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - BlockState blockState = world.getBlockState(globalPos.pos()); -+ BlockState blockState = world.getBlockStateIfLoaded(globalPos.pos()); // Paper -+ if (blockState == null) { return false; } // Paper ++ BlockState blockState = world.getBlockStateIfLoaded(globalPos.pos()); // Paper - Prevent sync chunk loads when villagers try to find beds ++ if (blockState == null) { return false; } // Paper - Prevent sync chunk loads when villagers try to find beds return globalPos.pos().closerToCenterThan(entity.position(), 2.0D) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED); } } diff --git a/patches/server/Properly-handle-BlockBreakEvent-isDropItems.patch b/patches/server/Properly-handle-BlockBreakEvent-isDropItems.patch index dbf4495fd7..ac025874f8 100644 --- a/patches/server/Properly-handle-BlockBreakEvent-isDropItems.patch +++ b/patches/server/Properly-handle-BlockBreakEvent-isDropItems.patch @@ -88,7 +88,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - super.playerDestroy(world, player, pos, state, blockEntity, tool); + public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion + super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion - // Paper start + // Paper start - Improve Block#breakNaturally API this.afterDestroy(world, pos, tool); } diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java diff --git a/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch index 01cfcaa196..13d4b204ac 100644 --- a/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch +++ b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch @@ -21,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockPos blockposition = BlockPos.containing(d4, d5, d6); BlockState iblockdata = this.level.getBlockState(blockposition); + if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed - FluidState fluid = iblockdata.getFluidState(); // Paper + FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions if (!this.level.isInWorldBounds(blockposition)) { diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java diff --git a/patches/server/Show-blockstate-location-if-we-failed-to-read-it.patch b/patches/server/Show-blockstate-location-if-we-failed-to-read-it.patch index cdc25a7371..9bf8a918cc 100644 --- a/patches/server/Show-blockstate-location-if-we-failed-to-read-it.patch +++ b/patches/server/Show-blockstate-location-if-we-failed-to-read-it.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.tileEntity = tileEntity; -+ try { // Paper - show location on failure ++ try { // Paper - Show blockstate location if we failed to read it // Paper start this.snapshotDisabled = DISABLE_SNAPSHOT; if (DISABLE_SNAPSHOT) { @@ -20,14 +20,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.load(this.snapshot); } // Paper end -+ // Paper start - show location on failure ++ // Paper start - Show blockstate location if we failed to read it + } catch (Throwable thr) { + if (thr instanceof ThreadDeath) { + throw (ThreadDeath)thr; + } + throw new RuntimeException("Failed to read BlockState at: world: " + this.getWorld().getName() + " location: (" + this.getX() + ", " + this.getY() + ", " + this.getZ() + ")", thr); + } -+ // Paper end ++ // Paper end - Show blockstate location if we failed to read it } protected CraftBlockEntityState(CraftBlockEntityState state) { diff --git a/patches/server/Validate-tripwire-hook-placement-before-update.patch b/patches/server/Validate-tripwire-hook-placement-before-update.patch index 34e1c65d66..4b37596188 100644 --- a/patches/server/Validate-tripwire-hook-placement-before-update.patch +++ b/patches/server/Validate-tripwire-hook-placement-before-update.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 TripWireHookBlock.emitState(world, pos, flag4, flag5, flag2, flag3); if (!flag) { -+ if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - validate ++ if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - Validate tripwire hook placement before update world.setBlock(pos, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection), 3); if (flag1) { TripWireHookBlock.notifyNeighbors(block, world, pos, enumdirection); diff --git a/patches/server/offset-item-frame-ticking.patch b/patches/server/offset-item-frame-ticking.patch index dc9e476c7a..89178a6c14 100644 --- a/patches/server/offset-item-frame-ticking.patch +++ b/patches/server/offset-item-frame-ticking.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return entity instanceof HangingEntity; }; - private int checkInterval; -+ private int checkInterval; { this.checkInterval = this.getId() % this.level().spigotConfig.hangingTickFrequency; } // Paper ++ private int checkInterval; { this.checkInterval = this.getId() % this.level().spigotConfig.hangingTickFrequency; } // Paper - Perf: offset item frame ticking public BlockPos pos; protected Direction direction;