diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch
index 7c6302e430..87a5b2cab0 100644
--- a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch
+++ b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch
@@ -80,7 +80,7 @@
 +    public final UUID uuid;
 +    public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
 +    public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
- 
++
 +    public LevelChunk getChunkIfLoaded(int x, int z) {
 +        return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
 +    }
@@ -149,7 +149,7 @@
 +        List<net.minecraft.world.level.chunk.ChunkAccess> ret = new java.util.ArrayList<>();
 +        it.unimi.dsi.fastutil.ints.IntArrayList ticketLevels = new it.unimi.dsi.fastutil.ints.IntArrayList();
 +        ServerChunkCache chunkProvider = this.getChunkSource();
-+
+ 
 +        int requiredChunks = (maxChunkX - minChunkX + 1) * (maxChunkZ - minChunkZ + 1);
 +        int[] loadedChunks = new int[1];
 +
@@ -487,9 +487,10 @@
          if (flag != this.isRaining()) {
              if (flag) {
 -                this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.STOP_RAINING, 0.0F));
-+                this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.STOP_RAINING, 0.0F));
-             } else {
+-            } else {
 -                this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0.0F));
++                this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.STOP_RAINING, 0.0F));
++            } else {
 +                this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.START_RAINING, 0.0F));
              }
  
@@ -625,13 +626,13 @@
 -        return this.addEntity(entity);
 +        // CraftBukkit start
 +        return this.addWithUUID(entity, CreatureSpawnEvent.SpawnReason.DEFAULT);
-     }
- 
++    }
++
 +    public boolean addWithUUID(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
 +        return this.addEntity(entity, reason);
 +        // CraftBukkit end
-+    }
-+
+     }
+ 
      public void addDuringTeleport(Entity entity) {
 +        // CraftBukkit start
 +        // SPIGOT-6415: Don't call spawn event for entities which travel trough worlds,
@@ -1100,10 +1101,12 @@
          return this.entityManager.getEntityGetter();
      }
  
-@@ -1802,6 +2239,27 @@
-         return this.serverLevelData.getGameRules();
-     }
+@@ -1800,7 +2237,28 @@
  
+     public GameRules getGameRules() {
+         return this.serverLevelData.getGameRules();
++    }
++
 +    // Paper start - respect global sound events gamerule
 +    public List<net.minecraft.server.level.ServerPlayer> getPlayersForGlobalSoundGamerule() {
 +        return this.getGameRules().getBoolean(GameRules.RULE_GLOBAL_SOUND_EVENTS) ? ((ServerLevel) this).getServer().getPlayerList().players : ((ServerLevel) this).players();
@@ -1122,13 +1125,12 @@
 +        if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) {
 +            this.notifyAndUpdatePhysics(craftBlockState.getPosition(), null, craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getFlag(), 512);
 +        }
-+    }
+     }
 +    // Paper end - notify observers even if grow failed
-+
+ 
      @Override
      public CrashReportCategory fillReportDetails(CrashReport report) {
-         CrashReportCategory crashreportsystemdetails = super.fillReportDetails(report);
-@@ -1828,6 +2286,7 @@
+@@ -1828,22 +2286,30 @@
          }
  
          public void onTickingStart(Entity entity) {
@@ -1136,7 +1138,14 @@
              ServerLevel.this.entityTickList.add(entity);
          }
  
-@@ -1836,14 +2295,15 @@
+         public void onTickingEnd(Entity entity) {
+             ServerLevel.this.entityTickList.remove(entity);
++            // Paper start - Reset pearls when they stop being ticked
++            if (ServerLevel.this.paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && ServerLevel.this.paperConfig().misc.legacyEnderPearlBehavior && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) {
++                pearl.cachedOwner = null;
++                pearl.ownerUUID = null;
++            }
++            // Paper end - Reset pearls when they stop being ticked
          }
  
          public void onTrackingStart(Entity entity) {
@@ -1154,7 +1163,7 @@
                      String s = "onTrackingStart called during navigation iteration";
  
                      Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration"));
-@@ -1864,9 +2324,58 @@
+@@ -1864,9 +2330,58 @@
              }
  
              entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
@@ -1213,7 +1222,7 @@
              ServerLevel.this.getChunkSource().removeEntity(entity);
              if (entity instanceof ServerPlayer entityplayer) {
                  ServerLevel.this.players.remove(entityplayer);
-@@ -1874,7 +2383,7 @@
+@@ -1874,7 +2389,7 @@
              }
  
              if (entity instanceof Mob entityinsentient) {
@@ -1222,7 +1231,7 @@
                      String s = "onTrackingStart called during navigation iteration";
  
                      Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration"));
-@@ -1895,10 +2404,27 @@
+@@ -1895,10 +2410,27 @@
              }
  
              entity.updateDynamicGameEventListener(DynamicGameEventListener::remove);
diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch
index 778f7aa5e1..4e0aeff12d 100644
--- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch
+++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch
@@ -58,7 +58,15 @@
              return this.cachedOwner;
          } else {
              return null;
-@@ -184,12 +210,20 @@
+@@ -108,6 +134,7 @@
+     protected void readAdditionalSaveData(CompoundTag nbt) {
+         if (nbt.hasUUID("Owner")) {
+             this.setOwnerThroughUUID(nbt.getUUID("Owner"));
++            if (this instanceof ThrownEnderpearl && this.level() != null && this.level().paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && this.level().paperConfig().misc.legacyEnderPearlBehavior) { this.ownerUUID = null; } // Paper - Reset pearls when they stop being ticked; Don't store shooter name for pearls to block enderpearl travel exploit
+         }
+ 
+         this.leftOwner = nbt.getBoolean("LeftOwner");
+@@ -184,12 +211,20 @@
  
          this.shoot((double) f5, (double) f6, (double) f7, speed, divergence);
          Vec3 vec3d = shooter.getKnownMovement();
@@ -81,7 +89,7 @@
              iprojectile.shootFromRotation(shooter, shooter.getXRot(), shooter.getYRot(), roll, power, divergence);
          });
      }
-@@ -201,7 +235,12 @@
+@@ -201,7 +236,12 @@
      }
  
      public static <T extends Projectile> T spawnProjectileUsingShoot(T projectile, ServerLevel world, ItemStack projectileStack, double velocityX, double velocityY, double velocityZ, float power, float divergence) {
@@ -95,12 +103,10 @@
              projectile.shoot(velocityX, velocityY, velocityZ, power, divergence);
          });
      }
-@@ -209,13 +248,47 @@
-     public static <T extends Projectile> T spawnProjectile(T projectile, ServerLevel world, ItemStack projectileStack) {
-         return Projectile.spawnProjectile(projectile, world, projectileStack, (iprojectile) -> {
+@@ -211,11 +251,45 @@
          });
-+    }
-+
+     }
+ 
 +    // Paper start - delayed projectile spawning
 +    public record Delayed<T extends Projectile>(
 +        T projectile,
@@ -129,9 +135,9 @@
 +            this.attemptSpawn(reason);
 +            return projectile();
 +        }
-     }
++    }
 +    // Paper end - delayed projectile spawning
- 
++
      public static <T extends Projectile> T spawnProjectile(T projectile, ServerLevel world, ItemStack projectileStack, Consumer<T> beforeSpawn) {
 +    // Paper start - delayed projectile spawning
 +        return spawnProjectileDelayed(projectile, world, projectileStack, beforeSpawn).spawn();
@@ -146,7 +152,7 @@
      }
  
      public void applyOnProjectileSpawned(ServerLevel world, ItemStack projectileStack) {
-@@ -232,6 +305,17 @@
+@@ -232,6 +306,17 @@
  
      }
  
@@ -164,7 +170,7 @@
      protected ProjectileDeflection hitTargetOrDeflectSelf(HitResult hitResult) {
          if (hitResult.getType() == HitResult.Type.ENTITY) {
              EntityHitResult movingobjectpositionentity = (EntityHitResult) hitResult;
-@@ -269,7 +353,13 @@
+@@ -269,7 +354,13 @@
      public boolean deflect(ProjectileDeflection deflection, @Nullable Entity deflector, @Nullable Entity owner, boolean fromAttack) {
          deflection.deflect(this, deflector, this.random);
          if (!this.level().isClientSide) {
@@ -179,7 +185,7 @@
              this.onDeflection(deflector, fromAttack);
          }
  
-@@ -309,6 +399,11 @@
+@@ -309,6 +400,11 @@
      protected void onHitEntity(EntityHitResult entityHitResult) {}
  
      protected void onHitBlock(BlockHitResult blockHitResult) {
@@ -191,7 +197,7 @@
          BlockState iblockdata = this.level().getBlockState(blockHitResult.getBlockPos());
  
          iblockdata.onProjectileHit(this.level(), iblockdata, blockHitResult, this);
-@@ -320,6 +415,15 @@
+@@ -320,6 +416,15 @@
          } else {
              Entity entity1 = this.getOwner();
  
@@ -207,7 +213,7 @@
              return entity1 == null || this.leftOwner || !entity1.isPassengerOfSameVehicle(entity);
          }
      }
-@@ -333,14 +437,8 @@
+@@ -333,14 +438,8 @@
      }
  
      protected static float lerpRotation(float prevRot, float newRot) {