From b2002c14fab455d6fd64aa504e8ceaff29b603a4 Mon Sep 17 00:00:00 2001
From: Spottedleaf <spottedleaf@users.noreply.github.com>
Date: Sat, 27 May 2023 20:34:33 +0200
Subject: [PATCH] Pull a few Folia patches

---
 ...access-to-lookups-field-in-RegistryO.patch | 30 +++++++++++++++
 ...eehive-without-any-players-nearby-th.patch | 25 +++++++++++++
 ...recalcBlockCounts-for-empty-sections.patch | 37 +++++++++++++++++++
 .../incremental-chunk-and-player-saving.patch |  2 +-
 4 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 patches/server/Fix-concurrenct-access-to-lookups-field-in-RegistryO.patch
 create mode 100644 patches/server/Fix-destroying-beehive-without-any-players-nearby-th.patch
 create mode 100644 patches/server/Optimise-recalcBlockCounts-for-empty-sections.patch

diff --git a/patches/server/Fix-concurrenct-access-to-lookups-field-in-RegistryO.patch b/patches/server/Fix-concurrenct-access-to-lookups-field-in-RegistryO.patch
new file mode 100644
index 0000000000..70065fbc20
--- /dev/null
+++ b/patches/server/Fix-concurrenct-access-to-lookups-field-in-RegistryO.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Spottedleaf <Spottedleaf@users.noreply.github.com>
+Date: Mon, 15 May 2023 00:20:59 -0700
+Subject: [PATCH] Fix concurrenct access to lookups field in RegistryOps
+
+The concurrent access occurs on the Netty IO threads when
+serializing packets. Thus, it seems it was an oversight of
+the implementator of this function as there are typically
+more than one Netty IO thread.
+
+Fixes https://github.com/PaperMC/Folia/issues/11
+
+diff --git a/src/main/java/net/minecraft/resources/RegistryOps.java b/src/main/java/net/minecraft/resources/RegistryOps.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/resources/RegistryOps.java
++++ b/src/main/java/net/minecraft/resources/RegistryOps.java
+@@ -0,0 +0,0 @@ public class RegistryOps<T> extends DelegatingOps<T> {
+ 
+     private static RegistryOps.RegistryInfoLookup memoizeLookup(final RegistryOps.RegistryInfoLookup registryInfoGetter) {
+         return new RegistryOps.RegistryInfoLookup() {
+-            private final Map<ResourceKey<? extends Registry<?>>, Optional<? extends RegistryOps.RegistryInfo<?>>> lookups = new HashMap<>();
++            private final Map<ResourceKey<? extends Registry<?>>, Optional<? extends RegistryOps.RegistryInfo<?>>> lookups = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - fix concurrent access to lookups field
+ 
+             @Override
+             public <T> Optional<RegistryOps.RegistryInfo<T>> lookup(ResourceKey<? extends Registry<? extends T>> registryRef) {
+-                return this.lookups.computeIfAbsent(registryRef, registryInfoGetter::lookup);
++                return (Optional<RegistryOps.RegistryInfo<T>>)this.lookups.computeIfAbsent(registryRef, registryInfoGetter::lookup); // Paper - fix concurrent access to lookups field
+             }
+         };
+     }
diff --git a/patches/server/Fix-destroying-beehive-without-any-players-nearby-th.patch b/patches/server/Fix-destroying-beehive-without-any-players-nearby-th.patch
new file mode 100644
index 0000000000..dee3277662
--- /dev/null
+++ b/patches/server/Fix-destroying-beehive-without-any-players-nearby-th.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Spottedleaf <Spottedleaf@users.noreply.github.com>
+Date: Mon, 3 Apr 2023 21:14:19 -0700
+Subject: [PATCH] Fix destroying beehive without any players nearby throwing an
+ exception
+
+If the player moves out of range by the time the block is destroyed,
+then the exception would throw and remove the player from the world
+
+diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
++++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
+@@ -0,0 +0,0 @@ public class BeehiveBlock extends BaseEntityBlock {
+ 
+         if (!list.isEmpty()) {
+             List<Player> list1 = world.getEntitiesOfClass(Player.class, (new AABB(pos)).inflate(8.0D, 6.0D, 8.0D));
++            // Paper start - if there are no players nearby, then nextInt() will throw
++            if (list1.isEmpty()) {
++                return;
++            }
++            // Paper end - if there are no players nearby, then nextInt() will throw
+             int i = list1.size();
+             Iterator iterator = list.iterator();
+ 
diff --git a/patches/server/Optimise-recalcBlockCounts-for-empty-sections.patch b/patches/server/Optimise-recalcBlockCounts-for-empty-sections.patch
new file mode 100644
index 0000000000..67b9ef3557
--- /dev/null
+++ b/patches/server/Optimise-recalcBlockCounts-for-empty-sections.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Spottedleaf <Spottedleaf@users.noreply.github.com>
+Date: Mon, 15 May 2023 20:25:26 -0700
+Subject: [PATCH] Optimise recalcBlockCounts() for empty sections
+
+In 1.18, every chunk section is initialised to a non-null value
+and recalcBlockCounts() is invoked for each section.
+However, in a standard world, most sections are empty. In such cases,
+recalcBlockCounts() would iterate over ever position - even though
+the block data would all be air. To avoid this, we skip
+searching the section unless the palette indicates there _could_ be
+a non-air block state or non-empty fluid state.
+
+Chunk loading initially showed that recalcBlockCounts() over
+sections with a ZeroBitStorage data to to take ~20% of the process,
+now it takes <1%.
+
+diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+@@ -0,0 +0,0 @@ public class LevelChunkSection {
+         this.nonEmptyBlockCount = 0;
+         this.tickingBlockCount = 0;
+         this.tickingFluidCount = 0;
++        if (this.maybeHas((BlockState state) -> !state.isAir() || !state.getFluidState().isEmpty())) { // Paper - do not run forEachLocation on clearly empty sections
+         this.states.forEachLocation((BlockState iblockdata, int i) -> {
+             FluidState fluid = iblockdata.getFluidState();
+ 
+@@ -0,0 +0,0 @@ public class LevelChunkSection {
+             }
+ 
+         });
++        } // Paper - do not run forEachLocation on clearly empty sections
+         // Paper end
+         this.initBlockCollisionData(); // Paper
+     }
diff --git a/patches/server/incremental-chunk-and-player-saving.patch b/patches/server/incremental-chunk-and-player-saving.patch
index 456546e66c..07ce138b95 100644
--- a/patches/server/incremental-chunk-and-player-saving.patch
+++ b/patches/server/incremental-chunk-and-player-saving.patch
@@ -156,7 +156,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            ServerPlayer entityplayer = this.players.get(i);
 +            if (interval == -1 || now - entityplayer.lastSave >= interval) {
 +                this.save(entityplayer);
-+                if (interval != -1 && io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick() != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; }
++                if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; }
 +            }
 +            // Paper end
          }