--- a/net/minecraft/world/entity/EntityTypes.java
+++ b/net/minecraft/world/entity/EntityTypes.java
@@ -157,6 +157,7 @@
 import net.minecraft.world.phys.AxisAlignedBB;
 import net.minecraft.world.phys.shapes.VoxelShape;
 import net.minecraft.world.phys.shapes.VoxelShapes;
+import org.bukkit.event.entity.CreatureSpawnEvent;
 import org.slf4j.Logger;
 
 public class EntityTypes<T extends Entity> implements FeatureElement, EntityTypeTest<Entity, T> {
@@ -167,7 +168,7 @@
     private static final float MAGIC_HORSE_WIDTH = 1.3964844F;
     private static final int DISPLAY_TRACKING_RANGE = 10;
     public static final EntityTypes<Allay> ALLAY = register("allay", EntityTypes.Builder.of(Allay::new, EnumCreatureType.CREATURE).sized(0.35F, 0.6F).clientTrackingRange(8).updateInterval(2));
-    public static final EntityTypes<EntityAreaEffectCloud> AREA_EFFECT_CLOUD = register("area_effect_cloud", EntityTypes.Builder.of(EntityAreaEffectCloud::new, EnumCreatureType.MISC).fireImmune().sized(6.0F, 0.5F).clientTrackingRange(10).updateInterval(Integer.MAX_VALUE));
+    public static final EntityTypes<EntityAreaEffectCloud> AREA_EFFECT_CLOUD = register("area_effect_cloud", EntityTypes.Builder.of(EntityAreaEffectCloud::new, EnumCreatureType.MISC).fireImmune().sized(6.0F, 0.5F).clientTrackingRange(10).updateInterval(10)); // CraftBukkit - SPIGOT-3729: track area effect clouds
     public static final EntityTypes<EntityArmorStand> ARMOR_STAND = register("armor_stand", EntityTypes.Builder.of(EntityArmorStand::new, EnumCreatureType.MISC).sized(0.5F, 1.975F).clientTrackingRange(10));
     public static final EntityTypes<EntityTippedArrow> ARROW = register("arrow", EntityTypes.Builder.of(EntityTippedArrow::new, EnumCreatureType.MISC).sized(0.5F, 0.5F).clientTrackingRange(4).updateInterval(20));
     public static final EntityTypes<Axolotl> AXOLOTL = register("axolotl", EntityTypes.Builder.of(Axolotl::new, EnumCreatureType.AXOLOTLS).sized(0.75F, 0.42F).clientTrackingRange(10));
@@ -308,8 +309,8 @@
     private final EntitySize dimensions;
     private final FeatureFlagSet requiredFeatures;
 
-    private static <T extends Entity> EntityTypes<T> register(String s, EntityTypes.Builder<T> entitytypes_builder) {
-        return (EntityTypes) IRegistry.register(BuiltInRegistries.ENTITY_TYPE, s, entitytypes_builder.build(s));
+    private static <T extends Entity> EntityTypes<T> register(String s, EntityTypes.Builder entitytypes_builder) { // CraftBukkit - decompile error
+        return (EntityTypes) IRegistry.register(BuiltInRegistries.ENTITY_TYPE, s, (EntityTypes<T>) entitytypes_builder.build(s)); // CraftBukkit - decompile error
     }
 
     public static MinecraftKey getKey(EntityTypes<?> entitytypes) {
@@ -337,8 +338,15 @@
 
     @Nullable
     public T spawn(WorldServer worldserver, @Nullable ItemStack itemstack, @Nullable EntityHuman entityhuman, BlockPosition blockposition, EnumMobSpawn enummobspawn, boolean flag, boolean flag1) {
+        // CraftBukkit start
+        return this.spawn(worldserver, itemstack, entityhuman, blockposition, enummobspawn, flag, flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG);
+    }
+
+    @Nullable
+    public T spawn(WorldServer worldserver, @Nullable ItemStack itemstack, @Nullable EntityHuman entityhuman, BlockPosition blockposition, EnumMobSpawn enummobspawn, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
+        // CraftBukkit end
         NBTTagCompound nbttagcompound;
-        Consumer consumer;
+        Consumer<T> consumer; // CraftBukkit - decompile error
 
         if (itemstack != null) {
             nbttagcompound = itemstack.getTag();
@@ -349,7 +357,7 @@
             nbttagcompound = null;
         }
 
-        return this.spawn(worldserver, nbttagcompound, consumer, blockposition, enummobspawn, flag, flag1);
+        return this.spawn(worldserver, nbttagcompound, consumer, blockposition, enummobspawn, flag, flag1, spawnReason); // CraftBukkit
     }
 
     public static <T extends Entity> Consumer<T> createDefaultStackConfig(WorldServer worldserver, ItemStack itemstack, @Nullable EntityHuman entityhuman) {
@@ -371,21 +379,37 @@
         NBTTagCompound nbttagcompound = itemstack.getTag();
 
         return nbttagcompound != null ? consumer.andThen((entity) -> {
-            updateCustomEntityTag(worldserver, entityhuman, entity, nbttagcompound);
+            try { updateCustomEntityTag(worldserver, entityhuman, entity, nbttagcompound); } catch (Throwable t) { LOGGER.warn("Error loading spawn egg NBT", t); } // CraftBukkit - SPIGOT-5665
         }) : consumer;
     }
 
     @Nullable
     public T spawn(WorldServer worldserver, BlockPosition blockposition, EnumMobSpawn enummobspawn) {
-        return this.spawn(worldserver, (NBTTagCompound) null, (Consumer) null, blockposition, enummobspawn, false, false);
+        // CraftBukkit start
+        return this.spawn(worldserver, blockposition, enummobspawn, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
+    }
+
+    @Nullable
+    public T spawn(WorldServer worldserver, BlockPosition blockposition, EnumMobSpawn enummobspawn, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
+        return this.spawn(worldserver, (NBTTagCompound) null, null, blockposition, enummobspawn, false, false, spawnReason); // CraftBukkit - decompile error
+        // CraftBukkit end
     }
 
     @Nullable
     public T spawn(WorldServer worldserver, @Nullable NBTTagCompound nbttagcompound, @Nullable Consumer<T> consumer, BlockPosition blockposition, EnumMobSpawn enummobspawn, boolean flag, boolean flag1) {
+        // CraftBukkit start
+        return this.spawn(worldserver, nbttagcompound, consumer, blockposition, enummobspawn, flag, flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
+    }
+
+    @Nullable
+    public T spawn(WorldServer worldserver, @Nullable NBTTagCompound nbttagcompound, @Nullable Consumer<T> consumer, BlockPosition blockposition, EnumMobSpawn enummobspawn, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
+        // CraftBukkit end
         T t0 = this.create(worldserver, nbttagcompound, consumer, blockposition, enummobspawn, flag, flag1);
 
         if (t0 != null) {
-            worldserver.addFreshEntityWithPassengers(t0);
+            worldserver.addFreshEntityWithPassengers(t0, spawnReason);
+            return !t0.isRemoved() ? t0 : null; // Don't return an entity when CreatureSpawnEvent is canceled
+            // CraftBukkit end
         }
 
         return t0;
@@ -572,7 +596,7 @@
             }
 
             return entity;
-        }).orElse((Object) null);
+        }).orElse(null); // CraftBukkit - decompile error
     }
 
     public static Stream<Entity> loadEntitiesRecursive(final List<? extends NBTBase> list, final World world) {
@@ -629,7 +653,7 @@
 
     @Nullable
     public T tryCast(Entity entity) {
-        return entity.getType() == this ? entity : null;
+        return entity.getType() == this ? (T) entity : null; // CraftBukkit - decompile error
     }
 
     @Override
@@ -664,7 +688,7 @@
             this.canSpawnFarFromPlayer = enumcreaturetype == EnumCreatureType.CREATURE || enumcreaturetype == EnumCreatureType.MISC;
         }
 
-        public static <T extends Entity> EntityTypes.Builder<T> of(EntityTypes.b<T> entitytypes_b, EnumCreatureType enumcreaturetype) {
+        public static <T extends Entity> EntityTypes.Builder<T> of(EntityTypes.b entitytypes_b, EnumCreatureType enumcreaturetype) { // CraftBukkit - decompile error
             return new EntityTypes.Builder<>(entitytypes_b, enumcreaturetype);
         }
 
