diff --git a/gradle.properties b/gradle.properties
index 79ef51ab6..04eaf6cef 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,7 +2,7 @@ group = org.purpurmc.purpur
version = 1.21.1-R0.1-SNAPSHOT
mcVersion = 1.21.1
-paperCommit = b483da4e026ad078c9b1dd6e1e5ec25ac450df69
+paperCommit = 3db475838f8341f0db0efee0843755864b2241fa
org.gradle.caching = true
org.gradle.parallel = true
diff --git a/patches/api/0033-Grindstone-API.patch b/patches/api/0033-Grindstone-API.patch
index 5a699b1c1..fc958c00f 100644
--- a/patches/api/0033-Grindstone-API.patch
+++ b/patches/api/0033-Grindstone-API.patch
@@ -6,10 +6,10 @@ Subject: [PATCH] Grindstone API
diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java
new file mode 100644
-index 0000000000000000000000000000000000000000..eebb5d124456b8209d1b8e8cc4cb772dd3714f04
+index 0000000000000000000000000000000000000000..d4ccbce1dc8817dcc97c7cdce65d099b6c16b0c8
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java
-@@ -0,0 +1,72 @@
+@@ -0,0 +1,74 @@
+package org.purpurmc.purpur.event.inventory;
+
+import org.bukkit.entity.HumanEntity;
@@ -55,6 +55,7 @@ index 0000000000000000000000000000000000000000..eebb5d124456b8209d1b8e8cc4cb772d
+
+ /**
+ * Get the amount of experience this transaction will give
++ * (takes priority over and uses result from {@link org.bukkit.event.block.BlockExpEvent})
+ *
+ * @return Amount of experience to give
+ */
@@ -64,6 +65,7 @@ index 0000000000000000000000000000000000000000..eebb5d124456b8209d1b8e8cc4cb772d
+
+ /**
+ * Set the amount of experience this transaction will give
++ * (takes priority over {@link org.bukkit.event.block.BlockExpEvent})
+ *
+ * @param experienceAmount Amount of experience to give
+ */
diff --git a/patches/server/0001-Pufferfish-Server-Changes.patch b/patches/server/0001-Pufferfish-Server-Changes.patch
index ba04eeb2a..63dd64f80 100644
--- a/patches/server/0001-Pufferfish-Server-Changes.patch
+++ b/patches/server/0001-Pufferfish-Server-Changes.patch
@@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
diff --git a/build.gradle.kts b/build.gradle.kts
-index 3588770a9ea6ee0a9508b218758650f43d994715..181784e18cd321f959845abdc0982e934f67a702 100644
+index 32832deabc39be99ae0d69fe81439b86789f09e4..ed6a1af4021d927c2b594e9e97835b8584334b34 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -13,7 +13,7 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) {
@@ -1197,7 +1197,7 @@ index dd56c8e041116ef3602a9f89c998c8208ab89b51..18bf9c42e76c8c35f57d74ea4adfa5b3
}
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
-index 1e0a6e5a3c907ab55ee6f2780a7d43bd455f2b7b..305bcd9f76eb2927da143b9c7f022ff073e9518a 100644
+index af8cb316ac169aa8d98a88765b85bb013b9ba961..6abae547de1c9de07a75800550631ca5ee693e0a 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -172,6 +172,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1211,7 +1211,7 @@ index 1e0a6e5a3c907ab55ee6f2780a7d43bd455f2b7b..305bcd9f76eb2927da143b9c7f022ff0
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) {
super(new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"), session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
-@@ -1281,8 +1285,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -1282,8 +1286,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
return ChunkMap.this.level.getServer().getScaledTrackingDistance(initialDistance);
}
@@ -1240,7 +1240,7 @@ index 1e0a6e5a3c907ab55ee6f2780a7d43bd455f2b7b..305bcd9f76eb2927da143b9c7f022ff0
Iterator iterator = this.entity.getIndirectPassengers().iterator();
while (iterator.hasNext()) {
-@@ -1294,6 +1318,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -1295,6 +1319,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
i = j;
}
}
@@ -1367,7 +1367,7 @@ index 8ea2f24695f5dad55e21f238b69442513e7a90c6..5a2f7f7cf79dcbb996574e18cad86ebb
this.wasOnGround = this.entity.onGround();
this.teleportDelay = 0;
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
-index 2fe9d9b38c01d04416843fdd48d3e33899b7de63..5a9712de8abe3c3ccd08c5699f89e3ce54b1f28d 100644
+index c96f3dcd365bc140b1f4680ef6bd770c80f8eda1..67d4b15143358c8947a7102a325dad66967e73a6 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -715,6 +715,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
@@ -1413,7 +1413,7 @@ index 2fe9d9b38c01d04416843fdd48d3e33899b7de63..5a9712de8abe3c3ccd08c5699f89e3ce
if (this.isRainingAt(blockposition)) {
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index b13057c0792067cc6b0abdf0d64a9be2cc9389a4..427ac2a5e90ad80328a07af27552b6b380c8f3f1 100644
+index fcccf989c25f0a259b160c4ff7873f7009e64d14..9422d8bd512555f54410391d55c4072474c1ae4e 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1157,6 +1157,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -1572,7 +1572,7 @@ index cb61462d4691a055a4b25f7b953609d8a154fdfe..f9440014ab2fe753c16b9383f5fffbb8
private String descriptionId;
@Nullable
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
-index ccd9dff20a60f019e0c320acfb526b8bf3e5f806..ce0d28cafcae0b7edc861749a1652ecc08d298b5 100644
+index 9c9e2377f44b1f1bbd8bb0e8bc963a80f4f9ee68..9a246178b8ffe3571d54c6c4156a31c818467062 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -157,7 +157,6 @@ import org.bukkit.event.entity.EntityTeleportEvent;
diff --git a/patches/server/0003-Rebrand.patch b/patches/server/0003-Rebrand.patch
index e3aa16c3b..cb289fe71 100644
--- a/patches/server/0003-Rebrand.patch
+++ b/patches/server/0003-Rebrand.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Rebrand
diff --git a/build.gradle.kts b/build.gradle.kts
-index f138c6fb5410c416d6af4d49ae51c9ac840515d6..97a4a54dfa74df7aafd9df5a0f2fdac72471c2d5 100644
+index 39ee61bacd75699538425cd743f4b92f799d0ef0..299881d2c9fb7321f4b29c019e9088e024b64689 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -13,7 +13,7 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) {
@@ -138,10 +138,10 @@ index 532306cacd52579cdf37e4aca25887b1ed3ba6a1..6d36fc6d8e22d9b68dea3830f6ecc876
}
}
diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
-index c5d5648f4ca603ef2b1df723b58f9caf4dd3c722..3cb56595822799926a8141e60a42f5d1edfc6de5 100644
+index 6ee39b534b8d992655bc0cef3c299d12cbae0034..90b3526479320064378f2cde6c2f2b8e48a59ba6 100644
--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
-@@ -17,7 +17,7 @@ public final class PaperConsole extends SimpleTerminalConsole {
+@@ -20,7 +20,7 @@ public final class PaperConsole extends SimpleTerminalConsole {
@Override
protected LineReader buildReader(LineReaderBuilder builder) {
builder
@@ -267,7 +267,7 @@ index 2f4d6b56301195f8d39ed50dffe842464065bfe1..30ddb35140ae4a6faba98c191bb8eadb
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
-index 00918d92a4105cc82a4d871423e516939cad951f..d85fe70212cb3203c432585e8c7ca4776338fc83 100644
+index 65e27259c3a44512f395b750e93226bb36743ff5..d6aae48a5920ccad0ee6c7ff2bacaa1ac7d8353b 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -487,7 +487,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
diff --git a/patches/server/0211-Config-for-grindstones.patch b/patches/server/0211-Config-for-grindstones.patch
index e07556eac..5df01f273 100644
--- a/patches/server/0211-Config-for-grindstones.patch
+++ b/patches/server/0211-Config-for-grindstones.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Config for grindstones
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
-index 1678f6c8b2c7db761783e53043169bf12bc2cb29..5d47ffc3fd31930c7dd2f23bc0e6b7da513d1595 100644
+index 138f77d13dda574def523d74fa55bc71b5bfa01b..57c9e636a10e5845f197cae39d4f885a1817d1f7 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
-@@ -131,7 +131,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
+@@ -135,7 +135,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
Holder holder = (Holder) entry.getKey();
int k = entry.getIntValue();
@@ -17,7 +17,7 @@ index 1678f6c8b2c7db761783e53043169bf12bc2cb29..5d47ffc3fd31930c7dd2f23bc0e6b7da
j += ((Enchantment) holder.value()).getMinCost(k);
}
}
-@@ -230,7 +230,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
+@@ -234,7 +234,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
Entry> entry = (Entry) iterator.next();
Holder holder = (Holder) entry.getKey();
@@ -26,7 +26,7 @@ index 1678f6c8b2c7db761783e53043169bf12bc2cb29..5d47ffc3fd31930c7dd2f23bc0e6b7da
itemenchantments_a.upgrade(holder, entry.getIntValue());
}
}
-@@ -238,10 +238,70 @@ public class GrindstoneMenu extends AbstractContainerMenu {
+@@ -242,10 +242,70 @@ public class GrindstoneMenu extends AbstractContainerMenu {
});
}
@@ -98,7 +98,7 @@ index 1678f6c8b2c7db761783e53043169bf12bc2cb29..5d47ffc3fd31930c7dd2f23bc0e6b7da
});
});
-@@ -256,6 +316,23 @@ public class GrindstoneMenu extends AbstractContainerMenu {
+@@ -260,6 +320,23 @@ public class GrindstoneMenu extends AbstractContainerMenu {
}
item.set(DataComponents.REPAIR_COST, i);
diff --git a/patches/server/0220-Grindstone-API.patch b/patches/server/0220-Grindstone-API.patch
index b662748f6..71bf4c24f 100644
--- a/patches/server/0220-Grindstone-API.patch
+++ b/patches/server/0220-Grindstone-API.patch
@@ -5,23 +5,26 @@ Subject: [PATCH] Grindstone API
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
-index 5d47ffc3fd31930c7dd2f23bc0e6b7da513d1595..cf373c763749161d0371bd243b8d77bb750a7d38 100644
+index 57c9e636a10e5845f197cae39d4f885a1817d1f7..3ba9ff1b10f8d1a105eb821a9cc0603fe28b7387 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
-@@ -96,9 +96,11 @@ public class GrindstoneMenu extends AbstractContainerMenu {
+@@ -96,12 +96,14 @@ public class GrindstoneMenu extends AbstractContainerMenu {
@Override
public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
+ ItemStack itemstack = activeQuickItem == null ? stack : activeQuickItem; // Purpur
context.execute((world, blockposition) -> {
-+ org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent grindstoneTakeResultEvent = new org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), this.getExperienceAmount(world)); grindstoneTakeResultEvent.callEvent(); // Purpur
if (world instanceof ServerLevel) {
-- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Paper
-+ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), grindstoneTakeResultEvent.getExperienceAmount(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Paper // Purpur
+ // Paper start - Fire BlockExpEvent on grindstone use
+ org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition), this.getExperienceAmount(world));
+ event.callEvent();
+- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player);
++ org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent grindstoneTakeResultEvent = new org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), event.getExpToDrop()); grindstoneTakeResultEvent.callEvent(); // Purpur
++ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), grindstoneTakeResultEvent.getExperienceAmount(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Purpur
+ // Paper end - Fire BlockExpEvent on grindstone use
}
- world.levelEvent(1042, blockposition, 0);
-@@ -394,7 +396,9 @@ public class GrindstoneMenu extends AbstractContainerMenu {
+@@ -398,7 +400,9 @@ public class GrindstoneMenu extends AbstractContainerMenu {
return ItemStack.EMPTY;
}