From 3bb1a88218169d8bb4a70b9ea94270d17f8dfa4e Mon Sep 17 00:00:00 2001 From: MrPowerGamerBR Date: Tue, 31 Aug 2021 20:14:55 -0300 Subject: [PATCH] Moar patches --- ...timize-random-calls-in-chunk-ticking.patch | 109 +++++ ...e-iterators-from-inventory-contains.patch} | 0 ...urn-optimization-for-target-finding.patch} | 0 patches/server/0012-Cache-palette-array.patch | 77 +++ ...for-plugins-not-shutting-down-tasks.patch} | 0 ...014-Improve-fluid-direction-caching.patch} | 0 ...Cache-climbing-check-for-activation.patch} | 0 ...0016-Use-array-for-gamerule-storage.patch} | 0 ...lisionContext-a-live-representation.patch} | 0 ...r-to-use-fast-item-merge-raytracing.patch} | 0 ...-aging-cache-for-biome-temperatures.patch} | 0 ...eams-and-iterators-from-range-check.patch} | 0 ...> 0021-Skip-cloning-loot-parameters.patch} | 0 ...45-block-goal-shouldn-t-load-chunks.patch} | 0 ...sequencing-of-futures-for-chunk-gen.patch} | 0 ...ove-container-checking-with-a-bitset.patch | 456 ++++++++++++++++++ ...er-checking-for-useless-move-packets.patch | 26 + ...ld-height-in-the-chunk-as-it-s-final.patch | 46 ++ ...hread-unsafe-random-for-mob-spawning.patch | 40 ++ ...-streams-from-getting-nearby-players.patch | 60 +++ ...029-Remove-lambda-from-ticking-guard.patch | 52 ++ .../0030-Configurable-feature-seeds.patch | 80 +++ 22 files changed, 946 insertions(+) create mode 100644 patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch rename patches/server/{0009-Remove-iterators-from-inventory-contains.patch => 0010-Remove-iterators-from-inventory-contains.patch} (100%) rename patches/server/{0010-Early-return-optimization-for-target-finding.patch => 0011-Early-return-optimization-for-target-finding.patch} (100%) create mode 100644 patches/server/0012-Cache-palette-array.patch rename patches/server/{0011-More-debug-for-plugins-not-shutting-down-tasks.patch => 0013-More-debug-for-plugins-not-shutting-down-tasks.patch} (100%) rename patches/server/{0012-Improve-fluid-direction-caching.patch => 0014-Improve-fluid-direction-caching.patch} (100%) rename patches/server/{0013-Cache-climbing-check-for-activation.patch => 0015-Cache-climbing-check-for-activation.patch} (100%) rename patches/server/{0014-Use-array-for-gamerule-storage.patch => 0016-Use-array-for-gamerule-storage.patch} (100%) rename patches/server/{0015-Make-EntityCollisionContext-a-live-representation.patch => 0017-Make-EntityCollisionContext-a-live-representation.patch} (100%) rename patches/server/{0016-Patch-Paper-to-use-fast-item-merge-raytracing.patch => 0018-Patch-Paper-to-use-fast-item-merge-raytracing.patch} (100%) rename patches/server/{0017-Use-aging-cache-for-biome-temperatures.patch => 0019-Use-aging-cache-for-biome-temperatures.patch} (100%) rename patches/server/{0018-Remove-streams-and-iterators-from-range-check.patch => 0020-Remove-streams-and-iterators-from-range-check.patch} (100%) rename patches/server/{0019-Skip-cloning-loot-parameters.patch => 0021-Skip-cloning-loot-parameters.patch} (100%) rename patches/server/{0020-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch => 0022-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch} (100%) rename patches/server/{0021-Quicker-sequencing-of-futures-for-chunk-gen.patch => 0023-Quicker-sequencing-of-futures-for-chunk-gen.patch} (100%) create mode 100644 patches/server/0024-Improve-container-checking-with-a-bitset.patch create mode 100644 patches/server/0025-Better-checking-for-useless-move-packets.patch create mode 100644 patches/server/0026-Cache-world-height-in-the-chunk-as-it-s-final.patch create mode 100644 patches/server/0027-Use-thread-unsafe-random-for-mob-spawning.patch create mode 100644 patches/server/0028-Remove-streams-from-getting-nearby-players.patch create mode 100644 patches/server/0029-Remove-lambda-from-ticking-guard.patch create mode 100644 patches/server/0030-Configurable-feature-seeds.patch diff --git a/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch b/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch new file mode 100644 index 0000000..bc987ca --- /dev/null +++ b/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Thu, 7 Jan 2021 11:49:36 -0600 +Subject: [PATCH] Optimize random calls in chunk ticking + +Especially at over 30,000 chunks these random calls are fairly heavy. We +use a different method here for checking lightning, and for checking +ice. + +Lightning: Each chunk now keeps an int of how many ticks until the +lightning should strike. This int is a random number from 0 to 100000 * 2, +the multiplication is required to keep the probability the same. + +Ice and snow: We just generate a single random number 0-16 and increment +it, while checking if it's 0 for the current chunk. + +Depending on configuration for things that tick in a chunk, this is a +5-10% improvement. + +Airplane +Copyright (C) 2020 Technove LLC + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index 7470f3ba66c2e894b5a5b0ba392ecabf8b04aff9..35f27e9a7c82eaec5b4a1a71696dac8485b2cd6d 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -983,6 +983,7 @@ public class ServerChunkCache extends ChunkSource { + } + // Paper end - optimize isOutisdeRange + this.level.getProfiler().push("pollingChunks"); ++ this.level.resetIceAndSnowTick(); // Airplane - reset ice & snow tick random + int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + boolean flag2 = level.ticksPerAnimalSpawns != 0L && worlddata.getGameTime() % level.ticksPerAnimalSpawns == 0L; // CraftBukkit + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index cebaf0fb8187335ca303621a2cb412bb22584e23..bc1a9981a769f3126efd453ee6bd4f5f32690fc8 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -833,6 +833,8 @@ public class ServerLevel extends Level implements WorldGenLevel { + private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); + // Paper end + ++ private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Airplane ++ + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { + ChunkPos chunkcoordintpair = chunk.getPos(); + boolean flag = this.isRaining(); +@@ -843,7 +845,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + gameprofilerfiller.push("thunder"); + final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change + +- if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.random.nextInt(100000) == 0) { // Paper - Disable thunder ++ if (!this.paperConfig.disableThunder && flag && this.isThundering() && chunk.shouldDoLightning(this.random)) { // Paper - Disable thunder // Airplane - replace random with shouldDoLightning + blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper + if (this.isRainingAt(blockposition)) { + DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition); +@@ -867,7 +869,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + + gameprofilerfiller.popPush("iceandsnow"); +- if (!this.paperConfig.disableIceAndSnow && this.randomTickRandom.nextInt(16) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking ++ if (!this.paperConfig.disableIceAndSnow && (this.currentIceAndSnowTick++ & 15) == 0) { // Paper - Disable ice and snow // Paper - optimise random ticking // Airplane - optimize further random ticking + // Paper start - optimise chunk ticking + this.getRandomBlockPosition(j, 0, k, 15, blockposition); + int normalY = chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, blockposition.getX() & 15, blockposition.getZ() & 15) + 1; +diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +index 86686c24b0b7de4b4bfadbc77419a8872a8e86ee..ff0fab668801d0b32abffbfedc7eb24abf71fed0 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -172,6 +172,18 @@ public class LevelChunk implements ChunkAccess { + } + // Paper end - rewrite light engine + ++ // Airplane start - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively ++ private int lightningTick; ++ // shouldDoLightning compiles down to 29 bytes, which with the default of 35 byte inlining should guarantee an inline ++ public final boolean shouldDoLightning(java.util.Random random) { ++ if (this.lightningTick-- <= 0) { ++ this.lightningTick = random.nextInt(100000) << 1; ++ return true; ++ } ++ return false; ++ } ++ // Airplane end ++ + public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes) { + this(world, pos, biomes, UpgradeData.EMPTY, EmptyTickList.empty(), EmptyTickList.empty(), 0L, (LevelChunkSection[]) null, (Consumer) null); + } +@@ -220,6 +232,7 @@ public class LevelChunk implements ChunkAccess { + this.postProcessing = new ShortList[world.getSectionsCount()]; + // CraftBukkit start + this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); ++ this.lightningTick = this.level.random.nextInt(100000) << 1; // Airplane - initialize lightning tick + } + + public org.bukkit.Chunk bukkitChunk; diff --git a/patches/server/0009-Remove-iterators-from-inventory-contains.patch b/patches/server/0010-Remove-iterators-from-inventory-contains.patch similarity index 100% rename from patches/server/0009-Remove-iterators-from-inventory-contains.patch rename to patches/server/0010-Remove-iterators-from-inventory-contains.patch diff --git a/patches/server/0010-Early-return-optimization-for-target-finding.patch b/patches/server/0011-Early-return-optimization-for-target-finding.patch similarity index 100% rename from patches/server/0010-Early-return-optimization-for-target-finding.patch rename to patches/server/0011-Early-return-optimization-for-target-finding.patch diff --git a/patches/server/0012-Cache-palette-array.patch b/patches/server/0012-Cache-palette-array.patch new file mode 100644 index 0000000..d93a088 --- /dev/null +++ b/patches/server/0012-Cache-palette-array.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Thu, 4 Feb 2021 23:28:46 -0600 +Subject: [PATCH] Cache palette array + +The reasoning for reusing it in ChunkRegionLoader is because ThreadLocal +lookups are fairly expensive, and if we put it in DataPaletteBlock the +ThreadLocal lookup would happen 18 times. + +Airplane +Copyright (C) 2020 Technove LLC + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +index c9e942669458668a184aaec3bc0a5509dd6ab5f0..178e56ffc87ea2beb4d84d1f278f4acf90102379 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java ++++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +@@ -263,13 +263,17 @@ public class PalettedContainer implements PaletteResize { + + } + ++ // Airplane start - allow reusing int array + public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey) { // Paper - synchronize ++ this.write(nbt, paletteKey, dataKey, new int[4096]); ++ } ++ public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey, int[] is) { // Paper - synchronize // Airplane end + try { + this.acquire(); + HashMapPalette hashMapPalette = new HashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer); + T object = this.defaultValue; + int i = hashMapPalette.idFor(this.defaultValue); +- int[] is = new int[4096]; ++ //int[] is = new int[4096]; // Airplane + + for(int j = 0; j < 4096; ++j) { + T object2 = this.get(j); +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +index 7921ee2786d0d6a60d43786b20efc03a0f9178e3..9ea4229f58679c6c833762fc6a50471445ff0b9d 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +@@ -500,6 +500,7 @@ public class ChunkSerializer { + return new AsyncSaveData(blockLight, skyLight, blockTickListSerialized, fluidTickListSerialized, blockEntitiesSerialized, world.getGameTime()); + } + ++ private static final ThreadLocal paletteArray = ThreadLocal.withInitial(() -> new int[4096]); // Airplane + public static CompoundTag write(ServerLevel world, ChunkAccess chunk) { + return saveChunk(world, chunk, null); + } +@@ -533,6 +534,7 @@ public class ChunkSerializer { + ThreadedLevelLightEngine lightenginethreaded = world.getChunkSource().getLightEngine(); + boolean flag = chunk.isLightCorrect(); + ++ int[] is = paletteArray.get(); // Airplane - use cached + for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) { + int finalI = i; // CraftBukkit - decompile errors + LevelChunkSection chunksection = (LevelChunkSection) Arrays.stream(achunksection).filter((chunksection1) -> { +@@ -547,7 +549,7 @@ public class ChunkSerializer { + + nbttagcompound2.putByte("Y", (byte) (i & 255)); + if (chunksection != LevelChunk.EMPTY_SECTION) { +- chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates"); ++ chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates", is); // Airplane - reuse array + } + + // Paper start - replace light engine diff --git a/patches/server/0011-More-debug-for-plugins-not-shutting-down-tasks.patch b/patches/server/0013-More-debug-for-plugins-not-shutting-down-tasks.patch similarity index 100% rename from patches/server/0011-More-debug-for-plugins-not-shutting-down-tasks.patch rename to patches/server/0013-More-debug-for-plugins-not-shutting-down-tasks.patch diff --git a/patches/server/0012-Improve-fluid-direction-caching.patch b/patches/server/0014-Improve-fluid-direction-caching.patch similarity index 100% rename from patches/server/0012-Improve-fluid-direction-caching.patch rename to patches/server/0014-Improve-fluid-direction-caching.patch diff --git a/patches/server/0013-Cache-climbing-check-for-activation.patch b/patches/server/0015-Cache-climbing-check-for-activation.patch similarity index 100% rename from patches/server/0013-Cache-climbing-check-for-activation.patch rename to patches/server/0015-Cache-climbing-check-for-activation.patch diff --git a/patches/server/0014-Use-array-for-gamerule-storage.patch b/patches/server/0016-Use-array-for-gamerule-storage.patch similarity index 100% rename from patches/server/0014-Use-array-for-gamerule-storage.patch rename to patches/server/0016-Use-array-for-gamerule-storage.patch diff --git a/patches/server/0015-Make-EntityCollisionContext-a-live-representation.patch b/patches/server/0017-Make-EntityCollisionContext-a-live-representation.patch similarity index 100% rename from patches/server/0015-Make-EntityCollisionContext-a-live-representation.patch rename to patches/server/0017-Make-EntityCollisionContext-a-live-representation.patch diff --git a/patches/server/0016-Patch-Paper-to-use-fast-item-merge-raytracing.patch b/patches/server/0018-Patch-Paper-to-use-fast-item-merge-raytracing.patch similarity index 100% rename from patches/server/0016-Patch-Paper-to-use-fast-item-merge-raytracing.patch rename to patches/server/0018-Patch-Paper-to-use-fast-item-merge-raytracing.patch diff --git a/patches/server/0017-Use-aging-cache-for-biome-temperatures.patch b/patches/server/0019-Use-aging-cache-for-biome-temperatures.patch similarity index 100% rename from patches/server/0017-Use-aging-cache-for-biome-temperatures.patch rename to patches/server/0019-Use-aging-cache-for-biome-temperatures.patch diff --git a/patches/server/0018-Remove-streams-and-iterators-from-range-check.patch b/patches/server/0020-Remove-streams-and-iterators-from-range-check.patch similarity index 100% rename from patches/server/0018-Remove-streams-and-iterators-from-range-check.patch rename to patches/server/0020-Remove-streams-and-iterators-from-range-check.patch diff --git a/patches/server/0019-Skip-cloning-loot-parameters.patch b/patches/server/0021-Skip-cloning-loot-parameters.patch similarity index 100% rename from patches/server/0019-Skip-cloning-loot-parameters.patch rename to patches/server/0021-Skip-cloning-loot-parameters.patch diff --git a/patches/server/0020-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch b/patches/server/0022-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch similarity index 100% rename from patches/server/0020-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch rename to patches/server/0022-Fix-Paper-6045-block-goal-shouldn-t-load-chunks.patch diff --git a/patches/server/0021-Quicker-sequencing-of-futures-for-chunk-gen.patch b/patches/server/0023-Quicker-sequencing-of-futures-for-chunk-gen.patch similarity index 100% rename from patches/server/0021-Quicker-sequencing-of-futures-for-chunk-gen.patch rename to patches/server/0023-Quicker-sequencing-of-futures-for-chunk-gen.patch diff --git a/patches/server/0024-Improve-container-checking-with-a-bitset.patch b/patches/server/0024-Improve-container-checking-with-a-bitset.patch new file mode 100644 index 0000000..cdb7bd6 --- /dev/null +++ b/patches/server/0024-Improve-container-checking-with-a-bitset.patch @@ -0,0 +1,456 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Wed, 19 May 2021 13:08:26 -0500 +Subject: [PATCH] Improve container checking with a bitset + + +diff --git a/src/main/java/gg/airplane/structs/ItemListWithBitset.java b/src/main/java/gg/airplane/structs/ItemListWithBitset.java +new file mode 100644 +index 0000000000000000000000000000000000000000..04565b596f7579eb22263ef844513aeba3437eb3 +--- /dev/null ++++ b/src/main/java/gg/airplane/structs/ItemListWithBitset.java +@@ -0,0 +1,105 @@ ++package gg.airplane.structs; ++ ++import net.minecraft.core.NonNullList; ++import net.minecraft.world.item.ItemStack; ++import org.apache.commons.lang.Validate; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Arrays; ++ ++public class ItemListWithBitset extends NonNullList { ++ public static ItemListWithBitset fromNonNullList(NonNullList list) { ++ if (list instanceof ItemListWithBitset) { ++ return (ItemListWithBitset) list; ++ } ++ return new ItemListWithBitset(list); ++ } ++ ++ private static ItemStack[] createArray(int size) { ++ ItemStack[] array = new ItemStack[size]; ++ Arrays.fill(array, ItemStack.EMPTY); ++ return array; ++ } ++ ++ private final ItemStack[] items; ++ ++ private long bitSet = 0; ++ private final long allBits; ++ ++ private ItemListWithBitset(NonNullList list) { ++ this(list.size()); ++ ++ for (int i = 0; i < list.size(); i++) { ++ this.set(i, list.get(i)); ++ } ++ } ++ ++ public ItemListWithBitset(int size) { ++ super(null, ItemStack.EMPTY); ++ ++ Validate.isTrue(size < Long.BYTES * 8, "size is too large"); ++ ++ this.items = createArray(size); ++ this.allBits = ((1L << size) - 1); ++ } ++ ++ public boolean isCompletelyEmpty() { ++ return this.bitSet == 0; ++ } ++ ++ public boolean hasFullStacks() { ++ return (this.bitSet & this.allBits) == allBits; ++ } ++ ++ @Override ++ public ItemStack set(int index, @NotNull ItemStack itemStack) { ++ ItemStack existing = this.items[index]; ++ ++ this.items[index] = itemStack; ++ ++ if (itemStack == ItemStack.EMPTY) { ++ this.bitSet &= ~(1L << index); ++ } else { ++ this.bitSet |= 1L << index; ++ } ++ ++ return existing; ++ } ++ ++ @NotNull ++ @Override ++ public ItemStack get(int var0) { ++ return this.items[var0]; ++ } ++ ++ @Override ++ public int size() { ++ return this.items.length; ++ } ++ ++ @Override ++ public void clear() { ++ Arrays.fill(this.items, ItemStack.EMPTY); ++ } ++ ++ // these are unsupported for block inventories which have a static size ++ @Override ++ public void add(int var0, ItemStack var1) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public ItemStack remove(int var0) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public String toString() { ++ return "ItemListWithBitset{" + ++ "items=" + Arrays.toString(items) + ++ ", bitSet=" + Long.toString(bitSet, 2) + ++ ", allBits=" + Long.toString(allBits, 2) + ++ ", size=" + this.items.length + ++ '}'; ++ } ++} +diff --git a/src/main/java/net/minecraft/world/CompoundContainer.java b/src/main/java/net/minecraft/world/CompoundContainer.java +index 087ae3a6b49872a3580eb1a572bdbc493711a77a..5ef8657197beea06c1dcad6a32968c56a823b182 100644 +--- a/src/main/java/net/minecraft/world/CompoundContainer.java ++++ b/src/main/java/net/minecraft/world/CompoundContainer.java +@@ -1,5 +1,6 @@ + package net.minecraft.world; + ++import net.minecraft.core.Direction; // Airplane + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.item.ItemStack; + +@@ -72,6 +73,23 @@ public class CompoundContainer implements Container { + this.container2 = second; + } + ++ // Airplane start ++ @Override ++ public boolean hasEmptySlot(Direction enumdirection) { ++ return this.container1.hasEmptySlot(null) || this.container2.hasEmptySlot(null); ++ } ++ ++ @Override ++ public boolean isCompletelyFull(Direction enumdirection) { ++ return this.container1.isCompletelyFull(null) && this.container2.isCompletelyFull(null); ++ } ++ ++ @Override ++ public boolean isCompletelyEmpty(Direction enumdirection) { ++ return this.container1.isCompletelyEmpty(null) && this.container2.isCompletelyEmpty(null); ++ } ++ // Airplane end ++ + @Override + public int getContainerSize() { + return this.container1.getContainerSize() + this.container2.getContainerSize(); +diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java +index 7437f01ca8f416e2c9150250e324af4725a4efb6..bdcd0e38a3ba904811112f41d8bfbfc0902ef190 100644 +--- a/src/main/java/net/minecraft/world/Container.java ++++ b/src/main/java/net/minecraft/world/Container.java +@@ -1,6 +1,8 @@ + package net.minecraft.world; + + import java.util.Set; ++ ++import net.minecraft.core.Direction; // Airplane + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.item.Item; + import net.minecraft.world.item.ItemStack; +@@ -9,6 +11,63 @@ import org.bukkit.craftbukkit.entity.CraftHumanEntity; + // CraftBukkit end + + public interface Container extends Clearable { ++ // Airplane start - allow the inventory to override and optimize these frequent calls ++ default boolean hasEmptySlot(@org.jetbrains.annotations.Nullable Direction enumdirection) { // there is a slot with 0 items in it ++ if (this instanceof WorldlyContainer worldlyContainer) { ++ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { ++ if (this.getItem(i).isEmpty()) { ++ return true; ++ } ++ } ++ } else { ++ int size = this.getContainerSize(); ++ for (int i = 0; i < size; i++) { ++ if (this.getItem(i).isEmpty()) { ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ ++ default boolean isCompletelyFull(@org.jetbrains.annotations.Nullable Direction enumdirection) { // every stack is maxed ++ if (this instanceof WorldlyContainer worldlyContainer) { ++ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { ++ ItemStack itemStack = this.getItem(i); ++ if (itemStack.getCount() < itemStack.getMaxStackSize()) { ++ return false; ++ } ++ } ++ } else { ++ int size = this.getContainerSize(); ++ for (int i = 0; i < size; i++) { ++ ItemStack itemStack = this.getItem(i); ++ if (itemStack.getCount() < itemStack.getMaxStackSize()) { ++ return false; ++ } ++ } ++ } ++ return true; ++ } ++ ++ default boolean isCompletelyEmpty(@org.jetbrains.annotations.Nullable Direction enumdirection) { ++ if (this instanceof WorldlyContainer worldlyContainer) { ++ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { ++ if (!this.getItem(i).isEmpty()) { ++ return false; ++ } ++ } ++ } else { ++ int size = this.getContainerSize(); ++ for (int i = 0; i < size; i++) { ++ if (!this.getItem(i).isEmpty()) { ++ return false; ++ } ++ } ++ } ++ return true; ++ } ++ // Airplane end + + int LARGE_MAX_STACK_SIZE = 64; + +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java +index f57864ce919ef4721cfb5913c636fe8903ce4cc1..4792d3d60e60202face2eb851c9f5b122dcfc19d 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java +@@ -40,7 +40,7 @@ import org.bukkit.inventory.InventoryHolder; + + public abstract class AbstractMinecartContainer extends AbstractMinecart implements Container, MenuProvider { + +- private NonNullList itemStacks; ++ private gg.airplane.structs.ItemListWithBitset itemStacks; // Airplane + @Nullable + public ResourceLocation lootTable; + public long lootTableSeed; +@@ -89,12 +89,12 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme + + protected AbstractMinecartContainer(EntityType type, Level world) { + super(type, world); +- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513 ++ this.itemStacks = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // CraftBukkit - SPIGOT-3513 // Airplane + } + + protected AbstractMinecartContainer(EntityType type, double x, double y, double z, Level world) { + super(type, world, x, y, z); +- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513 ++ this.itemStacks = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // CraftBukkit - SPIGOT-3513 // Airplane + } + + @Override +@@ -217,7 +217,7 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme + protected void readAdditionalSaveData(CompoundTag nbt) { + super.readAdditionalSaveData(nbt); + this.lootableData.loadNbt(nbt); // Paper +- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); ++ this.itemStacks = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // Airplane + if (nbt.contains("LootTable", 8)) { + this.lootTable = new ResourceLocation(nbt.getString("LootTable")); + this.lootTableSeed = nbt.getLong("LootTableSeed"); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java +index 52de9852f87d346714a950b60a0004d386ac10f0..305a8f5ea917c7e242011fa98a3e161517afe9be 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java +@@ -32,7 +32,7 @@ import org.bukkit.entity.HumanEntity; + public class ChestBlockEntity extends RandomizableContainerBlockEntity implements LidBlockEntity { + + private static final int EVENT_SET_OPEN_COUNT = 1; +- private NonNullList items; ++ private gg.airplane.structs.ItemListWithBitset items; // Airplane + public final ContainerOpenersCounter openersCounter; + private final ChestLidController chestLidController; + +@@ -66,9 +66,10 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement + } + // CraftBukkit end + ++ private final boolean isNative = getClass().equals(ChestBlockEntity.class); // Airplane + protected ChestBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); +- this.items = NonNullList.withSize(27, ItemStack.EMPTY); ++ this.items = new gg.airplane.structs.ItemListWithBitset(27); // Airplane - use with bitset + this.openersCounter = new ContainerOpenersCounter() { + @Override + protected void onOpen(Level world, BlockPos pos, BlockState state) { +@@ -99,6 +100,23 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement + this.chestLidController = new ChestLidController(); + } + ++ // Airplane start ++ @Override ++ public boolean hasEmptySlot(Direction enumdirection) { ++ return isNative ? !this.items.hasFullStacks() : super.hasEmptySlot(enumdirection); ++ } ++ ++ @Override ++ public boolean isCompletelyFull(Direction enumdirection) { ++ return isNative ? this.items.hasFullStacks() && super.isCompletelyFull(enumdirection) : super.isCompletelyFull(enumdirection); ++ } ++ ++ @Override ++ public boolean isCompletelyEmpty(Direction enumdirection) { ++ return isNative && this.items.isCompletelyEmpty() || super.isCompletelyEmpty(enumdirection); ++ } ++ // Airplane end ++ + public ChestBlockEntity(BlockPos pos, BlockState state) { + this(BlockEntityType.CHEST, pos, state); + } +@@ -116,7 +134,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement + @Override + public void load(CompoundTag nbt) { + super.load(nbt); +- this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); ++ this.items = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // Airplane + if (!this.tryLoadLootTable(nbt)) { + ContainerHelper.loadAllItems(nbt, this.items); + } +@@ -189,7 +207,7 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement + + @Override + protected void setItems(NonNullList list) { +- this.items = list; ++ this.items = gg.airplane.structs.ItemListWithBitset.fromNonNullList(list); // Airplane + } + + @Override +diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java +index d41851f9119c334cae3fc2c433d6450a3eed9096..ddf82e65d3ef1f53b72017bf5159b9f7b5484632 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java +@@ -44,7 +44,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + + public static final int MOVE_ITEM_SPEED = 8; + public static final int HOPPER_CONTAINER_SIZE = 5; +- private NonNullList items; ++ private gg.airplane.structs.ItemListWithBitset items; // Airplane + private int cooldownTime; + private long tickedGameTime; + +@@ -80,14 +80,31 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + + public HopperBlockEntity(BlockPos pos, BlockState state) { + super(BlockEntityType.HOPPER, pos, state); +- this.items = NonNullList.withSize(5, ItemStack.EMPTY); ++ this.items = new gg.airplane.structs.ItemListWithBitset(5); // Airplane + this.cooldownTime = -1; + } + ++ // Airplane start ++ @Override ++ public boolean hasEmptySlot(Direction enumdirection) { ++ return !this.items.hasFullStacks(); ++ } ++ ++ @Override ++ public boolean isCompletelyFull(Direction enumdirection) { ++ return this.items.hasFullStacks() && super.isCompletelyFull(enumdirection); ++ } ++ ++ @Override ++ public boolean isCompletelyEmpty(Direction enumdirection) { ++ return this.items.isCompletelyEmpty() || super.isCompletelyEmpty(enumdirection); ++ } ++ // Airplane end ++ + @Override + public void load(CompoundTag nbt) { + super.load(nbt); +- this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); ++ this.items = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // Airplane + if (!this.tryLoadLootTable(nbt)) { + ContainerHelper.loadAllItems(nbt, this.items); + } +@@ -160,7 +177,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + flag = HopperBlockEntity.a(world, pos, state, (Container) blockEntity, blockEntity); // CraftBukkit + } + +- if (!blockEntity.inventoryFull()) { ++ if (!blockEntity.items.hasFullStacks() || !blockEntity.inventoryFull()) { // Airplane - use bitset first + flag |= booleansupplier.getAsBoolean(); + } + +@@ -199,7 +216,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + skipPushModeEventFire = skipHopperEvents; + boolean foundItem = false; + for (int i = 0; i < hopper.getContainerSize(); ++i) { +- ItemStack item = hopper.getItem(i); ++ ItemStack item = hopper.getItem(i); // Airplane + if (!item.isEmpty()) { + foundItem = true; + ItemStack origItemStack = item; +@@ -403,12 +420,18 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + } + + private static boolean isFullContainer(Container inventory, Direction direction) { +- return allMatch(inventory, direction, STACK_SIZE_TEST); // Paper - no streams ++ // Airplane start - use bitsets ++ //return allMatch(inventory, direction, STACK_SIZE_TEST); // Paper - no streams ++ return inventory.isCompletelyFull(direction); ++ // Airplane end + } + + private static boolean isEmptyContainer(Container inv, Direction facing) { + // Paper start +- return allMatch(inv, facing, IS_EMPTY_TEST); ++ // Airplane start - use bitsets ++ //return allMatch(inv, facing, IS_EMPTY_TEST); ++ return inv.isCompletelyEmpty(facing); ++ // Airplane end + } + private static boolean allMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate test) { + if (iinventory instanceof WorldlyContainer) { +@@ -585,7 +608,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + + if (HopperBlockEntity.canPlaceItemInContainer(to, stack, slot, enumdirection)) { + boolean flag = false; +- boolean flag1 = to.isEmpty(); ++ boolean flag1 = to.isCompletelyEmpty(enumdirection); // Airplane + + if (itemstack1.isEmpty()) { + // Spigot start - SPIGOT-6693, InventorySubcontainer#setItem +@@ -731,7 +754,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + + @Override + protected void setItems(NonNullList list) { +- this.items = list; ++ this.items = gg.airplane.structs.ItemListWithBitset.fromNonNullList(list); // Airplane + } + + public static void entityInside(Level world, BlockPos pos, BlockState state, Entity entity, HopperBlockEntity blockEntity) { +diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java +index ed3518fe7c841d9e1a9c97626acaa3d765a6d76f..ac564148956beb984650341c5c0994573f4f7225 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java +@@ -96,13 +96,8 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc + public boolean isEmpty() { + this.unpackLootTable((Player)null); + // Paper start +- for (ItemStack itemStack : this.getItems()) { +- if (!itemStack.isEmpty()) { +- return false; +- } +- } ++ return this.isCompletelyEmpty(null); // Airplane - use super + // Paper end +- return true; + } + + @Override diff --git a/patches/server/0025-Better-checking-for-useless-move-packets.patch b/patches/server/0025-Better-checking-for-useless-move-packets.patch new file mode 100644 index 0000000..a860358 --- /dev/null +++ b/patches/server/0025-Better-checking-for-useless-move-packets.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Thu, 20 May 2021 12:05:47 -0500 +Subject: [PATCH] Better checking for useless move packets + + +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index b7c9294fdd3d799d410afba4a1118aa371c98533..c71bc00973899feec0ec5530bf3d237928810cf4 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -174,6 +174,7 @@ public class ServerEntity { + boolean flag4 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L; + + if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround() && !(com.destroystokyo.paper.PaperConfig.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync ++ if (flag2 || flag3 || this.entity instanceof AbstractArrow) { // Airplane + if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) { + if (flag2) { + packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.isOnGround()); +@@ -183,6 +184,7 @@ public class ServerEntity { + } else { + packet1 = new ClientboundMoveEntityPacket.PosRot(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), (byte) i, (byte) j, this.entity.isOnGround()); + } ++ } // Airplane + } else { + this.wasOnGround = this.entity.isOnGround(); + this.teleportDelay = 0; diff --git a/patches/server/0026-Cache-world-height-in-the-chunk-as-it-s-final.patch b/patches/server/0026-Cache-world-height-in-the-chunk-as-it-s-final.patch new file mode 100644 index 0000000..a86b228 --- /dev/null +++ b/patches/server/0026-Cache-world-height-in-the-chunk-as-it-s-final.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Tue, 22 Jun 2021 15:01:21 -0500 +Subject: [PATCH] Cache world height in the chunk, as it's final + + +diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +index ff0fab668801d0b32abffbfedc7eb24abf71fed0..e265980f07d95a7912bf8873819033e51ef04c98 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -184,11 +184,13 @@ public class LevelChunk implements ChunkAccess { + } + // Airplane end + ++ private final int levelHeight; private final int minBuildHeight; // Airplane + public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes) { + this(world, pos, biomes, UpgradeData.EMPTY, EmptyTickList.empty(), EmptyTickList.empty(), 0L, (LevelChunkSection[]) null, (Consumer) null); + } + + public LevelChunk(Level world, ChunkPos pos, ChunkBiomeContainer biomes, UpgradeData upgradeData, TickList blockTickScheduler, TickList fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sections, @Nullable Consumer loadToWorldConsumer) { ++ this.levelHeight = world.getHeight(); this.minBuildHeight = world.getMinBuildHeight(); // Airplane + // Paper start + this.blockNibbles = StarLightEngine.getFilledEmptyLight(world); + this.skyNibbles = StarLightEngine.getFilledEmptyLight(world); +@@ -1309,13 +1311,17 @@ public class LevelChunk implements ChunkAccess { + } + + @Override +- public int getMinBuildHeight() { +- return this.level.getMinBuildHeight(); ++ // Airplane start ++ public final int getMinBuildHeight() { ++ return this.minBuildHeight; ++ // Airplane end + } + + @Override +- public int getHeight() { +- return this.level.getHeight(); ++ // Airplane start ++ public final int getHeight() { ++ return this.levelHeight; ++ // Airplane end + } + + @Override diff --git a/patches/server/0027-Use-thread-unsafe-random-for-mob-spawning.patch b/patches/server/0027-Use-thread-unsafe-random-for-mob-spawning.patch new file mode 100644 index 0000000..a8b8fa9 --- /dev/null +++ b/patches/server/0027-Use-thread-unsafe-random-for-mob-spawning.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Tue, 22 Jun 2021 15:04:37 -0500 +Subject: [PATCH] Use thread unsafe random for mob spawning + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index bc1a9981a769f3126efd453ee6bd4f5f32690fc8..30478d8172a49110a4e31a2cb18311bfb119c242 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -830,7 +830,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + // Paper start - optimise random block ticking + private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); +- private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); ++ private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); public java.util.Random getThreadUnsafeRandom() { return this.randomTickRandom; } // Airplane - getter + // Paper end + + private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Airplane +diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +index 403f50ef908f65c62d4aaa7e5328faa0a7654480..e5fa91b5e19edab169b361865e7a6b2742c9ca4b 100644 +--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java ++++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +@@ -407,12 +407,12 @@ public final class NaturalSpawner { + return spawnGroup == MobCategory.MONSTER && world.getBlockState(pos.below()).is(Blocks.NETHER_BRICKS) && structureAccessor.getStructureAt(pos, false, StructureFeature.NETHER_BRIDGE).isValid() ? StructureFeature.NETHER_BRIDGE.getSpecialEnemies() : chunkGenerator.getMobsAt(biome != null ? biome : world.getBiome(pos), structureAccessor, spawnGroup, pos); + } + +- private static BlockPos getRandomPosWithin(Level world, LevelChunk chunk) { ++ private static BlockPos getRandomPosWithin(ServerLevel world, LevelChunk chunk) { // Airplane - accept serverlevel + ChunkPos chunkcoordintpair = chunk.getPos(); +- int i = chunkcoordintpair.getMinBlockX() + world.random.nextInt(16); +- int j = chunkcoordintpair.getMinBlockZ() + world.random.nextInt(16); ++ int i = chunkcoordintpair.getMinBlockX() + world.getThreadUnsafeRandom().nextInt(16); // Airplane - use thread unsafe random ++ int j = chunkcoordintpair.getMinBlockZ() + world.getThreadUnsafeRandom().nextInt(16); // Airplane + int k = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, j) + 1; +- int l = Mth.randomBetweenInclusive(world.random, world.getMinBuildHeight(), k); ++ int l = Mth.randomBetweenInclusive(world.getThreadUnsafeRandom(), world.getMinBuildHeight(), k); // Airplane + + return new BlockPos(i, l, j); + } diff --git a/patches/server/0028-Remove-streams-from-getting-nearby-players.patch b/patches/server/0028-Remove-streams-from-getting-nearby-players.patch new file mode 100644 index 0000000..1343bcc --- /dev/null +++ b/patches/server/0028-Remove-streams-from-getting-nearby-players.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul +Date: Tue, 29 Jun 2021 02:19:34 -0500 +Subject: [PATCH] Remove streams from getting nearby players + +This results in a 3% improvement at 20,000 entities, but more +importantly is the heaviest part of the entity tracker currently. + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 94857a736d2a16e8ade286c6f2ddf8bd798008eb..b4cf231c5a980e62cd3c00351e3e5232a71adbda 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -362,17 +362,36 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n + this.isLegacyTrackingEntity = isLegacyTrackingEntity; + } + ++ private org.spigotmc.TrackingRange.TrackingRangeType getFurthestEntity(Entity entity, net.minecraft.server.level.ChunkMap chunkMap, org.spigotmc.TrackingRange.TrackingRangeType type, int range) { ++ List passengers = entity.getPassengers(); ++ for (int i = 0, size = passengers.size(); i < size; i++) { ++ Entity passenger = passengers.get(i); ++ org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType; ++ int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal()); ++ if (passengerRange > range) { ++ type = passengerType; ++ range = passengerRange; ++ } ++ ++ type = this.getFurthestEntity(passenger, chunkMap, type, range); ++ } ++ ++ return type; ++ } ++ + public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getPlayersInTrackRange() { + // determine highest range of passengers + if (this.passengers.isEmpty()) { + return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()] + .getObjectsInRange(MCUtil.getCoordinateKey(this)); + } +- Iterable passengers = this.getIndirectPassengers(); ++ //Iterable passengers = this.getIndirectPassengers(); // Airplane + net.minecraft.server.level.ChunkMap chunkMap = ((ServerLevel)this.level).getChunkSource().chunkMap; + org.spigotmc.TrackingRange.TrackingRangeType type = this.trackingRangeType; + int range = chunkMap.getEntityTrackerRange(type.ordinal()); + ++ // Airplane start - use getFurthestEntity to skip getIndirectPassengers ++ /* + for (Entity passenger : passengers) { + org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType; + int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal()); +@@ -381,6 +400,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n + range = passengerRange; + } + } ++ */ ++ type = this.getFurthestEntity(this, chunkMap, type, range); ++ // Airplane end + + return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this)); + } diff --git a/patches/server/0029-Remove-lambda-from-ticking-guard.patch b/patches/server/0029-Remove-lambda-from-ticking-guard.patch new file mode 100644 index 0000000..2b41fcc --- /dev/null +++ b/patches/server/0029-Remove-lambda-from-ticking-guard.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul +Date: Fri, 2 Jul 2021 18:27:12 -0500 +Subject: [PATCH] Remove lambda from ticking guard + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 30478d8172a49110a4e31a2cb18311bfb119c242..d743d50a9b3ad9502fc11adc6fe43e9a58d7a94b 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -772,7 +772,20 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + + gameprofilerfiller.push("tick"); +- this.guardEntityTick(this::tickNonPassenger, entity); ++ // Airplane start - copied from this.guardEntityTick ++ try { ++ this.tickNonPassenger(entity); // Airplane - changed ++ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick ++ } catch (Throwable throwable) { ++ if (throwable instanceof ThreadDeath) throw throwable; // Paper ++ // Paper start - Prevent tile entity and entity crashes ++ final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); ++ MinecraftServer.LOGGER.error(msg, throwable); ++ getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); ++ entity.discard(); ++ // Paper end ++ } ++ // Airplane end + gameprofilerfiller.pop(); + } + } +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 90df8fbc7de54d31aeb92310dca72404b9ac0e06..f1b942aead309111a8e57db4391cff1edfe18062 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -1070,13 +1070,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + try { + tickConsumer.accept(entity); + MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick +- } catch (Throwable throwable) { ++ } catch (Throwable throwable) { // Airplane - diff on change ServerLevel.tick + if (throwable instanceof ThreadDeath) throw throwable; // Paper + // Paper start - Prevent tile entity and entity crashes + final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); + MinecraftServer.LOGGER.error(msg, throwable); + getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable))); +- entity.discard(); ++ entity.discard(); // Airplane - diff on change ServerLevel.tick + // Paper end + } + } diff --git a/patches/server/0030-Configurable-feature-seeds.patch b/patches/server/0030-Configurable-feature-seeds.patch new file mode 100644 index 0000000..47007f3 --- /dev/null +++ b/patches/server/0030-Configurable-feature-seeds.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Tue, 31 Aug 2021 17:05:27 +0200 +Subject: [PATCH] Configurable feature seeds + +Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index 4ae21ba5d04c954592ec4f85d43ff71ec7dadea1..bee97b02227ef198c79c48b43610fb417435a2d2 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -922,6 +922,37 @@ public class PaperWorldConfig { + return table; + } + ++ public it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap featureSeeds = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); ++ private void featureSeeds() { ++ featureSeeds.defaultReturnValue(-1); ++ final boolean randomise = getBoolean("feature-seeds.generate-random-seeds-for-all", false); ++ ConfigurationSection section = config.getConfigurationSection("world-settings." + worldName + ".feature-seeds"); ++ if (section == null) { ++ section = config.getConfigurationSection("world-settings.default.feature-seeds"); ++ } ++ for (final String key : section.getKeys(false)) { ++ net.minecraft.resources.ResourceLocation resourceKey = new net.minecraft.resources.ResourceLocation(key); ++ featureSeeds.put(resourceKey, section.getLong(key)); ++ } ++ if (randomise) { ++ final Map randomisedSeeds = new HashMap<>(); ++ final java.util.Random random = new java.util.Random(); ++ for (net.minecraft.resources.ResourceLocation resourceLocation : net.minecraft.server.MinecraftServer.getServer() ++ .registryAccess().registryOrThrow(net.minecraft.core.Registry.CONFIGURED_FEATURE_REGISTRY).keySet()) { ++ if (featureSeeds.containsKey(resourceLocation)) { ++ continue; ++ } ++ ++ final long seed = random.nextLong(); ++ randomisedSeeds.put("world-settings." + worldName + ".feature-seeds." + resourceLocation.getPath(), seed); ++ featureSeeds.put(resourceLocation, seed); ++ } ++ if (!randomisedSeeds.isEmpty()) { ++ config.addDefaults(randomisedSeeds); ++ } ++ } ++ } ++ + public int getBehaviorTickRate(String typeName, String entityType, int def) { + return getIntOrDefault(behaviorTickRates, typeName, entityType, def); + } +diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java +index 0ea6fedf6e660bc133fd5eb34d3d9bac3e581f32..b5c6b0bc307aef2835761cfa50413cebfd624795 100644 +--- a/src/main/java/net/minecraft/world/level/biome/Biome.java ++++ b/src/main/java/net/minecraft/world/level/biome/Biome.java +@@ -225,7 +225,7 @@ public final class Biome { + + public void generate(StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, WorldGenRegion region, long populationSeed, WorldgenRandom random, BlockPos origin) { + List>>> list = this.generationSettings.features(); +- Registry> registry = region.registryAccess().registryOrThrow(Registry.CONFIGURED_FEATURE_REGISTRY); ++ Registry> registry = region.registryAccess().registryOrThrow(Registry.CONFIGURED_FEATURE_REGISTRY); // Paper - diff on change + Registry> registry2 = region.registryAccess().registryOrThrow(Registry.STRUCTURE_FEATURE_REGISTRY); + int i = GenerationStep.Decoration.values().length; + +@@ -267,7 +267,16 @@ public final class Biome { + Supplier supplier3 = () -> { + return registry.getResourceKey(configuredFeature).map(Object::toString).orElseGet(configuredFeature::toString); + }; +- random.setFeatureSeed(populationSeed, k, j); ++ // Paper start - change populationSeed used in random ++ long featurePopulationSeed = populationSeed; ++ final ResourceLocation location = registry.getKey(configuredFeature); ++ final long configFeatureSeed = region.getMinecraftWorld().paperConfig.featureSeeds.getLong(location); ++ if (configFeatureSeed != -1) { ++ final ChunkPos center = region.getCenter(); ++ featurePopulationSeed = random.setDecorationSeed(configFeatureSeed, center.getMinBlockX(), center.getMinBlockZ()); // See ChunkGenerator#addVanillaDecorations ++ } ++ random.setFeatureSeed(featurePopulationSeed, k, j); ++ // Paper end + + try { + region.setCurrentlyGenerating(supplier3);