--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -1,7 +1,9 @@
 package net.minecraft.world.level.levelgen;
 
+import java.util.Iterator;
 import net.minecraft.core.BlockPos;
 import net.minecraft.nbt.CompoundTag;
+import io.papermc.paper.util.MCUtil;
 import net.minecraft.server.level.ServerLevel;
 import net.minecraft.server.level.ServerPlayer;
 import net.minecraft.stats.ServerStatsCounter;
@@ -21,8 +23,11 @@
 import net.minecraft.world.level.material.FluidState;
 
 public class PhantomSpawner implements CustomSpawner {
+
     private int nextTick;
 
+    public PhantomSpawner() {}
+
     @Override
     public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) {
         if (!spawnMonsters) {
@@ -30,42 +35,60 @@
         } else if (!world.getGameRules().getBoolean(GameRules.RULE_DOINSOMNIA)) {
             return 0;
         } else {
-            RandomSource randomSource = world.random;
+            RandomSource randomsource = world.random;
+
             --this.nextTick;
             if (this.nextTick > 0) {
                 return 0;
             } else {
-                this.nextTick += (60 + randomSource.nextInt(60)) * 20;
+                this.nextTick += (60 + randomsource.nextInt(60)) * 20;
                 if (world.getSkyDarken() < 5 && world.dimensionType().hasSkyLight()) {
                     return 0;
                 } else {
                     int i = 0;
+                    Iterator iterator = world.players().iterator();
 
-                    for(Player player : world.players()) {
-                        if (!player.isSpectator()) {
-                            BlockPos blockPos = player.blockPosition();
-                            if (!world.dimensionType().hasSkyLight() || blockPos.getY() >= world.getSeaLevel() && world.canSeeSky(blockPos)) {
-                                DifficultyInstance difficultyInstance = world.getCurrentDifficultyAt(blockPos);
-                                if (difficultyInstance.isHarderThan(randomSource.nextFloat() * 3.0F)) {
-                                    ServerStatsCounter serverStatsCounter = ((ServerPlayer)player).getStats();
-                                    int j = Mth.clamp(serverStatsCounter.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
-                                    int k = 24000;
-                                    if (randomSource.nextInt(j) >= 72000) {
-                                        BlockPos blockPos2 = blockPos.above(20 + randomSource.nextInt(15)).east(-10 + randomSource.nextInt(21)).south(-10 + randomSource.nextInt(21));
-                                        BlockState blockState = world.getBlockState(blockPos2);
-                                        FluidState fluidState = world.getFluidState(blockPos2);
-                                        if (NaturalSpawner.isValidEmptySpawnBlock(world, blockPos2, blockState, fluidState, EntityType.PHANTOM)) {
-                                            SpawnGroupData spawnGroupData = null;
-                                            int l = 1 + randomSource.nextInt(difficultyInstance.getDifficulty().getId() + 1);
+                    while (iterator.hasNext()) {
+                        Player entityhuman = (Player) iterator.next();
 
-                                            for(int m = 0; m < l; ++m) {
-                                                Phantom phantom = EntityType.PHANTOM.create(world);
-                                                phantom.moveTo(blockPos2, 0.0F, 0.0F);
-                                                spawnGroupData = phantom.finalizeSpawn(world, difficultyInstance, MobSpawnType.NATURAL, spawnGroupData, (CompoundTag)null);
-                                                world.addFreshEntityWithPassengers(phantom);
+                        if (!entityhuman.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityhuman.isCreative())) { // Paper
+                            BlockPos blockposition = entityhuman.blockPosition();
+
+                            if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) {
+                                DifficultyInstance difficultydamagescaler = world.getCurrentDifficultyAt(blockposition);
+
+                                if (difficultydamagescaler.isHarderThan(randomsource.nextFloat() * 3.0F)) {
+                                    ServerStatsCounter serverstatisticmanager = ((ServerPlayer) entityhuman).getStats();
+                                    int j = Mth.clamp(serverstatisticmanager.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), (int) 1, Integer.MAX_VALUE);
+                                    boolean flag2 = true;
+
+                                    if (randomsource.nextInt(j) >= 72000) {
+                                        BlockPos blockposition1 = blockposition.above(20 + randomsource.nextInt(15)).east(-10 + randomsource.nextInt(21)).south(-10 + randomsource.nextInt(21));
+                                        BlockState iblockdata = world.getBlockState(blockposition1);
+                                        FluidState fluid = world.getFluidState(blockposition1);
+
+                                        if (NaturalSpawner.isValidEmptySpawnBlock(world, blockposition1, iblockdata, fluid, EntityType.PHANTOM)) {
+                                            SpawnGroupData groupdataentity = null;
+                                            int k = 1 + randomsource.nextInt(difficultydamagescaler.getDifficulty().getId() + 1);
+
+                                            for (int l = 0; l < k; ++l) {
+                                                // Paper start
+                                                com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent event = new com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent(MCUtil.toLocation(world, blockposition1), ((ServerPlayer) entityhuman).getBukkitEntity(), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL);
+                                                if (!event.callEvent()) {
+                                                    if (event.shouldAbortSpawn()) {
+                                                        break;
+                                                    }
+                                                    continue;
+                                                }
+                                                // Paper end
+                                                Phantom entityphantom = (Phantom) EntityType.PHANTOM.create(world);
+                                                entityphantom.setSpawningEntity(entityhuman.getUUID()); // Paper
+                                                entityphantom.moveTo(blockposition1, 0.0F, 0.0F);
+                                                groupdataentity = entityphantom.finalizeSpawn(world, difficultydamagescaler, MobSpawnType.NATURAL, groupdataentity, (CompoundTag) null);
+                                                world.addFreshEntityWithPassengers(entityphantom, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit
                                             }
 
-                                            i += l;
+                                            i += k;
                                         }
                                     }
                                 }
