--- a/net/minecraft/world/entity/monster/ZombieVillager.java
+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
@@ -3,21 +3,9 @@
 import com.mojang.logging.LogUtils;
 import com.mojang.serialization.DataResult;
 import com.mojang.serialization.Dynamic;
+import java.util.Objects;
 import java.util.UUID;
 import javax.annotation.Nullable;
-import net.minecraft.advancements.CriteriaTriggers;
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Registry;
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.NbtOps;
-import net.minecraft.nbt.Tag;
-import net.minecraft.network.syncher.EntityDataAccessor;
-import net.minecraft.network.syncher.EntityDataSerializers;
-import net.minecraft.network.syncher.SynchedEntityData;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.server.level.ServerPlayer;
-import net.minecraft.sounds.SoundEvent;
-import net.minecraft.sounds.SoundEvents;
 import net.minecraft.world.DifficultyInstance;
 import net.minecraft.world.InteractionHand;
 import net.minecraft.world.InteractionResult;
@@ -45,8 +33,27 @@
 import net.minecraft.world.level.block.Blocks;
 import net.minecraft.world.level.block.state.BlockState;
 import org.slf4j.Logger;
+import net.minecraft.advancements.CriteriaTriggers;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Registry;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.NbtOps;
+import net.minecraft.nbt.Tag;
+import net.minecraft.network.syncher.EntityDataAccessor;
+import net.minecraft.network.syncher.EntityDataSerializers;
+import net.minecraft.network.syncher.SynchedEntityData;
+// CraftBukkit start
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.sounds.SoundEvents;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.entity.EntityTransformEvent;
+// CraftBukkit end
 
 public class ZombieVillager extends Zombie implements VillagerDataHolder {
+
     private static final Logger LOGGER = LogUtils.getLogger();
     public static final EntityDataAccessor<Boolean> DATA_CONVERTING_ID = SynchedEntityData.defineId(ZombieVillager.class, EntityDataSerializers.BOOLEAN);
     private static final EntityDataAccessor<VillagerData> DATA_VILLAGER_DATA = SynchedEntityData.defineId(ZombieVillager.class, EntityDataSerializers.VILLAGER_DATA);
@@ -62,26 +69,31 @@
     @Nullable
     private CompoundTag tradeOffers;
     private int villagerXp;
+    private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field
 
     public ZombieVillager(EntityType<? extends ZombieVillager> type, Level world) {
         super(type, world);
         Registry.VILLAGER_PROFESSION.getRandom(this.random).ifPresent((holder) -> {
-            this.setVillagerData(this.getVillagerData().setProfession(holder.value()));
+            this.setVillagerData(this.getVillagerData().setProfession((VillagerProfession) holder.value()));
         });
     }
 
     @Override
     protected void defineSynchedData() {
         super.defineSynchedData();
-        this.entityData.define(DATA_CONVERTING_ID, false);
-        this.entityData.define(DATA_VILLAGER_DATA, new VillagerData(VillagerType.PLAINS, VillagerProfession.NONE, 1));
+        this.entityData.define(ZombieVillager.DATA_CONVERTING_ID, false);
+        this.entityData.define(ZombieVillager.DATA_VILLAGER_DATA, new VillagerData(VillagerType.PLAINS, VillagerProfession.NONE, 1));
     }
 
     @Override
     public void addAdditionalSaveData(CompoundTag nbt) {
         super.addAdditionalSaveData(nbt);
-        VillagerData.CODEC.encodeStart(NbtOps.INSTANCE, this.getVillagerData()).resultOrPartial(LOGGER::error).ifPresent((tag) -> {
-            nbt.put("VillagerData", tag);
+        DataResult<Tag> dataresult = VillagerData.CODEC.encodeStart(NbtOps.INSTANCE, this.getVillagerData()); // CraftBukkit - decompile error
+        Logger logger = ZombieVillager.LOGGER;
+
+        Objects.requireNonNull(logger);
+        dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> {
+            nbt.put("VillagerData", nbtbase);
         });
         if (this.tradeOffers != null) {
             nbt.put("Offers", this.tradeOffers);
@@ -103,8 +115,11 @@
     public void readAdditionalSaveData(CompoundTag nbt) {
         super.readAdditionalSaveData(nbt);
         if (nbt.contains("VillagerData", 10)) {
-            DataResult<VillagerData> dataResult = VillagerData.CODEC.parse(new Dynamic<>(NbtOps.INSTANCE, nbt.get("VillagerData")));
-            dataResult.resultOrPartial(LOGGER::error).ifPresent(this::setVillagerData);
+            DataResult<VillagerData> dataresult = VillagerData.CODEC.parse(new Dynamic(NbtOps.INSTANCE, nbt.get("VillagerData")));
+            Logger logger = ZombieVillager.LOGGER;
+
+            Objects.requireNonNull(logger);
+            dataresult.resultOrPartial(logger::error).ifPresent(this::setVillagerData);
         }
 
         if (nbt.contains("Offers", 10)) {
@@ -129,22 +144,29 @@
     public void tick() {
         if (!this.level.isClientSide && this.isAlive() && this.isConverting()) {
             int i = this.getConversionProgress();
+            // CraftBukkit start - Use wall time instead of ticks for villager conversion
+            int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
+            i *= elapsedTicks;
+            // CraftBukkit end
+
             this.villagerConversionTime -= i;
             if (this.villagerConversionTime <= 0) {
-                this.finishConversion((ServerLevel)this.level);
+                this.finishConversion((ServerLevel) this.level);
             }
         }
 
         super.tick();
+        this.lastTick = MinecraftServer.currentTick; // CraftBukkit
     }
 
     @Override
     public InteractionResult mobInteract(Player player, InteractionHand hand) {
-        ItemStack itemStack = player.getItemInHand(hand);
-        if (itemStack.is(Items.GOLDEN_APPLE)) {
+        ItemStack itemstack = player.getItemInHand(hand);
+
+        if (itemstack.is(Items.GOLDEN_APPLE)) {
             if (this.hasEffect(MobEffects.WEAKNESS)) {
                 if (!player.getAbilities().instabuild) {
-                    itemStack.shrink(1);
+                    itemstack.shrink(1);
                 }
 
                 if (!this.level.isClientSide) {
@@ -171,16 +193,24 @@
     }
 
     public boolean isConverting() {
-        return this.getEntityData().get(DATA_CONVERTING_ID);
+        return (Boolean) this.getEntityData().get(ZombieVillager.DATA_CONVERTING_ID);
     }
 
     public void startConverting(@Nullable UUID uuid, int delay) {
+    // Paper start - missing entity behaviour api - converting without entity event
+        this.startConverting(uuid, delay, true);
+    }
+
+    public void startConverting(@Nullable UUID uuid, int delay, boolean broadcastEntityEvent) {
+    // Paper end - missing entity behaviour api - converting without entity event
         this.conversionStarter = uuid;
         this.villagerConversionTime = delay;
-        this.getEntityData().set(DATA_CONVERTING_ID, true);
-        this.removeEffect(MobEffects.WEAKNESS);
-        this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, delay, Math.min(this.level.getDifficulty().getId() - 1, 0)));
-        this.level.broadcastEntityEvent(this, (byte)16);
+        this.getEntityData().set(ZombieVillager.DATA_CONVERTING_ID, true);
+        // CraftBukkit start
+        this.removeEffect(MobEffects.WEAKNESS, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION);
+        this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, delay, Math.min(this.level.getDifficulty().getId() - 1, 0)), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION);
+        // CraftBukkit end
+        if (broadcastEntityEvent) this.level.broadcastEntityEvent(this, (byte) 16); // Paper - missing entity behaviour api - converting without entity event
     }
 
     @Override
@@ -196,60 +226,76 @@
     }
 
     private void finishConversion(ServerLevel world) {
-        Villager villager = this.convertTo(EntityType.VILLAGER, false);
+        // CraftBukkit start
+        Villager entityvillager = (Villager) this.convertTo(EntityType.VILLAGER, false, EntityTransformEvent.TransformReason.CURED, CreatureSpawnEvent.SpawnReason.CURED);
+        if (entityvillager == null) {
+            ((org.bukkit.entity.ZombieVillager) getBukkitEntity()).setConversionTime(-1); // SPIGOT-5208: End conversion to stop event spam
+            return;
+        }
+        // CraftBukkit end
+        EquipmentSlot[] aenumitemslot = EquipmentSlot.values();
+        int i = aenumitemslot.length;
 
-        for(EquipmentSlot equipmentSlot : EquipmentSlot.values()) {
-            ItemStack itemStack = this.getItemBySlot(equipmentSlot);
-            if (!itemStack.isEmpty()) {
-                if (EnchantmentHelper.hasBindingCurse(itemStack)) {
-                    villager.getSlot(equipmentSlot.getIndex() + 300).set(itemStack);
+        for (int j = 0; j < i; ++j) {
+            EquipmentSlot enumitemslot = aenumitemslot[j];
+            ItemStack itemstack = this.getItemBySlot(enumitemslot);
+
+            if (!itemstack.isEmpty()) {
+                if (EnchantmentHelper.hasBindingCurse(itemstack)) {
+                    entityvillager.getSlot(enumitemslot.getIndex() + 300).set(itemstack);
                 } else {
-                    double d = (double)this.getEquipmentDropChance(equipmentSlot);
-                    if (d > 1.0D) {
-                        this.spawnAtLocation(itemStack);
+                    double d0 = (double) this.getEquipmentDropChance(enumitemslot);
+
+                    if (d0 > 1.0D) {
+                        this.forceDrops = true; // CraftBukkit
+                        this.spawnAtLocation(itemstack);
+                        this.forceDrops = false; // CraftBukkit
                     }
                 }
             }
         }
 
-        villager.setVillagerData(this.getVillagerData());
+        entityvillager.setVillagerData(this.getVillagerData());
         if (this.gossips != null) {
-            villager.setGossips(this.gossips);
+            entityvillager.setGossips(this.gossips);
         }
 
         if (this.tradeOffers != null) {
-            villager.setOffers(new MerchantOffers(this.tradeOffers));
+            entityvillager.setOffers(new MerchantOffers(this.tradeOffers));
         }
 
-        villager.setVillagerXp(this.villagerXp);
-        villager.finalizeSpawn(world, world.getCurrentDifficultyAt(villager.blockPosition()), MobSpawnType.CONVERSION, (SpawnGroupData)null, (CompoundTag)null);
-        villager.refreshBrain(world);
+        entityvillager.setVillagerXp(this.villagerXp);
+        entityvillager.finalizeSpawn(world, world.getCurrentDifficultyAt(entityvillager.blockPosition()), MobSpawnType.CONVERSION, (SpawnGroupData) null, (CompoundTag) null);
+        entityvillager.refreshBrain(world);
         if (this.conversionStarter != null) {
-            Player player = world.getPlayerByUUID(this.conversionStarter);
-            if (player instanceof ServerPlayer) {
-                CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer)player, this, villager);
-                world.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, player, villager);
+            Player entityhuman = world.getPlayerByUUID(this.conversionStarter);
+
+            if (entityhuman instanceof ServerPlayer) {
+                CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer) entityhuman, this, entityvillager);
+                world.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, entityhuman, entityvillager);
             }
         }
 
-        villager.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0));
+        entityvillager.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); // CraftBukkit
         if (!this.isSilent()) {
-            world.levelEvent((Player)null, 1027, this.blockPosition(), 0);
+            world.levelEvent((Player) null, 1027, this.blockPosition(), 0);
         }
 
     }
 
     private int getConversionProgress() {
         int i = 1;
+
         if (this.random.nextFloat() < 0.01F) {
             int j = 0;
-            BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+            BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
 
-            for(int k = (int)this.getX() - 4; k < (int)this.getX() + 4 && j < 14; ++k) {
-                for(int l = (int)this.getY() - 4; l < (int)this.getY() + 4 && j < 14; ++l) {
-                    for(int m = (int)this.getZ() - 4; m < (int)this.getZ() + 4 && j < 14; ++m) {
-                        BlockState blockState = this.level.getBlockState(mutableBlockPos.set(k, l, m));
-                        if (blockState.is(Blocks.IRON_BARS) || blockState.getBlock() instanceof BedBlock) {
+            for (int k = (int) this.getX() - 4; k < (int) this.getX() + 4 && j < 14; ++k) {
+                for (int l = (int) this.getY() - 4; l < (int) this.getY() + 4 && j < 14; ++l) {
+                    for (int i1 = (int) this.getZ() - 4; i1 < (int) this.getZ() + 4 && j < 14; ++i1) {
+                        BlockState iblockdata = this.level.getBlockState(blockposition_mutableblockposition.set(k, l, i1));
+
+                        if (iblockdata.is(Blocks.IRON_BARS) || iblockdata.getBlock() instanceof BedBlock) {
                             if (this.random.nextFloat() < 0.3F) {
                                 ++i;
                             }
@@ -311,17 +357,18 @@
 
     @Override
     public void setVillagerData(VillagerData villagerData) {
-        VillagerData villagerData2 = this.getVillagerData();
-        if (villagerData2.getProfession() != villagerData.getProfession()) {
+        VillagerData villagerdata1 = this.getVillagerData();
+
+        if (villagerdata1.getProfession() != villagerData.getProfession()) {
             this.tradeOffers = null;
         }
 
-        this.entityData.set(DATA_VILLAGER_DATA, villagerData);
+        this.entityData.set(ZombieVillager.DATA_VILLAGER_DATA, villagerData);
     }
 
     @Override
     public VillagerData getVillagerData() {
-        return this.entityData.get(DATA_VILLAGER_DATA);
+        return (VillagerData) this.entityData.get(ZombieVillager.DATA_VILLAGER_DATA);
     }
 
     public int getVillagerXp() {
